etnaviv: keep track of buffer valid ranges for PIPE_BUFFER
authorChristian Gmeiner <christian.gmeiner@gmail.com>
Fri, 6 Sep 2019 13:13:51 +0000 (15:13 +0200)
committerChristian Gmeiner <christian.gmeiner@gmail.com>
Sun, 20 Oct 2019 09:03:06 +0000 (09:03 +0000)
This allows a write to proceed to an uninitialized part of a buffer
even when the GPU is using the previously-initialized portions.

Such a situation can be triggered with the following API usage example:

  glBufferSubData(..., offset, size, data1);
  glDrawArrays(...);
  // append new vertex data
  glBufferSubData(..., offset+size, size, data2);
  glDrawArrays(...);

Same is done for freedreno, nouveau and radeon.

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
src/gallium/drivers/etnaviv/etnaviv_resource.c
src/gallium/drivers/etnaviv/etnaviv_resource.h
src/gallium/drivers/etnaviv/etnaviv_transfer.c

index f1e314cb06f64018f227c672ec14483b01c4c9b2..cca8b64d7c6048f66d078007bd659db350a5fc57 100644 (file)
@@ -300,6 +300,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
    rsc->halign = halign;
 
    pipe_reference_init(&rsc->base.reference, 1);
+   util_range_init(&rsc->valid_buffer_range);
 
    size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale);
 
@@ -477,6 +478,8 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
    if (rsc->scanout)
       renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro);
 
+   util_range_destroy(&rsc->valid_buffer_range);
+
    pipe_resource_reference(&rsc->texture, NULL);
    pipe_resource_reference(&rsc->render, NULL);
 
@@ -513,6 +516,7 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
    *prsc = *tmpl;
 
    pipe_reference_init(&prsc->reference, 1);
+   util_range_init(&rsc->valid_buffer_range);
    prsc->screen = pscreen;
 
    rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride);
index 64aef18a016dc84cc8aba8443fde4a3c10c5d3c5..226e444b02ab7fac2dd8824e1237b6a1f316e557 100644 (file)
@@ -33,6 +33,7 @@
 #include "util/list.h"
 #include "util/set.h"
 #include "util/u_helpers.h"
+#include "util/u_range.h"
 
 struct etna_context;
 struct pipe_screen;
@@ -84,6 +85,9 @@ struct etna_resource {
 
    struct etna_resource_level levels[ETNA_NUM_LOD];
 
+   /* buffer range that has been initialized */
+   struct util_range valid_buffer_range;
+
    /* for when TE doesn't support the base layout */
    struct pipe_resource *texture;
    /* for when PE doesn't support the base layout */
index 62b876f2d995826d279701d1648341c686f19ed9..77a9abafa99dd7900d026af7a77e4c6b040bcdda 100644 (file)
@@ -174,6 +174,14 @@ etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
    if (!trans->rsc && !(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED))
       etna_bo_cpu_fini(rsc->bo);
 
+   if ((ptrans->resource->target == PIPE_BUFFER) &&
+       (ptrans->usage & PIPE_TRANSFER_WRITE)) {
+      util_range_add(&rsc->base,
+                     &rsc->valid_buffer_range,
+                     ptrans->box.x,
+                     ptrans->box.x + ptrans->box.width);
+      }
+
    pipe_resource_reference(&trans->rsc, NULL);
    pipe_resource_reference(&ptrans->resource, NULL);
    slab_free(&ctx->transfer_pool, trans);
@@ -199,6 +207,17 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
    /* slab_alloc() doesn't zero */
    memset(trans, 0, sizeof(*trans));
 
+   /*
+    * Upgrade to UNSYNCHRONIZED if target is PIPE_BUFFER and range is uninitialized.
+    */
+   if ((usage & PIPE_TRANSFER_WRITE) &&
+       (prsc->target == PIPE_BUFFER) &&
+       !util_ranges_intersect(&rsc->valid_buffer_range,
+                              box->x,
+                              box->x + box->width)) {
+      usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
+   }
+
    /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
     * being mapped. If we add buffer reallocation to avoid CPU/GPU sync this
     * check needs to be extended to coherent mappings and shared resources.
@@ -460,10 +479,16 @@ fail_prep:
 
 static void
 etna_transfer_flush_region(struct pipe_context *pctx,
-                           struct pipe_transfer *transfer,
+                           struct pipe_transfer *ptrans,
                            const struct pipe_box *box)
 {
-   /* NOOP for now */
+   struct etna_resource *rsc = etna_resource(ptrans->resource);
+
+   if (ptrans->resource->target == PIPE_BUFFER)
+      util_range_add(&rsc->base,
+                     &rsc->valid_buffer_range,
+                     ptrans->box.x + box->x,
+                     ptrans->box.x + box->x + box->width);
 }
 
 void