summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Olšák <marek.olsak@amd.com>2022-04-25 04:53:28 -0400
committerMarge Bot <emma+marge@anholt.net>2022-08-03 00:57:16 +0000
commit788dce46a3c8ebea782da9d37b94bab744c21c28 (patch)
treec76220a03e90e21c82a27b4bb43e1fc73785beea
parenta42be1efdc345f236f745781ae862e9d4299570a (diff)
downloadmesa-788dce46a3c8ebea782da9d37b94bab744c21c28.tar.gz
radeonsi: add a randomized blit test
Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17864>
-rw-r--r--src/gallium/drivers/radeonsi/si_pipe.c5
-rw-r--r--src/gallium/drivers/radeonsi/si_pipe.h3
-rw-r--r--src/gallium/drivers/radeonsi/si_test_image_copy_region.c591
-rw-r--r--src/util/format/u_format.c8
4 files changed, 586 insertions, 21 deletions
diff --git a/src/gallium/drivers/radeonsi/si_pipe.c b/src/gallium/drivers/radeonsi/si_pipe.c
index 2cbaa9b54a0..39f68031e0b 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.c
+++ b/src/gallium/drivers/radeonsi/si_pipe.c
@@ -124,6 +124,8 @@ static const struct debug_named_value radeonsi_debug_options[] = {
static const struct debug_named_value test_options[] = {
/* Tests: */
{"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."},
{"testvmfaultcp", DBG(TEST_VMFAULT_CP), "Invoke a CP VM fault test and exit."},
{"testvmfaultshader", DBG(TEST_VMFAULT_SHADER), "Invoke a shader VM fault test and exit."},
{"testdmaperf", DBG(TEST_DMA_PERF), "Test DMA performance"},
@@ -1428,6 +1430,9 @@ static struct pipe_screen *radeonsi_screen_create_impl(struct radeon_winsys *ws,
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)) {
si_test_dma_perf(sscreen);
}
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 05668b1ae0b..a0aca0632e2 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -266,6 +266,8 @@ enum
{
/* Tests: */
DBG_TEST_IMAGE_COPY,
+ DBG_TEST_CB_RESOLVE,
+ DBG_TEST_COMPUTE_BLIT,
DBG_TEST_VMFAULT_CP,
DBG_TEST_VMFAULT_SHADER,
DBG_TEST_DMA_PERF,
@@ -1567,6 +1569,7 @@ void gfx10_destroy_query(struct si_context *sctx);
/* si_test_image_copy_region.c */
void si_test_image_copy_region(struct si_screen *sscreen);
+void si_test_blit(struct si_screen *sscreen, unsigned test_flags);
/* si_test_clearbuffer.c */
void si_test_dma_perf(struct si_screen *sscreen);
diff --git a/src/gallium/drivers/radeonsi/si_test_image_copy_region.c b/src/gallium/drivers/radeonsi/si_test_image_copy_region.c
index 0c72a63c3ab..2d9ca7f081a 100644
--- a/src/gallium/drivers/radeonsi/si_test_image_copy_region.c
+++ b/src/gallium/drivers/radeonsi/si_test_image_copy_region.c
@@ -88,6 +88,52 @@ static void set_random_pixels(struct pipe_context *ctx, struct pipe_resource *te
pipe_texture_unmap(ctx, t);
}
+static void set_random_pixels_for_2_textures(struct pipe_context *ctx, struct pipe_resource *tex1,
+ struct pipe_resource *tex2)
+{
+ /* tex1 and tex2 are assumed to be the same size, format, and layout */
+ for (unsigned level = 0; level <= tex1->last_level; level++) {
+ for (unsigned sample = 0; sample < MAX2(tex1->nr_samples, 1); sample++) {
+ struct pipe_transfer *t1, *t2;
+ uint8_t *map1, *map2;
+ int x, y, z;
+ unsigned width = align(u_minify(tex1->width0, level), util_format_get_blockwidth(tex1->format));
+ unsigned height = align(u_minify(tex1->height0, level), util_format_get_blockheight(tex1->format));
+ unsigned num_y_blocks = util_format_get_nblocksy(tex1->format, height);
+ unsigned num_layers = util_num_layers(tex1, level);
+ /* If we set level to sample + 1, we will only upload that sample instead of
+ * overwriting all samples.
+ */
+ unsigned level_or_sample = tex1->nr_samples > 1 ? sample + 1 : level;
+
+ map1 = pipe_texture_map_3d(ctx, tex1, level_or_sample, PIPE_MAP_WRITE, 0, 0, 0, width, height,
+ num_layers, &t1);
+ map2 = pipe_texture_map_3d(ctx, tex2, level_or_sample, PIPE_MAP_WRITE, 0, 0, 0, width, height,
+ num_layers, &t2);
+ assert(map1 && map2);
+ assert(t1->stride == t2->stride);
+
+ for (z = 0; z < num_layers; z++) {
+ for (y = 0; y < num_y_blocks; y++) {
+ uint64_t *ptr1 = (uint64_t *)(map1 + t1->layer_stride * z + t1->stride * y);
+ uint64_t *ptr2 = (uint64_t *)(map2 + t2->layer_stride * z + t2->stride * y);
+ unsigned size = t1->stride / 8;
+
+ assert(t1->stride % 8 == 0);
+ assert(t2->stride % 8 == 0);
+
+ for (x = 0; x < size; x++) {
+ *ptr1++ = *ptr2++ = rand_xorshift128plus(seed_xorshift128plus);
+ }
+ }
+ }
+
+ pipe_texture_unmap(ctx, t1);
+ pipe_texture_unmap(ctx, t2);
+ }
+ }
+}
+
static bool compare_textures(struct pipe_context *ctx, struct pipe_resource *tex,
struct cpu_texture *cpu, unsigned level)
{
@@ -121,40 +167,178 @@ done:
return pass;
}
-static enum pipe_format get_random_format(struct si_screen *sscreen)
+static bool compare_gpu_textures(struct pipe_context *ctx, struct pipe_resource *tex1,
+ struct pipe_resource *tex2)
{
+ /* tex1 and tex2 are assumed to be the same size, format, and layout */
+ for (unsigned level = 0; level <= tex1->last_level; level++) {
+ struct pipe_transfer *t1, *t2;
+ uint8_t *map1, *map2;
+ unsigned width = u_minify(tex1->width0, level);
+ unsigned height = u_minify(tex1->height0, level);
+ unsigned stride = util_format_get_stride(tex1->format, width);
+ unsigned num_y_blocks = util_format_get_nblocksy(tex1->format, height);
+ unsigned num_layers = util_num_layers(tex1, level);
+
+ map1 = pipe_texture_map_3d(ctx, tex1, level, PIPE_MAP_READ, 0, 0, 0, width, height,
+ num_layers, &t1);
+ map2 = pipe_texture_map_3d(ctx, tex2, level, PIPE_MAP_READ, 0, 0, 0, width, height,
+ num_layers, &t2);
+ assert(map1 && map2);
+ assert(t1->stride == t2->stride);
+
+ for (unsigned z = 0; z < num_layers; z++) {
+ for (unsigned y = 0; y < num_y_blocks; y++) {
+ uint64_t *ptr1 = (uint64_t *)(map1 + t1->layer_stride * z + t1->stride * y);
+ uint64_t *ptr2 = (uint64_t *)(map2 + t2->layer_stride * z + t2->stride * y);
+
+ assert(t1->stride % 8 == 0);
+ assert(t2->stride % 8 == 0);
+
+ if (memcmp(ptr1, ptr2, stride)) {
+ pipe_texture_unmap(ctx, t1);
+ pipe_texture_unmap(ctx, t2);
+ return false;
+ }
+ }
+ }
+
+ pipe_texture_unmap(ctx, t1);
+ pipe_texture_unmap(ctx, t2);
+ }
+
+ return true;
+}
+
+struct si_format_options {
+ bool only_resolve;
+ bool allow_float;
+ bool allow_unorm16;
+ bool allow_srgb;
+ bool allow_x_channels;
+ bool allow_subsampled;
+ bool allow_compressed;
+};
+
+static enum pipe_format get_random_format(struct si_screen *sscreen, bool render_target,
+ enum pipe_format color_or_zs, /* must be color or Z/S */
+ enum pipe_format res_format, /* must have the same bpp */
+ enum pipe_format integer_or_not, /* must be integer or non-integer */
+ const struct si_format_options *options)
+{
+ /* Depth/stencil formats can only select Z/S using the blit mask, not via the view format. */
+ if (res_format != PIPE_FORMAT_NONE && util_format_is_depth_or_stencil(res_format))
+ return res_format;
+
/* Keep generating formats until we get a supported one. */
while (1) {
/* Skip one format: PIPE_FORMAT_NONE */
enum pipe_format format = (rand() % (PIPE_FORMAT_COUNT - 1)) + 1;
const struct util_format_description *desc = util_format_description(format);
+ if (desc->colorspace == UTIL_FORMAT_COLORSPACE_YUV ||
+ format == PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8)
+ continue;
+
+ if (!options->allow_srgb && desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
+ continue;
+
+ if (!options->allow_subsampled && desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
+ continue;
+
+ if (!options->allow_compressed && util_format_get_blockwidth(format) >= 4)
+ continue;
+
+ if (color_or_zs != PIPE_FORMAT_NONE &&
+ (util_format_is_depth_or_stencil(color_or_zs) !=
+ util_format_is_depth_or_stencil(format)))
+ continue;
+
if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) {
- unsigned i;
+ if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
+ /* Don't select stencil-only formats - we don't support them for rendering. */
+ if (util_format_has_stencil(desc) && !util_format_has_depth(desc))
+ continue;
+ }
- /* Don't test formats with X channels because cpu_texture doesn't emulate them. */
- for (i = 0; i < desc->nr_channels; i++) {
- if (desc->channel[i].type == UTIL_FORMAT_TYPE_VOID)
- break;
+ if (!options->allow_x_channels) {
+ unsigned i;
+
+ /* Don't test formats with X channels because cpu_texture doesn't emulate them. */
+ for (i = 0; i < desc->nr_channels; i++) {
+ if (desc->channel[i].type == UTIL_FORMAT_TYPE_VOID)
+ break;
+ }
+ if (i != desc->nr_channels)
+ continue;
}
- if (i != desc->nr_channels)
+ }
+
+ if (res_format != PIPE_FORMAT_NONE) {
+ /* If the resource format is Z/S, we handle it at the beginning of this function,
+ * so here res_format can only be a color format.
+ */
+ if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS)
+ continue;
+
+ if (util_format_get_blocksize(res_format) != util_format_get_blocksize(format) ||
+ util_format_get_blockwidth(res_format) != util_format_get_blockwidth(format) ||
+ util_format_get_blockheight(res_format) != util_format_get_blockheight(format))
continue;
}
- if (desc->colorspace == UTIL_FORMAT_COLORSPACE_YUV)
+ if (integer_or_not != PIPE_FORMAT_NONE) {
+ /* The integer property must match between blit src/dst. */
+ if (util_format_is_pure_integer(integer_or_not) != util_format_is_pure_integer(format))
+ continue;
+ }
+
+ if (options->only_resolve &&
+ (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS || util_format_is_pure_integer(format)))
continue;
- if (sscreen->b.is_format_supported(&sscreen->b, format, PIPE_TEXTURE_2D, 1, 1,
- PIPE_BIND_SAMPLER_VIEW))
+ if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) {
+ /* Every integer format should have an equivalent non-integer format, but 128-bit integer
+ * formats don't have that if floats are disallowed, which can cause an infinite loop later
+ * if compat_type is non-integer.
+ */
+ if (!options->allow_float &&
+ (util_format_is_float(format) || util_format_get_blocksizebits(format) == 128))
+ continue;
+
+ if (!options->allow_unorm16 &&
+ desc->channel[0].size == 16 && desc->channel[0].normalized &&
+ desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
+ continue;
+ }
+
+ unsigned bind = PIPE_BIND_SAMPLER_VIEW;
+ if (render_target) {
+ if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS)
+ bind = PIPE_BIND_DEPTH_STENCIL;
+ else
+ bind = PIPE_BIND_RENDER_TARGET;
+ }
+
+ if (sscreen->b.is_format_supported(&sscreen->b, format, PIPE_TEXTURE_2D, 1, 1, bind))
return format;
}
}
#define MAX_ALLOC_SIZE (64 * 1024 * 1024)
-static void set_random_image_attrs(struct pipe_resource *templ)
+static void set_random_image_attrs(struct pipe_resource *templ, bool allow_msaa,
+ bool only_cb_resolve)
{
- switch (rand() % 6) {
+ unsigned target_index;
+
+ if (only_cb_resolve) {
+ target_index = 6; /* CB resolving doesn't support array textures. */
+ } else {
+ target_index = rand() % (allow_msaa ? 8 : 6);
+ }
+
+ switch (target_index) {
case 0:
templ->target = PIPE_TEXTURE_1D;
break;
@@ -163,7 +347,7 @@ static void set_random_image_attrs(struct pipe_resource *templ)
break;
case 2:
if (util_format_is_depth_or_stencil(templ->format))
- templ->target = PIPE_TEXTURE_2D; /* 3D doesn't support Z/S */
+ templ->target = PIPE_TEXTURE_2D_ARRAY; /* 3D doesn't support Z/S */
else
templ->target = PIPE_TEXTURE_3D;
break;
@@ -174,9 +358,18 @@ static void set_random_image_attrs(struct pipe_resource *templ)
templ->target = PIPE_TEXTURE_1D_ARRAY;
break;
case 5:
- default:
templ->target = PIPE_TEXTURE_2D_ARRAY;
break;
+ case 6:
+ templ->target = PIPE_TEXTURE_2D;
+ templ->nr_samples = 2 << (rand() % 3);
+ break;
+ case 7:
+ templ->target = PIPE_TEXTURE_2D_ARRAY;
+ templ->nr_samples = 2 << (rand() % 3);
+ break;
+ default:
+ unreachable("invalid path");
}
templ->usage = PIPE_USAGE_DEFAULT;
@@ -184,6 +377,7 @@ static void set_random_image_attrs(struct pipe_resource *templ)
templ->height0 = 1;
templ->depth0 = 1;
templ->array_size = 1;
+ templ->nr_storage_samples = templ->nr_samples;
/* Try to hit microtiling in 1/2 of the cases. */
unsigned max_tex_size = rand() & 1 ? 128 : 1024;
@@ -230,7 +424,8 @@ static void set_random_image_attrs(struct pipe_resource *templ)
util_format_description(templ->format)->layout != UTIL_FORMAT_LAYOUT_SUBSAMPLED) {
unsigned max_dim = MAX3(templ->width0, templ->height0, templ->depth0);
- templ->last_level = rand() % (util_logbase2(max_dim) + 1);
+ if (templ->nr_samples <= 1)
+ templ->last_level = rand() % (util_logbase2(max_dim) + 1);
}
}
@@ -280,8 +475,9 @@ static void print_image_attrs(struct si_screen *sscreen, struct si_texture *tex)
snprintf(size, sizeof(size), "%ux%ux%u", tex->buffer.b.b.width0, tex->buffer.b.b.height0,
util_num_layers(&tex->buffer.b.b, 0));
- printf("%8s, %14s, %2u levels, %8s", targets[tex->buffer.b.b.target], size,
- tex->buffer.b.b.last_level + 1, mode);
+ printf("%8s, %14s, %2u %7s, %8s", targets[tex->buffer.b.b.target], size,
+ tex->buffer.b.b.nr_samples > 1 ? tex->buffer.b.b.nr_samples : tex->buffer.b.b.last_level + 1,
+ tex->buffer.b.b.nr_samples > 1 ? "samples" : "levels", mode);
}
void si_test_image_copy_region(struct si_screen *sscreen)
@@ -315,9 +511,22 @@ void si_test_image_copy_region(struct si_screen *sscreen)
bool pass;
/* generate a random test case */
- tsrc.format = tdst.format = get_random_format(sscreen);
- set_random_image_attrs(&tsrc);
- set_random_image_attrs(&tdst);
+ struct si_format_options format_options = {
+ .only_resolve = false,
+ .allow_float = true,
+ .allow_unorm16 = true,
+ .allow_x_channels = false, /* cpu_texture doesn't implement X channels */
+ .allow_subsampled = false, /* TODO: fix subsampled formats */
+ .allow_compressed = false, /* TODO: fix compressed formats */
+ };
+
+ tsrc.format = tdst.format = get_random_format(sscreen, false, 0, 0, 0, &format_options);
+
+ /* MSAA copy testing not implemented and might be too difficult because of how
+ * cpu_texture works.
+ */
+ set_random_image_attrs(&tsrc, false, false);
+ set_random_image_attrs(&tdst, false, false);
/* Allocate textures (both the GPU and CPU copies).
* The CPU will emulate what the GPU should be doing.
@@ -333,7 +542,7 @@ void si_test_image_copy_region(struct si_screen *sscreen)
print_image_attrs(sscreen, sdst);
printf("), src = (");
print_image_attrs(sscreen, ssrc);
- printf("), format = %18s, ", util_format_description(tsrc.format)->short_name);
+ printf("), format = %20s, ", util_format_description(tsrc.format)->short_name);
fflush(stdout);
for (unsigned level = 0; level <= tsrc.last_level; level++) {
@@ -430,3 +639,343 @@ void si_test_image_copy_region(struct si_screen *sscreen)
ctx->destroy(ctx);
exit(0);
}
+
+void si_test_blit(struct si_screen *sscreen, unsigned test_flags)
+{
+ 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 iterations;
+ unsigned num_pass = 0, num_fail = 0;
+ bool only_cb_resolve = test_flags == DBG(TEST_CB_RESOLVE);
+
+ bool allow_float = false;
+ bool allow_unorm16_dst = false;
+ bool allow_srgb_dst = false;
+ bool allow_filter = false;
+ bool allow_scaled_min = false;
+ bool allow_scaled_mag = false;
+ bool allow_out_of_bounds_dst = false;
+ bool allow_out_of_bounds_src = false;
+ bool allow_scissor = false;
+ bool allow_flip = false;
+
+ /* The following tests always compare the tested operation with the gfx blit (u_blitter). */
+ switch (test_flags) {
+ case DBG(TEST_CB_RESOLVE):
+ /* This is mostly failing because the precision of CB_RESOLVE is very different
+ * from the gfx blit. FP32 and FP16 are the only formats that mostly pass.
+ */
+ allow_float = true;
+ allow_unorm16_dst = true;
+ allow_srgb_dst = true;
+ break;
+
+ case DBG(TEST_COMPUTE_BLIT):
+ //allow_float = true; /* precision difference: NaNs not preserved by CB (u_blitter) */
+ allow_unorm16_dst = true;
+ //allow_srgb_dst = true; /* precision difference: sRGB is less precise in CB (u_blitter) */
+ //allow_filter = true; /* not implemented by compute blits, lots of precision differences */
+ //allow_scaled_min = true; /* not implemented by compute blits, lots of precision differences */
+ //allow_scaled_mag = true; /* not implemented by compute blits, lots of precision differences */
+ allow_out_of_bounds_dst = true;
+ allow_out_of_bounds_src = true;
+ //allow_scissor = true; /* not implemented by compute blits */
+ allow_flip = true;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ /* the seed for random test parameters */
+ srand(0x9b47d95b);
+ /* the seed for random pixel data */
+ s_rand_xorshift128plus(seed_xorshift128plus, false);
+
+ iterations = 10000000; /* just kill it when you are bored */
+
+ /* These parameters are randomly generated per test:
+ * - which texture dimensions to use
+ * - random initial pixels in src
+ * - random pipe_blit_info
+ */
+ for (unsigned i = 0; i < iterations; i++) {
+ struct pipe_resource tsrc = {}, tdst = {}, *gfx_src, *gfx_dst, *comp_src, *comp_dst;
+
+ /* Generate a random test case. */
+ {
+ struct si_format_options format_options = {
+ .only_resolve = only_cb_resolve,
+ .allow_float = allow_float,
+ .allow_unorm16 = true,
+ .allow_srgb = true,
+ .allow_x_channels = true,
+ .allow_subsampled = false, /* TODO: fix subsampled formats */
+ .allow_compressed = false, /* TODO: fix compressed formats */
+ };
+
+ tsrc.format = get_random_format(sscreen, false, 0, 0, 0, &format_options);
+ tdst.format = get_random_format(sscreen, true, tsrc.format, 0, 0, &format_options);
+ }
+
+ set_random_image_attrs(&tsrc, true, only_cb_resolve);
+ set_random_image_attrs(&tdst, !only_cb_resolve, false);
+
+ /* MSAA blits must have matching sample counts. */
+ if (tsrc.nr_samples > 1 && tdst.nr_samples > 1)
+ tdst.nr_samples = tdst.nr_storage_samples = tsrc.nr_samples;
+
+ /* Allocate textures. */
+ gfx_src = screen->resource_create(screen, &tsrc);
+ gfx_dst = screen->resource_create(screen, &tdst);
+ comp_src = screen->resource_create(screen, &tsrc);
+ comp_dst = screen->resource_create(screen, &tdst);
+
+ /* clear dst pixels */
+ uint32_t zero = 0;
+ si_clear_buffer(sctx, gfx_dst, 0, ((struct si_texture *)gfx_dst)->surface.surf_size, &zero,
+ 4, SI_OP_SYNC_BEFORE_AFTER, SI_COHERENCY_SHADER, SI_AUTO_SELECT_CLEAR_METHOD);
+ si_clear_buffer(sctx, comp_dst, 0, ((struct si_texture *)comp_dst)->surface.surf_size, &zero,
+ 4, SI_OP_SYNC_BEFORE_AFTER, SI_COHERENCY_SHADER, SI_AUTO_SELECT_CLEAR_METHOD);
+
+ /* TODO: These two fix quite a lot of BCn cases. */
+ /*si_clear_buffer(sctx, gfx_src, 0, ((struct si_texture *)gfx_src)->surface.surf_size, &zero,
+ 4, SI_OP_SYNC_BEFORE_AFTER, SI_COHERENCY_SHADER, SI_AUTO_SELECT_CLEAR_METHOD);
+ si_clear_buffer(sctx, comp_src, 0, ((struct si_texture *)comp_src)->surface.surf_size, &zero,
+ 4, SI_OP_SYNC_BEFORE_AFTER, SI_COHERENCY_SHADER, SI_AUTO_SELECT_CLEAR_METHOD);*/
+
+ set_random_pixels_for_2_textures(ctx, gfx_src, comp_src);
+
+ struct pipe_blit_info info;
+ memset(&info, 0, sizeof(info));
+
+ {
+ struct si_format_options format_options = {
+ .only_resolve = only_cb_resolve,
+ .allow_float = allow_float,
+ .allow_unorm16 = true,
+ .allow_srgb = true,
+ .allow_x_channels = true,
+ .allow_subsampled = false, /* TODO: fix subsampled formats */
+ .allow_compressed = false, /* TODO: fix compressed formats */
+ };
+
+ info.src.format = get_random_format(sscreen, false, 0, tsrc.format, 0, &format_options);
+ format_options.allow_unorm16 = allow_unorm16_dst;
+ format_options.allow_srgb = allow_srgb_dst;
+ info.dst.format = get_random_format(sscreen, true, 0, tdst.format, info.src.format,
+ &format_options);
+ }
+
+ printf("%4u: dst = (", i);
+ print_image_attrs(sscreen, (struct si_texture *)gfx_dst);
+ printf(", %20s as %20s), src = (",
+ util_format_description(tdst.format)->short_name,
+ util_format_short_name(info.dst.format));
+ print_image_attrs(sscreen, (struct si_texture *)gfx_src);
+ printf(", %20s as %20s)",
+ util_format_description(tsrc.format)->short_name,
+ util_format_short_name(info.src.format));
+ fflush(stdout);
+
+ int src_width, src_height, src_depth, dst_width, dst_height, dst_depth;
+ int srcx, srcy, srcz, dstx, dsty, dstz;
+
+ unsigned src_level = rand() % (tsrc.last_level + 1);
+ unsigned dst_level = rand() % (tdst.last_level + 1);
+
+ unsigned max_src_width = u_minify(tsrc.width0, src_level);
+ unsigned max_src_height = u_minify(tsrc.height0, src_level);
+ unsigned max_src_depth = util_num_layers(&tsrc, src_level);
+
+ unsigned max_dst_width = u_minify(tdst.width0, dst_level);
+ unsigned max_dst_height = u_minify(tdst.height0, dst_level);
+ unsigned max_dst_depth = util_num_layers(&tdst, dst_level);
+
+ /* make sure that it doesn't divide by zero */
+ assert(max_src_width && max_src_height && max_src_depth &&
+ max_dst_width && max_dst_height && max_dst_depth);
+
+ /* random sub-rectangle copies from src to dst */
+ src_width = (rand() % max_src_width) + 1;
+ src_height = (rand() % max_src_height) + 1;
+ src_depth = (rand() % max_src_depth) + 1;
+
+ dst_width = (rand() % max_dst_width) + 1;
+ dst_height = (rand() % max_dst_height) + 1;
+ dst_depth = (rand() % max_dst_depth) + 1;
+
+ srcx = rand() % (u_minify(tsrc.width0, src_level) - src_width + 1);
+ srcy = rand() % (u_minify(tsrc.height0, src_level) - src_height + 1);
+ srcz = rand() % (util_num_layers(&tsrc, src_level) - src_depth + 1);
+
+ dstx = rand() % (u_minify(tdst.width0, dst_level) - dst_width + 1);
+ dsty = rand() % (u_minify(tdst.height0, dst_level) - dst_height + 1);
+ dstz = rand() % (util_num_layers(&tdst, dst_level) - dst_depth + 1);
+
+ /* Test out-of-bounds boxes. Add -dim/10 .. +dim/10 */
+ if (allow_out_of_bounds_src) {
+ if (max_src_width / 5 >= 2)
+ srcx += rand() % (max_src_width / 5) - max_src_width / 10;
+ if (max_src_height / 5 >= 2)
+ srcy += rand() % (max_src_height / 5) - max_src_height / 10;
+ }
+
+ if (allow_out_of_bounds_dst) {
+ if (max_dst_width / 5 >= 2)
+ dstx += rand() % (max_dst_width / 5) - max_dst_width / 10;
+ if (max_dst_height / 5 >= 2)
+ dsty += rand() % (max_dst_height / 5) - max_dst_height / 10;
+ }
+
+ /* Align the box to the format block size. */
+ srcx &= ~(util_format_get_blockwidth(tsrc.format) - 1);
+ srcy &= ~(util_format_get_blockheight(tsrc.format) - 1);
+
+ dstx &= ~(util_format_get_blockwidth(tdst.format) - 1);
+ dsty &= ~(util_format_get_blockheight(tdst.format) - 1);
+
+ src_width = align(src_width, util_format_get_blockwidth(tsrc.format));
+ src_height = align(src_height, util_format_get_blockheight(tsrc.format));
+
+ dst_width = align(dst_width, util_format_get_blockwidth(tdst.format));
+ dst_height = align(dst_height, util_format_get_blockheight(tdst.format));
+
+ if (!allow_scaled_min) {
+ if (src_width > dst_width)
+ src_width = dst_width;
+ if (src_height > dst_height)
+ src_height = dst_height;
+ if (src_depth > dst_depth)
+ src_depth = dst_depth;
+ }
+
+ if (!allow_scaled_mag) {
+ if (src_width < dst_width)
+ dst_width = src_width;
+ if (src_height < dst_height)
+ dst_height = src_height;
+ if (src_depth < dst_depth)
+ dst_depth = src_depth;
+ }
+
+ /* Flips */
+ if (allow_flip) {
+ if (rand() % 2) {
+ srcx += src_width;
+ src_width = -src_width;
+ }
+ if (rand() % 2) {
+ srcy += src_height;
+ src_height = -src_height;
+ }
+ }
+
+ info.src.level = src_level;
+ info.dst.level = dst_level;
+
+ u_box_3d(srcx, srcy, srcz, src_width, src_height, src_depth, &info.src.box);
+ u_box_3d(dstx, dsty, dstz, dst_width, dst_height, dst_depth, &info.dst.box);
+
+ if (util_format_is_depth_and_stencil(tsrc.format)) {
+ switch (rand() % 3) {
+ case 0:
+ info.mask = PIPE_MASK_ZS;
+ break;
+ case 1:
+ info.mask = PIPE_MASK_Z;
+ break;
+ case 2:
+ info.mask = PIPE_MASK_S;
+ break;
+ }
+ } else {
+ /* RGBA, Z, or S */
+ info.mask = util_format_get_mask(tdst.format);
+ }
+
+ /* Don't filter MSAA and integer sources. */
+ if (allow_filter && tsrc.nr_samples <= 1 &&
+ !util_format_is_pure_integer(info.src.format) && rand() % 2)
+ info.filter = PIPE_TEX_FILTER_LINEAR;
+ else
+ info.filter = PIPE_TEX_FILTER_NEAREST;
+
+ info.scissor_enable = allow_scissor ? rand() % 2 : false;
+
+ if (info.scissor_enable) {
+ info.scissor.minx = MAX2(MIN2(info.dst.box.x, info.dst.box.x + info.dst.box.width), 0);
+ info.scissor.miny = MAX2(MIN2(info.dst.box.y, info.dst.box.y + info.dst.box.height), 0);
+ info.scissor.maxx = MIN2(MAX2(info.dst.box.x, info.dst.box.x + info.dst.box.width), UINT16_MAX);
+ info.scissor.maxy = MIN2(MAX2(info.dst.box.y, info.dst.box.y + info.dst.box.height), UINT16_MAX);
+
+ if (abs(info.dst.box.width) / 2 >= 2) {
+ info.scissor.minx += rand() % (abs(info.dst.box.width) / 2);
+ info.scissor.maxx -= rand() % (abs(info.dst.box.width) / 2);
+ }
+ if (abs(info.dst.box.height) / 2 >= 2) {
+ info.scissor.miny += rand() % (abs(info.dst.box.height) / 2);
+ info.scissor.maxy -= rand() % (abs(info.dst.box.height) / 2);
+ }
+ }
+
+ char dstbox_s[128], srcbox_s[128], scissor[128];
+
+ snprintf(dstbox_s, sizeof(dstbox_s), "{%ix%ix%i .. %ix%ix%i}",
+ info.dst.box.x, info.dst.box.y, info.dst.box.z,
+ info.dst.box.width, info.dst.box.height, info.dst.box.depth);
+ snprintf(srcbox_s, sizeof(srcbox_s), "{%ix%ix%i .. %ix%ix%i}",
+ info.src.box.x, info.src.box.y, info.src.box.z,
+ info.src.box.width, info.src.box.height, info.src.box.depth);
+ if (info.scissor_enable) {
+ snprintf(scissor, sizeof(scissor), "(%u..%u, %u..%u)",
+ info.scissor.minx, info.scissor.maxx, info.scissor.miny, info.scissor.maxy);
+ } else {
+ snprintf(scissor, sizeof(scissor), "(none)");
+ }
+
+ printf(", filter %u, mask 0x%02x, ", info.filter, info.mask);
+ printf("dst(level %u, box = %-28s), ", info.dst.level, dstbox_s);
+ printf("src(level %u, box = %-28s), ", info.src.level, srcbox_s);
+ printf("scissor%-20s", scissor);
+
+ /* Blits. */
+ info.src.resource = gfx_src;
+ info.dst.resource = gfx_dst;
+ si_gfx_blit(ctx, &info);
+
+ info.src.resource = comp_src;
+ info.dst.resource = comp_dst;
+
+ bool success;
+ if (only_cb_resolve)
+ success = si_msaa_resolve_blit_via_CB(ctx, &info);
+ else
+ success = false;
+
+ if (success) {
+ printf(" %-7s", only_cb_resolve ? "resolve" : "comp");
+ } else {
+ si_gfx_blit(ctx, &info);
+ printf(" %-7s", "gfx");
+ }
+
+ bool pass = compare_gpu_textures(ctx, gfx_dst, comp_dst);
+ if (pass)
+ num_pass++;
+ else
+ num_fail++;
+
+ printf(" %s [%u/%u]\n", pass ? "pass" : "fail", num_pass, num_pass + num_fail);
+
+ /* cleanup */
+ pipe_resource_reference(&gfx_src, NULL);
+ pipe_resource_reference(&gfx_dst, NULL);
+ pipe_resource_reference(&comp_src, NULL);
+ pipe_resource_reference(&comp_dst, NULL);
+ }
+
+ ctx->destroy(ctx);
+ exit(0);
+}
diff --git a/src/util/format/u_format.c b/src/util/format/u_format.c
index aba5d51ed97..c071250d874 100644
--- a/src/util/format/u_format.c
+++ b/src/util/format/u_format.c
@@ -174,6 +174,14 @@ util_format_is_pure_integer(enum pipe_format format)
const struct util_format_description *desc = util_format_description(format);
int i;
+ if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
+ if (util_format_has_depth(desc))
+ return false;
+
+ assert(util_format_has_stencil(desc));
+ return true;
+ }
+
/* Find the first non-void channel. */
i = util_format_get_first_non_void_channel(format);
if (i == -1)