1// 2// Copyright 2023 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// ProgramExecutableMtl.cpp: Implementation of ProgramExecutableMtl. 7 8#include "libANGLE/renderer/metal/ProgramExecutableMtl.h" 9 10#include "libANGLE/renderer/metal/BufferMtl.h" 11#include "libANGLE/renderer/metal/ContextMtl.h" 12#include "libANGLE/renderer/metal/TextureMtl.h" 13#include "libANGLE/renderer/metal/blocklayoutMetal.h" 14#include "libANGLE/renderer/metal/renderermtl_utils.h" 15 16namespace rx 17{ 18namespace 19{ 20#define SHADER_ENTRY_NAME @"main0" 21 22bool CompareBlockInfo(const sh::BlockMemberInfo &a, const sh::BlockMemberInfo &b) 23{ 24 return a.offset < b.offset; 25} 26 27size_t GetAlignmentOfUniformGroup(sh::BlockLayoutMap *blockLayoutMap) 28{ 29 size_t align = 1; 30 for (auto layoutIter = blockLayoutMap->begin(); layoutIter != blockLayoutMap->end(); 31 ++layoutIter) 32 { 33 align = std::max(mtl::GetMetalAlignmentForGLType(layoutIter->second.type), align); 34 } 35 return align; 36} 37 38void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms, 39 sh::BlockLayoutMap *blockLayoutMapOut, 40 size_t *blockSizeOut) 41{ 42 if (uniforms.empty()) 43 { 44 *blockSizeOut = 0; 45 return; 46 } 47 48 mtl::BlockLayoutEncoderMTL blockEncoder; 49 sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut); 50 size_t blockAlign = GetAlignmentOfUniformGroup(blockLayoutMapOut); 51 size_t blockSize = roundUp(blockEncoder.getCurrentOffset(), blockAlign); 52 53 // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized. 54 if (blockSize == 0) 55 { 56 *blockSizeOut = 0; 57 return; 58 } 59 60 *blockSizeOut = blockSize; 61 return; 62} 63 64template <typename T> 65class [[nodiscard]] ScopedAutoClearVector 66{ 67 public: 68 ScopedAutoClearVector(std::vector<T> *array) : mArray(*array) {} 69 ~ScopedAutoClearVector() { mArray.clear(); } 70 71 private: 72 std::vector<T> &mArray; 73}; 74 75inline void memcpy_guarded(void *dst, const void *src, const void *maxSrcPtr, size_t size) 76{ 77 size_t bytesAvailable = maxSrcPtr > src ? (const uint8_t *)maxSrcPtr - (const uint8_t *)src : 0; 78 size_t bytesToCopy = std::min(size, bytesAvailable); 79 size_t bytesToZero = size - bytesToCopy; 80 81 if (bytesToCopy) 82 memcpy(dst, src, bytesToCopy); 83 if (bytesToZero) 84 memset((uint8_t *)dst + bytesToCopy, 0, bytesToZero); 85} 86 87// Copy matrix one column at a time 88inline void copy_matrix(void *dst, 89 const void *src, 90 const void *maxSrcPtr, 91 size_t srcStride, 92 size_t dstStride, 93 GLenum type) 94{ 95 size_t elemSize = mtl::GetMetalSizeForGLType(gl::VariableComponentType(type)); 96 const size_t dstRows = gl::VariableRowCount(type); 97 const size_t dstCols = gl::VariableColumnCount(type); 98 99 for (size_t col = 0; col < dstCols; col++) 100 { 101 size_t srcOffset = col * srcStride; 102 memcpy_guarded(((uint8_t *)dst) + dstStride * col, (const uint8_t *)src + srcOffset, 103 maxSrcPtr, elemSize * dstRows); 104 } 105} 106 107// Copy matrix one element at a time to transpose. 108inline void copy_matrix_row_major(void *dst, 109 const void *src, 110 const void *maxSrcPtr, 111 size_t srcStride, 112 size_t dstStride, 113 GLenum type) 114{ 115 size_t elemSize = mtl::GetMetalSizeForGLType(gl::VariableComponentType(type)); 116 const size_t dstRows = gl::VariableRowCount(type); 117 const size_t dstCols = gl::VariableColumnCount(type); 118 119 for (size_t col = 0; col < dstCols; col++) 120 { 121 for (size_t row = 0; row < dstRows; row++) 122 { 123 size_t srcOffset = row * srcStride + col * elemSize; 124 memcpy_guarded((uint8_t *)dst + dstStride * col + row * elemSize, 125 (const uint8_t *)src + srcOffset, maxSrcPtr, elemSize); 126 } 127 } 128} 129// TODO(angleproject:7979) Upgrade ANGLE Uniform buffer remapper to compute shaders 130angle::Result ConvertUniformBufferData(ContextMtl *contextMtl, 131 const UBOConversionInfo &blockConversionInfo, 132 mtl::BufferPool *dynamicBuffer, 133 const uint8_t *sourceData, 134 size_t sizeToCopy, 135 mtl::BufferRef *bufferOut, 136 size_t *bufferOffsetOut) 137{ 138 uint8_t *dst = nullptr; 139 const uint8_t *maxSrcPtr = sourceData + sizeToCopy; 140 dynamicBuffer->releaseInFlightBuffers(contextMtl); 141 142 // When converting a UBO buffer, we convert all of the data 143 // supplied in a buffer at once (sizeToCopy = bufferMtl->size() - initial offset). 144 // It's possible that a buffer could represent multiple instances of 145 // a uniform block, so we loop over the number of block conversions we intend 146 // to do. 147 size_t numBlocksToCopy = 148 (sizeToCopy + blockConversionInfo.stdSize() - 1) / blockConversionInfo.stdSize(); 149 size_t bytesToAllocate = numBlocksToCopy * blockConversionInfo.metalSize(); 150 ANGLE_TRY(dynamicBuffer->allocate(contextMtl, bytesToAllocate, &dst, bufferOut, bufferOffsetOut, 151 nullptr)); 152 153 const std::vector<sh::BlockMemberInfo> &stdConversions = blockConversionInfo.stdInfo(); 154 const std::vector<sh::BlockMemberInfo> &mtlConversions = blockConversionInfo.metalInfo(); 155 for (size_t i = 0; i < numBlocksToCopy; ++i) 156 { 157 auto stdIterator = stdConversions.begin(); 158 auto mtlIterator = mtlConversions.begin(); 159 160 while (stdIterator != stdConversions.end()) 161 { 162 for (int arraySize = 0; arraySize < stdIterator->arraySize; ++arraySize) 163 { 164 // For every entry in an array, calculate the offset based off of the 165 // array element size. 166 167 // Offset of a single entry is 168 // blockIndex*blockSize + arrayOffset*arraySize + offset of field in base struct. 169 // Fields are copied per block, per member, per array entry of member. 170 171 size_t stdArrayOffset = stdIterator->arrayStride * arraySize; 172 size_t mtlArrayOffset = mtlIterator->arrayStride * arraySize; 173 174 if (gl::IsMatrixType(mtlIterator->type)) 175 { 176 177 void *dstMat = dst + mtlIterator->offset + mtlArrayOffset + 178 blockConversionInfo.metalSize() * i; 179 const void *srcMat = sourceData + stdIterator->offset + stdArrayOffset + 180 blockConversionInfo.stdSize() * i; 181 // Transpose matricies into column major order, if they're row major encoded. 182 if (stdIterator->isRowMajorMatrix) 183 { 184 copy_matrix_row_major(dstMat, srcMat, maxSrcPtr, stdIterator->matrixStride, 185 mtlIterator->matrixStride, mtlIterator->type); 186 } 187 else 188 { 189 copy_matrix(dstMat, srcMat, maxSrcPtr, stdIterator->matrixStride, 190 mtlIterator->matrixStride, mtlIterator->type); 191 } 192 } 193 // Compress bool from four bytes to one byte because bool values in GLSL 194 // are uint-sized: ES 3.0 Section 2.12.6.3 "Uniform Buffer Object Storage". 195 // Bools in metal are byte-sized. (Metal shading language spec Table 2.2) 196 else if (gl::VariableComponentType(mtlIterator->type) == GL_BOOL) 197 { 198 for (int boolCol = 0; boolCol < gl::VariableComponentCount(mtlIterator->type); 199 boolCol++) 200 { 201 const uint8_t *srcBool = 202 (sourceData + stdIterator->offset + stdArrayOffset + 203 blockConversionInfo.stdSize() * i + 204 gl::VariableComponentSize(GL_BOOL) * boolCol); 205 unsigned int srcValue = 206 srcBool < maxSrcPtr ? *((unsigned int *)(srcBool)) : 0; 207 uint8_t *dstBool = dst + mtlIterator->offset + mtlArrayOffset + 208 blockConversionInfo.metalSize() * i + 209 sizeof(bool) * boolCol; 210 *dstBool = (srcValue != 0); 211 } 212 } 213 else 214 { 215 memcpy_guarded(dst + mtlIterator->offset + mtlArrayOffset + 216 blockConversionInfo.metalSize() * i, 217 sourceData + stdIterator->offset + stdArrayOffset + 218 blockConversionInfo.stdSize() * i, 219 maxSrcPtr, mtl::GetMetalSizeForGLType(mtlIterator->type)); 220 } 221 } 222 ++stdIterator; 223 ++mtlIterator; 224 } 225 } 226 227 ANGLE_TRY(dynamicBuffer->commit(contextMtl)); 228 return angle::Result::Continue; 229} 230 231constexpr size_t PipelineParametersToFragmentShaderVariantIndex(bool multisampledRendering, 232 bool allowFragDepthWrite) 233{ 234 const size_t index = (allowFragDepthWrite << 1) | multisampledRendering; 235 ASSERT(index < kFragmentShaderVariants); 236 return index; 237} 238 239void InitArgumentBufferEncoder(mtl::Context *context, 240 id<MTLFunction> function, 241 uint32_t bufferIndex, 242 ProgramArgumentBufferEncoderMtl *encoder) 243{ 244 encoder->metalArgBufferEncoder = 245 mtl::adoptObjCObj([function newArgumentEncoderWithBufferIndex:bufferIndex]); 246 if (encoder->metalArgBufferEncoder) 247 { 248 encoder->bufferPool.initialize(context, encoder->metalArgBufferEncoder.get().encodedLength, 249 mtl::kArgumentBufferOffsetAlignment, 0); 250 } 251} 252 253bool DisableFastMathForShaderCompilation(mtl::Context *context) 254{ 255 return context->getDisplay()->getFeatures().intelDisableFastMath.enabled; 256} 257 258bool UsesInvariance(const mtl::TranslatedShaderInfo *translatedMslInfo) 259{ 260 return translatedMslInfo->hasInvariant; 261} 262 263template <typename T> 264void UpdateDefaultUniformBlockWithElementSize(GLsizei count, 265 uint32_t arrayIndex, 266 int componentCount, 267 const T *v, 268 size_t baseElementSize, 269 const sh::BlockMemberInfo &layoutInfo, 270 angle::MemoryBuffer *uniformData) 271{ 272 const int elementSize = (int)(baseElementSize * componentCount); 273 274 uint8_t *dst = uniformData->data() + layoutInfo.offset; 275 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize) 276 { 277 uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride; 278 uint8_t *writePtr = dst + arrayOffset; 279 ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size()); 280 memcpy(writePtr, v, elementSize * count); 281 } 282 else 283 { 284 // Have to respect the arrayStride between each element of the array. 285 int maxIndex = arrayIndex + count; 286 for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex; 287 writeIndex++, readIndex++) 288 { 289 const int arrayOffset = writeIndex * layoutInfo.arrayStride; 290 uint8_t *writePtr = dst + arrayOffset; 291 const T *readPtr = v + (readIndex * componentCount); 292 ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size()); 293 memcpy(writePtr, readPtr, elementSize); 294 } 295 } 296} 297template <typename T> 298void ReadFromDefaultUniformBlock(int componentCount, 299 uint32_t arrayIndex, 300 T *dst, 301 size_t elementSize, 302 const sh::BlockMemberInfo &layoutInfo, 303 const angle::MemoryBuffer *uniformData) 304{ 305 ReadFromDefaultUniformBlockWithElementSize(componentCount, arrayIndex, dst, sizeof(T), 306 layoutInfo, uniformData); 307} 308 309void ReadFromDefaultUniformBlockWithElementSize(int componentCount, 310 uint32_t arrayIndex, 311 void *dst, 312 size_t baseElementSize, 313 const sh::BlockMemberInfo &layoutInfo, 314 const angle::MemoryBuffer *uniformData) 315{ 316 ASSERT(layoutInfo.offset != -1); 317 318 const size_t elementSize = (baseElementSize * componentCount); 319 const uint8_t *source = uniformData->data() + layoutInfo.offset; 320 321 if (layoutInfo.arrayStride == 0 || (size_t)layoutInfo.arrayStride == elementSize) 322 { 323 const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride; 324 memcpy(dst, readPtr, elementSize); 325 } 326 else 327 { 328 // Have to respect the arrayStride between each element of the array. 329 const int arrayOffset = arrayIndex * layoutInfo.arrayStride; 330 const uint8_t *readPtr = source + arrayOffset; 331 memcpy(dst, readPtr, elementSize); 332 } 333} 334 335class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory 336{ 337 public: 338 sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); } 339}; 340 341class Std430BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory 342{ 343 public: 344 sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std430BlockEncoder(); } 345}; 346 347class StdMTLBLockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory 348{ 349 public: 350 sh::BlockLayoutEncoder *makeEncoder() override { return new mtl::BlockLayoutEncoderMTL(); } 351}; 352} // anonymous namespace 353 354angle::Result CreateMslShaderLib(ContextMtl *context, 355 gl::InfoLog &infoLog, 356 mtl::TranslatedShaderInfo *translatedMslInfo, 357 const std::map<std::string, std::string> &substitutionMacros) 358{ 359 ANGLE_MTL_OBJC_SCOPE 360 { 361 mtl::LibraryCache &libraryCache = context->getDisplay()->getLibraryCache(); 362 363 // Convert to actual binary shader 364 mtl::AutoObjCPtr<NSError *> err = nil; 365 bool disableFastMath = DisableFastMathForShaderCompilation(context); 366 bool usesInvariance = UsesInvariance(translatedMslInfo); 367 translatedMslInfo->metalLibrary = libraryCache.getOrCompileShaderLibrary( 368 context, translatedMslInfo->metalShaderSource, substitutionMacros, disableFastMath, 369 usesInvariance, &err); 370 if (err && !translatedMslInfo->metalLibrary) 371 { 372 std::ostringstream ss; 373 ss << "Internal error compiling shader with Metal backend.\n"; 374 ss << err.get().localizedDescription.UTF8String << "\n"; 375 ss << "-----\n"; 376 ss << *(translatedMslInfo->metalShaderSource); 377 ss << "-----\n"; 378 379 infoLog << ss.str(); 380 381 ANGLE_MTL_HANDLE_ERROR(context, ss.str().c_str(), GL_INVALID_OPERATION); 382 return angle::Result::Stop; 383 } 384 385 return angle::Result::Continue; 386 } 387} 388DefaultUniformBlockMtl::DefaultUniformBlockMtl() {} 389 390DefaultUniformBlockMtl::~DefaultUniformBlockMtl() = default; 391 392ProgramExecutableMtl::ProgramExecutableMtl(const gl::ProgramExecutable *executable) 393 : ProgramExecutableImpl(executable), mProgramHasFlatAttributes(false), mShadowCompareModes{} 394{ 395 mCurrentShaderVariants.fill(nullptr); 396 397 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 398 { 399 mMslShaderTranslateInfo[shaderType].reset(); 400 } 401 mMslXfbOnlyVertexShaderInfo.reset(); 402} 403 404ProgramExecutableMtl::~ProgramExecutableMtl() {} 405 406void ProgramExecutableMtl::destroy(const gl::Context *context) 407{ 408 auto contextMtl = mtl::GetImpl(context); 409 reset(contextMtl); 410} 411 412void ProgramExecutableMtl::reset(ContextMtl *context) 413{ 414 mProgramHasFlatAttributes = false; 415 416 for (auto &block : mDefaultUniformBlocks) 417 { 418 block.uniformLayout.clear(); 419 } 420 421 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 422 { 423 mMslShaderTranslateInfo[shaderType].reset(); 424 mCurrentShaderVariants[shaderType] = nullptr; 425 } 426 mMslXfbOnlyVertexShaderInfo.reset(); 427 428 for (ProgramShaderObjVariantMtl &var : mVertexShaderVariants) 429 { 430 var.reset(context); 431 } 432 for (ProgramShaderObjVariantMtl &var : mFragmentShaderVariants) 433 { 434 var.reset(context); 435 } 436 437 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 438 { 439 if (mDefaultUniformBufferPools[shaderType]) 440 { 441 mDefaultUniformBufferPools[shaderType]->destroy(context); 442 mDefaultUniformBufferPools[shaderType].reset(); 443 } 444 } 445} 446 447angle::Result ProgramExecutableMtl::load(ContextMtl *contextMtl, gl::BinaryInputStream *stream) 448{ 449 loadTranslatedShaders(stream); 450 loadShaderInternalInfo(stream); 451 ANGLE_TRY(loadDefaultUniformBlocksInfo(contextMtl, stream)); 452 return loadInterfaceBlockInfo(stream); 453} 454 455void ProgramExecutableMtl::save(gl::BinaryOutputStream *stream) 456{ 457 saveTranslatedShaders(stream); 458 saveShaderInternalInfo(stream); 459 saveDefaultUniformBlocksInfo(stream); 460 saveInterfaceBlockInfo(stream); 461} 462 463void ProgramExecutableMtl::saveInterfaceBlockInfo(gl::BinaryOutputStream *stream) 464{ 465 // Serializes the uniformLayout data of mDefaultUniformBlocks 466 // First, save the number of Ib's to process 467 stream->writeInt<unsigned int>((unsigned int)mUniformBlockConversions.size()); 468 // Next, iterate through all of the conversions. 469 for (auto conversion : mUniformBlockConversions) 470 { 471 // Write the name of the conversion 472 stream->writeString(conversion.first); 473 // Write the number of entries in the conversion 474 const UBOConversionInfo &conversionInfo = conversion.second; 475 stream->writeVector(conversionInfo.stdInfo()); 476 stream->writeVector(conversionInfo.metalInfo()); 477 stream->writeInt<size_t>(conversionInfo.stdSize()); 478 stream->writeInt<size_t>(conversionInfo.metalSize()); 479 } 480} 481 482angle::Result ProgramExecutableMtl::loadInterfaceBlockInfo(gl::BinaryInputStream *stream) 483{ 484 mUniformBlockConversions.clear(); 485 // First, load the number of Ib's to process 486 uint32_t numBlocks = stream->readInt<uint32_t>(); 487 // Next, iterate through all of the conversions. 488 for (uint32_t nBlocks = 0; nBlocks < numBlocks; ++nBlocks) 489 { 490 // Read the name of the conversion 491 std::string blockName = stream->readString(); 492 // Read the number of entries in the conversion 493 std::vector<sh::BlockMemberInfo> stdInfo, metalInfo; 494 stream->readVector(&stdInfo); 495 stream->readVector(&metalInfo); 496 size_t stdSize = stream->readInt<size_t>(); 497 size_t metalSize = stream->readInt<size_t>(); 498 mUniformBlockConversions.insert( 499 {blockName, UBOConversionInfo(stdInfo, metalInfo, stdSize, metalSize)}); 500 } 501 return angle::Result::Continue; 502} 503 504void ProgramExecutableMtl::saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream) 505{ 506 // Serializes the uniformLayout data of mDefaultUniformBlocks 507 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 508 { 509 stream->writeVector(mDefaultUniformBlocks[shaderType].uniformLayout); 510 } 511 512 // Serializes required uniform block memory sizes 513 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 514 { 515 stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size()); 516 } 517} 518 519angle::Result ProgramExecutableMtl::loadDefaultUniformBlocksInfo(mtl::Context *context, 520 gl::BinaryInputStream *stream) 521{ 522 gl::ShaderMap<size_t> requiredBufferSize; 523 requiredBufferSize.fill(0); 524 // Deserializes the uniformLayout data of mDefaultUniformBlocks 525 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 526 { 527 stream->readVector(&mDefaultUniformBlocks[shaderType].uniformLayout); 528 } 529 530 // Deserializes required uniform block memory sizes 531 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 532 { 533 requiredBufferSize[shaderType] = stream->readInt<size_t>(); 534 } 535 536 return resizeDefaultUniformBlocksMemory(context, requiredBufferSize); 537} 538 539void ProgramExecutableMtl::saveShaderInternalInfo(gl::BinaryOutputStream *stream) 540{ 541 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 542 { 543 stream->writeInt<int>(mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer); 544 for (const mtl::SamplerBinding &binding : 545 mMslShaderTranslateInfo[shaderType].actualSamplerBindings) 546 { 547 stream->writeInt<uint32_t>(binding.textureBinding); 548 stream->writeInt<uint32_t>(binding.samplerBinding); 549 } 550 for (int rwTextureBinding : mMslShaderTranslateInfo[shaderType].actualImageBindings) 551 { 552 stream->writeInt<int>(rwTextureBinding); 553 } 554 555 for (uint32_t uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings) 556 { 557 stream->writeInt<uint32_t>(uboBinding); 558 } 559 stream->writeBool(mMslShaderTranslateInfo[shaderType].hasInvariant); 560 } 561 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 562 { 563 stream->writeInt( 564 mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]); 565 } 566 567 // Write out XFB info. 568 { 569 stream->writeInt<int>(mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer); 570 for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings) 571 { 572 stream->writeInt<uint32_t>(binding.textureBinding); 573 stream->writeInt<uint32_t>(binding.samplerBinding); 574 } 575 for (int rwTextureBinding : mMslXfbOnlyVertexShaderInfo.actualImageBindings) 576 { 577 stream->writeInt<int>(rwTextureBinding); 578 } 579 580 for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings) 581 { 582 stream->writeInt<uint32_t>(uboBinding); 583 } 584 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 585 { 586 stream->writeInt(mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]); 587 } 588 } 589 590 stream->writeBool(mProgramHasFlatAttributes); 591} 592 593void ProgramExecutableMtl::loadShaderInternalInfo(gl::BinaryInputStream *stream) 594{ 595 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 596 { 597 mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer = stream->readInt<int>() != 0; 598 for (mtl::SamplerBinding &binding : 599 mMslShaderTranslateInfo[shaderType].actualSamplerBindings) 600 { 601 binding.textureBinding = stream->readInt<uint32_t>(); 602 binding.samplerBinding = stream->readInt<uint32_t>(); 603 } 604 for (int &rwTextureBinding : mMslShaderTranslateInfo[shaderType].actualImageBindings) 605 { 606 rwTextureBinding = stream->readInt<int>(); 607 } 608 609 for (uint32_t &uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings) 610 { 611 uboBinding = stream->readInt<uint32_t>(); 612 } 613 mMslShaderTranslateInfo[shaderType].hasInvariant = stream->readBool(); 614 } 615 616 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 617 { 618 stream->readInt( 619 &mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]); 620 } 621 // Load Transform Feedback info 622 { 623 mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer = stream->readInt<int>() != 0; 624 for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings) 625 { 626 binding.textureBinding = stream->readInt<uint32_t>(); 627 binding.samplerBinding = stream->readInt<uint32_t>(); 628 } 629 for (int &rwTextureBinding : mMslXfbOnlyVertexShaderInfo.actualImageBindings) 630 { 631 rwTextureBinding = stream->readInt<int>(); 632 } 633 634 for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings) 635 { 636 uboBinding = stream->readInt<uint32_t>(); 637 } 638 for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++) 639 { 640 stream->readInt(&mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]); 641 } 642 mMslXfbOnlyVertexShaderInfo.metalLibrary = nullptr; 643 } 644 645 mProgramHasFlatAttributes = stream->readBool(); 646} 647 648void ProgramExecutableMtl::saveTranslatedShaders(gl::BinaryOutputStream *stream) 649{ 650 auto writeTranslatedSource = [](gl::BinaryOutputStream *stream, 651 const mtl::TranslatedShaderInfo &shaderInfo) { 652 const std::string &source = 653 shaderInfo.metalShaderSource ? *shaderInfo.metalShaderSource : std::string(); 654 stream->writeString(source); 655 }; 656 657 // Write out shader sources for all shader types 658 for (const gl::ShaderType shaderType : gl::AllShaderTypes()) 659 { 660 writeTranslatedSource(stream, mMslShaderTranslateInfo[shaderType]); 661 } 662 writeTranslatedSource(stream, mMslXfbOnlyVertexShaderInfo); 663} 664 665void ProgramExecutableMtl::loadTranslatedShaders(gl::BinaryInputStream *stream) 666{ 667 auto readTranslatedSource = [](gl::BinaryInputStream *stream, 668 mtl::TranslatedShaderInfo &shaderInfo) { 669 std::string source = stream->readString(); 670 if (!source.empty()) 671 { 672 shaderInfo.metalShaderSource = std::make_shared<const std::string>(std::move(source)); 673 } 674 else 675 { 676 shaderInfo.metalShaderSource = nullptr; 677 } 678 }; 679 680 // Read in shader sources for all shader types 681 for (const gl::ShaderType shaderType : gl::AllShaderTypes()) 682 { 683 readTranslatedSource(stream, mMslShaderTranslateInfo[shaderType]); 684 } 685 readTranslatedSource(stream, mMslXfbOnlyVertexShaderInfo); 686} 687 688void ProgramExecutableMtl::linkUpdateHasFlatAttributes( 689 const gl::SharedCompiledShaderState &vertexShader) 690{ 691 mProgramHasFlatAttributes = false; 692 693 const auto &programInputs = mExecutable->getProgramInputs(); 694 for (auto &attribute : programInputs) 695 { 696 if (attribute.getInterpolation() == sh::INTERPOLATION_FLAT) 697 { 698 mProgramHasFlatAttributes = true; 699 return; 700 } 701 } 702 703 const auto &flatVaryings = vertexShader->outputVaryings; 704 for (auto &attribute : flatVaryings) 705 { 706 if (attribute.interpolation == sh::INTERPOLATION_FLAT) 707 { 708 mProgramHasFlatAttributes = true; 709 return; 710 } 711 } 712} 713 714angle::Result ProgramExecutableMtl::initDefaultUniformBlocks( 715 mtl::Context *context, 716 const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders) 717{ 718 // Process vertex and fragment uniforms into std140 packing. 719 gl::ShaderMap<sh::BlockLayoutMap> layoutMap; 720 gl::ShaderMap<size_t> requiredBufferSize; 721 requiredBufferSize.fill(0); 722 723 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 724 { 725 const gl::SharedCompiledShaderState &shader = shaders[shaderType]; 726 if (shader) 727 { 728 const std::vector<sh::Uniform> &uniforms = shader->uniforms; 729 InitDefaultUniformBlock(uniforms, &layoutMap[shaderType], 730 &requiredBufferSize[shaderType]); 731 // Set up block conversion buffer 732 initUniformBlocksRemapper(shader); 733 } 734 } 735 736 // Init the default block layout info. 737 const auto &uniforms = mExecutable->getUniforms(); 738 const auto &uniformNames = mExecutable->getUniformNames(); 739 const auto &uniformLocations = mExecutable->getUniformLocations(); 740 for (size_t locSlot = 0; locSlot < uniformLocations.size(); ++locSlot) 741 { 742 const gl::VariableLocation &location = uniformLocations[locSlot]; 743 gl::ShaderMap<sh::BlockMemberInfo> layoutInfo; 744 745 if (location.used() && !location.ignored) 746 { 747 const gl::LinkedUniform &uniform = uniforms[location.index]; 748 if (uniform.isInDefaultBlock() && !uniform.isSampler() && !uniform.isImage()) 749 { 750 std::string uniformName = uniformNames[location.index]; 751 if (uniform.isArray()) 752 { 753 // Gets the uniform name without the [0] at the end. 754 uniformName = gl::ParseResourceName(uniformName, nullptr); 755 } 756 757 bool found = false; 758 759 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 760 { 761 auto it = layoutMap[shaderType].find(uniformName); 762 if (it != layoutMap[shaderType].end()) 763 { 764 found = true; 765 layoutInfo[shaderType] = it->second; 766 } 767 } 768 769 ASSERT(found); 770 } 771 } 772 773 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 774 { 775 mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]); 776 } 777 } 778 779 return resizeDefaultUniformBlocksMemory(context, requiredBufferSize); 780} 781 782angle::Result ProgramExecutableMtl::resizeDefaultUniformBlocksMemory( 783 mtl::Context *context, 784 const gl::ShaderMap<size_t> &requiredBufferSize) 785{ 786 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 787 { 788 if (requiredBufferSize[shaderType] > 0) 789 { 790 ASSERT(requiredBufferSize[shaderType] <= mtl::kDefaultUniformsMaxSize); 791 792 if (!mDefaultUniformBlocks[shaderType].uniformData.resize( 793 requiredBufferSize[shaderType])) 794 { 795 ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY); 796 } 797 798 // Initialize uniform buffer memory to zero by default. 799 mDefaultUniformBlocks[shaderType].uniformData.fill(0); 800 mDefaultUniformBlocksDirty.set(shaderType); 801 } 802 } 803 804 return angle::Result::Continue; 805} 806 807// TODO(angleproject:7979) Upgrade ANGLE Uniform buffer remapper to compute shaders 808void ProgramExecutableMtl::initUniformBlocksRemapper(const gl::SharedCompiledShaderState &shader) 809{ 810 std::unordered_map<std::string, UBOConversionInfo> conversionMap; 811 const std::vector<sh::InterfaceBlock> ibs = shader->uniformBlocks; 812 for (size_t i = 0; i < ibs.size(); ++i) 813 { 814 815 const sh::InterfaceBlock &ib = ibs[i]; 816 if (mUniformBlockConversions.find(ib.name) == mUniformBlockConversions.end()) 817 { 818 mtl::BlockLayoutEncoderMTL metalEncoder; 819 sh::BlockLayoutEncoder *encoder; 820 switch (ib.layout) 821 { 822 case sh::BLOCKLAYOUT_PACKED: 823 case sh::BLOCKLAYOUT_SHARED: 824 case sh::BLOCKLAYOUT_STD140: 825 { 826 Std140BlockLayoutEncoderFactory factory; 827 encoder = factory.makeEncoder(); 828 } 829 break; 830 case sh::BLOCKLAYOUT_STD430: 831 { 832 Std430BlockLayoutEncoderFactory factory; 833 encoder = factory.makeEncoder(); 834 } 835 break; 836 } 837 sh::BlockLayoutMap blockLayoutMapOut, stdMapOut; 838 839 sh::GetInterfaceBlockInfo(ib.fields, "", &metalEncoder, &blockLayoutMapOut); 840 sh::GetInterfaceBlockInfo(ib.fields, "", encoder, &stdMapOut); 841 842 auto stdIterator = stdMapOut.begin(); 843 auto mtlIterator = blockLayoutMapOut.begin(); 844 845 std::vector<sh::BlockMemberInfo> stdConversions, mtlConversions; 846 while (stdIterator != stdMapOut.end()) 847 { 848 stdConversions.push_back(stdIterator->second); 849 mtlConversions.push_back(mtlIterator->second); 850 stdIterator++; 851 mtlIterator++; 852 } 853 std::sort(stdConversions.begin(), stdConversions.end(), CompareBlockInfo); 854 std::sort(mtlConversions.begin(), mtlConversions.end(), CompareBlockInfo); 855 856 size_t stdSize = encoder->getCurrentOffset(); 857 size_t metalAlign = GetAlignmentOfUniformGroup(&blockLayoutMapOut); 858 size_t metalSize = roundUp(metalEncoder.getCurrentOffset(), metalAlign); 859 860 conversionMap.insert( 861 {ib.name, UBOConversionInfo(stdConversions, mtlConversions, stdSize, metalSize)}); 862 SafeDelete(encoder); 863 } 864 } 865 mUniformBlockConversions.insert(conversionMap.begin(), conversionMap.end()); 866} 867 868mtl::BufferPool *ProgramExecutableMtl::getBufferPool(ContextMtl *context, gl::ShaderType shaderType) 869{ 870 auto &pool = mDefaultUniformBufferPools[shaderType]; 871 if (pool == nullptr) 872 { 873 DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType]; 874 875 // Size each buffer to hold 10 draw calls worth of uniform updates before creating extra 876 // buffers. This number was chosen loosely to balance the size of buffers versus the total 877 // number allocated. Without any sub-allocation, the total buffer count can reach the 878 // thousands when many draw calls are issued with the same program. 879 size_t bufferSize = 880 std::max(uniformBlock.uniformData.size() * 10, mtl::kDefaultUniformsMaxSize * 2); 881 882 pool.reset(new mtl::BufferPool(false)); 883 884 // Allow unbounded growth of the buffer count. Doing a full CPU/GPU sync waiting for new 885 // uniform uploads has catastrophic performance cost. 886 pool->initialize(context, bufferSize, mtl::kUniformBufferSettingOffsetMinAlignment, 0); 887 } 888 return pool.get(); 889} 890 891angle::Result ProgramExecutableMtl::setupDraw(const gl::Context *glContext, 892 mtl::RenderCommandEncoder *cmdEncoder, 893 const mtl::RenderPipelineDesc &pipelineDesc, 894 bool pipelineDescChanged, 895 bool forceTexturesSetting, 896 bool uniformBuffersDirty) 897{ 898 ContextMtl *context = mtl::GetImpl(glContext); 899 900 if (pipelineDescChanged) 901 { 902 id<MTLFunction> vertexShader = nil; 903 ANGLE_TRY( 904 getSpecializedShader(context, gl::ShaderType::Vertex, pipelineDesc, &vertexShader)); 905 906 id<MTLFunction> fragmentShader = nil; 907 ANGLE_TRY( 908 getSpecializedShader(context, gl::ShaderType::Fragment, pipelineDesc, &fragmentShader)); 909 910 mtl::AutoObjCPtr<id<MTLRenderPipelineState>> pipelineState; 911 ANGLE_TRY(context->getPipelineCache().getRenderPipeline( 912 context, vertexShader, fragmentShader, pipelineDesc, &pipelineState)); 913 914 cmdEncoder->setRenderPipelineState(pipelineState); 915 916 // We need to rebind uniform buffers & textures also 917 mDefaultUniformBlocksDirty.set(); 918 mSamplerBindingsDirty.set(); 919 920 // Cache current shader variant references for easier querying. 921 mCurrentShaderVariants[gl::ShaderType::Vertex] = 922 &mVertexShaderVariants[pipelineDesc.rasterizationType]; 923 924 const bool multisampledRendering = pipelineDesc.outputDescriptor.sampleCount > 1; 925 const bool allowFragDepthWrite = 926 pipelineDesc.outputDescriptor.depthAttachmentPixelFormat != 0; 927 mCurrentShaderVariants[gl::ShaderType::Fragment] = 928 pipelineDesc.rasterizationEnabled() 929 ? &mFragmentShaderVariants[PipelineParametersToFragmentShaderVariantIndex( 930 multisampledRendering, allowFragDepthWrite)] 931 : nullptr; 932 } 933 934 ANGLE_TRY(commitUniforms(context, cmdEncoder)); 935 ANGLE_TRY(updateTextures(glContext, cmdEncoder, forceTexturesSetting)); 936 937 if (uniformBuffersDirty || pipelineDescChanged) 938 { 939 ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc)); 940 } 941 942 if (pipelineDescChanged) 943 { 944 ANGLE_TRY(updateXfbBuffers(context, cmdEncoder, pipelineDesc)); 945 } 946 947 return angle::Result::Continue; 948} 949 950angle::Result ProgramExecutableMtl::getSpecializedShader( 951 ContextMtl *context, 952 gl::ShaderType shaderType, 953 const mtl::RenderPipelineDesc &renderPipelineDesc, 954 id<MTLFunction> *shaderOut) 955{ 956 static_assert(YES == 1, "YES should have value of 1"); 957 958 mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType]; 959 ProgramShaderObjVariantMtl *shaderVariant; 960 mtl::AutoObjCObj<MTLFunctionConstantValues> funcConstants; 961 962 if (shaderType == gl::ShaderType::Vertex) 963 { 964 // For vertex shader, we need to create 3 variants, one with emulated rasterization 965 // discard, one with true rasterization discard and one without. 966 shaderVariant = &mVertexShaderVariants[renderPipelineDesc.rasterizationType]; 967 if (shaderVariant->metalShader) 968 { 969 // Already created. 970 *shaderOut = shaderVariant->metalShader; 971 return angle::Result::Continue; 972 } 973 974 if (renderPipelineDesc.rasterizationType == mtl::RenderPipelineRasterization::Disabled) 975 { 976 // Special case: XFB output only vertex shader. 977 ASSERT(!mExecutable->getLinkedTransformFeedbackVaryings().empty()); 978 translatedMslInfo = &mMslXfbOnlyVertexShaderInfo; 979 if (!translatedMslInfo->metalLibrary) 980 { 981 // Lazily compile XFB only shader 982 gl::InfoLog infoLog; 983 ANGLE_TRY(CreateMslShaderLib(context, infoLog, &mMslXfbOnlyVertexShaderInfo, 984 {{"TRANSFORM_FEEDBACK_ENABLED", "1"}})); 985 translatedMslInfo->metalLibrary.get().label = @"TransformFeedback"; 986 } 987 } 988 989 ANGLE_MTL_OBJC_SCOPE 990 { 991 BOOL emulateDiscard = renderPipelineDesc.rasterizationType == 992 mtl::RenderPipelineRasterization::EmulatedDiscard; 993 994 NSString *discardEnabledStr = 995 [NSString stringWithUTF8String:sh::mtl::kRasterizerDiscardEnabledConstName]; 996 997 funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]); 998 [funcConstants setConstantValue:&emulateDiscard 999 type:MTLDataTypeBool 1000 withName:discardEnabledStr]; 1001 } 1002 } // if (shaderType == gl::ShaderType::Vertex) 1003 else if (shaderType == gl::ShaderType::Fragment) 1004 { 1005 // For fragment shader, we need to create 4 variants, 1006 // combining multisampled rendering and depth write enabled states. 1007 const bool multisampledRendering = renderPipelineDesc.outputDescriptor.sampleCount > 1; 1008 const bool allowFragDepthWrite = 1009 renderPipelineDesc.outputDescriptor.depthAttachmentPixelFormat != 0; 1010 shaderVariant = &mFragmentShaderVariants[PipelineParametersToFragmentShaderVariantIndex( 1011 multisampledRendering, allowFragDepthWrite)]; 1012 if (shaderVariant->metalShader) 1013 { 1014 // Already created. 1015 *shaderOut = shaderVariant->metalShader; 1016 return angle::Result::Continue; 1017 } 1018 1019 ANGLE_MTL_OBJC_SCOPE 1020 { 1021 NSString *multisampledRenderingStr = 1022 [NSString stringWithUTF8String:sh::mtl::kMultisampledRenderingConstName]; 1023 1024 NSString *depthWriteEnabledStr = 1025 [NSString stringWithUTF8String:sh::mtl::kDepthWriteEnabledConstName]; 1026 1027 funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]); 1028 [funcConstants setConstantValue:&multisampledRendering 1029 type:MTLDataTypeBool 1030 withName:multisampledRenderingStr]; 1031 [funcConstants setConstantValue:&allowFragDepthWrite 1032 type:MTLDataTypeBool 1033 withName:depthWriteEnabledStr]; 1034 } 1035 1036 } // gl::ShaderType::Fragment 1037 else 1038 { 1039 UNREACHABLE(); 1040 return angle::Result::Stop; 1041 } 1042 [funcConstants 1043 setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareGradient.enabled) 1044 type:MTLDataTypeBool 1045 withName:@"ANGLEUseSampleCompareGradient"]; 1046 [funcConstants 1047 setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareLod.enabled) 1048 type:MTLDataTypeBool 1049 withName:@"ANGLEUseSampleCompareLod"]; 1050 [funcConstants 1051 setConstantValue:&(context->getDisplay()->getFeatures().emulateAlphaToCoverage.enabled) 1052 type:MTLDataTypeBool 1053 withName:@"ANGLEEmulateAlphaToCoverage"]; 1054 [funcConstants 1055 setConstantValue:&(context->getDisplay()->getFeatures().writeHelperSampleMask.enabled) 1056 type:MTLDataTypeBool 1057 withName:@"ANGLEWriteHelperSampleMask"]; 1058 // Create Metal shader object 1059 ANGLE_MTL_OBJC_SCOPE 1060 { 1061 ANGLE_TRY(CreateMslShader(context, translatedMslInfo->metalLibrary, SHADER_ENTRY_NAME, 1062 funcConstants.get(), &shaderVariant->metalShader)); 1063 } 1064 1065 // Store reference to the translated source for easily querying mapped bindings later. 1066 shaderVariant->translatedSrcInfo = translatedMslInfo; 1067 1068 // Initialize argument buffer encoder if required 1069 if (translatedMslInfo->hasUBOArgumentBuffer) 1070 { 1071 InitArgumentBufferEncoder(context, shaderVariant->metalShader, 1072 mtl::kUBOArgumentBufferBindingIndex, 1073 &shaderVariant->uboArgBufferEncoder); 1074 } 1075 1076 *shaderOut = shaderVariant->metalShader; 1077 1078 return angle::Result::Continue; 1079} 1080 1081angle::Result ProgramExecutableMtl::commitUniforms(ContextMtl *context, 1082 mtl::RenderCommandEncoder *cmdEncoder) 1083{ 1084 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1085 { 1086 if (!mDefaultUniformBlocksDirty[shaderType] || !mCurrentShaderVariants[shaderType]) 1087 { 1088 continue; 1089 } 1090 DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType]; 1091 1092 if (!uniformBlock.uniformData.size()) 1093 { 1094 continue; 1095 } 1096 1097 // If we exceed the default inline max size, try to allocate a buffer 1098 bool needsCommitUniform = true; 1099 if (needsCommitUniform && uniformBlock.uniformData.size() <= mtl::kInlineConstDataMaxSize) 1100 { 1101 ASSERT(uniformBlock.uniformData.size() <= mtl::kInlineConstDataMaxSize); 1102 cmdEncoder->setBytes(shaderType, uniformBlock.uniformData.data(), 1103 uniformBlock.uniformData.size(), 1104 mtl::kDefaultUniformsBindingIndex); 1105 } 1106 else if (needsCommitUniform) 1107 { 1108 mtl::BufferPool *bufferPool = getBufferPool(context, shaderType); 1109 bufferPool->releaseInFlightBuffers(context); 1110 1111 ASSERT(uniformBlock.uniformData.size() <= mtl::kDefaultUniformsMaxSize); 1112 mtl::BufferRef mtlBufferOut; 1113 size_t offsetOut; 1114 uint8_t *ptrOut; 1115 // Allocate a new Uniform buffer 1116 ANGLE_TRY(bufferPool->allocate(context, uniformBlock.uniformData.size(), &ptrOut, 1117 &mtlBufferOut, &offsetOut)); 1118 // Copy the uniform result 1119 memcpy(ptrOut, uniformBlock.uniformData.data(), uniformBlock.uniformData.size()); 1120 // Commit 1121 ANGLE_TRY(bufferPool->commit(context)); 1122 // Set buffer 1123 cmdEncoder->setBuffer(shaderType, mtlBufferOut, (uint32_t)offsetOut, 1124 mtl::kDefaultUniformsBindingIndex); 1125 } 1126 1127 mDefaultUniformBlocksDirty.reset(shaderType); 1128 } 1129 return angle::Result::Continue; 1130} 1131 1132angle::Result ProgramExecutableMtl::updateTextures(const gl::Context *glContext, 1133 mtl::RenderCommandEncoder *cmdEncoder, 1134 bool forceUpdate) 1135{ 1136 ContextMtl *contextMtl = mtl::GetImpl(glContext); 1137 const auto &glState = glContext->getState(); 1138 const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache(); 1139 1140 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1141 { 1142 if ((!mSamplerBindingsDirty[shaderType] && !forceUpdate) || 1143 !mCurrentShaderVariants[shaderType]) 1144 { 1145 continue; 1146 } 1147 1148 const mtl::TranslatedShaderInfo &shaderInfo = 1149 mCurrentShaderVariants[shaderType]->translatedSrcInfo 1150 ? *mCurrentShaderVariants[shaderType]->translatedSrcInfo 1151 : mMslShaderTranslateInfo[shaderType]; 1152 bool hasDepthSampler = false; 1153 1154 for (uint32_t textureIndex = 0; textureIndex < mExecutable->getSamplerBindings().size(); 1155 ++textureIndex) 1156 { 1157 const gl::SamplerBinding &samplerBinding = 1158 mExecutable->getSamplerBindings()[textureIndex]; 1159 const mtl::SamplerBinding &mslBinding = shaderInfo.actualSamplerBindings[textureIndex]; 1160 if (mslBinding.textureBinding >= mtl::kMaxShaderSamplers) 1161 { 1162 // No binding assigned 1163 continue; 1164 } 1165 1166 gl::TextureType textureType = samplerBinding.textureType; 1167 1168 for (uint32_t arrayElement = 0; arrayElement < samplerBinding.textureUnitsCount; 1169 ++arrayElement) 1170 { 1171 GLuint textureUnit = samplerBinding.getTextureUnit( 1172 mExecutable->getSamplerBoundTextureUnits(), arrayElement); 1173 gl::Texture *texture = completeTextures[textureUnit]; 1174 gl::Sampler *sampler = contextMtl->getState().getSampler(textureUnit); 1175 uint32_t textureSlot = mslBinding.textureBinding + arrayElement; 1176 uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement; 1177 if (!texture) 1178 { 1179 ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, 1180 samplerBinding.format, &texture)); 1181 } 1182 const gl::SamplerState *samplerState = 1183 sampler ? &sampler->getSamplerState() : &texture->getSamplerState(); 1184 TextureMtl *textureMtl = mtl::GetImpl(texture); 1185 if (samplerBinding.format == gl::SamplerFormat::Shadow) 1186 { 1187 hasDepthSampler = true; 1188 mShadowCompareModes[textureSlot] = mtl::MslGetShaderShadowCompareMode( 1189 samplerState->getCompareMode(), samplerState->getCompareFunc()); 1190 } 1191 ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler, 1192 textureSlot, samplerSlot)); 1193 } // for array elements 1194 } // for sampler bindings 1195 1196 if (hasDepthSampler) 1197 { 1198 cmdEncoder->setData(shaderType, mShadowCompareModes, 1199 mtl::kShadowSamplerCompareModesBindingIndex); 1200 } 1201 1202 for (const gl::ImageBinding &imageBinding : mExecutable->getImageBindings()) 1203 { 1204 if (imageBinding.boundImageUnits.size() != 1) 1205 { 1206 UNIMPLEMENTED(); 1207 continue; 1208 } 1209 1210 int glslImageBinding = imageBinding.boundImageUnits[0]; 1211 int mtlRWTextureBinding = shaderInfo.actualImageBindings[glslImageBinding]; 1212 ASSERT(mtlRWTextureBinding < static_cast<int>(mtl::kMaxShaderImages)); 1213 if (mtlRWTextureBinding < 0) 1214 { 1215 continue; // The program does not have an image bound at this unit. 1216 } 1217 1218 const gl::ImageUnit &imageUnit = glState.getImageUnit(glslImageBinding); 1219 TextureMtl *textureMtl = mtl::GetImpl(imageUnit.texture.get()); 1220 if (imageUnit.layered) 1221 { 1222 UNIMPLEMENTED(); 1223 continue; 1224 } 1225 ANGLE_TRY(textureMtl->bindToShaderImage( 1226 glContext, cmdEncoder, shaderType, static_cast<uint32_t>(mtlRWTextureBinding), 1227 imageUnit.level, imageUnit.layer, imageUnit.format)); 1228 } 1229 } // for shader types 1230 1231 return angle::Result::Continue; 1232} 1233 1234angle::Result ProgramExecutableMtl::updateUniformBuffers( 1235 ContextMtl *context, 1236 mtl::RenderCommandEncoder *cmdEncoder, 1237 const mtl::RenderPipelineDesc &pipelineDesc) 1238{ 1239 const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks(); 1240 if (blocks.empty()) 1241 { 1242 return angle::Result::Continue; 1243 } 1244 1245 // This array is only used inside this function and its callees. 1246 ScopedAutoClearVector<uint32_t> scopeArrayClear(&mArgumentBufferRenderStageUsages); 1247 ScopedAutoClearVector<std::pair<mtl::BufferRef, uint32_t>> scopeArrayClear2( 1248 &mLegalizedOffsetedUniformBuffers); 1249 mArgumentBufferRenderStageUsages.resize(blocks.size()); 1250 mLegalizedOffsetedUniformBuffers.resize(blocks.size()); 1251 1252 ANGLE_TRY(legalizeUniformBufferOffsets(context)); 1253 1254 const gl::State &glState = context->getState(); 1255 1256 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1257 { 1258 if (!mCurrentShaderVariants[shaderType]) 1259 { 1260 continue; 1261 } 1262 1263 if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer) 1264 { 1265 ANGLE_TRY(encodeUniformBuffersInfoArgumentBuffer(context, cmdEncoder, shaderType)); 1266 } 1267 else 1268 { 1269 ANGLE_TRY(bindUniformBuffersToDiscreteSlots(context, cmdEncoder, shaderType)); 1270 } 1271 } // for shader types 1272 1273 // After encode the uniform buffers into an argument buffer, we need to tell Metal that 1274 // the buffers are being used by what shader stages. 1275 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1276 { 1277 const GLuint binding = mExecutable->getUniformBlockBinding(bufferIndex); 1278 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1279 glState.getIndexedUniformBuffer(binding); 1280 if (bufferBinding.get() == nullptr) 1281 { 1282 continue; 1283 } 1284 1285 // Remove any other stages other than vertex and fragment. 1286 uint32_t stages = mArgumentBufferRenderStageUsages[bufferIndex] & 1287 (mtl::kRenderStageVertex | mtl::kRenderStageFragment); 1288 1289 if (stages == 0) 1290 { 1291 continue; 1292 } 1293 1294 cmdEncoder->useResource(mLegalizedOffsetedUniformBuffers[bufferIndex].first, 1295 MTLResourceUsageRead, static_cast<mtl::RenderStages>(stages)); 1296 } 1297 1298 return angle::Result::Continue; 1299} 1300 1301angle::Result ProgramExecutableMtl::legalizeUniformBufferOffsets(ContextMtl *context) 1302{ 1303 const gl::State &glState = context->getState(); 1304 const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks(); 1305 1306 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1307 { 1308 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1309 const GLuint binding = mExecutable->getUniformBlockBinding(bufferIndex); 1310 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1311 glState.getIndexedUniformBuffer(binding); 1312 1313 if (bufferBinding.get() == nullptr) 1314 { 1315 continue; 1316 } 1317 1318 BufferMtl *bufferMtl = mtl::GetImpl(bufferBinding.get()); 1319 size_t srcOffset = std::min<size_t>(bufferBinding.getOffset(), bufferMtl->size()); 1320 ASSERT(mUniformBlockConversions.find(block.name) != mUniformBlockConversions.end()); 1321 const UBOConversionInfo &conversionInfo = mUniformBlockConversions.at(block.name); 1322 if (conversionInfo.needsConversion()) 1323 { 1324 1325 UniformConversionBufferMtl *conversion = 1326 (UniformConversionBufferMtl *)bufferMtl->getUniformConversionBuffer( 1327 context, std::pair<size_t, size_t>(bufferIndex, srcOffset), 1328 conversionInfo.stdSize()); 1329 // Has the content of the buffer has changed since last conversion? 1330 if (conversion->dirty) 1331 { 1332 const uint8_t *srcBytes = bufferMtl->getBufferDataReadOnly(context); 1333 srcBytes += conversion->initialSrcOffset(); 1334 size_t sizeToCopy = bufferMtl->size() - conversion->initialSrcOffset(); 1335 1336 ANGLE_TRY(ConvertUniformBufferData( 1337 context, conversionInfo, &conversion->data, srcBytes, sizeToCopy, 1338 &conversion->convertedBuffer, &conversion->convertedOffset)); 1339 1340 conversion->dirty = false; 1341 } 1342 // Calculate offset in new block. 1343 size_t dstOffsetSource = srcOffset - conversion->initialSrcOffset(); 1344 ASSERT(dstOffsetSource % conversionInfo.stdSize() == 0); 1345 unsigned int numBlocksToOffset = 1346 (unsigned int)(dstOffsetSource / conversionInfo.stdSize()); 1347 size_t bytesToOffset = numBlocksToOffset * conversionInfo.metalSize(); 1348 1349 mLegalizedOffsetedUniformBuffers[bufferIndex].first = conversion->convertedBuffer; 1350 mLegalizedOffsetedUniformBuffers[bufferIndex].second = 1351 static_cast<uint32_t>(conversion->convertedOffset + bytesToOffset); 1352 // Ensure that the converted info can fit in the buffer. 1353 ASSERT(conversion->convertedOffset + bytesToOffset + conversionInfo.metalSize() <= 1354 conversion->convertedBuffer->size()); 1355 } 1356 else 1357 { 1358 mLegalizedOffsetedUniformBuffers[bufferIndex].first = bufferMtl->getCurrentBuffer(); 1359 mLegalizedOffsetedUniformBuffers[bufferIndex].second = 1360 static_cast<uint32_t>(bufferBinding.getOffset()); 1361 } 1362 } 1363 return angle::Result::Continue; 1364} 1365 1366angle::Result ProgramExecutableMtl::bindUniformBuffersToDiscreteSlots( 1367 ContextMtl *context, 1368 mtl::RenderCommandEncoder *cmdEncoder, 1369 gl::ShaderType shaderType) 1370{ 1371 const gl::State &glState = context->getState(); 1372 const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks(); 1373 const mtl::TranslatedShaderInfo &shaderInfo = 1374 *mCurrentShaderVariants[shaderType]->translatedSrcInfo; 1375 1376 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1377 { 1378 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1379 const GLuint binding = mExecutable->getUniformBlockBinding(bufferIndex); 1380 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1381 glState.getIndexedUniformBuffer(binding); 1382 1383 if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType)) 1384 { 1385 continue; 1386 } 1387 1388 uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex]; 1389 1390 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1391 { 1392 continue; 1393 } 1394 1395 mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first; 1396 uint32_t offset = mLegalizedOffsetedUniformBuffers[bufferIndex].second; 1397 cmdEncoder->setBuffer(shaderType, mtlBuffer, offset, actualBufferIdx); 1398 } 1399 return angle::Result::Continue; 1400} 1401 1402angle::Result ProgramExecutableMtl::encodeUniformBuffersInfoArgumentBuffer( 1403 ContextMtl *context, 1404 mtl::RenderCommandEncoder *cmdEncoder, 1405 gl::ShaderType shaderType) 1406{ 1407 const gl::State &glState = context->getState(); 1408 const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks(); 1409 1410 ASSERT(mCurrentShaderVariants[shaderType]->translatedSrcInfo); 1411 const mtl::TranslatedShaderInfo &shaderInfo = 1412 *mCurrentShaderVariants[shaderType]->translatedSrcInfo; 1413 1414 // Encode all uniform buffers into an argument buffer. 1415 ProgramArgumentBufferEncoderMtl &bufferEncoder = 1416 mCurrentShaderVariants[shaderType]->uboArgBufferEncoder; 1417 1418 mtl::BufferRef argumentBuffer; 1419 size_t argumentBufferOffset; 1420 bufferEncoder.bufferPool.releaseInFlightBuffers(context); 1421 ANGLE_TRY(bufferEncoder.bufferPool.allocate( 1422 context, bufferEncoder.metalArgBufferEncoder.get().encodedLength, nullptr, &argumentBuffer, 1423 &argumentBufferOffset)); 1424 1425 // MTLArgumentEncoder is modifying the buffer indirectly on CPU. We need to call map() 1426 // so that the buffer's data changes could be flushed to the GPU side later. 1427 ANGLE_UNUSED_VARIABLE(argumentBuffer->mapWithOpt(context, /*readonly=*/false, /*noSync=*/true)); 1428 1429 [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get() 1430 offset:argumentBufferOffset]; 1431 1432 constexpr gl::ShaderMap<MTLRenderStages> kShaderStageMap = { 1433 {gl::ShaderType::Vertex, mtl::kRenderStageVertex}, 1434 {gl::ShaderType::Fragment, mtl::kRenderStageFragment}, 1435 }; 1436 1437 auto mtlRenderStage = kShaderStageMap[shaderType]; 1438 1439 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex) 1440 { 1441 const gl::InterfaceBlock &block = blocks[bufferIndex]; 1442 const GLuint binding = mExecutable->getUniformBlockBinding(bufferIndex); 1443 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1444 glState.getIndexedUniformBuffer(binding); 1445 1446 if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType)) 1447 { 1448 continue; 1449 } 1450 1451 mArgumentBufferRenderStageUsages[bufferIndex] |= mtlRenderStage; 1452 1453 uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex]; 1454 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1455 { 1456 continue; 1457 } 1458 1459 mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first; 1460 uint32_t offset = mLegalizedOffsetedUniformBuffers[bufferIndex].second; 1461 [bufferEncoder.metalArgBufferEncoder setBuffer:mtlBuffer->get() 1462 offset:offset 1463 atIndex:actualBufferIdx]; 1464 } 1465 1466 // Flush changes made by MTLArgumentEncoder to GPU. 1467 argumentBuffer->unmapAndFlushSubset(context, argumentBufferOffset, 1468 bufferEncoder.metalArgBufferEncoder.get().encodedLength); 1469 1470 cmdEncoder->setBuffer(shaderType, argumentBuffer, static_cast<uint32_t>(argumentBufferOffset), 1471 mtl::kUBOArgumentBufferBindingIndex); 1472 return angle::Result::Continue; 1473} 1474 1475angle::Result ProgramExecutableMtl::updateXfbBuffers(ContextMtl *context, 1476 mtl::RenderCommandEncoder *cmdEncoder, 1477 const mtl::RenderPipelineDesc &pipelineDesc) 1478{ 1479 const gl::State &glState = context->getState(); 1480 gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); 1481 1482 if (pipelineDesc.rasterizationEnabled() || !glState.isTransformFeedbackActiveUnpaused() || 1483 ANGLE_UNLIKELY(!transformFeedback)) 1484 { 1485 // XFB output can only be used with rasterization disabled. 1486 return angle::Result::Continue; 1487 } 1488 1489 size_t xfbBufferCount = glState.getProgramExecutable()->getTransformFeedbackBufferCount(); 1490 1491 ASSERT(xfbBufferCount > 0); 1492 ASSERT(mExecutable->getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS || 1493 xfbBufferCount == 1); 1494 1495 for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) 1496 { 1497 uint32_t actualBufferIdx = mMslXfbOnlyVertexShaderInfo.actualXFBBindings[bufferIndex]; 1498 1499 if (actualBufferIdx >= mtl::kMaxShaderBuffers) 1500 { 1501 continue; 1502 } 1503 1504 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 1505 transformFeedback->getIndexedBuffer(bufferIndex); 1506 gl::Buffer *buffer = bufferBinding.get(); 1507 ASSERT((bufferBinding.getOffset() % 4) == 0); 1508 ASSERT(buffer != nullptr); 1509 1510 BufferMtl *bufferMtl = mtl::GetImpl(buffer); 1511 1512 // Use offset=0, actual offset will be set in Driver Uniform inside ContextMtl. 1513 cmdEncoder->setBufferForWrite(gl::ShaderType::Vertex, bufferMtl->getCurrentBuffer(), 0, 1514 actualBufferIdx); 1515 } 1516 1517 return angle::Result::Continue; 1518} 1519 1520template <typename T> 1521void ProgramExecutableMtl::setUniformImpl(GLint location, 1522 GLsizei count, 1523 const T *v, 1524 GLenum entryPointType) 1525{ 1526 const std::vector<gl::VariableLocation> &uniformLocations = mExecutable->getUniformLocations(); 1527 const gl::VariableLocation &locationInfo = uniformLocations[location]; 1528 1529 const std::vector<gl::LinkedUniform> &linkedUniforms = mExecutable->getUniforms(); 1530 const gl::LinkedUniform &linkedUniform = linkedUniforms[locationInfo.index]; 1531 1532 if (linkedUniform.isSampler()) 1533 { 1534 // Sampler binding has changed. 1535 mSamplerBindingsDirty.set(); 1536 return; 1537 } 1538 1539 if (linkedUniform.getType() == entryPointType) 1540 { 1541 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1542 { 1543 DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType]; 1544 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1545 1546 // Assume an offset of -1 means the block is unused. 1547 if (layoutInfo.offset == -1) 1548 { 1549 continue; 1550 } 1551 1552 const GLint componentCount = (GLint)linkedUniform.getElementComponents(); 1553 const GLint baseComponentSize = (GLint)mtl::GetMetalSizeForGLType( 1554 gl::VariableComponentType(linkedUniform.getType())); 1555 UpdateDefaultUniformBlockWithElementSize(count, locationInfo.arrayIndex, componentCount, 1556 v, baseComponentSize, layoutInfo, 1557 &uniformBlock.uniformData); 1558 mDefaultUniformBlocksDirty.set(shaderType); 1559 } 1560 } 1561 else 1562 { 1563 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1564 { 1565 DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType]; 1566 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1567 1568 // Assume an offset of -1 means the block is unused. 1569 if (layoutInfo.offset == -1) 1570 { 1571 continue; 1572 } 1573 1574 const GLint componentCount = linkedUniform.getElementComponents(); 1575 1576 ASSERT(linkedUniform.getType() == gl::VariableBoolVectorType(entryPointType)); 1577 1578 GLint initialArrayOffset = 1579 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset; 1580 for (GLint i = 0; i < count; i++) 1581 { 1582 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset; 1583 bool *dest = 1584 reinterpret_cast<bool *>(uniformBlock.uniformData.data() + elementOffset); 1585 const T *source = v + i * componentCount; 1586 1587 for (int c = 0; c < componentCount; c++) 1588 { 1589 dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE; 1590 } 1591 } 1592 1593 mDefaultUniformBlocksDirty.set(shaderType); 1594 } 1595 } 1596} 1597 1598template <typename T> 1599void ProgramExecutableMtl::getUniformImpl(GLint location, T *v, GLenum entryPointType) const 1600{ 1601 const gl::VariableLocation &locationInfo = mExecutable->getUniformLocations()[location]; 1602 const gl::LinkedUniform &linkedUniform = mExecutable->getUniforms()[locationInfo.index]; 1603 1604 ASSERT(!linkedUniform.isSampler()); 1605 1606 const gl::ShaderType shaderType = linkedUniform.getFirstActiveShaderType(); 1607 ASSERT(shaderType != gl::ShaderType::InvalidEnum); 1608 1609 const DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType]; 1610 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1611 1612 ASSERT(linkedUniform.getUniformTypeInfo().componentType == entryPointType || 1613 linkedUniform.getUniformTypeInfo().componentType == 1614 gl::VariableBoolVectorType(entryPointType)); 1615 const GLint baseComponentSize = 1616 (GLint)mtl::GetMetalSizeForGLType(gl::VariableComponentType(linkedUniform.getType())); 1617 1618 if (gl::IsMatrixType(linkedUniform.getType())) 1619 { 1620 const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset + 1621 (locationInfo.arrayIndex * layoutInfo.arrayStride); 1622 mtl::GetMatrixUniformMetal(linkedUniform.getType(), v, 1623 reinterpret_cast<const T *>(ptrToElement), false); 1624 } 1625 // Decompress bool from one byte to four bytes because bool values in GLSL 1626 // are uint-sized: ES 3.0 Section 2.12.6.3 "Uniform Buffer Object Storage". 1627 else if (gl::VariableComponentType(linkedUniform.getType()) == GL_BOOL) 1628 { 1629 bool bVals[4] = {0}; 1630 ReadFromDefaultUniformBlockWithElementSize( 1631 linkedUniform.getElementComponents(), locationInfo.arrayIndex, bVals, baseComponentSize, 1632 layoutInfo, &uniformBlock.uniformData); 1633 for (int bCol = 0; bCol < linkedUniform.getElementComponents(); ++bCol) 1634 { 1635 unsigned int data = bVals[bCol]; 1636 *(v + bCol) = static_cast<T>(data); 1637 } 1638 } 1639 else 1640 { 1641 1642 assert(baseComponentSize == sizeof(T)); 1643 ReadFromDefaultUniformBlockWithElementSize(linkedUniform.getElementComponents(), 1644 locationInfo.arrayIndex, v, baseComponentSize, 1645 layoutInfo, &uniformBlock.uniformData); 1646 } 1647} 1648 1649void ProgramExecutableMtl::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) 1650{ 1651 setUniformImpl(location, count, v, GL_FLOAT); 1652} 1653 1654void ProgramExecutableMtl::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) 1655{ 1656 setUniformImpl(location, count, v, GL_FLOAT_VEC2); 1657} 1658 1659void ProgramExecutableMtl::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) 1660{ 1661 setUniformImpl(location, count, v, GL_FLOAT_VEC3); 1662} 1663 1664void ProgramExecutableMtl::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) 1665{ 1666 setUniformImpl(location, count, v, GL_FLOAT_VEC4); 1667} 1668 1669void ProgramExecutableMtl::setUniform1iv(GLint startLocation, GLsizei count, const GLint *v) 1670{ 1671 setUniformImpl(startLocation, count, v, GL_INT); 1672} 1673 1674void ProgramExecutableMtl::setUniform2iv(GLint location, GLsizei count, const GLint *v) 1675{ 1676 setUniformImpl(location, count, v, GL_INT_VEC2); 1677} 1678 1679void ProgramExecutableMtl::setUniform3iv(GLint location, GLsizei count, const GLint *v) 1680{ 1681 setUniformImpl(location, count, v, GL_INT_VEC3); 1682} 1683 1684void ProgramExecutableMtl::setUniform4iv(GLint location, GLsizei count, const GLint *v) 1685{ 1686 setUniformImpl(location, count, v, GL_INT_VEC4); 1687} 1688 1689void ProgramExecutableMtl::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) 1690{ 1691 setUniformImpl(location, count, v, GL_UNSIGNED_INT); 1692} 1693 1694void ProgramExecutableMtl::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) 1695{ 1696 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2); 1697} 1698 1699void ProgramExecutableMtl::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) 1700{ 1701 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3); 1702} 1703 1704void ProgramExecutableMtl::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) 1705{ 1706 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4); 1707} 1708 1709template <int cols, int rows> 1710void ProgramExecutableMtl::setUniformMatrixfv(GLint location, 1711 GLsizei count, 1712 GLboolean transpose, 1713 const GLfloat *value) 1714{ 1715 const gl::VariableLocation &locationInfo = mExecutable->getUniformLocations()[location]; 1716 const gl::LinkedUniform &linkedUniform = mExecutable->getUniforms()[locationInfo.index]; 1717 1718 for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes) 1719 { 1720 DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType]; 1721 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 1722 1723 // Assume an offset of -1 means the block is unused. 1724 if (layoutInfo.offset == -1) 1725 { 1726 continue; 1727 } 1728 1729 mtl::SetFloatUniformMatrixMetal<cols, rows>::Run( 1730 locationInfo.arrayIndex, linkedUniform.getBasicTypeElementCount(), count, transpose, 1731 value, uniformBlock.uniformData.data() + layoutInfo.offset); 1732 1733 mDefaultUniformBlocksDirty.set(shaderType); 1734 } 1735} 1736 1737void ProgramExecutableMtl::setUniformMatrix2fv(GLint location, 1738 GLsizei count, 1739 GLboolean transpose, 1740 const GLfloat *value) 1741{ 1742 setUniformMatrixfv<2, 2>(location, count, transpose, value); 1743} 1744 1745void ProgramExecutableMtl::setUniformMatrix3fv(GLint location, 1746 GLsizei count, 1747 GLboolean transpose, 1748 const GLfloat *value) 1749{ 1750 setUniformMatrixfv<3, 3>(location, count, transpose, value); 1751} 1752 1753void ProgramExecutableMtl::setUniformMatrix4fv(GLint location, 1754 GLsizei count, 1755 GLboolean transpose, 1756 const GLfloat *value) 1757{ 1758 setUniformMatrixfv<4, 4>(location, count, transpose, value); 1759} 1760 1761void ProgramExecutableMtl::setUniformMatrix2x3fv(GLint location, 1762 GLsizei count, 1763 GLboolean transpose, 1764 const GLfloat *value) 1765{ 1766 setUniformMatrixfv<2, 3>(location, count, transpose, value); 1767} 1768 1769void ProgramExecutableMtl::setUniformMatrix3x2fv(GLint location, 1770 GLsizei count, 1771 GLboolean transpose, 1772 const GLfloat *value) 1773{ 1774 setUniformMatrixfv<3, 2>(location, count, transpose, value); 1775} 1776 1777void ProgramExecutableMtl::setUniformMatrix2x4fv(GLint location, 1778 GLsizei count, 1779 GLboolean transpose, 1780 const GLfloat *value) 1781{ 1782 setUniformMatrixfv<2, 4>(location, count, transpose, value); 1783} 1784 1785void ProgramExecutableMtl::setUniformMatrix4x2fv(GLint location, 1786 GLsizei count, 1787 GLboolean transpose, 1788 const GLfloat *value) 1789{ 1790 setUniformMatrixfv<4, 2>(location, count, transpose, value); 1791} 1792 1793void ProgramExecutableMtl::setUniformMatrix3x4fv(GLint location, 1794 GLsizei count, 1795 GLboolean transpose, 1796 const GLfloat *value) 1797{ 1798 setUniformMatrixfv<3, 4>(location, count, transpose, value); 1799} 1800 1801void ProgramExecutableMtl::setUniformMatrix4x3fv(GLint location, 1802 GLsizei count, 1803 GLboolean transpose, 1804 const GLfloat *value) 1805{ 1806 setUniformMatrixfv<4, 3>(location, count, transpose, value); 1807} 1808 1809void ProgramExecutableMtl::getUniformfv(const gl::Context *context, 1810 GLint location, 1811 GLfloat *params) const 1812{ 1813 getUniformImpl(location, params, GL_FLOAT); 1814} 1815 1816void ProgramExecutableMtl::getUniformiv(const gl::Context *context, 1817 GLint location, 1818 GLint *params) const 1819{ 1820 getUniformImpl(location, params, GL_INT); 1821} 1822 1823void ProgramExecutableMtl::getUniformuiv(const gl::Context *context, 1824 GLint location, 1825 GLuint *params) const 1826{ 1827 getUniformImpl(location, params, GL_UNSIGNED_INT); 1828} 1829} // namespace rx 1830