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// ProgramMtl.mm: 7// Implements the class methods for ProgramMtl. 8// 9 10#include "libANGLE/renderer/metal/ProgramMtl.h" 11 12#include <TargetConditionals.h> 13 14#include <sstream> 15 16#include "common/debug.h" 17#include "common/system_utils.h" 18#include "libANGLE/Context.h" 19#include "libANGLE/ProgramLinkedResources.h" 20#include "libANGLE/renderer/metal/BufferMtl.h" 21#include "libANGLE/renderer/metal/CompilerMtl.h" 22#include "libANGLE/renderer/metal/ContextMtl.h" 23#include "libANGLE/renderer/metal/DisplayMtl.h" 24#include "libANGLE/renderer/metal/TextureMtl.h" 25#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h" 26#include "libANGLE/renderer/metal/mtl_utils.h" 27#include "libANGLE/renderer/renderer_utils.h" 28 29#if ANGLE_ENABLE_METAL_SPIRV 30# include "libANGLE/renderer/metal/mtl_glslang_utils.h" 31#endif 32 33namespace rx 34{ 35 36namespace 37{ 38 39#define SHADER_ENTRY_NAME @"main0" 40#if ANGLE_ENABLE_METAL_SPIRV 41constexpr char kSpirvCrossSpecConstSuffix[] = "_tmp"; 42#endif 43template <typename T> 44class ANGLE_NO_DISCARD ScopedAutoClearVector 45{ 46 public: 47 ScopedAutoClearVector(std::vector<T> *array) : mArray(*array) {} 48 ~ScopedAutoClearVector() { mArray.clear(); } 49 50 private: 51 std::vector<T> &mArray; 52}; 53 54angle::Result StreamUniformBufferData(ContextMtl *contextMtl, 55 mtl::BufferPool *dynamicBuffer, 56 const uint8_t *sourceData, 57 size_t bytesToAllocate, 58 size_t sizeToCopy, 59 mtl::BufferRef *bufferOut, 60 size_t *bufferOffsetOut) 61{ 62 uint8_t *dst = nullptr; 63 dynamicBuffer->releaseInFlightBuffers(contextMtl); 64 ANGLE_TRY(dynamicBuffer->allocate(contextMtl, bytesToAllocate, &dst, bufferOut, bufferOffsetOut, 65 nullptr)); 66 memcpy(dst, sourceData, sizeToCopy); 67 68 ANGLE_TRY(dynamicBuffer->commit(contextMtl)); 69 return angle::Result::Continue; 70} 71 72void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms, 73 gl::Shader *shader, 74 sh::BlockLayoutMap *blockLayoutMapOut, 75 size_t *blockSizeOut) 76{ 77 if (uniforms.empty()) 78 { 79 *blockSizeOut = 0; 80 return; 81 } 82 83 sh::Std140BlockEncoder blockEncoder; 84 sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut); 85 86 size_t blockSize = blockEncoder.getCurrentOffset(); 87 88 // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized. 89 if (blockSize == 0) 90 { 91 *blockSizeOut = 0; 92 return; 93 } 94 95 // Need to round up to multiple of vec4 96 *blockSizeOut = roundUp(blockSize, static_cast<size_t>(16)); 97 return; 98} 99 100inline NSDictionary<NSString *, NSObject *> *getDefaultSubstitutionDictionary() 101{ 102 return @{}; 103} 104 105template <typename T> 106void UpdateDefaultUniformBlock(GLsizei count, 107 uint32_t arrayIndex, 108 int componentCount, 109 const T *v, 110 const sh::BlockMemberInfo &layoutInfo, 111 angle::MemoryBuffer *uniformData) 112{ 113 const int elementSize = sizeof(T) * componentCount; 114 115 uint8_t *dst = uniformData->data() + layoutInfo.offset; 116 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize) 117 { 118 uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride; 119 uint8_t *writePtr = dst + arrayOffset; 120 ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size()); 121 memcpy(writePtr, v, elementSize * count); 122 } 123 else 124 { 125 // Have to respect the arrayStride between each element of the array. 126 int maxIndex = arrayIndex + count; 127 for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex; 128 writeIndex++, readIndex++) 129 { 130 const int arrayOffset = writeIndex * layoutInfo.arrayStride; 131 uint8_t *writePtr = dst + arrayOffset; 132 const T *readPtr = v + (readIndex * componentCount); 133 ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size()); 134 memcpy(writePtr, readPtr, elementSize); 135 } 136 } 137} 138 139template <typename T> 140void ReadFromDefaultUniformBlock(int componentCount, 141 uint32_t arrayIndex, 142 T *dst, 143 const sh::BlockMemberInfo &layoutInfo, 144 const angle::MemoryBuffer *uniformData) 145{ 146 ASSERT(layoutInfo.offset != -1); 147 148 const int elementSize = sizeof(T) * componentCount; 149 const uint8_t *source = uniformData->data() + layoutInfo.offset; 150 151 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize) 152 { 153 const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride; 154 memcpy(dst, readPtr, elementSize); 155 } 156 else 157 { 158 // Have to respect the arrayStride between each element of the array. 159 const int arrayOffset = arrayIndex * layoutInfo.arrayStride; 160 const uint8_t *readPtr = source + arrayOffset; 161 memcpy(dst, readPtr, elementSize); 162 } 163} 164 165class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory 166{ 167 public: 168 sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); } 169}; 170 171void InitArgumentBufferEncoder(mtl::Context *context, 172 id<MTLFunction> function, 173 uint32_t bufferIndex, 174 ProgramArgumentBufferEncoderMtl *encoder) 175{ 176 encoder->metalArgBufferEncoder = [function newArgumentEncoderWithBufferIndex:bufferIndex]; 177 if (encoder->metalArgBufferEncoder) 178 { 179 encoder->bufferPool.initialize(context, encoder->metalArgBufferEncoder.get().encodedLength, 180 mtl::kArgumentBufferOffsetAlignment, 0); 181 } 182} 183 184} // namespace 185 186// ProgramArgumentBufferEncoderMtl implementation 187void ProgramArgumentBufferEncoderMtl::reset(ContextMtl *contextMtl) 188{ 189 metalArgBufferEncoder = nil; 190 bufferPool.destroy(contextMtl); 191} 192 193// ProgramShaderObjVariantMtl implementation 194void ProgramShaderObjVariantMtl::reset(ContextMtl *contextMtl) 195{ 196 metalShader = nil; 197 198 uboArgBufferEncoder.reset(contextMtl); 199 200 translatedSrcInfo = nullptr; 201} 202 203// ProgramMtl implementation 204ProgramMtl::DefaultUniformBlock::DefaultUniformBlock() {} 205 206ProgramMtl::DefaultUniformBlock::~DefaultUniformBlock() = default; 207 208ProgramMtl::ProgramMtl(const gl::ProgramState &state) 209 : ProgramImpl(state), 210 mProgramHasFlatAttributes(false), 211 mShadowCompareModes(), 212 mMetalRenderPipelineCache(this), 213 mAuxBufferPool(nullptr) 214{} 215 216ProgramMtl::~ProgramMtl() {} 217 218void ProgramMtl::destroy(const gl::Context *context) 219{ 220 auto contextMtl = mtl::GetImpl(context); 221 if (mAuxBufferPool) 222 { 223 mAuxBufferPool->destroy(contextMtl); 224 delete mAuxBufferPool; 225 mAuxBufferPool = nullptr; 226 } 227 reset(contextMtl); 228} 229 230void ProgramMtl::reset(ContextMtl *context) 231{ 232 mProgramHasFlatAttributes = false; 233 234 for (auto &block : mDefaultUniformBlocks) 235 { 236 block.uniformLayout.clear(); 237 } 238 239 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 240 { 241 mMslShaderTranslateInfo[shaderType].reset(); 242 mCurrentShaderVariants[shaderType] = nullptr; 243 } 244 mMslXfbOnlyVertexShaderInfo.reset(); 245 246 for (ProgramShaderObjVariantMtl &var : mVertexShaderVariants) 247 { 248 var.reset(context); 249 } 250 for (ProgramShaderObjVariantMtl &var : mFragmentShaderVariants) 251 { 252 var.reset(context); 253 } 254 if (mAuxBufferPool) 255 { 256 if (mAuxBufferPool->reset(context, mtl::kDefaultUniformsMaxSize * 2, 257 mtl::kUniformBufferSettingOffsetMinAlignment, 258 3) != angle::Result::Continue) 259 { 260 mAuxBufferPool->destroy(context); 261 delete mAuxBufferPool; 262 mAuxBufferPool = nullptr; 263 } 264 } 265 mMetalRenderPipelineCache.clear(); 266} 267 268void ProgramMtl::saveTranslatedShaders(gl::BinaryOutputStream *stream) 269{ 270 // Write out shader sources for all shader types 271 for (const gl::ShaderType shaderType : gl::AllShaderTypes()) 272 { 273 stream->writeString(mMslShaderTranslateInfo[shaderType].metalShaderSource); 274 } 275 stream->writeString(mMslXfbOnlyVertexShaderInfo.metalShaderSource); 276} 277 278void ProgramMtl::loadTranslatedShaders(gl::BinaryInputStream *stream) 279{ 280 // Read in shader sources for all shader types 281 for (const gl::ShaderType shaderType : gl::AllShaderTypes()) 282 { 283 mMslShaderTranslateInfo[shaderType].metalShaderSource = stream->readString(); 284 } 285 mMslXfbOnlyVertexShaderInfo.metalShaderSource = stream->readString(); 286} 287 288std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context, 289 gl::BinaryInputStream *stream, 290 gl::InfoLog &infoLog) 291{ 292 293 return std::make_unique<LinkEventDone>(linkTranslatedShaders(context, stream, infoLog)); 294} 295 296void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream) 297{ 298 saveTranslatedShaders(stream); 299 saveShaderInternalInfo(stream); 300 saveDefaultUniformBlocksInfo(stream); 301} 302 303void ProgramMtl::setBinaryRetrievableHint(bool retrievable) 304{ 305 UNIMPLEMENTED(); 306} 307 308void ProgramMtl::setSeparable(bool separable) 309{ 310 UNIMPLEMENTED(); 311} 312 313std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context, 314 const gl::ProgramLinkedResources &resources, 315 gl::InfoLog &infoLog, 316 const gl::ProgramMergedVaryings &mergedVaryings) 317{ 318 // Link resources before calling GetShaderSource to make sure they are ready for the set/binding 319 // assignment done in that function. 320 linkResources(resources); 321 322 // NOTE(hqle): Parallelize linking. 323 return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog)); 324} 325 326#if ANGLE_ENABLE_METAL_SPIRV 327angle::Result ProgramMtl::linkImplSpirv(const gl::Context *glContext, 328 const gl::ProgramLinkedResources &resources, 329 gl::InfoLog &infoLog) 330{ 331 ContextMtl *contextMtl = mtl::GetImpl(glContext); 332 333 reset(contextMtl); 334 335 ANGLE_TRY(initDefaultUniformBlocks(glContext)); 336 337 // Gather variable info and transform sources. 338 gl::ShaderMap<const angle::spirv::Blob *> spirvBlobs; 339 ShaderInterfaceVariableInfoMap variableInfoMap; 340 ShaderInterfaceVariableInfoMap xfbOnlyVariableInfoMap; 341 mtl::GlslangGetShaderSpirvCode(mState, resources, &spirvBlobs, &variableInfoMap, 342 &xfbOnlyVariableInfoMap); 343 344 // Convert GLSL to spirv code 345 gl::ShaderMap<angle::spirv::Blob> shaderCodes; 346 gl::ShaderMap<angle::spirv::Blob> xfbOnlyShaderCodes; // only vertex shader is needed. 347 ANGLE_TRY(mtl::GlslangTransformSpirvCode(mState.getExecutable().getLinkedShaderStages(), 348 spirvBlobs, false, variableInfoMap, &shaderCodes)); 349 350 if (!mState.getLinkedTransformFeedbackVaryings().empty()) 351 { 352 gl::ShaderBitSet onlyVS; 353 onlyVS.set(gl::ShaderType::Vertex); 354 ANGLE_TRY(mtl::GlslangTransformSpirvCode(onlyVS, spirvBlobs, true, xfbOnlyVariableInfoMap, 355 &xfbOnlyShaderCodes)); 356 } 357 358 // Convert spirv code to MSL 359 ANGLE_TRY(mtl::SpirvCodeToMsl(contextMtl, mState, xfbOnlyVariableInfoMap, &shaderCodes, 360 &xfbOnlyShaderCodes[gl::ShaderType::Vertex], 361 &mMslShaderTranslateInfo, &mMslXfbOnlyVertexShaderInfo)); 362 363 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 364 { 365 // Create actual Metal shader library 366 ANGLE_TRY(createMslShaderLib(contextMtl, shaderType, infoLog, 367 &mMslShaderTranslateInfo[shaderType], 368 getDefaultSubstitutionDictionary())); 369 } 370 371 return angle::Result::Continue; 372} 373#endif 374 375angle::Result ProgramMtl::linkImplDirect(const gl::Context *glContext, 376 const gl::ProgramLinkedResources &resources, 377 gl::InfoLog &infoLog) 378{ 379 ContextMtl *contextMtl = mtl::GetImpl(glContext); 380 381 reset(contextMtl); 382 ANGLE_TRY(initDefaultUniformBlocks(glContext)); 383 ShaderInterfaceVariableInfoMap variableInfoMap; 384 385 gl::ShaderMap<std::string> shaderSources; 386 gl::ShaderMap<std::string> translatedMslShaders; 387 mtl::MSLGetShaderSource(mState, resources, &shaderSources, &variableInfoMap); 388 389 ANGLE_TRY(mtl::GlslangGetMSL(glContext, mState, contextMtl->getCaps(), shaderSources, 390 variableInfoMap, &mMslShaderTranslateInfo, &translatedMslShaders, 391 mState.getExecutable().getTransformFeedbackBufferCount())); 392 mMslXfbOnlyVertexShaderInfo = mMslShaderTranslateInfo[gl::ShaderType::Vertex]; 393 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 394 { 395 // Create actual Metal shader 396 ANGLE_TRY(createMslShaderLib(contextMtl, shaderType, infoLog, 397 &mMslShaderTranslateInfo[shaderType], 398 getDefaultSubstitutionDictionary())); 399 } 400 return angle::Result::Continue; 401} 402 403void ProgramMtl::linkUpdateHasFlatAttributes() 404{ 405 mProgramHasFlatAttributes = false; 406 407 const auto &programInputs = mState.getProgramInputs(); 408 for (auto &attribute : programInputs) 409 { 410 if (attribute.interpolation == sh::INTERPOLATION_FLAT) 411 { 412 mProgramHasFlatAttributes = true; 413 return; 414 } 415 } 416 417 const auto &flatVaryings = 418 mState.getAttachedShader(gl::ShaderType::Vertex)->getOutputVaryings(); 419 for (auto &attribute : flatVaryings) 420 { 421 if (attribute.interpolation == sh::INTERPOLATION_FLAT) 422 { 423 mProgramHasFlatAttributes = true; 424 return; 425 } 426 } 427} 428 429angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, 430 const gl::ProgramLinkedResources &resources, 431 gl::InfoLog &infoLog) 432{ 433#if ANGLE_ENABLE_METAL_SPIRV 434 ContextMtl *contextMtl = mtl::GetImpl(glContext); 435 if (contextMtl->getDisplay()->useDirectToMetalCompiler()) 436 { 437 ANGLE_TRY(linkImplDirect(glContext, resources, infoLog)); 438 } 439 else 440 { 441 ANGLE_TRY(linkImplSpirv(glContext, resources, infoLog)); 442 } 443#else 444 ANGLE_TRY(linkImplDirect(glContext, resources, infoLog)); 445#endif 446 linkUpdateHasFlatAttributes(); 447 return angle::Result::Continue; 448} 449 450angle::Result ProgramMtl::linkTranslatedShaders(const gl::Context *glContext, 451 gl::BinaryInputStream *stream, 452 gl::InfoLog &infoLog) 453{ 454 ContextMtl *contextMtl = mtl::GetImpl(glContext); 455 // NOTE(hqle): No transform feedbacks for now, since we only support ES 2.0 atm 456 457 reset(contextMtl); 458 459 loadTranslatedShaders(stream); 460 loadShaderInternalInfo(stream); 461 ANGLE_TRY(loadDefaultUniformBlocksInfo(glContext, stream)); 462 ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Vertex, infoLog, 463 &mMslShaderTranslateInfo[gl::ShaderType::Vertex], 464 getDefaultSubstitutionDictionary())); 465 ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Fragment, infoLog, 466 &mMslShaderTranslateInfo[gl::ShaderType::Fragment], 467 getDefaultSubstitutionDictionary())); 468 469 return angle::Result::Continue; 470} 471 472mtl::BufferPool *ProgramMtl::getBufferPool(ContextMtl *context) 473{ 474 if (mAuxBufferPool == nullptr) 475 { 476 mAuxBufferPool = new mtl::BufferPool(true); 477 mAuxBufferPool->initialize(context, mtl::kDefaultUniformsMaxSize * 2, 478 mtl::kUniformBufferSettingOffsetMinAlignment, 3); 479 } 480 return mAuxBufferPool; 481} 482void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources) 483{ 484 Std140BlockLayoutEncoderFactory std140EncoderFactory; 485 gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory); 486 487 linker.linkResources(mState, resources); 488} 489 490angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext) 491{ 492 // Process vertex and fragment uniforms into std140 packing. 493 gl::ShaderMap<sh::BlockLayoutMap> layoutMap; 494 gl::ShaderMap<size_t> requiredBufferSize; 495 requiredBufferSize.fill(0); 496 497 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 498 { 499 gl::Shader *shader = mState.getAttachedShader(shaderType); 500 if (shader) 501 { 502 const std::vector<sh::Uniform> &uniforms = shader->getUniforms(); 503 InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType], 504 &requiredBufferSize[shaderType]); 505 } 506 } 507 508 // Init the default block layout info. 509 const auto &uniforms = mState.getUniforms(); 510 const auto &uniformLocations = mState.getUniformLocations(); 511 for (size_t locSlot = 0; locSlot < uniformLocations.size(); ++locSlot) 512 { 513 const gl::VariableLocation &location = uniformLocations[locSlot]; 514 gl::ShaderMap<sh::BlockMemberInfo> layoutInfo; 515 516 if (location.used() && !location.ignored) 517 { 518 const gl::LinkedUniform &uniform = uniforms[location.index]; 519 if (uniform.isInDefaultBlock() && !uniform.isSampler()) 520 { 521 std::string uniformName = uniform.name; 522 if (uniform.isArray()) 523 { 524 // Gets the uniform name without the [0] at the end. 525 uniformName = gl::ParseResourceName(uniformName, nullptr); 526 } 527 528 bool found = false; 529 530 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 531 { 532 auto it = layoutMap[shaderType].find(uniformName); 533 if (it != layoutMap[shaderType].end()) 534 { 535 found = true; 536 layoutInfo[shaderType] = it->second; 537 } 538 } 539 540 ASSERT(found); 541 } 542 } 543 544 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 545 { 546 mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]); 547 } 548 } 549 550 return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize); 551} 552 553angle::Result ProgramMtl::resizeDefaultUniformBlocksMemory( 554 const gl::Context *glContext, 555 const gl::ShaderMap<size_t> &requiredBufferSize) 556{ 557 ContextMtl *contextMtl = mtl::GetImpl(glContext); 558 559 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 560 { 561 if (requiredBufferSize[shaderType] > 0) 562 { 563 ASSERT(requiredBufferSize[shaderType] <= mtl::kDefaultUniformsMaxSize); 564 565 if (!mDefaultUniformBlocks[shaderType].uniformData.resize( 566 requiredBufferSize[shaderType])) 567 { 568 ANGLE_MTL_CHECK(contextMtl, false, GL_OUT_OF_MEMORY); 569 } 570 571 // Initialize uniform buffer memory to zero by default. 572 mDefaultUniformBlocks[shaderType].uniformData.fill(0); 573 mDefaultUniformBlocksDirty.set(shaderType); 574 } 575 } 576 577 return angle::Result::Continue; 578} 579 580angle::Result ProgramMtl::getSpecializedShader(ContextMtl *context, 581 gl::ShaderType shaderType, 582 const mtl::RenderPipelineDesc &renderPipelineDesc, 583 id<MTLFunction> *shaderOut) 584{ 585 static_assert(YES == 1, "YES should have value of 1"); 586#if ANGLE_ENABLE_METAL_SPIRV 587 const bool useSpirv = !context->getDisplay()->useDirectToMetalCompiler(); 588#endif 589 590 mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType]; 591 ProgramShaderObjVariantMtl *shaderVariant; 592 mtl::AutoObjCObj<MTLFunctionConstantValues> funcConstants; 593 594 if (shaderType == gl::ShaderType::Vertex) 595 { 596 // For vertex shader, we need to create 3 variants, one with emulated rasterization 597 // discard, one with true rasterization discard and one without. 598 shaderVariant = &mVertexShaderVariants[renderPipelineDesc.rasterizationType]; 599 if (shaderVariant->metalShader) 600 { 601 // Already created. 602 *shaderOut = shaderVariant->metalShader; 603 return angle::Result::Continue; 604 } 605 606 if (renderPipelineDesc.rasterizationType == mtl::RenderPipelineRasterization::Disabled) 607 { 608 // Special case: XFB output only vertex shader. 609 ASSERT(!mState.getLinkedTransformFeedbackVaryings().empty()); 610 translatedMslInfo = &mMslXfbOnlyVertexShaderInfo; 611 if (!translatedMslInfo->metalLibrary) 612 { 613 // Lazily compile XFB only shader 614 gl::InfoLog infoLog; 615 ANGLE_TRY(createMslShaderLib(context, shaderType, infoLog, 616 &mMslXfbOnlyVertexShaderInfo, 617 @{@"TRANSFORM_FEEDBACK_ENABLED" : @"1"})); 618 translatedMslInfo->metalLibrary.get().label = @"TransformFeedback"; 619 } 620 } 621 622 ANGLE_MTL_OBJC_SCOPE 623 { 624 BOOL emulateDiscard = renderPipelineDesc.rasterizationType == 625 mtl::RenderPipelineRasterization::EmulatedDiscard; 626 627 NSString *discardEnabledStr; 628#if ANGLE_ENABLE_METAL_SPIRV 629 if (useSpirv) 630 { 631 discardEnabledStr = 632 [NSString stringWithFormat:@"%s%s", sh::mtl::kRasterizerDiscardEnabledConstName, 633 kSpirvCrossSpecConstSuffix]; 634 } 635 else 636#endif 637 { 638 discardEnabledStr = 639 [NSString stringWithUTF8String:sh::mtl::kRasterizerDiscardEnabledConstName]; 640 } 641 642 funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]); 643 [funcConstants setConstantValue:&emulateDiscard 644 type:MTLDataTypeBool 645 withName:discardEnabledStr]; 646 } 647 } // if (shaderType == gl::ShaderType::Vertex) 648 else if (shaderType == gl::ShaderType::Fragment) 649 { 650 // For fragment shader, we need to create 2 variants, one with sample coverage mask 651 // disabled, one with the mask enabled. 652 BOOL emulateCoverageMask = renderPipelineDesc.emulateCoverageMask; 653 shaderVariant = &mFragmentShaderVariants[emulateCoverageMask]; 654 if (shaderVariant->metalShader) 655 { 656 // Already created. 657 *shaderOut = shaderVariant->metalShader; 658 return angle::Result::Continue; 659 } 660 661 ANGLE_MTL_OBJC_SCOPE 662 { 663 NSString *coverageMaskEnabledStr; 664#if ANGLE_ENABLE_METAL_SPIRV 665 if (useSpirv) 666 { 667 coverageMaskEnabledStr = 668 [NSString stringWithFormat:@"%s%s", sh::mtl::kCoverageMaskEnabledConstName, 669 kSpirvCrossSpecConstSuffix]; 670 } 671 else 672#endif 673 { 674 coverageMaskEnabledStr = 675 [NSString stringWithUTF8String:sh::mtl::kCoverageMaskEnabledConstName]; 676 } 677 678 NSString *depthWriteEnabledStr = 679 [NSString stringWithUTF8String:sh::mtl::kDepthWriteEnabledConstName]; 680 681 funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]); 682 [funcConstants setConstantValue:&emulateCoverageMask 683 type:MTLDataTypeBool 684 withName:coverageMaskEnabledStr]; 685 686 MTLPixelFormat depthPixelFormat = 687 (MTLPixelFormat)renderPipelineDesc.outputDescriptor.depthAttachmentPixelFormat; 688 BOOL fragDepthWriteEnabled = depthPixelFormat != MTLPixelFormatInvalid; 689 [funcConstants setConstantValue:&fragDepthWriteEnabled 690 type:MTLDataTypeBool 691 withName:depthWriteEnabledStr]; 692 } 693 694 } // gl::ShaderType::Fragment 695 else 696 { 697 UNREACHABLE(); 698 return angle::Result::Stop; 699 } 700 [funcConstants 701 setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareGradient.enabled) 702 type:MTLDataTypeBool 703 withName:@"ANGLEUseSampleCompareGradient"]; 704 [funcConstants 705 setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareLod.enabled) 706 type:MTLDataTypeBool 707 withName:@"ANGLEUseSampleCompareLod"]; 708 // Create Metal shader object 709 ANGLE_MTL_OBJC_SCOPE 710 { 711 ANGLE_TRY(CreateMslShader(context, translatedMslInfo->metalLibrary, SHADER_ENTRY_NAME, 712 funcConstants.get(), &shaderVariant->metalShader)); 713 } 714 715 // Store reference to the translated source for easily querying mapped bindings later. 716 shaderVariant->translatedSrcInfo = translatedMslInfo; 717 718 // Initialize argument buffer encoder if required 719 if (translatedMslInfo->hasUBOArgumentBuffer) 720 { 721 InitArgumentBufferEncoder(context, shaderVariant->metalShader, 722 mtl::kUBOArgumentBufferBindingIndex, 723 &shaderVariant->uboArgBufferEncoder); 724 } 725 726 *shaderOut = shaderVariant->metalShader; 727 728 return angle::Result::Continue; 729} 730 731bool ProgramMtl::hasSpecializedShader(gl::ShaderType shaderType, 732 const mtl::RenderPipelineDesc &renderPipelineDesc) 733{ 734 return true; 735} 736 737angle::Result ProgramMtl::createMslShaderLib( 738 ContextMtl *context, 739 gl::ShaderType shaderType, 740 gl::InfoLog &infoLog, 741 mtl::TranslatedShaderInfo *translatedMslInfo, 742 NSDictionary<NSString *, NSObject *> *substitutionMacros) 743{ 744 ANGLE_MTL_OBJC_SCOPE 745 { 746 const mtl::ContextDevice &metalDevice = context->getMetalDevice(); 747 748 // Convert to actual binary shader 749 mtl::AutoObjCPtr<NSError *> err = nil; 750 bool disableFastMath = (context->getDisplay()->getFeatures().intelDisableFastMath.enabled && 751 translatedMslInfo->hasInvariantOrAtan); 752 translatedMslInfo->metalLibrary = 753 mtl::CreateShaderLibrary(metalDevice, translatedMslInfo->metalShaderSource, 754 substitutionMacros, !disableFastMath, &err); 755 if (err && !translatedMslInfo->metalLibrary) 756 { 757 std::ostringstream ss; 758 ss << "Internal error compiling shader with Metal backend.\n"; 759#if !defined(NDEBUG) 760 ss << err.get().localizedDescription.UTF8String << "\n"; 761 ss << "-----\n"; 762 ss << translatedMslInfo->metalShaderSource; 763 ss << "-----\n"; 764#else 765 ss << "Please submit this shader, or website as a bug to https://bugs.webkit.org\n"; 766#endif 767 ERR() << ss.str(); 768 769 infoLog << ss.str(); 770 771 ANGLE_MTL_CHECK(context, false, GL_INVALID_OPERATION); 772 } 773 774 return angle::Result::Continue; 775 } 776} 777 778void ProgramMtl::saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream) 779{ 780 // Serializes the uniformLayout data of mDefaultUniformBlocks 781 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 782 { 783 const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size(); 784 stream->writeInt<size_t>(uniformCount); 785 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) 786 { 787 sh::BlockMemberInfo &blockInfo = 788 mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex]; 789 gl::WriteBlockMemberInfo(stream, blockInfo); 790 } 791 } 792 793 // Serializes required uniform block memory sizes 794 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 795 { 796 stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size()); 797 } 798} 799 800angle::Result ProgramMtl::loadDefaultUniformBlocksInfo(const gl::Context *glContext, 801 gl::BinaryInputStream *stream) 802{ 803 gl::ShaderMap<size_t> requiredBufferSize; 804 requiredBufferSize.fill(0); 805 806 // Deserializes the uniformLayout data of mDefaultUniformBlocks 807 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 808 { 809 const size_t uniformCount = stream->readInt<size_t>(); 810 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) 811 { 812 sh::BlockMemberInfo blockInfo; 813 gl::LoadBlockMemberInfo(stream, &blockInfo); 814 mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo); 815 } 816 } 817 818 // Deserializes required uniform block memory sizes 819 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 820 { 821 requiredBufferSize[shaderType] = stream->readInt<size_t>(); 822 } 823 824 return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize); 825} 826 827void ProgramMtl::saveShaderInternalInfo(gl::BinaryOutputStream *stream) 828{ 829 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 830 { 831 stream->writeInt<int>(mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer); 832 for (const mtl::SamplerBinding &binding : 833 mMslShaderTranslateInfo[shaderType].actualSamplerBindings) 834 { 835 stream->writeInt<uint32_t>(binding.textureBinding); 836 stream->writeInt<uint32_t>(binding.samplerBinding); 837 } 838 839 for (uint32_t uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings) 840 { 841 stream->writeInt<uint32_t>(uboBinding); 842 } 843 stream->writeBool(mMslShaderTranslateInfo[shaderType].hasInvariantOrAtan); 844 } 845 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 846 { 847 stream->writeInt( 848 mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]); 849 } 850 851 // Write out XFB info. 852 { 853 stream->writeInt<int>(mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer); 854 for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings) 855 { 856 stream->writeInt<uint32_t>(binding.textureBinding); 857 stream->writeInt<uint32_t>(binding.samplerBinding); 858 } 859 860 for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings) 861 { 862 stream->writeInt<uint32_t>(uboBinding); 863 } 864 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 865 { 866 stream->writeInt(mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]); 867 } 868 } 869 870 stream->writeBool(mProgramHasFlatAttributes); 871} 872 873void ProgramMtl::loadShaderInternalInfo(gl::BinaryInputStream *stream) 874{ 875 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 876 { 877 mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer = stream->readInt<int>() != 0; 878 for (mtl::SamplerBinding &binding : 879 mMslShaderTranslateInfo[shaderType].actualSamplerBindings) 880 { 881 binding.textureBinding = stream->readInt<uint32_t>(); 882 binding.samplerBinding = stream->readInt<uint32_t>(); 883 } 884 885 for (uint32_t &uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings) 886 { 887 uboBinding = stream->readInt<uint32_t>(); 888 } 889 mMslShaderTranslateInfo[shaderType].hasInvariantOrAtan = stream->readBool(); 890 } 891 892 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 893 { 894 stream->readInt( 895 &mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]); 896 } 897 // Load Transform Feedback info 898 { 899 mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer = stream->readInt<int>() != 0; 900 for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings) 901 { 902 binding.textureBinding = stream->readInt<uint32_t>(); 903 binding.samplerBinding = stream->readInt<uint32_t>(); 904 } 905 906 for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings) 907 { 908 uboBinding = stream->readInt<uint32_t>(); 909 } 910 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 911 { 912 stream->readInt(&mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]); 913 } 914 mMslXfbOnlyVertexShaderInfo.metalLibrary = nullptr; 915 } 916 917 mProgramHasFlatAttributes = stream->readBool(); 918} 919 920GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog) 921{ 922 // No-op. The spec is very vague about the behavior of validation. 923 return GL_TRUE; 924} 925 926template <typename T> 927void ProgramMtl::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType) 928{ 929 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 930 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 931 932 if (linkedUniform.isSampler()) 933 { 934 // Sampler binding has changed. 935 mSamplerBindingsDirty.set(); 936 return; 937 } 938 939 if (linkedUniform.typeInfo->type == entryPointType) 940 { 941 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 942 { 943 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 944 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 945 946 // Assume an offset of -1 means the block is unused. 947 if (layoutInfo.offset == -1) 948 { 949 continue; 950 } 951 952 const GLint componentCount = linkedUniform.typeInfo->componentCount; 953 UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo, 954 &uniformBlock.uniformData); 955 mDefaultUniformBlocksDirty.set(shaderType); 956 } 957 } 958 else 959 { 960 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 961 { 962 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 963 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 964 965 // Assume an offset of -1 means the block is unused. 966 if (layoutInfo.offset == -1) 967 { 968 continue; 969 } 970 971 const GLint componentCount = linkedUniform.typeInfo->componentCount; 972 973 ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType)); 974 975 GLint initialArrayOffset = 976 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset; 977 for (GLint i = 0; i < count; i++) 978 { 979 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset; 980 GLint *dest = 981 reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset); 982 const T *source = v + i * componentCount; 983 984 for (int c = 0; c < componentCount; c++) 985 { 986 dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE; 987 } 988 } 989 990 mDefaultUniformBlocksDirty.set(shaderType); 991 } 992 } 993} 994 995template <typename T> 996void ProgramMtl::getUniformImpl(GLint location, T *v, GLenum entryPointType) const 997{ 998 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 999 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 1000 1001 ASSERT(!linkedUniform.isSampler()); 1002 1003 const gl::ShaderType shaderType = linkedUniform.getFirstShaderTypeWhereActive(); 1004 ASSERT(shaderType != gl::ShaderType::InvalidEnum); 1005 1006 const DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 1007 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1008 1009 ASSERT(linkedUniform.typeInfo->componentType == entryPointType || 1010 linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType)); 1011 1012 if (gl::IsMatrixType(linkedUniform.type)) 1013 { 1014 const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset + 1015 (locationInfo.arrayIndex * layoutInfo.arrayStride); 1016 GetMatrixUniform(linkedUniform.type, v, reinterpret_cast<const T *>(ptrToElement), false); 1017 } 1018 else 1019 { 1020 ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex, 1021 v, layoutInfo, &uniformBlock.uniformData); 1022 } 1023} 1024 1025void ProgramMtl::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) 1026{ 1027 setUniformImpl(location, count, v, GL_FLOAT); 1028} 1029 1030void ProgramMtl::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) 1031{ 1032 setUniformImpl(location, count, v, GL_FLOAT_VEC2); 1033} 1034 1035void ProgramMtl::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) 1036{ 1037 setUniformImpl(location, count, v, GL_FLOAT_VEC3); 1038} 1039 1040void ProgramMtl::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) 1041{ 1042 setUniformImpl(location, count, v, GL_FLOAT_VEC4); 1043} 1044 1045void ProgramMtl::setUniform1iv(GLint startLocation, GLsizei count, const GLint *v) 1046{ 1047 setUniformImpl(startLocation, count, v, GL_INT); 1048} 1049 1050void ProgramMtl::setUniform2iv(GLint location, GLsizei count, const GLint *v) 1051{ 1052 setUniformImpl(location, count, v, GL_INT_VEC2); 1053} 1054 1055void ProgramMtl::setUniform3iv(GLint location, GLsizei count, const GLint *v) 1056{ 1057 setUniformImpl(location, count, v, GL_INT_VEC3); 1058} 1059 1060void ProgramMtl::setUniform4iv(GLint location, GLsizei count, const GLint *v) 1061{ 1062 setUniformImpl(location, count, v, GL_INT_VEC4); 1063} 1064 1065void ProgramMtl::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) 1066{ 1067 setUniformImpl(location, count, v, GL_UNSIGNED_INT); 1068} 1069 1070void ProgramMtl::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) 1071{ 1072 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2); 1073} 1074 1075void ProgramMtl::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) 1076{ 1077 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3); 1078} 1079 1080void ProgramMtl::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) 1081{ 1082 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4); 1083} 1084 1085template <int cols, int rows> 1086void ProgramMtl::setUniformMatrixfv(GLint location, 1087 GLsizei count, 1088 GLboolean transpose, 1089 const GLfloat *value) 1090{ 1091 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 1092 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 1093 1094 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1095 { 1096 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 1097 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1098 1099 // Assume an offset of -1 means the block is unused. 1100 if (layoutInfo.offset == -1) 1101 { 1102 continue; 1103 } 1104 1105 SetFloatUniformMatrixGLSL<cols, rows>::Run( 1106 locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value, 1107 uniformBlock.uniformData.data() + layoutInfo.offset); 1108 1109 mDefaultUniformBlocksDirty.set(shaderType); 1110 } 1111} 1112 1113void ProgramMtl::setUniformMatrix2fv(GLint location, 1114 GLsizei count, 1115 GLboolean transpose, 1116 const GLfloat *value) 1117{ 1118 setUniformMatrixfv<2, 2>(location, count, transpose, value); 1119} 1120 1121void ProgramMtl::setUniformMatrix3fv(GLint location, 1122 GLsizei count, 1123 GLboolean transpose, 1124 const GLfloat *value) 1125{ 1126 setUniformMatrixfv<3, 3>(location, count, transpose, value); 1127} 1128 1129void ProgramMtl::setUniformMatrix4fv(GLint location, 1130 GLsizei count, 1131 GLboolean transpose, 1132 const GLfloat *value) 1133{ 1134 setUniformMatrixfv<4, 4>(location, count, transpose, value); 1135} 1136 1137void ProgramMtl::setUniformMatrix2x3fv(GLint location, 1138 GLsizei count, 1139 GLboolean transpose, 1140 const GLfloat *value) 1141{ 1142 setUniformMatrixfv<2, 3>(location, count, transpose, value); 1143} 1144 1145void ProgramMtl::setUniformMatrix3x2fv(GLint location, 1146 GLsizei count, 1147 GLboolean transpose, 1148 const GLfloat *value) 1149{ 1150 setUniformMatrixfv<3, 2>(location, count, transpose, value); 1151} 1152 1153void ProgramMtl::setUniformMatrix2x4fv(GLint location, 1154 GLsizei count, 1155 GLboolean transpose, 1156 const GLfloat *value) 1157{ 1158 setUniformMatrixfv<2, 4>(location, count, transpose, value); 1159} 1160 1161void ProgramMtl::setUniformMatrix4x2fv(GLint location, 1162 GLsizei count, 1163 GLboolean transpose, 1164 const GLfloat *value) 1165{ 1166 setUniformMatrixfv<4, 2>(location, count, transpose, value); 1167} 1168 1169void ProgramMtl::setUniformMatrix3x4fv(GLint location, 1170 GLsizei count, 1171 GLboolean transpose, 1172 const GLfloat *value) 1173{ 1174 setUniformMatrixfv<3, 4>(location, count, transpose, value); 1175} 1176 1177void ProgramMtl::setUniformMatrix4x3fv(GLint location, 1178 GLsizei count, 1179 GLboolean transpose, 1180 const GLfloat *value) 1181{ 1182 setUniformMatrixfv<4, 3>(location, count, transpose, value); 1183} 1184 1185void ProgramMtl::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const 1186{ 1187 getUniformImpl(location, params, GL_FLOAT); 1188} 1189 1190void ProgramMtl::getUniformiv(const gl::Context *context, GLint location, GLint *params) const 1191{ 1192 getUniformImpl(location, params, GL_INT); 1193} 1194 1195void ProgramMtl::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const 1196{ 1197 getUniformImpl(location, params, GL_UNSIGNED_INT); 1198} 1199 1200angle::Result ProgramMtl::setupDraw(const gl::Context *glContext, 1201 mtl::RenderCommandEncoder *cmdEncoder, 1202 const mtl::RenderPipelineDesc &pipelineDesc, 1203 bool pipelineDescChanged, 1204 bool forceTexturesSetting, 1205 bool uniformBuffersDirty) 1206{ 1207 ContextMtl *context = mtl::GetImpl(glContext); 1208 if (pipelineDescChanged) 1209 { 1210 // Render pipeline state needs to be changed 1211 id<MTLRenderPipelineState> pipelineState = 1212 mMetalRenderPipelineCache.getRenderPipelineState(context, pipelineDesc); 1213 if (!pipelineState) 1214 { 1215 // Error already logged inside getRenderPipelineState() 1216 return angle::Result::Stop; 1217 } 1218 cmdEncoder->setRenderPipelineState(pipelineState); 1219 1220 // We need to rebind uniform buffers & textures also 1221 mDefaultUniformBlocksDirty.set(); 1222 mSamplerBindingsDirty.set(); 1223 1224 // Cache current shader variant references for easier querying. 1225 mCurrentShaderVariants[gl::ShaderType::Vertex] = 1226 &mVertexShaderVariants[pipelineDesc.rasterizationType]; 1227 mCurrentShaderVariants[gl::ShaderType::Fragment] = 1228 pipelineDesc.rasterizationEnabled() 1229 ? &mFragmentShaderVariants[pipelineDesc.emulateCoverageMask] 1230 : nullptr; 1231 } 1232 1233 ANGLE_TRY(commitUniforms(context, cmdEncoder)); 1234 ANGLE_TRY(updateTextures(glContext, cmdEncoder, forceTexturesSetting)); 1235 1236 if (uniformBuffersDirty || pipelineDescChanged) 1237 { 1238 ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc)); 1239 } 1240 1241 if (pipelineDescChanged) 1242 { 1243 ANGLE_TRY(updateXfbBuffers(context, cmdEncoder, pipelineDesc)); 1244 } 1245 1246 return angle::Result::Continue; 1247} 1248 1249angle::Result ProgramMtl::commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder) 1250{ 1251 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1252 { 1253 if (!mDefaultUniformBlocksDirty[shaderType] || !mCurrentShaderVariants[shaderType]) 1254 { 1255 continue; 1256 } 1257 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 1258 1259 if (!uniformBlock.uniformData.size()) 1260 { 1261 continue; 1262 } 1263 // If we exceed the default uniform max size, try to allocate a buffer. Worst case 1264 // scenario, fall back on a large setBytes. 1265 bool needsCommitUniform = true; 1266 if (needsCommitUniform) 1267 { 1268 ASSERT(uniformBlock.uniformData.size() <= mtl::kDefaultUniformsMaxSize); 1269 cmdEncoder->setBytes(shaderType, uniformBlock.uniformData.data(), 1270 uniformBlock.uniformData.size(), 1271 mtl::kDefaultUniformsBindingIndex); 1272 } 1273 1274 mDefaultUniformBlocksDirty.reset(shaderType); 1275 } 1276 1277 return angle::Result::Continue; 1278} 1279 1280angle::Result ProgramMtl::updateTextures(const gl::Context *glContext, 1281 mtl::RenderCommandEncoder *cmdEncoder, 1282 bool forceUpdate) 1283{ 1284 ContextMtl *contextMtl = mtl::GetImpl(glContext); 1285 const auto &glState = glContext->getState(); 1286 const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache(); 1287 1288 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1289 { 1290 if ((!mSamplerBindingsDirty[shaderType] && !forceUpdate) || 1291 !mCurrentShaderVariants[shaderType]) 1292 { 1293 continue; 1294 } 1295 1296 const mtl::TranslatedShaderInfo &shaderInfo = 1297 mCurrentShaderVariants[shaderType]->translatedSrcInfo 1298 ? *mCurrentShaderVariants[shaderType]->translatedSrcInfo 1299 : mMslShaderTranslateInfo[shaderType]; 1300 bool hasDepthSampler = false; 1301 1302 for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size(); 1303 ++textureIndex) 1304 { 1305 const gl::SamplerBinding &samplerBinding = mState.getSamplerBindings()[textureIndex]; 1306 const mtl::SamplerBinding &mslBinding = shaderInfo.actualSamplerBindings[textureIndex]; 1307 if (mslBinding.textureBinding >= mtl::kMaxShaderSamplers) 1308 { 1309 // No binding assigned 1310 continue; 1311 } 1312 1313 gl::TextureType textureType = samplerBinding.textureType; 1314 1315 for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size(); 1316 ++arrayElement) 1317 { 1318 GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement]; 1319 gl::Texture *texture = completeTextures[textureUnit]; 1320 gl::Sampler *sampler = contextMtl->getState().getSampler(textureUnit); 1321 uint32_t textureSlot = mslBinding.textureBinding + arrayElement; 1322 uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement; 1323 if (!texture) 1324 { 1325 ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, &texture)); 1326 } 1327 const gl::SamplerState *samplerState = 1328 sampler ? &sampler->getSamplerState() : &texture->getSamplerState(); 1329 TextureMtl *textureMtl = mtl::GetImpl(texture); 1330 if (samplerBinding.format == gl::SamplerFormat::Shadow) 1331 { 1332 hasDepthSampler = true; 1333 mShadowCompareModes[textureSlot] = mtl::MslGetShaderShadowCompareMode( 1334 samplerState->getCompareMode(), samplerState->getCompareFunc()); 1335 } 1336 ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler, 1337 textureSlot, samplerSlot)); 1338 } // for array elements 1339 } // for sampler bindings 1340 1341 if (hasDepthSampler) 1342 { 1343 cmdEncoder->setData(shaderType, mShadowCompareModes, 1344 mtl::kShadowSamplerCompareModesBindingIndex); 1345 } 1346 } // for shader types 1347 1348 return angle::Result::Continue; 1349} 1350 1351angle::Result ProgramMtl::updateUniformBuffers(ContextMtl *context, 1352 mtl::RenderCommandEncoder *cmdEncoder, 1353 const mtl::RenderPipelineDesc &pipelineDesc) 1354{ 1355 const std::vector<gl::InterfaceBlock> &blocks = mState.getUniformBlocks(); 1356 if (blocks.empty()) 1357 { 1358 return angle::Result::Continue; 1359 } 1360 1361 // This array is only used inside this function and its callees. 1362 ScopedAutoClearVector<uint32_t> scopeArrayClear(&mArgumentBufferRenderStageUsages); 1363 ScopedAutoClearVector<std::pair<mtl::BufferRef, uint32_t>> scopeArrayClear2( 1364 &mLegalizedOffsetedUniformBuffers); 1365 mArgumentBufferRenderStageUsages.resize(blocks.size()); 1366 mLegalizedOffsetedUniformBuffers.resize(blocks.size()); 1367 1368 ANGLE_TRY(legalizeUniformBufferOffsets(context, blocks)); 1369 1370 const gl::State &glState = context->getState(); 1371 1372 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1373 { 1374 if (!mCurrentShaderVariants[shaderType]) 1375 { 1376 continue; 1377 } 1378 1379 if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer) 1380 { 1381 ANGLE_TRY( 1382 encodeUniformBuffersInfoArgumentBuffer(context, cmdEncoder, blocks, shaderType)); 1383 } 1384 else 1385 { 1386 ANGLE_TRY(bindUniformBuffersToDiscreteSlots(context, cmdEncoder, blocks, shaderType)); 1387 } 1388 } // for shader types 1389 1390 // After encode the uniform buffers into an argument buffer, we need to tell Metal that 1391 // the buffers are being used by what shader stages. 1392 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1393 { 1394 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1395 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1396 glState.getIndexedUniformBuffer(block.binding); 1397 if (bufferBinding.get() == nullptr) 1398 { 1399 continue; 1400 } 1401 1402 // Remove any other stages other than vertex and fragment. 1403 uint32_t stages = mArgumentBufferRenderStageUsages[bufferIndex] & 1404 (mtl::kRenderStageVertex | mtl::kRenderStageFragment); 1405 1406 if (stages == 0) 1407 { 1408 continue; 1409 } 1410 1411 cmdEncoder->useResource(mLegalizedOffsetedUniformBuffers[bufferIndex].first, 1412 MTLResourceUsageRead, static_cast<mtl::RenderStages>(stages)); 1413 } 1414 1415 return angle::Result::Continue; 1416} 1417 1418angle::Result ProgramMtl::legalizeUniformBufferOffsets( 1419 ContextMtl *context, 1420 const std::vector<gl::InterfaceBlock> &blocks) 1421{ 1422 const gl::State &glState = context->getState(); 1423 1424 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1425 { 1426 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1427 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1428 glState.getIndexedUniformBuffer(block.binding); 1429 1430 if (bufferBinding.get() == nullptr) 1431 { 1432 continue; 1433 } 1434 1435 BufferMtl *bufferMtl = mtl::GetImpl(bufferBinding.get()); 1436 size_t srcOffset = std::min<size_t>(bufferBinding.getOffset(), bufferMtl->size()); 1437 size_t offsetModulo = srcOffset % mtl::kUniformBufferSettingOffsetMinAlignment; 1438 if (offsetModulo) 1439 { 1440 ConversionBufferMtl *conversion = 1441 bufferMtl->getUniformConversionBuffer(context, offsetModulo); 1442 // Has the content of the buffer has changed since last conversion? 1443 if (conversion->dirty) 1444 { 1445 const uint8_t *srcBytes = bufferMtl->getClientShadowCopyData(context); 1446 srcBytes += offsetModulo; 1447 size_t sizeToCopy = bufferMtl->size() - offsetModulo; 1448 size_t bytesToAllocate = roundUp<size_t>(sizeToCopy, 16u); 1449 ANGLE_TRY(StreamUniformBufferData( 1450 context, &conversion->data, srcBytes, bytesToAllocate, sizeToCopy, 1451 &conversion->convertedBuffer, &conversion->convertedOffset)); 1452#ifndef NDEBUG 1453 ANGLE_MTL_OBJC_SCOPE 1454 { 1455 conversion->convertedBuffer->get().label = [NSString 1456 stringWithFormat:@"Converted from %p offset=%zu", bufferMtl, offsetModulo]; 1457 } 1458#endif 1459 conversion->dirty = false; 1460 } 1461 // reuse the converted buffer 1462 mLegalizedOffsetedUniformBuffers[bufferIndex].first = conversion->convertedBuffer; 1463 mLegalizedOffsetedUniformBuffers[bufferIndex].second = 1464 static_cast<uint32_t>(conversion->convertedOffset + srcOffset - offsetModulo); 1465 } 1466 else 1467 { 1468 mLegalizedOffsetedUniformBuffers[bufferIndex].first = bufferMtl->getCurrentBuffer(); 1469 mLegalizedOffsetedUniformBuffers[bufferIndex].second = 1470 static_cast<uint32_t>(bufferBinding.getOffset()); 1471 } 1472 } 1473 return angle::Result::Continue; 1474} 1475 1476angle::Result ProgramMtl::bindUniformBuffersToDiscreteSlots( 1477 ContextMtl *context, 1478 mtl::RenderCommandEncoder *cmdEncoder, 1479 const std::vector<gl::InterfaceBlock> &blocks, 1480 gl::ShaderType shaderType) 1481{ 1482 const gl::State &glState = context->getState(); 1483 const mtl::TranslatedShaderInfo &shaderInfo = 1484 *mCurrentShaderVariants[shaderType]->translatedSrcInfo; 1485 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1486 { 1487 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1488 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1489 glState.getIndexedUniformBuffer(block.binding); 1490 1491 if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType)) 1492 { 1493 continue; 1494 } 1495 1496 uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex]; 1497 1498 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1499 { 1500 continue; 1501 } 1502 1503 mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first; 1504 uint32_t offset = mLegalizedOffsetedUniformBuffers[bufferIndex].second; 1505 cmdEncoder->setBuffer(shaderType, mtlBuffer, offset, actualBufferIdx); 1506 } 1507 return angle::Result::Continue; 1508} 1509angle::Result ProgramMtl::encodeUniformBuffersInfoArgumentBuffer( 1510 ContextMtl *context, 1511 mtl::RenderCommandEncoder *cmdEncoder, 1512 const std::vector<gl::InterfaceBlock> &blocks, 1513 gl::ShaderType shaderType) 1514{ 1515 const gl::State &glState = context->getState(); 1516 ASSERT(mCurrentShaderVariants[shaderType]->translatedSrcInfo); 1517 const mtl::TranslatedShaderInfo &shaderInfo = 1518 *mCurrentShaderVariants[shaderType]->translatedSrcInfo; 1519 1520 // Encode all uniform buffers into an argument buffer. 1521 ProgramArgumentBufferEncoderMtl &bufferEncoder = 1522 mCurrentShaderVariants[shaderType]->uboArgBufferEncoder; 1523 1524 mtl::BufferRef argumentBuffer; 1525 size_t argumentBufferOffset; 1526 bufferEncoder.bufferPool.releaseInFlightBuffers(context); 1527 ANGLE_TRY(bufferEncoder.bufferPool.allocate( 1528 context, bufferEncoder.metalArgBufferEncoder.get().encodedLength, nullptr, &argumentBuffer, 1529 &argumentBufferOffset)); 1530 1531 [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get() 1532 offset:argumentBufferOffset]; 1533 1534 constexpr gl::ShaderMap<MTLRenderStages> kShaderStageMap = { 1535 {gl::ShaderType::Vertex, mtl::kRenderStageVertex}, 1536 {gl::ShaderType::Fragment, mtl::kRenderStageFragment}, 1537 }; 1538 1539 auto mtlRenderStage = kShaderStageMap[shaderType]; 1540 1541 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1542 { 1543 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1544 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1545 glState.getIndexedUniformBuffer(block.binding); 1546 1547 if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType)) 1548 { 1549 continue; 1550 } 1551 1552 mArgumentBufferRenderStageUsages[bufferIndex] |= mtlRenderStage; 1553 1554 uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex]; 1555 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1556 { 1557 continue; 1558 } 1559 1560 mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first; 1561 uint32_t offset = mLegalizedOffsetedUniformBuffers[bufferIndex].second; 1562 [bufferEncoder.metalArgBufferEncoder setBuffer:mtlBuffer->get() 1563 offset:offset 1564 atIndex:actualBufferIdx]; 1565 } 1566 1567 ANGLE_TRY(bufferEncoder.bufferPool.commit(context)); 1568 1569 cmdEncoder->setBuffer(shaderType, argumentBuffer, static_cast<uint32_t>(argumentBufferOffset), 1570 mtl::kUBOArgumentBufferBindingIndex); 1571 return angle::Result::Continue; 1572} 1573 1574angle::Result ProgramMtl::updateXfbBuffers(ContextMtl *context, 1575 mtl::RenderCommandEncoder *cmdEncoder, 1576 const mtl::RenderPipelineDesc &pipelineDesc) 1577{ 1578 const gl::State &glState = context->getState(); 1579 gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); 1580 1581 if (pipelineDesc.rasterizationEnabled() || !glState.isTransformFeedbackActiveUnpaused() || 1582 ANGLE_UNLIKELY(!transformFeedback)) 1583 { 1584 // XFB output can only be used with rasterization disabled. 1585 return angle::Result::Continue; 1586 } 1587 1588 size_t xfbBufferCount = glState.getProgramExecutable()->getTransformFeedbackBufferCount(); 1589 1590 ASSERT(xfbBufferCount > 0); 1591 ASSERT(mState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS || 1592 xfbBufferCount == 1); 1593 1594 for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) 1595 { 1596 uint32_t actualBufferIdx = mMslXfbOnlyVertexShaderInfo.actualXFBBindings[bufferIndex]; 1597 1598 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1599 { 1600 continue; 1601 } 1602 1603 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1604 transformFeedback->getIndexedBuffer(bufferIndex); 1605 gl::Buffer *buffer = bufferBinding.get(); 1606 ASSERT((bufferBinding.getOffset() % 4) == 0); 1607 ASSERT(buffer != nullptr); 1608 1609 BufferMtl *bufferMtl = mtl::GetImpl(buffer); 1610 1611 // Use offset=0, actual offset will be set in Driver Uniform inside ContextMtl. 1612 cmdEncoder->setBufferForWrite(gl::ShaderType::Vertex, bufferMtl->getCurrentBuffer(), 0, 1613 actualBufferIdx); 1614 } 1615 1616 return angle::Result::Continue; 1617} 1618 1619} // namespace rx 1620