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