zink: track resource_object usage instead of resource usage
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Tue, 27 Oct 2020 16:07:36 +0000 (12:07 -0400)
committerMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Tue, 16 Mar 2021 02:08:06 +0000 (22:08 -0400)
the resource object is now a state tracker for the inner resource_object,
so it can safely be destroyed even if the backing resource is still in use

this also requires updating various things to keep descriptor states/caches working

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

src/gallium/drivers/zink/zink_batch.c
src/gallium/drivers/zink/zink_context.c
src/gallium/drivers/zink/zink_descriptors.c
src/gallium/drivers/zink/zink_descriptors.h
src/gallium/drivers/zink/zink_draw.c
src/gallium/drivers/zink/zink_fence.c
src/gallium/drivers/zink/zink_resource.c
src/gallium/drivers/zink/zink_resource.h

index 76168d0..a952dd3 100644 (file)
@@ -28,8 +28,8 @@ zink_reset_batch(struct zink_context *ctx, struct zink_batch *batch)
 
    /* unref all used resources */
    set_foreach(batch->resources, entry) {
-      struct pipe_resource *pres = (struct pipe_resource *)entry->key;
-      pipe_resource_reference(&pres, NULL);
+      struct zink_resource_object *obj = (struct zink_resource_object *)entry->key;
+      zink_resource_object_reference(screen, &obj, NULL);
       _mesa_set_remove(batch->resources, entry);
    }
 
