[Mesa-dev] [PATCH v3 3/4] etnaviv: hook-up etc2 patching
Lucas Stach
l.stach at pengutronix.de
Thu Feb 28 06:32:49 UTC 2019
Am Donnerstag, den 28.02.2019, 07:26 +0100 schrieb Christian Gmeiner:
> Changes v1 -> v2:
> - Avoid the GPU sampling from the resource that gets mutated by the the
> transfer map by setting DRM_ETNA_PREP_WRITE.
>
> Changes v2 -> v3:
> - make use of likely(..)
> - drop minor optimization regarding rsc->layout == ETNA_LAYOUT_LINEAR
> - better documentation why DRM_ETNA_PREP_WRITE is needed
>
> Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
Reviewed-by: Lucas Stach <l.stach at pengutronix.de>
> ---
> .../drivers/etnaviv/etnaviv_resource.c | 3 +
> .../drivers/etnaviv/etnaviv_resource.h | 5 ++
> .../drivers/etnaviv/etnaviv_transfer.c | 56 +++++++++++++++++++
> 3 files changed, 64 insertions(+)
>
> diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c
> index db5ead4d0ba..45d5f69169e 100644
> --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c
> +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c
> @@ -478,6 +478,9 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
> pipe_resource_reference(&rsc->texture, NULL);
> pipe_resource_reference(&rsc->external, NULL);
>
> + for (unsigned i = 0; i < ETNA_NUM_LOD; i++)
> + FREE(rsc->levels[i].patch_offsets);
> +
> FREE(rsc);
> }
>
> diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h
> index 75aa80b3d7a..c45ff7586d1 100644
> --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h
> +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h
> @@ -33,6 +33,7 @@
> #include "util/list.h"
>
> struct pipe_screen;
> +struct util_dynarray;
>
> struct etna_resource_level {
> unsigned width, padded_width; /* in pixels */
> @@ -47,6 +48,10 @@ struct etna_resource_level {
> uint32_t ts_size;
> uint32_t clear_value; /* clear value of resource level (mainly for TS) */
> bool ts_valid;
> +
> + /* keep track if we have done some per block patching */
> + bool patched;
> + struct util_dynarray *patch_offsets;
> };
>
> enum etna_resource_addressing_mode {
> diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
> index 01da393d211..3b925a8ef9f 100644
> --- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c
> +++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
> @@ -28,6 +28,7 @@
> #include "etnaviv_clear_blit.h"
> #include "etnaviv_context.h"
> #include "etnaviv_debug.h"
> +#include "etnaviv_etc2.h"
> #include "etnaviv_screen.h"
>
> #include "pipe/p_defines.h"
> @@ -57,6 +58,46 @@ etna_compute_offset(enum pipe_format format, const struct pipe_box *box,
> util_format_get_blocksize(format);
> }
>
> +static void etna_patch_data(void *buffer, const struct pipe_transfer *ptrans)
> +{
> + struct pipe_resource *prsc = ptrans->resource;
> + struct etna_resource *rsc = etna_resource(prsc);
> + struct etna_resource_level *level = &rsc->levels[ptrans->level];
> +
> + if (likely(!etna_etc2_needs_patching(prsc)))
> + return;
> +
> + if (level->patched)
> + return;
> +
> + /* do have the offsets of blocks to patch? */
> + if (!level->patch_offsets) {
> + level->patch_offsets = CALLOC_STRUCT(util_dynarray);
> +
> + etna_etc2_calculate_blocks(buffer, ptrans->stride,
> + ptrans->box.width, ptrans->box.height,
> + prsc->format, level->patch_offsets);
> + }
> +
> + etna_etc2_patch(buffer, level->patch_offsets);
> +
> + level->patched = true;
> +}
> +
> +static void etna_unpatch_data(void *buffer, const struct pipe_transfer *ptrans)
> +{
> + struct pipe_resource *prsc = ptrans->resource;
> + struct etna_resource *rsc = etna_resource(prsc);
> + struct etna_resource_level *level = &rsc->levels[ptrans->level];
> +
> + if (!level->patched)
> + return;
> +
> + etna_etc2_patch(buffer, level->patch_offsets);
> +
> + level->patched = false;
> +}
> +
> static void
> etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
> {
> @@ -119,6 +160,9 @@ etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
> }
> }
>
> + /* We need to have the patched data ready for the GPU. */
> + etna_patch_data(trans->mapped, ptrans);
> +
> /*
> * Transfers without a temporary are only pulled into the CPU domain if they
> * are not mapped unsynchronized. If they are, must push them back into GPU
> @@ -321,6 +365,14 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
> if (usage & PIPE_TRANSFER_WRITE)
> prep_flags |= DRM_ETNA_PREP_WRITE;
>
> + /*
> + * The ETC2 patching operates in-place on the resource, so the resource will
> + * get written even on read-only transfers. This blocks the GPU to sample
> + * from this resource.
> + */
> + if ((usage & PIPE_TRANSFER_READ) && etna_etc2_needs_patching(prsc))
> + prep_flags |= DRM_ETNA_PREP_WRITE;
> +
> if (etna_bo_cpu_prep(rsc->bo, prep_flags))
> goto fail_prep;
> }
> @@ -340,6 +392,10 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
> etna_compute_offset(prsc->format, box, res_level->stride,
> res_level->layer_stride);
>
> + /* We need to have the unpatched data ready for the gfx stack. */
> + if (usage & PIPE_TRANSFER_READ)
> + etna_unpatch_data(trans->mapped, ptrans);
> +
> return trans->mapped;
> } else {
> unsigned divSizeX = util_format_get_blockwidth(format);
More information about the mesa-dev
mailing list