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