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.gmei...@gmail.com>

Reviewed-by: Lucas Stach <l.st...@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);

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to