1 // 2 // Copyright 2023 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 // ProgramExecutableMtl.h: Implementation of ProgramExecutableImpl. 8 9 #ifndef LIBANGLE_RENDERER_MTL_PROGRAMEXECUTABLEMTL_H_ 10 #define LIBANGLE_RENDERER_MTL_PROGRAMEXECUTABLEMTL_H_ 11 12 #include "libANGLE/ProgramExecutable.h" 13 #include "libANGLE/renderer/ProgramExecutableImpl.h" 14 #include "libANGLE/renderer/metal/mtl_buffer_pool.h" 15 #include "libANGLE/renderer/metal/mtl_command_buffer.h" 16 #include "libANGLE/renderer/metal/mtl_common.h" 17 #include "libANGLE/renderer/metal/mtl_msl_utils.h" 18 #include "libANGLE/renderer/metal/mtl_resources.h" 19 #include "libANGLE/renderer/metal/mtl_state_cache.h" 20 21 namespace rx 22 { 23 class ContextMtl; 24 25 struct UBOConversionInfo 26 { 27 UBOConversionInfoUBOConversionInfo28 UBOConversionInfo(const std::vector<sh::BlockMemberInfo> &stdInfo, 29 const std::vector<sh::BlockMemberInfo> &metalInfo, 30 size_t stdSize, 31 size_t metalSize) 32 : _stdInfo(stdInfo), _metalInfo(metalInfo), _stdSize(stdSize), _metalSize(metalSize) 33 { 34 _needsConversion = _calculateNeedsConversion(); 35 } stdInfoUBOConversionInfo36 const std::vector<sh::BlockMemberInfo> &stdInfo() const { return _stdInfo; } metalInfoUBOConversionInfo37 const std::vector<sh::BlockMemberInfo> &metalInfo() const { return _metalInfo; } stdSizeUBOConversionInfo38 size_t stdSize() const { return _stdSize; } metalSizeUBOConversionInfo39 size_t metalSize() const { return _metalSize; } 40 needsConversionUBOConversionInfo41 bool needsConversion() const { return _needsConversion; } 42 43 private: 44 std::vector<sh::BlockMemberInfo> _stdInfo, _metalInfo; 45 size_t _stdSize, _metalSize; 46 bool _needsConversion; 47 _calculateNeedsConversionUBOConversionInfo48 bool _calculateNeedsConversion() 49 { 50 // If we have a different number of fields then we need conversion 51 if (_stdInfo.size() != _metalInfo.size()) 52 { 53 return true; 54 } 55 for (size_t i = 0; i < _stdInfo.size(); ++i) 56 { 57 // If the matrix is transposed 58 if (_stdInfo[i].isRowMajorMatrix) 59 { 60 return true; 61 } 62 // If we have a bool 63 if (gl::VariableComponentType(_stdInfo[i].type) == GL_BOOL) 64 { 65 return true; 66 } 67 // If any offset information is different 68 if (!(_stdInfo[i] == _metalInfo[i])) 69 { 70 return true; 71 } 72 } 73 return false; 74 } 75 }; 76 77 struct ProgramArgumentBufferEncoderMtl 78 { 79 void reset(ContextMtl *contextMtl); 80 81 mtl::AutoObjCPtr<id<MTLArgumentEncoder>> metalArgBufferEncoder; 82 mtl::BufferPool bufferPool; 83 }; 84 85 constexpr size_t kFragmentShaderVariants = 4; 86 87 // Represents a specialized shader variant. For example, a shader variant with fragment coverage 88 // mask enabled and a shader variant without. 89 struct ProgramShaderObjVariantMtl 90 { 91 void reset(ContextMtl *contextMtl); 92 93 mtl::AutoObjCPtr<id<MTLFunction>> metalShader; 94 // UBO's argument buffer encoder. Used when number of UBOs used exceeds number of allowed 95 // discrete slots, and thus needs to encode all into one argument buffer. 96 ProgramArgumentBufferEncoderMtl uboArgBufferEncoder; 97 98 // Store reference to the TranslatedShaderInfo to easy querying mapped textures/UBO/XFB 99 // bindings. 100 const mtl::TranslatedShaderInfo *translatedSrcInfo; 101 }; 102 103 // State for the default uniform blocks. 104 struct DefaultUniformBlockMtl final : private angle::NonCopyable 105 { 106 DefaultUniformBlockMtl(); 107 ~DefaultUniformBlockMtl(); 108 109 // Shadow copies of the shader uniform data. 110 angle::MemoryBuffer uniformData; 111 112 // Since the default blocks are laid out in std140, this tells us where to write on a call 113 // to a setUniform method. They are arranged in uniform location order. 114 std::vector<sh::BlockMemberInfo> uniformLayout; 115 }; 116 117 class ProgramExecutableMtl : public ProgramExecutableImpl 118 { 119 public: 120 ProgramExecutableMtl(const gl::ProgramExecutable *executable); 121 ~ProgramExecutableMtl() override; 122 123 void destroy(const gl::Context *context) override; 124 125 angle::Result load(ContextMtl *contextMtl, gl::BinaryInputStream *stream); 126 void save(gl::BinaryOutputStream *stream); 127 128 void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override; 129 void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override; 130 void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override; 131 void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override; 132 void setUniform1iv(GLint location, GLsizei count, const GLint *v) override; 133 void setUniform2iv(GLint location, GLsizei count, const GLint *v) override; 134 void setUniform3iv(GLint location, GLsizei count, const GLint *v) override; 135 void setUniform4iv(GLint location, GLsizei count, const GLint *v) override; 136 void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override; 137 void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override; 138 void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override; 139 void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override; 140 void setUniformMatrix2fv(GLint location, 141 GLsizei count, 142 GLboolean transpose, 143 const GLfloat *value) override; 144 void setUniformMatrix3fv(GLint location, 145 GLsizei count, 146 GLboolean transpose, 147 const GLfloat *value) override; 148 void setUniformMatrix4fv(GLint location, 149 GLsizei count, 150 GLboolean transpose, 151 const GLfloat *value) override; 152 void setUniformMatrix2x3fv(GLint location, 153 GLsizei count, 154 GLboolean transpose, 155 const GLfloat *value) override; 156 void setUniformMatrix3x2fv(GLint location, 157 GLsizei count, 158 GLboolean transpose, 159 const GLfloat *value) override; 160 void setUniformMatrix2x4fv(GLint location, 161 GLsizei count, 162 GLboolean transpose, 163 const GLfloat *value) override; 164 void setUniformMatrix4x2fv(GLint location, 165 GLsizei count, 166 GLboolean transpose, 167 const GLfloat *value) override; 168 void setUniformMatrix3x4fv(GLint location, 169 GLsizei count, 170 GLboolean transpose, 171 const GLfloat *value) override; 172 void setUniformMatrix4x3fv(GLint location, 173 GLsizei count, 174 GLboolean transpose, 175 const GLfloat *value) override; 176 177 void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override; 178 void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override; 179 void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override; 180 hasFlatAttribute()181 bool hasFlatAttribute() const { return mProgramHasFlatAttributes; } 182 183 // Calls this before drawing, changedPipelineDesc is passed when vertex attributes desc and/or 184 // shader program changed. 185 angle::Result setupDraw(const gl::Context *glContext, 186 mtl::RenderCommandEncoder *cmdEncoder, 187 const mtl::RenderPipelineDesc &pipelineDesc, 188 bool pipelineDescChanged, 189 bool forceTexturesSetting, 190 bool uniformBuffersDirty); 191 192 private: 193 friend class ProgramMtl; 194 195 void reset(ContextMtl *context); 196 197 template <int cols, int rows> 198 void setUniformMatrixfv(GLint location, 199 GLsizei count, 200 GLboolean transpose, 201 const GLfloat *value); 202 template <class T> 203 void getUniformImpl(GLint location, T *v, GLenum entryPointType) const; 204 205 template <typename T> 206 void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType); 207 208 void saveTranslatedShaders(gl::BinaryOutputStream *stream); 209 void loadTranslatedShaders(gl::BinaryInputStream *stream); 210 211 void saveShaderInternalInfo(gl::BinaryOutputStream *stream); 212 void loadShaderInternalInfo(gl::BinaryInputStream *stream); 213 214 void saveInterfaceBlockInfo(gl::BinaryOutputStream *stream); 215 angle::Result loadInterfaceBlockInfo(gl::BinaryInputStream *stream); 216 217 void saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream); 218 angle::Result loadDefaultUniformBlocksInfo(mtl::Context *context, 219 gl::BinaryInputStream *stream); 220 221 void linkUpdateHasFlatAttributes(const gl::SharedCompiledShaderState &vertexShader); 222 223 angle::Result initDefaultUniformBlocks( 224 mtl::Context *context, 225 const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders); 226 angle::Result resizeDefaultUniformBlocksMemory(mtl::Context *context, 227 const gl::ShaderMap<size_t> &requiredBufferSize); 228 void initUniformBlocksRemapper(const gl::SharedCompiledShaderState &shader); 229 230 mtl::BufferPool *getBufferPool(ContextMtl *context, gl::ShaderType shaderType); 231 232 angle::Result getSpecializedShader(ContextMtl *context, 233 gl::ShaderType shaderType, 234 const mtl::RenderPipelineDesc &renderPipelineDesc, 235 id<MTLFunction> *shaderOut); 236 237 angle::Result commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder); 238 angle::Result updateTextures(const gl::Context *glContext, 239 mtl::RenderCommandEncoder *cmdEncoder, 240 bool forceUpdate); 241 242 angle::Result updateUniformBuffers(ContextMtl *context, 243 mtl::RenderCommandEncoder *cmdEncoder, 244 const mtl::RenderPipelineDesc &pipelineDesc); 245 angle::Result updateXfbBuffers(ContextMtl *context, 246 mtl::RenderCommandEncoder *cmdEncoder, 247 const mtl::RenderPipelineDesc &pipelineDesc); 248 angle::Result legalizeUniformBufferOffsets(ContextMtl *context); 249 angle::Result bindUniformBuffersToDiscreteSlots(ContextMtl *context, 250 mtl::RenderCommandEncoder *cmdEncoder, 251 gl::ShaderType shaderType); 252 253 angle::Result encodeUniformBuffersInfoArgumentBuffer(ContextMtl *context, 254 mtl::RenderCommandEncoder *cmdEncoder, 255 gl::ShaderType shaderType); 256 257 bool mProgramHasFlatAttributes; 258 259 gl::ShaderMap<DefaultUniformBlockMtl> mDefaultUniformBlocks; 260 std::unordered_map<std::string, UBOConversionInfo> mUniformBlockConversions; 261 262 // Translated metal shaders: 263 gl::ShaderMap<mtl::TranslatedShaderInfo> mMslShaderTranslateInfo; 264 265 // Translated metal version for transform feedback only vertex shader: 266 // - Metal doesn't allow vertex shader to write to both buffers and to stage output 267 // (gl_Position). Need a special version of vertex shader that only writes to transform feedback 268 // buffers. 269 mtl::TranslatedShaderInfo mMslXfbOnlyVertexShaderInfo; 270 271 // Compiled native shader object variants: 272 // - Vertex shader: One with emulated rasterization discard, one with true rasterization 273 // discard, one without. 274 mtl::RenderPipelineRasterStateMap<ProgramShaderObjVariantMtl> mVertexShaderVariants; 275 // - Fragment shader: Combinations of sample coverage mask and depth write enabled states. 276 std::array<ProgramShaderObjVariantMtl, kFragmentShaderVariants> mFragmentShaderVariants; 277 278 // Cached references of current shader variants. 279 gl::ShaderMap<ProgramShaderObjVariantMtl *> mCurrentShaderVariants; 280 281 gl::ShaderBitSet mDefaultUniformBlocksDirty; 282 gl::ShaderBitSet mSamplerBindingsDirty; 283 284 // Scratch data: 285 // Legalized buffers and their offsets. For example, uniform buffer's offset=1 is not a valid 286 // offset, it will be converted to legal offset and the result is stored in this array. 287 std::vector<std::pair<mtl::BufferRef, uint32_t>> mLegalizedOffsetedUniformBuffers; 288 // Stores the render stages usage of each uniform buffer. Only used if the buffers are encoded 289 // into an argument buffer. 290 std::vector<uint32_t> mArgumentBufferRenderStageUsages; 291 292 uint32_t mShadowCompareModes[mtl::kMaxShaderSamplers]; 293 294 gl::ShaderMap<std::unique_ptr<mtl::BufferPool>> mDefaultUniformBufferPools; 295 }; 296 297 angle::Result CreateMslShaderLib(mtl::Context *context, 298 gl::InfoLog &infoLog, 299 mtl::TranslatedShaderInfo *translatedMslInfo, 300 const std::map<std::string, std::string> &substitutionMacros); 301 } // namespace rx 302 303 #endif // LIBANGLE_RENDERER_MTL_PROGRAMEXECUTABLEMTL_H_ 304