From b754fcc49c3940beaf8a2f7aa8cfc16e17f2738a Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 19 Aug 2026 22:40:54 -0400 Subject: [PATCH] [TEST] Ensure resolve shadow reads on msaa + shader extencil fallback --- src/video_core/renderer_vulkan/blit_image.cpp | 32 +++++++++++++------ .../renderer_vulkan/vk_scheduler.cpp | 1 + .../renderer_vulkan/vk_texture_cache.cpp | 26 +++++++++++---- .../renderer_vulkan/vk_texture_cache.h | 9 ++++++ 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 5d82bfe3b8..09ffa4df12 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -844,28 +844,40 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { - if (!device.IsExtShaderStencilExportSupported()) { - return; - } ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); + const bool blit_stencil = device.IsExtShaderStencilExportSupported(); const BlitImagePipelineKey key{ .renderpass = dst_framebuffer->RenderPass(), .operation = operation, }; - const VkPipelineLayout layout = *two_textures_pipeline_layout; + VkPipelineLayout layout{}; + VkPipeline pipeline{}; + VkImageView src_stencil_view = VK_NULL_HANDLE; + if (blit_stencil) { + layout = *two_textures_pipeline_layout; + pipeline = FindOrEmplaceDepthStencilPipeline(key); + src_stencil_view = src_image_view.StencilView(); + } else { + layout = *one_texture_pipeline_layout; + pipeline = FindOrEmplaceBlitDepthPipeline(key.renderpass); + } const VkSampler sampler = *nearest_sampler; - const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key); const VkImageView src_depth_view = src_image_view.DepthView(); - const VkImageView src_stencil_view = src_image_view.StencilView(); RecordShaderReadBarrier(scheduler, src_image_view); scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view, - src_stencil_view, this](vk::CommandBuffer cmdbuf) { - const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit(); - UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, - src_stencil_view); + src_stencil_view, blit_stencil, this](vk::CommandBuffer cmdbuf) { + VkDescriptorSet descriptor_set{}; + if (blit_stencil) { + descriptor_set = two_textures_descriptor_allocator.Commit(); + UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, + src_stencil_view); + } else { + descriptor_set = one_texture_descriptor_allocator.Commit(); + UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_depth_view); + } cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 792377d242..31e852e943 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -132,6 +132,7 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass num_renderpass_images = framebuffer->NumImages(); renderpass_images = framebuffer->Images(); renderpass_image_ranges = framebuffer->ImageRanges(); + framebuffer->MarkResolveShadowsUpToDate(); } void Scheduler::RealizeDeferredClear() { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 47d285f297..0c7f8cca77 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1019,7 +1019,6 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk if (shadow.image && shadow.format == format && shadow.extent.width == extent.width && shadow.extent.height == extent.height && shadow.layers == layers && shadow.aspect_mask == aspect_mask) { - shadow.up_to_date = true; return *shadow.view; } VkImageUsageFlags shadow_usage = @@ -1069,7 +1068,7 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk shadow.extent = extent; shadow.layers = layers; shadow.aspect_mask = aspect_mask; - shadow.up_to_date = true; + shadow.up_to_date = false; return *shadow.view; } @@ -1082,6 +1081,13 @@ const TextureCacheRuntime::ResolveShadow* TextureCacheRuntime::GetValidResolveSh return &it->second; } +void TextureCacheRuntime::MarkResolveShadowUpToDate(VkImage msaa_image) { + const auto it = resolve_shadows.find(msaa_image); + if (it != resolve_shadows.end()) { + it->second.up_to_date = true; + } +} + void TextureCacheRuntime::InvalidateResolveShadow(VkImage msaa_image) { const auto it = resolve_shadows.find(msaa_image); if (it != resolve_shadows.end()) { @@ -1753,10 +1759,6 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, if ((dst_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) { const bool copies_stencil = (dst_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 && device.IsExtShaderStencilExportSupported(); - if ((dst_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 && !copies_stencil) { - UNIMPLEMENTED_MSG("Copying images with different samples is not supported."); - return; - } blit_image_helper.CopyMSAADepth(render_pass_cache, dst.Handle(), dst.info.format, src.Handle(), src.info.format, num_samples, copies, copies_stencil, msaa_to_non_msaa); @@ -3059,6 +3061,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, renderpass = runtime.render_pass_cache.Get(renderpass_key); render_pass_key = renderpass_key; render_pass_cache = &runtime.render_pass_cache; + runtime_ptr = &runtime; render_area.width = (std::min)(render_area.width, width); render_area.height = (std::min)(render_area.height, height); @@ -3075,6 +3078,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, const VkImage msaa_image = images[rt_map[index]]; attachments.push_back(runtime.GetOrCreateResolveShadow( msaa_image, vk_format, render_area, layers, VK_IMAGE_ASPECT_COLOR_BIT)); + resolve_shadow_images[num_resolve_shadows++] = msaa_image; continue; } VkImageCreateInfo resolve_ci{ @@ -3127,6 +3131,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, .format; attachments.push_back(runtime.GetOrCreateResolveShadow(depth_image, vk_format, render_area, layers, depth_aspect_mask)); + resolve_shadow_images[num_resolve_shadows++] = depth_image; } num_color_buffers = static_cast(num_colors); @@ -3143,6 +3148,15 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, }); } +void Framebuffer::MarkResolveShadowsUpToDate() const { + if (runtime_ptr == nullptr) { + return; + } + for (u32 index = 0; index < num_resolve_shadows; ++index) { + runtime_ptr->MarkResolveShadowUpToDate(resolve_shadow_images[index]); + } +} + VkRenderPass Framebuffer::RenderPassVariant(u32 color_clear_mask, bool depth_stencil_clear, u32 color_discard_mask, bool depth_stencil_discard) const { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index fd11dd2ef6..f611c0f31b 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -131,6 +131,8 @@ public: void InvalidateResolveShadow(VkImage msaa_image); + void MarkResolveShadowUpToDate(VkImage msaa_image); + void EraseResolveShadow(VkImage msaa_image); std::span ViewFormats(PixelFormat format) { @@ -257,6 +259,10 @@ public: return discard_msaa_depth_stencil; } + /// Records that a render pass has begun, so its resolve attachments will hold valid contents + /// once it ends. + void MarkResolveShadowsUpToDate() const; + private: static constexpr size_t NUM_MEMOIZED_RENDER_PASS_VARIANTS = 8; @@ -274,6 +280,9 @@ private: bool is_rescaled{}; std::vector resolve_images; std::vector resolve_image_views; + std::array resolve_shadow_images{}; + u32 num_resolve_shadows = 0; + TextureCacheRuntime* runtime_ptr{nullptr}; RenderPassKey render_pass_key{}; RenderPassCache* render_pass_cache{nullptr}; bool discard_msaa_color{};