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