xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/ProgramExecutableMtl.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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