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