radeonsi: add correctness tests for the clear/copy_buffer compute shader

Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30208>
This commit is contained in:
Marek Olšák
2024-07-14 01:54:12 -04:00
committed by Marge Bot
parent a48a376bc5
commit 4d78052321
3 changed files with 241 additions and 2 deletions
+9 -2
View File
@@ -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);
+4
View File
@@ -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);
@@ -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);
}