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 <christian.gmeiner@gmail.com>
Signed-off-by: Marek Vasut <marex@denx.de>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Tested-by: Marek Vasut <marex@denx.de>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Tested-by: Boris Brezillon <boris.brezillon@collabora.com>
This commit is contained in:
Christian Gmeiner 2019-02-23 16:15:19 +01:00
parent f1061fa577
commit 64813541d5
7 changed files with 83 additions and 29 deletions

View file

@ -36,6 +36,7 @@
#include "etnaviv_query.h" #include "etnaviv_query.h"
#include "etnaviv_query_hw.h" #include "etnaviv_query_hw.h"
#include "etnaviv_rasterizer.h" #include "etnaviv_rasterizer.h"
#include "etnaviv_resource.h"
#include "etnaviv_screen.h" #include "etnaviv_screen.h"
#include "etnaviv_shader.h" #include "etnaviv_shader.h"
#include "etnaviv_state.h" #include "etnaviv_state.h"
@ -329,7 +330,8 @@ static void
etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv) etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv)
{ {
struct etna_context *ctx = 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_API_MODE, VIVS_GL_API_MODE_OPENGL);
etna_set_state(stream, VIVS_GL_VERTEX_ELEMENT_CONFIG, 0x00000001); 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 = ~0L;
ctx->dirty_sampler_views = ~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) * Go through all _resources_ associated with this _screen_, pending
{ * in this _context_ and mark them as not pending in this _context_
debug_assert(rsc->status != 0); * anymore, since they were just flushed.
rsc->status = 0; */
rsc->pending_ctx = NULL; mtx_lock(&screen->lock);
list_delinit(&rsc->list); 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 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: */ /* need some sane default in case state tracker doesn't set some state: */
ctx->sample_mask = 0xffff; ctx->sample_mask = 0xffff;
list_inithead(&ctx->used_resources);
/* Set sensible defaults for state */ /* Set sensible defaults for state */
etna_cmd_stream_reset_notify(ctx->stream, ctx); etna_cmd_stream_reset_notify(ctx->stream, ctx);

View file

@ -137,9 +137,6 @@ struct etna_context {
uint32_t prim_hwsupport; uint32_t prim_hwsupport;
struct primconvert_context *primconvert; struct primconvert_context *primconvert;
/* list of resources used by currently-unsubmitted renders */
struct list_head used_resources;
struct slab_child_pool transfer_pool; struct slab_child_pool transfer_pool;
struct blitter_context *blitter; struct blitter_context *blitter;

View file

@ -33,6 +33,7 @@
#include "etnaviv_screen.h" #include "etnaviv_screen.h"
#include "etnaviv_translate.h" #include "etnaviv_translate.h"
#include "util/hash_table.h"
#include "util/u_inlines.h" #include "util/u_inlines.h"
#include "util/u_memory.h" #include "util/u_memory.h"
@ -280,7 +281,6 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
rsc->addressing_mode = mode; rsc->addressing_mode = mode;
pipe_reference_init(&rsc->base.reference, 1); pipe_reference_init(&rsc->base.reference, 1);
list_inithead(&rsc->list);
size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale); 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); 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; return &rsc->base;
free_rsc: free_rsc:
@ -462,8 +467,14 @@ etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
static void static void
etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) 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); 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) if (rsc->bo)
etna_bo_del(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) if (rsc->scanout)
renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro); renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro);
list_delinit(&rsc->list);
pipe_resource_reference(&rsc->texture, NULL); pipe_resource_reference(&rsc->texture, NULL);
pipe_resource_reference(&rsc->external, NULL); pipe_resource_reference(&rsc->external, NULL);
@ -511,7 +520,6 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
*prsc = *tmpl; *prsc = *tmpl;
pipe_reference_init(&prsc->reference, 1); pipe_reference_init(&prsc->reference, 1);
list_inithead(&rsc->list);
prsc->screen = pscreen; prsc->screen = pscreen;
rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride); 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; 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) { if (rsc->layout == ETNA_LAYOUT_LINEAR) {
/* /*
* Both sampler and pixel pipes can't handle linear, create a compatible * 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, etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
enum etna_resource_status status) enum etna_resource_status status)
{ {
struct etna_screen *screen = ctx->screen;
struct set_entry *entry;
struct etna_resource *rsc; struct etna_resource *rsc;
if (!prsc) if (!prsc)
return; return;
rsc = etna_resource(prsc); 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; rsc->status |= status;
/* TODO resources can actually be shared across contexts, _mesa_set_add(screen->used_resources, rsc);
* so I'm not sure a single list-head will do the trick? */ _mesa_set_add(rsc->pending_ctx, ctx);
debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx);
list_delinit(&rsc->list); mtx_unlock(&screen->lock);
list_addtail(&rsc->list, &ctx->used_resources);
rsc->pending_ctx = ctx;
} }
bool bool

