zink: add a mechanism to track current resource usage in batches

this is really primitive, but it at least gives an idea of whether a
resource has been submitted for writing in a pending batch

Reviewed-by: Erik Faye-Lun <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6924>
This commit is contained in:
Mike Blumenkrantz 2020-06-15 15:51:05 -04:00
parent 48b988e35f
commit c6687eef2d
10 changed files with 88 additions and 31 deletions

View file

@ -9,6 +9,7 @@
#include "zink_resource.h"
#include "zink_screen.h"
#include "util/hash_table.h"
#include "util/u_debug.h"
#include "util/set.h"
@ -104,23 +105,32 @@ zink_end_batch(struct zink_context *ctx, struct zink_batch *batch)
}
void
zink_batch_reference_resoure(struct zink_batch *batch,
struct zink_resource *res)
zink_batch_reference_resource_rw(struct zink_batch *batch, struct zink_resource *res, bool write)
{
unsigned mask = write ? ZINK_RESOURCE_ACCESS_WRITE : ZINK_RESOURCE_ACCESS_READ;
/* u_transfer_helper unrefs the stencil buffer when the depth buffer is unrefed,
* so we add an extra ref here to the stencil buffer to compensate
*/
struct zink_resource *stencil;
zink_get_depth_stencil_resources((struct pipe_resource*)res, NULL, &stencil);
struct set_entry *entry = _mesa_set_search(batch->resources, res);
if (!entry) {
entry = _mesa_set_add(batch->resources, res);
pipe_reference(NULL, &res->base.reference);
/* u_transfer_helper unrefs the stencil buffer when the depth buffer is unrefed,
* so we add an extra ref here to the stencil buffer to compensate
*/
struct zink_resource *stencil;
zink_get_depth_stencil_resources((struct pipe_resource*)res, NULL, &stencil);
if (stencil)
pipe_reference(NULL, &stencil->base.reference);
}
/* the batch_uses value for this batch is guaranteed to not be in use now because
* reset_batch() waits on the fence and removes access before resetting
*/
res->batch_uses[batch->batch_id] |= mask;
if (stencil)
stencil->batch_uses[batch->batch_id] |= mask;
}
void

View file

