diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c index ff03650ffa5..4a33b7a9229 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.c +++ b/src/gallium/drivers/etnaviv/etnaviv_context.c @@ -63,23 +63,38 @@ etna_context_destroy(struct pipe_context *pctx) struct etna_context *ctx = etna_context(pctx); struct etna_screen *screen = ctx->screen; - if (ctx->used_resources) { - mtx_lock(&screen->lock); + mtx_lock(&screen->lock); + if (ctx->used_resources_read) { /* * There should be no resources tracked in the context when it's being * destroyed. Be sure there are none to avoid memory leaks on buggy * programs. */ - set_foreach(ctx->used_resources, entry) { + set_foreach(ctx->used_resources_read, entry) { struct etna_resource *rsc = (struct etna_resource *)entry->key; _mesa_set_remove_key(rsc->pending_ctx, ctx); } - _mesa_set_destroy(ctx->used_resources, NULL); + _mesa_set_destroy(ctx->used_resources_read, NULL); - mtx_unlock(&screen->lock); } + if (ctx->used_resources_write) { + + /* + * There should be no resources tracked in the context when it's being + * destroyed. Be sure there are none to avoid memory leaks on buggy + * programs. + */ + set_foreach(ctx->used_resources_write, entry) { + struct etna_resource *rsc = (struct etna_resource *)entry->key; + + _mesa_set_remove_key(rsc->pending_ctx, ctx); + } + _mesa_set_destroy(ctx->used_resources_write, NULL); + + } + mtx_unlock(&screen->lock); if (ctx->dummy_rt) etna_bo_del(ctx->dummy_rt); @@ -417,17 +432,25 @@ etna_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence, * Go through all _resources_ pending in this _context_ and mark them as * not pending in this _context_ anymore, since they were just flushed. */ - set_foreach(ctx->used_resources, entry) { + set_foreach(ctx->used_resources_read, entry) { struct etna_resource *rsc = (struct etna_resource *)entry->key; struct pipe_resource *referenced = &rsc->base; - rsc->status = 0; - _mesa_set_remove_key(rsc->pending_ctx, ctx); pipe_resource_reference(&referenced, NULL); } - _mesa_set_clear(ctx->used_resources, NULL); + _mesa_set_clear(ctx->used_resources_read, NULL); + + set_foreach(ctx->used_resources_write, entry) { + struct etna_resource *rsc = (struct etna_resource *)entry->key; + struct pipe_resource *referenced = &rsc->base; + + _mesa_set_remove_key(rsc->pending_ctx, ctx); + + pipe_resource_reference(&referenced, NULL); + } + _mesa_set_clear(ctx->used_resources_write, NULL); mtx_unlock(&screen->lock); @@ -479,9 +502,14 @@ etna_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) if (ctx->stream == NULL) goto fail; - ctx->used_resources = _mesa_set_create(NULL, _mesa_hash_pointer, + ctx->used_resources_read = _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); - if (!ctx->used_resources) + if (!ctx->used_resources_read) + goto fail; + + ctx->used_resources_write = _mesa_set_create(NULL, _mesa_hash_pointer, + _mesa_key_pointer_equal); + if (!ctx->used_resources_write) goto fail; /* context ctxate setup */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h index 9fa6396dbb5..25169abd71d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.h +++ b/src/gallium/drivers/etnaviv/etnaviv_context.h @@ -192,7 +192,8 @@ struct etna_context { struct etna_reloc dummy_rt_reloc; /* set of resources used by currently-unsubmitted renders */ - struct set *used_resources; + struct set *used_resources_read; + struct set *used_resources_write; }; static inline struct etna_context * diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index 4ccf887f600..1d1a0587f2a 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -605,6 +605,35 @@ etna_resource_get_handle(struct pipe_screen *pscreen, } } +enum etna_resource_status +etna_resource_get_status(struct etna_context *ctx, struct etna_resource *rsc) +{ + enum etna_resource_status newstatus = 0; + + set_foreach(rsc->pending_ctx, entry) { + struct etna_context *extctx = (struct etna_context *)entry->key; + struct pipe_context *pctx = &extctx->base; + + set_foreach(extctx->used_resources_read, entry2) { + struct etna_resource *rsc2 = (struct etna_resource *)entry2->key; + if (ctx == extctx || rsc2 != rsc) + continue; + + newstatus |= ETNA_PENDING_READ; + } + + set_foreach(extctx->used_resources_write, entry2) { + struct etna_resource *rsc2 = (struct etna_resource *)entry2->key; + if (ctx == extctx || rsc2 != rsc) + continue; + + newstatus |= ETNA_PENDING_WRITE; + } + } + + return newstatus; +} + void etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc, enum etna_resource_status status) @@ -616,40 +645,40 @@ etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc, if (!prsc) return; - rsc = etna_resource(prsc); - mtx_lock(&screen->lock); - /* - * if we are pending read or write by any other context or - * if reading a resource pending a write, then - * flush all the contexts to maintain coherency - */ - if (((status & ETNA_PENDING_WRITE) && rsc->status) || - ((status & ETNA_PENDING_READ) && (rsc->status & ETNA_PENDING_WRITE))) { - set_foreach(rsc->pending_ctx, entry) { - struct etna_context *extctx = (struct etna_context *)entry->key; - struct pipe_context *pctx = &extctx->base; + rsc = etna_resource(prsc); - if (extctx == ctx) + enum etna_resource_status newstatus = 0; + + set_foreach(rsc->pending_ctx, entry) { + struct etna_context *extctx = (struct etna_context *)entry->key; + struct pipe_context *pctx = &extctx->base; + + set_foreach(extctx->used_resources_read, entry2) { + struct etna_resource *rsc2 = (struct etna_resource *)entry2->key; + if (ctx == extctx || rsc2 != rsc) + continue; + + if (status & ETNA_PENDING_WRITE) + pctx->flush(pctx, NULL, 0); + } + + set_foreach(extctx->used_resources_write, entry2) { + struct etna_resource *rsc2 = (struct etna_resource *)entry2->key; + if (ctx == extctx || rsc2 != rsc) continue; pctx->flush(pctx, NULL, 0); - /* It's safe to clear the status here. If we need to flush it means - * either another context had the resource in exclusive (write) use, - * or we transition the resource to exclusive use in our context. - * In both cases the new status accurately reflects the resource use - * after the flush. - */ - rsc->status = 0; } } - rsc->status |= status; + rsc->status = status; if (!_mesa_set_search(rsc->pending_ctx, ctx)) { pipe_resource_reference(&referenced, prsc); - _mesa_set_add(ctx->used_resources, rsc); + _mesa_set_add((status & ETNA_PENDING_READ) ? + ctx->used_resources_read : ctx->used_resources_write, rsc); _mesa_set_add(rsc->pending_ctx, ctx); } diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index 1c253006471..64aef18a016 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h @@ -134,6 +134,9 @@ etna_resource(struct pipe_resource *p) return (struct etna_resource *)p; } +enum etna_resource_status +etna_resource_get_status(struct etna_context *ctx, struct etna_resource *rsc); + void etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc, enum etna_resource_status status);