1 // 2 // Copyright 2020 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 7 #ifndef COMPILER_TRANSLATOR_MSL_H_ 8 #define COMPILER_TRANSLATOR_MSL_H_ 9 10 #include "compiler/translator/Compiler.h" 11 12 namespace sh 13 { 14 15 constexpr const char kUniformsVar[] = "angleUniforms"; 16 constexpr const char kUnassignedAttributeString[] = " __unassigned_attribute__"; 17 constexpr const char kUnassignedFragmentOutputString[] = "__unassigned_output__"; 18 19 class DriverUniform; 20 class DriverUniformMetal; 21 class SpecConst; 22 class TOutputMSL; 23 class TranslatorMetalReflection; 24 typedef std::unordered_map<size_t, std::string> originalNamesMap; 25 typedef std::unordered_map<std::string, size_t> samplerBindingMap; 26 typedef std::unordered_map<std::string, size_t> textureBindingMap; 27 typedef std::unordered_map<int, int> rwTextureBindingMap; // GLSL image -> mtl read_write texture. 28 typedef std::unordered_map<std::string, size_t> userUniformBufferBindingMap; 29 typedef std::pair<size_t, size_t> uboBindingInfo; 30 struct UBOBindingInfo 31 { 32 size_t bindIndex = 0; 33 size_t arraySize = 0; 34 }; 35 typedef std::unordered_map<std::string, UBOBindingInfo> uniformBufferBindingMap; 36 37 namespace mtl 38 { 39 TranslatorMetalReflection *getTranslatorMetalReflection(const TCompiler *compiler); 40 } 41 42 class TranslatorMetalReflection 43 { 44 public: TranslatorMetalReflection()45 TranslatorMetalReflection() : hasUBOs(false), hasFlatInput(false) {} ~TranslatorMetalReflection()46 ~TranslatorMetalReflection() {} 47 addOriginalName(const size_t id,const std::string & name)48 void addOriginalName(const size_t id, const std::string &name) 49 { 50 originalNames.insert({id, name}); 51 } addSamplerBinding(const std::string & name,size_t samplerBinding)52 void addSamplerBinding(const std::string &name, size_t samplerBinding) 53 { 54 samplerBindings.insert({name, samplerBinding}); 55 } addTextureBinding(const std::string & name,size_t textureBinding)56 void addTextureBinding(const std::string &name, size_t textureBinding) 57 { 58 textureBindings.insert({name, textureBinding}); 59 } addRWTextureBinding(int glslImageBinding,int mtlRWTextureBinding)60 void addRWTextureBinding(int glslImageBinding, int mtlRWTextureBinding) 61 { 62 bool inserted = rwTextureBindings.insert({glslImageBinding, mtlRWTextureBinding}).second; 63 if (!inserted) 64 { 65 // Shader images are currently only implemented enough to support pixel local storage, 66 // which does not allow more than one image to be bound to the same index. 67 // 68 // NOTE: Pixel local storage also does not allow image bindings to change via 69 // glUniform1i, which we do not currently account for in this backend. 70 UNIMPLEMENTED(); 71 } 72 } addUserUniformBufferBinding(const std::string & name,size_t userUniformBufferBinding)73 void addUserUniformBufferBinding(const std::string &name, size_t userUniformBufferBinding) 74 { 75 userUniformBufferBindings.insert({name, userUniformBufferBinding}); 76 } addUniformBufferBinding(const std::string & name,UBOBindingInfo bindingInfo)77 void addUniformBufferBinding(const std::string &name, UBOBindingInfo bindingInfo) 78 { 79 uniformBufferBindings.insert({name, bindingInfo}); 80 } getOriginalName(const size_t id)81 std::string getOriginalName(const size_t id) { return originalNames.at(id); } getSamplerBindings()82 samplerBindingMap getSamplerBindings() const { return samplerBindings; } getTextureBindings()83 textureBindingMap getTextureBindings() const { return textureBindings; } getUserUniformBufferBindings()84 userUniformBufferBindingMap getUserUniformBufferBindings() const 85 { 86 return userUniformBufferBindings; 87 } getUniformBufferBindings()88 uniformBufferBindingMap getUniformBufferBindings() const { return uniformBufferBindings; } getSamplerBinding(const std::string & name)89 size_t getSamplerBinding(const std::string &name) const 90 { 91 auto it = samplerBindings.find(name); 92 if (it != samplerBindings.end()) 93 { 94 return it->second; 95 } 96 // If we can't find a matching sampler, assert out on Debug, and return an invalid value on 97 // release. 98 ASSERT(0); 99 return std::numeric_limits<size_t>::max(); 100 } getTextureBinding(const std::string & name)101 size_t getTextureBinding(const std::string &name) const 102 { 103 auto it = textureBindings.find(name); 104 if (it != textureBindings.end()) 105 { 106 return it->second; 107 } 108 // If we can't find a matching texture, assert out on Debug, and return an invalid value on 109 // release. 110 ASSERT(0); 111 return std::numeric_limits<size_t>::max(); 112 } getRWTextureBinding(int glslImageBinding)113 int getRWTextureBinding(int glslImageBinding) const 114 { 115 auto it = rwTextureBindings.find(glslImageBinding); 116 if (it != rwTextureBindings.end()) 117 { 118 return it->second; 119 } 120 // If there isn't a shader image bound to this slot, return -1. This signals to the program 121 // that there is nothing here to bind. 122 return -1; 123 } getUserUniformBufferBinding(const std::string & name)124 size_t getUserUniformBufferBinding(const std::string &name) const 125 { 126 auto it = userUniformBufferBindings.find(name); 127 if (it != userUniformBufferBindings.end()) 128 { 129 return it->second; 130 } 131 // If we can't find a matching Uniform binding, assert out on Debug, and return an invalid 132 // value. 133 ASSERT(0); 134 return std::numeric_limits<size_t>::max(); 135 } getUniformBufferBinding(const std::string & name)136 UBOBindingInfo getUniformBufferBinding(const std::string &name) const 137 { 138 auto it = uniformBufferBindings.find(name); 139 if (it != uniformBufferBindings.end()) 140 { 141 return it->second; 142 } 143 // If we can't find a matching UBO binding by name, assert out on Debug, and return an 144 // invalid value. 145 ASSERT(0); 146 return {.bindIndex = std::numeric_limits<size_t>::max(), 147 .arraySize = std::numeric_limits<size_t>::max()}; 148 } reset()149 void reset() 150 { 151 hasUBOs = false; 152 hasFlatInput = false; 153 hasAtan = false; 154 hasInvariance = false; 155 originalNames.clear(); 156 samplerBindings.clear(); 157 textureBindings.clear(); 158 rwTextureBindings.clear(); 159 userUniformBufferBindings.clear(); 160 uniformBufferBindings.clear(); 161 } 162 163 bool hasUBOs = false; 164 bool hasFlatInput = false; 165 bool hasAtan = false; 166 bool hasInvariance = false; 167 168 private: 169 originalNamesMap originalNames; 170 samplerBindingMap samplerBindings; 171 textureBindingMap textureBindings; 172 rwTextureBindingMap rwTextureBindings; 173 userUniformBufferBindingMap userUniformBufferBindings; 174 uniformBufferBindingMap uniformBufferBindings; 175 }; 176 177 class TranslatorMSL : public TCompiler 178 { 179 public: 180 TranslatorMSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); 181 182 #ifdef ANGLE_ENABLE_METAL getAsTranslatorMSL()183 TranslatorMSL *getAsTranslatorMSL() override { return this; } 184 #endif 185 getTranslatorMetalReflection()186 TranslatorMetalReflection *getTranslatorMetalReflection() { return &translatorMetalReflection; } 187 188 protected: 189 bool translate(TIntermBlock *root, 190 const ShCompileOptions &compileOptions, 191 PerformanceDiagnostics *perfDiagnostics) override; 192 193 // The sample mask can't be in our fragment output struct if we read the framebuffer. Luckily, 194 // pixel local storage bans gl_SampleMask, so we can just not use it when PLS is active. isSampleMaskAllowed()195 bool isSampleMaskAllowed() const { return !hasPixelLocalStorageUniforms(); } 196 197 [[nodiscard]] bool translateImpl(TInfoSinkBase &sink, 198 TIntermBlock *root, 199 const ShCompileOptions &compileOptions, 200 PerformanceDiagnostics *perfDiagnostics, 201 SpecConst *specConst, 202 DriverUniformMetal *driverUniforms); 203 204 [[nodiscard]] bool shouldFlattenPragmaStdglInvariantAll() override; 205 206 [[nodiscard]] bool transformDepthBeforeCorrection(TIntermBlock *root, 207 const DriverUniformMetal *driverUniforms); 208 209 [[nodiscard]] bool appendVertexShaderDepthCorrectionToMain( 210 TIntermBlock *root, 211 const DriverUniformMetal *driverUniforms); 212 213 [[nodiscard]] bool insertSampleMaskWritingLogic(TIntermBlock &root, 214 DriverUniformMetal &driverUniforms); 215 [[nodiscard]] bool insertRasterizationDiscardLogic(TIntermBlock &root); 216 217 TranslatorMetalReflection translatorMetalReflection = {}; 218 }; 219 220 } // namespace sh 221 222 #endif // COMPILER_TRANSLATOR_MSL_H_ 223