zink: add locking for resource maps
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Fri, 25 Dec 2020 00:43:10 +0000 (19:43 -0500)
committerMarge Bot <eric+marge@anholt.net>
Tue, 30 Mar 2021 15:12:58 +0000 (15:12 +0000)
vulkan prohibits multiple maps on a resource, so these have to be locked
down

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9885>

src/gallium/drivers/zink/zink_resource.c
src/gallium/drivers/zink/zink_resource.h

index b0d8783..2ab39de 100644 (file)
@@ -130,6 +130,7 @@ zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_ob
    } else {
       vkDestroyImage(screen->dev, obj->image, NULL);
    }
+   simple_mtx_destroy(&obj->map_mtx);
 
    zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj);
    cache_or_free_mem(screen, obj);
@@ -338,6 +339,7 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t
 
    pipe_reference_init(&obj->reference, 1);
    util_dynarray_init(&obj->desc_set_refs.refs, NULL);
+   simple_mtx_init(&obj->map_mtx, mtx_plain);
    if (templ->target == PIPE_BUFFER) {
       VkBufferCreateInfo bci = create_bci(screen, templ, templ->bind);
 
@@ -656,6 +658,31 @@ zink_resource_has_usage(struct zink_resource *res, enum zink_resource_access usa
 }
 
 static void *
+map_resource(struct zink_screen *screen, struct zink_resource *res)
+{
+   simple_mtx_lock(&res->obj->map_mtx);
+   VkResult result = VK_SUCCESS;
+   if (!res->obj->map_count)
+      result = vkMapMemory(screen->dev, res->obj->mem, res->obj->offset,
+                           res->obj->size, 0, &res->obj->map);
+   res->obj->map_count++;
+   simple_mtx_unlock(&res->obj->map_mtx);
+   return result == VK_SUCCESS ? res->obj->map : NULL;
+}
+
+static void
+unmap_resource(struct zink_screen *screen, struct zink_resource *res)
+{
+   simple_mtx_lock(&res->obj->map_mtx);
+   res->obj->map_count--;
+   if (!res->obj->map_count) {
+      res->obj->map = NULL;
+      vkUnmapMemory(screen->dev, res->obj->mem);
+   }
+   simple_mtx_unlock(&res->obj->map_mtx);
+}
+
+static void *
 buffer_transfer_map(struct zink_context *ctx, struct zink_resource *res, unsigned usage,
                     const struct pipe_box *box, struct zink_transfer *trans)
 {
@@ -689,16 +716,18 @@ buffer_transfer_map(struct zink_context *ctx, struct zink_resource *res, unsigne
                         (struct pipe_resource **)&trans->staging_res, (void **)&ptr);
 
             res = zink_resource(trans->staging_res);
+            /* replacing existing map, still need to increment refcount for tracking since
+             * unmaps will still occur
+             */
+            p_atomic_inc(&res->obj->map_count);
+            res->obj->map = ptr;
          }
       }
    }
 
-   if (!trans->staging_res && res->obj->map)
-      ptr = res->obj->map;
-
    if (!ptr) {
-      VkResult result = vkMapMemory(screen->dev, res->obj->mem, res->obj->offset, res->obj->size, 0, &ptr);
-      if (result != VK_SUCCESS)
+      ptr = map_resource(screen, res);
+      if (!ptr)
          return NULL;
    }
 
@@ -795,18 +824,15 @@ zink_transfer_map(struct pipe_context *pctx,
             zink_fence_wait(pctx);
          }
 
-         VkResult result = vkMapMemory(screen->dev, staging_res->obj->mem,
-                                       staging_res->obj->offset,
-                                       staging_res->obj->size, 0, &base);
-         if (result != VK_SUCCESS)
+         ptr = base = map_resource(screen, staging_res);
+         if (!base)
             return NULL;
-         ptr = base;
-
       } else {
          assert(!res->optimal_tiling);
-
+         base = map_resource(screen, res);
+         if (!base)
+            return NULL;
          /* special case compute reads since they aren't handled by zink_fence_wait() */
-            /* special case compute reads since they aren't handled by zink_fence_wait() */
          if (zink_resource_has_usage(res, ZINK_RESOURCE_ACCESS_READ))
             resource_sync_reads(ctx, res);
          if (zink_resource_has_usage(res, ZINK_RESOURCE_ACCESS_RW)) {
@@ -815,13 +841,6 @@ zink_transfer_map(struct pipe_context *pctx,
             else
                zink_fence_wait(pctx);
          }
-         if (res->obj->map)
-            base = res->obj->map;
-         else {
-            VkResult result = vkMapMemory(screen->dev, res->obj->mem, res->obj->offset, res->obj->size, 0, &base);
-            if (result != VK_SUCCESS)
-               return NULL;
-         }
          VkImageSubresource isr = {
             res->aspect,
             level,
@@ -842,14 +861,6 @@ zink_transfer_map(struct pipe_context *pctx,
    if ((usage & PIPE_MAP_PERSISTENT) && !(usage & PIPE_MAP_COHERENT))
       res->obj->persistent_maps++;
 
-   if (trans->staging_res) {
-      zink_resource(trans->staging_res)->obj->map = base;
-      p_atomic_inc(&zink_resource(trans->staging_res)->obj->map_count);
-   } else {
-      res->obj->map = base;
-      p_atomic_inc(&res->obj->map_count);
-   }
-
    *transfer = &trans->base;
    return ptr;
 }
@@ -884,15 +895,9 @@ zink_transfer_unmap(struct pipe_context *pctx,
    struct zink_resource *res = zink_resource(ptrans->resource);
    struct zink_transfer *trans = (struct zink_transfer *)ptrans;
    if (trans->staging_res) {
-      struct zink_resource *staging_res = zink_resource(trans->staging_res);
-      if (p_atomic_dec_zero(&staging_res->obj->map_count)) {
-         vkUnmapMemory(screen->dev, staging_res->obj->mem);
-         staging_res->obj->map = NULL;
-      }
-   } else if (p_atomic_dec_zero(&res->obj->map_count)) {
-      vkUnmapMemory(screen->dev, res->obj->mem);
-      res->obj->map = NULL;
-   }
+      unmap_resource(screen, zink_resource(trans->staging_res));
+   } else
+      unmap_resource(screen, res);
    if ((trans->base.usage & PIPE_MAP_PERSISTENT) && !(trans->base.usage & PIPE_MAP_COHERENT))
       res->obj->persistent_maps--;
    if (!(trans->base.usage & (PIPE_MAP_FLUSH_EXPLICIT | PIPE_MAP_COHERENT))) {
index 920a253..9e97dd3 100644 (file)
@@ -31,6 +31,7 @@ struct zink_context;
 
 #define ZINK_RESOURCE_USAGE_STREAMOUT (1 << 10) //much greater than ZINK_DESCRIPTOR_TYPES
 
+#include "util/simple_mtx.h"
 #include "util/u_transfer.h"
 #include "util/u_range.h"
 #include "util/u_dynarray.h"
@@ -71,6 +72,7 @@ struct zink_resource_object {
 
    struct zink_batch_usage reads;
    struct zink_batch_usage writes;
+   simple_mtx_t map_mtx;
    unsigned map_count;
    void *map;
    bool is_buffer;