• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_surface_test_common.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 
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)204 static void test_modifier(const struct radeon_info *info,
205                           const char *name,
206                           struct ac_addrlib *addrlib,
207                           uint64_t modifier,
208                           enum pipe_format format,
209                           struct u_vector *test_entries)
210 {
211    unsigned elem_bits = util_logbase2(util_format_get_blocksize(format));
212    const unsigned dims[][2] = {
213       {1, 1},
214       {1920, 1080},
215       {1366, 768},
216       {3840, 2160},
217       {233, 938},
218    };
219    for (unsigned i = 0; i < ARRAY_SIZE(dims); ++i) {
220       struct ac_surf_config config = (struct ac_surf_config) {
221          .info = (struct ac_surf_info) {
222             .width = dims[i][0],
223             .height = dims[i][1],
224             .depth = 1,
225             .samples = 1,
226             .storage_samples = 1,
227             .levels = 1,
228             .num_channels = 3,
229             .array_size = 1
230          },
231       };
232 
233       struct test_entry entry = {
234          .modifier = modifier,
235          .w = config.info.width,
236          .h = config.info.height,
237          .format = format,
238          .name = name,
239          .pipes = G_0098F8_NUM_PIPES(info->gb_addr_config),
240          .rb = G_0098F8_NUM_RB_PER_SE(info->gb_addr_config) +
241                G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config),
242          .se = G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config),
243          .banks_or_pkrs = info->gfx_level >= GFX10 ?
244             G_0098F8_NUM_PKRS(info->gb_addr_config) : G_0098F8_NUM_BANKS(info->gb_addr_config)
245       };
246 
247       struct radeon_surf surf = (struct radeon_surf) {
248          .blk_w = 1,
249          .blk_h = 1,
250          .bpe = util_format_get_blocksize(format),
251          .modifier = modifier,
252       };
253 
254       int r = ac_compute_surface(addrlib, info, &config, RADEON_SURF_MODE_2D, &surf);
255       assert(!r);
256 
257       assert(surf.cmask_offset == 0);
258       assert(surf.fmask_offset == 0);
259 
260       uint64_t surf_size;
261       unsigned aligned_pitch, aligned_height;
262       if (modifier != DRM_FORMAT_MOD_LINEAR) {
263          unsigned block_size_bits =
264             surf.u.gfx9.swizzle_mode >= ADDR_SW_256KB_Z_X ? 18 : 16;
265 
266          surf_size = block_count(dims[i][0], dims[i][1],
267                   elem_bits, block_size_bits, &aligned_pitch,
268                   &aligned_height) << block_size_bits;
269       } else {
270          unsigned alignment = 256;
271 
272          aligned_pitch = align(dims[i][0], alignment / util_format_get_blocksize(format));
273          aligned_height = dims[i][1];
274          surf_size = align(dims[i][0] * util_format_get_blocksize(format), alignment) * dims[i][1];
275       }
276 
277       assert(surf.u.gfx9.surf_pitch == aligned_pitch);
278       assert(surf.u.gfx9.surf_height == aligned_height);
279       assert(surf.surf_size == surf_size);
280       uint64_t expected_offset = surf_size;
281 
282       if (ac_modifier_has_dcc_retile(modifier)) {
283          unsigned dcc_align = info->gfx_level >= GFX10 ? 4096 : 65536;
284          unsigned dcc_pitch;
285          uint64_t dcc_size = block_count(dims[i][0], dims[i][1],
286                      elem_bits, 20, &dcc_pitch,
287                      NULL) << 12;
288 
289          assert(surf.u.gfx9.color.display_dcc_size == align(dcc_size, dcc_align));
290          assert(surf.u.gfx9.color.display_dcc_pitch_max + 1 == dcc_pitch);
291          assert(surf.display_dcc_offset == expected_offset);
292 
293          expected_offset += align(dcc_size, dcc_align);
294       } else
295          assert(!surf.display_dcc_offset);
296 
297       if (ac_modifier_has_dcc(modifier)) {
298          uint64_t dcc_align = 1;
299          unsigned block_bits;
300          if (info->gfx_level >= GFX10) {
301             unsigned num_pipes = G_0098F8_NUM_PIPES(info->gb_addr_config);
302             if (info->gfx_level >= GFX10_3 &&
303                 G_0098F8_NUM_PKRS(info->gb_addr_config) == num_pipes && num_pipes > 1)
304                ++num_pipes;
305             block_bits = 16 +
306                num_pipes +
307                G_0098F8_PIPE_INTERLEAVE_SIZE_GFX9(info->gb_addr_config);
308             block_bits = MAX2(block_bits, 20);
309             dcc_align = MAX2(4096, 256 <<
310                                   (num_pipes +
311                                    G_0098F8_PIPE_INTERLEAVE_SIZE_GFX9(info->gb_addr_config)));
312          } else {
313             block_bits = 18 +
314                G_0098F8_NUM_RB_PER_SE(info->gb_addr_config) +
315                G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config);
316             block_bits = MAX2(block_bits, 20);
317             dcc_align = 65536;
318          }
319 
320          expected_offset = align(expected_offset, dcc_align);
321          assert(surf.meta_offset == expected_offset);
322 
323          uint64_t dcc_size = block_count(dims[i][0], dims[i][1],
324                      elem_bits, block_bits,
325                      NULL, NULL) << (block_bits - 8);
326          dcc_size = align64(dcc_size, dcc_align);
327          assert(surf.meta_size == dcc_size);
328 
329          expected_offset += dcc_size;
330       } else
331          assert(!surf.meta_offset);
332 
333       assert(surf.total_size == expected_offset);
334 
335       gfx9_generate_hash(addrlib, &entry, &surf);
336       *(struct test_entry*)u_vector_add(test_entries) = entry;
337    }
338 }
339 
run_modifier_test(struct u_vector * test_entries,const char * name,const struct radeon_info * info)340 static void run_modifier_test(struct u_vector *test_entries, const char *name,
341                                   const struct radeon_info *info)
342 {
343    struct ac_addrlib *addrlib = ac_addrlib_create(info, NULL);
344    assert(addrlib);
345 
346    const struct ac_modifier_options options = {
347       .dcc = true,
348       .dcc_retile = true,
349    };
350 
351    enum pipe_format formats[] = {
352       PIPE_FORMAT_R8_UNORM,
353       PIPE_FORMAT_R16_UNORM,
354       PIPE_FORMAT_R32_FLOAT,
355       PIPE_FORMAT_R32G32_FLOAT,
356       PIPE_FORMAT_R32G32B32A32_FLOAT
357    };
358    for (unsigned j = 0; j < ARRAY_SIZE(formats); ++j) {
359       unsigned mod_count = 0;
360       ac_get_supported_modifiers(info, &options, formats[j], &mod_count, NULL);
361 
362       uint64_t *modifiers = malloc(sizeof(uint64_t) * mod_count);
363       ac_get_supported_modifiers(info, &options, formats[j], &mod_count, modifiers);
364 
365       for (unsigned i = 0; i < mod_count; ++i) {
366          test_modifier(info, name, addrlib, modifiers[i], formats[j], test_entries);
367       }
368 
369       free(modifiers);
370    }
371    ac_addrlib_destroy(addrlib);
372 }
373 
compare_test_entry(const void * a,const void * b)374 static int compare_test_entry(const void *a, const void *b)
375 {
376    return memcmp(a, b, sizeof(struct test_entry));
377 }
378 
test_entry_key_equal(const struct test_entry * a,const struct test_entry * b)379 static bool test_entry_key_equal(const struct test_entry *a, const struct test_entry *b)
380 {
381    return a->modifier == b->modifier && a->w == b->w && a->h == b->h && a->format == b->format;
382 }
383 
test_entry_value_equal(const struct test_entry * a,const struct test_entry * b)384 static bool test_entry_value_equal(const struct test_entry *a, const struct test_entry *b)
385 {
386    if (memcmp(a->hash, b->hash, sizeof(a->hash)))
387       return false;
388    return true;
389 }
390 
print_test_entry(const struct test_entry * e)391 static void print_test_entry(const struct test_entry *e)
392 {
393    fprintf(stderr, "%.16" PRIx64 " %.4d %.4d %.2d %s %d %d %d %d\n", e->modifier, e->w, e->h,
394            util_format_get_blocksize(e->format), e->name, e->pipes, e->rb, e->se, e->banks_or_pkrs);
395 }
396 
main()397 int main()
398 {
399    STATIC_ASSERT(sizeof(struct test_entry) == 64);
400 
401    struct u_vector test_entries;
402    u_vector_init_pow2(&test_entries, 64, sizeof(struct test_entry));
403 
404    for (unsigned i = 0; i < ARRAY_SIZE(testcases); ++i) {
405       struct radeon_info info = get_radeon_info(&testcases[i]);
406 
407       run_modifier_test(&test_entries, testcases[i].name, &info);
408    }
409 
410    qsort(u_vector_tail(&test_entries),
411          u_vector_length(&test_entries),
412          sizeof(struct test_entry),
413          compare_test_entry);
414 
415    struct test_entry *cur, *prev = NULL, *prevprev = NULL;
416    bool mismatched_duplicates = false;
417    u_vector_foreach(cur, &test_entries) {
418       if (prev && test_entry_key_equal(cur, prev) &&
419           !test_entry_value_equal(cur, prev)) {
420          if (!prevprev || !test_entry_key_equal(prev, prevprev)) {
421             print_test_entry(prev);
422          }
423          print_test_entry(cur);
424          mismatched_duplicates = true;
425       }
426       prevprev = prev;
427       prev = cur;
428    }
429    assert(!mismatched_duplicates);
430 
431    u_vector_finish(&test_entries);
432 
433    return 0;
434 }
435