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