@@ -199,12 +199,12 @@ zink_batch_reference_resource_rw(struct zink_batch *batch, struct zink_resource
    uint32_t check_mask = (ZINK_RESOURCE_ACCESS_READ | ZINK_RESOURCE_ACCESS_WRITE) << batch->batch_id;
    if (!(uses_check & check_mask)) {
       bool found = false;
-      _mesa_set_search_and_add(batch->resources, res, &found);
+      _mesa_set_search_and_add(batch->resources, res->obj, &found);
       if (!found) {
-         pipe_reference(NULL, &res->base.reference);
+         pipe_reference(NULL, &res->obj->reference);
          batch->resource_size += res->obj->size;
          if (stencil) {
-            pipe_reference(NULL, &stencil->base.reference);
+            pipe_reference(NULL, &stencil->obj->reference);
             batch->resource_size += stencil->obj->size;
          }
       }
@@ -215,10 +215,10 @@ zink_batch_reference_resource_rw(struct zink_batch *batch, struct zink_resource
    /* the batch_uses value for this batch is guaranteed to not be in use now because
     * zink_reset_batch() waits on the fence and removes access before resetting
     */
-   res->batch_uses[batch->batch_id] |= mask;
+   res->obj->batch_uses[batch->batch_id] |= mask;
 
    if (stencil)
-      stencil->batch_uses[batch->batch_id] |= mask;
+      stencil->obj->batch_uses[batch->batch_id] |= mask;
 
    batch->has_work = true;
    return batch_to_flush;
index ad1f45a..5ec0505 100644 (file)
@@ -57,7 +57,9 @@
 static uint32_t
 calc_descriptor_state_hash_ubo(struct zink_context *ctx, struct zink_shader *zs, enum pipe_shader_type shader, int i, int idx, uint32_t hash)
 {
-   hash = XXH32(&ctx->ubos[shader][idx].buffer, sizeof(void*), hash);
+   struct zink_resource *res = zink_resource(ctx->ubos[shader][idx].buffer);
+   struct zink_resource_object *obj = res ? res->obj : NULL;
+   hash = XXH32(&obj, sizeof(void*), hash);
    void *hash_data = &ctx->ubos[shader][idx].buffer_size;
    size_t data_size = sizeof(unsigned);
    hash = XXH32(hash_data, data_size, hash);
@@ -69,9 +71,15 @@ calc_descriptor_state_hash_ubo(struct zink_context *ctx, struct zink_shader *zs,
 static uint32_t
 calc_descriptor_state_hash_ssbo(struct zink_context *ctx, struct zink_shader *zs, enum pipe_shader_type shader, int i, int idx, uint32_t hash)
 {
-   void *hash_data = &ctx->ssbos[shader][idx];
-   size_t data_size = sizeof(struct pipe_shader_buffer);
-   return XXH32(hash_data, data_size, hash);
+   struct zink_resource *res = zink_resource(ctx->ssbos[shader][idx].buffer);
+   struct zink_resource_object *obj = res ? res->obj : NULL;
+   hash = XXH32(&obj, sizeof(void*), hash);
+   if (obj) {
+      struct pipe_shader_buffer *ssbo = &ctx->ssbos[shader][idx];
+      hash = XXH32(&ssbo->buffer_offset, sizeof(ssbo->buffer_offset), hash);
+      hash = XXH32(&ssbo->buffer_size, sizeof(ssbo->buffer_size), hash);
+   }
+   return hash;
 }
 
 static void
@@ -137,7 +145,7 @@ calc_descriptor_state_hash_image(struct zink_context *ctx, struct zink_shader *z
 
    for (unsigned k = 0; k < zs->bindings[ZINK_DESCRIPTOR_TYPE_IMAGE][i].size; k++) {
       if (!ctx->image_views[shader][idx + k].base.resource) {
-         VkDescriptorImageInfo null_info = {VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED};
+         VkDescriptorImageInfo null_info = {0};
          hash_data = &null_info;
          data_size = sizeof(VkDescriptorImageInfo);
          hash = XXH32(hash_data, data_size, hash);
index 2a1fefc..070af73 100644 (file)
@@ -220,8 +220,8 @@ allocate_desc_set(struct zink_screen *screen, struct zink_program *pg, enum zink
    struct zink_descriptor_set *alloc = ralloc_array(pool, struct zink_descriptor_set, bucket_size);
    assert(alloc);
    unsigned num_resources = pool->num_resources;
-   struct zink_resource **resources = rzalloc_array(pool, struct zink_resource*, num_resources * bucket_size);
-   assert(resources);
+   struct zink_resource_object **res_objs = rzalloc_array(pool, struct zink_resource_object*, num_resources * bucket_size);
+   assert(res_objs);
    void **samplers = NULL;
    if (type == ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW) {
       samplers = rzalloc_array(pool, void*, num_resources * bucket_size);
@@ -246,10 +246,10 @@ allocate_desc_set(struct zink_screen *screen, struct zink_program *pg, enum zink
       zds->num_resources = num_resources;
 #endif
       if (type == ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW) {
-         zds->sampler_views = (struct zink_sampler_view**)&resources[i * pool->key.num_descriptors];
+         zds->sampler_views = (struct zink_sampler_view**)&res_objs[i * pool->key.num_descriptors];
          zds->sampler_states = (struct zink_sampler_state**)&samplers[i * pool->key.num_descriptors];
       } else
-         zds->resources = (struct zink_resource**)&resources[i * pool->key.num_descriptors];
+         zds->res_objs = (struct zink_resource_object**)&res_objs[i * pool->key.num_descriptors];
       zds->desc_set = desc_set[i];
       if (i > 0)
          util_dynarray_append(&pool->alloc_desc_sets, struct zink_descriptor_set *, zds);
@@ -448,7 +448,7 @@ zink_sampler_view_desc_set_add(struct zink_sampler_view *sampler_view, struct zi
 void
 zink_resource_desc_set_add(struct zink_resource *res, struct zink_descriptor_set *zds, unsigned idx)
 {
-   desc_set_ref_add(zds, &res->desc_set_refs, (void**)&zds->resources[idx], res);
+   desc_set_ref_add(zds, res ? &res->obj->desc_set_refs : NULL, (void**)&zds->res_objs[idx], res ? res->obj : NULL);
 }
 
 void
index 5766a02..cc3ccd4 100644 (file)
@@ -101,7 +101,7 @@ struct zink_descriptor_set {
    unsigned num_resources;
 #endif
    union {
-      struct zink_resource **resources;
+      struct zink_resource_object **res_objs;
       struct zink_image_view **image_views;
       struct {
          struct zink_sampler_view **sampler_views;
index c53fb3a..36c2b9d 100644 (file)
@@ -25,7 +25,7 @@ desc_set_res_add(struct zink_descriptor_set *zds, struct zink_resource *res, uns
     * hash table on every resource with the associated descriptor sets that then needs to be iterated through
     * whenever a resource is destroyed
     */
-   assert(!cache_hit || zds->resources[i] == res);
+   assert(!cache_hit || zds->res_objs[i] == (res ? res->obj : NULL));
    if (!cache_hit)
       zink_resource_desc_set_add(res, zds, i);
 }
index 2e1408a..ecdf6b8 100644 (file)
@@ -81,9 +81,9 @@ zink_fence_init(struct zink_fence *fence, struct zink_batch *batch)
       /* the fence needs its own reference to ensure it can safely access lifetime-dependent
        * resource members
        */
-      struct pipe_resource *r = NULL, *pres = (struct pipe_resource *)entry->key;
-      pipe_resource_reference(&r, pres);
-      util_dynarray_append(&fence->resources, struct pipe_resource*, pres);
+      struct zink_resource_object *obj = (struct zink_resource_object *)entry->key;
+      pipe_reference(NULL, &obj->reference);
+      util_dynarray_append(&fence->resources, struct zink_resource_object*, obj);
    }
    fence->deferred_ctx = NULL;
    fence->submitted = true;
@@ -110,9 +110,9 @@ fence_reference(struct pipe_screen *pscreen,
 }
 
 static inline void
-fence_remove_resource_access(struct zink_fence *fence, struct zink_resource *res)
+fence_remove_resource_access(struct zink_fence *fence, struct zink_resource_object *obj)
 {
-   p_atomic_set(&res->batch_uses[fence->batch_id], 0);
+   p_atomic_set(&obj->batch_uses[fence->batch_id], 0);
 }
 
 bool
@@ -139,15 +139,10 @@ zink_fence_finish(struct zink_screen *screen, struct pipe_context *pctx, struct
          zink_prune_queries(screen, fence);
 
       /* unref all used resources */
-      util_dynarray_foreach(&fence->resources, struct pipe_resource*, pres) {
-         struct zink_resource *stencil, *res = zink_resource(*pres);
-         fence_remove_resource_access(fence, res);
-
-         /* we still hold a ref, so this doesn't need to be atomic */
-         zink_get_depth_stencil_resources((struct pipe_resource*)res, NULL, &stencil);
-         if (stencil)
-            fence_remove_resource_access(fence, stencil);
-         pipe_resource_reference(pres, NULL);
+      util_dynarray_foreach(&fence->resources, struct zink_resource_object*, obj) {
+         fence_remove_resource_access(fence, *obj);
+
+         zink_resource_object_reference(screen, obj, NULL);
       }
       util_dynarray_clear(&fence->resources);
       fence->submitted = false;
index 9da0961..4d1d873 100644 (file)
 #include "drm-uapi/drm_fourcc.h"
 #endif
 
+void
+debug_describe_zink_resource_object(char *buf, const struct zink_resource_object *ptr)
+{
+   sprintf(buf, "zink_resource_object");
+}
+
+
 static void
 resource_sync_writes_from_batch_usage(struct zink_context *ctx, uint32_t batch_uses)
 {
@@ -120,14 +127,15 @@ cache_or_free_mem(struct zink_screen *screen, struct zink_resource_object *obj)
    vkFreeMemory(screen->dev, obj->mem, NULL);
 }
 
-static void
-resource_object_destroy(struct zink_screen *screen, struct zink_resource_object *obj)
+void
+zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_object *obj)
 {
    if (obj->is_buffer)
       vkDestroyBuffer(screen->dev, obj->buffer, NULL);
    else
       vkDestroyImage(screen->dev, obj->image, NULL);
 
+   zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj);
    cache_or_free_mem(screen, obj);
    FREE(obj);
 }
@@ -141,8 +149,7 @@ zink_resource_destroy(struct pipe_screen *pscreen,
    if (pres->target == PIPE_BUFFER)
       util_range_destroy(&res->valid_buffer_range);
 
-   zink_descriptor_set_refs_clear(&res->desc_set_refs, res);
-   resource_object_destroy(screen, res->obj);
+   zink_resource_object_reference(screen, &res->obj, NULL);
    FREE(res);
 }
 
@@ -189,6 +196,8 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t
    VkMemoryRequirements reqs = {};
    VkMemoryPropertyFlags flags;
 
+   pipe_reference_init(&obj->reference, 1);
+   util_dynarray_init(&obj->desc_set_refs.refs, NULL);
    if (templ->target == PIPE_BUFFER) {
       VkBufferCreateInfo bci = {};
       bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
@@ -498,7 +507,6 @@ resource_create(struct pipe_screen *pscreen,
                                              &res->dt_stride);
    }
 
-   util_dynarray_init(&res->desc_set_refs.refs, NULL);
    return &res->base;
 }
 
@@ -589,8 +597,8 @@ uint32_t
 zink_get_resource_usage(struct zink_resource *res)
 {
    uint32_t batch_uses = 0;
-   for (unsigned i = 0; i < ARRAY_SIZE(res->batch_uses); i++)
-      batch_uses |= p_atomic_read(&res->batch_uses[i]) << i;
+   for (unsigned i = 0; i < ARRAY_SIZE(res->obj->batch_uses); i++)
+      batch_uses |= p_atomic_read(&res->obj->batch_uses[i]) << i;
    return batch_uses;
 }
 
index 85b4ff8..ada3edc 100644 (file)
@@ -57,6 +57,10 @@ struct zink_resource_object {
    VkDeviceSize offset, size;
 
    unsigned persistent_maps; //if nonzero, requires vkFlushMappedMemoryRanges during batch use
+   struct zink_descriptor_refs desc_set_refs;
+
+   /* this has to be atomic for fence access, so we can't use a bitmask and make everything neat */
+   uint8_t batch_uses[5]; //ZINK_NUM_BATCHES
    bool is_buffer;
    bool host_visible;
 };
@@ -82,11 +86,6 @@ struct zink_resource {
 
    struct sw_displaytarget *dt;
    unsigned dt_stride;
-
-   struct zink_descriptor_refs desc_set_refs;
-
-   /* this has to be atomic for fence access, so we can't use a bitmask and make everything neat */
-   uint8_t batch_uses[5]; //ZINK_NUM_BATCHES
 };
 
 struct zink_transfer {
@@ -122,4 +121,25 @@ zink_get_resource_usage(struct zink_resource *res);
 
 void
 zink_resource_desc_set_add(struct zink_resource *res, struct zink_descriptor_set *zds, unsigned idx);
+
+
+void
+zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_object *resource_object);
+
+void
+debug_describe_zink_resource_object(char *buf, const struct zink_resource_object *ptr);
+
+static inline void
+zink_resource_object_reference(struct zink_screen *screen,
+                             struct zink_resource_object **dst,
+                             struct zink_resource_object *src)
+{
+   struct zink_resource_object *old_dst = dst ? *dst : NULL;
+
+   if (pipe_reference_described(old_dst ? &old_dst->reference : NULL, &src->reference,
+                                (debug_reference_descriptor)debug_describe_zink_resource_object))
+      zink_destroy_resource_object(screen, old_dst);
+   if (dst) *dst = src;
+}
+
 #endif