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// mtl_msl_utils.h: Utilities to manipulate MSL. 7// 8 9#import <Foundation/Foundation.h> 10 11#include <variant> 12#include "common/string_utils.h" 13#include "common/utilities.h" 14#include "compiler/translator/Name.h" 15#include "compiler/translator/msl/TranslatorMSL.h" 16#include "libANGLE/renderer/metal/ContextMtl.h" 17#include "libANGLE/renderer/metal/ShaderMtl.h" 18#include "libANGLE/renderer/metal/mtl_msl_utils.h" 19 20namespace rx 21{ 22namespace 23{ 24constexpr char kXfbBindingsMarker[] = "@@XFB-Bindings@@"; 25constexpr char kXfbOutMarker[] = "ANGLE_@@XFB-OUT@@"; 26constexpr char kUserDefinedNamePrefix[] = "_u"; // Defined in GLSLANG/ShaderLang.h 27constexpr char kAttribBindingsMarker[] = "@@Attrib-Bindings@@\n"; 28 29std::string GetXfbBufferNameMtl(const uint32_t bufferIndex) 30{ 31 return "xfbBuffer" + Str(bufferIndex); 32} 33 34// Name format needs to match sh::Name. 35struct UserDefinedNameExpr 36{ 37 std::string name; 38}; 39 40std::ostream &operator<<(std::ostream &stream, const UserDefinedNameExpr &expr) 41{ 42 return stream << kUserDefinedNamePrefix << expr.name; 43} 44 45struct UserDefinedNameComponentExpr 46{ 47 UserDefinedNameExpr name; 48 const int component; 49}; 50 51std::ostream &operator<<(std::ostream &stream, const UserDefinedNameComponentExpr &expr) 52{ 53 return stream << expr.name << '[' << expr.component << ']'; 54} 55 56struct InternalNameExpr 57{ 58 std::string name; 59}; 60 61std::ostream &operator<<(std::ostream &stream, const InternalNameExpr &expr) 62{ 63 return stream << sh::kAngleInternalPrefix << '_' << expr.name; 64} 65 66struct InternalNameComponentExpr 67{ 68 InternalNameExpr name; 69 const int component; 70}; 71 72std::ostream &operator<<(std::ostream &stream, const InternalNameComponentExpr &expr) 73{ 74 return stream << expr.name << '_' << expr.component; 75} 76 77// ModifyStructs phase forwarded a single-component user-defined name or created a new AngleInternal 78// field name to support multi-component fields as multiple single-component fields. 79std::variant<UserDefinedNameExpr, InternalNameComponentExpr> 80ResolveModifiedAttributeName(const std::string &name, int registerIndex, int registerCount) 81{ 82 if (registerCount < 2) 83 { 84 return UserDefinedNameExpr{name}; 85 } 86 return InternalNameComponentExpr{InternalNameExpr{name}, registerIndex}; 87} 88 89std::variant<UserDefinedNameExpr, InternalNameComponentExpr> 90ResolveModifiedOutputName(const std::string &name, int component, int componentCount) 91{ 92 if (componentCount == 0) 93 { 94 return UserDefinedNameExpr{name}; 95 } 96 return InternalNameComponentExpr{InternalNameExpr{name}, component}; 97} 98 99// Accessing unmodified structs uses user-defined name, business as usual. 100std::variant<UserDefinedNameExpr, UserDefinedNameComponentExpr> 101ResolveUserDefinedName(const std::string &name, int component, int componentCount) 102{ 103 if (componentCount == 0) 104 { 105 return UserDefinedNameExpr{name}; 106 } 107 return UserDefinedNameComponentExpr{{name}, component}; 108} 109 110template <class T> 111struct ApplyOStream 112{ 113 const T &value; 114}; 115 116template <class T> 117ApplyOStream(T) -> ApplyOStream<T>; 118 119template <class T> 120std::ostream &operator<<(std::ostream &stream, ApplyOStream<T> sv) 121{ 122 stream << sv.value; 123 return stream; 124} 125 126template <class... Ts> 127std::ostream &operator<<(std::ostream &stream, ApplyOStream<std::variant<Ts...>> sv) 128{ 129 std::visit([&stream](auto &&v) { stream << ApplyOStream{v}; }, sv.value); 130 return stream; 131} 132 133} // namespace 134 135namespace mtl 136{ 137 138void TranslatedShaderInfo::reset() 139{ 140 metalShaderSource = nullptr; 141 metalLibrary = nil; 142 hasUBOArgumentBuffer = false; 143 hasIsnanOrIsinf = false; 144 hasInvariant = false; 145 for (mtl::SamplerBinding &binding : actualSamplerBindings) 146 { 147 binding.textureBinding = mtl::kMaxShaderSamplers; 148 binding.samplerBinding = 0; 149 } 150 for (int &rwTextureBinding : actualImageBindings) 151 { 152 rwTextureBinding = -1; 153 } 154 for (uint32_t &binding : actualUBOBindings) 155 { 156 binding = mtl::kMaxShaderBuffers; 157 } 158 159 for (uint32_t &binding : actualXFBBindings) 160 { 161 binding = mtl::kMaxShaderBuffers; 162 } 163} 164 165// Original mapping of front end from sampler name to multiple sampler slots (in form of 166// slot:count pair) 167using OriginalSamplerBindingMap = 168 std::unordered_map<std::string, std::vector<std::pair<uint32_t, uint32_t>>>; 169 170bool MappedSamplerNameNeedsUserDefinedPrefix(const std::string &originalName) 171{ 172 return originalName.find('.') == std::string::npos; 173} 174 175static std::string MSLGetMappedSamplerName(const std::string &originalName) 176{ 177 std::string samplerName = originalName; 178 179 // Samplers in structs are extracted. 180 std::replace(samplerName.begin(), samplerName.end(), '.', '_'); 181 182 // Remove array elements 183 auto out = samplerName.begin(); 184 for (auto in = samplerName.begin(); in != samplerName.end(); in++) 185 { 186 if (*in == '[') 187 { 188 while (*in != ']') 189 { 190 in++; 191 ASSERT(in != samplerName.end()); 192 } 193 } 194 else 195 { 196 *out++ = *in; 197 } 198 } 199 200 samplerName.erase(out, samplerName.end()); 201 202 if (MappedSamplerNameNeedsUserDefinedPrefix(originalName)) 203 { 204 samplerName = sh::kUserDefinedNamePrefix + samplerName; 205 } 206 207 return samplerName; 208} 209 210void MSLGetShaderSource(const gl::ProgramState &programState, 211 const gl::ProgramLinkedResources &resources, 212 gl::ShaderMap<std::string> *shaderSourcesOut) 213{ 214 for (const gl::ShaderType shaderType : gl::AllShaderTypes()) 215 { 216 const gl::SharedCompiledShaderState &glShader = programState.getAttachedShader(shaderType); 217 (*shaderSourcesOut)[shaderType] = glShader ? glShader->translatedSource : ""; 218 } 219} 220 221void GetAssignedSamplerBindings(const sh::TranslatorMetalReflection *reflection, 222 const OriginalSamplerBindingMap &originalBindings, 223 std::unordered_set<std::string> &structSamplers, 224 std::array<SamplerBinding, mtl::kMaxGLSamplerBindings> *bindings) 225{ 226 for (auto &sampler : reflection->getSamplerBindings()) 227 { 228 const std::string &name = sampler.first; 229 const uint32_t actualSamplerSlot = (uint32_t)reflection->getSamplerBinding(name); 230 const uint32_t actualTextureSlot = (uint32_t)reflection->getTextureBinding(name); 231 232 // Assign sequential index for subsequent array elements 233 const bool structSampler = structSamplers.find(name) != structSamplers.end(); 234 const std::string mappedName = 235 structSampler ? name : MSLGetMappedSamplerName(sh::kUserDefinedNamePrefix + name); 236 auto original = originalBindings.find(mappedName); 237 if (original != originalBindings.end()) 238 { 239 const std::vector<std::pair<uint32_t, uint32_t>> &resOrignalBindings = 240 originalBindings.at(mappedName); 241 uint32_t currentTextureSlot = actualTextureSlot; 242 uint32_t currentSamplerSlot = actualSamplerSlot; 243 for (const std::pair<uint32_t, uint32_t> &originalBindingRange : resOrignalBindings) 244 { 245 SamplerBinding &actualBinding = bindings->at(originalBindingRange.first); 246 actualBinding.textureBinding = currentTextureSlot; 247 actualBinding.samplerBinding = currentSamplerSlot; 248 249 currentTextureSlot += originalBindingRange.second; 250 currentSamplerSlot += originalBindingRange.second; 251 } 252 } 253 } 254} 255 256std::string UpdateAliasedShaderAttributes(std::string shaderSourceIn, 257 const gl::ProgramExecutable &executable) 258{ 259 // Cache max number of components for each attribute location 260 std::array<uint8_t, gl::MAX_VERTEX_ATTRIBS> maxComponents{}; 261 for (auto &attribute : executable.getProgramInputs()) 262 { 263 const int location = attribute.getLocation(); 264 const int registers = gl::VariableRegisterCount(attribute.getType()); 265 const uint8_t components = gl::VariableColumnCount(attribute.getType()); 266 for (int i = 0; i < registers; ++i) 267 { 268 ASSERT(location + i < static_cast<int>(maxComponents.size())); 269 maxComponents[location + i] = std::max(maxComponents[location + i], components); 270 } 271 } 272 273 // Define aliased names pointing to real attributes with swizzles as needed 274 std::ostringstream stream; 275 for (auto &attribute : executable.getProgramInputs()) 276 { 277 const int location = attribute.getLocation(); 278 const int registers = gl::VariableRegisterCount(attribute.getType()); 279 const uint8_t components = gl::VariableColumnCount(attribute.getType()); 280 for (int i = 0; i < registers; i++) 281 { 282 stream << "#define ANGLE_ALIASED_" 283 << ApplyOStream{ResolveModifiedAttributeName(attribute.name, i, registers)} 284 << " ANGLE_modified.ANGLE_ATTRIBUTE_" << (location + i); 285 if (components != maxComponents[location + i]) 286 { 287 ASSERT(components < maxComponents[location + i]); 288 switch (components) 289 { 290 case 1: 291 stream << ".x"; 292 break; 293 case 2: 294 stream << ".xy"; 295 break; 296 case 3: 297 stream << ".xyz"; 298 break; 299 } 300 } 301 stream << "\n"; 302 } 303 } 304 305 // Declare actual MSL attributes 306 for (size_t i : executable.getActiveAttribLocationsMask()) 307 { 308 stream << " float"; 309 if (maxComponents[i] > 1) 310 { 311 stream << static_cast<int>(maxComponents[i]); 312 } 313 stream << " ANGLE_ATTRIBUTE_" << i << "[[attribute(" << i << ")]];\n"; 314 } 315 316 std::string outputSource = shaderSourceIn; 317 size_t markerFound = outputSource.find(kAttribBindingsMarker); 318 ASSERT(markerFound != std::string::npos); 319 outputSource.replace(markerFound, angle::ConstStrLen(kAttribBindingsMarker), stream.str()); 320 return outputSource; 321} 322 323std::string updateShaderAttributes(std::string shaderSourceIn, 324 const gl::ProgramExecutable &executable) 325{ 326 // Build string to attrib map. 327 const auto &programAttributes = executable.getProgramInputs(); 328 std::ostringstream stream; 329 std::unordered_map<std::string, uint32_t> attributeBindings; 330 for (auto &attribute : programAttributes) 331 { 332 const int registers = gl::VariableRegisterCount(attribute.getType()); 333 for (int i = 0; i < registers; i++) 334 { 335 stream.str(""); 336 stream << ' ' 337 << ApplyOStream{ResolveModifiedAttributeName(attribute.name, i, registers)} 338 << sh::kUnassignedAttributeString; 339 attributeBindings.insert({stream.str(), i + attribute.getLocation()}); 340 } 341 } 342 // Rewrite attributes 343 std::string outputSource = shaderSourceIn; 344 for (auto it = attributeBindings.begin(); it != attributeBindings.end(); ++it) 345 { 346 std::size_t attribFound = outputSource.find(it->first); 347 if (attribFound != std::string::npos) 348 { 349 stream.str(""); 350 stream << "[[attribute(" << it->second << ")]]"; 351 outputSource = outputSource.replace( 352 attribFound + it->first.length() - 353 angle::ConstStrLen(sh::kUnassignedAttributeString), 354 angle::ConstStrLen(sh::kUnassignedAttributeString), stream.str()); 355 } 356 } 357 return outputSource; 358} 359 360std::string UpdateFragmentShaderOutputs(std::string shaderSourceIn, 361 const gl::ProgramExecutable &executable, 362 bool defineAlpha0) 363{ 364 std::ostringstream stream; 365 std::string outputSource = shaderSourceIn; 366 const auto &outputVariables = executable.getOutputVariables(); 367 368 // For alpha-to-coverage emulation, a reference to the alpha channel 369 // of color output 0 is needed. For ESSL 1.00, it is gl_FragColor or 370 // gl_FragData[0]; for ESSL 3.xx, it is a user-defined output. 371 std::string alphaOutputName; 372 373 auto assignLocations = [&](const std::vector<gl::VariableLocation> &locations, bool secondary) { 374 for (auto &outputLocation : locations) 375 { 376 if (!outputLocation.used()) 377 { 378 continue; 379 } 380 const int index = outputLocation.arrayIndex; 381 const gl::ProgramOutput &outputVar = outputVariables[outputLocation.index]; 382 ASSERT(outputVar.pod.location >= 0); 383 const int location = outputVar.pod.location + index; 384 const int arraySize = outputVar.getOutermostArraySize(); 385 stream.str(""); 386 stream << ApplyOStream{ResolveModifiedOutputName(outputVar.name, index, arraySize)} 387 << " [[" << sh::kUnassignedFragmentOutputString; 388 const std::string placeholder(stream.str()); 389 390 size_t outputFound = outputSource.find(placeholder); 391 if (outputFound != std::string::npos) 392 { 393 stream.str(""); 394 stream << "color(" << location << (secondary ? "), index(1)" : ")"); 395 outputSource = outputSource.replace( 396 outputFound + placeholder.length() - 397 angle::ConstStrLen(sh::kUnassignedFragmentOutputString), 398 angle::ConstStrLen(sh::kUnassignedFragmentOutputString), stream.str()); 399 } 400 401 if (defineAlpha0 && location == 0 && !secondary && outputVar.pod.type == GL_FLOAT_VEC4) 402 { 403 ASSERT(index == 0); 404 ASSERT(alphaOutputName.empty()); 405 std::ostringstream nameStream; 406 nameStream << "ANGLE_fragmentOut." 407 << ApplyOStream{ResolveUserDefinedName(outputVar.name, index, arraySize)} 408 << ".a"; 409 alphaOutputName = nameStream.str(); 410 } 411 } 412 }; 413 assignLocations(executable.getOutputLocations(), false); 414 assignLocations(executable.getSecondaryOutputLocations(), true); 415 416 if (defineAlpha0) 417 { 418 // Locations are empty for ESSL 1.00 shaders, try built-in outputs 419 if (alphaOutputName.empty()) 420 { 421 for (auto &v : outputVariables) 422 { 423 if (v.name == "gl_FragColor") 424 { 425 alphaOutputName = "ANGLE_fragmentOut.gl_FragColor.a"; 426 break; 427 } 428 else if (v.name == "gl_FragData") 429 { 430 alphaOutputName = "ANGLE_fragmentOut.ANGLE_gl_FragData_0.a"; 431 break; 432 } 433 } 434 } 435 436 // Set a value used for alpha-to-coverage emulation 437 const std::string alphaPlaceholder("#define ANGLE_ALPHA0"); 438 size_t alphaFound = outputSource.find(alphaPlaceholder); 439 ASSERT(alphaFound != std::string::npos); 440 441 std::ostringstream alphaStream; 442 alphaStream << alphaPlaceholder << " "; 443 alphaStream << (alphaOutputName.empty() ? "1.0" : alphaOutputName); 444 outputSource = 445 outputSource.replace(alphaFound, alphaPlaceholder.length(), alphaStream.str()); 446 } 447 448 return outputSource; 449} 450 451std::string SubstituteTransformFeedbackMarkers(const std::string &originalSource, 452 const std::string &xfbBindings, 453 const std::string &xfbOut) 454{ 455 const size_t xfbBindingsMarkerStart = originalSource.find(kXfbBindingsMarker); 456 bool hasBindingsMarker = xfbBindingsMarkerStart != std::string::npos; 457 const size_t xfbBindingsMarkerEnd = 458 xfbBindingsMarkerStart + angle::ConstStrLen(kXfbBindingsMarker); 459 460 const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker, xfbBindingsMarkerStart); 461 bool hasOutMarker = xfbOutMarkerStart != std::string::npos; 462 const size_t xfbOutMarkerEnd = xfbOutMarkerStart + angle::ConstStrLen(kXfbOutMarker); 463 464 // The shader is the following form: 465 // 466 // ..part1.. 467 // @@ XFB-BINDINGS @@ 468 // ..part2.. 469 // @@ XFB-OUT @@; 470 // ..part3.. 471 // 472 // Construct the string by concatenating these five pieces, replacing the markers with the given 473 // values. 474 std::string result; 475 if (hasBindingsMarker && hasOutMarker) 476 { 477 result.append(&originalSource[0], &originalSource[xfbBindingsMarkerStart]); 478 result.append(xfbBindings); 479 result.append(&originalSource[xfbBindingsMarkerEnd], &originalSource[xfbOutMarkerStart]); 480 result.append(xfbOut); 481 result.append(&originalSource[xfbOutMarkerEnd], &originalSource[originalSource.size()]); 482 return result; 483 } 484 return originalSource; 485} 486 487std::string GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVarying &varying, 488 const gl::UniformTypeInfo &info, 489 size_t strideBytes, 490 size_t offset, 491 const std::string &bufferIndex) 492{ 493 std::ostringstream result; 494 495 ASSERT(strideBytes % 4 == 0); 496 size_t stride = strideBytes / 4; 497 498 const size_t arrayIndexStart = varying.arrayIndex == GL_INVALID_INDEX ? 0 : varying.arrayIndex; 499 const size_t arrayIndexEnd = arrayIndexStart + varying.size(); 500 501 for (size_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex) 502 { 503 for (int col = 0; col < info.columnCount; ++col) 504 { 505 for (int row = 0; row < info.rowCount; ++row) 506 { 507 result << " "; 508 result << "ANGLE_" << "xfbBuffer" << bufferIndex << "[" << "ANGLE_" 509 << std::string(sh::kUniformsVar) << ".ANGLE_xfbBufferOffsets[" << bufferIndex 510 << "] + (ANGLE_vertexIDMetal + (ANGLE_instanceIdMod - ANGLE_baseInstance) * " 511 << "ANGLE_" << std::string(sh::kUniformsVar) 512 << ".ANGLE_xfbVerticesPerInstance) * " << stride << " + " << offset 513 << "] = " << "as_type<float>" << "(" << "ANGLE_vertexOut."; 514 if (!varying.isBuiltIn()) 515 { 516 result << kUserDefinedNamePrefix; 517 } 518 result << varying.name; 519 520 if (varying.isArray()) 521 { 522 result << "[" << arrayIndex << "]"; 523 } 524 525 if (info.columnCount > 1) 526 { 527 result << "[" << col << "]"; 528 } 529 530 if (info.rowCount > 1) 531 { 532 result << "[" << row << "]"; 533 } 534 535 result << ");\n"; 536 ++offset; 537 } 538 } 539 } 540 541 return result.str(); 542} 543 544void GenerateTransformFeedbackEmulationOutputs( 545 const gl::ProgramExecutable &executable, 546 std::string *vertexShader, 547 std::array<uint32_t, kMaxShaderXFBs> *xfbBindingRemapOut) 548{ 549 const std::vector<gl::TransformFeedbackVarying> &varyings = 550 executable.getLinkedTransformFeedbackVaryings(); 551 const std::vector<GLsizei> &bufferStrides = executable.getTransformFeedbackStrides(); 552 const bool isInterleaved = 553 executable.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS; 554 const size_t bufferCount = isInterleaved ? 1 : varyings.size(); 555 556 std::vector<std::string> xfbIndices(bufferCount); 557 558 std::string xfbBindings; 559 560 for (uint32_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex) 561 { 562 const std::string xfbBinding = Str(0); 563 xfbIndices[bufferIndex] = Str(bufferIndex); 564 565 std::string bufferName = GetXfbBufferNameMtl(bufferIndex); 566 567 xfbBindings += ", "; 568 // TODO: offset from last used buffer binding from front end 569 // XFB buffer is allocated slot starting from last discrete Metal buffer slot. 570 uint32_t bindingPoint = kMaxShaderBuffers - 1 - bufferIndex; 571 xfbBindingRemapOut->at(bufferIndex) = bindingPoint; 572 xfbBindings += 573 "device float* ANGLE_" + bufferName + " [[buffer(" + Str(bindingPoint) + ")]]"; 574 } 575 576 std::string xfbOut = "#if TRANSFORM_FEEDBACK_ENABLED\n {\n"; 577 size_t outputOffset = 0; 578 for (size_t varyingIndex = 0; varyingIndex < varyings.size(); ++varyingIndex) 579 { 580 const size_t bufferIndex = isInterleaved ? 0 : varyingIndex; 581 const gl::TransformFeedbackVarying &varying = varyings[varyingIndex]; 582 583 // For every varying, output to the respective buffer packed. If interleaved, the output is 584 // always to the same buffer, but at different offsets. 585 const gl::UniformTypeInfo &info = gl::GetUniformTypeInfo(varying.type); 586 xfbOut += GenerateTransformFeedbackVaryingOutput(varying, info, bufferStrides[bufferIndex], 587 outputOffset, xfbIndices[bufferIndex]); 588 589 if (isInterleaved) 590 { 591 outputOffset += info.columnCount * info.rowCount * varying.size(); 592 } 593 } 594 xfbOut += " }\n#endif\n"; 595 596 *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbBindings, xfbOut); 597} 598 599angle::Result MTLGetMSL(const angle::FeaturesMtl &features, 600 const gl::ProgramExecutable &executable, 601 const gl::ShaderMap<std::string> &shaderSources, 602 const gl::ShaderMap<SharedCompiledShaderStateMtl> &shadersState, 603 gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut) 604{ 605 // Retrieve original uniform buffer bindings generated by front end. We will need to do a remap. 606 std::unordered_map<std::string, uint32_t> uboOriginalBindings; 607 const std::vector<gl::InterfaceBlock> &blocks = executable.getUniformBlocks(); 608 for (uint32_t bufferIdx = 0; bufferIdx < blocks.size(); ++bufferIdx) 609 { 610 const gl::InterfaceBlock &block = blocks[bufferIdx]; 611 if (!uboOriginalBindings.count(block.name)) 612 { 613 uboOriginalBindings[block.name] = bufferIdx; 614 } 615 } 616 // Retrieve original sampler bindings produced by front end. 617 OriginalSamplerBindingMap originalSamplerBindings; 618 const std::vector<gl::SamplerBinding> &samplerBindings = executable.getSamplerBindings(); 619 std::unordered_set<std::string> structSamplers = {}; 620 621 for (uint32_t textureIndex = 0; textureIndex < samplerBindings.size(); ++textureIndex) 622 { 623 const gl::SamplerBinding &samplerBinding = samplerBindings[textureIndex]; 624 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(textureIndex); 625 const std::string &uniformName = executable.getUniformNames()[uniformIndex]; 626 const std::string &uniformMappedName = executable.getUniformMappedNames()[uniformIndex]; 627 bool isSamplerInStruct = uniformName.find('.') != std::string::npos; 628 std::string mappedSamplerName = isSamplerInStruct 629 ? MSLGetMappedSamplerName(uniformName) 630 : MSLGetMappedSamplerName(uniformMappedName); 631 // These need to be prefixed later seperately 632 if (isSamplerInStruct) 633 structSamplers.insert(mappedSamplerName); 634 originalSamplerBindings[mappedSamplerName].push_back( 635 {textureIndex, static_cast<uint32_t>(samplerBinding.textureUnitsCount)}); 636 } 637 for (gl::ShaderType type : {gl::ShaderType::Vertex, gl::ShaderType::Fragment}) 638 { 639 std::string source; 640 if (type == gl::ShaderType::Vertex) 641 { 642 source = 643 shadersState[gl::ShaderType::Vertex]->translatorMetalReflection.hasAttributeAliasing 644 ? UpdateAliasedShaderAttributes(shaderSources[type], executable) 645 : updateShaderAttributes(shaderSources[type], executable); 646 // Write transform feedback output code. 647 if (!source.empty()) 648 { 649 if (executable.getLinkedTransformFeedbackVaryings().empty()) 650 { 651 source = SubstituteTransformFeedbackMarkers(source, "", ""); 652 } 653 else 654 { 655 GenerateTransformFeedbackEmulationOutputs( 656 executable, &source, &(*mslShaderInfoOut)[type].actualXFBBindings); 657 } 658 } 659 } 660 else 661 { 662 ASSERT(type == gl::ShaderType::Fragment); 663 const bool defineAlpha0 = features.emulateAlphaToCoverage.enabled || 664 features.generateShareableShaders.enabled; 665 source = UpdateFragmentShaderOutputs(shaderSources[type], executable, defineAlpha0); 666 } 667 (*mslShaderInfoOut)[type].metalShaderSource = 668 std::make_shared<const std::string>(std::move(source)); 669 const sh::TranslatorMetalReflection *reflection = 670 &shadersState[type]->translatorMetalReflection; 671 if (reflection->hasUBOs) 672 { 673 (*mslShaderInfoOut)[type].hasUBOArgumentBuffer = true; 674 675 for (auto &uboBinding : reflection->getUniformBufferBindings()) 676 { 677 const std::string &uboName = uboBinding.first; 678 const sh::UBOBindingInfo &bindInfo = uboBinding.second; 679 const uint32_t uboBindIndex = static_cast<uint32_t>(bindInfo.bindIndex); 680 const uint32_t uboArraySize = static_cast<uint32_t>(bindInfo.arraySize); 681 const uint32_t originalBinding = uboOriginalBindings.at(uboName); 682 uint32_t currentSlot = static_cast<uint>(uboBindIndex); 683 for (uint32_t i = 0; i < uboArraySize; ++i) 684 { 685 // Use consecutive slot for member in array 686 (*mslShaderInfoOut)[type].actualUBOBindings[originalBinding + i] = 687 currentSlot + i; 688 } 689 } 690 } 691 // Retrieve automatic texture slot assignments 692 if (originalSamplerBindings.size() > 0) 693 { 694 GetAssignedSamplerBindings(reflection, originalSamplerBindings, structSamplers, 695 &mslShaderInfoOut->at(type).actualSamplerBindings); 696 } 697 for (uint32_t i = 0; i < kMaxShaderImages; ++i) 698 { 699 mslShaderInfoOut->at(type).actualImageBindings[i] = reflection->getRWTextureBinding(i); 700 } 701 (*mslShaderInfoOut)[type].hasIsnanOrIsinf = reflection->hasIsnanOrIsinf; 702 (*mslShaderInfoOut)[type].hasInvariant = reflection->hasInvariance; 703 } 704 return angle::Result::Continue; 705} 706 707uint MslGetShaderShadowCompareMode(GLenum mode, GLenum func) 708{ 709 // See SpirvToMslCompiler::emit_header() 710 if (mode == GL_NONE) 711 { 712 return 0; 713 } 714 else 715 { 716 switch (func) 717 { 718 case GL_LESS: 719 return 1; 720 case GL_LEQUAL: 721 return 2; 722 case GL_GREATER: 723 return 3; 724 case GL_GEQUAL: 725 return 4; 726 case GL_NEVER: 727 return 5; 728 case GL_ALWAYS: 729 return 6; 730 case GL_EQUAL: 731 return 7; 732 case GL_NOTEQUAL: 733 return 8; 734 default: 735 UNREACHABLE(); 736 return 1; 737 } 738 } 739} 740 741} // namespace mtl 742} // namespace rx 743