xref: /aosp_15_r20/external/skia/tests/graphite/UniformManagerTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2022 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/base/SkFloatBits.h"
9 #include "src/base/SkHalf.h"
10 #include "src/core/SkSLTypeShared.h"
11 #include "src/gpu/graphite/PipelineData.h"
12 #include "src/gpu/graphite/Uniform.h"
13 #include "src/gpu/graphite/UniformManager.h"
14 #include "tests/Test.h"
15 
16 using namespace skgpu::graphite;
17 
18 static constexpr Layout kLayouts[] = {
19         Layout::kStd140,
20         Layout::kStd430,
21         Layout::kMetal,
22 };
23 
24 // This list excludes SkSLTypes that we don't support in uniforms, like Bool, UInt or UShort.
25 static constexpr SkSLType kTypes[] = {
26         SkSLType::kFloat,    SkSLType::kFloat2,   SkSLType::kFloat3,   SkSLType::kFloat4,   //
27         SkSLType::kHalf,     SkSLType::kHalf2,    SkSLType::kHalf3,    SkSLType::kHalf4,    //
28         SkSLType::kInt,      SkSLType::kInt2,     SkSLType::kInt3,     SkSLType::kInt4,     //
29         SkSLType::kFloat2x2, SkSLType::kFloat3x3, SkSLType::kFloat4x4,                      //
30         SkSLType::kHalf2x2,  SkSLType::kHalf3x3,  SkSLType::kHalf4x4,
31 };
32 
33 static constexpr float kFloats[16] = { 1.0f,  2.0f,  3.0f,  4.0f,
34                                        5.0f,  6.0f,  7.0f,  8.0f,
35                                        9.0f, 10.0f, 11.0f, 12.0f,
36                                       13.0f, 14.0f, 15.0f, 16.0f };
37 
38 static constexpr SkHalf kHalfs[16] = { 0x3C00, 0x4000, 0x4200, 0x4400,
39                                        0x4500, 0x4600, 0x4700, 0x4800,
40                                        0x4880, 0x4900, 0x4980, 0x4A00,
41                                        0x4A80, 0x4B00, 0x4B80, 0x4C00 };
42 
43 static constexpr int32_t kInts[16] = { 1,  -2,  3,  -4,
44                                        5,  -6,  7,  -8,
45                                        9, -10, 11, -12,
46                                       13, -14, 15, -16 };
47 
element_size(Layout layout,SkSLType type)48 static size_t element_size(Layout layout, SkSLType type) {
49     // Metal encodes half-precision uniforms in 16 bits.
50     // Other layouts are expected to encode uniforms in 32 bits.
51     return (layout == Layout::kMetal && !SkSLTypeIsFullPrecisionNumericType(type)) ? 2 : 4;
52 }
53 
DEF_GRAPHITE_TEST(UniformManagerCheckSingleUniform,r,CtsEnforcement::kApiLevel_V)54 DEF_GRAPHITE_TEST(UniformManagerCheckSingleUniform, r, CtsEnforcement::kApiLevel_V) {
55     // Verify that the uniform manager can hold all the basic uniform types, in every layout.
56     for (Layout layout : kLayouts) {
57         UniformManager mgr(layout);
58 
59         for (SkSLType type : kTypes) {
60             const Uniform expectations[] = {{"uniform", type}};
61             SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
62             mgr.write(expectations[0], kFloats);
63             SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
64             REPORTER_ASSERT(r, mgr.size() > 0, "Layout: %s - Type: %s",
65                             LayoutString(layout), SkSLTypeString(type));
66             mgr.reset();
67         }
68     }
69 }
70 
DEF_GRAPHITE_TEST(UniformManagerCheckFloatEncoding,r,CtsEnforcement::kApiLevel_V)71 DEF_GRAPHITE_TEST(UniformManagerCheckFloatEncoding, r, CtsEnforcement::kApiLevel_V) {
72     // Verify that the uniform manager encodes float data properly.
73     for (Layout layout : kLayouts) {
74         UniformManager mgr(layout);
75 
76         for (SkSLType type : kTypes) {
77             // Only test scalar and vector floats. (Matrices can introduce padding between values.)
78             int vecLength = SkSLTypeVecLength(type);
79             if (!SkSLTypeIsFloatType(type) || vecLength < 1) {
80                 continue;
81             }
82 
83             // Write our uniform float scalar/vector.
84             const Uniform expectations[] = {{"uniform", type}};
85             SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
86             mgr.write(expectations[0], kFloats);
87             SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
88 
89             // Read back the uniform data.
90             SkSpan<const char> uniformData = mgr.finish();
91             size_t elementSize = element_size(layout, type);
92             const void* validData = (elementSize == 4) ? (const void*)kFloats : (const void*)kHalfs;
93             REPORTER_ASSERT(r, uniformData.size() >= vecLength * elementSize);
94             REPORTER_ASSERT(r, 0 == memcmp(validData, uniformData.data(), vecLength * elementSize),
95                             "Layout: %s - Type: %s float encoding failed",
96                             LayoutString(layout), SkSLTypeString(type));
97             mgr.reset();
98         }
99     }
100 }
101 
DEF_GRAPHITE_TEST(UniformManagerCheckIntEncoding,r,CtsEnforcement::kApiLevel_V)102 DEF_GRAPHITE_TEST(UniformManagerCheckIntEncoding, r, CtsEnforcement::kApiLevel_V) {
103     // Verify that the uniform manager encodes int data properly.
104     for (Layout layout : kLayouts) {
105         UniformManager mgr(layout);
106 
107         for (SkSLType type : kTypes) {
108             if (!SkSLTypeIsIntegralType(type)) {
109                 continue;
110             }
111 
112             // Write our uniform int scalar/vector.
113             const Uniform expectations[] = {{"uniform", type}};
114             SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
115             mgr.write(expectations[0], kInts);
116             SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
117 
118             // Read back the uniform data.
119             SkSpan<const char> uniformData = mgr.finish();
120             int vecLength = SkSLTypeVecLength(type);
121             size_t elementSize = element_size(layout, type);
122             REPORTER_ASSERT(r, uniformData.size() >= vecLength * elementSize);
123             REPORTER_ASSERT(r, 0 == memcmp(kInts, uniformData.data(), vecLength * elementSize),
124                             "Layout: %s - Type: %s int encoding failed",
125                             LayoutString(layout), SkSLTypeString(type));
126             mgr.reset();
127         }
128     }
129 }
130 
DEF_GRAPHITE_TEST(UniformManagerCheckScalarVectorPacking,r,CtsEnforcement::kApiLevel_V)131 DEF_GRAPHITE_TEST(UniformManagerCheckScalarVectorPacking, r, CtsEnforcement::kApiLevel_V) {
132     // Verify that the uniform manager can pack scalars and vectors of identical type correctly.
133     for (Layout layout : kLayouts) {
134         UniformManager mgr(layout);
135 
136         for (SkSLType type : kTypes) {
137             int vecLength = SkSLTypeVecLength(type);
138             if (vecLength < 1) {
139                 continue;
140             }
141 
142             // Write three matching uniforms.
143             const Uniform expectations[] = {{"a", type}, {"b", type}, {"c", type}};
144             SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
145             mgr.write(expectations[0], kFloats);
146             mgr.write(expectations[1], kFloats);
147             mgr.write(expectations[2], kFloats);
148             SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
149 
150             // Verify the uniform data packing.
151             SkSpan<const char> uniformData = mgr.finish();
152             size_t elementSize = element_size(layout, type);
153             // Vec3s must be laid out as if they were vec4s.
154             size_t effectiveVecLength = (vecLength == 3) ? 4 : vecLength;
155             REPORTER_ASSERT(r, uniformData.size() == elementSize * effectiveVecLength * 3,
156                             "Layout: %s - Type: %s tight packing failed",
157                             LayoutString(layout), SkSLTypeString(type));
158             mgr.reset();
159         }
160     }
161 }
162 
DEF_GRAPHITE_TEST(UniformManagerCheckMatrixPacking,r,CtsEnforcement::kApiLevel_V)163 DEF_GRAPHITE_TEST(UniformManagerCheckMatrixPacking, r, CtsEnforcement::kApiLevel_V) {
164     // Verify that the uniform manager can pack matrices correctly.
165     for (Layout layout : kLayouts) {
166         UniformManager mgr(layout);
167 
168         for (SkSLType type : kTypes) {
169             int matrixSize = SkSLTypeMatrixSize(type);
170             if (matrixSize < 2) {
171                 continue;
172             }
173 
174             // Write three matching uniforms.
175             const Uniform expectations[] = {{"a", type}, {"b", type}, {"c", type}};
176             SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
177             mgr.write(expectations[0], kFloats);
178             mgr.write(expectations[1], kFloats);
179             mgr.write(expectations[2], kFloats);
180             SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
181 
182             // Verify the uniform data packing.
183             SkSpan<const char> uniformData = mgr.finish();
184             size_t elementSize = element_size(layout, type);
185             // In all layouts, mat3s burn 12 elements, not 9. In std140, mat2s burn 8 elements
186             // instead of 4.
187             size_t numElements;
188             if (matrixSize == 3) {
189                 numElements = 12;
190             } else if (matrixSize == 2 && layout == Layout::kStd140) {
191                 numElements = 8;
192             } else {
193                 numElements = matrixSize * matrixSize;
194             }
195             REPORTER_ASSERT(r, uniformData.size() == elementSize * numElements * 3,
196                             "Layout: %s - Type: %s matrix packing failed",
197                             LayoutString(layout), SkSLTypeString(type));
198             mgr.reset();
199         }
200     }
201 }
202 
DEF_GRAPHITE_TEST(UniformManagerCheckPaddingScalarVector,r,CtsEnforcement::kApiLevel_V)203 DEF_GRAPHITE_TEST(UniformManagerCheckPaddingScalarVector, r, CtsEnforcement::kApiLevel_V) {
204     // Verify that the uniform manager properly adds padding between pairs of scalar/vector.
205     for (Layout layout : kLayouts) {
206         UniformManager mgr(layout);
207 
208         for (SkSLType type1 : kTypes) {
209             const int vecLength1 = SkSLTypeVecLength(type1);
210             if (vecLength1 < 1) {
211                 continue;
212             }
213 
214             for (SkSLType type2 : kTypes) {
215                 const int vecLength2 = SkSLTypeVecLength(type2);
216                 if (vecLength2 < 1) {
217                     continue;
218                 }
219 
220                 // Write two scalar/vector uniforms.
221                 const Uniform expectations[] = {{"a", type1}, {"b", type2}};
222                 SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
223                 mgr.write(expectations[0], kFloats);
224                 mgr.write(expectations[1], kFloats);
225                 SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
226 
227                 // The expected packing varies depending on the bit-widths of each element.
228                 const size_t elementSize1 = element_size(layout, type1);
229                 const size_t elementSize2 = element_size(layout, type2);
230                 if (elementSize1 == elementSize2) {
231                     // Elements in the array correspond to the element size (either 16 or 32 bits).
232                     // The expected uniform layout is listed as strings below.
233                     // A/B: uniform values.
234                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
235                     // _  : padding between uniforms for alignment
236                     static constexpr const char* kExpectedLayout[2][5][5] = {
237                         // Metal (vec3 consumes vec4 size)
238                         {{ "", "",         "",         "",         ""         },
239                          { "", "AB",       "A_BB",     "A___BBBb", "A___BBBB" },
240                          { "", "AAB_",     "AABB",     "AA__BBBb", "AA__BBBB" },
241                          { "", "AAAaB___", "AAAaBB__", "AAAaBBBb", "AAAaBBBB" },
242                          { "", "AAAAB___", "AAAABB__", "AAAABBBb", "AAAABBBB" }},
243                         // std140 and std430 (vec3 aligns to vec4, but consumes only 3 elements)
244                         {{ "", "",         "",         "",         ""         },
245                          { "", "AB",       "A_BB",     "A___BBBb", "A___BBBB" },
246                          { "", "AAB_",     "AABB",     "AA__BBBb", "AA__BBBB" },
247                          { "", "AAAB",     "AAA_BB__", "AAA_BBBb", "AAA_BBBB" },
248                          { "", "AAAAB___", "AAAABB__", "AAAABBBb", "AAAABBBB" }},
249                     };
250                     int layoutIdx = static_cast<int>(layout != Layout::kMetal);
251                     const size_t size = strlen(kExpectedLayout[layoutIdx][vecLength1][vecLength2]) *
252                                         elementSize1;
253                     SkSpan<const char> uniformData = mgr.finish();
254                     REPORTER_ASSERT(r, uniformData.size() == size,
255                                     "Layout: %s - Types: %s, %s padding test failed",
256                                     LayoutString(layout),
257                                     SkSLTypeString(type1), SkSLTypeString(type2));
258                 } else if (elementSize1 == 2 && elementSize2 == 4) {
259                     // Elements in the array below correspond to 16 bits apiece.
260                     // The expected uniform layout is listed as strings below.
261                     // A/B: uniform values.
262                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
263                     // _  : padding between uniforms for alignment
264                     static constexpr const char* kExpectedLayout[5][5] = {
265                         { "", "",         "",         "",                 ""         },
266                         { "", "A_BB",     "A___BBBB", "A_______BBBBBBbb", "A_______BBBBBBBB" },
267                         { "", "AABB",     "AA__BBBB", "AA______BBBBBBbb", "AA______BBBBBBBB" },
268                         { "", "AAAaBB__", "AAAaBBBB", "AAAa____BBBBBBbb", "AAAa____BBBBBBBB" },
269                         { "", "AAAABB__", "AAAABBBB", "AAAA____BBBBBBbb", "AAAA____BBBBBBBB" },
270                     };
271                     const size_t size = strlen(kExpectedLayout[vecLength1][vecLength2]) * 2;
272                     SkSpan<const char> uniformData = mgr.finish();
273                     REPORTER_ASSERT(r, uniformData.size() == size,
274                                     "Layout: %s - Types: %s, %s padding test failed",
275                                     LayoutString(layout),
276                                     SkSLTypeString(type1), SkSLTypeString(type2));
277                 } else if (elementSize1 == 4 && elementSize2 == 2) {
278                     // Elements in the array below correspond to 16 bits apiece.
279                     // The expected uniform layout is listed as strings below.
280                     // A/B: uniform values.
281                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
282                     // _  : padding between uniforms for alignment
283                     static constexpr const char* kExpectedLayout[5][5] = {
284                         { "", "", "", "", "" },
285                         { "", "AAB_",     "AABB",     "AA__BBBb", "AA__BBBB" },
286                         { "", "AAAAB___", "AAAABB__", "AAAABBBb", "AAAABBBB" },
287                         { "",
288                           "AAAAAAaaB_______",
289                           "AAAAAAaaBB______",
290                           "AAAAAAaaBBBb____",
291                           "AAAAAAaaBBBB____" },
292                         { "",
293                           "AAAAAAAAB_______",
294                           "AAAAAAAABB______",
295                           "AAAAAAAABBBb____",
296                           "AAAAAAAABBBB____" },
297                     };
298                     const size_t size = strlen(kExpectedLayout[vecLength1][vecLength2]) * 2;
299                     SkSpan<const char> uniformData = mgr.finish();
300                     REPORTER_ASSERT(r, uniformData.size() == size,
301                                     "Layout: %s - Types: %s, %s padding test failed",
302                                     LayoutString(layout),
303                                     SkSLTypeString(type1), SkSLTypeString(type2));
304                 } else {
305                     ERRORF(r, "Unexpected element sizes: %zu %zu", elementSize1, elementSize2);
306                 }
307                 mgr.reset();
308             }
309         }
310     }
311 }
312 
DEF_GRAPHITE_TEST(UniformManagerCheckPaddingVectorMatrix,r,CtsEnforcement::kApiLevel_V)313 DEF_GRAPHITE_TEST(UniformManagerCheckPaddingVectorMatrix, r, CtsEnforcement::kApiLevel_V) {
314     // Verify that the uniform manager properly adds padding between vectors and matrices.
315     for (Layout layout : kLayouts) {
316         UniformManager mgr(layout);
317 
318         for (SkSLType type1 : kTypes) {
319             const int vecLength1 = SkSLTypeVecLength(type1);
320             if (vecLength1 < 1) {
321                 continue;
322             }
323 
324             for (SkSLType type2 : kTypes) {
325                 const int matSize2 = SkSLTypeMatrixSize(type2);
326                 if (matSize2 < 2) {
327                     continue;
328                 }
329 
330                 // Write the scalar/vector and matrix uniforms.
331                 const Uniform expectations[] = {{"a", type1}, {"b", type2}};
332                 SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
333                 mgr.write(expectations[0], kFloats);
334                 mgr.write(expectations[1], kFloats);
335                 SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
336 
337                 // The expected packing varies depending on the bit-widths of each element.
338                 const size_t elementSize1 = element_size(layout, type1);
339                 const size_t elementSize2 = element_size(layout, type2);
340                 if (elementSize1 == elementSize2) {
341                     // Elements in the array correspond to the element size (32 bits).
342                     // The expected uniform layout is listed as strings below.
343                     // A/B: uniform values.
344                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
345                     // _  : padding between uniforms for alignment
346                     static constexpr const char* kExpectedLayout[2][5][5] = {
347                         // std140 layout
348                         {
349                             { "", "", "",             "",                 "" },
350                             { "", "", "A___BBbbBBbb", "A___BBBbBBBbBBBb", "A___BBBBBBBBBBBBBBBB" },
351                             { "", "", "AA__BBbbBBbb", "AA__BBBbBBBbBBBb", "AA__BBBBBBBBBBBBBBBB" },
352                             { "", "", "AAAaBBbbBBbb", "AAAaBBBbBBBbBBBb", "AAAaBBBBBBBBBBBBBBBB" },
353                             { "", "", "AAAABBbbBBbb", "AAAABBBbBBBbBBBb", "AAAABBBBBBBBBBBBBBBB" },
354                         },
355                         // All other layouts
356                         {
357                             { "", "", "",         "",                 "" },
358                             { "", "", "A_BBBB",   "A___BBBbBBBbBBBb", "A___BBBBBBBBBBBBBBBB" },
359                             { "", "", "AABBBB",   "AA__BBBbBBBbBBBb", "AA__BBBBBBBBBBBBBBBB" },
360                             { "", "", "AAAaBBBB", "AAAaBBBbBBBbBBBb", "AAAaBBBBBBBBBBBBBBBB" },
361                             { "", "", "AAAABBBB", "AAAABBBbBBBbBBBb", "AAAABBBBBBBBBBBBBBBB" },
362                         },
363                     };
364                     int layoutIdx = static_cast<int>(layout != Layout::kStd140);
365                     const size_t size = strlen(kExpectedLayout[layoutIdx][vecLength1][matSize2]) *
366                                         elementSize1;
367                     SkSpan<const char> uniformData = mgr.finish();
368                     REPORTER_ASSERT(r, uniformData.size() == size,
369                                     "Layout: %s - Types: %s, %s vector-matrix padding test failed",
370                                     LayoutString(layout),
371                                     SkSLTypeString(type1), SkSLTypeString(type2));
372                 } else if (elementSize1 == 2 && elementSize2 == 4) {
373                     // Elements in the array below correspond to 16 bits apiece.
374                     // The expected uniform layout is listed as strings below.
375                     // A/B: uniform values.
376                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
377                     // _  : padding between uniforms for alignment
378                     static constexpr const char* kExpectedLayout[5][5] = {
379                             {"", "", "", "", ""},
380                             {"", "",
381                              "A___BBBBBBBB",
382                              "A_______BBBBBBbbBBBBBBbbBBBBBBbb",
383                              "A_______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
384                             {"", "",
385                              "AA__BBBBBBBB",
386                              "AA______BBBBBBbbBBBBBBbbBBBBBBbb",
387                              "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
388                             {"", "",
389                              "AAAaBBBBBBBB",
390                              "AAAa____BBBBBBbbBBBBBBbbBBBBBBbb",
391                              "AAAa____BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
392                             {"", "",
393                              "AAAABBBBBBBB",
394                              "AAAA____BBBBBBbbBBBBBBbbBBBBBBbb",
395                              "AAAA____BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
396                     };
397                     const size_t size = strlen(kExpectedLayout[vecLength1][matSize2]) * 2;
398                     SkSpan<const char> uniformData = mgr.finish();
399                     REPORTER_ASSERT(r, uniformData.size() == size,
400                                     "Layout: %s - Types: %s, %s vector-matrix padding test failed",
401                                     LayoutString(layout),
402                                     SkSLTypeString(type1), SkSLTypeString(type2));
403                 } else if (elementSize1 == 4 && elementSize2 == 2) {
404                     // Elements in the array below correspond to 16 bits apiece.
405                     // The expected uniform layout is listed as strings below.
406                     // A/B: uniform values.
407                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
408                     // _  : padding between uniforms for alignment
409                     static constexpr const char* kExpectedLayout[5][5] = {
410                             {"", "", "", "", ""},
411                             {"", "", "AABBBB",   "AA__BBBbBBBbBBBb", "AA__BBBBBBBBBBBBBBBB"},
412                             {"", "", "AAAABBBB", "AAAABBBbBBBbBBBb", "AAAABBBBBBBBBBBBBBBB"},
413                             {"", "",
414                              "AAAAAAaaBBBB____",
415                              "AAAAAAaaBBBbBBBbBBBb____",
416                              "AAAAAAaaBBBBBBBBBBBBBBBB"},
417                             {"", "",
418                              "AAAAAAAABBBB____",
419                              "AAAAAAAABBBbBBBbBBBb____",
420                              "AAAAAAAABBBBBBBBBBBBBBBB"},
421                     };
422                     const size_t size = strlen(kExpectedLayout[vecLength1][matSize2]) * 2;
423                     SkSpan<const char> uniformData = mgr.finish();
424                     REPORTER_ASSERT(r, uniformData.size() == size,
425                                     "Layout: %s - Types: %s, %s vector-matrix padding test failed",
426                                     LayoutString(layout),
427                                     SkSLTypeString(type1), SkSLTypeString(type2));
428                 }
429                 mgr.reset();
430             }
431         }
432     }
433 }
434 
DEF_GRAPHITE_TEST(UniformManagerCheckPaddingMatrixVector,r,CtsEnforcement::kApiLevel_V)435 DEF_GRAPHITE_TEST(UniformManagerCheckPaddingMatrixVector, r, CtsEnforcement::kApiLevel_V) {
436     // Verify that the uniform manager properly adds padding between matrices and vectors.
437     for (Layout layout : kLayouts) {
438         UniformManager mgr(layout);
439 
440         for (SkSLType type1 : kTypes) {
441             const int matSize1 = SkSLTypeMatrixSize(type1);
442             if (matSize1 < 2) {
443                 continue;
444             }
445 
446             for (SkSLType type2 : kTypes) {
447                 const int vecLength2 = SkSLTypeVecLength(type2);
448                 if (vecLength2 < 1) {
449                     continue;
450                 }
451 
452                 // Write the scalar/vector and matrix uniforms.
453                 const Uniform expectations[] = {{"a", type1}, {"b", type2}};
454                 SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
455                 mgr.write(expectations[0], kFloats);
456                 mgr.write(expectations[1], kFloats);
457                 SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
458 
459                 // The expected packing varies depending on the bit-widths of each element.
460                 const size_t elementSize1 = element_size(layout, type1);
461                 const size_t elementSize2 = element_size(layout, type2);
462                 if (elementSize1 == elementSize2) {
463                     // Elements in the array correspond to the element size (32 bits).
464                     // The expected uniform layout is listed as strings below.
465                     // A/B: uniform values.
466                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
467                     // _  : padding between uniforms for alignment
468                     static constexpr const char* kExpectedLayout[2][5][5] = {
469                         // std140 layout
470                         {
471                             { "", "", "", "", "" },
472                             { "", "", "", "", "" },
473                             { "", "AAaaAAaaB___", "AAaaAAaaBB__", "AAaaAAaaBBBb", "AAaaAAaaBBBB" },
474                             { "",
475                               "AAAaAAAaAAAaB___",
476                               "AAAaAAAaAAAaBB__",
477                               "AAAaAAAaAAAaBBBb",
478                               "AAAaAAAaAAAaBBBB" },
479                             { "",
480                               "AAAAAAAAAAAAAAAAB___",
481                               "AAAAAAAAAAAAAAAABB__",
482                               "AAAAAAAAAAAAAAAABBBb",
483                               "AAAAAAAAAAAAAAAABBBB" },
484                         },
485                         // All other layouts
486                         {
487                             { "", "", "", "", "" },
488                             { "", "", "", "", "" },
489                             { "", "AAAAB_", "AAAABB", "AAAABBBb", "AAAABBBB" },
490                             { "",
491                               "AAAaAAAaAAAaB___",
492                               "AAAaAAAaAAAaBB__",
493                               "AAAaAAAaAAAaBBBb",
494                               "AAAaAAAaAAAaBBBB" },
495                             { "",
496                               "AAAAAAAAAAAAAAAAB___",
497                               "AAAAAAAAAAAAAAAABB__",
498                               "AAAAAAAAAAAAAAAABBBb",
499                               "AAAAAAAAAAAAAAAABBBB" },
500                         },
501                     };
502                     int layoutIdx = static_cast<int>(layout != Layout::kStd140);
503                     const size_t size = strlen(kExpectedLayout[layoutIdx][matSize1][vecLength2]) *
504                                         elementSize1;
505                     SkSpan<const char> uniformData = mgr.finish();
506                     REPORTER_ASSERT(r, uniformData.size() == size,
507                                     "Layout: %s - Types: %s, %s matrix-vector padding test failed",
508                                     LayoutString(layout),
509                                     SkSLTypeString(type1), SkSLTypeString(type2));
510                 } else if (elementSize1 == 2 && elementSize2 == 4) {
511                     // Elements in the array below correspond to 16 bits apiece.
512                     // The expected uniform layout is listed as strings below.
513                     // A/B: uniform values.
514                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
515                     // _  : padding between uniforms for alignment
516                     static constexpr const char* kExpectedLayout[5][5] = {
517                         { "", "", "", "", "" },
518                         { "", "", "", "", "" },
519                         { "", "AAAABB", "AAAABBBB", "AAAA____BBBBBBbb", "AAAA____BBBBBBBB" },
520                         { "",
521                           "AAAaAAAaAAAaBB__",
522                           "AAAaAAAaAAAaBBBB",
523                           "AAAaAAAaAAAa____BBBBBBbb",
524                           "AAAaAAAaAAAa____BBBBBBBB" },
525                         { "",
526                           "AAAAAAAAAAAAAAAABB__",
527                           "AAAAAAAAAAAAAAAABBBB",
528                           "AAAAAAAAAAAAAAAABBBBBBbb",
529                           "AAAAAAAAAAAAAAAABBBBBBBB" },
530                     };
531                     const size_t size = strlen(kExpectedLayout[matSize1][vecLength2]) * 2;
532                     SkSpan<const char> uniformData = mgr.finish();
533                     REPORTER_ASSERT(r, uniformData.size() == size,
534                                     "Layout: %s - Types: %s, %s matrix-vector padding test failed",
535                                     LayoutString(layout),
536                                     SkSLTypeString(type1), SkSLTypeString(type2));
537                 } else if (elementSize1 == 4 && elementSize2 == 2) {
538                     // Elements in the array below correspond to 16 bits apiece.
539                     // The expected uniform layout is listed as strings below.
540                     // A/B: uniform values.
541                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
542                     // _  : padding between uniforms for alignment
543                     static constexpr const char* kExpectedLayout[5][5] = {
544                         { "", "", "", "", "" },
545                         { "", "", "", "", "" },
546                         { "", "AAAAAAAAB___", "AAAAAAAABB__", "AAAAAAAABBBb", "AAAAAAAABBBB" },
547                         { "",
548                           "AAAAAAaaAAAAAAaaAAAAAAaaB_______",
549                           "AAAAAAaaAAAAAAaaAAAAAAaaBB______",
550                           "AAAAAAaaAAAAAAaaAAAAAAaaBBBb____",
551                           "AAAAAAaaAAAAAAaaAAAAAAaaBBBB____" },
552                         { "",
553                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_______",
554                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB______",
555                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBb____",
556                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB____" },
557                     };
558                     const size_t size = strlen(kExpectedLayout[matSize1][vecLength2]) * 2;
559                     SkSpan<const char> uniformData = mgr.finish();
560                     REPORTER_ASSERT(r, uniformData.size() == size,
561                                     "Layout: %s - Types: %s, %s matrix-vector padding test failed",
562                                     LayoutString(layout),
563                                     SkSLTypeString(type1), SkSLTypeString(type2));
564                 }
565                 mgr.reset();
566             }
567         }
568     }
569 }
570 
DEF_GRAPHITE_TEST(UniformManagerMetalArrayLayout,r,CtsEnforcement::kApiLevel_V)571 DEF_GRAPHITE_TEST(UniformManagerMetalArrayLayout, r, CtsEnforcement::kApiLevel_V) {
572     UniformManager mgr(Layout::kMetal);
573 
574     // Tests set up a uniform block with a single half (to force alignment) and an array of 3
575     // elements. Test every type that can appear in an array.
576     constexpr size_t kArraySize = 3;
577 
578     // Buffer large enough to hold a float4x4[3] array.
579     static constexpr uint8_t kBuffer[192] = {};
580     static const char* kExpectedLayout[] = {
581         // Each letter (A/B/a/b) corresponds to a single byte.
582         // The expected uniform layout is listed as strings below.
583         // A/B: uniform values.
584         // a/b: padding as part of the uniform type.
585         // _  : padding between uniforms for alignment.
586 
587         /* {half, float[3]}  */  "AA__BBBBBBBBBBBB",
588         /* {half, float2[3]} */  "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
589         /* {half, float3[3]} */  "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
590         /* {half, float4[3]} */  "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
591         /* {half, half[3]}   */  "AABBBBBB",
592         /* {half, half2[3]}  */  "AA__BBBBBBBBBBBB",
593         /* {half, half3[3]}  */  "AA______BBBBBBbbBBBBBBbbBBBBBBbb",
594         /* {half, half4[3]}  */  "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
595         /* {half, int[3]}    */  "AA__BBBBBBBBBBBB",
596         /* {half, int2[3]}   */  "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
597         /* {half, int3[3]}   */  "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
598         /* {half, int4[3]}   */  "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
599 
600         /* {half, float2x2[3] */ "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
601         /* {half, float3x3[3] */ "AA______________"
602                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
603                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
604                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
605         /* {half, float4x4[3] */ "AA______________"
606                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
607                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
608                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
609 
610         /* {half, half2x2[3] */  "AA__BBBBBBBBBBBBBBBBBBBBBBBB",
611         /* {half, half3x3[3] */  "AA______"
612                                  "BBBBBBbbBBBBBBbbBBBBBBbb"
613                                  "BBBBBBbbBBBBBBbbBBBBBBbb"
614                                  "BBBBBBbbBBBBBBbbBBBBBBbb",
615         /* {half, half4x4[3] */  "AA______"
616                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
617                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
618                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
619     };
620     for (size_t i = 0; i < std::size(kExpectedLayout); i++) {
621         const SkSLType arrayType = kTypes[i];
622         const Uniform expectations[] = {{"a", SkSLType::kHalf}, {"b", arrayType, kArraySize}};
623 
624         SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
625         mgr.write(expectations[0], kHalfs);
626         mgr.write(expectations[1], kBuffer);
627         SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
628 
629         const size_t expectedSize = strlen(kExpectedLayout[i]);
630         SkSpan<const char> uniformData = mgr.finish();
631         REPORTER_ASSERT(r, uniformData.size() == expectedSize,
632                         "array test %d for type %s failed - expected size: %zu, actual size: %zu",
633                         (int)i, SkSLTypeString(arrayType), expectedSize, uniformData.size());
634 
635         mgr.reset();
636     }
637 }
638 
DEF_GRAPHITE_TEST(UniformManagerStd430ArrayLayout,r,CtsEnforcement::kApiLevel_V)639 DEF_GRAPHITE_TEST(UniformManagerStd430ArrayLayout, r, CtsEnforcement::kApiLevel_V) {
640     UniformManager mgr(Layout::kStd430);
641 
642     // Tests set up a uniform block with a single half (to force alignment) and an array of 3
643     // elements. Test every type that can appear in an array.
644     constexpr size_t kArraySize = 3;
645 
646     // Buffer large enough to hold a float4x4[3] array.
647     static constexpr uint8_t kBuffer[192] = {};
648     static const char* kExpectedLayout[] = {
649         // Each letter (A/B/a/b) corresponds to a single byte.
650         // The expected uniform layout is listed as strings below.
651         // A/B: uniform values.
652         // a/b: padding as part of the uniform type.
653         // _  : padding between uniforms for alignment.
654 
655         /* {half, float[3]}  */  "AA__BBBBBBBBBBBB",
656         /* {half, float2[3]} */  "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
657         /* {half, float3[3]} */  "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
658         /* {half, float4[3]} */  "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
659         /* {half, half[3]}   */  "AA__BBBBBBBBBBBB",
660         /* {half, half2[3]}  */  "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
661         /* {half, half3[3]}  */  "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
662         /* {half, half4[3]}  */  "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
663         /* {half, int[3]}    */  "AA__BBBBBBBBBBBB",
664         /* {half, int2[3]}   */  "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
665         /* {half, int3[3]}   */  "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
666         /* {half, int4[3]}   */  "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
667 
668         /* {half, float2x2[3] */ "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
669         /* {half, float3x3[3] */ "AA______________"
670                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
671                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
672                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
673         /* {half, float4x4[3] */ "AA______________"
674                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
675                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
676                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
677 
678         /* {half, half2x2[3]  */ "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
679         /* {half, half3x3[3]  */ "AA______________"
680                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
681                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
682                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
683         /* {half, half4x4[3]  */ "AA______________"
684                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
685                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
686                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
687     };
688     for (size_t i = 0; i < std::size(kExpectedLayout); i++) {
689         const SkSLType arrayType = kTypes[i];
690         const Uniform expectations[] = {{"a", SkSLType::kHalf}, {"b", arrayType, kArraySize}};
691 
692         SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
693         mgr.write(expectations[0], kHalfs);
694         mgr.write(expectations[1], kBuffer);
695         SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
696 
697         const size_t expectedSize = strlen(kExpectedLayout[i]);
698         SkSpan<const char> uniformData = mgr.finish();
699         REPORTER_ASSERT(r, uniformData.size() == expectedSize,
700                         "array test %d for type %s failed - expected size: %zu, actual size: %zu",
701                         (int)i, SkSLTypeString(arrayType), expectedSize, uniformData.size());
702 
703         mgr.reset();
704     }
705 }
706 
DEF_GRAPHITE_TEST(UniformManagerStd140ArrayLayout,r,CtsEnforcement::kApiLevel_V)707 DEF_GRAPHITE_TEST(UniformManagerStd140ArrayLayout, r, CtsEnforcement::kApiLevel_V) {
708     UniformManager mgr(Layout::kStd140);
709 
710     // Tests set up a uniform block with a single half (to force alignment) and an array of 3
711     // elements. Test every type that can appear in an array.
712     constexpr size_t kArraySize = 3;
713 
714     // Buffer large enough to hold a float4x4[3] array.
715     static constexpr uint8_t kBuffer[192] = {};
716     static const char* kExpectedLayout[] = {
717         // Each letter (A/B/a/b) corresponds to a single byte.
718         // The expected uniform layout is listed as strings below.
719         // A/B: uniform values.
720         // a/b: padding as part of the uniform type.
721         // _  : padding between uniforms for alignment.
722 
723         /* {half, float[3]}  */  "AA______________BBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbb",
724         /* {half, float2[3]} */  "AA______________BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
725         /* {half, float3[3]} */  "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
726         /* {half, float4[3]} */  "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
727         /* {half, half[3]}   */  "AA______________BBbbbbbbbbbbbbbbBBbbbbbbbbbbbbbbBBbbbbbbbbbbbbbb",
728         /* {half, half2[3]}  */  "AA______________BBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbb",
729         /* {half, half3[3]}  */  "AA______________BBBBBBbbbbbbbbbbBBBBBBbbbbbbbbbbBBBBBBbbbbbbbbbb",
730         /* {half, half4[3]}  */  "AA______________BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
731         /* {half, int[3]}    */  "AA______________BBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbb",
732         /* {half, int2[3]}   */  "AA______________BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
733         /* {half, int3[3]}   */  "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
734         /* {half, int4[3]}   */  "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
735 
736         /* {half, float2x2[3] */ "AA______________"
737                                  "BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb"
738                                  "BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb"
739                                  "BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
740         /* {half, float3x3[3] */ "AA______________"
741                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
742                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
743                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
744         /* {half, float4x4[3] */ "AA______________"
745                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
746                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
747                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
748 
749         /* {half, half2x2[3]  */ "AA______________"
750                                  "BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb"
751                                  "BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb"
752                                  "BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
753         /* {half, half3x3[3]  */ "AA______________"
754                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
755                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
756                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
757         /* {half, half4x4[3]  */ "AA______________"
758                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
759                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
760                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
761     };
762     for (size_t i = 0; i < std::size(kExpectedLayout); i++) {
763         const SkSLType arrayType = kTypes[i];
764         const Uniform expectations[] = {{"a", SkSLType::kHalf}, {"b", arrayType, kArraySize}};
765 
766         SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
767         mgr.write(expectations[0], kHalfs);
768         mgr.write(expectations[1], kBuffer);
769         SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
770 
771         const size_t expectedSize = strlen(kExpectedLayout[i]);
772         SkSpan<const char> uniformData = mgr.finish();
773         REPORTER_ASSERT(r, uniformData.size() == expectedSize,
774                         "array test %d for type %s failed - expected size: %zu, actual size: %zu",
775                         (int)i, SkSLTypeString(arrayType), expectedSize, uniformData.size());
776 
777         mgr.reset();
778     }
779 }
780 
781 // This test validates that the uniform data for matrix types get written out according to the
782 // layout expectations.
DEF_GRAPHITE_TEST(UniformManagerStd140MatrixLayoutContents,r,CtsEnforcement::kApiLevel_V)783 DEF_GRAPHITE_TEST(UniformManagerStd140MatrixLayoutContents, r, CtsEnforcement::kApiLevel_V) {
784     UniformManager mgr(Layout::kStd140);
785 
786     // float2x2, half2x2
787     for (SkSLType type : {SkSLType::kFloat2x2, SkSLType::kHalf2x2}) {
788         const Uniform expectations[] = {{"m", type}};
789         SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
790         mgr.write(expectations[0], kFloats);
791         SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
792         SkSpan<const char> uniformData = mgr.finish();
793         REPORTER_ASSERT(r, uniformData.size() == 32,
794                         "%s layout size expected 32, got %zu",
795                         SkSLTypeString(type), uniformData.size());
796 
797         // The expected offsets of the 4 matrix elements.
798         const int kOffsets[4] = {0, 1, 4, 5};
799         const float* elements = reinterpret_cast<const float*>(uniformData.data());
800         for (size_t i = 0u; i < std::size(kOffsets); ++i) {
801             float expected = kFloats[i];
802             float el = elements[kOffsets[i]];
803             REPORTER_ASSERT(r, el == expected,
804                             "Incorrect %s element %zu - expected %f, got %f",
805                             SkSLTypeString(type), i, expected, el);
806         }
807         mgr.reset();
808     }
809 
810     // float3x3, half3x3
811     for (SkSLType type : {SkSLType::kFloat3x3, SkSLType::kHalf3x3}) {
812         const Uniform expectations[] = {{"m", type}};
813         SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
814         mgr.write(expectations[0], kFloats);
815         SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
816         SkSpan<const char> uniformData = mgr.finish();
817         REPORTER_ASSERT(r, uniformData.size() == 48,
818                         "%s layout size expected 48, got %zu",
819                         SkSLTypeString(type), uniformData.size());
820 
821         // The expected offsets of the 9 matrix elements.
822         const int kOffsets[9] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
823         const float* elements = reinterpret_cast<const float*>(uniformData.data());
824         for (size_t i = 0u; i < std::size(kOffsets); ++i) {
825             float expected = kFloats[i];
826             float el = elements[kOffsets[i]];
827             REPORTER_ASSERT(r, el == expected,
828                             "Incorrect %s element %zu - expected %f, got %f",
829                             SkSLTypeString(type), i, expected, el);
830         }
831         mgr.reset();
832     }
833 }
834 
835 // This test validates that the uniform data for matrix types get written out according to the
836 // layout expectations.
DEF_GRAPHITE_TEST(UniformManagerStd430MatrixLayoutContents,r,CtsEnforcement::kApiLevel_V)837 DEF_GRAPHITE_TEST(UniformManagerStd430MatrixLayoutContents, r, CtsEnforcement::kApiLevel_V) {
838     UniformManager mgr(Layout::kStd430);
839 
840     // float2x2, half2x2
841     for (SkSLType type : {SkSLType::kFloat2x2, SkSLType::kHalf2x2}) {
842         const Uniform expectations[] = {{"m", type}};
843         SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
844         mgr.write(expectations[0], kFloats);
845         SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
846         SkSpan<const char> uniformData = mgr.finish();
847         REPORTER_ASSERT(r, uniformData.size() == 16,
848                         "%s layout size expected 16, got %zu",
849                         SkSLTypeString(type), uniformData.size());
850 
851         // The expected offsets of the 4 matrix elements. This uses a tighter packing than std140
852         // layout.
853         const int kOffsets[4] = {0, 1, 2, 3};
854         const float* elements = reinterpret_cast<const float*>(uniformData.data());
855         for (size_t i = 0u; i < std::size(kOffsets); ++i) {
856             float expected = kFloats[i];
857             float el = elements[kOffsets[i]];
858             REPORTER_ASSERT(r, el == expected,
859                             "Incorrect %s element %zu - expected %f, got %f",
860                             SkSLTypeString(type), i, expected, el);
861         }
862         mgr.reset();
863     }
864 
865     // float3x3, half3x3
866     for (SkSLType type : {SkSLType::kFloat3x3, SkSLType::kHalf3x3}) {
867         const Uniform expectations[] = {{"m", type}};
868         SkDEBUGCODE(mgr.setExpectedUniforms(SkSpan(expectations), /*isSubstruct=*/false);)
869         mgr.write(expectations[0], kFloats);
870         SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
871         SkSpan<const char> uniformData = mgr.finish();
872         REPORTER_ASSERT(r, uniformData.size() == 48,
873                         "%s layout size expected 48, got %zu",
874                         SkSLTypeString(type), uniformData.size());
875 
876         // The expected offsets of the 9 matrix elements. This is the same as std140 layout.
877         const int kOffsets[9] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
878         const float* elements = reinterpret_cast<const float*>(uniformData.data());
879         for (size_t i = 0u; i < std::size(kOffsets); ++i) {
880             float expected = kFloats[i];
881             float el = elements[kOffsets[i]];
882             REPORTER_ASSERT(r, el == expected,
883                             "Incorrect %s element %zu - expected %f, got %f",
884                             SkSLTypeString(type), i, expected, el);
885         }
886         mgr.reset();
887     }
888 }
889 
890 // These tests validate that substructs are written and aligned appropriately.
DEF_GRAPHITE_TEST(UniformManagerStructLayout,r,CtsEnforcement::kNextRelease)891 DEF_GRAPHITE_TEST(UniformManagerStructLayout, r, CtsEnforcement::kNextRelease) {
892     static constexpr uint32_t _ = 0; // 0s will only be written as padding
893     static const struct TestCase {
894         // For convenience, these should only have kFloat[2,3,4] as their types. However the values
895         // written are integers and will be bit-punned to floats so that expectations are easy to
896         // define (UniformManager and Skia have no defined kInt3 object type). Written integers
897         // start at 1 and are incremented with each component across uniforms.
898         std::vector<Uniform> fPreStruct;  // before beginStruct(), top-level fields or struct
899         std::vector<Uniform> fSubstruct;  // within beginStruct()/endStruct()
900         std::vector<Uniform> fPostStruct; // after endStruct(), top-level fields
901 
902         std::pair<int, std::vector<uint32_t>> fExpectedAlignmentAndData[std::size(kLayouts)];
903 
904         // If non-empty, holds base alignments for fPreStruct base alignment as a struct
905         std::vector<int> fPreStructAlignments = {};
906     } kCases[] = {
907         // Struct tests with no preceeding or following top-level fields
908         {/*prestruct=*/ {},
909          /*substruct=*/ {{"u1", SkSLType::kFloat},
910                          {"u2", SkSLType::kFloat},
911                          {"u3", SkSLType::kFloat},
912                          {"u4", SkSLType::kFloat}},
913          /*poststruct=*/{},
914          /*expect=*/{
915             /*std140=*/{/*baseAlign=*/16, /*data=*/{1, 2, 3, 4}},
916             /*std430=*/{/*baseAlign=*/4,  /*data=*/{1, 2, 3, 4}},
917             /*metal=*/ {/*baseAlign=*/4,  /*data=*/{1, 2, 3, 4}}
918          }},
919 
920         {/*prestruct=*/ {},
921          /*substruct=*/ {{"u1", SkSLType::kFloat3},
922                          {"u2", SkSLType::kFloat}},
923          /*poststruct=*/{},
924          /*expect=*/{
925             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,2,3, 4}},
926             /*std430=*/{/*baseAlign=*/16, /*data=*/{1,2,3, 4}},
927             /*metal=*/ {/*baseAlign=*/16, /*data=*/{1,2,3,_, 4,_,_,_}}
928          }},
929 
930         {/*prestruct=*/ {},
931          /*substruct=*/ {{"u1", SkSLType::kFloat2},
932                          {"u2", SkSLType::kFloat},
933                          {"u3", SkSLType::kFloat},
934                          {"u4", SkSLType::kFloat}},
935          /*poststruct=*/{},
936          /*expect=*/{
937             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,2, 3, 4, 5,_,_,_}},
938             /*std430=*/{/*baseAlign=*/8,  /*data=*/{1,2, 3, 4, 5,_}},
939             /*metal=*/ {/*baseAlign=*/8,  /*data=*/{1,2, 3, 4, 5,_}}
940          }},
941 
942         {/*prestruct=*/ {},
943          /*substruct=*/ {{"u1", SkSLType::kFloat},
944                          {"u2", SkSLType::kFloat4},
945                          {"u3", SkSLType::kFloat2},
946                          {"u4", SkSLType::kFloat3}},
947          /*poststruct=*/{},
948          /*expect=*/{
949             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4,5, 6,7,_,_, 8,9,10,_}},
950             /*std430=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4,5, 6,7,_,_, 8,9,10,_}},
951             /*metal=*/ {/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4,5, 6,7,_,_, 8,9,10,_}}
952          }},
953 
954 
955         // Struct tests with a preceeding float to require padding to the struct's base alignment
956         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
957          /*substruct=*/ {{"u1", SkSLType::kFloat},
958                          {"u2", SkSLType::kFloat},
959                          {"u3", SkSLType::kFloat},
960                          {"u4", SkSLType::kFloat}},
961          /*poststruct=*/{},
962          /*expect=*/{
963             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2, 3, 4, 5}},
964             /*std430=*/{/*baseAlign=*/4,  /*data=*/{1, 2, 3, 4, 5}},
965             /*metal=*/ {/*baseAlign=*/4,  /*data=*/{1, 2, 3, 4, 5}}
966          }},
967 
968         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
969          /*substruct=*/ {{"u1", SkSLType::kFloat3},
970                          {"u2", SkSLType::kFloat}},
971          /*poststruct=*/{},
972          /*expect=*/{
973             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4, 5}},
974             /*std430=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4, 5}},
975             /*metal=*/ {/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4,_, 5,_,_,_}}
976          }},
977 
978         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
979          /*substruct=*/ {{"u1", SkSLType::kFloat2},
980                          {"u2", SkSLType::kFloat},
981                          {"u3", SkSLType::kFloat},
982                          {"u4", SkSLType::kFloat}},
983          /*poststruct=*/{},
984          /*expect=*/{
985             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3, 4, 5, 6,_,_,_}},
986             /*std430=*/{/*baseAlign=*/8,  /*data=*/{1,_, 2,3, 4, 5, 6,_}},
987             /*metal=*/ {/*baseAlign=*/8,  /*data=*/{1,_, 2,3, 4, 5, 6,_}}
988          }},
989 
990         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
991          /*substruct=*/ {{"u1", SkSLType::kFloat},
992                          {"u2", SkSLType::kFloat4},
993                          {"u3", SkSLType::kFloat2},
994                          {"u4", SkSLType::kFloat3}},
995          /*poststruct=*/{},
996          /*expect=*/{
997             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,_,_,_, 3,4,5,6, 7,8,_,_, 9,10,11,_}},
998             /*std430=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,_,_,_, 3,4,5,6, 7,8,_,_, 9,10,11,_}},
999             /*metal=*/ {/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,_,_,_, 3,4,5,6, 7,8,_,_, 9,10,11,_}}
1000          }},
1001 
1002         // Struct tests with a preceeding float to require padding to the struct's base alignment,
1003         // and a following float4 to test alignment after a struct.
1004         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
1005          /*substruct=*/ {{"u1", SkSLType::kFloat},
1006                          {"u2", SkSLType::kFloat},
1007                          {"u3", SkSLType::kFloat},
1008                          {"u4", SkSLType::kFloat}},
1009          /*poststruct=*/{{"p2", SkSLType::kFloat4}},
1010          /*expect=*/{
1011             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2, 3, 4, 5, 6,7,8,9}},
1012             /*std430=*/{/*baseAlign=*/4,  /*data=*/{1, 2, 3, 4, 5, _,_,_,6,7,8,9}},
1013             /*metal=*/ {/*baseAlign=*/4,  /*data=*/{1, 2, 3, 4, 5, _,_,_,6,7,8,9}}
1014          }},
1015 
1016         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
1017          /*substruct=*/ {{"u1", SkSLType::kFloat3},
1018                          {"u2", SkSLType::kFloat}},
1019          /*poststruct=*/{{"p2", SkSLType::kFloat4}},
1020          /*expect=*/{
1021             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4, 5, 6,7,8,9}},
1022             /*std430=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4, 5, 6,7,8,9}},
1023             /*metal=*/ {/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3,4,_, 5,_,_,_, 6,7,8,9}}
1024          }},
1025 
1026         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
1027          /*substruct=*/ {{"u1", SkSLType::kFloat2},
1028                          {"u2", SkSLType::kFloat},
1029                          {"u3", SkSLType::kFloat},
1030                          {"u4", SkSLType::kFloat}},
1031          /*poststruct=*/{{"p2", SkSLType::kFloat4}},
1032          /*expect=*/{
1033             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,3, 4, 5, 6,_,_,_, 7,8,9,10}},
1034             /*std430=*/{/*baseAlign=*/8,  /*data=*/{1,_, 2,3, 4, 5, 6,_, 7,8,9,10}},
1035             /*metal=*/ {/*baseAlign=*/8,  /*data=*/{1,_, 2,3, 4, 5, 6,_, 7,8,9,10}}
1036          }},
1037 
1038         {/*prestruct=*/ {{"p1", SkSLType::kFloat}},
1039          /*substruct=*/ {{"u1", SkSLType::kFloat},
1040                          {"u2", SkSLType::kFloat4},
1041                          {"u3", SkSLType::kFloat2},
1042                          {"u4", SkSLType::kFloat3}},
1043          /*poststruct=*/{{"p2", SkSLType::kFloat4}},
1044          /*expect=*/{
1045             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,_,_,_, 3,4,5,6, 7,8,_,_, 9,10,11,_, 12,13,14,15}},
1046             /*std430=*/{/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,_,_,_, 3,4,5,6, 7,8,_,_, 9,10,11,_, 12,13,14,15}},
1047             /*metal=*/ {/*baseAlign=*/16, /*data=*/{1,_,_,_, 2,_,_,_, 3,4,5,6, 7,8,_,_, 9,10,11,_, 12,13,14,15}}
1048          }},
1049 
1050         // Struct tests with two adjacent structs
1051         {/*prestruct=*/ {{"p1", SkSLType::kFloat2},
1052                          {"p2", SkSLType::kFloat}},
1053          /*substruct=*/ {{"u1", SkSLType::kFloat},
1054                          {"u2", SkSLType::kFloat}},
1055          /*poststruct=*/{},
1056          /*expect=*/{
1057             /*std140=*/{/*baseAlign=*/16, /*data=*/{1,2, 3,_, 4, 5,_,_}},
1058             /*std430=*/{/*baseAlign=*/4,  /*data=*/{1,2, 3,_, 4, 5}},
1059             /*metal=*/ {/*baseAlign=*/4,  /*data=*/{1,2, 3,_, 4, 5}}
1060          },
1061          /*preStructAlignments=*/{
1062             /*std140=*/16,
1063             /*std430=*/8,
1064             /*metal=*/ 8
1065          }}
1066     };
1067 
1068     auto writeFields = [](UniformManager* mgr, SkSpan<const Uniform> fields, uint32_t baseValue) {
1069         for (const Uniform& f : fields) {
1070             switch(f.type()) {
1071                 case SkSLType::kFloat:
1072                     mgr->write(SkBits2Float(baseValue++));
1073                     break;
1074                 case SkSLType::kFloat2:
1075                     mgr->write(SkV2{SkBits2Float(baseValue++),
1076                                     SkBits2Float(baseValue++)});
1077                     break;
1078                 case SkSLType::kFloat3:
1079                     mgr->write(SkV3{SkBits2Float(baseValue++),
1080                                     SkBits2Float(baseValue++),
1081                                     SkBits2Float(baseValue++)});
1082                     break;
1083                 case SkSLType::kFloat4:
1084                     mgr->write(SkV4{SkBits2Float(baseValue++),
1085                                     SkBits2Float(baseValue++),
1086                                     SkBits2Float(baseValue++),
1087                                     SkBits2Float(baseValue++)});
1088                     break;
1089                 default:
1090                     SkUNREACHABLE;
1091             }
1092         }
1093         return baseValue;
1094     };
1095 
1096     bool dataMatchFailureLogged = false;
1097     for (size_t l = 0; l < std::size(kLayouts); ++l) {
1098         const Layout layout = kLayouts[l];
1099         skiatest::ReporterContext layoutLabel(r, LayoutString(layout));
1100 
1101         for (size_t t = 0; t < std::size(kCases); ++t) {
1102             const TestCase& test = kCases[t];
1103             skiatest::ReporterContext testLabel(r, std::to_string(t));
1104 
1105             auto [baseAlignment, expectedData] = test.fExpectedAlignmentAndData[l];
1106 
1107             UniformManager mgr{layout};
1108             int baseValue = 1;
1109             if (!test.fPreStruct.empty()) {
1110                 // pre-struct fields
1111                 const bool preStructIsStruct = !test.fPreStructAlignments.empty();
1112                 SkDEBUGCODE(mgr.setExpectedUniforms(test.fPreStruct, preStructIsStruct);)
1113                 if (preStructIsStruct) {
1114                     mgr.beginStruct(test.fPreStructAlignments[l]);
1115                 }
1116                 baseValue = writeFields(&mgr, test.fPreStruct, baseValue);
1117                 if (preStructIsStruct) {
1118                     mgr.endStruct();
1119                 }
1120                 SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
1121             }
1122             if (!test.fSubstruct.empty()) {
1123                 // substruct fields
1124                 SkDEBUGCODE(mgr.setExpectedUniforms(test.fSubstruct, /*isSubstruct=*/true);)
1125                 mgr.beginStruct(baseAlignment);
1126                 baseValue = writeFields(&mgr, test.fSubstruct, baseValue);
1127                 mgr.endStruct();
1128                 SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
1129             }
1130             if (!test.fPostStruct.empty()) {
1131                 // post-struct fields
1132                 SkDEBUGCODE(mgr.setExpectedUniforms(test.fPostStruct, /*isSubstruct=*/false);)
1133                 baseValue = writeFields(&mgr, test.fPostStruct, baseValue);
1134                 SkDEBUGCODE(mgr.doneWithExpectedUniforms();)
1135             }
1136 
1137             SkSpan<const char> data = mgr.finish();
1138 
1139             bool sizeMatch = data.size() == sizeof(uint32_t)*expectedData.size();
1140             // To reduce logging/asserts, pretend contents "match" if the sizes differ since that
1141             // will already be triggering test failures
1142             bool contentsMatch = !sizeMatch ||
1143                                  memcmp(data.data(), expectedData.data(), data.size()) == 0;
1144             REPORTER_ASSERT(r, sizeMatch, "Size mismatch between written (%zu) and expected (%zu)",
1145                             data.size(), expectedData.size());
1146             REPORTER_ASSERT(r, contentsMatch, "Contents differ between written and expected");
1147 
1148             if (!contentsMatch && !dataMatchFailureLogged) {
1149                 // Print out actual and expected values once if it's only the contents that are
1150                 // incorrect (don't bother printing contents if their lengths differ).
1151                 SkDebugf("Expected contents:\n");
1152                 for (size_t i = 0; i < expectedData.size(); ++i) {
1153                     SkDebugf("%s%u", i % 4 == 0 ? " " : ",", expectedData[i]);
1154                 }
1155                 SkDebugf("\nActual contents:\n");
1156                 SkASSERT(data.size() % 4 == 0);
1157                 const uint32_t* actualData = reinterpret_cast<const uint32_t*>(data.begin());
1158                 for (size_t i = 0; i < expectedData.size(); ++i) {
1159                     SkDebugf("%s%u", i % 4 == 0 ? " " : ",", actualData[i]);
1160                 }
1161                 SkDebugf("\n\n");
1162                 dataMatchFailureLogged = true;
1163             }
1164         }
1165     }
1166 }
1167