• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkHalf.h"
9 #include "src/core/SkSLTypeShared.h"
10 #include "src/gpu/graphite/PipelineData.h"
11 #include "src/gpu/graphite/Uniform.h"
12 #include "src/gpu/graphite/UniformManager.h"
13 #include "tests/Test.h"
14 
15 using namespace skgpu::graphite;
16 
17 static constexpr Layout kLayouts[] = {
18         Layout::kStd140,
19         Layout::kStd430,
20         Layout::kMetal,
21 };
22 
23 // This list excludes SkSLTypes that we don't support in uniforms, like Bool, UInt or UShort.
24 static constexpr SkSLType kTypes[] = {
25         SkSLType::kShort,    SkSLType::kShort2,   SkSLType::kShort3,   SkSLType::kShort4,   //
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 int16_t kShorts[16] = { 1,  -2,  3,  -4,
44                                          5,  -6,  7,  -8,
45                                          9, -10, 11, -12,
46                                         13, -14, 15, -16 };
47 
48 static constexpr int32_t kInts[16] = { 1,  -2,  3,  -4,
49                                        5,  -6,  7,  -8,
50                                        9, -10, 11, -12,
51                                       13, -14, 15, -16 };
52 
element_size(Layout layout,SkSLType type)53 static size_t element_size(Layout layout, SkSLType type) {
54     // Metal should encode half-precision uniforms in 16 bits.
55     // Other layouts should always encode uniforms in 32 bit.
56     return (layout == Layout::kMetal && !SkSLTypeIsFullPrecisionNumericType(type)) ? 2 : 4;
57 }
58 
DEF_TEST(UniformManagerCheckSingleUniform,r)59 DEF_TEST(UniformManagerCheckSingleUniform, r) {
60     // Verify that the uniform manager can hold all the basic uniform types, in every layout.
61     for (Layout layout : kLayouts) {
62         UniformManager mgr(layout);
63 
64         for (SkSLType type : kTypes) {
65             const Uniform expectations[] = {{"uniform", type}};
66             mgr.setExpectedUniforms(SkSpan(expectations));
67             mgr.write(type, kFloats);
68             mgr.doneWithExpectedUniforms();
69             REPORTER_ASSERT(r, mgr.size() > 0);
70             mgr.reset();
71         }
72     }
73 }
74 
DEF_TEST(UniformManagerCheckFloatEncoding,r)75 DEF_TEST(UniformManagerCheckFloatEncoding, r) {
76     // Verify that the uniform manager encodes float data properly.
77     for (Layout layout : kLayouts) {
78         UniformManager mgr(layout);
79 
80         for (SkSLType type : kTypes) {
81             // Only test scalar and vector floats. (Matrices can introduce padding between values.)
82             int vecLength = SkSLTypeVecLength(type);
83             if (!SkSLTypeIsFloatType(type) || vecLength < 1) {
84                 continue;
85             }
86 
87             // Write our uniform float scalar/vector.
88             const Uniform expectations[] = {{"uniform", type}};
89             mgr.setExpectedUniforms(SkSpan(expectations));
90             mgr.write(type, kFloats);
91             mgr.doneWithExpectedUniforms();
92 
93             // Read back the uniform data.
94             UniformDataBlock uniformData = mgr.finishUniformDataBlock();
95             size_t elementSize = element_size(layout, type);
96             const void* validData = (elementSize == 4) ? (const void*)kFloats : (const void*)kHalfs;
97             REPORTER_ASSERT(r, uniformData.size() >= vecLength * elementSize);
98             REPORTER_ASSERT(r, 0 == memcmp(validData, uniformData.data(), vecLength * elementSize),
99                             "Layout:%d Type:%d float encoding failed", (int)layout, (int)type);
100             mgr.reset();
101         }
102     }
103 }
104 
DEF_TEST(UniformManagerCheckIntEncoding,r)105 DEF_TEST(UniformManagerCheckIntEncoding, r) {
106     // Verify that the uniform manager encodes int data properly.
107     for (Layout layout : kLayouts) {
108         UniformManager mgr(layout);
109 
110         for (SkSLType type : kTypes) {
111             if (!SkSLTypeIsIntegralType(type)) {
112                 continue;
113             }
114 
115             // Write our uniform int scalar/vector.
116             const Uniform expectations[] = {{"uniform", type}};
117             mgr.setExpectedUniforms(SkSpan(expectations));
118             mgr.write(type, kInts);
119             mgr.doneWithExpectedUniforms();
120 
121             // Read back the uniform data.
122             UniformDataBlock uniformData = mgr.finishUniformDataBlock();
123             int vecLength = SkSLTypeVecLength(type);
124             size_t elementSize = element_size(layout, type);
125             const void* validData = (elementSize == 4) ? (const void*)kInts : (const void*)kShorts;
126             REPORTER_ASSERT(r, uniformData.size() >= vecLength * elementSize);
127             REPORTER_ASSERT(r, 0 == memcmp(validData, uniformData.data(), vecLength * elementSize),
128                             "Layout:%d Type:%d int encoding failed", (int)layout, (int)type);
129             mgr.reset();
130         }
131     }
132 }
133 
DEF_TEST(UniformManagerCheckScalarVectorPacking,r)134 DEF_TEST(UniformManagerCheckScalarVectorPacking, r) {
135     // Verify that the uniform manager can pack scalars and vectors of identical type correctly.
136     for (Layout layout : kLayouts) {
137         UniformManager mgr(layout);
138 
139         for (SkSLType type : kTypes) {
140             int vecLength = SkSLTypeVecLength(type);
141             if (vecLength < 1) {
142                 continue;
143             }
144 
145             // Write three matching uniforms.
146             const Uniform expectations[] = {{"a", type}, {"b", type}, {"c", type}};
147             mgr.setExpectedUniforms(SkSpan(expectations));
148             mgr.write(type, kFloats);
149             mgr.write(type, kFloats);
150             mgr.write(type, kFloats);
151             mgr.doneWithExpectedUniforms();
152 
153             // Verify that the uniform data was packed as tight as it should be.
154             UniformDataBlock uniformData = mgr.finishUniformDataBlock();
155             size_t elementSize = element_size(layout, type);
156             // Vec3s should be packed as if they were vec4s.
157             size_t effectiveVecLength = (vecLength == 3) ? 4 : vecLength;
158             REPORTER_ASSERT(r, uniformData.size() == elementSize * effectiveVecLength * 3,
159                             "Layout:%d Type:%d tight packing failed", (int)layout, (int)type);
160             mgr.reset();
161         }
162     }
163 }
164 
DEF_TEST(UniformManagerCheckMatrixPacking,r)165 DEF_TEST(UniformManagerCheckMatrixPacking, r) {
166     // Verify that the uniform manager can pack matrices correctly.
167     for (Layout layout : kLayouts) {
168         UniformManager mgr(layout);
169 
170         for (SkSLType type : kTypes) {
171             int matrixSize = SkSLTypeMatrixSize(type);
172             if (matrixSize < 2) {
173                 continue;
174             }
175 
176             // Write three matching uniforms.
177             const Uniform expectations[] = {{"a", type}, {"b", type}, {"c", type}};
178             mgr.setExpectedUniforms(SkSpan(expectations));
179             mgr.write(type, kFloats);
180             mgr.write(type, kFloats);
181             mgr.write(type, kFloats);
182             mgr.doneWithExpectedUniforms();
183 
184             // Verify that the uniform data was packed as tight as it should be.
185             UniformDataBlock uniformData = mgr.finishUniformDataBlock();
186             size_t elementSize = element_size(layout, type);
187             // In all layouts, mat3s should burn 12 elements, not 9.
188             size_t numElements = (matrixSize == 3) ? 12 : (matrixSize * matrixSize);
189             REPORTER_ASSERT(r, uniformData.size() == elementSize * numElements * 3,
190                             "Layout:%d Type:%d matrix packing failed", (int)layout, (int)type);
191             mgr.reset();
192         }
193     }
194 }
195 
DEF_TEST(UniformManagerCheckPaddingScalarVector,r)196 DEF_TEST(UniformManagerCheckPaddingScalarVector, r) {
197     // Verify that the uniform manager properly adds padding between pairs of scalar/vector.
198     for (Layout layout : kLayouts) {
199         UniformManager mgr(layout);
200 
201         for (SkSLType type1 : kTypes) {
202             const int vecLength1 = SkSLTypeVecLength(type1);
203             if (vecLength1 < 1) {
204                 continue;
205             }
206 
207             for (SkSLType type2 : kTypes) {
208                 const int vecLength2 = SkSLTypeVecLength(type2);
209                 if (vecLength2 < 1) {
210                     continue;
211                 }
212 
213                 // Write two scalar/vector uniforms.
214                 const Uniform expectations[] = {{"a", type1}, {"b", type2}};
215                 mgr.setExpectedUniforms(SkSpan(expectations));
216                 mgr.write(type1, kFloats);
217                 mgr.write(type2, kFloats);
218                 mgr.doneWithExpectedUniforms();
219 
220                 // The expected packing varies depending on the bit-widths of each element.
221                 const size_t elementSize1 = element_size(layout, type1);
222                 const size_t elementSize2 = element_size(layout, type2);
223                 if (elementSize1 == elementSize2) {
224                     // Elements in the array correspond to the element size (either 16 or 32 bits).
225                     // The expected uniform layout is listed as strings below.
226                     // A/B: uniform values.
227                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
228                     // _  : padding between uniforms for alignment
229                     static constexpr const char* kExpectedLayout[5][5] = {
230                         { "", "",         "",         "",         ""         },
231                         { "", "AB",       "A_BB",     "A___BBBb", "A___BBBB" },
232                         { "", "AAB_",     "AABB",     "AA__BBBb", "AA__BBBB" },
233                         { "", "AAAaB___", "AAAaBB__", "AAAaBBBb", "AAAaBBBB" },
234                         { "", "AAAAB___", "AAAABB__", "AAAABBBb", "AAAABBBB" },
235                     };
236                     const size_t size = strlen(kExpectedLayout[vecLength1][vecLength2]) *
237                                         elementSize1;
238                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
239                     REPORTER_ASSERT(r, uniformData.size() == size,
240                                     "Layout:%d Types:%d %d padding test failed",
241                                     (int)layout, (int)type1, (int)type2);
242                 } else if (elementSize1 == 2 && elementSize2 == 4) {
243                     // Elements in the array below correspond to 16 bits apiece.
244                     // The expected uniform layout is listed as strings below.
245                     // A/B: uniform values.
246                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
247                     // _  : padding between uniforms for alignment
248                     static constexpr const char* kExpectedLayout[5][5] = {
249                         { "", "",         "",         "",                 ""         },
250                         { "", "A_BB",     "A___BBBB", "A_______BBBBBBbb", "A_______BBBBBBBB" },
251                         { "", "AABB",     "AA__BBBB", "AA______BBBBBBbb", "AA______BBBBBBBB" },
252                         { "", "AAAaBB__", "AAAaBBBB", "AAAa____BBBBBBbb", "AAAa____BBBBBBBB" },
253                         { "", "AAAABB__", "AAAABBBB", "AAAA____BBBBBBbb", "AAAA____BBBBBBBB" },
254                     };
255                     const size_t size = strlen(kExpectedLayout[vecLength1][vecLength2]) * 2;
256                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
257                     REPORTER_ASSERT(r, uniformData.size() == size,
258                                     "Layout:%d Types:%d %d padding test failed",
259                                     (int)layout, (int)type1, (int)type2);
260                 } else if (elementSize1 == 4 && elementSize2 == 2) {
261                     // Elements in the array below correspond to 16 bits apiece.
262                     // The expected uniform layout is listed as strings below.
263                     // A/B: uniform values.
264                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
265                     // _  : padding between uniforms for alignment
266                     static constexpr const char* kExpectedLayout[5][5] = {
267                         { "", "", "", "", "" },
268                         { "", "AAB_",     "AABB",     "AA__BBBb", "AA__BBBB" },
269                         { "", "AAAAB___", "AAAABB__", "AAAABBBb", "AAAABBBB" },
270                         { "",
271                           "AAAAAAaaB_______",
272                           "AAAAAAaaBB______",
273                           "AAAAAAaaBBBb____",
274                           "AAAAAAaaBBBB____" },
275                         { "",
276                           "AAAAAAAAB_______",
277                           "AAAAAAAABB______",
278                           "AAAAAAAABBBb____",
279                           "AAAAAAAABBBB____" },
280                     };
281                     const size_t size = strlen(kExpectedLayout[vecLength1][vecLength2]) * 2;
282                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
283                     REPORTER_ASSERT(r, uniformData.size() == size,
284                                     "Layout:%d Types:%d %d padding test failed",
285                                     (int)layout, (int)type1, (int)type2);
286                 } else {
287                     ERRORF(r, "Unexpected element sizes: %zu %zu", elementSize1, elementSize2);
288                 }
289                 mgr.reset();
290             }
291         }
292     }
293 }
294 
DEF_TEST(UniformManagerCheckPaddingVectorMatrix,r)295 DEF_TEST(UniformManagerCheckPaddingVectorMatrix, r) {
296     // Verify that the uniform manager properly adds padding between vectors and matrices.
297     for (Layout layout : kLayouts) {
298         UniformManager mgr(layout);
299 
300         for (SkSLType type1 : kTypes) {
301             const int vecLength1 = SkSLTypeVecLength(type1);
302             if (vecLength1 < 1) {
303                 continue;
304             }
305 
306             for (SkSLType type2 : kTypes) {
307                 const int matSize2 = SkSLTypeMatrixSize(type2);
308                 if (matSize2 < 2) {
309                     continue;
310                 }
311 
312                 // Write the scalar/vector and matrix uniforms.
313                 const Uniform expectations[] = {{"a", type1}, {"b", type2}};
314                 mgr.setExpectedUniforms(SkSpan(expectations));
315                 mgr.write(type1, kFloats);
316                 mgr.write(type2, kFloats);
317                 mgr.doneWithExpectedUniforms();
318 
319                 // The expected packing varies depending on the bit-widths of each element.
320                 const size_t elementSize1 = element_size(layout, type1);
321                 const size_t elementSize2 = element_size(layout, type2);
322                 if (elementSize1 == elementSize2) {
323                     // Elements in the array correspond to the element size (32 bits).
324                     // The expected uniform layout is listed as strings below.
325                     // A/B: uniform values.
326                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
327                     // _  : padding between uniforms for alignment
328                     static constexpr const char* kExpectedLayout[5][5] = {
329                         { "", "", "",         "",                     "" },
330                         { "", "", "A_BBBB",   "A___BBBbBBBbBBBb", "A___BBBBBBBBBBBBBBBB" },
331                         { "", "", "AABBBB",   "AA__BBBbBBBbBBBb", "AA__BBBBBBBBBBBBBBBB" },
332                         { "", "", "AAAaBBBB", "AAAaBBBbBBBbBBBb", "AAAaBBBBBBBBBBBBBBBB" },
333                         { "", "", "AAAABBBB", "AAAABBBbBBBbBBBb", "AAAABBBBBBBBBBBBBBBB" },
334                     };
335                     const size_t size = strlen(kExpectedLayout[vecLength1][matSize2]) *
336                                         elementSize1;
337                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
338                     REPORTER_ASSERT(r, uniformData.size() == size,
339                                     "Types:%d %d vector-matrix padding test failed",
340                                     (int)type1, (int)type2);
341                 } else if (elementSize1 == 2 && elementSize2 == 4) {
342                     // Elements in the array below correspond to 16 bits apiece.
343                     // The expected uniform layout is listed as strings below.
344                     // A/B: uniform values.
345                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
346                     // _  : padding between uniforms for alignment
347                     static constexpr const char* kExpectedLayout[5][5] = {
348                             {"", "", "", "", ""},
349                             {"", "",
350                              "A___BBBBBBBB",
351                              "A_______BBBBBBbbBBBBBBbbBBBBBBbb",
352                              "A_______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
353                             {"", "",
354                              "AA__BBBBBBBB",
355                              "AA______BBBBBBbbBBBBBBbbBBBBBBbb",
356                              "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
357                             {"", "",
358                              "AAAaBBBBBBBB",
359                              "AAAa____BBBBBBbbBBBBBBbbBBBBBBbb",
360                              "AAAa____BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
361                             {"", "",
362                              "AAAABBBBBBBB",
363                              "AAAA____BBBBBBbbBBBBBBbbBBBBBBbb",
364                              "AAAA____BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"},
365                     };
366                     const size_t size = strlen(kExpectedLayout[vecLength1][matSize2]) * 2;
367                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
368                     REPORTER_ASSERT(r, uniformData.size() == size,
369                                     "Types:%d %d vector-matrix padding test failed",
370                                     (int)type1, (int)type2);
371                 } else if (elementSize1 == 4 && elementSize2 == 2) {
372                     // Elements in the array below correspond to 16 bits apiece.
373                     // The expected uniform layout is listed as strings below.
374                     // A/B: uniform values.
375                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
376                     // _  : padding between uniforms for alignment
377                     static constexpr const char* kExpectedLayout[5][5] = {
378                             {"", "", "", "", ""},
379                             {"", "", "AABBBB",   "AA__BBBbBBBbBBBb", "AA__BBBBBBBBBBBBBBBB"},
380                             {"", "", "AAAABBBB", "AAAABBBbBBBbBBBb", "AAAABBBBBBBBBBBBBBBB"},
381                             {"", "",
382                              "AAAAAAaaBBBB____",
383                              "AAAAAAaaBBBbBBBbBBBb____",
384                              "AAAAAAaaBBBBBBBBBBBBBBBB"},
385                             {"", "",
386                              "AAAAAAAABBBB____",
387                              "AAAAAAAABBBbBBBbBBBb____",
388                              "AAAAAAAABBBBBBBBBBBBBBBB"},
389                     };
390                     const size_t size = strlen(kExpectedLayout[vecLength1][matSize2]) * 2;
391                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
392                     REPORTER_ASSERT(r, uniformData.size() == size,
393                                     "Types:%d %d vector-matrix padding test failed",
394                                     (int)type1, (int)type2);
395                 }
396                 mgr.reset();
397             }
398         }
399     }
400 }
401 
DEF_TEST(UniformManagerCheckPaddingMatrixVector,r)402 DEF_TEST(UniformManagerCheckPaddingMatrixVector, r) {
403     // Verify that the uniform manager properly adds padding between matrices and vectors.
404     for (Layout layout : kLayouts) {
405         UniformManager mgr(layout);
406 
407         for (SkSLType type1 : kTypes) {
408             const int matSize1 = SkSLTypeMatrixSize(type1);
409             if (matSize1 < 2) {
410                 continue;
411             }
412 
413             for (SkSLType type2 : kTypes) {
414                 const int vecLength2 = SkSLTypeVecLength(type2);
415                 if (vecLength2 < 1) {
416                     continue;
417                 }
418 
419                 // Write the scalar/vector and matrix uniforms.
420                 const Uniform expectations[] = {{"a", type1}, {"b", type2}};
421                 mgr.setExpectedUniforms(SkSpan(expectations));
422                 mgr.write(type1, kFloats);
423                 mgr.write(type2, kFloats);
424                 mgr.doneWithExpectedUniforms();
425 
426                 // The expected packing varies depending on the bit-widths of each element.
427                 const size_t elementSize1 = element_size(layout, type1);
428                 const size_t elementSize2 = element_size(layout, type2);
429                 if (elementSize1 == elementSize2) {
430                     // Elements in the array correspond to the element size (32 bits).
431                     // The expected uniform layout is listed as strings below.
432                     // A/B: uniform values.
433                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
434                     // _  : padding between uniforms for alignment
435                     static constexpr const char* kExpectedLayout[5][5] = {
436                         { "", "", "", "", "" },
437                         { "", "", "", "", "" },
438                         { "", "AAAAB_", "AAAABB", "AAAABBBb", "AAAABBBB" },
439                         { "",
440                           "AAAaAAAaAAAaB___",
441                           "AAAaAAAaAAAaBB__",
442                           "AAAaAAAaAAAaBBBb",
443                           "AAAaAAAaAAAaBBBB" },
444                         { "",
445                           "AAAAAAAAAAAAAAAAB___",
446                           "AAAAAAAAAAAAAAAABB__",
447                           "AAAAAAAAAAAAAAAABBBb",
448                           "AAAAAAAAAAAAAAAABBBB" },
449                     };
450                     const size_t size = strlen(kExpectedLayout[matSize1][vecLength2]) *
451                                         elementSize1;
452                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
453                     REPORTER_ASSERT(r, uniformData.size() == size,
454                                     "Types:%d %d matrix-vector padding test failed",
455                                     (int)type1, (int)type2);
456                 } else if (elementSize1 == 2 && elementSize2 == 4) {
457                     // Elements in the array below correspond to 16 bits apiece.
458                     // The expected uniform layout is listed as strings below.
459                     // A/B: uniform values.
460                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
461                     // _  : padding between uniforms for alignment
462                     static constexpr const char* kExpectedLayout[5][5] = {
463                         { "", "", "", "", "" },
464                         { "", "", "", "", "" },
465                         { "", "AAAABB", "AAAABBBB", "AAAA____BBBBBBbb", "AAAA____BBBBBBBB" },
466                         { "",
467                           "AAAaAAAaAAAaBB__",
468                           "AAAaAAAaAAAaBBBB",
469                           "AAAaAAAaAAAa____BBBBBBbb",
470                           "AAAaAAAaAAAa____BBBBBBBB" },
471                         { "",
472                           "AAAAAAAAAAAAAAAABB__",
473                           "AAAAAAAAAAAAAAAABBBB",
474                           "AAAAAAAAAAAAAAAABBBBBBbb",
475                           "AAAAAAAAAAAAAAAABBBBBBBB" },
476                     };
477                     const size_t size = strlen(kExpectedLayout[matSize1][vecLength2]) * 2;
478                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
479                     REPORTER_ASSERT(r, uniformData.size() == size,
480                                     "Types:%d %d matrix-vector padding test failed",
481                                     (int)type1, (int)type2);
482                 } else if (elementSize1 == 4 && elementSize2 == 2) {
483                     // Elements in the array below correspond to 16 bits apiece.
484                     // The expected uniform layout is listed as strings below.
485                     // A/B: uniform values.
486                     // a/b: padding as part of the uniform type (vec3 takes 4 slots)
487                     // _  : padding between uniforms for alignment
488                     static constexpr const char* kExpectedLayout[5][5] = {
489                         { "", "", "", "", "" },
490                         { "", "", "", "", "" },
491                         { "", "AAAAAAAAB___", "AAAAAAAABB__", "AAAAAAAABBBb", "AAAAAAAABBBB" },
492                         { "",
493                           "AAAAAAaaAAAAAAaaAAAAAAaaB_______",
494                           "AAAAAAaaAAAAAAaaAAAAAAaaBB______",
495                           "AAAAAAaaAAAAAAaaAAAAAAaaBBBb____",
496                           "AAAAAAaaAAAAAAaaAAAAAAaaBBBB____" },
497                         { "",
498                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_______",
499                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB______",
500                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBb____",
501                           "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB____" },
502                     };
503                     const size_t size = strlen(kExpectedLayout[matSize1][vecLength2]) * 2;
504                     UniformDataBlock uniformData = mgr.finishUniformDataBlock();
505                     REPORTER_ASSERT(r, uniformData.size() == size,
506                                     "Types:%d %d matrix-vector padding test failed",
507                                     (int)type1, (int)type2);
508                 }
509                 mgr.reset();
510             }
511         }
512     }
513 }
514 
DEF_TEST(UniformManagerMetalArrayLayout,r)515 DEF_TEST(UniformManagerMetalArrayLayout, r) {
516     UniformManager mgr(Layout::kMetal);
517 
518     // Tests set up a uniform block with a single half (to force alignment) and an array of 3
519     // elements. Test every type that can appear in an array.
520     constexpr size_t kArraySize = 3;
521 
522     // Buffer large enough to hold a float4x4[3] array.
523     static constexpr uint8_t kBuffer[192] = {};
524     static const char* kExpectedLayout[] = {
525         // Elements in the array below correspond to 16 bits apiece.
526         // The expected uniform layout is listed as strings below.
527         // A/B: uniform values.
528         // a/b: padding as part of the uniform type (vec3 takes 4 slots)
529         // _  : padding between uniforms for alignment.
530 
531         /* {half, short[3]}  */ "AABBBBBB",
532         /* {half, short2[3]} */ "AA__BBBBBBBBBBBB",
533         /* {half, short3[3]} */ "AA______BBBBBBbbBBBBBBbbBBBBBBbb",
534         /* {half, short4[3]} */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
535         /* {half, float[3]}  */ "AA__BBBBBBBBBBBB",
536         /* {half, float2[3]} */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
537         /* {half, float3[3]} */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
538         /* {half, float4[3]} */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
539         /* {half, half[3]}   */ "AABBBBBB",
540         /* {half, half2[3]}  */ "AA__BBBBBBBBBBBB",
541         /* {half, half3[3]}  */ "AA______BBBBBBbbBBBBBBbbBBBBBBbb",
542         /* {half, half4[3]}  */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
543         /* {half, int[3]}    */ "AA__BBBBBBBBBBBB",
544         /* {half, int2[3]}   */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
545         /* {half, int3[3]}   */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
546         /* {half, int4[3]}   */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
547 
548         /* {half, float2x2[3] */ "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
549         /* {half, float3x3[3] */ "AA______________"
550                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
551                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
552                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
553         /* {half, float4x4[3] */ "AA______________"
554                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
555                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
556                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
557 
558         /* {half, half2x2[3] */ "AA__BBBBBBBBBBBBBBBBBBBBBBBB",
559         /* {half, half3x3[3] */ "AA______"
560                                  "BBBBBBbbBBBBBBbbBBBBBBbb"
561                                  "BBBBBBbbBBBBBBbbBBBBBBbb"
562                                  "BBBBBBbbBBBBBBbbBBBBBBbb",
563         /* {half, half4x4[3] */ "AA______"
564                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
565                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
566                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
567     };
568     for (size_t i = 0; i < std::size(kExpectedLayout); i++) {
569         const SkSLType arrayType = kTypes[i];
570         const Uniform expectations[] = {{"a", SkSLType::kHalf}, {"b", arrayType, kArraySize}};
571 
572         mgr.setExpectedUniforms(SkSpan(expectations));
573         mgr.write(SkSLType::kHalf, kHalfs);
574         mgr.writeArray(arrayType, kBuffer, kArraySize);
575         mgr.doneWithExpectedUniforms();
576 
577         const size_t expectedSize = strlen(kExpectedLayout[i]);
578         const UniformDataBlock uniformData = mgr.finishUniformDataBlock();
579         REPORTER_ASSERT(r, uniformData.size() == expectedSize,
580                         "array test %d for type %s failed - expected size: %zu, actual size: %zu",
581                         (int)i, SkSLTypeString(arrayType), expectedSize, uniformData.size());
582 
583         mgr.reset();
584     }
585 }
586 
DEF_TEST(UniformManagerStd430ArrayLayout,r)587 DEF_TEST(UniformManagerStd430ArrayLayout, r) {
588     UniformManager mgr(Layout::kStd430);
589 
590     // Tests set up a uniform block with a single half (to force alignment) and an array of 3
591     // elements. Test every type that can appear in an array.
592     constexpr size_t kArraySize = 3;
593 
594     // Buffer large enough to hold a float4x4[3] array.
595     static constexpr uint8_t kBuffer[192] = {};
596     static const char* kExpectedLayout[] = {
597         // Elements in the array below correspond to 16 bits apiece.
598         // The expected uniform layout is listed as strings below.
599         // A/B: uniform values.
600         // a/b: padding as part of the uniform type (vec3 takes 4 slots)
601         // _  : padding between uniforms for alignment.
602 
603         /* {half, short[3]}  */ "AA__BBBBBBBBBBBB",
604         /* {half, short2[3]} */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
605         /* {half, short3[3]} */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
606         /* {half, short4[3]} */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
607         /* {half, float[3]}  */ "AA__BBBBBBBBBBBB",
608         /* {half, float2[3]} */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
609         /* {half, float3[3]} */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
610         /* {half, float4[3]} */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
611         /* {half, half[3]}   */ "AA__BBBBBBBBBBBB",
612         /* {half, half2[3]}  */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
613         /* {half, half3[3]}  */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
614         /* {half, half4[3]}  */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
615         /* {half, int[3]}    */ "AA__BBBBBBBBBBBB",
616         /* {half, int2[3]}   */ "AA______BBBBBBBBBBBBBBBBBBBBBBBB",
617         /* {half, int3[3]}   */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
618         /* {half, int4[3]}   */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
619 
620         /* {half, float2x2[3] */ "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
621         /* {half, float3x3[3] */ "AA______________"
622                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
623                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
624                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
625         /* {half, float4x4[3] */ "AA______________"
626                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
627                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
628                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
629 
630         /* {half, half2x2[3]  */ "AA______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
631         /* {half, half3x3[3]  */ "AA______________"
632                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
633                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
634                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
635         /* {half, half4x4[3]  */ "AA______________"
636                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
637                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
638                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
639     };
640     for (size_t i = 0; i < std::size(kExpectedLayout); i++) {
641         const SkSLType arrayType = kTypes[i];
642         const Uniform expectations[] = {{"a", SkSLType::kHalf}, {"b", arrayType, kArraySize}};
643 
644         mgr.setExpectedUniforms(SkSpan(expectations));
645         mgr.write(SkSLType::kHalf, kHalfs);
646         mgr.writeArray(arrayType, kBuffer, kArraySize);
647         mgr.doneWithExpectedUniforms();
648 
649         const size_t expectedSize = strlen(kExpectedLayout[i]);
650         const UniformDataBlock uniformData = mgr.finishUniformDataBlock();
651         REPORTER_ASSERT(r, uniformData.size() == expectedSize,
652                         "array test %d for type %s failed - expected size: %zu, actual size: %zu",
653                         (int)i, SkSLTypeString(arrayType), expectedSize, uniformData.size());
654 
655         mgr.reset();
656     }
657 }
658 
DEF_TEST(UniformManagerStd140ArrayLayout,r)659 DEF_TEST(UniformManagerStd140ArrayLayout, r) {
660     UniformManager mgr(Layout::kStd140);
661 
662     // Tests set up a uniform block with a single half (to force alignment) and an array of 3
663     // elements. Test every type that can appear in an array.
664     constexpr size_t kArraySize = 3;
665 
666     // Buffer large enough to hold a float4x4[3] array.
667     static constexpr uint8_t kBuffer[192] = {};
668     static const char* kExpectedLayout[] = {
669         // Elements in the array below correspond to 16 bits apiece.
670         // The expected uniform layout is listed as strings below.
671         // A/B: uniform values.
672         // a/b: padding as part of the uniform type (vec3 takes 4 slots)
673         // _  : padding between uniforms for alignment.
674 
675         /* {half, short[3]}  */ "AA______________BBbbbbbbbbbbbbbbBBbbbbbbbbbbbbbbBBbbbbbbbbbbbbbb",
676         /* {half, short2[3]} */ "AA______________BBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbb",
677         /* {half, short3[3]} */ "AA______________BBBBBBbbbbbbbbbbBBBBBBbbbbbbbbbbBBBBBBbbbbbbbbbb",
678         /* {half, short4[3]} */ "AA______________BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
679         /* {half, float[3]}  */ "AA______________BBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbb",
680         /* {half, float2[3]} */ "AA______________BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
681         /* {half, float3[3]} */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
682         /* {half, float4[3]} */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
683         /* {half, half[3]}   */ "AA______________BBbbbbbbbbbbbbbbBBbbbbbbbbbbbbbbBBbbbbbbbbbbbbbb",
684         /* {half, half2[3]}  */ "AA______________BBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbb",
685         /* {half, half3[3]}  */ "AA______________BBBBBBbbbbbbbbbbBBBBBBbbbbbbbbbbBBBBBBbbbbbbbbbb",
686         /* {half, half4[3]}  */ "AA______________BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
687         /* {half, int[3]}    */ "AA______________BBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbbBBBBbbbbbbbbbbbb",
688         /* {half, int2[3]}   */ "AA______________BBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbbBBBBBBBBbbbbbbbb",
689         /* {half, int3[3]}   */ "AA______________BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
690         /* {half, int4[3]}   */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
691 
692         /* {half, float2x2[3] */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
693         /* {half, float3x3[3] */ "AA______________"
694                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
695                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
696                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
697         /* {half, float4x4[3] */ "AA______________"
698                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
699                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
700                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
701 
702         /* {half, half2x2[3]  */ "AA______________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
703         /* {half, half3x3[3]  */ "AA______________"
704                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
705                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb"
706                                  "BBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbbBBBBBBBBBBBBbbbb",
707         /* {half, half4x4[3]  */ "AA______________"
708                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
709                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
710                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
711     };
712     for (size_t i = 0; i < std::size(kExpectedLayout); i++) {
713         const SkSLType arrayType = kTypes[i];
714         const Uniform expectations[] = {{"a", SkSLType::kHalf}, {"b", arrayType, kArraySize}};
715 
716         mgr.setExpectedUniforms(SkSpan(expectations));
717         mgr.write(SkSLType::kHalf, kHalfs);
718         mgr.writeArray(arrayType, kBuffer, kArraySize);
719         mgr.doneWithExpectedUniforms();
720 
721         const size_t expectedSize = strlen(kExpectedLayout[i]);
722         const UniformDataBlock uniformData = mgr.finishUniformDataBlock();
723         REPORTER_ASSERT(r, uniformData.size() == expectedSize,
724                         "array test %d for type %s failed - expected size: %zu, actual size: %zu",
725                         (int)i, SkSLTypeString(arrayType), expectedSize, uniformData.size());
726 
727         mgr.reset();
728     }
729 }
730