panfrost: Track BO lifetime with jobs and reference counts

This (fairly large) patch continues work surrounding the panfrost_job
abstraction to improve job lifetime management. In particular, we add
infrastructure to track which BOs are used by a particular job
(currently limited to the vertex buffer BOs), to reference count these
BOs, and to automatically manage the BOs memory based on the reference
count. This set of changes serves as a code cleanup, as a way of future
proofing for allowing flushing BOs, and immediately as a bugfix to
workaround the missing reference counting for vertex buffer BOs.
Meanwhile, there are a few cleanups to vertex buffer handling code
itself, so in the short-term, this allows us to remove the costly VBO
staging workaround, since this patch addresses the underlying causes.

v2: Use pipe_reference for BO reference counting, rather than managing
it ourselves. Don't duplicate hash-table key removal. Fix vertex buffer
counting.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig
2019-04-14 22:42:44 +00:00
parent a151500dd1
commit e008d4f011
9 changed files with 207 additions and 37 deletions

View File

@@ -228,6 +228,7 @@ static struct panfrost_bo *
panfrost_create_bo(struct panfrost_screen *screen, const struct pipe_resource *template)
{
struct panfrost_bo *bo = CALLOC_STRUCT(panfrost_bo);
pipe_reference_init(&bo->reference, 1);
/* Based on the usage, figure out what storing will be used. There are
* various tradeoffs:
@@ -297,6 +298,8 @@ panfrost_resource_create(struct pipe_screen *screen,
assert(0);
}
util_range_init(&so->valid_buffer_range);
if (template->bind & PIPE_BIND_DISPLAY_TARGET ||
template->bind & PIPE_BIND_SCANOUT ||
template->bind & PIPE_BIND_SHARED) {
@@ -359,6 +362,22 @@ panfrost_destroy_bo(struct panfrost_screen *screen, struct panfrost_bo *pbo)
}
}
void
panfrost_bo_reference(struct panfrost_bo *bo)
{
pipe_reference(NULL, &bo->reference);
}
void
panfrost_bo_unreference(struct pipe_screen *screen, struct panfrost_bo *bo)
{
/* When the reference count goes to zero, we need to cleanup */
if (pipe_reference(&bo->reference, NULL)) {
panfrost_destroy_bo(pan_screen(screen), bo);
}
}
static void
panfrost_resource_destroy(struct pipe_screen *screen,
struct pipe_resource *pt)
@@ -370,8 +389,9 @@ panfrost_resource_destroy(struct pipe_screen *screen,
renderonly_scanout_destroy(rsrc->scanout, pscreen->ro);
if (rsrc->bo)
panfrost_destroy_bo(pscreen, rsrc->bo);
panfrost_bo_unreference(screen, rsrc->bo);
util_range_destroy(&rsrc->valid_buffer_range);
FREE(rsrc);
}
@@ -384,7 +404,8 @@ panfrost_transfer_map(struct pipe_context *pctx,
struct pipe_transfer **out_transfer)
{
int bytes_per_pixel = util_format_get_blocksize(resource->format);
struct panfrost_bo *bo = pan_resource(resource)->bo;
struct panfrost_resource *rsrc = pan_resource(resource);
struct panfrost_bo *bo = rsrc->bo;
struct panfrost_gtransfer *transfer = CALLOC_STRUCT(panfrost_gtransfer);
transfer->base.level = level;
@@ -405,6 +426,25 @@ panfrost_transfer_map(struct pipe_context *pctx,
panfrost_flush(pctx, NULL, PIPE_FLUSH_END_OF_FRAME);
}
if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
/* TODO: reallocate */
//printf("debug: Missed reallocate\n");
} else if ((usage & PIPE_TRANSFER_WRITE)
&& resource->target == PIPE_BUFFER
&& !util_ranges_intersect(&rsrc->valid_buffer_range, box->x, box->x + box->width)) {
/* No flush for writes to uninitialized */
} else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
if (usage & PIPE_TRANSFER_WRITE) {
/* STUB: flush reading */
//printf("debug: missed reading flush %d\n", resource->target);
} else if (usage & PIPE_TRANSFER_READ) {
/* STUB: flush writing */
//printf("debug: missed writing flush %d (%d-%d)\n", resource->target, box->x, box->x + box->width);
} else {
/* Why are you even mapping?! */
}
}
if (bo->layout != PAN_LINEAR) {
/* Non-linear resources need to be indirectly mapped */
@@ -460,9 +500,9 @@ panfrost_transfer_unmap(struct pipe_context *pctx,
/* Gallium expects writeback here, so we tile */
struct panfrost_gtransfer *trans = pan_transfer(transfer);
struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
if (trans->map) {
struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
struct panfrost_bo *bo = prsrc->bo;
if (transfer->usage & PIPE_TRANSFER_WRITE) {
@@ -480,6 +520,11 @@ panfrost_transfer_unmap(struct pipe_context *pctx,
free(trans->map);
}
util_range_add(&prsrc->valid_buffer_range,
transfer->box.x,
transfer->box.x + transfer->box.width);
/* Derefence the resource */
pipe_resource_reference(&transfer->resource, NULL);
@@ -487,6 +532,20 @@ panfrost_transfer_unmap(struct pipe_context *pctx,
free(transfer);
}
static void
panfrost_transfer_flush_region(struct pipe_context *pctx,
struct pipe_transfer *transfer,
const struct pipe_box *box)
{
struct panfrost_resource *rsc = pan_resource(transfer->resource);
if (transfer->resource->target == PIPE_BUFFER) {
util_range_add(&rsc->valid_buffer_range,
transfer->box.x + box->x,
transfer->box.x + box->x + box->width);
}
}
static struct pb_slab *
panfrost_slab_alloc(void *priv, unsigned heap, unsigned entry_size, unsigned group_index)
{
@@ -564,7 +623,7 @@ static const struct u_transfer_vtbl transfer_vtbl = {
.resource_destroy = panfrost_resource_destroy,
.transfer_map = panfrost_transfer_map,
.transfer_unmap = panfrost_transfer_unmap,
.transfer_flush_region = u_default_transfer_flush_region,
.transfer_flush_region = panfrost_transfer_flush_region,
.get_internal_format = panfrost_resource_get_internal_format,
.set_stencil = panfrost_resource_set_stencil,
.get_stencil = panfrost_resource_get_stencil,