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