xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/blocklayoutMetal.cpp (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 // blocklayoutMetal.cpp:
7 //   Implementation for metal block layout classes and methods.
8 //
9 
10 #include "libANGLE/renderer/metal/blocklayoutMetal.h"
11 #include "common/mathutil.h"
12 #include "common/utilities.h"
13 #include "compiler/translator/blocklayout.h"
14 namespace rx
15 {
16 namespace mtl
17 {
18 // Sizes and types are available at
19 // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
20 // Section 2
GetMetalSizeForGLType(GLenum type)21 size_t GetMetalSizeForGLType(GLenum type)
22 {
23     switch (type)
24     {
25         case GL_BOOL:
26             return 1;
27         case GL_BOOL_VEC2:
28             return 2;
29         case GL_BOOL_VEC3:
30         case GL_BOOL_VEC4:
31             return 4;
32         case GL_FLOAT:
33             return 4;
34         case GL_FLOAT_VEC2:
35             return 8;
36         case GL_FLOAT_VEC3:
37         case GL_FLOAT_VEC4:
38             return 16;
39         case GL_FLOAT_MAT2:  // 2x2
40             return 16;
41         case GL_FLOAT_MAT3:  // 3x4
42             return 48;
43         case GL_FLOAT_MAT4:  // 4x4
44             return 64;
45         case GL_FLOAT_MAT2x3:  // 2x4
46             return 32;
47         case GL_FLOAT_MAT3x2:  // 3x2
48             return 24;
49         case GL_FLOAT_MAT2x4:  // 2x4
50             return 32;
51         case GL_FLOAT_MAT4x2:  // 4x2
52             return 32;
53         case GL_FLOAT_MAT3x4:  // 3x4
54             return 48;
55         case GL_FLOAT_MAT4x3:  // 4x4
56             return 64;
57         case GL_INT:
58             return 4;
59         case GL_INT_VEC2:
60             return 8;
61         case GL_INT_VEC3:
62         case GL_INT_VEC4:
63             return 16;
64         case GL_UNSIGNED_INT:
65             return 4;
66         case GL_UNSIGNED_INT_VEC2:
67             return 8;
68         case GL_UNSIGNED_INT_VEC3:
69         case GL_UNSIGNED_INT_VEC4:
70             return 16;
71         case GL_SAMPLER_2D:
72         case GL_SAMPLER_2D_RECT_ANGLE:
73         case GL_SAMPLER_3D:
74         case GL_SAMPLER_CUBE:
75         case GL_SAMPLER_CUBE_MAP_ARRAY:
76         case GL_SAMPLER_2D_ARRAY:
77         case GL_SAMPLER_EXTERNAL_OES:
78         case GL_SAMPLER_2D_MULTISAMPLE:
79         case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
80         case GL_INT_SAMPLER_BUFFER:
81         case GL_INT_SAMPLER_2D:
82         case GL_INT_SAMPLER_3D:
83         case GL_INT_SAMPLER_CUBE:
84         case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
85         case GL_INT_SAMPLER_2D_ARRAY:
86         case GL_INT_SAMPLER_2D_MULTISAMPLE:
87         case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
88         case GL_UNSIGNED_INT_SAMPLER_2D:
89         case GL_UNSIGNED_INT_SAMPLER_3D:
90         case GL_UNSIGNED_INT_SAMPLER_CUBE:
91         case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
92         case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
93         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
94         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
95         case GL_SAMPLER_2D_SHADOW:
96         case GL_SAMPLER_BUFFER:
97         case GL_SAMPLER_CUBE_SHADOW:
98         case GL_SAMPLER_2D_ARRAY_SHADOW:
99         case GL_IMAGE_2D:
100         case GL_INT_IMAGE_2D:
101         case GL_UNSIGNED_INT_IMAGE_2D:
102         case GL_IMAGE_3D:
103         case GL_INT_IMAGE_3D:
104         case GL_UNSIGNED_INT_IMAGE_3D:
105         case GL_IMAGE_2D_ARRAY:
106         case GL_INT_IMAGE_2D_ARRAY:
107         case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
108         case GL_IMAGE_CUBE:
109         case GL_INT_IMAGE_CUBE:
110         case GL_UNSIGNED_INT_IMAGE_CUBE:
111         case GL_IMAGE_CUBE_MAP_ARRAY:
112         case GL_INT_IMAGE_CUBE_MAP_ARRAY:
113         case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
114         case GL_IMAGE_BUFFER:
115         case GL_INT_IMAGE_BUFFER:
116         case GL_UNSIGNED_INT_SAMPLER_BUFFER:
117         case GL_UNSIGNED_INT_IMAGE_BUFFER:
118         case GL_UNSIGNED_INT_ATOMIC_COUNTER:
119         case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
120         case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT:
121             UNREACHABLE();
122             break;
123         default:
124             UNREACHABLE();
125             break;
126     }
127     return 0;
128 }
129 
GetMetalAlignmentForGLType(GLenum type)130 size_t GetMetalAlignmentForGLType(GLenum type)
131 {
132     switch (type)
133     {
134         case GL_BOOL:
135             return 1;
136         case GL_BOOL_VEC2:
137             return 2;
138         case GL_BOOL_VEC3:
139         case GL_BOOL_VEC4:
140             return 4;
141         case GL_FLOAT:
142             return 4;
143         case GL_FLOAT_VEC2:
144             return 8;
145         case GL_FLOAT_VEC3:
146         case GL_FLOAT_VEC4:
147             return 16;
148         case GL_FLOAT_MAT2:
149             return 8;
150         case GL_FLOAT_MAT3:
151             return 16;
152         case GL_FLOAT_MAT4:
153             return 16;
154         case GL_FLOAT_MAT2x3:
155             return 16;
156         case GL_FLOAT_MAT3x2:
157             return 8;
158         case GL_FLOAT_MAT2x4:
159             return 16;
160         case GL_FLOAT_MAT4x2:
161             return 8;
162         case GL_FLOAT_MAT3x4:
163             return 16;
164         case GL_FLOAT_MAT4x3:
165             return 16;
166         case GL_INT:
167             return 4;
168         case GL_INT_VEC2:
169             return 8;
170         case GL_INT_VEC3:
171             return 16;
172         case GL_INT_VEC4:
173             return 16;
174         case GL_UNSIGNED_INT:
175             return 4;
176         case GL_UNSIGNED_INT_VEC2:
177             return 8;
178         case GL_UNSIGNED_INT_VEC3:
179         case GL_UNSIGNED_INT_VEC4:
180             return 16;
181         case GL_SAMPLER_2D:
182         case GL_SAMPLER_2D_RECT_ANGLE:
183         case GL_SAMPLER_3D:
184         case GL_SAMPLER_CUBE:
185         case GL_SAMPLER_CUBE_MAP_ARRAY:
186         case GL_SAMPLER_2D_ARRAY:
187         case GL_SAMPLER_EXTERNAL_OES:
188         case GL_SAMPLER_2D_MULTISAMPLE:
189         case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
190         case GL_INT_SAMPLER_BUFFER:
191         case GL_INT_SAMPLER_2D:
192         case GL_INT_SAMPLER_3D:
193         case GL_INT_SAMPLER_CUBE:
194         case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
195         case GL_INT_SAMPLER_2D_ARRAY:
196         case GL_INT_SAMPLER_2D_MULTISAMPLE:
197         case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
198         case GL_UNSIGNED_INT_SAMPLER_2D:
199         case GL_UNSIGNED_INT_SAMPLER_3D:
200         case GL_UNSIGNED_INT_SAMPLER_CUBE:
201         case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
202         case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
203         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
204         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
205         case GL_SAMPLER_2D_SHADOW:
206         case GL_SAMPLER_BUFFER:
207         case GL_SAMPLER_CUBE_SHADOW:
208         case GL_SAMPLER_2D_ARRAY_SHADOW:
209         case GL_IMAGE_2D:
210         case GL_INT_IMAGE_2D:
211         case GL_UNSIGNED_INT_IMAGE_2D:
212         case GL_IMAGE_3D:
213         case GL_INT_IMAGE_3D:
214         case GL_UNSIGNED_INT_IMAGE_3D:
215         case GL_IMAGE_2D_ARRAY:
216         case GL_INT_IMAGE_2D_ARRAY:
217         case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
218         case GL_IMAGE_CUBE:
219         case GL_INT_IMAGE_CUBE:
220         case GL_UNSIGNED_INT_IMAGE_CUBE:
221         case GL_IMAGE_CUBE_MAP_ARRAY:
222         case GL_INT_IMAGE_CUBE_MAP_ARRAY:
223         case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
224         case GL_IMAGE_BUFFER:
225         case GL_INT_IMAGE_BUFFER:
226         case GL_UNSIGNED_INT_SAMPLER_BUFFER:
227         case GL_UNSIGNED_INT_IMAGE_BUFFER:
228         case GL_UNSIGNED_INT_ATOMIC_COUNTER:
229         case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
230         case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT:
231             UNREACHABLE();
232             break;
233         default:
234             UNREACHABLE();
235             break;
236     }
237     return 0;
238 }
239 
GetMTLBaseAlignment(GLenum variableType,bool isRowMajor)240 size_t GetMTLBaseAlignment(GLenum variableType, bool isRowMajor)
241 {
242     return mtl::GetMetalAlignmentForGLType(variableType);
243 }
244 
visitVariable(const sh::ShaderVariable & variable,bool isRowMajor)245 void MetalAlignmentVisitor::visitVariable(const sh::ShaderVariable &variable, bool isRowMajor)
246 {
247     size_t baseAlignment = GetMTLBaseAlignment(variable.type, isRowMajor);
248     mCurrentAlignment    = std::max(mCurrentAlignment, baseAlignment);
249 }
250 
BlockLayoutEncoderMTL()251 BlockLayoutEncoderMTL::BlockLayoutEncoderMTL() : BlockLayoutEncoder() {}
252 
getBlockLayoutInfo(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int * arrayStrideOut,int * matrixStrideOut)253 void BlockLayoutEncoderMTL::getBlockLayoutInfo(GLenum type,
254                                                const std::vector<unsigned int> &arraySizes,
255                                                bool isRowMajorMatrix,
256                                                int *arrayStrideOut,
257                                                int *matrixStrideOut)
258 {
259     size_t baseAlignment = 0;
260     int matrixStride     = 0;
261     int arrayStride      = 0;
262 
263     if (gl::IsMatrixType(type))
264     {
265         baseAlignment = static_cast<int>(mtl::GetMetalAlignmentForGLType(type));
266         matrixStride  = static_cast<int>(mtl::GetMetalAlignmentForGLType(type));
267         if (!arraySizes.empty())
268         {
269             arrayStride = static_cast<int>(mtl::GetMetalSizeForGLType(type));
270         }
271     }
272     else if (!arraySizes.empty())
273     {
274         baseAlignment = static_cast<int>(mtl::GetMetalAlignmentForGLType(type));
275         arrayStride   = static_cast<int>(mtl::GetMetalSizeForGLType(type));
276     }
277     else
278     {
279         baseAlignment = mtl::GetMetalAlignmentForGLType(type);
280     }
281     align(baseAlignment);
282     *matrixStrideOut = matrixStride;
283     *arrayStrideOut  = arrayStride;
284 }
encodeType(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix)285 sh::BlockMemberInfo BlockLayoutEncoderMTL::encodeType(GLenum type,
286                                                       const std::vector<unsigned int> &arraySizes,
287                                                       bool isRowMajorMatrix)
288 {
289     int arrayStride;
290     int matrixStride;
291 
292     getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride);
293     const sh::BlockMemberInfo memberInfo(
294         type, static_cast<int>(mCurrentOffset), static_cast<int>(arrayStride),
295         static_cast<int>(matrixStride), gl::ArraySizeProduct(arraySizes), isRowMajorMatrix);
296     assert(memberInfo.offset >= 0);
297 
298     advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride);
299 
300     return memberInfo;
301 }
302 
encodeArrayOfPreEncodedStructs(size_t size,const std::vector<unsigned int> & arraySizes)303 sh::BlockMemberInfo BlockLayoutEncoderMTL::encodeArrayOfPreEncodedStructs(
304     size_t size,
305     const std::vector<unsigned int> &arraySizes)
306 {
307     const unsigned int innerArraySizeProduct = gl::InnerArraySizeProduct(arraySizes);
308     const unsigned int outermostArraySize    = gl::OutermostArraySize(arraySizes);
309 
310     // The size of struct is expected to be already aligned appropriately.
311     const size_t arrayStride = size * innerArraySizeProduct;
312     // Aggregate blockMemberInfo types not needed: only used by the Metal bakcend.
313     const sh::BlockMemberInfo memberInfo(GL_INVALID_ENUM, static_cast<int>(mCurrentOffset),
314                                          static_cast<int>(arrayStride), -1,
315                                          gl::ArraySizeProduct(arraySizes), false);
316 
317     angle::base::CheckedNumeric<size_t> checkedOffset(arrayStride);
318     checkedOffset *= outermostArraySize;
319     checkedOffset += mCurrentOffset;
320     mCurrentOffset = checkedOffset.ValueOrDie();
321 
322     return memberInfo;
323 }
324 
getCurrentOffset() const325 size_t BlockLayoutEncoderMTL::getCurrentOffset() const
326 {
327     angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
328     return checkedOffset.ValueOrDie();
329 }
330 
enterAggregateType(const sh::ShaderVariable & structVar)331 void BlockLayoutEncoderMTL::enterAggregateType(const sh::ShaderVariable &structVar)
332 {
333     align(getBaseAlignment(structVar));
334 }
335 
exitAggregateType(const sh::ShaderVariable & structVar)336 void BlockLayoutEncoderMTL::exitAggregateType(const sh::ShaderVariable &structVar)
337 {
338     align(getBaseAlignment(structVar));
339 }
340 
getShaderVariableSize(const sh::ShaderVariable & structVar,bool isRowMajor)341 size_t BlockLayoutEncoderMTL::getShaderVariableSize(const sh::ShaderVariable &structVar,
342                                                     bool isRowMajor)
343 {
344     size_t currentOffset = mCurrentOffset;
345     mCurrentOffset       = 0;
346     sh::BlockEncoderVisitor visitor("", "", this);
347     enterAggregateType(structVar);
348     TraverseShaderVariables(structVar.fields, isRowMajor, &visitor);
349     exitAggregateType(structVar);
350     size_t structVarSize = getCurrentOffset();
351     mCurrentOffset       = currentOffset;
352     return structVarSize;
353 }
354 
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)355 void BlockLayoutEncoderMTL::advanceOffset(GLenum type,
356                                           const std::vector<unsigned int> &arraySizes,
357                                           bool isRowMajorMatrix,
358                                           int arrayStride,
359                                           int matrixStride)
360 {
361     if (!arraySizes.empty())
362     {
363         angle::base::CheckedNumeric<size_t> checkedOffset(arrayStride);
364         checkedOffset *= gl::ArraySizeProduct(arraySizes);
365         checkedOffset += mCurrentOffset;
366         mCurrentOffset = checkedOffset.ValueOrDie();
367     }
368     else if (gl::IsMatrixType(type))
369     {
370         angle::base::CheckedNumeric<size_t> checkedOffset;
371         checkedOffset = mtl::GetMetalSizeForGLType(type);
372         checkedOffset += mCurrentOffset;
373         mCurrentOffset = checkedOffset.ValueOrDie();
374     }
375     else
376     {
377         angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
378         checkedOffset += mtl::GetMetalSizeForGLType(type);
379         mCurrentOffset = checkedOffset.ValueOrDie();
380     }
381 }
382 
getBaseAlignment(const sh::ShaderVariable & shaderVar) const383 size_t BlockLayoutEncoderMTL::getBaseAlignment(const sh::ShaderVariable &shaderVar) const
384 {
385     if (shaderVar.isStruct())
386     {
387         MetalAlignmentVisitor visitor;
388         TraverseShaderVariables(shaderVar.fields, false, &visitor);
389         return visitor.getBaseAlignment();
390     }
391 
392     return GetMTLBaseAlignment(shaderVar.type, shaderVar.isRowMajorLayout);
393 }
394 
getTypeBaseAlignment(GLenum type,bool isRowMajorMatrix) const395 size_t BlockLayoutEncoderMTL::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
396 {
397     return GetMTLBaseAlignment(type, isRowMajorMatrix);
398 }
399 
400 }  // namespace mtl
401 }  // namespace rx
402