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