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