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