1 /* Make the test not meaningless when asserts are disabled. */
2 #undef NDEBUG
3
4 #include <assert.h>
5 #include <inttypes.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 #include <amdgpu.h>
10 #include "drm-uapi/amdgpu_drm.h"
11 #include "drm-uapi/drm_fourcc.h"
12
13 #include "ac_surface.h"
14 #include "util/macros.h"
15 #include "util/u_math.h"
16 #include "util/u_vector.h"
17 #include "util/mesa-sha1.h"
18 #include "addrlib/inc/addrinterface.h"
19
20 #include "ac_fake_hw_db.h"
21
22 /*
23 * The main goal of this test is making sure that we do
24 * not change the meaning of existing modifiers.
25 */
26
27 struct test_entry {
28 /* key part */
29 uint64_t modifier;
30 unsigned w;
31 unsigned h;
32 enum pipe_format format;
33
34 /* debug info */
35 const char *name;
36 uint8_t pipes;
37 uint8_t rb;
38 uint8_t banks_or_pkrs;
39 uint8_t se;
40
41 /* value to determine uniqueness */
42 unsigned char hash[20];
43
44 /* u_vector requires power of two sizing */
45 char padding[sizeof(void*) == 8 ? 8 : 16];
46 };
47
48 static uint64_t
block_count(unsigned w,unsigned h,unsigned elem_bits,unsigned block_bits,unsigned * aligned_pitch,unsigned * aligned_height)49 block_count(unsigned w, unsigned h, unsigned elem_bits, unsigned block_bits,
50 unsigned *aligned_pitch, unsigned *aligned_height)
51 {
52 unsigned align_bits = block_bits - elem_bits;
53 unsigned w_align = 1 << (align_bits / 2 + align_bits % 2);
54 unsigned h_align = 1 << (align_bits / 2);
55
56 w = align(w, w_align);
57 h = align(h, h_align);
58
59 if (aligned_pitch)
60 *aligned_pitch = w;
61
62 if (aligned_height)
63 *aligned_height = h;
64 return ((uint64_t)w * h) >> align_bits;
65 }
66
67
68 static ADDR2_COMPUTE_DCC_ADDRFROMCOORD_INPUT
gfx9_get_addr_from_coord_base(ADDR_HANDLE addrlib,const struct radeon_surf * surf,unsigned w,unsigned h,enum pipe_format format,bool rb_aligned,bool pipe_aligned)69 gfx9_get_addr_from_coord_base(ADDR_HANDLE addrlib, const struct radeon_surf *surf,
70 unsigned w, unsigned h, enum pipe_format format,
71 bool rb_aligned, bool pipe_aligned)
72 {
73 ADDR2_COMPUTE_DCCINFO_INPUT din = {0};
74 ADDR2_COMPUTE_DCCINFO_OUTPUT dout = {0};
75 din.size = sizeof(ADDR2_COMPUTE_DCCINFO_INPUT);
76 dout.size = sizeof(ADDR2_COMPUTE_DCCINFO_OUTPUT);
77
78 din.swizzleMode = surf->u.gfx9.swizzle_mode;
79 din.resourceType = ADDR_RSRC_TEX_2D;
80 din.bpp = util_format_get_blocksizebits(format);
81 din.unalignedWidth = w;
82 din.unalignedHeight = h;
83 din.numSlices = 1;
84 din.numMipLevels = 1;
85 din.numFrags = 1;
86 din.dccKeyFlags.pipeAligned = surf->u.gfx9.color.dcc.pipe_aligned;
87 din.dccKeyFlags.rbAligned = surf->u.gfx9.color.dcc.rb_aligned;
88 din.dataSurfaceSize = surf->surf_size;
89
90 ADDR_E_RETURNCODE ret = Addr2ComputeDccInfo(addrlib, &din, &dout);
91 assert(ret == ADDR_OK);
92
93 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_INPUT dcc_input = {0};
94 dcc_input.size = sizeof(dcc_input);
95 dcc_input.swizzleMode = surf->u.gfx9.swizzle_mode;
96 dcc_input.resourceType = ADDR_RSRC_TEX_2D;
97 dcc_input.bpp = din.bpp;
98 dcc_input.numSlices = 1;
99 dcc_input.numMipLevels = 1;
100 dcc_input.numFrags = 1;
101 dcc_input.dccKeyFlags.pipeAligned = pipe_aligned;
102 dcc_input.dccKeyFlags.rbAligned = rb_aligned;
103 dcc_input.pitch = dout.pitch;
104 dcc_input.height = dout.height;
105 dcc_input.compressBlkWidth = dout.compressBlkWidth;
106 dcc_input.compressBlkHeight = dout.compressBlkHeight;
107 dcc_input.compressBlkDepth = dout.compressBlkDepth;
108 dcc_input.metaBlkWidth = dout.metaBlkWidth;
109 dcc_input.metaBlkHeight = dout.metaBlkHeight;
110 dcc_input.metaBlkDepth = dout.metaBlkDepth;
111 return dcc_input;
112 }
113
gfx9_generate_hash(struct ac_addrlib * ac_addrlib,struct test_entry * entry,const struct radeon_surf * surf)114 static void gfx9_generate_hash(struct ac_addrlib *ac_addrlib,
115 struct test_entry *entry,
116 const struct radeon_surf *surf)
117 {
118 ADDR_HANDLE addrlib = ac_addrlib_get_handle(ac_addrlib);
119
120 srandom(53);
121 struct mesa_sha1 ctx;
122 _mesa_sha1_init(&ctx);
123
124 _mesa_sha1_update(&ctx, &surf->total_size, sizeof(surf->total_size));
125 _mesa_sha1_update(&ctx, &surf->meta_offset, sizeof(surf->meta_offset));
126 _mesa_sha1_update(&ctx, &surf->display_dcc_offset, sizeof(surf->display_dcc_offset));
127 _mesa_sha1_update(&ctx, &surf->u.gfx9.color.display_dcc_pitch_max,
128 sizeof(surf->u.gfx9.color.display_dcc_pitch_max));
129
130 ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT input = {0};
131 input.size = sizeof(input);
132 input.swizzleMode = surf->u.gfx9.swizzle_mode;
133 input.resourceType = ADDR_RSRC_TEX_2D;
134 input.bpp = util_format_get_blocksizebits(entry->format);
135 input.unalignedWidth = entry->w;
136 input.unalignedHeight = entry->h;
137 input.numSlices = 1;
138 input.numMipLevels = 1;
139 input.numSamples = 1;
140 input.numFrags = 1;
141 input.pitchInElement = surf->u.gfx9.surf_pitch;
142
143 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_INPUT dcc_input = {0};
144 if (surf->meta_offset) {
145 dcc_input = gfx9_get_addr_from_coord_base(addrlib, surf, entry->w,
146 entry->h, entry->format,
147 surf->u.gfx9.color.dcc.rb_aligned,
148 surf->u.gfx9.color.dcc.pipe_aligned);
149 }
150
151 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_INPUT display_dcc_input = {0};
152 if (surf->display_dcc_offset) {
153 display_dcc_input = gfx9_get_addr_from_coord_base(addrlib, surf, entry->w,
154 entry->h, entry->format,
155 false, false);
156 }
157
158 for (unsigned i = 0; i < 1000; ++i) {
159 int32_t x, y;
160 x = random();
161 y = random();
162
163 input.x = (x & INT_MAX) % entry->w;
164 input.y = (y & INT_MAX) % entry->h;
165
166 ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT output = {0};
167 output.size = sizeof(output);
168
169 ADDR_E_RETURNCODE ret = Addr2ComputeSurfaceAddrFromCoord(addrlib, &input, &output);
170 assert(ret == ADDR_OK);
171
172 _mesa_sha1_update(&ctx, &output.addr, sizeof(output.addr));
173
174 if (surf->meta_offset) {
175 dcc_input.x = (x & INT_MAX) % entry->w;
176 dcc_input.y = (y & INT_MAX) % entry->h;
177
178 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_OUTPUT dcc_output = {0};
179 dcc_output.size = sizeof(dcc_output);
180
181 ret = Addr2ComputeDccAddrFromCoord(addrlib, &dcc_input, &dcc_output);
182 assert(ret == ADDR_OK);
183
184 _mesa_sha1_update(&ctx, &dcc_output.addr, sizeof(dcc_output.addr));
185 }
186
187 if (surf->display_dcc_offset) {
188 display_dcc_input.x = (x & INT_MAX) % entry->w;
189 display_dcc_input.y = (y & INT_MAX) % entry->h;
190
191 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_OUTPUT dcc_output = {0};
192 dcc_output.size = sizeof(dcc_output);
193
194 ret = Addr2ComputeDccAddrFromCoord(addrlib, &display_dcc_input, &dcc_output);
195 assert(ret == ADDR_OK);
196
197 _mesa_sha1_update(&ctx, &dcc_output.addr, sizeof(dcc_output.addr));
198 }
199 }
200
201 _mesa_sha1_final(&ctx, entry->hash);
202 }
203
gfx12_generate_hash(struct ac_addrlib * ac_addrlib,struct test_entry * entry,const struct radeon_surf * surf)204 static void gfx12_generate_hash(struct ac_addrlib *ac_addrlib,
205 struct test_entry *entry,
206 const struct radeon_surf *surf)
207 {
208 ADDR_HANDLE addrlib = ac_addrlib_get_handle(ac_addrlib);
209
210 srandom(53);
211 struct mesa_sha1 ctx;
212 _mesa_sha1_init(&ctx);
213
214 _mesa_sha1_update(&ctx, &surf->total_size, sizeof(surf->total_size));
215 /* We need to hash these even though they are not used by gfx12. */
216 _mesa_sha1_update(&ctx, &surf->meta_offset, sizeof(surf->meta_offset));
217 _mesa_sha1_update(&ctx, &surf->display_dcc_offset, sizeof(surf->display_dcc_offset));
218 _mesa_sha1_update(&ctx, &surf->u.gfx9.color.display_dcc_pitch_max,
219 sizeof(surf->u.gfx9.color.display_dcc_pitch_max));
220
221 ADDR3_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT input = {0};
222 input.size = sizeof(input);
223 input.swizzleMode = surf->u.gfx9.swizzle_mode;
224 input.resourceType = ADDR_RSRC_TEX_2D;
225 input.bpp = util_format_get_blocksizebits(entry->format);
226 input.unAlignedDims.width = entry->w;
227 input.unAlignedDims.height = entry->h;
228 input.unAlignedDims.depth = 1;
229 input.numMipLevels = 1;
230 input.numSamples = 1;
231 input.pitchInElement = surf->u.gfx9.surf_pitch;
232
233 for (unsigned i = 0; i < 1000; ++i) {
234 int32_t x, y;
235 x = random();
236 y = random();
237
238 input.x = (x & INT_MAX) % entry->w;
239 input.y = (y & INT_MAX) % entry->h;
240
241 ADDR3_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT output = {0};
242 output.size = sizeof(output);
243
244 ADDR_E_RETURNCODE ret = Addr3ComputeSurfaceAddrFromCoord(addrlib, &input, &output);
245 assert(ret == ADDR_OK);
246
247 _mesa_sha1_update(&ctx, &output.addr, sizeof(output.addr));
248 }
249
250 _mesa_sha1_final(&ctx, entry->hash);
251 }
252
test_modifier(const struct radeon_info * info,const char * name,struct ac_addrlib * addrlib,uint64_t modifier,enum pipe_format format,struct u_vector * test_entries)253 static void test_modifier(const struct radeon_info *info,
254 const char *name,
255 struct ac_addrlib *addrlib,
256 uint64_t modifier,
257 enum pipe_format format,
258 struct u_vector *test_entries)
259 {
260 unsigned elem_bits = util_logbase2(util_format_get_blocksize(format));
261 const unsigned dims[][2] = {
262 {1, 1},
263 {1920, 1080},
264 {1366, 768},
265 {3840, 2160},
266 {233, 938},
267 };
268 for (unsigned i = 0; i < ARRAY_SIZE(dims); ++i) {
269 struct ac_surf_config config = (struct ac_surf_config) {
270 .info = (struct ac_surf_info) {
271 .width = dims[i][0],
272 .height = dims[i][1],
273 .depth = 1,
274 .samples = 1,
275 .storage_samples = 1,
276 .levels = 1,
277 .num_channels = 3,
278 .array_size = 1
279 },
280 };
281
282 struct test_entry entry = {
283 .modifier = modifier,
284 .w = config.info.width,
285 .h = config.info.height,
286 .format = format,
287 .name = name,
288 .pipes = G_0098F8_NUM_PIPES(info->gb_addr_config),
289 .rb = G_0098F8_NUM_RB_PER_SE(info->gb_addr_config) +
290 G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config),
291 .se = G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config),
292 .banks_or_pkrs = info->gfx_level >= GFX10 ?
293 G_0098F8_NUM_PKRS(info->gb_addr_config) : G_0098F8_NUM_BANKS(info->gb_addr_config)
294 };
295
296 struct radeon_surf surf = (struct radeon_surf) {
297 .blk_w = 1,
298 .blk_h = 1,
299 .bpe = util_format_get_blocksize(format),
300 .modifier = modifier,
301 };
302
303 int r = ac_compute_surface(addrlib, info, &config, RADEON_SURF_MODE_2D, &surf);
304 assert(!r);
305
306 assert(surf.cmask_offset == 0);
307 assert(surf.fmask_offset == 0);
308
309 uint64_t surf_size;
310 unsigned aligned_pitch, aligned_height;
311 unsigned block_size_bits = 0;
312 if (modifier != DRM_FORMAT_MOD_LINEAR) {
313 if (info->gfx_level >= GFX12) {
314 switch (surf.u.gfx9.swizzle_mode) {
315 case ADDR3_256B_2D:
316 block_size_bits = 8;
317 break;
318 case ADDR3_4KB_2D:
319 block_size_bits = 12;
320 break;
321 case ADDR3_64KB_2D:
322 block_size_bits = 16;
323 break;
324 case ADDR3_256KB_2D:
325 block_size_bits = 18;
326 break;
327 default:
328 unreachable("invalid swizzle mode");
329 }
330 } else {
331 switch (surf.u.gfx9.swizzle_mode) {
332 case ADDR_SW_256B_S:
333 case ADDR_SW_256B_D:
334 case ADDR_SW_256B_R:
335 block_size_bits = 8;
336 break;
337 case ADDR_SW_4KB_Z:
338 case ADDR_SW_4KB_S:
339 case ADDR_SW_4KB_D:
340 case ADDR_SW_4KB_R:
341 case ADDR_SW_4KB_Z_X:
342 case ADDR_SW_4KB_S_X:
343 case ADDR_SW_4KB_D_X:
344 case ADDR_SW_4KB_R_X:
345 block_size_bits = 12;
346 break;
347 case ADDR_SW_64KB_Z:
348 case ADDR_SW_64KB_S:
349 case ADDR_SW_64KB_D:
350 case ADDR_SW_64KB_R:
351 case ADDR_SW_64KB_Z_T:
352 case ADDR_SW_64KB_S_T:
353 case ADDR_SW_64KB_D_T:
354 case ADDR_SW_64KB_R_T:
355 case ADDR_SW_64KB_Z_X:
356 case ADDR_SW_64KB_S_X:
357 case ADDR_SW_64KB_D_X:
358 case ADDR_SW_64KB_R_X:
359 block_size_bits = 16;
360 break;
361 case ADDR_SW_256KB_Z_X:
362 case ADDR_SW_256KB_S_X:
363 case ADDR_SW_256KB_D_X:
364 case ADDR_SW_256KB_R_X:
365 block_size_bits = 18;
366 break;
367 default:
368 unreachable("invalid swizzle mode");
369 }
370 }
371
372 surf_size = block_count(dims[i][0], dims[i][1],
373 elem_bits, block_size_bits, &aligned_pitch,
374 &aligned_height) << block_size_bits;
375 } else {
376 unsigned alignment = 256;
377
378 aligned_pitch = align(dims[i][0], alignment / util_format_get_blocksize(format));
379 aligned_height = dims[i][1];
380 surf_size = align(dims[i][0] * util_format_get_blocksize(format), alignment) * dims[i][1];
381 }
382
383 assert(surf.u.gfx9.surf_pitch == aligned_pitch);
384 assert(surf.u.gfx9.surf_height == aligned_height);
385 assert(surf.surf_size == surf_size);
386 uint64_t expected_offset = surf_size;
387
388 if (ac_modifier_has_dcc_retile(modifier)) {
389 unsigned dcc_align = info->gfx_level >= GFX10 ? 4096 : 65536;
390 unsigned dcc_pitch;
391 uint64_t dcc_size = block_count(dims[i][0], dims[i][1],
392 elem_bits, 20, &dcc_pitch,
393 NULL) << 12;
394
395 assert(surf.u.gfx9.color.display_dcc_size == align(dcc_size, dcc_align));
396 assert(surf.u.gfx9.color.display_dcc_pitch_max + 1 == dcc_pitch);
397 assert(surf.display_dcc_offset == expected_offset);
398
399 expected_offset += align(dcc_size, dcc_align);
400 } else
401 assert(!surf.display_dcc_offset);
402
403 if (info->gfx_level < GFX12 && ac_modifier_has_dcc(modifier)) {
404 uint64_t dcc_align = 1;
405 unsigned block_bits;
406 if (info->gfx_level >= GFX10) {
407 unsigned num_pipes = G_0098F8_NUM_PIPES(info->gb_addr_config);
408 if (info->gfx_level >= GFX10_3 &&
409 G_0098F8_NUM_PKRS(info->gb_addr_config) == num_pipes && num_pipes > 1)
410 ++num_pipes;
411 block_bits = 16 +
412 num_pipes +
413 G_0098F8_PIPE_INTERLEAVE_SIZE_GFX9(info->gb_addr_config);
414 block_bits = MAX2(block_bits, 20);
415 dcc_align = MAX2(4096, 256 <<
416 (num_pipes +
417 G_0098F8_PIPE_INTERLEAVE_SIZE_GFX9(info->gb_addr_config)));
418 } else {
419 unsigned num_se = G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config);
420 unsigned num_rb_per_se = G_0098F8_NUM_RB_PER_SE(info->gb_addr_config);
421 unsigned num_rb = num_se + num_rb_per_se;
422 unsigned num_pipes = G_0098F8_NUM_PIPES(info->gb_addr_config) + num_se;
423 block_bits = 18 + num_rb;
424 block_bits = MAX2(block_bits, 20);
425 dcc_align = 1 << MAX2(block_size_bits,
426 MIN2(num_pipes, block_size_bits - 8) + num_rb + 8);
427 }
428
429 expected_offset = align(expected_offset, dcc_align);
430 assert(surf.meta_offset == expected_offset);
431
432 uint64_t dcc_size = block_count(dims[i][0], dims[i][1],
433 elem_bits, block_bits,
434 NULL, NULL) << (block_bits - 8);
435 dcc_size = align64(dcc_size, dcc_align);
436 assert(surf.meta_size == dcc_size);
437
438 expected_offset += dcc_size;
439 } else
440 assert(!surf.meta_offset);
441
442 assert(surf.total_size == expected_offset);
443
444 if (info->gfx_level >= GFX12)
445 gfx12_generate_hash(addrlib, &entry, &surf);
446 else
447 gfx9_generate_hash(addrlib, &entry, &surf);
448
449 *(struct test_entry*)u_vector_add(test_entries) = entry;
450 }
451 }
452
run_modifier_test(struct u_vector * test_entries,const char * name,const struct radeon_info * info)453 static void run_modifier_test(struct u_vector *test_entries, const char *name,
454 const struct radeon_info *info)
455 {
456 struct ac_addrlib *addrlib = ac_addrlib_create(info, NULL);
457 assert(addrlib);
458
459 const struct ac_modifier_options options = {
460 .dcc = true,
461 .dcc_retile = true,
462 };
463
464 enum pipe_format formats[] = {
465 PIPE_FORMAT_R8_UNORM,
466 PIPE_FORMAT_R16_UNORM,
467 PIPE_FORMAT_R32_FLOAT,
468 PIPE_FORMAT_R32G32_FLOAT,
469 PIPE_FORMAT_R32G32B32A32_FLOAT
470 };
471 for (unsigned j = 0; j < ARRAY_SIZE(formats); ++j) {
472 unsigned mod_count = 0;
473 ac_get_supported_modifiers(info, &options, formats[j], &mod_count, NULL);
474
475 uint64_t *modifiers = malloc(sizeof(uint64_t) * mod_count);
476 ac_get_supported_modifiers(info, &options, formats[j], &mod_count, modifiers);
477
478 for (unsigned i = 0; i < mod_count; ++i) {
479 test_modifier(info, name, addrlib, modifiers[i], formats[j], test_entries);
480 }
481
482 free(modifiers);
483 }
484 ac_addrlib_destroy(addrlib);
485 }
486
compare_test_entry(const void * a,const void * b)487 static int compare_test_entry(const void *a, const void *b)
488 {
489 return memcmp(a, b, sizeof(struct test_entry));
490 }
491
test_entry_key_equal(const struct test_entry * a,const struct test_entry * b)492 static bool test_entry_key_equal(const struct test_entry *a, const struct test_entry *b)
493 {
494 return a->modifier == b->modifier && a->w == b->w && a->h == b->h && a->format == b->format;
495 }
496
test_entry_value_equal(const struct test_entry * a,const struct test_entry * b)497 static bool test_entry_value_equal(const struct test_entry *a, const struct test_entry *b)
498 {
499 if (memcmp(a->hash, b->hash, sizeof(a->hash)))
500 return false;
501 return true;
502 }
503
print_test_entry(const struct test_entry * e)504 static void print_test_entry(const struct test_entry *e)
505 {
506 fprintf(stderr, "%.16" PRIx64 " %.4d %.4d %.2d %s %d %d %d %d\n", e->modifier, e->w, e->h,
507 util_format_get_blocksize(e->format), e->name, e->pipes, e->rb, e->se, e->banks_or_pkrs);
508 }
509
main()510 int main()
511 {
512 STATIC_ASSERT(sizeof(struct test_entry) == 64);
513
514 struct u_vector test_entries;
515 u_vector_init_pow2(&test_entries, 64, sizeof(struct test_entry));
516
517 for (unsigned i = 0; i < ARRAY_SIZE(ac_fake_hw_db); ++i) {
518 struct radeon_info info = { .drm_major = 0 };
519
520 get_radeon_info(&info, &ac_fake_hw_db[i]);
521
522 run_modifier_test(&test_entries, ac_fake_hw_db[i].name, &info);
523 }
524
525 qsort(u_vector_tail(&test_entries),
526 u_vector_length(&test_entries),
527 sizeof(struct test_entry),
528 compare_test_entry);
529
530 struct test_entry *cur, *prev = NULL, *prevprev = NULL;
531 bool mismatched_duplicates = false;
532 u_vector_foreach(cur, &test_entries) {
533 if (prev && test_entry_key_equal(cur, prev) &&
534 !test_entry_value_equal(cur, prev)) {
535 if (!prevprev || !test_entry_key_equal(prev, prevprev)) {
536 print_test_entry(prev);
537 }
538 print_test_entry(cur);
539 mismatched_duplicates = true;
540 }
541 prevprev = prev;
542 prev = cur;
543 }
544 assert(!mismatched_duplicates);
545
546 u_vector_finish(&test_entries);
547
548 return 0;
549 }
550