zink: add locking for resource maps

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>
This commit is contained in:
Mike Blumenkrantz 2020-12-24 19:43:10 -05:00 committed by Marge Bot
parent e7420c7708
commit 0731861748
2 changed files with 44 additions and 37 deletions

View 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);
@ -655,6 +657,31 @@ zink_resource_has_usage(struct zink_resource *res, enum zink_resource_access usa
return batch_uses & usage;
}
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))) {

View 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;