etnaviv: fix resource usage tracking across different pipe_context's
authorChristian Gmeiner <christian.gmeiner@gmail.com>
Sat, 23 Feb 2019 15:15:19 +0000 (16:15 +0100)
committerChristian Gmeiner <christian.gmeiner@gmail.com>
Fri, 1 Mar 2019 07:08:56 +0000 (08:08 +0100)
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>
src/gallium/drivers/etnaviv/etnaviv_context.c
src/gallium/drivers/etnaviv/etnaviv_context.h
src/gallium/drivers/etnaviv/etnaviv_resource.c
src/gallium/drivers/etnaviv/etnaviv_resource.h
src/gallium/drivers/etnaviv/etnaviv_screen.c
src/gallium/drivers/etnaviv/etnaviv_screen.h
src/gallium/drivers/etnaviv/etnaviv_transfer.c

index 44b50925a4fbf3519eec9d1f4d4153617eabb2e6..83a703f7cc25b8e3b6912348c85903a05e1c988e 100644 (file)
@@ -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);
 
index 45b3954c7cb5a647097069fca149685847eb9e6a..a79d739100d97a489138f3693b7bcfd376a9324b 100644 (file)
@@ -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;
 
index 45d5f69169ead5f34bb6ccdc5cbfa661661ca6f3..4437eedfcaba628242911592d97d95fc2b6401c8 100644 (file)
@@ -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
index c45ff7586d14d780c5cdfbbaee0addaf9c309a97..2938ffa9170804464fa2cd508fb6563221ca1977 100644 (file)
 #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 */
index ee32a499fb5cbe54cbe0e71be331d2dbc24a329c..62b6f1c80fae9e8a6f5da8cecea418b7fcf13276 100644 (file)
@@ -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;
index bffd4b6ef94ab272111657435e97b0fece6191ef..9757985526ecf6da3a09dee8f6d5e88e85512cf6 100644 (file)
 #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 *
index 3b925a8ef9f65a4bdf525da12ddbe272ee20cf54..45cd31207f700dc4b41965b449dde3dce4a27832 100644 (file)
@@ -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)