@ -40,6 +40,7 @@ struct zink_sampler_view;
#define ZINK_BATCH_DESC_SIZE 1000
struct zink_batch {
unsigned batch_id : 2;
VkCommandBuffer cmdbuf;
VkDescriptorPool descpool;
int descs_left;
@ -64,8 +65,9 @@ void
zink_end_batch(struct zink_context *ctx, struct zink_batch *batch);
void
zink_batch_reference_resoure(struct zink_batch *batch,
struct zink_resource *res);
zink_batch_reference_resource_rw(struct zink_batch *batch,
struct zink_resource *res,
bool write);
void
zink_batch_reference_sampler_view(struct zink_batch *batch,

View file

@ -28,8 +28,8 @@ blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info)
struct zink_batch *batch = zink_batch_no_rp(ctx);
zink_batch_reference_resoure(batch, src);
zink_batch_reference_resoure(batch, dst);
zink_batch_reference_resource_rw(batch, src, false);
zink_batch_reference_resource_rw(batch, dst, true);
zink_resource_setup_transfer_layouts(batch, src, dst);
@ -88,8 +88,8 @@ blit_native(struct zink_context *ctx, const struct pipe_blit_info *info)
return false;
struct zink_batch *batch = zink_batch_no_rp(ctx);
zink_batch_reference_resoure(batch, src);
zink_batch_reference_resoure(batch, dst);
zink_batch_reference_resource_rw(batch, src, false);
zink_batch_reference_resource_rw(batch, dst, true);
zink_resource_setup_transfer_layouts(batch, src, dst);

View file

@ -971,8 +971,8 @@ zink_resource_copy_region(struct pipe_context *pctx,
region.extent.height = src_box->height;
struct zink_batch *batch = zink_batch_no_rp(ctx);
zink_batch_reference_resoure(batch, src);
zink_batch_reference_resoure(batch, dst);
zink_batch_reference_resource_rw(batch, src, false);
zink_batch_reference_resource_rw(batch, dst, true);
zink_resource_setup_transfer_layouts(batch, src, dst);
vkCmdCopyImage(batch->cmdbuf, src->image, src->layout,
@ -986,8 +986,8 @@ zink_resource_copy_region(struct pipe_context *pctx,
region.size = src_box->width;
struct zink_batch *batch = zink_batch_no_rp(ctx);
zink_batch_reference_resoure(batch, src);
zink_batch_reference_resoure(batch, dst);
zink_batch_reference_resource_rw(batch, src, false);
zink_batch_reference_resource_rw(batch, dst, true);
vkCmdCopyBuffer(batch->cmdbuf, src->buffer, dst->buffer, 1, &region);
} else
@ -1180,6 +1180,8 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
if (vkCreateDescriptorPool(screen->dev, &dpci, 0,
&ctx->batches[i].descpool) != VK_SUCCESS)
goto fail;
ctx->batches[i].batch_id = i;
}
vkGetDeviceQueue(screen->dev, screen->gfx_queue, 0, &ctx->queue);

View file

@ -95,7 +95,7 @@ zink_emit_xfb_vertex_input_barrier(struct zink_context *ctx, struct zink_resourc
barriers[0].buffer = res->buffer;
barriers[0].size = VK_WHOLE_SIZE;
struct zink_batch *batch = zink_batch_no_rp(ctx);
zink_batch_reference_resoure(batch, res);
zink_batch_reference_resource_rw(batch, res, false);
vkCmdPipelineBarrier(batch->cmdbuf,
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
@ -120,7 +120,7 @@ zink_emit_stream_output_targets(struct pipe_context *pctx)
for (unsigned i = 0; i < ctx->num_so_targets; i++) {
struct zink_so_target *t = (struct zink_so_target *)ctx->so_targets[i];
buffers[i] = zink_resource(t->base.buffer)->buffer;
zink_batch_reference_resoure(batch, zink_resource(t->base.buffer));
zink_batch_reference_resource_rw(batch, zink_resource(t->base.buffer), true);
buffer_offsets[i] = t->base.buffer_offset;
buffer_sizes[i] = t->base.buffer_size;
}
@ -144,7 +144,7 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
struct zink_resource *res = zink_resource(vb->buffer.resource);
buffers[i] = res->buffer;
buffer_offsets[i] = vb->buffer_offset;
zink_batch_reference_resoure(batch, res);
zink_batch_reference_resource_rw(batch, res, false);
} else {
buffers[i] = zink_resource(ctx->dummy_buffer)->buffer;
buffer_offsets[i] = 0;
@ -386,7 +386,7 @@ zink_draw_vbo(struct pipe_context *pctx,
int index = shader->bindings[j].index;
if (shader->bindings[j].type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
struct zink_resource *res = zink_resource(ctx->ubos[i][index].buffer);
zink_batch_reference_resoure(batch, res);
zink_batch_reference_resource_rw(batch, res, false);
} else {
struct zink_sampler_view *sampler_view = zink_sampler_view(ctx->image_views[i][index]);
zink_batch_reference_sampler_view(batch, sampler_view);
@ -450,7 +450,7 @@ zink_draw_vbo(struct pipe_context *pctx,
struct zink_so_target *t = zink_so_target(ctx->so_targets[i]);
struct zink_resource *res = zink_resource(t->counter_buffer);
if (t->counter_buffer_valid) {
zink_batch_reference_resoure(batch, zink_resource(t->counter_buffer));
zink_batch_reference_resource_rw(batch, res, true);
counter_buffers[i] = res->buffer;
counter_buffer_offsets[i] = t->counter_buffer_offset;
} else
@ -481,13 +481,13 @@ zink_draw_vbo(struct pipe_context *pctx,
}
struct zink_resource *res = zink_resource(index_buffer);
vkCmdBindIndexBuffer(batch->cmdbuf, res->buffer, index_offset, index_type);
zink_batch_reference_resoure(batch, res);
zink_batch_reference_resource_rw(batch, res, false);
vkCmdDrawIndexed(batch->cmdbuf,
dinfo->count, dinfo->instance_count,
need_index_buffer_unref ? 0 : dinfo->start, dinfo->index_bias, dinfo->start_instance);
} else {
if (so_target && screen->info.tf_props.transformFeedbackDraw) {
zink_batch_reference_resoure(batch, zink_resource(so_target->counter_buffer));
zink_batch_reference_resource_rw(batch, zink_resource(so_target->counter_buffer), true);
screen->vk_CmdDrawIndirectByteCountEXT(batch->cmdbuf, dinfo->instance_count, dinfo->start_instance,
zink_resource(so_target->counter_buffer)->buffer, so_target->counter_buffer_offset, 0,
MIN2(so_target->stride, screen->info.tf_props.maxTransformFeedbackBufferDataStride));

View file

@ -25,8 +25,10 @@
#include "zink_fence.h"
#include "zink_query.h"
#include "zink_resource.h"
#include "zink_screen.h"
#include "util/set.h"
#include "util/u_memory.h"
static void
@ -34,6 +36,7 @@ destroy_fence(struct zink_screen *screen, struct zink_fence *fence)
{
if (fence->fence)
vkDestroyFence(screen->dev, fence->fence, NULL);
util_dynarray_fini(&fence->resources);
FREE(fence);
}
@ -58,6 +61,17 @@ zink_create_fence(struct pipe_screen *pscreen, struct zink_batch *batch)
ret->active_queries = batch->active_queries;
batch->active_queries = NULL;
ret->batch_id = batch->batch_id;
util_dynarray_init(&ret->resources, NULL);
set_foreach(batch->resources, entry) {
/* 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(&ret->resources, struct pipe_resource*, pres);
}
pipe_reference_init(&ret->reference, 1);
return ret;
@ -86,14 +100,35 @@ fence_reference(struct pipe_screen *pscreen,
zink_fence(pfence));
}
static inline void
fence_remove_resource_access(struct zink_fence *fence, struct zink_resource *res)
{
p_atomic_set(&res->batch_uses[fence->batch_id], 0);
}
bool
zink_fence_finish(struct zink_screen *screen, struct zink_fence *fence,
uint64_t timeout_ns)
{
bool success = vkWaitForFences(screen->dev, 1, &fence->fence, VK_TRUE,
timeout_ns) == VK_SUCCESS;
if (success && fence->active_queries)
zink_prune_queries(screen, fence);
if (success) {
if (fence->active_queries)
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_clear(&fence->resources);
}
return success;
}

View file

@ -25,6 +25,7 @@
#define ZINK_FENCE_H
#include "util/u_inlines.h"
#include "util/u_dynarray.h"
#include <vulkan/vulkan.h>
@ -33,8 +34,10 @@ struct zink_screen;
struct zink_fence {
struct pipe_reference reference;
unsigned batch_id : 2;
VkFence fence;
struct set *active_queries; /* zink_query objects which were active at some point in this batch */
struct util_dynarray resources;
};
static inline struct zink_fence *

View file

@ -472,7 +472,7 @@ zink_render_condition(struct pipe_context *pctx,
begin_info.flags = begin_flags;
screen->vk_CmdBeginConditionalRenderingEXT(batch->cmdbuf, &begin_info);
zink_batch_reference_resoure(batch, res);
zink_batch_reference_resource_rw(batch, res, true);
pipe_resource_reference(&pres, NULL);
}

View file

@ -388,8 +388,8 @@ zink_transfer_copy_bufimage(struct zink_context *ctx,
copyRegion.imageExtent.width = trans->base.box.width;
copyRegion.imageExtent.height = trans->base.box.height;
zink_batch_reference_resoure(batch, res);
zink_batch_reference_resoure(batch, staging_res);
zink_batch_reference_resource_rw(batch, res, buf2img);
zink_batch_reference_resource_rw(batch, staging_res, !buf2img);
/* we're using u_transfer_helper_deinterleave, which means we'll be getting PIPE_MAP_* usage
* to indicate whether to copy either the depth or stencil aspects

View file

@ -32,6 +32,9 @@ struct zink_batch;
#include <vulkan/vulkan.h>
#define ZINK_RESOURCE_ACCESS_READ 1
#define ZINK_RESOURCE_ACCESS_WRITE 16
struct zink_resource {
struct pipe_resource base;
@ -53,6 +56,8 @@ struct zink_resource {
struct sw_displaytarget *dt;
unsigned dt_stride;
/* this has to be atomic for fence access, so we can't use a bitmask and make everything neat */
uint8_t batch_uses[4];
bool needs_xfb_barrier;
};