From: Christian Gmeiner Date: Sat, 23 Feb 2019 15:15:19 +0000 (+0100) Subject: etnaviv: fix resource usage tracking across different pipe_context's X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=commitdiff_plain;h=64813541d575c4244293c6cbcd9739b12a22a76f etnaviv: fix resource usage tracking across different pipe_context's A pipe_resource can be shared by all the pipe_context's hanging off the same pipe_screen. Changes from v2 -> v3: - add locking with mtx_*() to resource and screen (Marek) Changes from v3 -> v4: - drop rsc->lock, just use screen->lock for the entire serialization (Marek) - simplify etna_resource_used() flush condition, which also prevents potentially flushing resources twice (Marek) - don't remove resouces from screen->used_resources in etna_cmd_stream_reset_notify(), they may still be used in other contexts and may need flushing there later on (Marek) Changes from v4 -> v5: - Fix coding style issues reported by Guido Changes from v5 -> v6: - Add missing locking in etna_transfer_map(..) (Boris) Signed-off-by: Christian Gmeiner Signed-off-by: Marek Vasut Signed-off-by: Boris Brezillon Tested-by: Marek Vasut Reviewed-by: Boris Brezillon Tested-by: Boris Brezillon --- diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c index 44b50925a4f..83a703f7cc2 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.c +++ b/src/gallium/drivers/etnaviv/etnaviv_context.c @@ -36,6 +36,7 @@ #include "etnaviv_query.h" #include "etnaviv_query_hw.h" #include "etnaviv_rasterizer.h" +#include "etnaviv_resource.h" #include "etnaviv_screen.h" #include "etnaviv_shader.h" #include "etnaviv_state.h" @@ -329,7 +330,8 @@ static void etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv) { struct etna_context *ctx = priv; - struct etna_resource *rsc, *rsc_tmp; + struct etna_screen *screen = ctx->screen; + struct set_entry *entry; etna_set_state(stream, VIVS_GL_API_MODE, VIVS_GL_API_MODE_OPENGL); etna_set_state(stream, VIVS_GL_VERTEX_ELEMENT_CONFIG, 0x00000001); @@ -384,16 +386,18 @@ etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv) ctx->dirty = ~0L; ctx->dirty_sampler_views = ~0L; - /* go through all the used resources and clear their status flag */ - LIST_FOR_EACH_ENTRY_SAFE(rsc, rsc_tmp, &ctx->used_resources, list) - { - debug_assert(rsc->status != 0); - rsc->status = 0; - rsc->pending_ctx = NULL; - list_delinit(&rsc->list); - } + /* + * Go through all _resources_ associated with this _screen_, pending + * in this _context_ and mark them as not pending in this _context_ + * anymore, since they were just flushed. + */ + mtx_lock(&screen->lock); + set_foreach(screen->used_resources, entry) { + struct etna_resource *rsc = (struct etna_resource *)entry->key; - assert(LIST_IS_EMPTY(&ctx->used_resources)); + _mesa_set_remove_key(rsc->pending_ctx, ctx); + } + mtx_unlock(&screen->lock); } static void @@ -437,8 +441,6 @@ etna_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) /* need some sane default in case state tracker doesn't set some state: */ ctx->sample_mask = 0xffff; - list_inithead(&ctx->used_resources); - /* Set sensible defaults for state */ etna_cmd_stream_reset_notify(ctx->stream, ctx); diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h index 45b3954c7cb..a79d739100d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.h +++ b/src/gallium/drivers/etnaviv/etnaviv_context.h @@ -137,9 +137,6 @@ struct etna_context { uint32_t prim_hwsupport; struct primconvert_context *primconvert; - /* list of resources used by currently-unsubmitted renders */ - struct list_head used_resources; - struct slab_child_pool transfer_pool; struct blitter_context *blitter; diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index 45d5f69169e..4437eedfcab 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -33,6 +33,7 @@ #include "etnaviv_screen.h" #include "etnaviv_translate.h" +#include "util/hash_table.h" #include "util/u_inlines.h" #include "util/u_memory.h" @@ -280,7 +281,6 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, rsc->addressing_mode = mode; pipe_reference_init(&rsc->base.reference, 1); - list_inithead(&rsc->list); size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale); @@ -301,6 +301,11 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, memset(map, 0, size); } + rsc->pending_ctx = _mesa_set_create(NULL, _mesa_hash_pointer, + _mesa_key_pointer_equal); + if (!rsc->pending_ctx) + goto free_rsc; + return &rsc->base; free_rsc: @@ -462,8 +467,14 @@ etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc) static void etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) { + struct etna_screen *screen = etna_screen(pscreen); struct etna_resource *rsc = etna_resource(prsc); + mtx_lock(&screen->lock); + _mesa_set_remove_key(screen->used_resources, rsc); + _mesa_set_destroy(rsc->pending_ctx, NULL); + mtx_unlock(&screen->lock); + if (rsc->bo) etna_bo_del(rsc->bo); @@ -473,8 +484,6 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) if (rsc->scanout) renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro); - list_delinit(&rsc->list); - pipe_resource_reference(&rsc->texture, NULL); pipe_resource_reference(&rsc->external, NULL); @@ -511,7 +520,6 @@ etna_resource_from_handle(struct pipe_screen *pscreen, *prsc = *tmpl; pipe_reference_init(&prsc->reference, 1); - list_inithead(&rsc->list); prsc->screen = pscreen; rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride); @@ -558,6 +566,11 @@ etna_resource_from_handle(struct pipe_screen *pscreen, goto fail; } + rsc->pending_ctx = _mesa_set_create(NULL, _mesa_hash_pointer, + _mesa_key_pointer_equal); + if (!rsc->pending_ctx) + goto fail; + if (rsc->layout == ETNA_LAYOUT_LINEAR) { /* * Both sampler and pixel pipes can't handle linear, create a compatible @@ -632,20 +645,39 @@ void etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc, enum etna_resource_status status) { + struct etna_screen *screen = ctx->screen; + struct set_entry *entry; struct etna_resource *rsc; 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; + + pctx->flush(pctx, NULL, 0); + } + rsc->status = 0; + } + rsc->status |= status; - /* TODO resources can actually be shared across contexts, - * so I'm not sure a single list-head will do the trick? */ - debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx); - list_delinit(&rsc->list); - list_addtail(&rsc->list, &ctx->used_resources); - rsc->pending_ctx = ctx; + _mesa_set_add(screen->used_resources, rsc); + _mesa_set_add(rsc->pending_ctx, ctx); + + mtx_unlock(&screen->lock); } bool diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index c45ff7586d1..2938ffa9170 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h @@ -31,7 +31,10 @@ #include "etnaviv_tiling.h" #include "pipe/p_state.h" #include "util/list.h" +#include "util/set.h" +#include "util/u_helpers.h" +struct etna_context; struct pipe_screen; struct util_dynarray; @@ -94,10 +97,7 @@ struct etna_resource { enum etna_resource_status status; - /* resources accessed by queued but not flushed draws are tracked - * in the used_resources list. */ - struct list_head list; - struct etna_context *pending_ctx; + struct set *pending_ctx; }; /* returns TRUE if a is newer than b */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c index ee32a499fb5..62b6f1c80fa 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_screen.c +++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c @@ -38,6 +38,7 @@ #include "etnaviv_resource.h" #include "etnaviv_translate.h" +#include "util/hash_table.h" #include "util/os_time.h" #include "util/u_math.h" #include "util/u_memory.h" @@ -82,6 +83,9 @@ etna_screen_destroy(struct pipe_screen *pscreen) { struct etna_screen *screen = etna_screen(pscreen); + _mesa_set_destroy(screen->used_resources, NULL); + mtx_destroy(&screen->lock); + if (screen->perfmon) etna_perfmon_del(screen->perfmon); @@ -1019,8 +1023,16 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu, if (screen->drm_version >= ETNA_DRM_VERSION_PERFMON) etna_pm_query_setup(screen); + mtx_init(&screen->lock, mtx_recursive); + screen->used_resources = _mesa_set_create(NULL, _mesa_hash_pointer, + _mesa_key_pointer_equal); + if (!screen->used_resources) + goto fail2; + return pscreen; +fail2: + mtx_destroy(&screen->lock); fail: etna_screen_destroy(pscreen); return NULL; diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.h b/src/gallium/drivers/etnaviv/etnaviv_screen.h index bffd4b6ef94..9757985526e 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_screen.h +++ b/src/gallium/drivers/etnaviv/etnaviv_screen.h @@ -34,8 +34,10 @@ #include "os/os_thread.h" #include "pipe/p_screen.h" #include "renderonly/renderonly.h" +#include "util/set.h" #include "util/slab.h" #include "util/u_dynarray.h" +#include "util/u_helpers.h" struct etna_bo; @@ -80,6 +82,10 @@ struct etna_screen { struct etna_specs specs; uint32_t drm_version; + + /* set of resources used by currently-unsubmitted renders */ + mtx_t lock; + struct set *used_resources; }; static inline struct etna_screen * diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c index 3b925a8ef9f..45cd31207f7 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c +++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c @@ -346,6 +346,7 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, * transfers without a temporary resource. */ if (trans->rsc || !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { + struct etna_screen *screen = ctx->screen; uint32_t prep_flags = 0; /* @@ -354,12 +355,16 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, * current GPU usage (reads must wait for GPU writes, writes must have * exclusive access to the buffer). */ + mtx_lock(&screen->lock); + if ((trans->rsc && (etna_resource(trans->rsc)->status & ETNA_PENDING_WRITE)) || (!trans->rsc && (((usage & PIPE_TRANSFER_READ) && (rsc->status & ETNA_PENDING_WRITE)) || ((usage & PIPE_TRANSFER_WRITE) && rsc->status)))) pctx->flush(pctx, NULL, 0); + mtx_unlock(&screen->lock); + if (usage & PIPE_TRANSFER_READ) prep_flags |= DRM_ETNA_PREP_READ; if (usage & PIPE_TRANSFER_WRITE)