zink: hook up global GENERAL image layouts

on some hardware/drivers, image layouts other than WSI are discarded,
which means a bunch of layout-specific synchronization can be omitted

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35259>
This commit is contained in:
Mike Blumenkrantz 2025-05-30 09:59:52 -04:00 committed by Marge Bot
parent 35ee74181e
commit 622612f67e
7 changed files with 188 additions and 90 deletions

View file

@ -566,14 +566,14 @@ zink_blit_barriers(struct zink_context *ctx, struct zink_resource *src, struct z
pipeline = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
if (src == dst) {
VkImageLayout layout = zink_screen(ctx->base.screen)->info.have_EXT_attachment_feedback_loop_layout ?
VkImageLayout layout = !screen->driver_workarounds.general_layout && screen->info.have_EXT_attachment_feedback_loop_layout ?
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
VK_IMAGE_LAYOUT_GENERAL;
screen->image_barrier(ctx, src, layout, VK_ACCESS_SHADER_READ_BIT | flags, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | pipeline);
} else {
if (src) {
VkImageLayout layout = util_format_is_depth_or_stencil(src->base.b.format) &&
src->obj->vkusage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ?
VkImageLayout layout = screen->driver_workarounds.general_layout ? VK_IMAGE_LAYOUT_GENERAL :
util_format_is_depth_or_stencil(src->base.b.format) && src->obj->vkusage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ?
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL :
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
screen->image_barrier(ctx, src, layout,
@ -581,9 +581,10 @@ zink_blit_barriers(struct zink_context *ctx, struct zink_resource *src, struct z
if (!ctx->unordered_blitting)
src->obj->unordered_read = false;
}
VkImageLayout layout = util_format_is_depth_or_stencil(dst->base.b.format) ?
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkImageLayout layout = screen->driver_workarounds.general_layout ? VK_IMAGE_LAYOUT_GENERAL :
util_format_is_depth_or_stencil(dst->base.b.format) ?
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
screen->image_barrier(ctx, dst, layout, flags, pipeline);
}
if (!ctx->unordered_blitting)

View file

@ -608,6 +608,8 @@ get_layout_for_binding(const struct zink_context *ctx, struct zink_resource *res
{
if (res->obj->is_buffer)
return 0;
if (zink_screen(ctx->base.screen)->driver_workarounds.general_layout)
return VK_IMAGE_LAYOUT_GENERAL;
switch (type) {
case ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW:
return zink_descriptor_util_image_layout_eval(ctx, res, is_compute);
@ -1837,13 +1839,14 @@ unbind_shader_image_counts(struct zink_context *ctx, struct zink_resource *res,
res->write_bind_count[is_compute]--;
res->image_bind_count[is_compute]--;
/* if this was the last image bind, the sampler bind layouts must be updated */
if (!res->obj->is_buffer && !res->image_bind_count[is_compute] && res->bind_count[is_compute])
if (!zink_screen(ctx->base.screen)->driver_workarounds.general_layout && !res->obj->is_buffer && !res->image_bind_count[is_compute] && res->bind_count[is_compute])
update_binds_for_samplerviews(ctx, res, is_compute);
}
ALWAYS_INLINE static bool
check_for_layout_update(struct zink_context *ctx, struct zink_resource *res, bool is_compute)
{
assert(!zink_screen(ctx->base.screen)->driver_workarounds.general_layout);
VkImageLayout layout = res->bind_count[is_compute] ? zink_descriptor_util_image_layout_eval(ctx, res, is_compute) : VK_IMAGE_LAYOUT_UNDEFINED;
VkImageLayout other_layout = res->bind_count[!is_compute] ? zink_descriptor_util_image_layout_eval(ctx, res, !is_compute) : VK_IMAGE_LAYOUT_UNDEFINED;
bool ret = false;
@ -1889,7 +1892,7 @@ unbind_shader_image(struct zink_context *ctx, gl_shader_stage stage, unsigned sl
} else {
unbind_descriptor_stage(res, stage);
unbind_descriptor_reads(res, stage == MESA_SHADER_COMPUTE);
if (!res->image_bind_count[is_compute])
if (!zink_screen(ctx->base.screen)->driver_workarounds.general_layout && !res->image_bind_count[is_compute])
check_for_layout_update(ctx, res, is_compute);
zink_surface_reference(zink_screen(ctx->base.screen), &image_view->surface, NULL);
}
@ -1912,20 +1915,27 @@ create_image_bufferview(struct zink_context *ctx, const struct pipe_image_view *
}
static void
finalize_image_bind(struct zink_context *ctx, struct zink_resource *res, bool is_compute)
finalize_image_bind(struct zink_context *ctx, struct zink_resource *res, bool is_compute, VkAccessFlags flags, VkPipelineStageFlags pipeline)
{
/* if this is the first image bind and there are sampler binds, the image's sampler layout
* must be updated to GENERAL
*/
if (res->image_bind_count[is_compute] == 1 &&
res->bind_count[is_compute] > 1)
update_binds_for_samplerviews(ctx, res, is_compute);
if (!check_for_layout_update(ctx, res, is_compute)) {
/* no deferred barrier: unset unordered usage immediately */
// TODO: figure out a way to link up layouts between unordered and main cmdbuf
// if (zink_resource_access_is_write(res->barrier_access[is_compute]))
struct zink_screen *screen = zink_screen(ctx->base.screen);
bool general_layout = screen->driver_workarounds.general_layout;
if (general_layout) {
/* no need to check later */
screen->image_barrier(ctx, res, VK_IMAGE_LAYOUT_GENERAL, flags, pipeline);
res->obj->unordered_write = false;
res->obj->unordered_read = false;
} else {
/* if this is the first image bind and there are sampler binds, the image's sampler layout
* must be updated to GENERAL
*/
if (res->image_bind_count[is_compute] == 1 &&
res->bind_count[is_compute] > 1)
update_binds_for_samplerviews(ctx, res, is_compute);
if (!check_for_layout_update(ctx, res, is_compute)) {
/* no deferred barrier: unset unordered usage immediately */
res->obj->unordered_write = false;
res->obj->unordered_read = false;
}
}
}
@ -2110,7 +2120,7 @@ zink_set_shader_images(struct pipe_context *pctx,
res->gfx_barrier);
zink_batch_resource_usage_set(ctx->bs, res,
zink_resource_access_is_write(access), true);
finalize_image_bind(ctx, a->import2d, is_compute);
finalize_image_bind(ctx, a->import2d, is_compute, access, res->gfx_barrier);
zink_batch_resource_usage_set(ctx->bs, a->import2d,
zink_resource_access_is_write(access), false);
if (zink_resource_access_is_write(access))
@ -2125,7 +2135,7 @@ zink_set_shader_images(struct pipe_context *pctx,
res->obj->unordered_write = false;
res->obj->unordered_read = false;
} else {
finalize_image_bind(ctx, res, is_compute);
finalize_image_bind(ctx, res, is_compute, access, res->gfx_barrier);
zink_batch_resource_usage_set(ctx->bs, res,
zink_resource_access_is_write(access), false);
}
@ -2189,10 +2199,11 @@ update_feedback_loop_state(struct zink_context *ctx, unsigned idx, unsigned feed
ALWAYS_INLINE static void
unbind_samplerview_res(struct zink_context *ctx, gl_shader_stage stage, unsigned slot, struct zink_resource *res)
{
bool general_layout = zink_screen(ctx->base.screen)->driver_workarounds.general_layout;
res->sampler_bind_count[stage == MESA_SHADER_COMPUTE]--;
if (stage != MESA_SHADER_COMPUTE && !res->sampler_bind_count[0] && res->fb_bind_count) {
u_foreach_bit(idx, res->fb_binds) {
if (ctx->feedback_loops & BITFIELD_BIT(idx)) {
if (!general_layout && ctx->feedback_loops & BITFIELD_BIT(idx)) {
ctx->dynamic_fb.attachments[idx].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
ctx->rp_layout_changed = true;
}
@ -2207,7 +2218,7 @@ unbind_samplerview_res(struct zink_context *ctx, gl_shader_stage stage, unsigned
} else {
unbind_descriptor_stage(res, stage);
unbind_descriptor_reads(res, stage == MESA_SHADER_COMPUTE);
if (!res->sampler_bind_count[stage == MESA_SHADER_COMPUTE])
if (!general_layout && !res->sampler_bind_count[stage == MESA_SHADER_COMPUTE])
check_for_layout_update(ctx, res, stage == MESA_SHADER_COMPUTE);
}
assert(slot < 32);
@ -2246,6 +2257,7 @@ zink_set_sampler_views(struct pipe_context *pctx,
struct pipe_sampler_view **views)
{
struct zink_context *ctx = zink_context(pctx);
bool general_layout = zink_screen(ctx->base.screen)->driver_workarounds.general_layout;
const uint32_t mask = BITFIELD_RANGE(start_slot, num_views);
uint32_t shadow_mask = ctx->di.zs_swizzle[shader_type].mask;
ctx->di.cubes[shader_type] &= ~mask;
@ -2317,10 +2329,16 @@ zink_set_sampler_views(struct pipe_context *pctx,
if (b->cube_array) {
ctx->di.cubes[shader_type] |= BITFIELD_BIT(start_slot + i);
}
if (!check_for_layout_update(ctx, res, shader_type == MESA_SHADER_COMPUTE) && !ctx->unordered_blitting) {
if (general_layout) {
if (!ctx->blitting)
zink_screen(ctx->base.screen)->image_barrier(ctx, res, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT, res->gfx_barrier);
if (!ctx->unordered_blitting)
/* no deferred barrier: unset unordered usage immediately */
res->obj->unordered_read = false;
} else if (!check_for_layout_update(ctx, res, shader_type == MESA_SHADER_COMPUTE) && !ctx->unordered_blitting) {
/* no deferred barrier: unset unordered usage immediately */
res->obj->unordered_read = false;
// TODO: figure out a way to link up layouts between unordered and main cmdbuf
res->obj->unordered_write = false;
}
if (!a)
@ -2507,6 +2525,8 @@ unbind_bindless_descriptor(struct zink_context *ctx, struct zink_resource *res)
unbind_descriptor_reads(res, i);
}
}
if (zink_screen(ctx->base.screen)->driver_workarounds.general_layout)
return;
for (unsigned i = 0; i < 2; i++) {
if (!res->image_bind_count[i])
check_for_layout_update(ctx, res, i);
@ -2517,6 +2537,7 @@ static void
zink_make_texture_handle_resident(struct pipe_context *pctx, uint64_t handle, bool resident)
{
struct zink_context *ctx = zink_context(pctx);
bool general_layout = zink_screen(ctx->base.screen)->driver_workarounds.general_layout;
bool is_buffer = ZINK_BINDLESS_IS_BUFFER(handle);
struct hash_entry *he = _mesa_hash_table_search(&ctx->di.bindless[is_buffer].tex_handles, (void*)(uintptr_t)handle);
assert(he);
@ -2549,15 +2570,18 @@ zink_make_texture_handle_resident(struct pipe_context *pctx, uint64_t handle, bo
ii->imageView = ds->surface->image_view;
ii->imageLayout = zink_descriptor_util_image_layout_eval(ctx, res, false);
flush_pending_clears(ctx, res, ds->surface->base.first_layer, ds->surface->base.last_layer - ds->surface->base.first_layer + 1);
if (!check_for_layout_update(ctx, res, false)) {
if (general_layout) {
res->obj->unordered_read = false;
// TODO: figure out a way to link up layouts between unordered and main cmdbuf
res->obj->unordered_write = false;
}
if (!check_for_layout_update(ctx, res, true)) {
res->obj->unordered_read = false;
// TODO: figure out a way to link up layouts between unordered and main cmdbuf
res->obj->unordered_write = false;
zink_screen(ctx->base.screen)->image_barrier(ctx, res, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
} else {
if (!check_for_layout_update(ctx, res, false)) {
res->obj->unordered_read = false;
res->obj->unordered_write = false;
}
if (!check_for_layout_update(ctx, res, true)) {
res->obj->unordered_read = false;
res->obj->unordered_write = false;
}
}
zink_batch_resource_usage_set(ctx->bs, res, false, false);
res->obj->unordered_write = false;
@ -2692,8 +2716,8 @@ zink_make_image_handle_resident(struct pipe_context *pctx, uint64_t handle, unsi
ii->sampler = VK_NULL_HANDLE;
ii->imageView = ds->surface->image_view;
ii->imageLayout = VK_IMAGE_LAYOUT_GENERAL;
finalize_image_bind(ctx, res, false);
finalize_image_bind(ctx, res, true);
finalize_image_bind(ctx, res, false, access, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
finalize_image_bind(ctx, res, true, access, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
zink_batch_resource_usage_set(ctx->bs, res, zink_resource_access_is_write(access), false);
res->obj->unordered_write = false;
}
@ -3408,12 +3432,14 @@ zink_prep_fb_attachment(struct zink_context *ctx, struct zink_surface *surf, uns
layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
struct zink_screen *screen = zink_screen(ctx->base.screen);
if (screen->driver_workarounds.general_layout)
layout = VK_IMAGE_LAYOUT_GENERAL;
/*
The image subresources for a storage image must be in the VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or
VK_IMAGE_LAYOUT_GENERAL layout in order to access its data in a shader.
- 14.1.1. Storage Image
*/
if (res->image_bind_count[0])
else if (res->image_bind_count[0])
layout = VK_IMAGE_LAYOUT_GENERAL;
else if (!screen->info.have_EXT_attachment_feedback_loop_layout &&
layout == VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT)
@ -3734,6 +3760,7 @@ rebind_fb_state(struct zink_context *ctx, struct zink_resource *match_res, bool
static void
unbind_fb_surface(struct zink_context *ctx, struct pipe_surface *surf, unsigned idx, bool changed)
{
bool general_layout = zink_screen(ctx->base.screen)->driver_workarounds.general_layout;
ctx->dynamic_fb.attachments[idx].imageView = VK_NULL_HANDLE;
if (!surf)
return;
@ -3745,7 +3772,7 @@ unbind_fb_surface(struct zink_context *ctx, struct pipe_surface *surf, unsigned
if (!res->fb_bind_count && !res->bind_count[0])
_mesa_set_remove_key(ctx->need_barriers[0], res);
unsigned feedback_loops = ctx->feedback_loops;
if (ctx->feedback_loops & BITFIELD_BIT(idx)) {
if (!general_layout && ctx->feedback_loops & BITFIELD_BIT(idx)) {
ctx->dynamic_fb.attachments[idx].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
ctx->rp_layout_changed = true;
}
@ -3764,7 +3791,7 @@ unbind_fb_surface(struct zink_context *ctx, struct pipe_surface *surf, unsigned
res->fb_binds &= ~BITFIELD_BIT(idx);
batch_ref_fb_surface(ctx, surf);
/* this is called just before the resource loses a reference, so a refcount==1 means the resource will be destroyed */
if (!res->fb_bind_count && res->base.b.reference.count > 1) {
if (!general_layout && !res->fb_bind_count && res->base.b.reference.count > 1) {
if (ctx->track_renderpasses && !ctx->blitting) {
if (!(res->base.b.bind & PIPE_BIND_DISPLAY_TARGET) && util_format_is_depth_or_stencil(surf->format))
/* assume that all depth buffers which are not swapchain images will be used for sampling to avoid splitting renderpasses */
@ -5122,6 +5149,7 @@ rebind_image(struct zink_context *ctx, struct zink_resource *res)
zink_rebind_framebuffer(ctx, res);
if (!zink_resource_has_binds(res))
return;
bool general_layout = zink_screen(ctx->base.screen)->driver_workarounds.general_layout;
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
if (res->sampler_binds[i]) {
for (unsigned j = 0; j < ctx->di.num_sampler_views[i]; j++) {
@ -5141,7 +5169,8 @@ rebind_image(struct zink_context *ctx, struct zink_resource *res)
if (zink_resource(ctx->image_views[i][j].base.resource) == res) {
ctx->invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_IMAGE, j, 1);
update_descriptor_state_image(ctx, i, j, res);
_mesa_set_add(ctx->need_barriers[i == MESA_SHADER_COMPUTE], res);
if (!general_layout)
_mesa_set_add(ctx->need_barriers[i == MESA_SHADER_COMPUTE], res);
}
}
}
@ -5196,7 +5225,8 @@ zink_rebind_all_images(struct zink_context *ctx)
{
assert(!ctx->blitting);
rebind_fb_state(ctx, NULL, false);
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
bool general_layout = zink_screen(ctx->base.screen)->driver_workarounds.general_layout;
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
for (unsigned j = 0; j < ctx->di.num_sampler_views[i]; j++) {
struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[i][j]);
if (!sv || !sv->image_view || sv->image_view->base.texture->target == PIPE_BUFFER)
@ -5220,7 +5250,8 @@ zink_rebind_all_images(struct zink_context *ctx)
image_view->surface = create_image_surface(ctx, &image_view->base, i == MESA_SHADER_COMPUTE);
ctx->invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_IMAGE, j, 1);
update_descriptor_state_image(ctx, i, j, res);
_mesa_set_add(ctx->need_barriers[i == MESA_SHADER_COMPUTE], res);
if (!general_layout)
_mesa_set_add(ctx->need_barriers[i == MESA_SHADER_COMPUTE], res);
}
}
}
@ -5531,11 +5562,13 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
_mesa_set_init(&ctx->rendering_state_cache[i], ctx, hash_rendering_state, equals_rendering_state);
ctx->dynamic_fb.info.pColorAttachments = ctx->dynamic_fb.attachments;
ctx->dynamic_fb.info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
bool general_layout = screen->driver_workarounds.general_layout;
for (unsigned i = 0; i < ARRAY_SIZE(ctx->dynamic_fb.attachments); i++) {
VkRenderingAttachmentInfo *att = &ctx->dynamic_fb.attachments[i];
att->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
att->imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att->resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att->imageLayout = general_layout ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att->resolveImageLayout = general_layout ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
}
ctx->dynamic_fb.fbfetch_att = (VkAttachmentFeedbackLoopInfoEXT){
@ -5822,11 +5855,13 @@ add_implicit_feedback_loop(struct zink_context *ctx, struct zink_resource *res)
}
ctx->rp_layout_changed = true;
ctx->feedback_loops |= res->fb_binds;
u_foreach_bit(idx, res->fb_binds) {
if (zink_screen(ctx->base.screen)->info.have_EXT_attachment_feedback_loop_layout)
ctx->dynamic_fb.attachments[idx].imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT;
else
ctx->dynamic_fb.attachments[idx].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
if (!zink_screen(ctx->base.screen)->driver_workarounds.general_layout) {
u_foreach_bit(idx, res->fb_binds) {
if (zink_screen(ctx->base.screen)->info.have_EXT_attachment_feedback_loop_layout)
ctx->dynamic_fb.attachments[idx].imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT;
else
ctx->dynamic_fb.attachments[idx].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
}
update_feedback_loop_dynamic_state(ctx);
return true;
@ -5842,14 +5877,18 @@ zink_update_barriers(struct zink_context *ctx, bool is_compute,
struct set *need_barriers = ctx->need_barriers[is_compute];
ctx->barrier_set_idx[is_compute] = !ctx->barrier_set_idx[is_compute];
ctx->need_barriers[is_compute] = &ctx->update_barriers[is_compute][ctx->barrier_set_idx[is_compute]];
bool general_layout = zink_screen(ctx->base.screen)->driver_workarounds.general_layout;
ASSERTED bool check_rp = ctx->in_rp && ctx->dynamic_fb.tc_info.zsbuf_invalidate;
set_foreach(need_barriers, he) {
struct zink_resource *res = (struct zink_resource *)he->key;
if (res->bind_count[is_compute]) {
VkPipelineStageFlagBits pipeline = is_compute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : res->gfx_barrier;
if (res->base.b.target == PIPE_BUFFER)
if (res->base.b.target == PIPE_BUFFER) {
zink_screen(ctx->base.screen)->buffer_barrier(ctx, res, res->barrier_access[is_compute], pipeline);
else {
} else if (general_layout) {
/* let sync figure this out */
zink_screen(ctx->base.screen)->image_barrier(ctx, res, VK_IMAGE_LAYOUT_GENERAL, res->barrier_access[is_compute], pipeline);
} else {
bool is_feedback = is_compute ? false : add_implicit_feedback_loop(ctx, res);
VkImageLayout layout = zink_descriptor_util_image_layout_eval(ctx, res, is_compute);
/* GENERAL is only used for feedback loops and storage image binds */

View file

@ -264,6 +264,8 @@ zink_descriptor_util_push_layouts_get(struct zink_context *ctx, struct zink_desc
VkImageLayout
zink_descriptor_util_image_layout_eval(const struct zink_context *ctx, const struct zink_resource *res, bool is_compute)
{
if (zink_screen(ctx->base.screen)->driver_workarounds.general_layout)
return VK_IMAGE_LAYOUT_GENERAL;
if (res->bindless[0] || res->bindless[1]) {
/* bindless needs most permissive layout */
if (res->image_bind_count[0] || res->image_bind_count[1])

View file

@ -163,6 +163,21 @@ zink_debug_mem_print_stats(struct zink_screen *screen)
simple_mtx_unlock(&screen->debug_mem_lock);
}
static void
image_hic_transition(struct zink_screen *screen, struct zink_resource *res, VkImageLayout layout)
{
VkHostImageLayoutTransitionInfoEXT t = {
VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
NULL,
res->obj->image,
res->layout,
layout,
{res->aspect, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}
};
VKSCR(TransitionImageLayoutEXT)(screen->dev, 1, &t);
res->layout = layout;
}
static bool
equals_ivci(const void *a, const void *b)
{
@ -1694,6 +1709,11 @@ resource_create(struct pipe_screen *pscreen,
} else {
_mesa_hash_table_init(&res->surface_cache, NULL, NULL, equals_ivci);
simple_mtx_init(&res->surface_mtx, mtx_plain);
/* immediately switch to GENERAL layout if possible to avoid extra sync */
if (res->obj->image && res->queue != VK_QUEUE_FAMILY_FOREIGN_EXT && (res->obj->vkusage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) &&
screen->driver_workarounds.general_layout)
image_hic_transition(screen, res, VK_IMAGE_LAYOUT_GENERAL);
}
if (res->obj->exportable)
res->base.b.bind |= ZINK_BIND_DMABUF;
@ -2678,20 +2698,9 @@ zink_image_subdata(struct pipe_context *pctx,
unsigned vk_layer_stride = util_format_get_2d_size(pres->format, stride, 1) * vk_stride;
layer_stride /= vk_layer_stride;
VkHostImageLayoutTransitionInfoEXT t = {
VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
NULL,
res->obj->image,
res->layout,
/* GENERAL support is guaranteed */
VK_IMAGE_LAYOUT_GENERAL,
{res->aspect, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}
};
/* only pre-transition uninit images to avoid thrashing */
if (change_layout) {
VKSCR(TransitionImageLayoutEXT)(screen->dev, 1, &t);
res->layout = VK_IMAGE_LAYOUT_GENERAL;
}
if (change_layout)
image_hic_transition(screen, res, VK_IMAGE_LAYOUT_GENERAL);
VkMemoryToImageCopyEXT region = {
VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
NULL,
@ -2712,14 +2721,12 @@ zink_image_subdata(struct pipe_context *pctx,
&region
};
VKSCR(CopyMemoryToImageEXT)(screen->dev, &copy);
if (change_layout && screen->can_hic_shader_read && !pres->last_level && !box->x && !box->y && !box->z &&
if (change_layout && !screen->driver_workarounds.general_layout && screen->can_hic_shader_read &&
!pres->last_level && !box->x && !box->y && !box->z &&
box->width == pres->width0 && box->height == pres->height0 &&
((is_arrayed && box->depth == pres->array_size) || (!is_arrayed && box->depth == pres->depth0))) {
/* assume full copy single-mip images use shader read access */
t.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
t.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VKSCR(TransitionImageLayoutEXT)(screen->dev, 1, &t);
res->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_hic_transition(screen, res, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
/* assume multi-mip where further subdata calls may happen */
}
/* make sure image is marked as having data */
@ -3157,6 +3164,7 @@ zink_resource_get_address(struct zink_screen *screen, struct zink_resource *res)
void
zink_resource_setup_transfer_layouts(struct zink_context *ctx, struct zink_resource *src, struct zink_resource *dst)
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
if (src == dst) {
/* The Vulkan 1.1 specification says the following about valid usage
* of vkCmdBlitImage:
@ -3174,20 +3182,20 @@ zink_resource_setup_transfer_layouts(struct zink_context *ctx, struct zink_resou
* VK_IMAGE_LAYOUT_GENERAL. And since this isn't a present-related
* operation, VK_IMAGE_LAYOUT_GENERAL seems most appropriate.
*/
zink_screen(ctx->base.screen)->image_barrier(ctx, src,
VK_IMAGE_LAYOUT_GENERAL,
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
screen->image_barrier(ctx, src,
VK_IMAGE_LAYOUT_GENERAL,
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
} else {
zink_screen(ctx->base.screen)->image_barrier(ctx, src,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
screen->image_barrier(ctx, src,
screen->driver_workarounds.general_layout ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
zink_screen(ctx->base.screen)->image_barrier(ctx, dst,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
screen->image_barrier(ctx, dst,
screen->driver_workarounds.general_layout ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
}
}

View file

@ -3023,6 +3023,19 @@ init_driver_workarounds(struct zink_screen *screen)
break;
}
switch (zink_driverid(screen)) {
case VK_DRIVER_ID_MESA_LLVMPIPE:
case VK_DRIVER_ID_MESA_NVK:
case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
case VK_DRIVER_ID_MESA_TURNIP:
case VK_DRIVER_ID_QUALCOMM_PROPRIETARY:
screen->driver_workarounds.general_layout = true;
break;
default:
screen->driver_workarounds.general_layout = screen->info.have_KHR_unified_image_layouts;
break;
}
if (!screen->resizable_bar)
screen->info.have_EXT_host_image_copy = false;
}

View file

@ -689,7 +689,7 @@ resource_needs_barrier(struct zink_resource *res, VkAccessFlags flags, VkPipelin
template <barrier_type BARRIER_API, bool UNSYNCHRONIZED>
template <barrier_type BARRIER_API, bool UNSYNCHRONIZED, bool GENERAL_IMAGE>
void
zink_resource_memory_barrier(struct zink_context *ctx, struct zink_resource *res, VkAccessFlags flags, VkPipelineStageFlags pipeline)
{
@ -761,8 +761,16 @@ zink_resource_memory_barrier(struct zink_context *ctx, struct zink_resource *res
zink_cmd_debug_marker_end(ctx, cmdbuf, marker);
}
if (!UNSYNCHRONIZED)
resource_check_defer_buffer_barrier(ctx, res, pipeline);
if (!UNSYNCHRONIZED) {
if (GENERAL_IMAGE) {
bool is_compute = (pipeline & VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT) == pipeline;
if (res->bind_count[!is_compute] || (is_compute && res->fb_bind_count))
/* compute rebind */
_mesa_set_add(ctx->need_barriers[is_compute], res);
} else {
resource_check_defer_buffer_barrier(ctx, res, pipeline);
}
}
if (is_write)
res->obj->last_write = flags;
@ -780,21 +788,47 @@ zink_resource_memory_barrier(struct zink_context *ctx, struct zink_resource *res
res->obj->access_stage = pipeline;
res->obj->ordered_access_is_copied = unordered;
}
if (pipeline != VK_PIPELINE_STAGE_TRANSFER_BIT && is_write)
if (pipeline != VK_PIPELINE_STAGE_TRANSFER_BIT && is_write && !GENERAL_IMAGE)
zink_resource_copies_reset(res);
}
template <bool UNSYNCHRONIZED>
void
zink_resource_image_barrier_general(struct zink_context *ctx, struct zink_resource *res, VkImageLayout new_layout, VkAccessFlags flags, VkPipelineStageFlags pipeline)
{
if (!pipeline)
pipeline = pipeline_dst_stage(new_layout);
if (!flags)
flags = access_dst_flags(new_layout);
assert(new_layout == VK_IMAGE_LAYOUT_GENERAL || new_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
/* if this requires an actual image barrier, send it through to the image barrier handlers */
if (res->obj->needs_zs_evaluate || res->obj->exportable || zink_is_swapchain(res) || res->layout != new_layout ||
res->queue != zink_screen(ctx->base.screen)->gfx_queue || res->queue != VK_QUEUE_FAMILY_IGNORED) {
zink_resource_image_barrier<barrier_KHR_synchronzation2, UNSYNCHRONIZED>(ctx, res, new_layout, flags, pipeline);
return;
}
/* this is just a synchronization barrier with GENERAL layout: use memory barrier for better granularity */
zink_resource_memory_barrier<barrier_KHR_synchronzation2, false, true>(ctx, res, flags, pipeline);
}
void
zink_synchronization_init(struct zink_screen *screen)
{
if (screen->info.have_vulkan13 || screen->info.have_KHR_synchronization2) {
screen->buffer_barrier = zink_resource_memory_barrier<barrier_KHR_synchronzation2, false>;
screen->buffer_barrier_unsync = zink_resource_memory_barrier<barrier_KHR_synchronzation2, true>;
screen->image_barrier = zink_resource_image_barrier<barrier_KHR_synchronzation2, false>;
screen->image_barrier_unsync = zink_resource_image_barrier<barrier_KHR_synchronzation2, true>;
screen->buffer_barrier = zink_resource_memory_barrier<barrier_KHR_synchronzation2, false, false>;
screen->buffer_barrier_unsync = zink_resource_memory_barrier<barrier_KHR_synchronzation2, true, false>;
if (screen->driver_workarounds.general_layout) {
screen->image_barrier = zink_resource_image_barrier<barrier_KHR_synchronzation2, false>;
screen->image_barrier_unsync = zink_resource_image_barrier<barrier_KHR_synchronzation2, true>;
} else {
screen->image_barrier = zink_resource_image_barrier<barrier_KHR_synchronzation2, false>;
screen->image_barrier_unsync = zink_resource_image_barrier<barrier_KHR_synchronzation2, true>;
}
} else {
screen->buffer_barrier = zink_resource_memory_barrier<barrier_default, false>;
screen->buffer_barrier_unsync = zink_resource_memory_barrier<barrier_default, true>;
screen->buffer_barrier = zink_resource_memory_barrier<barrier_default, false, false>;
screen->buffer_barrier_unsync = zink_resource_memory_barrier<barrier_default, true, false>;
screen->image_barrier = zink_resource_image_barrier<barrier_default, false>;
screen->image_barrier_unsync = zink_resource_image_barrier<barrier_default, true>;
}

View file

@ -1520,6 +1520,7 @@ struct zink_screen {
bool inconsistent_interpolation;
bool can_2d_view_sparse;
bool general_depth_layout;
bool general_layout;
} driver_workarounds;
};