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 27struct 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 48static uint64_t 49block_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 68static ADDR2_COMPUTE_DCC_ADDRFROMCOORD_INPUT 69get_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 114static 115void generate_hash(struct ac_addrlib *ac_addrlib, 116 struct test_entry *entry, 117 const struct radeon_surf *surf) 118{ 119 ADDR_HANDLE addrlib = ac_addrlib_get_handle(ac_addrlib); 120 121 srandom(53); 122 struct mesa_sha1 ctx; 123 _mesa_sha1_init(&ctx); 124 125 _mesa_sha1_update(&ctx, &surf->total_size, sizeof(surf->total_size)); 126 _mesa_sha1_update(&ctx, &surf->meta_offset, sizeof(surf->meta_offset)); 127 _mesa_sha1_update(&ctx, &surf->display_dcc_offset, sizeof(surf->display_dcc_offset)); 128 _mesa_sha1_update(&ctx, &surf->u.gfx9.color.display_dcc_pitch_max, 129 sizeof(surf->u.gfx9.color.display_dcc_pitch_max)); 130 131 ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT input = {0}; 132 input.size = sizeof(input); 133 input.swizzleMode = surf->u.gfx9.swizzle_mode; 134 input.resourceType = ADDR_RSRC_TEX_2D; 135 input.bpp = util_format_get_blocksizebits(entry->format); 136 input.unalignedWidth = entry->w; 137 input.unalignedHeight = entry->h; 138 input.numSlices = 1; 139 input.numMipLevels = 1; 140 input.numSamples = 1; 141 input.numFrags = 1; 142 input.pitchInElement = surf->u.gfx9.surf_pitch; 143 144 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_INPUT dcc_input = {0}; 145 if (surf->meta_offset) { 146 dcc_input = get_addr_from_coord_base(addrlib, surf, entry->w, 147 entry->h, entry->format, 148 surf->u.gfx9.color.dcc.rb_aligned, 149 surf->u.gfx9.color.dcc.pipe_aligned); 150 } 151 152 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_INPUT display_dcc_input = {0}; 153 if (surf->display_dcc_offset) { 154 display_dcc_input = get_addr_from_coord_base(addrlib, surf, entry->w, 155 entry->h, entry->format, 156 false, false); 157 } 158 159 for (unsigned i = 0; i < 1000; ++i) { 160 int32_t x, y; 161 x = random(); 162 y = random(); 163 164 input.x = (x & INT_MAX) % entry->w; 165 input.y = (y & INT_MAX) % entry->h; 166 167 ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT output = {0}; 168 output.size = sizeof(output); 169 170 ADDR_E_RETURNCODE ret = Addr2ComputeSurfaceAddrFromCoord(addrlib, &input, &output); 171 assert(ret == ADDR_OK); 172 173 _mesa_sha1_update(&ctx, &output.addr, sizeof(output.addr)); 174 175 if (surf->meta_offset) { 176 dcc_input.x = (x & INT_MAX) % entry->w; 177 dcc_input.y = (y & INT_MAX) % entry->h; 178 179 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_OUTPUT dcc_output = {0}; 180 dcc_output.size = sizeof(dcc_output); 181 182 ret = Addr2ComputeDccAddrFromCoord(addrlib, &dcc_input, &dcc_output); 183 assert(ret == ADDR_OK); 184 185 _mesa_sha1_update(&ctx, &dcc_output.addr, sizeof(dcc_output.addr)); 186 } 187 188 if (surf->display_dcc_offset) { 189 display_dcc_input.x = (x & INT_MAX) % entry->w; 190 display_dcc_input.y = (y & INT_MAX) % entry->h; 191 192 ADDR2_COMPUTE_DCC_ADDRFROMCOORD_OUTPUT dcc_output = {0}; 193 dcc_output.size = sizeof(dcc_output); 194 195 ret = Addr2ComputeDccAddrFromCoord(addrlib, &display_dcc_input, &dcc_output); 196 assert(ret == ADDR_OK); 197 198 _mesa_sha1_update(&ctx, &dcc_output.addr, sizeof(dcc_output.addr)); 199 } 200 } 201 202 _mesa_sha1_final(&ctx, entry->hash); 203} 204 205static void test_modifier(const struct radeon_info *info, 206 const char *name, 207 struct ac_addrlib *addrlib, 208 uint64_t modifier, 209 enum pipe_format format, 210 struct u_vector *test_entries) 211{ 212 unsigned elem_bits = util_logbase2(util_format_get_blocksize(format)); 213 const unsigned dims[][2] = { 214 {1, 1}, 215 {1920, 1080}, 216 {1366, 768}, 217 {3840, 2160}, 218 {233, 938}, 219 }; 220 for (unsigned i = 0; i < ARRAY_SIZE(dims); ++i) { 221 struct ac_surf_config config = (struct ac_surf_config) { 222 .info = (struct ac_surf_info) { 223 .width = dims[i][0], 224 .height = dims[i][1], 225 .depth = 1, 226 .samples = 1, 227 .storage_samples = 1, 228 .levels = 1, 229 .num_channels = 3, 230 .array_size = 1 231 }, 232 }; 233 234 struct test_entry entry = { 235 .modifier = modifier, 236 .w = config.info.width, 237 .h = config.info.height, 238 .format = format, 239 .name = name, 240 .pipes = G_0098F8_NUM_PIPES(info->gb_addr_config), 241 .rb = G_0098F8_NUM_RB_PER_SE(info->gb_addr_config) + 242 G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config), 243 .se = G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config), 244 .banks_or_pkrs = info->gfx_level >= GFX10 ? 245 G_0098F8_NUM_PKRS(info->gb_addr_config) : G_0098F8_NUM_BANKS(info->gb_addr_config) 246 }; 247 248 struct radeon_surf surf = (struct radeon_surf) { 249 .blk_w = 1, 250 .blk_h = 1, 251 .bpe = util_format_get_blocksize(format), 252 .modifier = modifier, 253 }; 254 255 int r = ac_compute_surface(addrlib, info, &config, RADEON_SURF_MODE_2D, &surf); 256 assert(!r); 257 258 assert(surf.cmask_offset == 0); 259 assert(surf.fmask_offset == 0); 260 261 unsigned block_size_bits = surf.u.gfx9.swizzle_mode >= ADDR_SW_256KB_Z_X ? 18 : 16; 262 263 uint64_t surf_size; 264 unsigned aligned_pitch, aligned_height; 265 if (modifier != DRM_FORMAT_MOD_LINEAR) { 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 aligned_pitch = align(dims[i][0], 256 / util_format_get_blocksize(format)); 271 aligned_height = dims[i][1]; 272 surf_size = align(dims[i][0] * util_format_get_blocksize(format), 256) * dims[i][1]; 273 } 274 275 276 assert(surf.u.gfx9.surf_pitch == aligned_pitch); 277 assert(surf.u.gfx9.surf_height == aligned_height); 278 assert(surf.surf_size == surf_size); 279 uint64_t expected_offset = surf_size; 280 281 if (ac_modifier_has_dcc_retile(modifier)) { 282 unsigned dcc_align = info->gfx_level >= GFX10 ? 4096 : 65536; 283 unsigned dcc_pitch; 284 uint64_t dcc_size = block_count(dims[i][0], dims[i][1], 285 elem_bits, 20, &dcc_pitch, 286 NULL) << 12; 287 288 assert(surf.u.gfx9.color.display_dcc_size == align(dcc_size, dcc_align)); 289 assert(surf.u.gfx9.color.display_dcc_pitch_max + 1 == dcc_pitch); 290 assert(surf.display_dcc_offset == expected_offset); 291 292 expected_offset += align(dcc_size, dcc_align); 293 } else 294 assert(!surf.display_dcc_offset); 295 296 if (ac_modifier_has_dcc(modifier)) { 297 uint64_t dcc_align = 1; 298 unsigned block_bits; 299 if (info->gfx_level >= GFX10) { 300 unsigned num_pipes = G_0098F8_NUM_PIPES(info->gb_addr_config); 301 if (info->gfx_level >= GFX10_3 && 302 G_0098F8_NUM_PKRS(info->gb_addr_config) == num_pipes && num_pipes > 1) 303 ++num_pipes; 304 block_bits = 16 + 305 num_pipes + 306 G_0098F8_PIPE_INTERLEAVE_SIZE_GFX9(info->gb_addr_config); 307 block_bits = MAX2(block_bits, 20); 308 dcc_align = MAX2(4096, 256 << 309 (num_pipes + 310 G_0098F8_PIPE_INTERLEAVE_SIZE_GFX9(info->gb_addr_config))); 311 } else { 312 block_bits = 18 + 313 G_0098F8_NUM_RB_PER_SE(info->gb_addr_config) + 314 G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config); 315 block_bits = MAX2(block_bits, 20); 316 dcc_align = 65536; 317 } 318 319 expected_offset = align(expected_offset, dcc_align); 320 assert(surf.meta_offset == expected_offset); 321 322 uint64_t dcc_size = block_count(dims[i][0], dims[i][1], 323 elem_bits, block_bits, 324 NULL, NULL) << (block_bits - 8); 325 dcc_size = align64(dcc_size, dcc_align); 326 assert(surf.meta_size == dcc_size); 327 328 expected_offset += dcc_size; 329 } else 330 assert(!surf.meta_offset); 331 332 assert(surf.total_size == expected_offset); 333 334 generate_hash(addrlib, &entry, &surf); 335 *(struct test_entry*)u_vector_add(test_entries) = entry; 336 } 337 338} 339 340static 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 374static int compare_test_entry(const void *a, const void *b) 375{ 376 return memcmp(a, b, sizeof(struct test_entry)); 377} 378 379static 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 384static 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 391static void print_test_entry(const struct test_entry *e) 392{ 393 printf("%.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 397int 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