From 4d78052321910e642a32daeac8189b55f4efdeb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sun, 14 Jul 2024 01:54:12 -0400 Subject: [PATCH] radeonsi: add correctness tests for the clear/copy_buffer compute shader Reviewed-by: Pierre-Eric Pelloux-Prayer Part-of: --- src/gallium/drivers/radeonsi/si_pipe.c | 11 +- src/gallium/drivers/radeonsi/si_pipe.h | 4 + .../drivers/radeonsi/si_test_dma_perf.c | 228 ++++++++++++++++++ 3 files changed, 241 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/radeonsi/si_pipe.c b/src/gallium/drivers/radeonsi/si_pipe.c index 22f42fc1c58..19149dc2c35 100644 --- a/src/gallium/drivers/radeonsi/si_pipe.c +++ b/src/gallium/drivers/radeonsi/si_pipe.c @@ -122,6 +122,8 @@ static const struct debug_named_value radeonsi_debug_options[] = { static const struct debug_named_value test_options[] = { /* Tests: */ + {"clearbuffer", DBG(TEST_CLEAR_BUFFER), "Test correctness of the clear_buffer compute shader"}, + {"copybuffer", DBG(TEST_COPY_BUFFER), "Test correctness of the copy_buffer compute shader"}, {"imagecopy", DBG(TEST_IMAGE_COPY), "Invoke resource_copy_region tests with images and exit."}, {"cbresolve", DBG(TEST_CB_RESOLVE), "Invoke MSAA resolve tests and exit."}, {"computeblit", DBG(TEST_COMPUTE_BLIT), "Invoke blits tests and exit."}, @@ -1498,15 +1500,20 @@ static struct pipe_screen *radeonsi_screen_create_impl(struct radeon_winsys *ws, } } + if (test_flags & DBG(TEST_CLEAR_BUFFER)) + si_test_clear_buffer(sscreen); + + if (test_flags & DBG(TEST_COPY_BUFFER)) + si_test_copy_buffer(sscreen); + if (test_flags & DBG(TEST_IMAGE_COPY)) si_test_image_copy_region(sscreen); if (test_flags & (DBG(TEST_CB_RESOLVE) | DBG(TEST_COMPUTE_BLIT))) si_test_blit(sscreen, test_flags); - if (test_flags & DBG(TEST_DMA_PERF)) { + if (test_flags & DBG(TEST_DMA_PERF)) si_test_dma_perf(sscreen); - } if (test_flags & DBG(TEST_MEM_PERF)) si_test_mem_perf(sscreen); diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h index fcdb83f506f..c37a2641d27 100644 --- a/src/gallium/drivers/radeonsi/si_pipe.h +++ b/src/gallium/drivers/radeonsi/si_pipe.h @@ -248,6 +248,8 @@ enum enum { /* Tests: */ + DBG_TEST_CLEAR_BUFFER, + DBG_TEST_COPY_BUFFER, DBG_TEST_IMAGE_COPY, DBG_TEST_CB_RESOLVE, DBG_TEST_COMPUTE_BLIT, @@ -1676,6 +1678,8 @@ void si_test_blit(struct si_screen *sscreen, unsigned test_flags); /* si_test_dma_perf.c */ void si_test_dma_perf(struct si_screen *sscreen); void si_test_mem_perf(struct si_screen *sscreen); +void si_test_clear_buffer(struct si_screen *sscreen); +void si_test_copy_buffer(struct si_screen *sscreen); /* si_test_blit_perf.c */ void si_test_blit_perf(struct si_screen *sscreen); diff --git a/src/gallium/drivers/radeonsi/si_test_dma_perf.c b/src/gallium/drivers/radeonsi/si_test_dma_perf.c index 4f6c2270260..25ca2c77c18 100644 --- a/src/gallium/drivers/radeonsi/si_test_dma_perf.c +++ b/src/gallium/drivers/radeonsi/si_test_dma_perf.c @@ -376,3 +376,231 @@ si_test_mem_perf(struct si_screen *sscreen) exit(0); } + +#define COLOR_RESET "\033[0m" +#define COLOR_RED "\033[1;31m" +#define COLOR_YELLOW "\033[1;33m" +#define COLOR_CYAN "\033[1;36m" + +void si_test_clear_buffer(struct si_screen *sscreen) +{ + struct pipe_screen *screen = &sscreen->b; + struct pipe_context *ctx = screen->context_create(screen, NULL, 0); + struct si_context *sctx = (struct si_context *)ctx; + unsigned buf_size = 32; + unsigned num_tests = 0, num_passes = 0; + + srand(0x9b47d95b); + + printf("dst, si,dw, %-*s, %-*s, %-*s, %-*s\n", + 32, "clear value", + buf_size * 2, "init dst", + buf_size * 2, "expected dst", + buf_size * 2, "observed dst"); + printf("off, ze,th\n"); + + /* Generate an infinite number of random tests. */ + while (1) { + struct pipe_resource *dst; + + dst = pipe_aligned_buffer_create(screen, 0, PIPE_USAGE_STAGING, buf_size, 256); + + unsigned clear_value_size = 1 << (rand() % 6); + if (clear_value_size == 32) + clear_value_size = 12; /* test only 1, 2, 4, 8, 16, and 12 */ + + uint8_t *clear_value = (uint8_t *)malloc(buf_size); + uint8_t *init_dst_buffer = (uint8_t *)malloc(buf_size); + uint8_t *expected_dst_buffer = (uint8_t *)malloc(buf_size); + uint8_t *read_dst_buffer = (uint8_t *)malloc(buf_size); + + for (unsigned i = 0; i < buf_size; i++) { + clear_value[i] = rand(); + init_dst_buffer[i] = rand(); + expected_dst_buffer[i] = rand(); + } + + pipe_buffer_write(ctx, dst, 0, buf_size, init_dst_buffer); + + unsigned op_size = (((rand() % buf_size) + 1) / clear_value_size) * clear_value_size; + if (!op_size) + op_size = clear_value_size; + + unsigned dst_offset = rand() % (buf_size - op_size + 1); + if (clear_value_size == 12) + dst_offset &= ~0x3; + + unsigned dwords_per_thread = 1 << (rand() % 3); + dwords_per_thread = MAX2(dwords_per_thread, DIV_ROUND_UP(clear_value_size, 4)); + + memcpy(expected_dst_buffer, init_dst_buffer, buf_size); + for (unsigned i = 0; i < op_size; i++) + expected_dst_buffer[dst_offset + i] = clear_value[i % clear_value_size]; + + printf(" %2u, %2u, %u, ", dst_offset, op_size, dwords_per_thread); + + /* Visualize the clear. */ + for (unsigned i = 0; i < clear_value_size; i++) + printf("%02x", clear_value[i]); + for (unsigned i = clear_value_size; i < 16; i++) + printf(" "); + + printf("%s, %s", COLOR_RESET, COLOR_CYAN); + for (unsigned i = 0; i < buf_size; i++) { + printf("%s%02x", + i < dst_offset || i >= dst_offset + op_size ? COLOR_CYAN : COLOR_RESET, + init_dst_buffer[i]); + } + printf("%s, ", COLOR_RESET); + for (unsigned i = 0; i < buf_size; i++) { + printf("%s%02x", + i >= dst_offset && i < dst_offset + op_size ? COLOR_YELLOW : COLOR_CYAN, + expected_dst_buffer[i]); + } + printf("%s, ", COLOR_RESET); + fflush(stdout); + + bool done = si_compute_clear_copy_buffer(sctx, dst, dst_offset, NULL, 0, op_size, + (uint32_t*)clear_value, clear_value_size, + SI_OP_SYNC_BEFORE_AFTER, SI_COHERENCY_SHADER, + dwords_per_thread, false); + + if (done) { + pipe_buffer_read(ctx, dst, 0, buf_size, read_dst_buffer); + bool success = !memcmp(read_dst_buffer, expected_dst_buffer, buf_size); + + num_tests++; + if (success) + num_passes++; + + for (unsigned i = 0; i < buf_size; i++) { + printf("%s%02x", + read_dst_buffer[i] != expected_dst_buffer[i] ? COLOR_RED : + i >= dst_offset && i < dst_offset + op_size ? COLOR_YELLOW : COLOR_CYAN, + read_dst_buffer[i]); + } + + printf("%s, %s [%u/%u]\n", COLOR_RESET, success ? "pass" : "fail", num_passes, num_tests); + } else { + printf("%*s, skip [%u/%u]\n", buf_size * 2, "", num_passes, num_tests); + } + + free(clear_value); + free(init_dst_buffer); + free(expected_dst_buffer); + free(read_dst_buffer); + pipe_resource_reference(&dst, NULL); + } + + ctx->destroy(ctx); + exit(0); +} + +void si_test_copy_buffer(struct si_screen *sscreen) +{ + struct pipe_screen *screen = &sscreen->b; + struct pipe_context *ctx = screen->context_create(screen, NULL, 0); + struct si_context *sctx = (struct si_context *)ctx; + unsigned buf_size = 32; + unsigned num_tests = 0, num_passes = 0; + + srand(0x9b47d95b); + + printf("src,dst, si,dw, %-*s, %-*s, %-*s, %-*s\n", + MIN2(buf_size, 32) * 2, "init src", + MIN2(buf_size, 32) * 2, "init dst", + MIN2(buf_size, 32) * 2, "expected dst", + MIN2(buf_size, 32) * 2, "observed dst"); + printf("off,off, ze,th\n"); + + /* Generate an infinite number of random tests. */ + while (1) { + struct pipe_resource *dst, *src; + + dst = pipe_aligned_buffer_create(screen, 0, PIPE_USAGE_STAGING, buf_size, 256); + src = pipe_aligned_buffer_create(screen, 0, PIPE_USAGE_STAGING, buf_size, 256); + + uint8_t *init_src_buffer = (uint8_t *)malloc(buf_size); + uint8_t *init_dst_buffer = (uint8_t *)malloc(buf_size); + uint8_t *expected_dst_buffer = (uint8_t *)malloc(buf_size); + uint8_t *read_dst_buffer = (uint8_t *)malloc(buf_size); + + for (unsigned i = 0; i < buf_size; i++) { + init_src_buffer[i] = rand(); + init_dst_buffer[i] = rand(); + } + + pipe_buffer_write(ctx, src, 0, buf_size, init_src_buffer); + pipe_buffer_write(ctx, dst, 0, buf_size, init_dst_buffer); + + unsigned dst_offset = rand() % buf_size; + unsigned op_size = (rand() % (buf_size - dst_offset)) + 1; + unsigned src_offset = rand() % (buf_size - op_size + 1); + unsigned dwords_per_thread = 1 << (rand() % 3); + + memcpy(expected_dst_buffer, init_dst_buffer, buf_size); + memcpy(expected_dst_buffer + dst_offset, init_src_buffer + src_offset, op_size); + + printf(" %2u, %2u, %2u, %u, ", src_offset, dst_offset, op_size, dwords_per_thread); + + if (buf_size <= 32) { + /* Visualize the copy. */ + for (unsigned i = 0; i < buf_size; i++) { + printf("%s%02x", + i >= src_offset && i < src_offset + op_size ? COLOR_YELLOW : COLOR_RESET, + init_src_buffer[i]); + } + printf("%s, %s", COLOR_RESET, COLOR_CYAN); + for (unsigned i = 0; i < buf_size; i++) { + printf("%s%02x", + i < dst_offset || i >= dst_offset + op_size ? COLOR_CYAN : COLOR_RESET, + init_dst_buffer[i]); + } + printf("%s, ", COLOR_RESET); + for (unsigned i = 0; i < buf_size; i++) { + printf("%s%02x", + i >= dst_offset && i < dst_offset + op_size ? COLOR_YELLOW : COLOR_CYAN, + expected_dst_buffer[i]); + } + printf("%s, ", COLOR_RESET); + } + fflush(stdout); + + bool done = si_compute_clear_copy_buffer(sctx, dst, dst_offset, src, src_offset, op_size, + NULL, 0, SI_OP_SYNC_BEFORE_AFTER, + SI_COHERENCY_SHADER, dwords_per_thread, false); + + if (done) { + pipe_buffer_read(ctx, dst, 0, buf_size, read_dst_buffer); + bool success = !memcmp(read_dst_buffer, expected_dst_buffer, buf_size); + + num_tests++; + if (success) + num_passes++; + + if (buf_size <= 32) { + for (unsigned i = 0; i < buf_size; i++) { + printf("%s%02x", + read_dst_buffer[i] != expected_dst_buffer[i] ? COLOR_RED : + i >= dst_offset && i < dst_offset + op_size ? COLOR_YELLOW : COLOR_CYAN, + read_dst_buffer[i]); + } + printf("%s, ", COLOR_RESET); + } + + printf("%s [%u/%u]\n", success ? "pass" : "fail", num_passes, num_tests); + } else { + printf("%*s, skip [%u/%u]\n", buf_size * 2, "", num_passes, num_tests); + } + + free(init_src_buffer); + free(init_dst_buffer); + free(expected_dst_buffer); + free(read_dst_buffer); + pipe_resource_reference(&dst, NULL); + pipe_resource_reference(&src, NULL); + } + + ctx->destroy(ctx); + exit(0); +}