[Mesa-dev] [PATCH 11/20] radeonsi: fix texture format reinterpretation with DCC
Bas Nieuwenhuizen
bas at basnieuwenhuizen.nl
Mon Aug 29 18:29:06 UTC 2016
Hi Marek,
I don't think this accounts for the fast clear bits? unorm->uint and
snorm<->sint should have compatible clear values, but otherwise we may
need to eliminate the fast clears.
Yours sincerely,
Bas Nieuwenhuizen
On Mon, Aug 29, 2016 at 5:28 PM, Marek Olšák <maraeo at gmail.com> wrote:
> From: Marek Olšák <marek.olsak at amd.com>
>
> 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.
> ---
> src/gallium/drivers/radeon/r600_pipe_common.h | 6 ++
> src/gallium/drivers/radeon/r600_texture.c | 96 +++++++++++++++++++++++++++
> src/gallium/drivers/radeonsi/si_blit.c | 8 +++
> src/gallium/drivers/radeonsi/si_descriptors.c | 3 +-
> src/gallium/drivers/radeonsi/si_state.c | 4 ++
> 5 files changed, 116 insertions(+), 1 deletion(-)
>
> diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h b/src/gallium/drivers/radeon/r600_pipe_common.h
> index 1924535..624dea3 100644
> --- a/src/gallium/drivers/radeon/r600_pipe_common.h
> +++ b/src/gallium/drivers/radeon/r600_pipe_common.h
> @@ -750,20 +750,26 @@ void r600_texture_get_fmask_info(struct r600_common_screen *rscreen,
> struct r600_fmask_info *out);
> void r600_texture_get_cmask_info(struct r600_common_screen *rscreen,
> struct r600_texture *rtex,
> struct r600_cmask_info *out);
> bool r600_init_flushed_depth_texture(struct pipe_context *ctx,
> struct pipe_resource *texture,
> struct r600_texture **staging);
> 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,
> unsigned width, unsigned height);
> unsigned r600_translate_colorswap(enum pipe_format format, bool do_endian_swap);
> void vi_separate_dcc_start_query(struct pipe_context *ctx,
> struct r600_texture *tex);
> void vi_separate_dcc_stop_query(struct pipe_context *ctx,
> struct r600_texture *tex);
> void vi_separate_dcc_process_and_reset_stats(struct pipe_context *ctx,
> diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c
> index 7bdceb1..2f04019 100644
> --- a/src/gallium/drivers/radeon/r600_texture.c
> +++ b/src/gallium/drivers/radeon/r600_texture.c
> @@ -1659,42 +1659,138 @@ static void r600_texture_transfer_unmap(struct pipe_context *ctx,
>
> static const struct u_resource_vtbl r600_texture_vtbl =
> {
> NULL, /* get_handle */
> r600_texture_destroy, /* resource_destroy */
> r600_texture_transfer_map, /* transfer_map */
> u_default_transfer_flush_region, /* transfer_flush_region */
> 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);
>
> if (!surface)
> return NULL;
>
> assert(templ->u.tex.first_layer <= util_max_layer(texture, templ->u.tex.level));
> assert(templ->u.tex.last_layer <= util_max_layer(texture, templ->u.tex.level));
>
> pipe_reference_init(&surface->base.reference, 1);
> pipe_resource_reference(&surface->base.texture, texture);
> surface->base.context = pipe;
> surface->base.format = templ->format;
> surface->base.width = width;
> 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;
> }
>
> static struct pipe_surface *r600_create_surface(struct pipe_context *pipe,
> struct pipe_resource *tex,
> const struct pipe_surface *templ)
> {
> unsigned level = templ->u.tex.level;
> unsigned width = u_minify(tex->width0, level);
> unsigned height = u_minify(tex->height0, level);
> diff --git a/src/gallium/drivers/radeonsi/si_blit.c b/src/gallium/drivers/radeonsi/si_blit.c
> index 1147b5b..c143601 100644
> --- a/src/gallium/drivers/radeonsi/si_blit.c
> +++ b/src/gallium/drivers/radeonsi/si_blit.c
> @@ -1117,20 +1117,26 @@ static void si_blit(struct pipe_context *ctx,
> info->dst.box.z,
> info->src.resource, info->src.level,
> &info->src.box);
> return;
> }
>
> assert(util_blitter_is_blit_supported(sctx->blitter, info));
>
> /* 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,
> info->src.box.z + info->src.box.depth - 1);
>
> if (sctx->screen->b.debug_flags & DBG_FORCE_DMA &&
> util_try_blit_via_copy_region(ctx, info))
> return;
>
> si_blitter_begin(ctx, SI_BLIT |
> @@ -1146,20 +1152,22 @@ static boolean si_generate_mipmap(struct pipe_context *ctx,
> unsigned first_layer, unsigned last_layer)
> {
> struct si_context *sctx = (struct si_context*)ctx;
> struct r600_texture *rtex = (struct r600_texture *)tex;
>
> if (!util_blitter_is_copy_supported(sctx->blitter, tex, tex))
> return false;
>
> /* 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);
>
> /* Clear dirty_level_mask for the levels that will be overwritten. */
> assert(base_level < last_level);
> rtex->dirty_level_mask &= ~u_bit_consecutive(base_level + 1,
> last_level - base_level);
>
> si_blitter_begin(ctx, SI_BLIT | SI_DISABLE_RENDER_COND);
> util_blitter_generate_mipmap(sctx->blitter, tex, format,
> diff --git a/src/gallium/drivers/radeonsi/si_descriptors.c b/src/gallium/drivers/radeonsi/si_descriptors.c
> index b3174c6..c150175 100644
> --- a/src/gallium/drivers/radeonsi/si_descriptors.c
> +++ b/src/gallium/drivers/radeonsi/si_descriptors.c
> @@ -646,21 +646,22 @@ static void si_set_shader_image(struct si_context *ctx,
> unsigned level = view->u.tex.level;
> unsigned width, height, depth;
> uint32_t *desc = descs->list + slot * 8;
> bool uses_dcc = tex->dcc_offset &&
> tex->surface.level[level].dcc_enabled;
>
> assert(!tex->is_depth);
> 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.
> */
> if (r600_texture_disable_dcc(&ctx->b, tex))
> uses_dcc = false;
> else
> ctx->b.decompress_dcc(&ctx->b.b, tex);
> }
>
> diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
> index 026aded..803a021 100644
> --- a/src/gallium/drivers/radeonsi/si_state.c
> +++ b/src/gallium/drivers/radeonsi/si_state.c
> @@ -3045,20 +3045,24 @@ si_create_sampler_view_custom(struct pipe_context *ctx,
> case PIPE_FORMAT_X24S8_UINT:
> case PIPE_FORMAT_S8X24_UINT:
> case PIPE_FORMAT_X32_S8X24_UINT:
> pipe_format = PIPE_FORMAT_S8_UINT;
> surflevel = tmp->surface.stencil_level;
> break;
> default:;
> }
> }
>
> + 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,
> state->u.tex.first_layer, last_layer,
> width, height, depth,
> view->state, view->fmask_state);
>
> view->base_level_info = &surflevel[base_level];
> view->base_level = base_level;
> view->block_width = util_format_get_blockwidth(pipe_format);
> --
> 2.7.4
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list