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 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(mtl::Context *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 MTLFunctionConstantValues *funcConstants = nil; 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 = [[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 funcConstants = [[MTLFunctionConstantValues alloc] init]; 679 [funcConstants setConstantValue:&emulateCoverageMask 680 type:MTLDataTypeBool 681 withName:coverageMaskEnabledStr]; 682 } 683 684 } // gl::ShaderType::Fragment 685 else 686 { 687 UNREACHABLE(); 688 return angle::Result::Stop; 689 } 690 [funcConstants 691 setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareGradient.enabled) 692 type:MTLDataTypeBool 693 withName:@"ANGLEUseSampleCompareGradient"]; 694 [funcConstants 695 setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareLod.enabled) 696 type:MTLDataTypeBool 697 withName:@"ANGLEUseSampleCompareLod"]; 698 // Create Metal shader object 699 ANGLE_MTL_OBJC_SCOPE 700 { 701 ANGLE_TRY(CreateMslShader(context, translatedMslInfo->metalLibrary, SHADER_ENTRY_NAME, 702 funcConstants, &shaderVariant->metalShader)); 703 [funcConstants ANGLE_MTL_AUTORELEASE]; 704 } 705 706 // Store reference to the translated source for easily querying mapped bindings later. 707 shaderVariant->translatedSrcInfo = translatedMslInfo; 708 709 // Initialize argument buffer encoder if required 710 if (translatedMslInfo->hasUBOArgumentBuffer) 711 { 712 InitArgumentBufferEncoder(context, shaderVariant->metalShader, 713 mtl::kUBOArgumentBufferBindingIndex, 714 &shaderVariant->uboArgBufferEncoder); 715 } 716 717 *shaderOut = shaderVariant->metalShader; 718 719 return angle::Result::Continue; 720} 721 722bool ProgramMtl::hasSpecializedShader(gl::ShaderType shaderType, 723 const mtl::RenderPipelineDesc &renderPipelineDesc) 724{ 725 return true; 726} 727 728angle::Result ProgramMtl::createMslShaderLib( 729 mtl::Context *context, 730 gl::ShaderType shaderType, 731 gl::InfoLog &infoLog, 732 mtl::TranslatedShaderInfo *translatedMslInfo, 733 NSDictionary<NSString *, NSObject *> *substitutionMacros) 734{ 735 ANGLE_MTL_OBJC_SCOPE 736 { 737 DisplayMtl *display = context->getDisplay(); 738 id<MTLDevice> mtlDevice = display->getMetalDevice(); 739 740 // Convert to actual binary shader 741 mtl::AutoObjCPtr<NSError *> err = nil; 742 bool disableFastMath = (context->getDisplay()->getFeatures().intelDisableFastMath.enabled && 743 translatedMslInfo->hasInvariantOrAtan); 744 translatedMslInfo->metalLibrary = 745 mtl::CreateShaderLibrary(mtlDevice, translatedMslInfo->metalShaderSource, 746 substitutionMacros, !disableFastMath, &err); 747 if (err && !translatedMslInfo->metalLibrary) 748 { 749 std::ostringstream ss; 750 ss << "Internal error compiling shader with Metal backend.\n"; 751#if !defined(NDEBUG) 752 ss << err.get().localizedDescription.UTF8String << "\n"; 753 ss << "-----\n"; 754 ss << translatedMslInfo->metalShaderSource; 755 ss << "-----\n"; 756#else 757 ss << "Please submit this shader, or website as a bug to https://bugs.webkit.org\n"; 758#endif 759 ERR() << ss.str(); 760 761 infoLog << ss.str(); 762 763 ANGLE_MTL_CHECK(context, false, GL_INVALID_OPERATION); 764 } 765 766 return angle::Result::Continue; 767 } 768} 769 770void ProgramMtl::saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream) 771{ 772 // Serializes the uniformLayout data of mDefaultUniformBlocks 773 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 774 { 775 const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size(); 776 stream->writeInt<size_t>(uniformCount); 777 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) 778 { 779 sh::BlockMemberInfo &blockInfo = 780 mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex]; 781 gl::WriteBlockMemberInfo(stream, blockInfo); 782 } 783 } 784 785 // Serializes required uniform block memory sizes 786 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 787 { 788 stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size()); 789 } 790} 791 792angle::Result ProgramMtl::loadDefaultUniformBlocksInfo(const gl::Context *glContext, 793 gl::BinaryInputStream *stream) 794{ 795 gl::ShaderMap<size_t> requiredBufferSize; 796 requiredBufferSize.fill(0); 797 798 // Deserializes the uniformLayout data of mDefaultUniformBlocks 799 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 800 { 801 const size_t uniformCount = stream->readInt<size_t>(); 802 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) 803 { 804 sh::BlockMemberInfo blockInfo; 805 gl::LoadBlockMemberInfo(stream, &blockInfo); 806 mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo); 807 } 808 } 809 810 // Deserializes required uniform block memory sizes 811 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 812 { 813 requiredBufferSize[shaderType] = stream->readInt<size_t>(); 814 } 815 816 return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize); 817} 818 819void ProgramMtl::saveShaderInternalInfo(gl::BinaryOutputStream *stream) 820{ 821 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 822 { 823 stream->writeInt<int>(mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer); 824 for (const mtl::SamplerBinding &binding : 825 mMslShaderTranslateInfo[shaderType].actualSamplerBindings) 826 { 827 stream->writeInt<uint32_t>(binding.textureBinding); 828 stream->writeInt<uint32_t>(binding.samplerBinding); 829 } 830 831 for (uint32_t uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings) 832 { 833 stream->writeInt<uint32_t>(uboBinding); 834 } 835 stream->writeBool(mMslShaderTranslateInfo[shaderType].hasInvariantOrAtan); 836 } 837 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 838 { 839 stream->writeInt( 840 mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]); 841 } 842 843 // Write out XFB info. 844 { 845 stream->writeInt<int>(mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer); 846 for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings) 847 { 848 stream->writeInt<uint32_t>(binding.textureBinding); 849 stream->writeInt<uint32_t>(binding.samplerBinding); 850 } 851 852 for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings) 853 { 854 stream->writeInt<uint32_t>(uboBinding); 855 } 856 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 857 { 858 stream->writeInt(mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]); 859 } 860 } 861 862 stream->writeBool(mProgramHasFlatAttributes); 863} 864 865void ProgramMtl::loadShaderInternalInfo(gl::BinaryInputStream *stream) 866{ 867 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 868 { 869 mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer = stream->readInt<int>() != 0; 870 for (mtl::SamplerBinding &binding : 871 mMslShaderTranslateInfo[shaderType].actualSamplerBindings) 872 { 873 binding.textureBinding = stream->readInt<uint32_t>(); 874 binding.samplerBinding = stream->readInt<uint32_t>(); 875 } 876 877 for (uint32_t &uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings) 878 { 879 uboBinding = stream->readInt<uint32_t>(); 880 } 881 mMslShaderTranslateInfo[shaderType].hasInvariantOrAtan = stream->readBool(); 882 } 883 884 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 885 { 886 stream->readInt( 887 &mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]); 888 } 889 // Load Transform Feedback info 890 { 891 mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer = stream->readInt<int>() != 0; 892 for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings) 893 { 894 binding.textureBinding = stream->readInt<uint32_t>(); 895 binding.samplerBinding = stream->readInt<uint32_t>(); 896 } 897 898 for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings) 899 { 900 uboBinding = stream->readInt<uint32_t>(); 901 } 902 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 903 { 904 stream->readInt(&mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]); 905 } 906 mMslXfbOnlyVertexShaderInfo.metalLibrary = nullptr; 907 } 908 909 mProgramHasFlatAttributes = stream->readBool(); 910} 911 912GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog) 913{ 914 // No-op. The spec is very vague about the behavior of validation. 915 return GL_TRUE; 916} 917 918template <typename T> 919void ProgramMtl::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType) 920{ 921 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 922 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 923 924 if (linkedUniform.isSampler()) 925 { 926 // Sampler binding has changed. 927 mSamplerBindingsDirty.set(); 928 return; 929 } 930 931 if (linkedUniform.typeInfo->type == entryPointType) 932 { 933 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 934 { 935 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 936 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 937 938 // Assume an offset of -1 means the block is unused. 939 if (layoutInfo.offset == -1) 940 { 941 continue; 942 } 943 944 const GLint componentCount = linkedUniform.typeInfo->componentCount; 945 UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo, 946 &uniformBlock.uniformData); 947 mDefaultUniformBlocksDirty.set(shaderType); 948 } 949 } 950 else 951 { 952 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 953 { 954 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 955 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 956 957 // Assume an offset of -1 means the block is unused. 958 if (layoutInfo.offset == -1) 959 { 960 continue; 961 } 962 963 const GLint componentCount = linkedUniform.typeInfo->componentCount; 964 965 ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType)); 966 967 GLint initialArrayOffset = 968 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset; 969 for (GLint i = 0; i < count; i++) 970 { 971 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset; 972 GLint *dest = 973 reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset); 974 const T *source = v + i * componentCount; 975 976 for (int c = 0; c < componentCount; c++) 977 { 978 dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE; 979 } 980 } 981 982 mDefaultUniformBlocksDirty.set(shaderType); 983 } 984 } 985} 986 987template <typename T> 988void ProgramMtl::getUniformImpl(GLint location, T *v, GLenum entryPointType) const 989{ 990 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 991 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 992 993 ASSERT(!linkedUniform.isSampler()); 994 995 const gl::ShaderType shaderType = linkedUniform.getFirstShaderTypeWhereActive(); 996 ASSERT(shaderType != gl::ShaderType::InvalidEnum); 997 998 const DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 999 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1000 1001 ASSERT(linkedUniform.typeInfo->componentType == entryPointType || 1002 linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType)); 1003 1004 if (gl::IsMatrixType(linkedUniform.type)) 1005 { 1006 const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset + 1007 (locationInfo.arrayIndex * layoutInfo.arrayStride); 1008 GetMatrixUniform(linkedUniform.type, v, reinterpret_cast<const T *>(ptrToElement), false); 1009 } 1010 else 1011 { 1012 ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex, 1013 v, layoutInfo, &uniformBlock.uniformData); 1014 } 1015} 1016 1017void ProgramMtl::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) 1018{ 1019 setUniformImpl(location, count, v, GL_FLOAT); 1020} 1021 1022void ProgramMtl::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) 1023{ 1024 setUniformImpl(location, count, v, GL_FLOAT_VEC2); 1025} 1026 1027void ProgramMtl::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) 1028{ 1029 setUniformImpl(location, count, v, GL_FLOAT_VEC3); 1030} 1031 1032void ProgramMtl::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) 1033{ 1034 setUniformImpl(location, count, v, GL_FLOAT_VEC4); 1035} 1036 1037void ProgramMtl::setUniform1iv(GLint startLocation, GLsizei count, const GLint *v) 1038{ 1039 setUniformImpl(startLocation, count, v, GL_INT); 1040} 1041 1042void ProgramMtl::setUniform2iv(GLint location, GLsizei count, const GLint *v) 1043{ 1044 setUniformImpl(location, count, v, GL_INT_VEC2); 1045} 1046 1047void ProgramMtl::setUniform3iv(GLint location, GLsizei count, const GLint *v) 1048{ 1049 setUniformImpl(location, count, v, GL_INT_VEC3); 1050} 1051 1052void ProgramMtl::setUniform4iv(GLint location, GLsizei count, const GLint *v) 1053{ 1054 setUniformImpl(location, count, v, GL_INT_VEC4); 1055} 1056 1057void ProgramMtl::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) 1058{ 1059 setUniformImpl(location, count, v, GL_UNSIGNED_INT); 1060} 1061 1062void ProgramMtl::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) 1063{ 1064 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2); 1065} 1066 1067void ProgramMtl::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) 1068{ 1069 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3); 1070} 1071 1072void ProgramMtl::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) 1073{ 1074 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4); 1075} 1076 1077template <int cols, int rows> 1078void ProgramMtl::setUniformMatrixfv(GLint location, 1079 GLsizei count, 1080 GLboolean transpose, 1081 const GLfloat *value) 1082{ 1083 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 1084 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 1085 1086 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1087 { 1088 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 1089 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1090 1091 // Assume an offset of -1 means the block is unused. 1092 if (layoutInfo.offset == -1) 1093 { 1094 continue; 1095 } 1096 1097 SetFloatUniformMatrixGLSL<cols, rows>::Run( 1098 locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value, 1099 uniformBlock.uniformData.data() + layoutInfo.offset); 1100 1101 mDefaultUniformBlocksDirty.set(shaderType); 1102 } 1103} 1104 1105void ProgramMtl::setUniformMatrix2fv(GLint location, 1106 GLsizei count, 1107 GLboolean transpose, 1108 const GLfloat *value) 1109{ 1110 setUniformMatrixfv<2, 2>(location, count, transpose, value); 1111} 1112 1113void ProgramMtl::setUniformMatrix3fv(GLint location, 1114 GLsizei count, 1115 GLboolean transpose, 1116 const GLfloat *value) 1117{ 1118 setUniformMatrixfv<3, 3>(location, count, transpose, value); 1119} 1120 1121void ProgramMtl::setUniformMatrix4fv(GLint location, 1122 GLsizei count, 1123 GLboolean transpose, 1124 const GLfloat *value) 1125{ 1126 setUniformMatrixfv<4, 4>(location, count, transpose, value); 1127} 1128 1129void ProgramMtl::setUniformMatrix2x3fv(GLint location, 1130 GLsizei count, 1131 GLboolean transpose, 1132 const GLfloat *value) 1133{ 1134 setUniformMatrixfv<2, 3>(location, count, transpose, value); 1135} 1136 1137void ProgramMtl::setUniformMatrix3x2fv(GLint location, 1138 GLsizei count, 1139 GLboolean transpose, 1140 const GLfloat *value) 1141{ 1142 setUniformMatrixfv<3, 2>(location, count, transpose, value); 1143} 1144 1145void ProgramMtl::setUniformMatrix2x4fv(GLint location, 1146 GLsizei count, 1147 GLboolean transpose, 1148 const GLfloat *value) 1149{ 1150 setUniformMatrixfv<2, 4>(location, count, transpose, value); 1151} 1152 1153void ProgramMtl::setUniformMatrix4x2fv(GLint location, 1154 GLsizei count, 1155 GLboolean transpose, 1156 const GLfloat *value) 1157{ 1158 setUniformMatrixfv<4, 2>(location, count, transpose, value); 1159} 1160 1161void ProgramMtl::setUniformMatrix3x4fv(GLint location, 1162 GLsizei count, 1163 GLboolean transpose, 1164 const GLfloat *value) 1165{ 1166 setUniformMatrixfv<3, 4>(location, count, transpose, value); 1167} 1168 1169void ProgramMtl::setUniformMatrix4x3fv(GLint location, 1170 GLsizei count, 1171 GLboolean transpose, 1172 const GLfloat *value) 1173{ 1174 setUniformMatrixfv<4, 3>(location, count, transpose, value); 1175} 1176 1177void ProgramMtl::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const 1178{ 1179 getUniformImpl(location, params, GL_FLOAT); 1180} 1181 1182void ProgramMtl::getUniformiv(const gl::Context *context, GLint location, GLint *params) const 1183{ 1184 getUniformImpl(location, params, GL_INT); 1185} 1186 1187void ProgramMtl::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const 1188{ 1189 getUniformImpl(location, params, GL_UNSIGNED_INT); 1190} 1191 1192angle::Result ProgramMtl::setupDraw(const gl::Context *glContext, 1193 mtl::RenderCommandEncoder *cmdEncoder, 1194 const mtl::RenderPipelineDesc &pipelineDesc, 1195 bool pipelineDescChanged, 1196 bool forceTexturesSetting, 1197 bool uniformBuffersDirty) 1198{ 1199 ContextMtl *context = mtl::GetImpl(glContext); 1200 if (pipelineDescChanged) 1201 { 1202 // Render pipeline state needs to be changed 1203 id<MTLRenderPipelineState> pipelineState = 1204 mMetalRenderPipelineCache.getRenderPipelineState(context, pipelineDesc); 1205 if (!pipelineState) 1206 { 1207 // Error already logged inside getRenderPipelineState() 1208 return angle::Result::Stop; 1209 } 1210 cmdEncoder->setRenderPipelineState(pipelineState); 1211 1212 // We need to rebind uniform buffers & textures also 1213 mDefaultUniformBlocksDirty.set(); 1214 mSamplerBindingsDirty.set(); 1215 1216 // Cache current shader variant references for easier querying. 1217 mCurrentShaderVariants[gl::ShaderType::Vertex] = 1218 &mVertexShaderVariants[pipelineDesc.rasterizationType]; 1219 mCurrentShaderVariants[gl::ShaderType::Fragment] = 1220 pipelineDesc.rasterizationEnabled() 1221 ? &mFragmentShaderVariants[pipelineDesc.emulateCoverageMask] 1222 : nullptr; 1223 } 1224 1225 ANGLE_TRY(commitUniforms(context, cmdEncoder)); 1226 ANGLE_TRY(updateTextures(glContext, cmdEncoder, forceTexturesSetting)); 1227 1228 if (uniformBuffersDirty || pipelineDescChanged) 1229 { 1230 ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc)); 1231 } 1232 1233 if (pipelineDescChanged) 1234 { 1235 ANGLE_TRY(updateXfbBuffers(context, cmdEncoder, pipelineDesc)); 1236 } 1237 1238 return angle::Result::Continue; 1239} 1240 1241angle::Result ProgramMtl::commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder) 1242{ 1243 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1244 { 1245 if (!mDefaultUniformBlocksDirty[shaderType] || !mCurrentShaderVariants[shaderType]) 1246 { 1247 continue; 1248 } 1249 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 1250 1251 if (!uniformBlock.uniformData.size()) 1252 { 1253 continue; 1254 } 1255 // If we exceed the default uniform max size, try to allocate a buffer. Worst case 1256 // scenario, fall back on a large setBytes. 1257 bool needsCommitUniform = true; 1258 if (needsCommitUniform) 1259 { 1260 ASSERT(uniformBlock.uniformData.size() <= mtl::kDefaultUniformsMaxSize); 1261 cmdEncoder->setBytes(shaderType, uniformBlock.uniformData.data(), 1262 uniformBlock.uniformData.size(), 1263 mtl::kDefaultUniformsBindingIndex); 1264 } 1265 1266 mDefaultUniformBlocksDirty.reset(shaderType); 1267 } 1268 1269 return angle::Result::Continue; 1270} 1271 1272angle::Result ProgramMtl::updateTextures(const gl::Context *glContext, 1273 mtl::RenderCommandEncoder *cmdEncoder, 1274 bool forceUpdate) 1275{ 1276 ContextMtl *contextMtl = mtl::GetImpl(glContext); 1277 const auto &glState = glContext->getState(); 1278 const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache(); 1279 1280 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1281 { 1282 if ((!mSamplerBindingsDirty[shaderType] && !forceUpdate) || 1283 !mCurrentShaderVariants[shaderType]) 1284 { 1285 continue; 1286 } 1287 1288 const mtl::TranslatedShaderInfo &shaderInfo = 1289 mCurrentShaderVariants[shaderType]->translatedSrcInfo 1290 ? *mCurrentShaderVariants[shaderType]->translatedSrcInfo 1291 : mMslShaderTranslateInfo[shaderType]; 1292 bool hasDepthSampler = false; 1293 1294 for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size(); 1295 ++textureIndex) 1296 { 1297 const gl::SamplerBinding &samplerBinding = mState.getSamplerBindings()[textureIndex]; 1298 const mtl::SamplerBinding &mslBinding = shaderInfo.actualSamplerBindings[textureIndex]; 1299 if (mslBinding.textureBinding >= mtl::kMaxShaderSamplers) 1300 { 1301 // No binding assigned 1302 continue; 1303 } 1304 1305 gl::TextureType textureType = samplerBinding.textureType; 1306 1307 for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size(); 1308 ++arrayElement) 1309 { 1310 GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement]; 1311 gl::Texture *texture = completeTextures[textureUnit]; 1312 gl::Sampler *sampler = contextMtl->getState().getSampler(textureUnit); 1313 uint32_t textureSlot = mslBinding.textureBinding + arrayElement; 1314 uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement; 1315 if (!texture) 1316 { 1317 ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, &texture)); 1318 } 1319 const gl::SamplerState *samplerState = 1320 sampler ? &sampler->getSamplerState() : &texture->getSamplerState(); 1321 TextureMtl *textureMtl = mtl::GetImpl(texture); 1322 if (samplerBinding.format == gl::SamplerFormat::Shadow) 1323 { 1324 hasDepthSampler = true; 1325 mShadowCompareModes[textureSlot] = mtl::MslGetShaderShadowCompareMode( 1326 samplerState->getCompareMode(), samplerState->getCompareFunc()); 1327 } 1328 ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler, 1329 textureSlot, samplerSlot)); 1330 } // for array elements 1331 } // for sampler bindings 1332 1333 if (hasDepthSampler) 1334 { 1335 cmdEncoder->setData(shaderType, mShadowCompareModes, 1336 mtl::kShadowSamplerCompareModesBindingIndex); 1337 } 1338 } // for shader types 1339 1340 return angle::Result::Continue; 1341} 1342 1343angle::Result ProgramMtl::updateUniformBuffers(ContextMtl *context, 1344 mtl::RenderCommandEncoder *cmdEncoder, 1345 const mtl::RenderPipelineDesc &pipelineDesc) 1346{ 1347 const std::vector<gl::InterfaceBlock> &blocks = mState.getUniformBlocks(); 1348 if (blocks.empty()) 1349 { 1350 return angle::Result::Continue; 1351 } 1352 1353 // This array is only used inside this function and its callees. 1354 ScopedAutoClearVector<uint32_t> scopeArrayClear(&mArgumentBufferRenderStageUsages); 1355 ScopedAutoClearVector<std::pair<mtl::BufferRef, uint32_t>> scopeArrayClear2( 1356 &mLegalizedOffsetedUniformBuffers); 1357 mArgumentBufferRenderStageUsages.resize(blocks.size()); 1358 mLegalizedOffsetedUniformBuffers.resize(blocks.size()); 1359 1360 ANGLE_TRY(legalizeUniformBufferOffsets(context, blocks)); 1361 1362 const gl::State &glState = context->getState(); 1363 1364 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1365 { 1366 if (!mCurrentShaderVariants[shaderType]) 1367 { 1368 continue; 1369 } 1370 1371 if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer) 1372 { 1373 ANGLE_TRY( 1374 encodeUniformBuffersInfoArgumentBuffer(context, cmdEncoder, blocks, shaderType)); 1375 } 1376 else 1377 { 1378 ANGLE_TRY(bindUniformBuffersToDiscreteSlots(context, cmdEncoder, blocks, shaderType)); 1379 } 1380 } // for shader types 1381 1382 // After encode the uniform buffers into an argument buffer, we need to tell Metal that 1383 // the buffers are being used by what shader stages. 1384 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1385 { 1386 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1387 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1388 glState.getIndexedUniformBuffer(block.binding); 1389 if (bufferBinding.get() == nullptr) 1390 { 1391 continue; 1392 } 1393 1394 // Remove any other stages other than vertex and fragment. 1395 uint32_t stages = mArgumentBufferRenderStageUsages[bufferIndex] & 1396 (mtl::kRenderStageVertex | mtl::kRenderStageFragment); 1397 1398 if (stages == 0) 1399 { 1400 continue; 1401 } 1402 1403 cmdEncoder->useResource(mLegalizedOffsetedUniformBuffers[bufferIndex].first, 1404 MTLResourceUsageRead, static_cast<mtl::RenderStages>(stages)); 1405 } 1406 1407 return angle::Result::Continue; 1408} 1409 1410angle::Result ProgramMtl::legalizeUniformBufferOffsets( 1411 ContextMtl *context, 1412 const std::vector<gl::InterfaceBlock> &blocks) 1413{ 1414 const gl::State &glState = context->getState(); 1415 1416 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1417 { 1418 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1419 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1420 glState.getIndexedUniformBuffer(block.binding); 1421 1422 if (bufferBinding.get() == nullptr) 1423 { 1424 continue; 1425 } 1426 1427 BufferMtl *bufferMtl = mtl::GetImpl(bufferBinding.get()); 1428 size_t srcOffset = std::min<size_t>(bufferBinding.getOffset(), bufferMtl->size()); 1429 size_t offsetModulo = srcOffset % mtl::kUniformBufferSettingOffsetMinAlignment; 1430 if (offsetModulo) 1431 { 1432 ConversionBufferMtl *conversion = 1433 bufferMtl->getUniformConversionBuffer(context, offsetModulo); 1434 // Has the content of the buffer has changed since last conversion? 1435 if (conversion->dirty) 1436 { 1437 const uint8_t *srcBytes = bufferMtl->getClientShadowCopyData(context); 1438 srcBytes += offsetModulo; 1439 size_t sizeToCopy = bufferMtl->size() - offsetModulo; 1440 size_t bytesToAllocate = roundUp<size_t>(sizeToCopy, 16u); 1441 ANGLE_TRY(StreamUniformBufferData( 1442 context, &conversion->data, srcBytes, bytesToAllocate, sizeToCopy, 1443 &conversion->convertedBuffer, &conversion->convertedOffset)); 1444#ifndef NDEBUG 1445 ANGLE_MTL_OBJC_SCOPE 1446 { 1447 conversion->convertedBuffer->get().label = [NSString 1448 stringWithFormat:@"Converted from %p offset=%zu", bufferMtl, offsetModulo]; 1449 } 1450#endif 1451 conversion->dirty = false; 1452 } 1453 // reuse the converted buffer 1454 mLegalizedOffsetedUniformBuffers[bufferIndex].first = conversion->convertedBuffer; 1455 mLegalizedOffsetedUniformBuffers[bufferIndex].second = 1456 static_cast<uint32_t>(conversion->convertedOffset + srcOffset - offsetModulo); 1457 } 1458 else 1459 { 1460 mLegalizedOffsetedUniformBuffers[bufferIndex].first = bufferMtl->getCurrentBuffer(); 1461 mLegalizedOffsetedUniformBuffers[bufferIndex].second = 1462 static_cast<uint32_t>(bufferBinding.getOffset()); 1463 } 1464 } 1465 return angle::Result::Continue; 1466} 1467 1468angle::Result ProgramMtl::bindUniformBuffersToDiscreteSlots( 1469 ContextMtl *context, 1470 mtl::RenderCommandEncoder *cmdEncoder, 1471 const std::vector<gl::InterfaceBlock> &blocks, 1472 gl::ShaderType shaderType) 1473{ 1474 const gl::State &glState = context->getState(); 1475 const mtl::TranslatedShaderInfo &shaderInfo = 1476 *mCurrentShaderVariants[shaderType]->translatedSrcInfo; 1477 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1478 { 1479 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1480 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1481 glState.getIndexedUniformBuffer(block.binding); 1482 1483 if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType)) 1484 { 1485 continue; 1486 } 1487 1488 uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex]; 1489 1490 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1491 { 1492 continue; 1493 } 1494 1495 mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first; 1496 uint32_t offset = mLegalizedOffsetedUniformBuffers[bufferIndex].second; 1497 cmdEncoder->setBuffer(shaderType, mtlBuffer, offset, actualBufferIdx); 1498 } 1499 return angle::Result::Continue; 1500} 1501angle::Result ProgramMtl::encodeUniformBuffersInfoArgumentBuffer( 1502 ContextMtl *context, 1503 mtl::RenderCommandEncoder *cmdEncoder, 1504 const std::vector<gl::InterfaceBlock> &blocks, 1505 gl::ShaderType shaderType) 1506{ 1507 const gl::State &glState = context->getState(); 1508 ASSERT(mCurrentShaderVariants[shaderType]->translatedSrcInfo); 1509 const mtl::TranslatedShaderInfo &shaderInfo = 1510 *mCurrentShaderVariants[shaderType]->translatedSrcInfo; 1511 1512 // Encode all uniform buffers into an argument buffer. 1513 ProgramArgumentBufferEncoderMtl &bufferEncoder = 1514 mCurrentShaderVariants[shaderType]->uboArgBufferEncoder; 1515 1516 mtl::BufferRef argumentBuffer; 1517 size_t argumentBufferOffset; 1518 bufferEncoder.bufferPool.releaseInFlightBuffers(context); 1519 ANGLE_TRY(bufferEncoder.bufferPool.allocate( 1520 context, bufferEncoder.metalArgBufferEncoder.get().encodedLength, nullptr, &argumentBuffer, 1521 &argumentBufferOffset)); 1522 1523 [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get() 1524 offset:argumentBufferOffset]; 1525 1526 constexpr gl::ShaderMap<MTLRenderStages> kShaderStageMap = { 1527 {gl::ShaderType::Vertex, mtl::kRenderStageVertex}, 1528 {gl::ShaderType::Fragment, mtl::kRenderStageFragment}, 1529 }; 1530 1531 auto mtlRenderStage = kShaderStageMap[shaderType]; 1532 1533 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1534 { 1535 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1536 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1537 glState.getIndexedUniformBuffer(block.binding); 1538 1539 if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType)) 1540 { 1541 continue; 1542 } 1543 1544 mArgumentBufferRenderStageUsages[bufferIndex] |= mtlRenderStage; 1545 1546 uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex]; 1547 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1548 { 1549 continue; 1550 } 1551 1552 mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first; 1553 uint32_t offset = mLegalizedOffsetedUniformBuffers[bufferIndex].second; 1554 [bufferEncoder.metalArgBufferEncoder setBuffer:mtlBuffer->get() 1555 offset:offset 1556 atIndex:actualBufferIdx]; 1557 } 1558 1559 ANGLE_TRY(bufferEncoder.bufferPool.commit(context)); 1560 1561 cmdEncoder->setBuffer(shaderType, argumentBuffer, static_cast<uint32_t>(argumentBufferOffset), 1562 mtl::kUBOArgumentBufferBindingIndex); 1563 return angle::Result::Continue; 1564} 1565 1566angle::Result ProgramMtl::updateXfbBuffers(ContextMtl *context, 1567 mtl::RenderCommandEncoder *cmdEncoder, 1568 const mtl::RenderPipelineDesc &pipelineDesc) 1569{ 1570 const gl::State &glState = context->getState(); 1571 gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); 1572 1573 if (pipelineDesc.rasterizationEnabled() || !glState.isTransformFeedbackActiveUnpaused() || 1574 ANGLE_UNLIKELY(!transformFeedback)) 1575 { 1576 // XFB output can only be used with rasterization disabled. 1577 return angle::Result::Continue; 1578 } 1579 1580 size_t xfbBufferCount = glState.getProgramExecutable()->getTransformFeedbackBufferCount(); 1581 1582 ASSERT(xfbBufferCount > 0); 1583 ASSERT(mState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS || 1584 xfbBufferCount == 1); 1585 1586 for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) 1587 { 1588 uint32_t actualBufferIdx = mMslXfbOnlyVertexShaderInfo.actualXFBBindings[bufferIndex]; 1589 1590 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1591 { 1592 continue; 1593 } 1594 1595 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1596 transformFeedback->getIndexedBuffer(bufferIndex); 1597 gl::Buffer *buffer = bufferBinding.get(); 1598 ASSERT((bufferBinding.getOffset() % 4) == 0); 1599 ASSERT(buffer != nullptr); 1600 1601 BufferMtl *bufferMtl = mtl::GetImpl(buffer); 1602 1603 // Use offset=0, actual offset will be set in Driver Uniform inside ContextMtl. 1604 cmdEncoder->setBufferForWrite(gl::ShaderType::Vertex, bufferMtl->getCurrentBuffer(), 0, 1605 actualBufferIdx); 1606 } 1607 1608 return angle::Result::Continue; 1609} 1610 1611} // namespace rx 1612