mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 07:28:11 +02:00
zink: create separate vk image/buffer objects for shader image use
the STORAGE_TEXEL and STORAGE_IMAGE bits can't be accurately applied due to opengl allowing all resources to be used everywhere, so instead we can create a separate object on demand which is used only by shaders and gets extra barriers inferred along with the base object to avoid desync whenever it is used Reviewed-by: Dave Airlie <airlied@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9788>
This commit is contained in:
parent
475c1bda8e
commit
69cdb6b776
6 changed files with 196 additions and 10 deletions
|
|
@ -984,6 +984,10 @@ zink_set_shader_images(struct pipe_context *pctx,
|
|||
if (images && images[i].resource) {
|
||||
util_dynarray_init(&image_view->desc_set_refs.refs, NULL);
|
||||
struct zink_resource *res = zink_resource(images[i].resource);
|
||||
if (!zink_resource_object_init_storage(ctx, res)) {
|
||||
debug_printf("couldn't create storage image!");
|
||||
continue;
|
||||
}
|
||||
res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_IMAGE);
|
||||
res->bind_stages |= 1 << p_stage;
|
||||
util_copy_image_view(&image_view->base, images + i);
|
||||
|
|
@ -1055,6 +1059,12 @@ zink_set_sampler_views(struct pipe_context *pctx,
|
|||
sampler_view_buffer_clear(ctx, b);
|
||||
b->buffer_view = buffer_view;
|
||||
}
|
||||
} else if (!res->obj->is_buffer) {
|
||||
if (res->obj != b->image_view->obj) {
|
||||
struct pipe_surface *psurf = &b->image_view->base;
|
||||
zink_rebind_surface(ctx, &psurf);
|
||||
b->image_view = zink_surface(psurf);
|
||||
}
|
||||
}
|
||||
res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW);
|
||||
res->bind_stages |= 1 << shader_type;
|
||||
|
|
@ -1375,6 +1385,27 @@ zink_flush_queue(struct zink_context *ctx)
|
|||
flush_batch(ctx);
|
||||
}
|
||||
|
||||
static bool
|
||||
rebind_fb_surface(struct zink_context *ctx, struct pipe_surface **surf, struct zink_resource *match_res)
|
||||
{
|
||||
if (!*surf)
|
||||
return false;
|
||||
struct zink_resource *surf_res = zink_resource((*surf)->texture);
|
||||
if ((match_res == surf_res) || surf_res->obj != zink_surface(*surf)->obj)
|
||||
return zink_rebind_surface(ctx, surf);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
rebind_fb_state(struct zink_context *ctx, struct zink_resource *match_res)
|
||||
{
|
||||
bool rebind = false;
|
||||
for (int i = 0; i < ctx->fb_state.nr_cbufs; i++)
|
||||
rebind |= rebind_fb_surface(ctx, &ctx->fb_state.cbufs[i], match_res);
|
||||
rebind |= rebind_fb_surface(ctx, &ctx->fb_state.zsbuf, match_res);
|
||||
return rebind;
|
||||
}
|
||||
|
||||
static void
|
||||
zink_set_framebuffer_state(struct pipe_context *pctx,
|
||||
const struct pipe_framebuffer_state *state)
|
||||
|
|
@ -1398,6 +1429,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx,
|
|||
}
|
||||
|
||||
util_copy_framebuffer_state(&ctx->fb_state, state);
|
||||
rebind_fb_state(ctx, NULL);
|
||||
/* get_framebuffer adds a ref if the fb is reused or created;
|
||||
* always do get_framebuffer first to avoid deleting the same fb
|
||||
* we're about to use
|
||||
|
|
@ -1632,6 +1664,7 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_batch *batch,
|
|||
/* only barrier if we're changing layout or doing something besides read -> read */
|
||||
batch = zink_batch_no_rp(ctx);
|
||||
assert(!batch->in_rp);
|
||||
assert(new_layout);
|
||||
vkCmdPipelineBarrier(
|
||||
batch->state->cmdbuf,
|
||||
res->access_stage ? res->access_stage : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
|
|
@ -2326,6 +2359,22 @@ zink_set_stream_output_targets(struct pipe_context *pctx,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res)
|
||||
{
|
||||
if (!ctx->framebuffer)
|
||||
return;
|
||||
for (unsigned i = 0; i < ctx->framebuffer->state.num_attachments; i++) {
|
||||
if (!ctx->framebuffer->surfaces[i] ||
|
||||
zink_resource(ctx->framebuffer->surfaces[i]->texture) != res)
|
||||
continue;
|
||||
zink_rebind_surface(ctx, &ctx->framebuffer->surfaces[i]);
|
||||
zink_batch_no_rp(ctx);
|
||||
}
|
||||
if (rebind_fb_state(ctx, res))
|
||||
zink_batch_no_rp(ctx);
|
||||
}
|
||||
|
||||
void
|
||||
zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res)
|
||||
{
|
||||
|
|
@ -2368,6 +2417,10 @@ zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res)
|
|||
struct zink_image_view *image_view = &ctx->image_views[shader][i];
|
||||
zink_descriptor_set_refs_clear(&image_view->desc_set_refs, image_view);
|
||||
zink_buffer_view_reference(zink_screen(ctx->base.screen), &image_view->buffer_view, NULL);
|
||||
if (!zink_resource_object_init_storage(ctx, res)) {
|
||||
debug_printf("couldn't create storage image!");
|
||||
continue;
|
||||
}
|
||||
image_view->buffer_view = get_buffer_view(ctx, res, image_view->base.format,
|
||||
image_view->base.u.buf.offset, image_view->base.u.buf.size);
|
||||
assert(image_view->buffer_view);
|
||||
|
|
|
|||
|
|
@ -323,6 +323,9 @@ zink_rect_from_box(const struct pipe_box *box)
|
|||
void
|
||||
zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res);
|
||||
|
||||
void
|
||||
zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res);
|
||||
|
||||
void
|
||||
zink_draw_vbo(struct pipe_context *pctx,
|
||||
const struct pipe_draw_info *dinfo,
|
||||
|
|
|
|||
|
|
@ -123,10 +123,13 @@ void
|
|||
zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_object *obj)
|
||||
{
|
||||
assert(!obj->map_count);
|
||||
if (obj->is_buffer)
|
||||
if (obj->is_buffer) {
|
||||
if (obj->sbuffer)
|
||||
vkDestroyBuffer(screen->dev, obj->sbuffer, NULL);
|
||||
vkDestroyBuffer(screen->dev, obj->buffer, NULL);
|
||||
else
|
||||
} else {
|
||||
vkDestroyImage(screen->dev, obj->image, NULL);
|
||||
}
|
||||
|
||||
zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj);
|
||||
cache_or_free_mem(screen, obj);
|
||||
|
|
@ -201,9 +204,6 @@ create_bci(struct zink_screen *screen, const struct pipe_resource *templ, unsign
|
|||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
|
||||
VkFormatProperties props = screen->format_props[templ->format];
|
||||
if (props.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
|
||||
bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||
}
|
||||
|
||||
if (bind & PIPE_BIND_VERTEX_BUFFER)
|
||||
|
|
@ -222,6 +222,9 @@ create_bci(struct zink_screen *screen, const struct pipe_resource *templ, unsign
|
|||
if (bind & PIPE_BIND_SHADER_BUFFER)
|
||||
bci.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
|
||||
if (bind & PIPE_BIND_SHADER_IMAGE)
|
||||
bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||
|
||||
if (bind & PIPE_BIND_COMMAND_ARGS_BUFFER)
|
||||
bci.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
|
||||
|
||||
|
|
@ -294,12 +297,8 @@ create_ici(struct zink_screen *screen, const struct pipe_resource *templ, unsign
|
|||
VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
if ((templ->nr_samples <= 1 || screen->info.feats.features.shaderStorageImageMultisample) &&
|
||||
(bind & PIPE_BIND_SHADER_IMAGE ||
|
||||
(bind & PIPE_BIND_SAMPLER_VIEW && templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY))) {
|
||||
(bind & PIPE_BIND_SHADER_IMAGE)) {
|
||||
VkFormatProperties props = screen->format_props[templ->format];
|
||||
/* gallium doesn't provide any way to actually know whether this will be used as a shader image,
|
||||
* so we have to just assume and set the bit if it's available
|
||||
*/
|
||||
if ((ici.tiling == VK_IMAGE_TILING_LINEAR && props.linearTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) ||
|
||||
(ici.tiling == VK_IMAGE_TILING_OPTIMAL && props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
|
||||
ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
|
|
@ -929,6 +928,81 @@ zink_resource_get_separate_stencil(struct pipe_resource *pres)
|
|||
|
||||
}
|
||||
|
||||
bool
|
||||
zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res)
|
||||
{
|
||||
struct zink_screen *screen = zink_screen(ctx->base.screen);
|
||||
/* base resource already has the cap */
|
||||
if (res->base.bind & PIPE_BIND_SHADER_IMAGE)
|
||||
return true;
|
||||
if (res->obj->is_buffer) {
|
||||
if (res->obj->sbuffer)
|
||||
return true;
|
||||
VkBufferCreateInfo bci = create_bci(screen, &res->base, res->base.bind | PIPE_BIND_SHADER_IMAGE);
|
||||
VkBuffer buffer;
|
||||
if (vkCreateBuffer(screen->dev, &bci, NULL, &buffer) != VK_SUCCESS)
|
||||
return false;
|
||||
vkBindBufferMemory(screen->dev, buffer, res->obj->mem, res->obj->offset);
|
||||
res->obj->sbuffer = res->obj->buffer;
|
||||
res->obj->buffer = buffer;
|
||||
} else {
|
||||
zink_fb_clears_apply_region(ctx, &res->base, (struct u_rect){0, res->base.width0, 0, res->base.height0});
|
||||
zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0);
|
||||
res->base.bind |= PIPE_BIND_SHADER_IMAGE;
|
||||
struct zink_resource_object *old_obj = res->obj;
|
||||
struct zink_resource_object *new_obj = resource_object_create(screen, &res->base, NULL, &res->optimal_tiling);
|
||||
if (!new_obj) {
|
||||
debug_printf("new backing resource alloc failed!");
|
||||
res->base.bind &= ~PIPE_BIND_SHADER_IMAGE;
|
||||
return false;
|
||||
}
|
||||
struct zink_resource staging = *res;
|
||||
staging.obj = old_obj;
|
||||
res->obj = new_obj;
|
||||
zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj);
|
||||
for (unsigned i = 0; i <= res->base.last_level; i++) {
|
||||
struct pipe_box box = {0, 0, 0,
|
||||
u_minify(res->base.width0, i),
|
||||
u_minify(res->base.height0, i), res->base.array_size};
|
||||
box.depth = util_num_layers(&res->base, i);
|
||||
ctx->base.resource_copy_region(&ctx->base, &res->base, i, 0, 0, 0, &staging.base, i, &box);
|
||||
}
|
||||
zink_resource_object_reference(screen, &old_obj, NULL);
|
||||
}
|
||||
|
||||
if (res->bind_history & BITFIELD64_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW)) {
|
||||
for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; shader++) {
|
||||
if (res->bind_stages & (1 << shader)) {
|
||||
for (unsigned i = 0; i < ZINK_DESCRIPTOR_TYPE_IMAGE; i++) {
|
||||
if (res->bind_history & BITFIELD64_BIT(i))
|
||||
zink_context_invalidate_descriptor_state(ctx, shader, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res->obj->is_buffer)
|
||||
zink_resource_rebind(ctx, res);
|
||||
else {
|
||||
zink_rebind_framebuffer(ctx, res);
|
||||
/* this will be cleaned up in future commits */
|
||||
if (res->bind_history & BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW)) {
|
||||
for (unsigned i = 0; i < PIPE_SHADER_TYPES; i++) {
|
||||
for (unsigned j = 0; j < ctx->num_sampler_views[i]; j++) {
|
||||
struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[i][j]);
|
||||
if (sv && sv->base.texture == &res->base) {
|
||||
struct pipe_surface *psurf = &sv->image_view->base;
|
||||
zink_rebind_surface(ctx, &psurf);
|
||||
sv->image_view = zink_surface(psurf);
|
||||
zink_context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
zink_resource_setup_transfer_layouts(struct zink_context *ctx, struct zink_resource *src, struct zink_resource *dst)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ struct zink_resource_object {
|
|||
VkBuffer buffer;
|
||||
VkImage image;
|
||||
};
|
||||
|
||||
VkBuffer sbuffer;
|
||||
bool storage_init; //layout was set for image
|
||||
|
||||
VkDeviceMemory mem;
|
||||
uint32_t mem_hash;
|
||||
struct mem_key mkey;
|
||||
|
|
@ -154,4 +158,6 @@ zink_resource_object_reference(struct zink_screen *screen,
|
|||
if (dst) *dst = src;
|
||||
}
|
||||
|
||||
bool
|
||||
zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ create_surface(struct pipe_context *pctx,
|
|||
surface->base.u.tex.level = level;
|
||||
surface->base.u.tex.first_layer = templ->u.tex.first_layer;
|
||||
surface->base.u.tex.last_layer = templ->u.tex.last_layer;
|
||||
surface->obj = zink_resource(pres)->obj;
|
||||
util_dynarray_init(&surface->framebuffer_refs, NULL);
|
||||
|
||||
if (vkCreateImageView(screen->dev, ivci, NULL,
|
||||
|
|
@ -218,11 +219,14 @@ zink_destroy_surface(struct zink_screen *screen, struct pipe_surface *psurface)
|
|||
simple_mtx_lock(&screen->surface_mtx);
|
||||
struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
|
||||
assert(he);
|
||||
assert(he->data == surface);
|
||||
_mesa_hash_table_remove(&screen->surface_cache, he);
|
||||
simple_mtx_unlock(&screen->surface_mtx);
|
||||
surface_clear_fb_refs(screen, psurface);
|
||||
util_dynarray_fini(&surface->framebuffer_refs);
|
||||
pipe_resource_reference(&psurface->texture, NULL);
|
||||
if (surface->simage_view)
|
||||
vkDestroyImageView(screen->dev, surface->simage_view, NULL);
|
||||
vkDestroyImageView(screen->dev, surface->image_view, NULL);
|
||||
FREE(surface);
|
||||
}
|
||||
|
|
@ -234,6 +238,47 @@ zink_surface_destroy(struct pipe_context *pctx,
|
|||
zink_destroy_surface(zink_screen(pctx->screen), psurface);
|
||||
}
|
||||
|
||||
bool
|
||||
zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface)
|
||||
{
|
||||
struct zink_surface *surface = zink_surface(*psurface);
|
||||
struct zink_screen *screen = zink_screen(ctx->base.screen);
|
||||
if (surface->simage_view)
|
||||
return false;
|
||||
VkImageViewCreateInfo ivci = create_ivci(screen,
|
||||
zink_resource((*psurface)->texture), (*psurface));
|
||||
uint32_t hash = hash_ivci(&ivci);
|
||||
|
||||
simple_mtx_lock(&screen->surface_mtx);
|
||||
struct hash_entry *new_entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, &ivci);
|
||||
surface_clear_fb_refs(screen, *psurface);
|
||||
if (new_entry) {
|
||||
/* reuse existing surface; old one will be cleaned up naturally */
|
||||
struct zink_surface *new_surface = new_entry->data;
|
||||
simple_mtx_unlock(&screen->surface_mtx);
|
||||
zink_surface_reference(screen, (struct zink_surface**)psurface, new_surface);
|
||||
return true;
|
||||
}
|
||||
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
|
||||
assert(entry);
|
||||
_mesa_hash_table_remove(&screen->surface_cache, entry);
|
||||
VkImageView image_view;
|
||||
if (vkCreateImageView(screen->dev, &ivci, NULL, &image_view) != VK_SUCCESS) {
|
||||
debug_printf("zink: failed to create new imageview");
|
||||
simple_mtx_unlock(&screen->surface_mtx);
|
||||
return false;
|
||||
}
|
||||
surface->hash = hash;
|
||||
surface->ivci = ivci;
|
||||
entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci, surface);
|
||||
assert(entry);
|
||||
surface->simage_view = surface->image_view;
|
||||
surface->image_view = image_view;
|
||||
surface->obj = zink_resource(surface->base.texture)->obj;
|
||||
simple_mtx_unlock(&screen->surface_mtx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
zink_context_surface_init(struct pipe_context *context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ struct zink_surface {
|
|||
struct pipe_surface base;
|
||||
VkImageViewCreateInfo ivci;
|
||||
VkImageView image_view;
|
||||
VkImageView simage_view;//old iview after storage replacement/rebind
|
||||
void *obj; //backing resource object
|
||||
uint32_t hash;
|
||||
struct zink_batch_usage batch_uses;
|
||||
struct util_dynarray framebuffer_refs;
|
||||
|
|
@ -93,4 +95,7 @@ zink_surface_clamp_viewtype(VkImageViewType viewType, unsigned first_layer, unsi
|
|||
}
|
||||
return viewType;
|
||||
}
|
||||
|
||||
bool
|
||||
zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue