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/ShaderInterfaceVariableInfoMap.h" 22 #include "libANGLE/renderer/glslang_wrapper_utils.h" 23 #include "libANGLE/renderer/metal/mtl_buffer_pool.h" 24 #include "libANGLE/renderer/metal/mtl_command_buffer.h" 25 #include "libANGLE/renderer/metal/mtl_common.h" 26 #include "libANGLE/renderer/metal/mtl_context_device.h" 27 #include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h" 28 #include "libANGLE/renderer/metal/mtl_resources.h" 29 #include "libANGLE/renderer/metal/mtl_state_cache.h" 30 31 namespace rx 32 { 33 #define SHADER_ENTRY_NAME @"main0" 34 class ContextMtl; 35 36 struct ProgramArgumentBufferEncoderMtl 37 { 38 void reset(ContextMtl *contextMtl); 39 40 mtl::AutoObjCPtr<id<MTLArgumentEncoder>> metalArgBufferEncoder; 41 mtl::BufferPool bufferPool; 42 }; 43 44 // Represents a specialized shader variant. For example, a shader variant with fragment coverage 45 // mask enabled and a shader variant without. 46 struct ProgramShaderObjVariantMtl 47 { 48 void reset(ContextMtl *contextMtl); 49 50 mtl::AutoObjCPtr<id<MTLFunction>> metalShader; 51 // UBO's argument buffer encoder. Used when number of UBOs used exceeds number of allowed 52 // discrete slots, and thus needs to encode all into one argument buffer. 53 ProgramArgumentBufferEncoderMtl uboArgBufferEncoder; 54 55 // Store reference to the TranslatedShaderInfo to easy querying mapped textures/UBO/XFB 56 // bindings. 57 const mtl::TranslatedShaderInfo *translatedSrcInfo; 58 }; 59 60 class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecializeShaderFactory 61 { 62 public: 63 ProgramMtl(const gl::ProgramState &state); 64 ~ProgramMtl() override; 65 66 void destroy(const gl::Context *context) override; 67 68 std::unique_ptr<LinkEvent> load(const gl::Context *context, 69 gl::BinaryInputStream *stream, 70 gl::InfoLog &infoLog) override; 71 void save(const gl::Context *context, gl::BinaryOutputStream *stream) override; 72 void setBinaryRetrievableHint(bool retrievable) override; 73 void setSeparable(bool separable) override; 74 75 std::unique_ptr<LinkEvent> link(const gl::Context *context, 76 const gl::ProgramLinkedResources &resources, 77 gl::InfoLog &infoLog, 78 const gl::ProgramMergedVaryings &mergedVaryings) override; 79 GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override; 80 81 void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override; 82 void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override; 83 void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override; 84 void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override; 85 void setUniform1iv(GLint location, GLsizei count, const GLint *v) override; 86 void setUniform2iv(GLint location, GLsizei count, const GLint *v) override; 87 void setUniform3iv(GLint location, GLsizei count, const GLint *v) override; 88 void setUniform4iv(GLint location, GLsizei count, const GLint *v) override; 89 void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override; 90 void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override; 91 void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override; 92 void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override; 93 void setUniformMatrix2fv(GLint location, 94 GLsizei count, 95 GLboolean transpose, 96 const GLfloat *value) override; 97 void setUniformMatrix3fv(GLint location, 98 GLsizei count, 99 GLboolean transpose, 100 const GLfloat *value) override; 101 void setUniformMatrix4fv(GLint location, 102 GLsizei count, 103 GLboolean transpose, 104 const GLfloat *value) override; 105 void setUniformMatrix2x3fv(GLint location, 106 GLsizei count, 107 GLboolean transpose, 108 const GLfloat *value) override; 109 void setUniformMatrix3x2fv(GLint location, 110 GLsizei count, 111 GLboolean transpose, 112 const GLfloat *value) override; 113 void setUniformMatrix2x4fv(GLint location, 114 GLsizei count, 115 GLboolean transpose, 116 const GLfloat *value) override; 117 void setUniformMatrix4x2fv(GLint location, 118 GLsizei count, 119 GLboolean transpose, 120 const GLfloat *value) override; 121 void setUniformMatrix3x4fv(GLint location, 122 GLsizei count, 123 GLboolean transpose, 124 const GLfloat *value) override; 125 void setUniformMatrix4x3fv(GLint location, 126 GLsizei count, 127 GLboolean transpose, 128 const GLfloat *value) override; 129 130 void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override; 131 void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override; 132 void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override; 133 134 // Override mtl::RenderPipelineCacheSpecializeShaderFactory 135 angle::Result getSpecializedShader(ContextMtl *context, 136 gl::ShaderType shaderType, 137 const mtl::RenderPipelineDesc &renderPipelineDesc, 138 id<MTLFunction> *shaderOut) override; 139 bool hasSpecializedShader(gl::ShaderType shaderType, 140 const mtl::RenderPipelineDesc &renderPipelineDesc) override; 141 142 angle::Result createMslShaderLib( 143 ContextMtl *context, 144 gl::ShaderType shaderType, 145 gl::InfoLog &infoLog, 146 mtl::TranslatedShaderInfo *translatedMslInfo, 147 NSDictionary<NSString *, NSObject *> *subtitutionDictionary = @{}); 148 // Calls this before drawing, changedPipelineDesc is passed when vertex attributes desc and/or 149 // shader program changed. 150 angle::Result setupDraw(const gl::Context *glContext, 151 mtl::RenderCommandEncoder *cmdEncoder, 152 const mtl::RenderPipelineDesc &pipelineDesc, 153 bool pipelineDescChanged, 154 bool forceTexturesSetting, 155 bool uniformBuffersDirty); 156 getTranslatedShaderSource(const gl::ShaderType shaderType)157 std::string getTranslatedShaderSource(const gl::ShaderType shaderType) const 158 { 159 return mMslShaderTranslateInfo[shaderType].metalShaderSource; 160 } 161 getTranslatedShaderInfo(const gl::ShaderType shaderType)162 mtl::TranslatedShaderInfo getTranslatedShaderInfo(const gl::ShaderType shaderType) const 163 { 164 return mMslShaderTranslateInfo[shaderType]; 165 } 166 hasFlatAttribute()167 bool hasFlatAttribute() const { return mProgramHasFlatAttributes; } 168 169 private: 170 template <int cols, int rows> 171 void setUniformMatrixfv(GLint location, 172 GLsizei count, 173 GLboolean transpose, 174 const GLfloat *value); 175 template <class T> 176 void getUniformImpl(GLint location, T *v, GLenum entryPointType) const; 177 178 template <typename T> 179 void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType); 180 181 angle::Result initDefaultUniformBlocks(const gl::Context *glContext); 182 angle::Result resizeDefaultUniformBlocksMemory(const gl::Context *glContext, 183 const gl::ShaderMap<size_t> &requiredBufferSize); 184 void saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream); 185 angle::Result loadDefaultUniformBlocksInfo(const gl::Context *glContext, 186 gl::BinaryInputStream *stream); 187 188 angle::Result commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder); 189 angle::Result updateTextures(const gl::Context *glContext, 190 mtl::RenderCommandEncoder *cmdEncoder, 191 bool forceUpdate); 192 193 angle::Result updateUniformBuffers(ContextMtl *context, 194 mtl::RenderCommandEncoder *cmdEncoder, 195 const mtl::RenderPipelineDesc &pipelineDesc); 196 angle::Result updateXfbBuffers(ContextMtl *context, 197 mtl::RenderCommandEncoder *cmdEncoder, 198 const mtl::RenderPipelineDesc &pipelineDesc); 199 angle::Result legalizeUniformBufferOffsets(ContextMtl *context, 200 const std::vector<gl::InterfaceBlock> &blocks); 201 angle::Result bindUniformBuffersToDiscreteSlots(ContextMtl *context, 202 mtl::RenderCommandEncoder *cmdEncoder, 203 const std::vector<gl::InterfaceBlock> &blocks, 204 gl::ShaderType shaderType); 205 angle::Result encodeUniformBuffersInfoArgumentBuffer( 206 ContextMtl *context, 207 mtl::RenderCommandEncoder *cmdEncoder, 208 const std::vector<gl::InterfaceBlock> &blocks, 209 gl::ShaderType shaderType); 210 211 void reset(ContextMtl *context); 212 213 void saveTranslatedShaders(gl::BinaryOutputStream *stream); 214 void loadTranslatedShaders(gl::BinaryInputStream *stream); 215 216 void saveShaderInternalInfo(gl::BinaryOutputStream *stream); 217 void loadShaderInternalInfo(gl::BinaryInputStream *stream); 218 219 void linkUpdateHasFlatAttributes(); 220 221 #if ANGLE_ENABLE_METAL_SPIRV 222 223 angle::Result linkImplSpirv(const gl::Context *glContext, 224 const gl::ProgramLinkedResources &resources, 225 gl::InfoLog &infoLog); 226 #endif 227 228 angle::Result linkImplDirect(const gl::Context *glContext, 229 const gl::ProgramLinkedResources &resources, 230 gl::InfoLog &infoLog); 231 232 void linkResources(const gl::ProgramLinkedResources &resources); 233 angle::Result linkImpl(const gl::Context *glContext, 234 const gl::ProgramLinkedResources &resources, 235 gl::InfoLog &infoLog); 236 237 angle::Result linkTranslatedShaders(const gl::Context *glContext, 238 gl::BinaryInputStream *stream, 239 gl::InfoLog &infoLog); 240 241 mtl::BufferPool *getBufferPool(ContextMtl *context); 242 243 // State for the default uniform blocks. 244 struct DefaultUniformBlock final : private angle::NonCopyable 245 { 246 DefaultUniformBlock(); 247 ~DefaultUniformBlock(); 248 249 // Shadow copies of the shader uniform data. 250 angle::MemoryBuffer uniformData; 251 252 // Since the default blocks are laid out in std140, this tells us where to write on a call 253 // to a setUniform method. They are arranged in uniform location order. 254 std::vector<sh::BlockMemberInfo> uniformLayout; 255 }; 256 257 bool mProgramHasFlatAttributes; 258 gl::ShaderBitSet mDefaultUniformBlocksDirty; 259 gl::ShaderBitSet mSamplerBindingsDirty; 260 gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks; 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: One with sample coverage mask enabled, one with it disabled. 276 std::array<ProgramShaderObjVariantMtl, 2> mFragmentShaderVariants; 277 278 // Cached references of current shader variants. 279 gl::ShaderMap<ProgramShaderObjVariantMtl *> mCurrentShaderVariants; 280 281 ShaderInterfaceVariableInfoMap mVariableInfoMap; 282 // Scratch data: 283 // Legalized buffers and their offsets. For example, uniform buffer's offset=1 is not a valid 284 // offset, it will be converted to legal offset and the result is stored in this array. 285 std::vector<std::pair<mtl::BufferRef, uint32_t>> mLegalizedOffsetedUniformBuffers; 286 // Stores the render stages usage of each uniform buffer. Only used if the buffers are encoded 287 // into an argument buffer. 288 std::vector<uint32_t> mArgumentBufferRenderStageUsages; 289 290 uint32_t mShadowCompareModes[mtl::kMaxShaderSamplers]; 291 292 mtl::RenderPipelineCache mMetalRenderPipelineCache; 293 mtl::BufferPool *mAuxBufferPool; 294 }; 295 296 } // namespace rx 297 298 #endif /* LIBANGLE_RENDERER_METAL_PROGRAMMTL_H_ */ 299