• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2019 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// mtl_state_cache.mm:
7//    Implements StateCache, RenderPipelineCache and various
8//    C struct versions of Metal sampler, depth stencil, render pass, render pipeline descriptors.
9//
10
11#include "libANGLE/renderer/metal/mtl_state_cache.h"
12
13#include <sstream>
14
15#include "common/debug.h"
16#include "common/hash_utils.h"
17#include "libANGLE/renderer/metal/ContextMtl.h"
18#include "libANGLE/renderer/metal/mtl_resources.h"
19#include "libANGLE/renderer/metal/mtl_utils.h"
20
21#define ANGLE_OBJC_CP_PROPERTY(DST, SRC, PROPERTY) (DST).PROPERTY = ToObjC((SRC).PROPERTY)
22
23#define ANGLE_PROP_EQ(LHS, RHS, PROP) ((LHS).PROP == (RHS).PROP)
24
25namespace rx
26{
27namespace mtl
28{
29
30namespace
31{
32
33template <class T>
34inline T ToObjC(const T p)
35{
36    return p;
37}
38
39inline MTLStencilDescriptor *ToObjC(const StencilDesc &desc)
40{
41    MTLStencilDescriptor *objCDesc = [[MTLStencilDescriptor alloc] init];
42
43    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, stencilFailureOperation);
44    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, depthFailureOperation);
45    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, depthStencilPassOperation);
46    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, stencilCompareFunction);
47    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, readMask);
48    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, writeMask);
49
50    return [objCDesc ANGLE_MTL_AUTORELEASE];
51}
52
53MTLDepthStencilDescriptor *ToObjC(const DepthStencilDesc &desc)
54{
55    MTLDepthStencilDescriptor *objCDesc = [[MTLDepthStencilDescriptor alloc] init];
56
57    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, backFaceStencil);
58    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, frontFaceStencil);
59    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, depthCompareFunction);
60    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, depthWriteEnabled);
61
62    return [objCDesc ANGLE_MTL_AUTORELEASE];
63}
64
65MTLSamplerDescriptor *ToObjC(const SamplerDesc &desc)
66{
67    MTLSamplerDescriptor *objCDesc = [[MTLSamplerDescriptor alloc] init];
68
69    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, rAddressMode);
70    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, sAddressMode);
71    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, tAddressMode);
72    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, minFilter);
73    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, magFilter);
74    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, mipFilter);
75    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, maxAnisotropy);
76
77    return [objCDesc ANGLE_MTL_AUTORELEASE];
78}
79
80MTLVertexAttributeDescriptor *ToObjC(const VertexAttributeDesc &desc)
81{
82    MTLVertexAttributeDescriptor *objCDesc = [[MTLVertexAttributeDescriptor alloc] init];
83
84    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, format);
85    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, offset);
86    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, bufferIndex);
87
88    ASSERT(desc.bufferIndex >= kVboBindingIndexStart);
89
90    return [objCDesc ANGLE_MTL_AUTORELEASE];
91}
92
93MTLVertexBufferLayoutDescriptor *ToObjC(const VertexBufferLayoutDesc &desc)
94{
95    MTLVertexBufferLayoutDescriptor *objCDesc = [[MTLVertexBufferLayoutDescriptor alloc] init];
96
97    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, stepFunction);
98    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, stepRate);
99    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, stride);
100
101    return [objCDesc ANGLE_MTL_AUTORELEASE];
102}
103
104MTLVertexDescriptor *ToObjC(const VertexDesc &desc)
105{
106    MTLVertexDescriptor *objCDesc = [[MTLVertexDescriptor alloc] init];
107    [objCDesc reset];
108
109    for (uint8_t i = 0; i < desc.numAttribs; ++i)
110    {
111        [objCDesc.attributes setObject:ToObjC(desc.attributes[i]) atIndexedSubscript:i];
112    }
113
114    for (uint8_t i = 0; i < desc.numBufferLayouts; ++i)
115    {
116        [objCDesc.layouts setObject:ToObjC(desc.layouts[i]) atIndexedSubscript:i];
117    }
118
119    return [objCDesc ANGLE_MTL_AUTORELEASE];
120}
121
122MTLRenderPipelineColorAttachmentDescriptor *ToObjC(const RenderPipelineColorAttachmentDesc &desc)
123{
124    MTLRenderPipelineColorAttachmentDescriptor *objCDesc =
125        [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
126
127    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, pixelFormat);
128    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, writeMask);
129    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, alphaBlendOperation);
130    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, rgbBlendOperation);
131    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, destinationAlphaBlendFactor);
132    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, destinationRGBBlendFactor);
133    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, sourceAlphaBlendFactor);
134    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, sourceRGBBlendFactor);
135    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, blendingEnabled);
136
137    return [objCDesc ANGLE_MTL_AUTORELEASE];
138}
139
140MTLRenderPipelineDescriptor *ToObjC(id<MTLFunction> vertexShader,
141                                    id<MTLFunction> fragmentShader,
142                                    const RenderPipelineDesc &desc)
143{
144    MTLRenderPipelineDescriptor *objCDesc = [[MTLRenderPipelineDescriptor alloc] init];
145    [objCDesc reset];
146    objCDesc.vertexFunction   = vertexShader;
147    objCDesc.fragmentFunction = fragmentShader;
148
149    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, vertexDescriptor);
150
151    for (uint8_t i = 0; i < desc.outputDescriptor.numColorAttachments; ++i)
152    {
153        [objCDesc.colorAttachments setObject:ToObjC(desc.outputDescriptor.colorAttachments[i])
154                          atIndexedSubscript:i];
155    }
156    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc.outputDescriptor, depthAttachmentPixelFormat);
157    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc.outputDescriptor, stencilAttachmentPixelFormat);
158
159#if ANGLE_MTL_PRIMITIVE_TOPOLOGY_CLASS_AVAILABLE
160    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, inputPrimitiveTopology);
161#endif
162    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, rasterizationEnabled);
163
164    return [objCDesc ANGLE_MTL_AUTORELEASE];
165}
166
167id<MTLTexture> ToObjC(const TextureRef &texture)
168{
169    auto textureRef = texture;
170    return textureRef ? textureRef->get() : nil;
171}
172
173void ToObjC(MTLRenderPassAttachmentDescriptor *dst, const RenderPassAttachmentDesc &src)
174{
175    ANGLE_OBJC_CP_PROPERTY(dst, src, texture);
176    ANGLE_OBJC_CP_PROPERTY(dst, src, level);
177    ANGLE_OBJC_CP_PROPERTY(dst, src, slice);
178
179    ANGLE_OBJC_CP_PROPERTY(dst, src, loadAction);
180    ANGLE_OBJC_CP_PROPERTY(dst, src, storeAction);
181    ANGLE_OBJC_CP_PROPERTY(dst, src, storeActionOptions);
182}
183
184MTLRenderPassColorAttachmentDescriptor *ToObjC(const RenderPassColorAttachmentDesc &desc)
185{
186    MTLRenderPassColorAttachmentDescriptor *objCDesc =
187        [[MTLRenderPassColorAttachmentDescriptor alloc] init];
188
189    ToObjC(objCDesc, desc);
190
191    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearColor);
192
193    return [objCDesc ANGLE_MTL_AUTORELEASE];
194}
195
196MTLRenderPassDepthAttachmentDescriptor *ToObjC(const RenderPassDepthAttachmentDesc &desc)
197{
198    MTLRenderPassDepthAttachmentDescriptor *objCDesc =
199        [[MTLRenderPassDepthAttachmentDescriptor alloc] init];
200
201    ToObjC(objCDesc, desc);
202
203    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearDepth);
204
205    return [objCDesc ANGLE_MTL_AUTORELEASE];
206}
207
208MTLRenderPassStencilAttachmentDescriptor *ToObjC(const RenderPassStencilAttachmentDesc &desc)
209{
210    MTLRenderPassStencilAttachmentDescriptor *objCDesc =
211        [[MTLRenderPassStencilAttachmentDescriptor alloc] init];
212
213    ToObjC(objCDesc, desc);
214
215    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearStencil);
216
217    return [objCDesc ANGLE_MTL_AUTORELEASE];
218}
219
220}  // namespace
221
222// StencilDesc implementation
223bool StencilDesc::operator==(const StencilDesc &rhs) const
224{
225    return ANGLE_PROP_EQ(*this, rhs, stencilFailureOperation) &&
226           ANGLE_PROP_EQ(*this, rhs, depthFailureOperation) &&
227           ANGLE_PROP_EQ(*this, rhs, depthStencilPassOperation) &&
228
229           ANGLE_PROP_EQ(*this, rhs, stencilCompareFunction) &&
230
231           ANGLE_PROP_EQ(*this, rhs, readMask) && ANGLE_PROP_EQ(*this, rhs, writeMask);
232}
233
234void StencilDesc::reset()
235{
236    stencilFailureOperation = depthFailureOperation = depthStencilPassOperation =
237        MTLStencilOperationKeep;
238
239    stencilCompareFunction = MTLCompareFunctionAlways;
240    readMask = writeMask = std::numeric_limits<uint32_t>::max() & mtl::kStencilMaskAll;
241}
242
243// DepthStencilDesc implementation
244DepthStencilDesc::DepthStencilDesc()
245{
246    memset(this, 0, sizeof(*this));
247}
248DepthStencilDesc::DepthStencilDesc(const DepthStencilDesc &src)
249{
250    memcpy(this, &src, sizeof(*this));
251}
252DepthStencilDesc::DepthStencilDesc(DepthStencilDesc &&src)
253{
254    memcpy(this, &src, sizeof(*this));
255}
256
257DepthStencilDesc &DepthStencilDesc::operator=(const DepthStencilDesc &src)
258{
259    memcpy(this, &src, sizeof(*this));
260    return *this;
261}
262
263bool DepthStencilDesc::operator==(const DepthStencilDesc &rhs) const
264{
265    return ANGLE_PROP_EQ(*this, rhs, backFaceStencil) &&
266           ANGLE_PROP_EQ(*this, rhs, frontFaceStencil) &&
267
268           ANGLE_PROP_EQ(*this, rhs, depthCompareFunction) &&
269
270           ANGLE_PROP_EQ(*this, rhs, depthWriteEnabled);
271}
272
273void DepthStencilDesc::reset()
274{
275    frontFaceStencil.reset();
276    backFaceStencil.reset();
277
278    depthCompareFunction = MTLCompareFunctionAlways;
279    depthWriteEnabled    = true;
280}
281
282void DepthStencilDesc::updateDepthTestEnabled(const gl::DepthStencilState &dsState)
283{
284    if (!dsState.depthTest)
285    {
286        depthCompareFunction = MTLCompareFunctionAlways;
287        depthWriteEnabled    = false;
288    }
289    else
290    {
291        updateDepthCompareFunc(dsState);
292        updateDepthWriteEnabled(dsState);
293    }
294}
295
296void DepthStencilDesc::updateDepthWriteEnabled(const gl::DepthStencilState &dsState)
297{
298    depthWriteEnabled = dsState.depthTest && dsState.depthMask;
299}
300
301void DepthStencilDesc::updateDepthCompareFunc(const gl::DepthStencilState &dsState)
302{
303    if (!dsState.depthTest)
304    {
305        return;
306    }
307    depthCompareFunction = GetCompareFunc(dsState.depthFunc);
308}
309
310void DepthStencilDesc::updateStencilTestEnabled(const gl::DepthStencilState &dsState)
311{
312    if (!dsState.stencilTest)
313    {
314        frontFaceStencil.stencilCompareFunction    = MTLCompareFunctionAlways;
315        frontFaceStencil.depthFailureOperation     = MTLStencilOperationKeep;
316        frontFaceStencil.depthStencilPassOperation = MTLStencilOperationKeep;
317        frontFaceStencil.writeMask                 = 0;
318
319        backFaceStencil.stencilCompareFunction    = MTLCompareFunctionAlways;
320        backFaceStencil.depthFailureOperation     = MTLStencilOperationKeep;
321        backFaceStencil.depthStencilPassOperation = MTLStencilOperationKeep;
322        backFaceStencil.writeMask                 = 0;
323    }
324    else
325    {
326        updateStencilFrontFuncs(dsState);
327        updateStencilFrontOps(dsState);
328        updateStencilFrontWriteMask(dsState);
329        updateStencilBackFuncs(dsState);
330        updateStencilBackOps(dsState);
331        updateStencilBackWriteMask(dsState);
332    }
333}
334
335void DepthStencilDesc::updateStencilFrontOps(const gl::DepthStencilState &dsState)
336{
337    if (!dsState.stencilTest)
338    {
339        return;
340    }
341    frontFaceStencil.stencilFailureOperation   = GetStencilOp(dsState.stencilFail);
342    frontFaceStencil.depthFailureOperation     = GetStencilOp(dsState.stencilPassDepthFail);
343    frontFaceStencil.depthStencilPassOperation = GetStencilOp(dsState.stencilPassDepthPass);
344}
345
346void DepthStencilDesc::updateStencilBackOps(const gl::DepthStencilState &dsState)
347{
348    if (!dsState.stencilTest)
349    {
350        return;
351    }
352    backFaceStencil.stencilFailureOperation   = GetStencilOp(dsState.stencilBackFail);
353    backFaceStencil.depthFailureOperation     = GetStencilOp(dsState.stencilBackPassDepthFail);
354    backFaceStencil.depthStencilPassOperation = GetStencilOp(dsState.stencilBackPassDepthPass);
355}
356
357void DepthStencilDesc::updateStencilFrontFuncs(const gl::DepthStencilState &dsState)
358{
359    if (!dsState.stencilTest)
360    {
361        return;
362    }
363    frontFaceStencil.stencilCompareFunction = GetCompareFunc(dsState.stencilFunc);
364    frontFaceStencil.readMask               = dsState.stencilMask & mtl::kStencilMaskAll;
365}
366
367void DepthStencilDesc::updateStencilBackFuncs(const gl::DepthStencilState &dsState)
368{
369    if (!dsState.stencilTest)
370    {
371        return;
372    }
373    backFaceStencil.stencilCompareFunction = GetCompareFunc(dsState.stencilBackFunc);
374    backFaceStencil.readMask               = dsState.stencilBackMask & mtl::kStencilMaskAll;
375}
376
377void DepthStencilDesc::updateStencilFrontWriteMask(const gl::DepthStencilState &dsState)
378{
379    if (!dsState.stencilTest)
380    {
381        return;
382    }
383    frontFaceStencil.writeMask = dsState.stencilWritemask & mtl::kStencilMaskAll;
384}
385
386void DepthStencilDesc::updateStencilBackWriteMask(const gl::DepthStencilState &dsState)
387{
388    if (!dsState.stencilTest)
389    {
390        return;
391    }
392    backFaceStencil.writeMask = dsState.stencilBackWritemask & mtl::kStencilMaskAll;
393}
394
395size_t DepthStencilDesc::hash() const
396{
397    return angle::ComputeGenericHash(*this);
398}
399
400// SamplerDesc implementation
401SamplerDesc::SamplerDesc()
402{
403    memset(this, 0, sizeof(*this));
404}
405SamplerDesc::SamplerDesc(const SamplerDesc &src)
406{
407    memcpy(this, &src, sizeof(*this));
408}
409SamplerDesc::SamplerDesc(SamplerDesc &&src)
410{
411    memcpy(this, &src, sizeof(*this));
412}
413
414SamplerDesc::SamplerDesc(const gl::SamplerState &glState) : SamplerDesc()
415{
416    rAddressMode = GetSamplerAddressMode(glState.getWrapR());
417    sAddressMode = GetSamplerAddressMode(glState.getWrapS());
418    tAddressMode = GetSamplerAddressMode(glState.getWrapT());
419
420    minFilter = GetFilter(glState.getMinFilter());
421    magFilter = GetFilter(glState.getMagFilter());
422    mipFilter = GetMipmapFilter(glState.getMinFilter());
423
424    maxAnisotropy = static_cast<uint32_t>(glState.getMaxAnisotropy());
425}
426
427SamplerDesc &SamplerDesc::operator=(const SamplerDesc &src)
428{
429    memcpy(this, &src, sizeof(*this));
430    return *this;
431}
432
433void SamplerDesc::reset()
434{
435    rAddressMode = MTLSamplerAddressModeClampToEdge;
436    sAddressMode = MTLSamplerAddressModeClampToEdge;
437    tAddressMode = MTLSamplerAddressModeClampToEdge;
438
439    minFilter = MTLSamplerMinMagFilterNearest;
440    magFilter = MTLSamplerMinMagFilterNearest;
441    mipFilter = MTLSamplerMipFilterNearest;
442
443    maxAnisotropy = 1;
444}
445
446bool SamplerDesc::operator==(const SamplerDesc &rhs) const
447{
448    return ANGLE_PROP_EQ(*this, rhs, rAddressMode) && ANGLE_PROP_EQ(*this, rhs, sAddressMode) &&
449           ANGLE_PROP_EQ(*this, rhs, tAddressMode) &&
450
451           ANGLE_PROP_EQ(*this, rhs, minFilter) && ANGLE_PROP_EQ(*this, rhs, magFilter) &&
452           ANGLE_PROP_EQ(*this, rhs, mipFilter) &&
453
454           ANGLE_PROP_EQ(*this, rhs, maxAnisotropy);
455}
456
457size_t SamplerDesc::hash() const
458{
459    return angle::ComputeGenericHash(*this);
460}
461
462// BlendDesc implementation
463bool BlendDesc::operator==(const BlendDesc &rhs) const
464{
465    return ANGLE_PROP_EQ(*this, rhs, writeMask) &&
466
467           ANGLE_PROP_EQ(*this, rhs, alphaBlendOperation) &&
468           ANGLE_PROP_EQ(*this, rhs, rgbBlendOperation) &&
469
470           ANGLE_PROP_EQ(*this, rhs, destinationAlphaBlendFactor) &&
471           ANGLE_PROP_EQ(*this, rhs, destinationRGBBlendFactor) &&
472           ANGLE_PROP_EQ(*this, rhs, sourceAlphaBlendFactor) &&
473           ANGLE_PROP_EQ(*this, rhs, sourceRGBBlendFactor) &&
474
475           ANGLE_PROP_EQ(*this, rhs, blendingEnabled);
476}
477
478void BlendDesc::reset()
479{
480    reset(MTLColorWriteMaskAll);
481}
482
483void BlendDesc::reset(MTLColorWriteMask _writeMask)
484{
485    writeMask = _writeMask;
486
487    blendingEnabled     = false;
488    alphaBlendOperation = rgbBlendOperation = MTLBlendOperationAdd;
489
490    destinationAlphaBlendFactor = destinationRGBBlendFactor = MTLBlendFactorZero;
491    sourceAlphaBlendFactor = sourceRGBBlendFactor = MTLBlendFactorOne;
492}
493
494void BlendDesc::updateWriteMask(const gl::BlendState &blendState)
495{
496    writeMask = MTLColorWriteMaskNone;
497    if (blendState.colorMaskRed)
498    {
499        writeMask |= MTLColorWriteMaskRed;
500    }
501    if (blendState.colorMaskGreen)
502    {
503        writeMask |= MTLColorWriteMaskGreen;
504    }
505    if (blendState.colorMaskBlue)
506    {
507        writeMask |= MTLColorWriteMaskBlue;
508    }
509    if (blendState.colorMaskAlpha)
510    {
511        writeMask |= MTLColorWriteMaskAlpha;
512    }
513}
514
515void BlendDesc::updateBlendFactors(const gl::BlendState &blendState)
516{
517    sourceRGBBlendFactor        = GetBlendFactor(blendState.sourceBlendRGB);
518    sourceAlphaBlendFactor      = GetBlendFactor(blendState.sourceBlendAlpha);
519    destinationRGBBlendFactor   = GetBlendFactor(blendState.destBlendRGB);
520    destinationAlphaBlendFactor = GetBlendFactor(blendState.destBlendAlpha);
521}
522
523void BlendDesc::updateBlendOps(const gl::BlendState &blendState)
524{
525    rgbBlendOperation   = GetBlendOp(blendState.blendEquationRGB);
526    alphaBlendOperation = GetBlendOp(blendState.blendEquationAlpha);
527}
528
529void BlendDesc::updateBlendEnabled(const gl::BlendState &blendState)
530{
531    blendingEnabled = blendState.blend;
532}
533
534// RenderPipelineColorAttachmentDesc implementation
535bool RenderPipelineColorAttachmentDesc::operator==(
536    const RenderPipelineColorAttachmentDesc &rhs) const
537{
538    if (!BlendDesc::operator==(rhs))
539    {
540        return false;
541    }
542    return ANGLE_PROP_EQ(*this, rhs, pixelFormat);
543}
544
545void RenderPipelineColorAttachmentDesc::reset()
546{
547    reset(MTLPixelFormatInvalid);
548}
549
550void RenderPipelineColorAttachmentDesc::reset(MTLPixelFormat format)
551{
552    reset(format, MTLColorWriteMaskAll);
553}
554
555void RenderPipelineColorAttachmentDesc::reset(MTLPixelFormat format, MTLColorWriteMask _writeMask)
556{
557    this->pixelFormat = format;
558
559    BlendDesc::reset(_writeMask);
560}
561
562void RenderPipelineColorAttachmentDesc::reset(MTLPixelFormat format, const BlendDesc &blendState)
563{
564    this->pixelFormat = format;
565
566    BlendDesc::operator=(blendState);
567}
568
569void RenderPipelineColorAttachmentDesc::update(const BlendDesc &blendState)
570{
571    BlendDesc::operator=(blendState);
572}
573
574// RenderPipelineOutputDesc implementation
575bool RenderPipelineOutputDesc::operator==(const RenderPipelineOutputDesc &rhs) const
576{
577    if (numColorAttachments != rhs.numColorAttachments)
578    {
579        return false;
580    }
581
582    for (uint8_t i = 0; i < numColorAttachments; ++i)
583    {
584        if (colorAttachments[i] != rhs.colorAttachments[i])
585        {
586            return false;
587        }
588    }
589
590    return ANGLE_PROP_EQ(*this, rhs, depthAttachmentPixelFormat) &&
591           ANGLE_PROP_EQ(*this, rhs, stencilAttachmentPixelFormat);
592}
593
594// RenderPipelineDesc implementation
595RenderPipelineDesc::RenderPipelineDesc()
596{
597    memset(this, 0, sizeof(*this));
598    rasterizationEnabled = true;
599}
600
601RenderPipelineDesc::RenderPipelineDesc(const RenderPipelineDesc &src)
602{
603    memcpy(this, &src, sizeof(*this));
604}
605
606RenderPipelineDesc::RenderPipelineDesc(RenderPipelineDesc &&src)
607{
608    memcpy(this, &src, sizeof(*this));
609}
610
611RenderPipelineDesc &RenderPipelineDesc::operator=(const RenderPipelineDesc &src)
612{
613    memcpy(this, &src, sizeof(*this));
614    return *this;
615}
616
617bool RenderPipelineDesc::operator==(const RenderPipelineDesc &rhs) const
618{
619    // NOTE(hqle): Use a faster way to compare, i.e take into account
620    // the number of active vertex attributes & render targets.
621    // If that way is used, hash() method must be changed also.
622    return memcmp(this, &rhs, sizeof(*this)) == 0;
623}
624
625size_t RenderPipelineDesc::hash() const
626{
627    return angle::ComputeGenericHash(*this);
628}
629
630// RenderPassDesc implementation
631RenderPassAttachmentDesc::RenderPassAttachmentDesc()
632{
633    reset();
634}
635
636void RenderPassAttachmentDesc::reset()
637{
638    texture.reset();
639    level              = 0;
640    slice              = 0;
641    loadAction         = MTLLoadActionLoad;
642    storeAction        = MTLStoreActionStore;
643    storeActionOptions = MTLStoreActionOptionNone;
644}
645
646bool RenderPassAttachmentDesc::equalIgnoreLoadStoreOptions(
647    const RenderPassAttachmentDesc &other) const
648{
649    return texture == other.texture && level == other.level && slice == other.slice;
650}
651
652bool RenderPassAttachmentDesc::operator==(const RenderPassAttachmentDesc &other) const
653{
654    if (!equalIgnoreLoadStoreOptions(other))
655    {
656        return false;
657    }
658
659    return loadAction == other.loadAction && storeAction == other.storeAction &&
660           storeActionOptions == other.storeActionOptions;
661}
662
663void RenderPassDesc::populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const
664{
665    populateRenderPipelineOutputDesc(MTLColorWriteMaskAll, outDesc);
666}
667
668void RenderPassDesc::populateRenderPipelineOutputDesc(MTLColorWriteMask colorWriteMask,
669                                                      RenderPipelineOutputDesc *outDesc) const
670{
671    // Default blend state.
672    BlendDesc blendState;
673    blendState.reset(colorWriteMask);
674
675    populateRenderPipelineOutputDesc(blendState, outDesc);
676}
677
678void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendState,
679                                                      RenderPipelineOutputDesc *outDesc) const
680{
681    auto &outputDescriptor               = *outDesc;
682    outputDescriptor.numColorAttachments = this->numColorAttachments;
683    for (uint32_t i = 0; i < this->numColorAttachments; ++i)
684    {
685        auto &renderPassColorAttachment = this->colorAttachments[i];
686        auto texture                    = renderPassColorAttachment.texture;
687
688        // Copy parameters from blend state
689        outputDescriptor.colorAttachments[i].update(blendState);
690
691        if (texture)
692        {
693
694            outputDescriptor.colorAttachments[i].pixelFormat = texture->pixelFormat();
695
696            // Combine the masks. This is useful when the texture is not supposed to have alpha
697            // channel such as GL_RGB8, however, Metal doesn't natively support 24 bit RGB, so
698            // we need to use RGBA texture, and then disable alpha write to this texture
699            outputDescriptor.colorAttachments[i].writeMask &= texture->getColorWritableMask();
700        }
701        else
702        {
703            outputDescriptor.colorAttachments[i].pixelFormat = MTLPixelFormatInvalid;
704        }
705    }
706
707    auto depthTexture = this->depthAttachment.texture;
708    outputDescriptor.depthAttachmentPixelFormat =
709        depthTexture ? depthTexture->pixelFormat() : MTLPixelFormatInvalid;
710
711    auto stencilTexture = this->stencilAttachment.texture;
712    outputDescriptor.stencilAttachmentPixelFormat =
713        stencilTexture ? stencilTexture->pixelFormat() : MTLPixelFormatInvalid;
714}
715
716bool RenderPassDesc::equalIgnoreLoadStoreOptions(const RenderPassDesc &other) const
717{
718    if (numColorAttachments != other.numColorAttachments)
719    {
720        return false;
721    }
722
723    for (uint32_t i = 0; i < numColorAttachments; ++i)
724    {
725        auto &renderPassColorAttachment = colorAttachments[i];
726        auto &otherRPAttachment         = other.colorAttachments[i];
727        if (!renderPassColorAttachment.equalIgnoreLoadStoreOptions(otherRPAttachment))
728        {
729            return false;
730        }
731    }
732
733    return depthAttachment.equalIgnoreLoadStoreOptions(other.depthAttachment) &&
734           stencilAttachment.equalIgnoreLoadStoreOptions(other.stencilAttachment);
735}
736
737bool RenderPassDesc::operator==(const RenderPassDesc &other) const
738{
739    if (numColorAttachments != other.numColorAttachments)
740    {
741        return false;
742    }
743
744    for (uint32_t i = 0; i < numColorAttachments; ++i)
745    {
746        auto &renderPassColorAttachment = colorAttachments[i];
747        auto &otherRPAttachment         = other.colorAttachments[i];
748        if (renderPassColorAttachment != (otherRPAttachment))
749        {
750            return false;
751        }
752    }
753
754    return depthAttachment == other.depthAttachment && stencilAttachment == other.stencilAttachment;
755}
756
757// Convert to Metal object
758AutoObjCObj<MTLRenderPassDescriptor> ToMetalObj(const RenderPassDesc &desc)
759{
760    ANGLE_MTL_OBJC_SCOPE
761    {
762        MTLRenderPassDescriptor *objCDesc = [MTLRenderPassDescriptor renderPassDescriptor];
763
764        for (uint32_t i = 0; i < desc.numColorAttachments; ++i)
765        {
766            [objCDesc.colorAttachments setObject:ToObjC(desc.colorAttachments[i])
767                              atIndexedSubscript:i];
768        }
769
770        ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, depthAttachment);
771        ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, stencilAttachment);
772
773        return objCDesc;
774    }
775}
776
777// RenderPipelineCache implementation
778RenderPipelineCache::RenderPipelineCache() {}
779
780RenderPipelineCache::~RenderPipelineCache() {}
781
782void RenderPipelineCache::setVertexShader(Context *context, id<MTLFunction> shader)
783{
784    mVertexShader.retainAssign(shader);
785
786    if (!shader)
787    {
788        clearPipelineStates();
789        return;
790    }
791
792    recreatePipelineStates(context);
793}
794
795void RenderPipelineCache::setFragmentShader(Context *context, id<MTLFunction> shader)
796{
797    mFragmentShader.retainAssign(shader);
798
799    if (!shader)
800    {
801        clearPipelineStates();
802        return;
803    }
804
805    recreatePipelineStates(context);
806}
807
808bool RenderPipelineCache::hasDefaultAttribs(const RenderPipelineDesc &rpdesc) const
809{
810    const VertexDesc &desc = rpdesc.vertexDescriptor;
811    for (uint8_t i = 0; i < desc.numAttribs; ++i)
812    {
813        if (desc.attributes[i].bufferIndex == kDefaultAttribsBindingIndex)
814        {
815            return true;
816        }
817    }
818
819    return false;
820}
821
822AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::getRenderPipelineState(
823    ContextMtl *context,
824    const RenderPipelineDesc &desc)
825{
826    auto insertDefaultAttribLayout = hasDefaultAttribs(desc);
827    int tableIdx                   = insertDefaultAttribLayout ? 1 : 0;
828    auto &table                    = mRenderPipelineStates[tableIdx];
829    auto ite                       = table.find(desc);
830    if (ite == table.end())
831    {
832        return insertRenderPipelineState(context, desc, insertDefaultAttribLayout);
833    }
834
835    return ite->second;
836}
837
838AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::insertRenderPipelineState(
839    Context *context,
840    const RenderPipelineDesc &desc,
841    bool insertDefaultAttribLayout)
842{
843    AutoObjCPtr<id<MTLRenderPipelineState>> newState =
844        createRenderPipelineState(context, desc, insertDefaultAttribLayout);
845
846    int tableIdx = insertDefaultAttribLayout ? 1 : 0;
847    auto re      = mRenderPipelineStates[tableIdx].insert(std::make_pair(desc, newState));
848    if (!re.second)
849    {
850        return nil;
851    }
852
853    return re.first->second;
854}
855
856AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelineState(
857    Context *context,
858    const RenderPipelineDesc &desc,
859    bool insertDefaultAttribLayout)
860{
861    ANGLE_MTL_OBJC_SCOPE
862    {
863        auto metalDevice = context->getMetalDevice();
864        AutoObjCObj<MTLRenderPipelineDescriptor> objCDesc =
865            ToObjC(mVertexShader, mFragmentShader, desc);
866
867        // special attribute slot for default attribute
868        if (insertDefaultAttribLayout)
869        {
870            MTLVertexBufferLayoutDescriptor *defaultAttribLayoutObjCDesc =
871                [[MTLVertexBufferLayoutDescriptor alloc] init];
872            defaultAttribLayoutObjCDesc.stepFunction = MTLVertexStepFunctionConstant;
873            defaultAttribLayoutObjCDesc.stepRate     = 0;
874            defaultAttribLayoutObjCDesc.stride       = kDefaultAttributeSize * kMaxVertexAttribs;
875
876            [objCDesc.get().vertexDescriptor.layouts
877                         setObject:[defaultAttribLayoutObjCDesc ANGLE_MTL_AUTORELEASE]
878                atIndexedSubscript:kDefaultAttribsBindingIndex];
879        }
880        // Create pipeline state
881        NSError *err  = nil;
882        auto newState = [metalDevice newRenderPipelineStateWithDescriptor:objCDesc error:&err];
883        if (err)
884        {
885            context->handleError(err, __FILE__, ANGLE_FUNCTION, __LINE__);
886            return nil;
887        }
888
889        return [newState ANGLE_MTL_AUTORELEASE];
890    }
891}
892
893void RenderPipelineCache::recreatePipelineStates(Context *context)
894{
895    for (int hasDefaultAttrib = 0; hasDefaultAttrib <= 1; ++hasDefaultAttrib)
896    {
897        for (auto &ite : mRenderPipelineStates[hasDefaultAttrib])
898        {
899            if (ite.second == nil)
900            {
901                continue;
902            }
903
904            ite.second = createRenderPipelineState(context, ite.first, hasDefaultAttrib);
905        }
906    }
907}
908
909void RenderPipelineCache::clear()
910{
911    mVertexShader   = nil;
912    mFragmentShader = nil;
913    clearPipelineStates();
914}
915
916void RenderPipelineCache::clearPipelineStates()
917{
918    mRenderPipelineStates[0].clear();
919    mRenderPipelineStates[1].clear();
920}
921
922// StateCache implementation
923StateCache::StateCache() {}
924
925StateCache::~StateCache() {}
926
927AutoObjCPtr<id<MTLDepthStencilState>> StateCache::getNullDepthStencilState(id<MTLDevice> device)
928{
929    if (!mNullDepthStencilState)
930    {
931        DepthStencilDesc desc;
932        desc.reset();
933        ASSERT(desc.frontFaceStencil.stencilCompareFunction == MTLCompareFunctionAlways);
934        desc.depthWriteEnabled = false;
935        mNullDepthStencilState = getDepthStencilState(device, desc);
936    }
937    return mNullDepthStencilState;
938}
939
940AutoObjCPtr<id<MTLDepthStencilState>> StateCache::getDepthStencilState(id<MTLDevice> metalDevice,
941                                                                       const DepthStencilDesc &desc)
942{
943    ANGLE_MTL_OBJC_SCOPE
944    {
945        auto ite = mDepthStencilStates.find(desc);
946        if (ite == mDepthStencilStates.end())
947        {
948            AutoObjCObj<MTLDepthStencilDescriptor> objCDesc = ToObjC(desc);
949            AutoObjCPtr<id<MTLDepthStencilState>> newState =
950                [[metalDevice newDepthStencilStateWithDescriptor:objCDesc] ANGLE_MTL_AUTORELEASE];
951
952            auto re = mDepthStencilStates.insert(std::make_pair(desc, newState));
953            if (!re.second)
954            {
955                return nil;
956            }
957
958            ite = re.first;
959        }
960
961        return ite->second;
962    }
963}
964
965AutoObjCPtr<id<MTLSamplerState>> StateCache::getSamplerState(id<MTLDevice> metalDevice,
966                                                             const SamplerDesc &desc)
967{
968    ANGLE_MTL_OBJC_SCOPE
969    {
970        auto ite = mSamplerStates.find(desc);
971        if (ite == mSamplerStates.end())
972        {
973            AutoObjCObj<MTLSamplerDescriptor> objCDesc = ToObjC(desc);
974            AutoObjCPtr<id<MTLSamplerState>> newState =
975                [[metalDevice newSamplerStateWithDescriptor:objCDesc] ANGLE_MTL_AUTORELEASE];
976
977            auto re = mSamplerStates.insert(std::make_pair(desc, newState));
978            if (!re.second)
979                return nil;
980
981            ite = re.first;
982        }
983
984        return ite->second;
985    }
986}
987
988AutoObjCPtr<id<MTLSamplerState>> StateCache::getNullSamplerState(Context *context)
989{
990    return getNullSamplerState(context->getMetalDevice());
991}
992
993AutoObjCPtr<id<MTLSamplerState>> StateCache::getNullSamplerState(id<MTLDevice> device)
994{
995    SamplerDesc desc;
996    desc.reset();
997
998    return getSamplerState(device, desc);
999}
1000
1001void StateCache::clear()
1002{
1003    mNullDepthStencilState = nil;
1004    mDepthStencilStates.clear();
1005    mSamplerStates.clear();
1006}
1007}  // namespace mtl
1008}  // namespace rx
1009