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