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 <christian.gmeiner@gmail.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
This commit is contained in:
Christian Gmeiner 2019-09-06 15:13:51 +02:00
parent eab6d75066
commit a6de05a968
3 changed files with 35 additions and 2 deletions

View 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);

View 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 */

View 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