1 /*
2 * Copyright © 2024 Collabora, Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "nir_test.h"
25 #include "nir_format_convert.h"
26
27 #include "util/macros.h"
28 #include "util/format/u_formats.h"
29 #include "util/format_srgb.h"
30 #include "util/half_float.h"
31 #include "util/u_endian.h"
32 #include "util/u_math.h"
33
34 /* These tests and the NIR code currently assume little endian */
35 #if UTIL_ARCH_LITTLE_ENDIAN
36
37 #define NUM_COLORS 32
38
39 class nir_format_convert_test
40 : public nir_test
41 , public testing::WithParamInterface<pipe_format>
42 {
43 protected:
nir_format_convert_test()44 nir_format_convert_test()
45 : nir_test::nir_test("nir_format_convert_test")
46 { }
47 };
48
49 /* Repeatable random number generator */
50 static uint16_t
rand_u16(void)51 rand_u16(void)
52 {
53 static const uint16_t data[] = {
54 /* Important numbers we want to hit, twice for good measure */
55 0, 0, 128, 128, 255, 255, 256, 256, 32768, 32768, 65535, 65535,
56
57 /* 100 random 16-bit numbers from random.org */
58 31401 , 17066 , 65230 , 954 , 12680 ,
59 3631 , 45135 , 1477 , 40861 , 62785 ,
60 35775 , 3171 , 24120 , 6774 , 24488 ,
61 12377 , 29039 , 22146 , 27893 , 62104 ,
62 15854 , 36623 , 23545 , 47719 , 31666 ,
63 23657 , 43795 , 64813 , 18846 , 32886 ,
64 48464 , 28934 , 48575 , 9247 , 32525 ,
65 82 , 15366 , 24299 , 13694 , 48017 ,
66 48449 , 13739 , 47257 , 52684 , 52094 ,
67 61776 , 42874 , 1031 , 11529 , 15276 ,
68 26020 , 494 , 47804 , 50461 , 55816 ,
69 44489 , 22592 , 44167 , 64247 , 60796 ,
70 49925 , 23000 , 12849 , 20699 , 62204 ,
71 5888 , 3813 , 27129 , 29019 , 7790 ,
72 65437 , 64541 , 41808 , 28539 , 29315 ,
73 50120 , 24765 , 7507 , 9653 , 62136 ,
74 32915 , 15143 , 39313 , 50201 , 29143 ,
75 14190 , 10041 , 31015 , 20616 , 42076 ,
76 23404 , 61917 , 10701 , 40230 , 38904 ,
77 30589 , 47499 , 63444 , 49431 , 40875 ,
78 };
79
80 static int count = 0;
81
82 int i = count;
83 count = (i + 1) % ARRAY_SIZE(data);
84
85 return data[i];
86 }
87
88 static uint32_t
rand_uint(unsigned bits)89 rand_uint(unsigned bits)
90 {
91 uint32_t data = rand_u16();
92 if (bits > 16)
93 data |= rand_u16() << 16;
94 assert(bits <= 32);
95
96 return data & BITFIELD_MASK(bits);
97 }
98
99 static int32_t
rand_int(unsigned bits)100 rand_int(unsigned bits)
101 {
102 uint32_t data = rand_u16();
103 if (bits > 16)
104 data |= rand_u16() << 16;
105 assert(bits <= 32);
106
107 return util_mask_sign_extend(data, bits);
108 }
109
110 static uint32_t
rand_color(util_format_colorspace colorspace,util_format_type type,bool normalized,bool pure_integer,unsigned bits)111 rand_color(util_format_colorspace colorspace,
112 util_format_type type,
113 bool normalized,
114 bool pure_integer,
115 unsigned bits)
116 {
117 switch (type) {
118 case UTIL_FORMAT_TYPE_VOID:
119 return 0;
120
121 case UTIL_FORMAT_TYPE_UNSIGNED:
122 if (pure_integer) {
123 assert(colorspace == UTIL_FORMAT_COLORSPACE_RGB);
124 return rand_uint(bits);
125 } else if (normalized) {
126 switch (colorspace) {
127 case UTIL_FORMAT_COLORSPACE_RGB:
128 /* By starting with an integer, we ensure we don't get funny
129 * rounding.
130 */
131 return fui(rand_uint(bits) / (float)u_uintN_max(bits));
132
133 case UTIL_FORMAT_COLORSPACE_SRGB:
134 /* By starting with an integer, we ensure we don't get funny
135 * rounding.
136 */
137 assert(bits == 8);
138 return util_format_srgb_8unorm_to_linear_float(rand_uint(8));
139
140 default:
141 unreachable("Unknown colorspace");
142 }
143 } else {
144 assert(colorspace == UTIL_FORMAT_COLORSPACE_RGB);
145 return fui((float)rand_uint(bits));
146 }
147
148 case UTIL_FORMAT_TYPE_SIGNED:
149 assert(colorspace == UTIL_FORMAT_COLORSPACE_RGB);
150 if (pure_integer) {
151 return rand_int(bits);
152 } else if (normalized) {
153 /* By starting with an integer, we ensure we don't get funny
154 * rounding.
155 */
156 return fui(rand_int(bits) / (float)u_intN_max(bits));
157 } else {
158 return fui((float)rand_int(bits));
159 }
160
161 case UTIL_FORMAT_TYPE_FIXED:
162 assert(colorspace == UTIL_FORMAT_COLORSPACE_RGB);
163 return rand_uint(bits);
164
165 case UTIL_FORMAT_TYPE_FLOAT:
166 assert(colorspace == UTIL_FORMAT_COLORSPACE_RGB);
167 if (bits <= 16) {
168 uint16_t val = rand_u16();
169 /* Let's keep it to numbers, shall we? */
170 if ((val & 0x7c00) == 0x7c00)
171 val &= 0xfc00;
172
173 /* Make sure the mantissa fits so we don't round funny */
174 if (bits < 16)
175 val &= ~BITFIELD_MASK(16 - bits);
176
177 return fui(_mesa_half_to_float(val));
178 } else if (bits == 32) {
179 uint32_t val = rand_uint(32);
180 /* Let's keep it to numbers, shall we? */
181 if ((val & 0x7f800000) == 0x7f800000)
182 val &= 0xff800000;
183 return val;
184 }
185
186 default:
187 unreachable("Invalid format type");
188 }
189 }
190
191 class rgba : public nir_format_convert_test { };
192
TEST_P(rgba,pack)193 TEST_P(rgba, pack)
194 {
195 pipe_format format = GetParam();
196 auto desc = util_format_description(format);
197
198 struct {
199 uint32_t u32[4];
200 } colors[NUM_COLORS];
201 for (unsigned i = 0; i < NUM_COLORS; i++) {
202 for (unsigned c = 0; c < 4; c++) {
203 pipe_swizzle s = (pipe_swizzle)desc->swizzle[c];
204 if (s < PIPE_SWIZZLE_X || s > PIPE_SWIZZLE_W) {
205 colors[i].u32[c] = 0;
206 } else {
207 auto chan = &desc->channel[s - PIPE_SWIZZLE_X];
208 assert(chan->type != (unsigned)UTIL_FORMAT_TYPE_VOID);
209 colors[i].u32[c] = rand_color(desc->colorspace,
210 (util_format_type)chan->type,
211 chan->normalized,
212 chan->pure_integer,
213 chan->size);
214 }
215 }
216 }
217
218 nir_intrinsic_instr *uses[NUM_COLORS];
219 for (unsigned i = 0; i < NUM_COLORS; i++) {
220 nir_def *rgba = nir_imm_ivec4(b, colors[i].u32[0],
221 colors[i].u32[1],
222 colors[i].u32[2],
223 colors[i].u32[3]);
224 nir_def *packed = nir_format_pack_rgba(b, format, rgba);
225 uses[i] = nir_use(b, packed);
226 }
227
228 nir_lower_undef_to_zero(b->shader);
229 ASSERT_TRUE(nir_opt_constant_folding(b->shader));
230 ASSERT_TRUE(nir_opt_dce(b->shader));
231
232 for (unsigned i = 0; i < NUM_COLORS; i++) {
233 char expected[16] = { 0, };
234 util_format_pack_rgba(format, expected, colors[i].u32, 1);
235
236 nir_def *packed_ssa = uses[i]->src[0].ssa;
237 const nir_const_value *packed =
238 nir_instr_as_load_const(packed_ssa->parent_instr)->value;
239 if (packed_ssa->num_components == 1) {
240 switch (packed_ssa->bit_size) {
241 case 8:
242 EXPECT_EQ(*(uint8_t *)expected, packed[0].u8);
243 break;
244 case 16:
245 EXPECT_EQ(*(uint16_t *)expected, packed[0].u16);
246 break;
247 case 32:
248 EXPECT_EQ(*(uint32_t *)expected, packed[0].u32);
249 break;
250 default:
251 unreachable("Unsupported packed data bit size");
252 }
253 } else {
254 assert(packed_ssa->bit_size == 32);
255 uint32_t *exp_u32 = (uint32_t *)expected;
256 for (unsigned c = 0; c < packed_ssa->num_components; c++)
257 EXPECT_EQ(exp_u32[c], packed[c].u32);
258 }
259 }
260 }
261
TEST_P(rgba,unpack)262 TEST_P(rgba, unpack)
263 {
264 pipe_format format = GetParam();
265 auto desc = util_format_description(format);
266 const unsigned dwords = DIV_ROUND_UP(desc->block.bits, 32);
267
268 struct {
269 uint32_t u32[4];
270 } colors[NUM_COLORS];
271 memset(colors, 0, sizeof(colors));
272
273 for (unsigned i = 0; i < NUM_COLORS; i++) {
274 for (unsigned dw = 0; dw < dwords; dw++) {
275 unsigned bits = MIN2(32, desc->block.bits - dw * 32);
276 colors[i].u32[dw] = rand_uint(bits);
277 }
278 }
279
280 nir_intrinsic_instr *uses[NUM_COLORS];
281 for (unsigned i = 0; i < NUM_COLORS; i++) {
282 nir_def *packed_comps[4];
283 for (unsigned dw = 0; dw < dwords; dw++)
284 packed_comps[dw] = nir_imm_int(b, colors[i].u32[dw]);
285 nir_def *packed = nir_vec(b, packed_comps, dwords);
286 nir_def *rgba = nir_format_unpack_rgba(b, packed, format);
287 uses[i] = nir_use(b, rgba);
288 }
289
290 nir_lower_undef_to_zero(b->shader);
291 ASSERT_TRUE(nir_opt_constant_folding(b->shader));
292 ASSERT_TRUE(nir_opt_dce(b->shader));
293
294 for (unsigned i = 0; i < NUM_COLORS; i++) {
295 char expected[16] = { 0, };
296 util_format_unpack_rgba(format, expected, colors[i].u32, 1);
297
298 nir_def *rgba_ssa = uses[i]->src[0].ssa;
299 assert(rgba_ssa->bit_size == 32);
300 assert(rgba_ssa->num_components == 4);
301
302 const nir_const_value *rgba =
303 nir_instr_as_load_const(rgba_ssa->parent_instr)->value;
304
305 if (util_format_is_pure_integer(format)) {
306 uint32_t *exp_u32 = (uint32_t *)expected;
307 for (uint32_t c = 0; c < 4; c++)
308 EXPECT_EQ(exp_u32[c], rgba[c].u32);
309 } else {
310 float *exp_f32 = (float *)expected;
311 for (uint32_t c = 0; c < 4; c++) {
312 EXPECT_EQ(isnan(exp_f32[c]), isnan(uif(rgba[c].u32)));
313 if (!isnan(exp_f32[c]) && !isnan(uif(rgba[c].u32))) {
314 EXPECT_FLOAT_EQ(exp_f32[c], uif(rgba[c].u32));
315 }
316 }
317 }
318 }
319 }
320
321 INSTANTIATE_TEST_SUITE_P(nir_format_convert_test, rgba, testing::Values(
322 // There's no way to get bit-for-bit identical with the CPU for these
323 //
324 // PIPE_FORMAT_R32_UNORM,
325 // PIPE_FORMAT_R32G32_UNORM,
326 // PIPE_FORMAT_R32G32B32_UNORM,
327 // PIPE_FORMAT_R32G32B32A32_UNORM,
328 // PIPE_FORMAT_R32_USCALED,
329 // PIPE_FORMAT_R32G32_USCALED,
330 // PIPE_FORMAT_R32G32B32_USCALED,
331 // PIPE_FORMAT_R32G32B32A32_USCALED,
332 // PIPE_FORMAT_R32_SNORM,
333 // PIPE_FORMAT_R32G32_SNORM,
334 // PIPE_FORMAT_R32G32B32_SNORM,
335 // PIPE_FORMAT_R32G32B32A32_SNORM,
336 // PIPE_FORMAT_R32_SSCALED,
337 // PIPE_FORMAT_R32G32_SSCALED,
338 // PIPE_FORMAT_R32G32B32_SSCALED,
339 // PIPE_FORMAT_R32G32B32A32_SSCALED,
340
341 PIPE_FORMAT_R16_UNORM,
342 PIPE_FORMAT_R16G16_UNORM,
343 PIPE_FORMAT_R16G16B16_UNORM,
344 PIPE_FORMAT_R16G16B16A16_UNORM,
345 PIPE_FORMAT_R16_USCALED,
346 PIPE_FORMAT_R16G16_USCALED,
347 PIPE_FORMAT_R16G16B16_USCALED,
348 PIPE_FORMAT_R16G16B16A16_USCALED,
349 PIPE_FORMAT_R16_SNORM,
350 PIPE_FORMAT_R16G16_SNORM,
351 PIPE_FORMAT_R16G16B16_SNORM,
352 PIPE_FORMAT_R16G16B16A16_SNORM,
353 PIPE_FORMAT_R16_SSCALED,
354 PIPE_FORMAT_R16G16_SSCALED,
355 PIPE_FORMAT_R16G16B16_SSCALED,
356 PIPE_FORMAT_R16G16B16A16_SSCALED,
357 PIPE_FORMAT_R8_UNORM,
358 PIPE_FORMAT_R8G8_UNORM,
359 PIPE_FORMAT_R8G8B8_UNORM,
360 PIPE_FORMAT_B8G8R8_UNORM,
361 PIPE_FORMAT_R8G8B8A8_UNORM,
362 PIPE_FORMAT_B8G8R8A8_UNORM,
363 PIPE_FORMAT_R8_USCALED,
364 PIPE_FORMAT_R8G8_USCALED,
365 PIPE_FORMAT_R8G8B8_USCALED,
366 PIPE_FORMAT_B8G8R8_USCALED,
367 PIPE_FORMAT_R8G8B8A8_USCALED,
368 PIPE_FORMAT_B8G8R8A8_USCALED,
369 PIPE_FORMAT_A8B8G8R8_USCALED,
370 PIPE_FORMAT_R8_SNORM,
371 PIPE_FORMAT_R8G8_SNORM,
372 PIPE_FORMAT_R8G8B8_SNORM,
373 PIPE_FORMAT_B8G8R8_SNORM,
374 PIPE_FORMAT_R8G8B8A8_SNORM,
375 PIPE_FORMAT_B8G8R8A8_SNORM,
376 PIPE_FORMAT_R8_SSCALED,
377 PIPE_FORMAT_R8G8_SSCALED,
378 PIPE_FORMAT_R8G8B8_SSCALED,
379 PIPE_FORMAT_B8G8R8_SSCALED,
380 PIPE_FORMAT_R8G8B8A8_SSCALED,
381 PIPE_FORMAT_B8G8R8A8_SSCALED,
382 PIPE_FORMAT_A8B8G8R8_SSCALED,
383 PIPE_FORMAT_A8R8G8B8_UNORM,
384
385 // nir_format_[un]pack() don't handle the legacy GL fixed formats
386 //
387 // PIPE_FORMAT_R32_FIXED,
388 // PIPE_FORMAT_R32G32_FIXED,
389 // PIPE_FORMAT_R32G32B32_FIXED,
390 // PIPE_FORMAT_R32G32B32A32_FIXED,
391
392 PIPE_FORMAT_R16_FLOAT,
393 PIPE_FORMAT_R16G16_FLOAT,
394 PIPE_FORMAT_R16G16B16_FLOAT,
395 PIPE_FORMAT_R16G16B16A16_FLOAT,
396 PIPE_FORMAT_R8_UINT,
397 PIPE_FORMAT_R8G8_UINT,
398 PIPE_FORMAT_R8G8B8_UINT,
399 PIPE_FORMAT_B8G8R8_UINT,
400 PIPE_FORMAT_R8G8B8A8_UINT,
401 PIPE_FORMAT_B8G8R8A8_UINT,
402 PIPE_FORMAT_R8_SINT,
403 PIPE_FORMAT_R8G8_SINT,
404 PIPE_FORMAT_R8G8B8_SINT,
405 PIPE_FORMAT_B8G8R8_SINT,
406 PIPE_FORMAT_R8G8B8A8_SINT,
407 PIPE_FORMAT_B8G8R8A8_SINT,
408 PIPE_FORMAT_R16_UINT,
409 PIPE_FORMAT_R16G16_UINT,
410 PIPE_FORMAT_R16G16B16_UINT,
411 PIPE_FORMAT_R16G16B16A16_UINT,
412 PIPE_FORMAT_R16_SINT,
413 PIPE_FORMAT_R16G16_SINT,
414 PIPE_FORMAT_R16G16B16_SINT,
415 PIPE_FORMAT_R16G16B16A16_SINT,
416 PIPE_FORMAT_R32_UINT,
417 PIPE_FORMAT_R32G32_UINT,
418 PIPE_FORMAT_R32G32B32_UINT,
419 PIPE_FORMAT_R32G32B32A32_UINT,
420 PIPE_FORMAT_R32_SINT,
421 PIPE_FORMAT_R32G32_SINT,
422 PIPE_FORMAT_R32G32B32_SINT,
423 PIPE_FORMAT_R32G32B32A32_SINT,
424
425 PIPE_FORMAT_R10G10B10A2_UNORM,
426 PIPE_FORMAT_R10G10B10A2_SNORM,
427 PIPE_FORMAT_R10G10B10A2_USCALED,
428 PIPE_FORMAT_R10G10B10A2_SSCALED,
429
430 PIPE_FORMAT_B10G10R10A2_UNORM,
431 PIPE_FORMAT_B10G10R10A2_SNORM,
432 PIPE_FORMAT_B10G10R10A2_USCALED,
433 PIPE_FORMAT_B10G10R10A2_SSCALED,
434
435 PIPE_FORMAT_R11G11B10_FLOAT,
436
437 PIPE_FORMAT_R10G10B10A2_UINT,
438 PIPE_FORMAT_R10G10B10A2_SINT,
439
440 PIPE_FORMAT_B10G10R10A2_UINT,
441 PIPE_FORMAT_B10G10R10A2_SINT,
442
443 PIPE_FORMAT_B8G8R8X8_UNORM,
444 PIPE_FORMAT_X8B8G8R8_UNORM,
445 PIPE_FORMAT_X8R8G8B8_UNORM,
446 PIPE_FORMAT_B5G5R5A1_UNORM,
447 PIPE_FORMAT_R4G4B4A4_UNORM,
448 PIPE_FORMAT_B4G4R4A4_UNORM,
449 PIPE_FORMAT_R5G6B5_UNORM,
450 PIPE_FORMAT_B5G6R5_UNORM,
451
452 PIPE_FORMAT_R8G8_SRGB,
453 PIPE_FORMAT_R8G8B8_SRGB,
454 PIPE_FORMAT_B8G8R8_SRGB,
455 PIPE_FORMAT_A8B8G8R8_SRGB,
456 PIPE_FORMAT_X8B8G8R8_SRGB,
457 PIPE_FORMAT_B8G8R8A8_SRGB,
458 PIPE_FORMAT_B8G8R8X8_SRGB,
459 PIPE_FORMAT_A8R8G8B8_SRGB,
460 PIPE_FORMAT_X8R8G8B8_SRGB,
461 PIPE_FORMAT_R8G8B8A8_SRGB
462 ));
463
464 #endif /* UTIL_ARCH_LITTLE_ENDIAN */
465