View file

@ -31,7 +31,10 @@
#include "etnaviv_tiling.h" #include "etnaviv_tiling.h"
#include "pipe/p_state.h" #include "pipe/p_state.h"
#include "util/list.h" #include "util/list.h"
#include "util/set.h"
#include "util/u_helpers.h"
struct etna_context;
struct pipe_screen; struct pipe_screen;
struct util_dynarray; struct util_dynarray;
@ -94,10 +97,7 @@ struct etna_resource {
enum etna_resource_status status; enum etna_resource_status status;
/* resources accessed by queued but not flushed draws are tracked struct set *pending_ctx;
* in the used_resources list. */
struct list_head list;
struct etna_context *pending_ctx;
}; };
/* returns TRUE if a is newer than b */ /* returns TRUE if a is newer than b */

View file

@ -38,6 +38,7 @@
#include "etnaviv_resource.h" #include "etnaviv_resource.h"
#include "etnaviv_translate.h" #include "etnaviv_translate.h"
#include "util/hash_table.h"
#include "util/os_time.h" #include "util/os_time.h"
#include "util/u_math.h" #include "util/u_math.h"
#include "util/u_memory.h" #include "util/u_memory.h"
@ -82,6 +83,9 @@ etna_screen_destroy(struct pipe_screen *pscreen)
{ {
struct etna_screen *screen = etna_screen(pscreen); struct etna_screen *screen = etna_screen(pscreen);
_mesa_set_destroy(screen->used_resources, NULL);
mtx_destroy(&screen->lock);
if (screen->perfmon) if (screen->perfmon)
etna_perfmon_del(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) if (screen->drm_version >= ETNA_DRM_VERSION_PERFMON)
etna_pm_query_setup(screen); 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; return pscreen;
fail2:
mtx_destroy(&screen->lock);
fail: fail:
etna_screen_destroy(pscreen); etna_screen_destroy(pscreen);
return NULL; return NULL;

View file

@ -34,8 +34,10 @@
#include "os/os_thread.h" #include "os/os_thread.h"
#include "pipe/p_screen.h" #include "pipe/p_screen.h"
#include "renderonly/renderonly.h" #include "renderonly/renderonly.h"
#include "util/set.h"
#include "util/slab.h" #include "util/slab.h"
#include "util/u_dynarray.h" #include "util/u_dynarray.h"
#include "util/u_helpers.h"
struct etna_bo; struct etna_bo;
@ -80,6 +82,10 @@ struct etna_screen {
struct etna_specs specs; struct etna_specs specs;
uint32_t drm_version; uint32_t drm_version;
/* set of resources used by currently-unsubmitted renders */
mtx_t lock;
struct set *used_resources;
}; };
static inline struct etna_screen * static inline struct etna_screen *

View file

@ -346,6 +346,7 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
* transfers without a temporary resource. * transfers without a temporary resource.
*/ */
if (trans->rsc || !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { if (trans->rsc || !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
struct etna_screen *screen = ctx->screen;
uint32_t prep_flags = 0; 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 * current GPU usage (reads must wait for GPU writes, writes must have
* exclusive access to the buffer). * exclusive access to the buffer).
*/ */
mtx_lock(&screen->lock);
if ((trans->rsc && (etna_resource(trans->rsc)->status & ETNA_PENDING_WRITE)) || if ((trans->rsc && (etna_resource(trans->rsc)->status & ETNA_PENDING_WRITE)) ||
(!trans->rsc && (!trans->rsc &&
(((usage & PIPE_TRANSFER_READ) && (rsc->status & ETNA_PENDING_WRITE)) || (((usage & PIPE_TRANSFER_READ) && (rsc->status & ETNA_PENDING_WRITE)) ||
((usage & PIPE_TRANSFER_WRITE) && rsc->status)))) ((usage & PIPE_TRANSFER_WRITE) && rsc->status))))
pctx->flush(pctx, NULL, 0); pctx->flush(pctx, NULL, 0);
mtx_unlock(&screen->lock);
if (usage & PIPE_TRANSFER_READ) if (usage & PIPE_TRANSFER_READ)
prep_flags |= DRM_ETNA_PREP_READ; prep_flags |= DRM_ETNA_PREP_READ;
if (usage & PIPE_TRANSFER_WRITE) if (usage & PIPE_TRANSFER_WRITE)