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