From a6de05a968dafc2f677df86376deb78ddce421e3 Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Fri, 6 Sep 2019 15:13:51 +0200 Subject: [PATCH] etnaviv: keep track of buffer valid ranges for PIPE_BUFFER 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 Reviewed-by: Lucas Stach --- .../drivers/etnaviv/etnaviv_resource.c | 4 +++ .../drivers/etnaviv/etnaviv_resource.h | 4 +++ .../drivers/etnaviv/etnaviv_transfer.c | 29 +++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index f1e314cb06f..cca8b64d7c6 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -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); diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index 64aef18a016..226e444b02a 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" #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 */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c index 62b876f2d99..77a9abafa99 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c +++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c @@ -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 -- 2.30.2