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>tags/19.1-branchpoint
@@ -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); | |||
@@ -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; | |||
@@ -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 |
@@ -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 */ |
@@ -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; |
@@ -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 * |
@@ -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) |