• 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.h:
7 //    Defines the class interface for StateCache, RenderPipelineCache and various
8 //    C struct versions of Metal sampler, depth stencil, render pass, render pipeline descriptors.
9 //
10 
11 #ifndef LIBANGLE_RENDERER_METAL_MTL_STATE_CACHE_H_
12 #define LIBANGLE_RENDERER_METAL_MTL_STATE_CACHE_H_
13 
14 #import <Metal/Metal.h>
15 
16 #include <unordered_map>
17 
18 #include "libANGLE/State.h"
19 #include "libANGLE/angletypes.h"
20 #include "libANGLE/renderer/metal/mtl_common.h"
21 #include "libANGLE/renderer/metal/mtl_resources.h"
22 
23 static inline bool operator==(const MTLClearColor &lhs, const MTLClearColor &rhs);
24 
25 namespace rx
26 {
27 class ContextMtl;
28 
29 namespace mtl
30 {
31 struct StencilDesc
32 {
33     bool operator==(const StencilDesc &rhs) const;
34 
35     // Set default values
36     void reset();
37 
38     MTLStencilOperation stencilFailureOperation;
39     MTLStencilOperation depthFailureOperation;
40     MTLStencilOperation depthStencilPassOperation;
41 
42     MTLCompareFunction stencilCompareFunction;
43 
44     uint32_t readMask;
45     uint32_t writeMask;
46 };
47 
48 struct DepthStencilDesc
49 {
50     DepthStencilDesc();
51     DepthStencilDesc(const DepthStencilDesc &src);
52     DepthStencilDesc(DepthStencilDesc &&src);
53 
54     DepthStencilDesc &operator=(const DepthStencilDesc &src);
55 
56     bool operator==(const DepthStencilDesc &rhs) const;
57 
58     // Set default values.
59     // Default is depth/stencil test disabled. Depth/stencil write enabled.
60     void reset();
61 
62     size_t hash() const;
63 
64     void updateDepthTestEnabled(const gl::DepthStencilState &dsState);
65     void updateDepthWriteEnabled(const gl::DepthStencilState &dsState);
66     void updateDepthCompareFunc(const gl::DepthStencilState &dsState);
67     void updateStencilTestEnabled(const gl::DepthStencilState &dsState);
68     void updateStencilFrontOps(const gl::DepthStencilState &dsState);
69     void updateStencilBackOps(const gl::DepthStencilState &dsState);
70     void updateStencilFrontFuncs(const gl::DepthStencilState &dsState);
71     void updateStencilBackFuncs(const gl::DepthStencilState &dsState);
72     void updateStencilFrontWriteMask(const gl::DepthStencilState &dsState);
73     void updateStencilBackWriteMask(const gl::DepthStencilState &dsState);
74 
75     StencilDesc backFaceStencil;
76     StencilDesc frontFaceStencil;
77 
78     MTLCompareFunction depthCompareFunction;
79     bool depthWriteEnabled;
80 };
81 
82 struct SamplerDesc
83 {
84     SamplerDesc();
85     SamplerDesc(const SamplerDesc &src);
86     SamplerDesc(SamplerDesc &&src);
87 
88     explicit SamplerDesc(const gl::SamplerState &glState);
89 
90     SamplerDesc &operator=(const SamplerDesc &src);
91 
92     // Set default values. All filters are nearest, and addresModes are clamp to edge.
93     void reset();
94 
95     bool operator==(const SamplerDesc &rhs) const;
96 
97     size_t hash() const;
98 
99     MTLSamplerAddressMode rAddressMode;
100     MTLSamplerAddressMode sAddressMode;
101     MTLSamplerAddressMode tAddressMode;
102 
103     MTLSamplerMinMagFilter minFilter;
104     MTLSamplerMinMagFilter magFilter;
105     MTLSamplerMipFilter mipFilter;
106 
107     uint32_t maxAnisotropy;
108 };
109 
110 struct VertexAttributeDesc
111 {
112     inline bool operator==(const VertexAttributeDesc &rhs) const
113     {
114         return format == rhs.format && offset == rhs.offset && bufferIndex == rhs.bufferIndex;
115     }
116     inline bool operator!=(const VertexAttributeDesc &rhs) const { return !(*this == rhs); }
117     MTLVertexFormat format;
118     NSUInteger offset;
119     NSUInteger bufferIndex;
120 };
121 
122 struct VertexBufferLayoutDesc
123 {
124     inline bool operator==(const VertexBufferLayoutDesc &rhs) const
125     {
126         return stepFunction == rhs.stepFunction && stepRate == rhs.stepRate && stride == rhs.stride;
127     }
128     inline bool operator!=(const VertexBufferLayoutDesc &rhs) const { return !(*this == rhs); }
129 
130     MTLVertexStepFunction stepFunction;
131     NSUInteger stepRate;
132     NSUInteger stride;
133 };
134 
135 struct VertexDesc
136 {
137     VertexAttributeDesc attributes[kMaxVertexAttribs];
138     VertexBufferLayoutDesc layouts[kMaxVertexAttribs];
139 
140     uint8_t numAttribs;
141     uint8_t numBufferLayouts;
142 };
143 
144 struct BlendDesc
145 {
146     bool operator==(const BlendDesc &rhs) const;
147     BlendDesc &operator=(const BlendDesc &src) = default;
148 
149     // Set default values
150     void reset();
151     void reset(MTLColorWriteMask writeMask);
152 
153     void updateWriteMask(const gl::BlendState &blendState);
154     void updateBlendFactors(const gl::BlendState &blendState);
155     void updateBlendOps(const gl::BlendState &blendState);
156     void updateBlendEnabled(const gl::BlendState &blendState);
157 
158     MTLColorWriteMask writeMask;
159 
160     MTLBlendOperation alphaBlendOperation;
161     MTLBlendOperation rgbBlendOperation;
162 
163     MTLBlendFactor destinationAlphaBlendFactor;
164     MTLBlendFactor destinationRGBBlendFactor;
165     MTLBlendFactor sourceAlphaBlendFactor;
166     MTLBlendFactor sourceRGBBlendFactor;
167 
168     bool blendingEnabled;
169 };
170 
171 struct RenderPipelineColorAttachmentDesc : public BlendDesc
172 {
173     bool operator==(const RenderPipelineColorAttachmentDesc &rhs) const;
174     inline bool operator!=(const RenderPipelineColorAttachmentDesc &rhs) const
175     {
176         return !(*this == rhs);
177     }
178 
179     // Set default values
180     void reset();
181     void reset(MTLPixelFormat format);
182     void reset(MTLPixelFormat format, MTLColorWriteMask writeMask);
183     void reset(MTLPixelFormat format, const BlendDesc &blendState);
184 
185     void update(const BlendDesc &blendState);
186 
187     MTLPixelFormat pixelFormat;
188 };
189 
190 struct RenderPipelineOutputDesc
191 {
192     bool operator==(const RenderPipelineOutputDesc &rhs) const;
193 
194     RenderPipelineColorAttachmentDesc colorAttachments[kMaxRenderTargets];
195     MTLPixelFormat depthAttachmentPixelFormat;
196     MTLPixelFormat stencilAttachmentPixelFormat;
197 
198     uint8_t numColorAttachments;
199 };
200 
201 // Some SDK levels don't declare MTLPrimitiveTopologyClass. Needs to do compile time check here:
202 #if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) && ANGLE_IOS_DEPLOY_TARGET < __IPHONE_12_0
203 #    define ANGLE_MTL_PRIMITIVE_TOPOLOGY_CLASS_AVAILABLE 0
204 using PrimitiveTopologyClass                                     = uint32_t;
205 constexpr PrimitiveTopologyClass kPrimitiveTopologyClassTriangle = 0;
206 constexpr PrimitiveTopologyClass kPrimitiveTopologyClassPoint    = 0;
207 #else
208 #    define ANGLE_MTL_PRIMITIVE_TOPOLOGY_CLASS_AVAILABLE 1
209 using PrimitiveTopologyClass = MTLPrimitiveTopologyClass;
210 constexpr PrimitiveTopologyClass kPrimitiveTopologyClassTriangle =
211     MTLPrimitiveTopologyClassTriangle;
212 constexpr PrimitiveTopologyClass kPrimitiveTopologyClassPoint = MTLPrimitiveTopologyClassPoint;
213 #endif
214 
215 struct RenderPipelineDesc
216 {
217     RenderPipelineDesc();
218     RenderPipelineDesc(const RenderPipelineDesc &src);
219     RenderPipelineDesc(RenderPipelineDesc &&src);
220 
221     RenderPipelineDesc &operator=(const RenderPipelineDesc &src);
222 
223     bool operator==(const RenderPipelineDesc &rhs) const;
224 
225     size_t hash() const;
226 
227     VertexDesc vertexDescriptor;
228 
229     RenderPipelineOutputDesc outputDescriptor;
230 
231     PrimitiveTopologyClass inputPrimitiveTopology;
232 
233     bool rasterizationEnabled;
234 };
235 
236 struct RenderPassAttachmentDesc
237 {
238     RenderPassAttachmentDesc();
239     // Set default values
240     void reset();
241 
242     bool equalIgnoreLoadStoreOptions(const RenderPassAttachmentDesc &other) const;
243     bool operator==(const RenderPassAttachmentDesc &other) const;
244 
245     TextureRef texture;
246     uint32_t level;
247     uint32_t slice;
248     MTLLoadAction loadAction;
249     MTLStoreAction storeAction;
250     MTLStoreActionOptions storeActionOptions;
251 };
252 
253 struct RenderPassColorAttachmentDesc : public RenderPassAttachmentDesc
254 {
255     inline bool operator==(const RenderPassColorAttachmentDesc &other) const
256     {
257         return RenderPassAttachmentDesc::operator==(other) && clearColor == other.clearColor;
258     }
259     inline bool operator!=(const RenderPassColorAttachmentDesc &other) const
260     {
261         return !(*this == other);
262     }
263     MTLClearColor clearColor = {0, 0, 0, 0};
264 };
265 
266 struct RenderPassDepthAttachmentDesc : public RenderPassAttachmentDesc
267 {
268     inline bool operator==(const RenderPassDepthAttachmentDesc &other) const
269     {
270         return RenderPassAttachmentDesc::operator==(other) && clearDepth == other.clearDepth;
271     }
272     inline bool operator!=(const RenderPassDepthAttachmentDesc &other) const
273     {
274         return !(*this == other);
275     }
276 
277     double clearDepth = 0;
278 };
279 
280 struct RenderPassStencilAttachmentDesc : public RenderPassAttachmentDesc
281 {
282     inline bool operator==(const RenderPassStencilAttachmentDesc &other) const
283     {
284         return RenderPassAttachmentDesc::operator==(other) && clearStencil == other.clearStencil;
285     }
286     inline bool operator!=(const RenderPassStencilAttachmentDesc &other) const
287     {
288         return !(*this == other);
289     }
290     uint32_t clearStencil = 0;
291 };
292 
293 struct RenderPassDesc
294 {
295     RenderPassColorAttachmentDesc colorAttachments[kMaxRenderTargets];
296     RenderPassDepthAttachmentDesc depthAttachment;
297     RenderPassStencilAttachmentDesc stencilAttachment;
298 
299     // This will populate the RenderPipelineOutputDesc with default blend state and
300     // MTLColorWriteMaskAll
301     void populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const;
302     // This will populate the RenderPipelineOutputDesc with default blend state and the specified
303     // MTLColorWriteMask
304     void populateRenderPipelineOutputDesc(MTLColorWriteMask colorWriteMask,
305                                           RenderPipelineOutputDesc *outDesc) const;
306     // This will populate the RenderPipelineOutputDesc with the specified blend state
307     void populateRenderPipelineOutputDesc(const BlendDesc &blendState,
308                                           RenderPipelineOutputDesc *outDesc) const;
309 
310     bool equalIgnoreLoadStoreOptions(const RenderPassDesc &other) const;
311     bool operator==(const RenderPassDesc &other) const;
312     inline bool operator!=(const RenderPassDesc &other) const { return !(*this == other); }
313 
314     uint32_t numColorAttachments = 0;
315 };
316 
317 // convert to Metal object
318 AutoObjCObj<MTLRenderPassDescriptor> ToMetalObj(const RenderPassDesc &desc);
319 }  // namespace mtl
320 }  // namespace rx
321 
322 namespace std
323 {
324 
325 template <>
326 struct hash<rx::mtl::DepthStencilDesc>
327 {
328     size_t operator()(const rx::mtl::DepthStencilDesc &key) const { return key.hash(); }
329 };
330 
331 template <>
332 struct hash<rx::mtl::SamplerDesc>
333 {
334     size_t operator()(const rx::mtl::SamplerDesc &key) const { return key.hash(); }
335 };
336 
337 template <>
338 struct hash<rx::mtl::RenderPipelineDesc>
339 {
340     size_t operator()(const rx::mtl::RenderPipelineDesc &key) const { return key.hash(); }
341 };
342 
343 }  // namespace std
344 
345 namespace rx
346 {
347 namespace mtl
348 {
349 // render pipeline state cache per shader program
350 class RenderPipelineCache final : angle::NonCopyable
351 {
352   public:
353     RenderPipelineCache();
354     ~RenderPipelineCache();
355 
356     void setVertexShader(Context *context, id<MTLFunction> shader);
357     void setFragmentShader(Context *context, id<MTLFunction> shader);
358 
359     id<MTLFunction> getVertexShader() { return mVertexShader.get(); }
360     id<MTLFunction> getFragmentShader() { return mFragmentShader.get(); }
361 
362     AutoObjCPtr<id<MTLRenderPipelineState>> getRenderPipelineState(ContextMtl *context,
363                                                                    const RenderPipelineDesc &desc);
364 
365     void clear();
366 
367   protected:
368     AutoObjCPtr<id<MTLFunction>> mVertexShader   = nil;
369     AutoObjCPtr<id<MTLFunction>> mFragmentShader = nil;
370 
371   private:
372     void clearPipelineStates();
373     void recreatePipelineStates(Context *context);
374     AutoObjCPtr<id<MTLRenderPipelineState>> insertRenderPipelineState(
375         Context *context,
376         const RenderPipelineDesc &desc,
377         bool insertDefaultAttribLayout);
378     AutoObjCPtr<id<MTLRenderPipelineState>> createRenderPipelineState(
379         Context *context,
380         const RenderPipelineDesc &desc,
381         bool insertDefaultAttribLayout);
382 
383     bool hasDefaultAttribs(const RenderPipelineDesc &desc) const;
384 
385     // One table with default attrib and one table without.
386     std::unordered_map<RenderPipelineDesc, AutoObjCPtr<id<MTLRenderPipelineState>>>
387         mRenderPipelineStates[2];
388 };
389 
390 class StateCache final : angle::NonCopyable
391 {
392   public:
393     StateCache();
394     ~StateCache();
395 
396     // Null depth stencil state has depth/stecil read & write disabled.
397     inline AutoObjCPtr<id<MTLDepthStencilState>> getNullDepthStencilState(Context *context)
398     {
399         return getNullDepthStencilState(context->getMetalDevice());
400     }
401     AutoObjCPtr<id<MTLDepthStencilState>> getNullDepthStencilState(id<MTLDevice> device);
402     AutoObjCPtr<id<MTLDepthStencilState>> getDepthStencilState(id<MTLDevice> device,
403                                                                const DepthStencilDesc &desc);
404     AutoObjCPtr<id<MTLSamplerState>> getSamplerState(id<MTLDevice> device, const SamplerDesc &desc);
405     // Null sampler state uses default SamplerDesc
406     AutoObjCPtr<id<MTLSamplerState>> getNullSamplerState(Context *context);
407     AutoObjCPtr<id<MTLSamplerState>> getNullSamplerState(id<MTLDevice> device);
408     void clear();
409 
410   private:
411     AutoObjCPtr<id<MTLDepthStencilState>> mNullDepthStencilState = nil;
412     std::unordered_map<DepthStencilDesc, AutoObjCPtr<id<MTLDepthStencilState>>> mDepthStencilStates;
413     std::unordered_map<SamplerDesc, AutoObjCPtr<id<MTLSamplerState>>> mSamplerStates;
414 };
415 
416 }  // namespace mtl
417 }  // namespace rx
418 
419 static inline bool operator==(const rx::mtl::VertexDesc &lhs, const rx::mtl::VertexDesc &rhs)
420 {
421     if (lhs.numAttribs != rhs.numAttribs || lhs.numBufferLayouts != rhs.numBufferLayouts)
422     {
423         return false;
424     }
425     for (uint8_t i = 0; i < lhs.numAttribs; ++i)
426     {
427         if (lhs.attributes[i] != rhs.attributes[i])
428         {
429             return false;
430         }
431     }
432     for (uint8_t i = 0; i < lhs.numBufferLayouts; ++i)
433     {
434         if (lhs.layouts[i] != rhs.layouts[i])
435         {
436             return false;
437         }
438     }
439     return true;
440 }
441 
442 static inline bool operator==(const MTLClearColor &lhs, const MTLClearColor &rhs)
443 {
444     return lhs.red == rhs.red && lhs.green == rhs.green && lhs.blue == rhs.blue &&
445            lhs.alpha == rhs.alpha;
446 }
447 
448 #endif /* LIBANGLE_RENDERER_METAL_MTL_STATE_CACHE_H_ */
449