1// 2// Copyright 2019 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6// ProgramMtl.mm: 7// Implements the class methods for ProgramMtl. 8// 9 10#include "libANGLE/renderer/metal/ProgramMtl.h" 11 12#include <TargetConditionals.h> 13 14#include <sstream> 15 16#include "common/debug.h" 17#include "libANGLE/Context.h" 18#include "libANGLE/ProgramLinkedResources.h" 19#include "libANGLE/renderer/metal/ContextMtl.h" 20#include "libANGLE/renderer/metal/DisplayMtl.h" 21#include "libANGLE/renderer/metal/TextureMtl.h" 22#include "libANGLE/renderer/metal/mtl_glslang_utils.h" 23#include "libANGLE/renderer/metal/mtl_utils.h" 24#include "libANGLE/renderer/renderer_utils.h" 25 26namespace rx 27{ 28 29namespace 30{ 31 32#define SHADER_ENTRY_NAME @"main0" 33 34void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms, 35 gl::Shader *shader, 36 sh::BlockLayoutMap *blockLayoutMapOut, 37 size_t *blockSizeOut) 38{ 39 if (uniforms.empty()) 40 { 41 *blockSizeOut = 0; 42 return; 43 } 44 45 sh::Std140BlockEncoder blockEncoder; 46 sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut); 47 48 size_t blockSize = blockEncoder.getCurrentOffset(); 49 50 if (blockSize == 0) 51 { 52 *blockSizeOut = 0; 53 return; 54 } 55 56 // Need to round up to multiple of vec4 57 *blockSizeOut = roundUp(blockSize, static_cast<size_t>(16)); 58 return; 59} 60 61template <typename T> 62void UpdateDefaultUniformBlock(GLsizei count, 63 uint32_t arrayIndex, 64 int componentCount, 65 const T *v, 66 const sh::BlockMemberInfo &layoutInfo, 67 angle::MemoryBuffer *uniformData) 68{ 69 const int elementSize = sizeof(T) * componentCount; 70 71 uint8_t *dst = uniformData->data() + layoutInfo.offset; 72 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize) 73 { 74 uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride; 75 uint8_t *writePtr = dst + arrayOffset; 76 ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size()); 77 memcpy(writePtr, v, elementSize * count); 78 } 79 else 80 { 81 // Have to respect the arrayStride between each element of the array. 82 int maxIndex = arrayIndex + count; 83 for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex; 84 writeIndex++, readIndex++) 85 { 86 const int arrayOffset = writeIndex * layoutInfo.arrayStride; 87 uint8_t *writePtr = dst + arrayOffset; 88 const T *readPtr = v + (readIndex * componentCount); 89 ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size()); 90 memcpy(writePtr, readPtr, elementSize); 91 } 92 } 93} 94 95template <typename T> 96void ReadFromDefaultUniformBlock(int componentCount, 97 uint32_t arrayIndex, 98 T *dst, 99 const sh::BlockMemberInfo &layoutInfo, 100 const angle::MemoryBuffer *uniformData) 101{ 102 ASSERT(layoutInfo.offset != -1); 103 104 const int elementSize = sizeof(T) * componentCount; 105 const uint8_t *source = uniformData->data() + layoutInfo.offset; 106 107 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize) 108 { 109 const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride; 110 memcpy(dst, readPtr, elementSize); 111 } 112 else 113 { 114 // Have to respect the arrayStride between each element of the array. 115 const int arrayOffset = arrayIndex * layoutInfo.arrayStride; 116 const uint8_t *readPtr = source + arrayOffset; 117 memcpy(dst, readPtr, elementSize); 118 } 119} 120 121class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory 122{ 123 public: 124 sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); } 125}; 126 127} // namespace 128 129// ProgramMtl implementation 130ProgramMtl::DefaultUniformBlock::DefaultUniformBlock() {} 131 132ProgramMtl::DefaultUniformBlock::~DefaultUniformBlock() = default; 133 134ProgramMtl::ProgramMtl(const gl::ProgramState &state) : ProgramImpl(state) {} 135 136ProgramMtl::~ProgramMtl() {} 137 138void ProgramMtl::destroy(const gl::Context *context) 139{ 140 auto contextMtl = mtl::GetImpl(context); 141 142 reset(contextMtl); 143} 144 145void ProgramMtl::reset(ContextMtl *context) 146{ 147 for (auto &block : mDefaultUniformBlocks) 148 { 149 block.uniformLayout.clear(); 150 } 151 152 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 153 { 154 for (mtl::SamplerBinding &binding : 155 mMslShaderTranslateInfo[shaderType].actualSamplerBindings) 156 { 157 binding.textureBinding = mtl::kMaxShaderSamplers; 158 } 159 } 160 161 mMetalRenderPipelineCache.clear(); 162} 163 164std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context, 165 gl::BinaryInputStream *stream, 166 gl::InfoLog &infoLog) 167{ 168 // NOTE(hqle): support binary shader 169 UNIMPLEMENTED(); 170 return std::make_unique<LinkEventDone>(angle::Result::Stop); 171} 172 173void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream) 174{ 175 // NOTE(hqle): support binary shader 176 UNIMPLEMENTED(); 177} 178 179void ProgramMtl::setBinaryRetrievableHint(bool retrievable) 180{ 181 UNIMPLEMENTED(); 182} 183 184void ProgramMtl::setSeparable(bool separable) 185{ 186 UNIMPLEMENTED(); 187} 188 189std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context, 190 const gl::ProgramLinkedResources &resources, 191 gl::InfoLog &infoLog) 192{ 193 // Link resources before calling GetShaderSource to make sure they are ready for the set/binding 194 // assignment done in that function. 195 linkResources(resources); 196 197 // NOTE(hqle): Parallelize linking. 198 return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog)); 199} 200 201angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, 202 const gl::ProgramLinkedResources &resources, 203 gl::InfoLog &infoLog) 204{ 205 ContextMtl *contextMtl = mtl::GetImpl(glContext); 206 // NOTE(hqle): No transform feedbacks for now, since we only support ES 2.0 atm 207 208 reset(contextMtl); 209 210 ANGLE_TRY(initDefaultUniformBlocks(glContext)); 211 212 // Gather variable info and transform sources. 213 gl::ShaderMap<std::string> shaderSources; 214 ShaderMapInterfaceVariableInfoMap variableInfoMap; 215 mtl::GlslangGetShaderSource(mState, resources, &shaderSources, &variableInfoMap); 216 217 // Convert GLSL to spirv code 218 gl::ShaderMap<std::vector<uint32_t>> shaderCodes; 219 ANGLE_TRY(mtl::GlslangGetShaderSpirvCode( 220 contextMtl, mState.getExecutable().getLinkedShaderStages(), contextMtl->getCaps(), 221 shaderSources, variableInfoMap, &shaderCodes)); 222 223 // Convert spirv code to MSL 224 ANGLE_TRY(mtl::SpirvCodeToMsl(contextMtl, mState, &shaderCodes, &mMslShaderTranslateInfo, 225 &mTranslatedMslShader)); 226 227 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 228 { 229 // Create actual Metal shader 230 ANGLE_TRY( 231 createMslShader(glContext, shaderType, infoLog, mTranslatedMslShader[shaderType])); 232 } 233 234 return angle::Result::Continue; 235} 236 237void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources) 238{ 239 Std140BlockLayoutEncoderFactory std140EncoderFactory; 240 gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory); 241 242 linker.linkResources(mState, resources); 243} 244 245angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext) 246{ 247 ContextMtl *contextMtl = mtl::GetImpl(glContext); 248 249 // Process vertex and fragment uniforms into std140 packing. 250 gl::ShaderMap<sh::BlockLayoutMap> layoutMap; 251 gl::ShaderMap<size_t> requiredBufferSize; 252 requiredBufferSize.fill(0); 253 254 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 255 { 256 gl::Shader *shader = mState.getAttachedShader(shaderType); 257 if (shader) 258 { 259 const std::vector<sh::Uniform> &uniforms = shader->getUniforms(); 260 InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType], 261 &requiredBufferSize[shaderType]); 262 } 263 } 264 265 // Init the default block layout info. 266 const auto &uniforms = mState.getUniforms(); 267 const auto &uniformLocations = mState.getUniformLocations(); 268 for (size_t locSlot = 0; locSlot < uniformLocations.size(); ++locSlot) 269 { 270 const gl::VariableLocation &location = uniformLocations[locSlot]; 271 gl::ShaderMap<sh::BlockMemberInfo> layoutInfo; 272 273 if (location.used() && !location.ignored) 274 { 275 const gl::LinkedUniform &uniform = uniforms[location.index]; 276 if (uniform.isInDefaultBlock() && !uniform.isSampler()) 277 { 278 std::string uniformName = uniform.name; 279 if (uniform.isArray()) 280 { 281 // Gets the uniform name without the [0] at the end. 282 uniformName = gl::ParseResourceName(uniformName, nullptr); 283 } 284 285 bool found = false; 286 287 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 288 { 289 auto it = layoutMap[shaderType].find(uniformName); 290 if (it != layoutMap[shaderType].end()) 291 { 292 found = true; 293 layoutInfo[shaderType] = it->second; 294 } 295 } 296 297 ASSERT(found); 298 } 299 } 300 301 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 302 { 303 mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]); 304 } 305 } 306 307 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 308 { 309 if (requiredBufferSize[shaderType] > 0) 310 { 311 ASSERT(requiredBufferSize[shaderType] <= mtl::kDefaultUniformsMaxSize); 312 313 if (!mDefaultUniformBlocks[shaderType].uniformData.resize( 314 requiredBufferSize[shaderType])) 315 { 316 ANGLE_MTL_CHECK(contextMtl, false, GL_OUT_OF_MEMORY); 317 } 318 319 // Initialize uniform buffer memory to zero by default. 320 mDefaultUniformBlocks[shaderType].uniformData.fill(0); 321 mDefaultUniformBlocksDirty.set(shaderType); 322 } 323 } 324 325 return angle::Result::Continue; 326} 327 328angle::Result ProgramMtl::createMslShader(const gl::Context *glContext, 329 gl::ShaderType shaderType, 330 gl::InfoLog &infoLog, 331 const std::string &translatedMsl) 332{ 333 ANGLE_MTL_OBJC_SCOPE 334 { 335 ContextMtl *contextMtl = mtl::GetImpl(glContext); 336 DisplayMtl *display = contextMtl->getDisplay(); 337 id<MTLDevice> mtlDevice = display->getMetalDevice(); 338 339 // Convert to actual binary shader 340 mtl::AutoObjCPtr<NSError *> err = nil; 341 mtl::AutoObjCPtr<id<MTLLibrary>> mtlShaderLib = 342 mtl::CreateShaderLibrary(mtlDevice, translatedMsl, &err); 343 if (err && !mtlShaderLib) 344 { 345 std::ostringstream ss; 346 ss << "Internal error compiling Metal shader:\n" 347 << err.get().localizedDescription.UTF8String << "\n"; 348 349 ERR() << ss.str(); 350 351 infoLog << ss.str(); 352 353 ANGLE_MTL_CHECK(contextMtl, false, GL_INVALID_OPERATION); 354 } 355 356 auto mtlShader = [mtlShaderLib.get() newFunctionWithName:SHADER_ENTRY_NAME]; 357 [mtlShader ANGLE_MTL_AUTORELEASE]; 358 ASSERT(mtlShader); 359 if (shaderType == gl::ShaderType::Vertex) 360 { 361 mMetalRenderPipelineCache.setVertexShader(contextMtl, mtlShader); 362 } 363 else if (shaderType == gl::ShaderType::Fragment) 364 { 365 mMetalRenderPipelineCache.setFragmentShader(contextMtl, mtlShader); 366 } 367 368 return angle::Result::Continue; 369 } 370} 371 372GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog) 373{ 374 // No-op. The spec is very vague about the behavior of validation. 375 return GL_TRUE; 376} 377 378template <typename T> 379void ProgramMtl::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType) 380{ 381 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 382 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 383 384 if (linkedUniform.isSampler()) 385 { 386 // Sampler binding has changed. 387 mSamplerBindingsDirty.set(); 388 return; 389 } 390 391 if (linkedUniform.typeInfo->type == entryPointType) 392 { 393 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 394 { 395 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 396 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 397 398 // Assume an offset of -1 means the block is unused. 399 if (layoutInfo.offset == -1) 400 { 401 continue; 402 } 403 404 const GLint componentCount = linkedUniform.typeInfo->componentCount; 405 UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo, 406 &uniformBlock.uniformData); 407 mDefaultUniformBlocksDirty.set(shaderType); 408 } 409 } 410 else 411 { 412 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 413 { 414 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 415 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 416 417 // Assume an offset of -1 means the block is unused. 418 if (layoutInfo.offset == -1) 419 { 420 continue; 421 } 422 423 const GLint componentCount = linkedUniform.typeInfo->componentCount; 424 425 ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType)); 426 427 GLint initialArrayOffset = 428 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset; 429 for (GLint i = 0; i < count; i++) 430 { 431 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset; 432 GLint *dest = 433 reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset); 434 const T *source = v + i * componentCount; 435 436 for (int c = 0; c < componentCount; c++) 437 { 438 dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE; 439 } 440 } 441 442 mDefaultUniformBlocksDirty.set(shaderType); 443 } 444 } 445} 446 447template <typename T> 448void ProgramMtl::getUniformImpl(GLint location, T *v, GLenum entryPointType) const 449{ 450 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 451 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 452 453 ASSERT(!linkedUniform.isSampler()); 454 455 const gl::ShaderType shaderType = linkedUniform.getFirstShaderTypeWhereActive(); 456 ASSERT(shaderType != gl::ShaderType::InvalidEnum); 457 458 const DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 459 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 460 461 ASSERT(linkedUniform.typeInfo->componentType == entryPointType || 462 linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType)); 463 464 if (gl::IsMatrixType(linkedUniform.type)) 465 { 466 const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset + 467 (locationInfo.arrayIndex * layoutInfo.arrayStride); 468 GetMatrixUniform(linkedUniform.type, v, reinterpret_cast<const T *>(ptrToElement), false); 469 } 470 else 471 { 472 ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex, 473 v, layoutInfo, &uniformBlock.uniformData); 474 } 475} 476 477void ProgramMtl::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) 478{ 479 setUniformImpl(location, count, v, GL_FLOAT); 480} 481 482void ProgramMtl::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) 483{ 484 setUniformImpl(location, count, v, GL_FLOAT_VEC2); 485} 486 487void ProgramMtl::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) 488{ 489 setUniformImpl(location, count, v, GL_FLOAT_VEC3); 490} 491 492void ProgramMtl::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) 493{ 494 setUniformImpl(location, count, v, GL_FLOAT_VEC4); 495} 496 497void ProgramMtl::setUniform1iv(GLint startLocation, GLsizei count, const GLint *v) 498{ 499 setUniformImpl(startLocation, count, v, GL_INT); 500} 501 502void ProgramMtl::setUniform2iv(GLint location, GLsizei count, const GLint *v) 503{ 504 setUniformImpl(location, count, v, GL_INT_VEC2); 505} 506 507void ProgramMtl::setUniform3iv(GLint location, GLsizei count, const GLint *v) 508{ 509 setUniformImpl(location, count, v, GL_INT_VEC3); 510} 511 512void ProgramMtl::setUniform4iv(GLint location, GLsizei count, const GLint *v) 513{ 514 setUniformImpl(location, count, v, GL_INT_VEC4); 515} 516 517void ProgramMtl::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) 518{ 519 setUniformImpl(location, count, v, GL_UNSIGNED_INT); 520} 521 522void ProgramMtl::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) 523{ 524 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2); 525} 526 527void ProgramMtl::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) 528{ 529 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3); 530} 531 532void ProgramMtl::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) 533{ 534 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4); 535} 536 537template <int cols, int rows> 538void ProgramMtl::setUniformMatrixfv(GLint location, 539 GLsizei count, 540 GLboolean transpose, 541 const GLfloat *value) 542{ 543 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; 544 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; 545 546 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 547 { 548 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 549 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; 550 551 // Assume an offset of -1 means the block is unused. 552 if (layoutInfo.offset == -1) 553 { 554 continue; 555 } 556 557 SetFloatUniformMatrixGLSL<cols, rows>::Run( 558 locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value, 559 uniformBlock.uniformData.data() + layoutInfo.offset); 560 561 mDefaultUniformBlocksDirty.set(shaderType); 562 } 563} 564 565void ProgramMtl::setUniformMatrix2fv(GLint location, 566 GLsizei count, 567 GLboolean transpose, 568 const GLfloat *value) 569{ 570 setUniformMatrixfv<2, 2>(location, count, transpose, value); 571} 572 573void ProgramMtl::setUniformMatrix3fv(GLint location, 574 GLsizei count, 575 GLboolean transpose, 576 const GLfloat *value) 577{ 578 setUniformMatrixfv<3, 3>(location, count, transpose, value); 579} 580 581void ProgramMtl::setUniformMatrix4fv(GLint location, 582 GLsizei count, 583 GLboolean transpose, 584 const GLfloat *value) 585{ 586 setUniformMatrixfv<4, 4>(location, count, transpose, value); 587} 588 589void ProgramMtl::setUniformMatrix2x3fv(GLint location, 590 GLsizei count, 591 GLboolean transpose, 592 const GLfloat *value) 593{ 594 setUniformMatrixfv<2, 3>(location, count, transpose, value); 595} 596 597void ProgramMtl::setUniformMatrix3x2fv(GLint location, 598 GLsizei count, 599 GLboolean transpose, 600 const GLfloat *value) 601{ 602 setUniformMatrixfv<3, 2>(location, count, transpose, value); 603} 604 605void ProgramMtl::setUniformMatrix2x4fv(GLint location, 606 GLsizei count, 607 GLboolean transpose, 608 const GLfloat *value) 609{ 610 setUniformMatrixfv<2, 4>(location, count, transpose, value); 611} 612 613void ProgramMtl::setUniformMatrix4x2fv(GLint location, 614 GLsizei count, 615 GLboolean transpose, 616 const GLfloat *value) 617{ 618 setUniformMatrixfv<4, 2>(location, count, transpose, value); 619} 620 621void ProgramMtl::setUniformMatrix3x4fv(GLint location, 622 GLsizei count, 623 GLboolean transpose, 624 const GLfloat *value) 625{ 626 setUniformMatrixfv<3, 4>(location, count, transpose, value); 627} 628 629void ProgramMtl::setUniformMatrix4x3fv(GLint location, 630 GLsizei count, 631 GLboolean transpose, 632 const GLfloat *value) 633{ 634 setUniformMatrixfv<4, 3>(location, count, transpose, value); 635} 636 637void ProgramMtl::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const 638{ 639 getUniformImpl(location, params, GL_FLOAT); 640} 641 642void ProgramMtl::getUniformiv(const gl::Context *context, GLint location, GLint *params) const 643{ 644 getUniformImpl(location, params, GL_INT); 645} 646 647void ProgramMtl::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const 648{ 649 getUniformImpl(location, params, GL_UNSIGNED_INT); 650} 651 652angle::Result ProgramMtl::setupDraw(const gl::Context *glContext, 653 mtl::RenderCommandEncoder *cmdEncoder, 654 const Optional<mtl::RenderPipelineDesc> &changedPipelineDescOpt, 655 bool forceTexturesSetting) 656{ 657 ContextMtl *context = mtl::GetImpl(glContext); 658 if (changedPipelineDescOpt.valid()) 659 { 660 const auto &changedPipelineDesc = changedPipelineDescOpt.value(); 661 // Render pipeline state needs to be changed 662 id<MTLRenderPipelineState> pipelineState = 663 mMetalRenderPipelineCache.getRenderPipelineState(context, changedPipelineDesc); 664 if (!pipelineState) 665 { 666 // Error already logged inside getRenderPipelineState() 667 return angle::Result::Stop; 668 } 669 cmdEncoder->setRenderPipelineState(pipelineState); 670 671 // We need to rebind uniform buffers & textures also 672 mDefaultUniformBlocksDirty.set(); 673 mSamplerBindingsDirty.set(); 674 } 675 676 ANGLE_TRY(commitUniforms(context, cmdEncoder)); 677 ANGLE_TRY(updateTextures(glContext, cmdEncoder, forceTexturesSetting)); 678 679 return angle::Result::Continue; 680} 681 682angle::Result ProgramMtl::commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder) 683{ 684 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 685 { 686 if (!mDefaultUniformBlocksDirty[shaderType]) 687 { 688 continue; 689 } 690 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; 691 692 if (!uniformBlock.uniformData.size()) 693 { 694 continue; 695 } 696 switch (shaderType) 697 { 698 case gl::ShaderType::Vertex: 699 cmdEncoder->setVertexBytes(uniformBlock.uniformData.data(), 700 uniformBlock.uniformData.size(), 701 mtl::kDefaultUniformsBindingIndex); 702 break; 703 case gl::ShaderType::Fragment: 704 cmdEncoder->setFragmentBytes(uniformBlock.uniformData.data(), 705 uniformBlock.uniformData.size(), 706 mtl::kDefaultUniformsBindingIndex); 707 break; 708 default: 709 UNREACHABLE(); 710 } 711 712 mDefaultUniformBlocksDirty.reset(shaderType); 713 } 714 715 return angle::Result::Continue; 716} 717 718angle::Result ProgramMtl::updateTextures(const gl::Context *glContext, 719 mtl::RenderCommandEncoder *cmdEncoder, 720 bool forceUpdate) 721{ 722 ContextMtl *contextMtl = mtl::GetImpl(glContext); 723 const auto &glState = glContext->getState(); 724 725 const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache(); 726 727 for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) 728 { 729 if (!mSamplerBindingsDirty[shaderType] && !forceUpdate) 730 { 731 continue; 732 } 733 734 for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size(); 735 ++textureIndex) 736 { 737 const gl::SamplerBinding &samplerBinding = mState.getSamplerBindings()[textureIndex]; 738 739 ASSERT(!samplerBinding.unreferenced); 740 741 const mtl::SamplerBinding &mslBinding = 742 mMslShaderTranslateInfo[shaderType].actualSamplerBindings[textureIndex]; 743 if (mslBinding.textureBinding >= mtl::kMaxShaderSamplers) 744 { 745 // No binding assigned 746 continue; 747 } 748 749 gl::TextureType textureType = samplerBinding.textureType; 750 751 for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size(); 752 ++arrayElement) 753 { 754 GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement]; 755 gl::Texture *texture = completeTextures[textureUnit]; 756 uint32_t textureSlot = mslBinding.textureBinding + arrayElement; 757 uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement; 758 if (!texture) 759 { 760 ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, &texture)); 761 } 762 763 TextureMtl *textureMtl = mtl::GetImpl(texture); 764 765 switch (shaderType) 766 { 767 case gl::ShaderType::Vertex: 768 ANGLE_TRY(textureMtl->bindVertexShader(glContext, cmdEncoder, textureSlot, 769 samplerSlot)); 770 break; 771 case gl::ShaderType::Fragment: 772 ANGLE_TRY(textureMtl->bindFragmentShader(glContext, cmdEncoder, textureSlot, 773 samplerSlot)); 774 break; 775 default: 776 UNREACHABLE(); 777 } 778 } // for array elements 779 } // for sampler bindings 780 } // for shader types 781 782 return angle::Result::Continue; 783} 784 785} // namespace rx 786