summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers
diff options
context:
space:
mode:
authorMarek Olšák <[email protected]>2016-08-22 13:45:05 +0200
committerMarek Olšák <[email protected]>2016-09-05 18:01:15 +0200
commit21de3be8e62b2b093569a99550e6356ed2f106b4 (patch)
tree90eca99db8834a44053c28ff34b68822823fbb03 /src/gallium/drivers
parent63da0c991d228b61ca36591314098620c511dbce (diff)
radeonsi: fix texture format reinterpretation with DCC
DCC is limited in how texture formats can be reinterpreted using texture views. If we get a view format that is incompatible with the initial texture format with respect to DCC, disable DCC. There is a new piglit which tests all format combinations. What works and what doesn't was deduced by looking at the piglit failures. Reviewed-by: Bas Nieuwenhuizen <[email protected]> Reviewed-by: Nicolai Hähnle <[email protected]>
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r--src/gallium/drivers/radeon/r600_pipe_common.h6
-rw-r--r--src/gallium/drivers/radeon/r600_texture.c96
-rw-r--r--src/gallium/drivers/radeonsi/si_blit.c8
-rw-r--r--src/gallium/drivers/radeonsi/si_descriptors.c3
-rw-r--r--src/gallium/drivers/radeonsi/si_state.c4
5 files changed, 116 insertions, 1 deletions
diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h b/src/gallium/drivers/radeon/r600_pipe_common.h
index 192453576e5..624dea3dbd7 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.h
+++ b/src/gallium/drivers/radeon/r600_pipe_common.h
@@ -757,6 +757,12 @@ bool r600_init_flushed_depth_texture(struct pipe_context *ctx,
void r600_print_texture_info(struct r600_texture *rtex, FILE *f);
struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
const struct pipe_resource *templ);
+bool vi_dcc_formats_compatible(enum pipe_format format1,
+ enum pipe_format format2);
+void vi_dcc_disable_if_incompatible_format(struct r600_common_context *rctx,
+ struct pipe_resource *tex,
+ unsigned level,
+ enum pipe_format view_format);
struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe,
struct pipe_resource *texture,
const struct pipe_surface *templ,
diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c
index 7bdceb1df9d..2f04019da02 100644
--- a/src/gallium/drivers/radeon/r600_texture.c
+++ b/src/gallium/drivers/radeon/r600_texture.c
@@ -1666,11 +1666,102 @@ static const struct u_resource_vtbl r600_texture_vtbl =
r600_texture_transfer_unmap, /* transfer_unmap */
};
+/* DCC channel type categories within which formats can be reinterpreted
+ * while keeping the same DCC encoding. The swizzle must also match. */
+enum dcc_channel_type {
+ dcc_channel_any32,
+ dcc_channel_int16,
+ dcc_channel_float16,
+ dcc_channel_any_10_10_10_2,
+ dcc_channel_any8,
+ dcc_channel_incompatible,
+};
+
+/* Return the type of DCC encoding. */
+static enum dcc_channel_type
+vi_get_dcc_channel_type(const struct util_format_description *desc)
+{
+ int i;
+
+ /* Find the first non-void channel. */
+ for (i = 0; i < desc->nr_channels; i++)
+ if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID)
+ break;
+ if (i == desc->nr_channels)
+ return dcc_channel_incompatible;
+
+ switch (desc->channel[i].size) {
+ case 32:
+ if (desc->nr_channels == 4)
+ return dcc_channel_incompatible;
+ else
+ return dcc_channel_any32;
+ case 16:
+ if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT)
+ return dcc_channel_float16;
+ else
+ return dcc_channel_int16;
+ case 10:
+ return dcc_channel_any_10_10_10_2;
+ case 8:
+ return dcc_channel_any8;
+ default:
+ return dcc_channel_incompatible;
+ }
+}
+
+/* Return if it's allowed to reinterpret one format as another with DCC enabled. */
+bool vi_dcc_formats_compatible(enum pipe_format format1,
+ enum pipe_format format2)
+{
+ const struct util_format_description *desc1, *desc2;
+ enum dcc_channel_type type1, type2;
+ int i;
+
+ if (format1 == format2)
+ return true;
+
+ desc1 = util_format_description(format1);
+ desc2 = util_format_description(format2);
+
+ if (desc1->nr_channels != desc2->nr_channels)
+ return false;
+
+ /* Swizzles must be the same. */
+ for (i = 0; i < desc1->nr_channels; i++)
+ if (desc1->swizzle[i] <= PIPE_SWIZZLE_W &&
+ desc2->swizzle[i] <= PIPE_SWIZZLE_W &&
+ desc1->swizzle[i] != desc2->swizzle[i])
+ return false;
+
+ type1 = vi_get_dcc_channel_type(desc1);
+ type2 = vi_get_dcc_channel_type(desc2);
+
+ return type1 != dcc_channel_incompatible &&
+ type2 != dcc_channel_incompatible &&
+ type1 == type2;
+}
+
+void vi_dcc_disable_if_incompatible_format(struct r600_common_context *rctx,
+ struct pipe_resource *tex,
+ unsigned level,
+ enum pipe_format view_format)
+{
+ struct r600_texture *rtex = (struct r600_texture *)tex;
+
+ if (rtex->dcc_offset &&
+ rtex->surface.level[level].dcc_enabled &&
+ !vi_dcc_formats_compatible(tex->format, view_format))
+ if (!r600_texture_disable_dcc(rctx, (struct r600_texture*)tex))
+ rctx->decompress_dcc(&rctx->b, rtex);
+}
+
struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe,
struct pipe_resource *texture,
const struct pipe_surface *templ,
unsigned width, unsigned height)
{
+ struct r600_common_context *rctx = (struct r600_common_context*)pipe;
struct r600_texture *rtex = (struct r600_texture*)texture;
struct r600_surface *surface = CALLOC_STRUCT(r600_surface);
@@ -1688,6 +1779,11 @@ struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe,
surface->base.height = height;
surface->base.u = templ->u;
surface->level_info = &rtex->surface.level[templ->u.tex.level];
+
+ vi_dcc_disable_if_incompatible_format(rctx, texture,
+ templ->u.tex.level,
+ templ->format);
+
return &surface->base;
}
diff --git a/src/gallium/drivers/radeonsi/si_blit.c b/src/gallium/drivers/radeonsi/si_blit.c
index 1147b5b3e22..c143601d55c 100644
--- a/src/gallium/drivers/radeonsi/si_blit.c
+++ b/src/gallium/drivers/radeonsi/si_blit.c
@@ -1124,6 +1124,12 @@ static void si_blit(struct pipe_context *ctx,
/* The driver doesn't decompress resources automatically while
* u_blitter is rendering. */
+ vi_dcc_disable_if_incompatible_format(&sctx->b, info->src.resource,
+ info->src.level,
+ info->src.format);
+ vi_dcc_disable_if_incompatible_format(&sctx->b, info->dst.resource,
+ info->dst.level,
+ info->dst.format);
si_decompress_subresource(ctx, info->src.resource, info->mask,
info->src.level,
info->src.box.z,
@@ -1153,6 +1159,8 @@ static boolean si_generate_mipmap(struct pipe_context *ctx,
/* The driver doesn't decompress resources automatically while
* u_blitter is rendering. */
+ vi_dcc_disable_if_incompatible_format(&sctx->b, tex, base_level,
+ format);
si_decompress_subresource(ctx, tex, PIPE_MASK_RGBAZS,
base_level, first_layer, last_layer);
diff --git a/src/gallium/drivers/radeonsi/si_descriptors.c b/src/gallium/drivers/radeonsi/si_descriptors.c
index b80f4f25436..b9fae79c577 100644
--- a/src/gallium/drivers/radeonsi/si_descriptors.c
+++ b/src/gallium/drivers/radeonsi/si_descriptors.c
@@ -653,7 +653,8 @@ static void si_set_shader_image(struct si_context *ctx,
assert(tex->fmask.size == 0);
if (uses_dcc &&
- view->access & PIPE_IMAGE_ACCESS_WRITE) {
+ (view->access & PIPE_IMAGE_ACCESS_WRITE ||
+ !vi_dcc_formats_compatible(res->b.b.format, view->format))) {
/* If DCC can't be disabled, at least decompress it.
* The decompression is relatively cheap if the surface
* has been decompressed already.
diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
index 41ff3200294..f54b0bcc3a8 100644
--- a/src/gallium/drivers/radeonsi/si_state.c
+++ b/src/gallium/drivers/radeonsi/si_state.c
@@ -3051,6 +3051,10 @@ si_create_sampler_view_custom(struct pipe_context *ctx,
}
}
+ vi_dcc_disable_if_incompatible_format(&sctx->b, texture,
+ state->u.tex.first_level,
+ state->format);
+
si_make_texture_descriptor(sctx->screen, tmp, true,
state->target, pipe_format, state_swizzle,
first_level, last_level,