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/msl/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 hasInvariant = false; 144 for (mtl::SamplerBinding &binding : actualSamplerBindings) 145 { 146 binding.textureBinding = mtl::kMaxShaderSamplers; 147 binding.samplerBinding = 0; 148 } 149 for (int &rwTextureBinding : actualImageBindings) 150 { 151 rwTextureBinding = -1; 152 } 153 for (uint32_t &binding : actualUBOBindings) 154 { 155 binding = mtl::kMaxShaderBuffers; 156 } 157 158 for (uint32_t &binding : actualXFBBindings) 159 { 160 binding = mtl::kMaxShaderBuffers; 161 } 162} 163 164// Original mapping of front end from sampler name to multiple sampler slots (in form of 165// slot:count pair) 166using OriginalSamplerBindingMap = 167 std::unordered_map<std::string, std::vector<std::pair<uint32_t, uint32_t>>>; 168 169bool MappedSamplerNameNeedsUserDefinedPrefix(const std::string &originalName) 170{ 171 return originalName.find('.') == std::string::npos; 172} 173 174static std::string MSLGetMappedSamplerName(const std::string &originalName) 175{ 176 std::string samplerName = originalName; 177 178 // Samplers in structs are extracted. 179 std::replace(samplerName.begin(), samplerName.end(), '.', '_'); 180 181 // Remove array elements 182 auto out = samplerName.begin(); 183 for (auto in = samplerName.begin(); in != samplerName.end(); in++) 184 { 185 if (*in == '[') 186 { 187 while (*in != ']') 188 { 189 in++; 190 ASSERT(in != samplerName.end()); 191 } 192 } 193 else 194 { 195 *out++ = *in; 196 } 197 } 198 199 samplerName.erase(out, samplerName.end()); 200 201 if (MappedSamplerNameNeedsUserDefinedPrefix(originalName)) 202 { 203 samplerName = sh::kUserDefinedNamePrefix + samplerName; 204 } 205 206 return samplerName; 207} 208 209void MSLGetShaderSource(const gl::ProgramState &programState, 210 const gl::ProgramLinkedResources &resources, 211 gl::ShaderMap<std::string> *shaderSourcesOut) 212{ 213 for (const gl::ShaderType shaderType : gl::AllShaderTypes()) 214 { 215 const gl::SharedCompiledShaderState &glShader = programState.getAttachedShader(shaderType); 216 (*shaderSourcesOut)[shaderType] = glShader ? glShader->translatedSource : ""; 217 } 218} 219 220void GetAssignedSamplerBindings(const sh::TranslatorMetalReflection *reflection, 221 const OriginalSamplerBindingMap &originalBindings, 222 std::unordered_set<std::string> &structSamplers, 223 std::array<SamplerBinding, mtl::kMaxGLSamplerBindings> *bindings) 224{ 225 for (auto &sampler : reflection->getSamplerBindings()) 226 { 227 const std::string &name = sampler.first; 228 const uint32_t actualSamplerSlot = (uint32_t)reflection->getSamplerBinding(name); 229 const uint32_t actualTextureSlot = (uint32_t)reflection->getTextureBinding(name); 230 231 // Assign sequential index for subsequent array elements 232 const bool structSampler = structSamplers.find(name) != structSamplers.end(); 233 const std::string mappedName = 234 structSampler ? name : MSLGetMappedSamplerName(sh::kUserDefinedNamePrefix + name); 235 auto original = originalBindings.find(mappedName); 236 if (original != originalBindings.end()) 237 { 238 const std::vector<std::pair<uint32_t, uint32_t>> &resOrignalBindings = 239 originalBindings.at(mappedName); 240 uint32_t currentTextureSlot = actualTextureSlot; 241 uint32_t currentSamplerSlot = actualSamplerSlot; 242 for (const std::pair<uint32_t, uint32_t> &originalBindingRange : resOrignalBindings) 243 { 244 SamplerBinding &actualBinding = bindings->at(originalBindingRange.first); 245 actualBinding.textureBinding = currentTextureSlot; 246 actualBinding.samplerBinding = currentSamplerSlot; 247 248 currentTextureSlot += originalBindingRange.second; 249 currentSamplerSlot += originalBindingRange.second; 250 } 251 } 252 } 253} 254 255std::string UpdateAliasedShaderAttributes(std::string shaderSourceIn, 256 const gl::ProgramExecutable &executable) 257{ 258 // Cache max number of components for each attribute location 259 std::array<uint8_t, gl::MAX_VERTEX_ATTRIBS> maxComponents{}; 260 for (auto &attribute : executable.getProgramInputs()) 261 { 262 const int location = attribute.getLocation(); 263 const int registers = gl::VariableRegisterCount(attribute.getType()); 264 const uint8_t components = gl::VariableColumnCount(attribute.getType()); 265 for (int i = 0; i < registers; ++i) 266 { 267 ASSERT(location + i < static_cast<int>(maxComponents.size())); 268 maxComponents[location + i] = std::max(maxComponents[location + i], components); 269 } 270 } 271 272 // Define aliased names pointing to real attributes with swizzles as needed 273 std::ostringstream stream; 274 for (auto &attribute : executable.getProgramInputs()) 275 { 276 const int location = attribute.getLocation(); 277 const int registers = gl::VariableRegisterCount(attribute.getType()); 278 const uint8_t components = gl::VariableColumnCount(attribute.getType()); 279 for (int i = 0; i < registers; i++) 280 { 281 stream << "#define ANGLE_ALIASED_" 282 << ApplyOStream{ResolveModifiedAttributeName(attribute.name, i, registers)} 283 << " ANGLE_modified.ANGLE_ATTRIBUTE_" << (location + i); 284 if (components != maxComponents[location + i]) 285 { 286 ASSERT(components < maxComponents[location + i]); 287 switch (components) 288 { 289 case 1: 290 stream << ".x"; 291 break; 292 case 2: 293 stream << ".xy"; 294 break; 295 case 3: 296 stream << ".xyz"; 297 break; 298 } 299 } 300 stream << "\n"; 301 } 302 } 303 304 // Declare actual MSL attributes 305 for (size_t i : executable.getActiveAttribLocationsMask()) 306 { 307 stream << " float"; 308 if (maxComponents[i] > 1) 309 { 310 stream << static_cast<int>(maxComponents[i]); 311 } 312 stream << " ANGLE_ATTRIBUTE_" << i << "[[attribute(" << i << ")]];\n"; 313 } 314 315 std::string outputSource = shaderSourceIn; 316 size_t markerFound = outputSource.find(kAttribBindingsMarker); 317 ASSERT(markerFound != std::string::npos); 318 outputSource.replace(markerFound, angle::ConstStrLen(kAttribBindingsMarker), stream.str()); 319 return outputSource; 320} 321 322std::string updateShaderAttributes(std::string shaderSourceIn, 323 const gl::ProgramExecutable &executable) 324{ 325 // Build string to attrib map. 326 const auto &programAttributes = executable.getProgramInputs(); 327 std::ostringstream stream; 328 std::unordered_map<std::string, uint32_t> attributeBindings; 329 for (auto &attribute : programAttributes) 330 { 331 const int registers = gl::VariableRegisterCount(attribute.getType()); 332 for (int i = 0; i < registers; i++) 333 { 334 stream.str(""); 335 stream << ' ' 336 << ApplyOStream{ResolveModifiedAttributeName(attribute.name, i, registers)} 337 << sh::kUnassignedAttributeString; 338 attributeBindings.insert({stream.str(), i + attribute.getLocation()}); 339 } 340 } 341 // Rewrite attributes 342 std::string outputSource = shaderSourceIn; 343 for (auto it = attributeBindings.begin(); it != attributeBindings.end(); ++it) 344 { 345 std::size_t attribFound = outputSource.find(it->first); 346 if (attribFound != std::string::npos) 347 { 348 stream.str(""); 349 stream << "[[attribute(" << it->second << ")]]"; 350 outputSource = outputSource.replace( 351 attribFound + it->first.length() - 352 angle::ConstStrLen(sh::kUnassignedAttributeString), 353 angle::ConstStrLen(sh::kUnassignedAttributeString), stream.str()); 354 } 355 } 356 return outputSource; 357} 358 359std::string UpdateFragmentShaderOutputs(std::string shaderSourceIn, 360 const gl::ProgramExecutable &executable, 361 bool defineAlpha0) 362{ 363 std::ostringstream stream; 364 std::string outputSource = shaderSourceIn; 365 const auto &outputVariables = executable.getOutputVariables(); 366 367 // For alpha-to-coverage emulation, a reference to the alpha channel 368 // of color output 0 is needed. For ESSL 1.00, it is gl_FragColor or 369 // gl_FragData[0]; for ESSL 3.xx, it is a user-defined output. 370 std::string alphaOutputName; 371 372 auto assignLocations = [&](const std::vector<gl::VariableLocation> &locations, bool secondary) { 373 for (auto &outputLocation : locations) 374 { 375 if (!outputLocation.used()) 376 { 377 continue; 378 } 379 const int index = outputLocation.arrayIndex; 380 const gl::ProgramOutput &outputVar = outputVariables[outputLocation.index]; 381 ASSERT(outputVar.pod.location >= 0); 382 const int location = outputVar.pod.location + index; 383 const int arraySize = outputVar.getOutermostArraySize(); 384 stream.str(""); 385 stream << ApplyOStream{ResolveModifiedOutputName(outputVar.name, index, arraySize)} 386 << " [[" << sh::kUnassignedFragmentOutputString; 387 const std::string placeholder(stream.str()); 388 389 size_t outputFound = outputSource.find(placeholder); 390 if (outputFound != std::string::npos) 391 { 392 stream.str(""); 393 stream << "color(" << location << (secondary ? "), index(1)" : ")"); 394 outputSource = outputSource.replace( 395 outputFound + placeholder.length() - 396 angle::ConstStrLen(sh::kUnassignedFragmentOutputString), 397 angle::ConstStrLen(sh::kUnassignedFragmentOutputString), stream.str()); 398 } 399 400 if (defineAlpha0 && location == 0 && !secondary && outputVar.pod.type == GL_FLOAT_VEC4) 401 { 402 ASSERT(index == 0); 403 ASSERT(alphaOutputName.empty()); 404 std::ostringstream nameStream; 405 nameStream << "ANGLE_fragmentOut." 406 << ApplyOStream{ResolveUserDefinedName(outputVar.name, index, arraySize)} 407 << ".a"; 408 alphaOutputName = nameStream.str(); 409 } 410 } 411 }; 412 assignLocations(executable.getOutputLocations(), false); 413 assignLocations(executable.getSecondaryOutputLocations(), true); 414 415 if (defineAlpha0) 416 { 417 // Locations are empty for ESSL 1.00 shaders, try built-in outputs 418 if (alphaOutputName.empty()) 419 { 420 for (auto &v : outputVariables) 421 { 422 if (v.name == "gl_FragColor") 423 { 424 alphaOutputName = "ANGLE_fragmentOut.gl_FragColor.a"; 425 break; 426 } 427 else if (v.name == "gl_FragData") 428 { 429 alphaOutputName = "ANGLE_fragmentOut.ANGLE_gl_FragData_0.a"; 430 break; 431 } 432 } 433 } 434 435 // Set a value used for alpha-to-coverage emulation 436 const std::string alphaPlaceholder("#define ANGLE_ALPHA0"); 437 size_t alphaFound = outputSource.find(alphaPlaceholder); 438 ASSERT(alphaFound != std::string::npos); 439 440 std::ostringstream alphaStream; 441 alphaStream << alphaPlaceholder << " "; 442 alphaStream << (alphaOutputName.empty() ? "1.0" : alphaOutputName); 443 outputSource = 444 outputSource.replace(alphaFound, alphaPlaceholder.length(), alphaStream.str()); 445 } 446 447 return outputSource; 448} 449 450std::string SubstituteTransformFeedbackMarkers(const std::string &originalSource, 451 const std::string &xfbBindings, 452 const std::string &xfbOut) 453{ 454 const size_t xfbBindingsMarkerStart = originalSource.find(kXfbBindingsMarker); 455 bool hasBindingsMarker = xfbBindingsMarkerStart != std::string::npos; 456 const size_t xfbBindingsMarkerEnd = 457 xfbBindingsMarkerStart + angle::ConstStrLen(kXfbBindingsMarker); 458 459 const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker, xfbBindingsMarkerStart); 460 bool hasOutMarker = xfbOutMarkerStart != std::string::npos; 461 const size_t xfbOutMarkerEnd = xfbOutMarkerStart + angle::ConstStrLen(kXfbOutMarker); 462 463 // The shader is the following form: 464 // 465 // ..part1.. 466 // @@ XFB-BINDINGS @@ 467 // ..part2.. 468 // @@ XFB-OUT @@; 469 // ..part3.. 470 // 471 // Construct the string by concatenating these five pieces, replacing the markers with the given 472 // values. 473 std::string result; 474 if (hasBindingsMarker && hasOutMarker) 475 { 476 result.append(&originalSource[0], &originalSource[xfbBindingsMarkerStart]); 477 result.append(xfbBindings); 478 result.append(&originalSource[xfbBindingsMarkerEnd], &originalSource[xfbOutMarkerStart]); 479 result.append(xfbOut); 480 result.append(&originalSource[xfbOutMarkerEnd], &originalSource[originalSource.size()]); 481 return result; 482 } 483 return originalSource; 484} 485 486std::string GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVarying &varying, 487 const gl::UniformTypeInfo &info, 488 size_t strideBytes, 489 size_t offset, 490 const std::string &bufferIndex) 491{ 492 std::ostringstream result; 493 494 ASSERT(strideBytes % 4 == 0); 495 size_t stride = strideBytes / 4; 496 497 const size_t arrayIndexStart = varying.arrayIndex == GL_INVALID_INDEX ? 0 : varying.arrayIndex; 498 const size_t arrayIndexEnd = arrayIndexStart + varying.size(); 499 500 for (size_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex) 501 { 502 for (int col = 0; col < info.columnCount; ++col) 503 { 504 for (int row = 0; row < info.rowCount; ++row) 505 { 506 result << " "; 507 result << "ANGLE_" << "xfbBuffer" << bufferIndex << "[" << "ANGLE_" 508 << std::string(sh::kUniformsVar) << ".ANGLE_xfbBufferOffsets[" << bufferIndex 509 << "] + (ANGLE_vertexIDMetal + (ANGLE_instanceIdMod - ANGLE_baseInstance) * " 510 << "ANGLE_" << std::string(sh::kUniformsVar) 511 << ".ANGLE_xfbVerticesPerInstance) * " << stride << " + " << offset 512 << "] = " << "as_type<float>" << "(" << "ANGLE_vertexOut."; 513 if (!varying.isBuiltIn()) 514 { 515 result << kUserDefinedNamePrefix; 516 } 517 result << varying.name; 518 519 if (varying.isArray()) 520 { 521 result << "[" << arrayIndex << "]"; 522 } 523 524 if (info.columnCount > 1) 525 { 526 result << "[" << col << "]"; 527 } 528 529 if (info.rowCount > 1) 530 { 531 result << "[" << row << "]"; 532 } 533 534 result << ");\n"; 535 ++offset; 536 } 537 } 538 } 539 540 return result.str(); 541} 542 543void GenerateTransformFeedbackEmulationOutputs( 544 const gl::ProgramExecutable &executable, 545 std::string *vertexShader, 546 std::array<uint32_t, kMaxShaderXFBs> *xfbBindingRemapOut) 547{ 548 const std::vector<gl::TransformFeedbackVarying> &varyings = 549 executable.getLinkedTransformFeedbackVaryings(); 550 const std::vector<GLsizei> &bufferStrides = executable.getTransformFeedbackStrides(); 551 const bool isInterleaved = 552 executable.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS; 553 const size_t bufferCount = isInterleaved ? 1 : varyings.size(); 554 555 std::vector<std::string> xfbIndices(bufferCount); 556 557 std::string xfbBindings; 558 559 for (uint32_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex) 560 { 561 const std::string xfbBinding = Str(0); 562 xfbIndices[bufferIndex] = Str(bufferIndex); 563 564 std::string bufferName = GetXfbBufferNameMtl(bufferIndex); 565 566 xfbBindings += ", "; 567 // TODO: offset from last used buffer binding from front end 568 // XFB buffer is allocated slot starting from last discrete Metal buffer slot. 569 uint32_t bindingPoint = kMaxShaderBuffers - 1 - bufferIndex; 570 xfbBindingRemapOut->at(bufferIndex) = bindingPoint; 571 xfbBindings += 572 "device float* ANGLE_" + bufferName + " [[buffer(" + Str(bindingPoint) + ")]]"; 573 } 574 575 std::string xfbOut = "#if TRANSFORM_FEEDBACK_ENABLED\n {\n"; 576 size_t outputOffset = 0; 577 for (size_t varyingIndex = 0; varyingIndex < varyings.size(); ++varyingIndex) 578 { 579 const size_t bufferIndex = isInterleaved ? 0 : varyingIndex; 580 const gl::TransformFeedbackVarying &varying = varyings[varyingIndex]; 581 582 // For every varying, output to the respective buffer packed. If interleaved, the output is 583 // always to the same buffer, but at different offsets. 584 const gl::UniformTypeInfo &info = gl::GetUniformTypeInfo(varying.type); 585 xfbOut += GenerateTransformFeedbackVaryingOutput(varying, info, bufferStrides[bufferIndex], 586 outputOffset, xfbIndices[bufferIndex]); 587 588 if (isInterleaved) 589 { 590 outputOffset += info.columnCount * info.rowCount * varying.size(); 591 } 592 } 593 xfbOut += " }\n#endif\n"; 594 595 *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbBindings, xfbOut); 596} 597 598angle::Result MTLGetMSL(Context *context, 599 const gl::ProgramExecutable &executable, 600 const gl::Caps &glCaps, 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 bool defineAlpha0 = 664 context->getDisplay()->getFeatures().emulateAlphaToCoverage.enabled || 665 context->getDisplay()->getFeatures().generateShareableShaders.enabled; 666 source = UpdateFragmentShaderOutputs(shaderSources[type], executable, defineAlpha0); 667 } 668 (*mslShaderInfoOut)[type].metalShaderSource = 669 std::make_shared<const std::string>(std::move(source)); 670 const sh::TranslatorMetalReflection *reflection = 671 &shadersState[type]->translatorMetalReflection; 672 if (reflection->hasUBOs) 673 { 674 (*mslShaderInfoOut)[type].hasUBOArgumentBuffer = true; 675 676 for (auto &uboBinding : reflection->getUniformBufferBindings()) 677 { 678 const std::string &uboName = uboBinding.first; 679 const sh::UBOBindingInfo &bindInfo = uboBinding.second; 680 const uint32_t uboBindIndex = static_cast<uint32_t>(bindInfo.bindIndex); 681 const uint32_t uboArraySize = static_cast<uint32_t>(bindInfo.arraySize); 682 const uint32_t originalBinding = uboOriginalBindings.at(uboName); 683 uint32_t currentSlot = static_cast<uint>(uboBindIndex); 684 for (uint32_t i = 0; i < uboArraySize; ++i) 685 { 686 // Use consecutive slot for member in array 687 (*mslShaderInfoOut)[type].actualUBOBindings[originalBinding + i] = 688 currentSlot + i; 689 } 690 } 691 } 692 // Retrieve automatic texture slot assignments 693 if (originalSamplerBindings.size() > 0) 694 { 695 GetAssignedSamplerBindings(reflection, originalSamplerBindings, structSamplers, 696 &mslShaderInfoOut->at(type).actualSamplerBindings); 697 } 698 for (uint32_t i = 0; i < kMaxShaderImages; ++i) 699 { 700 mslShaderInfoOut->at(type).actualImageBindings[i] = reflection->getRWTextureBinding(i); 701 } 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