From f6522b69ea6e2d6a65105de77e920a4286e617f4 Mon Sep 17 00:00:00 2001 From: izzy2lost Date: Mon, 30 Mar 2026 02:57:27 -0400 Subject: [PATCH] Improve Vulkan zeta surface texture correctness --- hw/xbox/nv2a/pgraph/vk/draw.c | 30 +++++++++ hw/xbox/nv2a/pgraph/vk/image.c | 33 ++++++++++ hw/xbox/nv2a/pgraph/vk/renderer.h | 2 + hw/xbox/nv2a/pgraph/vk/shaders.c | 2 +- hw/xbox/nv2a/pgraph/vk/surface.c | 20 ++++-- hw/xbox/nv2a/pgraph/vk/texture.c | 103 +++++++++++++++++++++++++++--- 6 files changed, 175 insertions(+), 15 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/vk/draw.c b/hw/xbox/nv2a/pgraph/vk/draw.c index bf22621702..02130fed4d 100644 --- a/hw/xbox/nv2a/pgraph/vk/draw.c +++ b/hw/xbox/nv2a/pgraph/vk/draw.c @@ -1321,6 +1321,36 @@ static void begin_render_pass(PGRAPHState *pg) assert(r->current_framebuffer != VK_NULL_HANDLE); + if (r->zeta_binding && + r->zeta_binding->image_layout != + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { + VkImageMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .oldLayout = r->zeta_binding->image_layout, + .newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = r->zeta_binding->image, + .subresourceRange = { + .aspectMask = r->zeta_binding->host_fmt.aspect, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + }; + vkCmdPipelineBarrier( + r->command_buffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + 0, 0, NULL, 0, NULL, 1, &barrier); + r->zeta_binding->image_layout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + VkRenderPassBeginInfo render_pass_begin_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderPass = r->render_pass, diff --git a/hw/xbox/nv2a/pgraph/vk/image.c b/hw/xbox/nv2a/pgraph/vk/image.c index e2dec87f59..1e2211a88e 100644 --- a/hw/xbox/nv2a/pgraph/vk/image.c +++ b/hw/xbox/nv2a/pgraph/vk/image.c @@ -202,6 +202,15 @@ void pgraph_vk_transition_image_layout(PGRAPHState *pg, VkCommandBuffer cmd, sourceStage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + // Depth Read-Only -> Src + } else if (oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && + newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + // Depth -> Dst } else if (oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { @@ -210,6 +219,14 @@ void pgraph_vk_transition_image_layout(PGRAPHState *pg, VkCommandBuffer cmd, sourceStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + // Depth Read-Only -> Dst + } else if (oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && + newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + // Src -> Color } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { @@ -226,6 +243,22 @@ void pgraph_vk_transition_image_layout(PGRAPHState *pg, VkCommandBuffer cmd, sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + // Src -> Depth Read-Only + } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && + newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + + // Dst -> Depth Read-Only + } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && + newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + // Src -> Dst } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index 27b5823d79..903246a8ce 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -141,6 +141,7 @@ typedef struct SurfaceBinding { VkImage image; VkImageView image_view; + VkImageLayout image_layout; VmaAllocation allocation; // Used for scaling @@ -449,6 +450,7 @@ typedef struct PGRAPHVkState { TextureBinding *texture_bindings[NV2A_MAX_TEXTURES]; bool tex_surface_direct[NV2A_MAX_TEXTURES]; VkImageView tex_surface_direct_views[NV2A_MAX_TEXTURES]; + VkImageLayout tex_surface_direct_layout[NV2A_MAX_TEXTURES]; TextureBinding dummy_texture; bool texture_bindings_changed; VkFormatProperties *texture_format_properties; diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index dbfe8c49cd..1e20caba7a 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -217,7 +217,7 @@ void pgraph_vk_update_descriptor_sets(PGRAPHState *pg) for (int i = 0; i < NV2A_MAX_TEXTURES; i++) { image_infos[i] = (VkDescriptorImageInfo){ .imageLayout = r->tex_surface_direct[i] - ? VK_IMAGE_LAYOUT_GENERAL + ? r->tex_surface_direct_layout[i] : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .imageView = r->tex_surface_direct[i] ? r->tex_surface_direct_views[i] diff --git a/hw/xbox/nv2a/pgraph/vk/surface.c b/hw/xbox/nv2a/pgraph/vk/surface.c index 55425f886d..5548726534 100644 --- a/hw/xbox/nv2a/pgraph/vk/surface.c +++ b/hw/xbox/nv2a/pgraph/vk/surface.c @@ -343,9 +343,9 @@ static void download_surface_to_buffer(NV2AState *d, SurfaceBinding *surface, pgraph_vk_transition_image_layout( pg, cmd, surface->image, surface->host_fmt.vk_format, - surface->color ? VK_IMAGE_LAYOUT_GENERAL : - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + surface->image_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + surface->image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; int num_copy_regions = 1; VkBufferImageCopy copy_regions[2]; @@ -455,6 +455,9 @@ static void download_surface_to_buffer(NV2AState *d, SurfaceBinding *surface, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, surface->color ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + surface->image_layout = + surface->color ? VK_IMAGE_LAYOUT_GENERAL : + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // FIXME: Verify output of depth stencil conversion // FIXME: Track current layout and only transition when required @@ -1145,6 +1148,9 @@ static void create_surface_image(PGRAPHState *pg, SurfaceBinding *surface) VK_IMAGE_LAYOUT_UNDEFINED, surface->color ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + surface->image_layout = + surface->color ? VK_IMAGE_LAYOUT_GENERAL : + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; nv2a_profile_inc_counter(NV2A_PROF_QUEUE_SUBMIT_3); pgraph_vk_end_debug_marker(r, cmd); @@ -1156,6 +1162,7 @@ static void migrate_surface_image(SurfaceBinding *dst, SurfaceBinding *src) { dst->image = src->image; dst->image_view = src->image_view; + dst->image_layout = src->image_layout; dst->allocation = src->allocation; dst->image_scratch = src->image_scratch; dst->image_scratch_current_layout = src->image_scratch_current_layout; @@ -1163,6 +1170,7 @@ static void migrate_surface_image(SurfaceBinding *dst, SurfaceBinding *src) src->image = VK_NULL_HANDLE; src->image_view = VK_NULL_HANDLE; + src->image_layout = VK_IMAGE_LAYOUT_UNDEFINED; src->allocation = VK_NULL_HANDLE; src->image_scratch = VK_NULL_HANDLE; src->image_scratch_current_layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -1582,9 +1590,9 @@ void pgraph_vk_upload_surface_data(NV2AState *d, SurfaceBinding *surface, pgraph_vk_transition_image_layout( pg, cmd, surface->image, surface->host_fmt.vk_format, - surface->color ? VK_IMAGE_LAYOUT_GENERAL : - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + surface->image_layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + surface->image_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; bool upscale = pg->surface_scale_factor > 1 && !use_compute_to_convert_depth_stencil_format; @@ -1637,6 +1645,9 @@ void pgraph_vk_upload_surface_data(NV2AState *d, SurfaceBinding *surface, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, surface->color ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + surface->image_layout = + surface->color ? VK_IMAGE_LAYOUT_GENERAL : + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; nv2a_profile_inc_counter(NV2A_PROF_QUEUE_SUBMIT_2); pgraph_vk_end_debug_marker(r, cmd); @@ -1741,6 +1752,7 @@ static void populate_surface_binding_target_sized(NV2AState *d, bool color, target->frame_time = pg->frame_time; target->draw_time = pg->draw_time; target->cleared = false; + target->image_layout = VK_IMAGE_LAYOUT_UNDEFINED; target->initialized = false; } diff --git a/hw/xbox/nv2a/pgraph/vk/texture.c b/hw/xbox/nv2a/pgraph/vk/texture.c index 63c04bad82..20f7191bdf 100644 --- a/hw/xbox/nv2a/pgraph/vk/texture.c +++ b/hw/xbox/nv2a/pgraph/vk/texture.c @@ -738,8 +738,9 @@ static void copy_zeta_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surfac pgraph_vk_transition_image_layout( pg, cmd, surface->image, surface->host_fmt.vk_format, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + surface->image_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + surface->image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; vkCmdCopyImageToBuffer(cmd, surface->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -765,6 +766,7 @@ static void copy_zeta_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surfac vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &depth_read_barrier); + surface->image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; VkImageViewCreateInfo depth_view_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -852,6 +854,7 @@ static void copy_zeta_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surfac VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0, 0, NULL, 0, NULL, 1, &depth_restore_barrier); + surface->image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; vkDestroyImageView(r->device, depth_view, NULL); texture_source_buffer = r->storage_buffers[BUFFER_COMPUTE_SRC].buffer; @@ -898,8 +901,9 @@ static void copy_zeta_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surfac pgraph_vk_transition_image_layout( pg, cmd, surface->image, surface->host_fmt.vk_format, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + surface->image_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + surface->image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; vkCmdCopyImageToBuffer(cmd, surface->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -910,6 +914,7 @@ static void copy_zeta_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surfac pg, cmd, surface->image, surface->host_fmt.vk_format, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + surface->image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; size_t packed_image_size = scaled_width * scaled_height * 4; @@ -1098,6 +1103,46 @@ static void bind_surface_as_texture(PGRAPHState *pg, SurfaceBinding *surface, texture->draw_time = surface->draw_time; } +static void bind_zeta_surface_as_texture(PGRAPHState *pg, SurfaceBinding *surface, + TextureBinding *texture) +{ + assert(!surface->color); + assert(!(surface->host_fmt.aspect & VK_IMAGE_ASPECT_STENCIL_BIT)); + + nv2a_profile_inc_counter(NV2A_PROF_SURF_TO_TEX); + + if (surface->image_layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { + VkCommandBuffer cmd = pgraph_vk_begin_nondraw_commands(pg); + + VkImageMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .oldLayout = surface->image_layout, + .newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = surface->image, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + }; + vkCmdPipelineBarrier( + cmd, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, 0, NULL, 0, NULL, 1, &barrier); + + pgraph_vk_end_nondraw_commands(pg, cmd); + surface->image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + + texture->draw_time = surface->draw_time; +} + static void copy_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surface, TextureBinding *texture) { @@ -1120,9 +1165,9 @@ static void copy_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surface, pgraph_vk_transition_image_layout( pg, cmd, surface->image, surface->host_fmt.vk_format, - surface->color ? VK_IMAGE_LAYOUT_GENERAL : - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + surface->image_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + surface->image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; pgraph_vk_transition_image_layout(pg, cmd, texture->image, vkf.vk_format, texture->current_layout, @@ -1149,6 +1194,9 @@ static void copy_surface_to_texture(PGRAPHState *pg, SurfaceBinding *surface, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, surface->color ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + surface->image_layout = + surface->color ? VK_IMAGE_LAYOUT_GENERAL : + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; pgraph_vk_transition_image_layout(pg, cmd, texture->image, vkf.vk_format, texture->current_layout, @@ -1413,6 +1461,8 @@ static void create_texture(PGRAPHState *pg, int texture_idx) bool surface_to_texture = false; r->tex_surface_direct[texture_idx] = false; r->tex_surface_direct_views[texture_idx] = VK_NULL_HANDLE; + r->tex_surface_direct_layout[texture_idx] = + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // Check active surfaces to see if this texture was a render target SurfaceBinding *surface = pgraph_vk_surface_get(d, texture_vram_offset); @@ -1511,12 +1561,28 @@ static void create_texture(PGRAPHState *pg, int texture_idx) if (binding_found) { if (surface_to_texture) { - if (surface->color) { - if (surface->draw_time != snode->draw_time) { - bind_surface_as_texture(pg, surface, snode); + bool can_direct_bind = + surface->color || + !(surface->host_fmt.aspect & VK_IMAGE_ASPECT_STENCIL_BIT); + if (can_direct_bind) { + VkImageLayout direct_layout; + if (surface->color) { + if (surface->draw_time != snode->draw_time) { + bind_surface_as_texture(pg, surface, snode); + } + direct_layout = VK_IMAGE_LAYOUT_GENERAL; + } else { + if (surface->draw_time != snode->draw_time || + surface->image_layout != + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { + bind_zeta_surface_as_texture(pg, surface, snode); + } + direct_layout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; } r->tex_surface_direct[texture_idx] = true; r->tex_surface_direct_views[texture_idx] = surface->image_view; + r->tex_surface_direct_layout[texture_idx] = direct_layout; } else if (surface->draw_time != snode->draw_time) { copy_surface_to_texture(pg, surface, snode); } @@ -1734,10 +1800,21 @@ static void create_texture(PGRAPHState *pg, int texture_idx) r->texture_bindings[texture_idx] = snode; if (surface_to_texture) { - if (surface->color) { - bind_surface_as_texture(pg, surface, snode); + bool can_direct_bind = + surface->color || + !(surface->host_fmt.aspect & VK_IMAGE_ASPECT_STENCIL_BIT); + if (can_direct_bind) { + VkImageLayout direct_layout; + if (surface->color) { + bind_surface_as_texture(pg, surface, snode); + direct_layout = VK_IMAGE_LAYOUT_GENERAL; + } else { + bind_zeta_surface_as_texture(pg, surface, snode); + direct_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } r->tex_surface_direct[texture_idx] = true; r->tex_surface_direct_views[texture_idx] = surface->image_view; + r->tex_surface_direct_layout[texture_idx] = direct_layout; } else { copy_surface_to_texture(pg, surface, snode); } @@ -1820,6 +1897,8 @@ void pgraph_vk_bind_textures(NV2AState *d) } r->tex_surface_direct[i] = false; r->tex_surface_direct_views[i] = VK_NULL_HANDLE; + r->tex_surface_direct_layout[i] = + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; pg->texture_dirty[i] = false; continue; } @@ -1834,12 +1913,14 @@ void pgraph_vk_bind_textures(NV2AState *d) TextureBinding *prev_binding = r->texture_bindings[i]; bool prev_direct = r->tex_surface_direct[i]; VkImageView prev_direct_view = r->tex_surface_direct_views[i]; + VkImageLayout prev_direct_layout = r->tex_surface_direct_layout[i]; create_texture(pg, i); pg->texture_dirty[i] = false; // FIXME: Move to renderer? if (r->texture_bindings[i] != prev_binding || r->tex_surface_direct[i] != prev_direct || - r->tex_surface_direct_views[i] != prev_direct_view) { + r->tex_surface_direct_views[i] != prev_direct_view || + r->tex_surface_direct_layout[i] != prev_direct_layout) { r->texture_bindings_changed = true; } } @@ -1976,6 +2057,8 @@ void pgraph_vk_finalize_textures(PGRAPHState *pg) r->texture_bindings[i] = NULL; r->tex_surface_direct[i] = false; r->tex_surface_direct_views[i] = VK_NULL_HANDLE; + r->tex_surface_direct_layout[i] = + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } destroy_dummy_texture(r);