• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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