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 <mar...@gmail.com> wrote: > From: Marek Olšák <marek.ol...@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@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev