From bad10039ae124cf729228f14376fa2af20a1720b Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 30 Sep 2026 13:03:09 -0400 Subject: [PATCH] Address some corrections towards MSAA discard/enable removal --- src/video_core/renderer_vulkan/blit_image.cpp | 11 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 12 +- .../renderer_vulkan/vk_query_cache.cpp | 17 +- .../renderer_vulkan/vk_scheduler.cpp | 233 +++++++++++------ src/video_core/renderer_vulkan/vk_scheduler.h | 13 + .../renderer_vulkan/vk_texture_cache.cpp | 242 ++++++++++-------- .../renderer_vulkan/vk_texture_cache.h | 2 + 7 files changed, 334 insertions(+), 196 deletions(-) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 92f2d0ea5c..7c91f53f32 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -690,9 +690,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView }; const VkPipelineLayout layout = *one_texture_pipeline_layout; const VkPipeline pipeline = FindOrEmplaceColorPipeline(key); - const auto attachments = - std::span(dst_framebuffer->Images()).first(dst_framebuffer->NumImages()); - if (std::ranges::find(attachments, src_image) != attachments.end()) { + if (scheduler.IsRenderPassImage(src_image)) { scheduler.RequestOutsideRenderPassOperationContext(); } scheduler.RequestRenderpass(dst_framebuffer); @@ -958,9 +956,14 @@ void BlitImageHelper::CopyMSAAImpl(const RenderingFormats& formats, VkPipeline p .extent = dst_extent, }; const VkImageView dst_view_handle = *dst_view; - const RenderingAttachments attachments = + RenderingAttachments attachments = MakeRenderingAttachments(formats, std::span(&dst_view_handle, formats.num_colors), dst_view_handle, render_area, 1); + attachments.colors[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments.depth.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + if (copy_stencil) { + attachments.stencil.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } const MSAACopyPushConstants push_constants{ .dst_offset = {dst_offset.x, dst_offset.y}, .src_offset = {copy.src_offset.x, copy.src_offset.y}, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 5f6f525d1d..577c7fb3f6 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -575,8 +575,16 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { prepare_stage(4); } texture_cache.UpdateRenderTargets(false); - texture_cache.CheckFeedbackLoop(std::span{views.data(), - views.size()}); + const std::span view_span{views.data(), views.size()}; + texture_cache.CheckFeedbackLoop(view_span); + const auto samples_render_pass_image = [&](const VideoCommon::ImageViewInOut& view) { + return view.id && + scheduler.IsRenderPassImage(texture_cache.GetImageView(view.id).ImageHandle()); + }; + if (scheduler.CanAliasRenderPass(texture_cache.GetFramebuffer()) && + std::ranges::any_of(view_span, samples_render_pass_image)) { + scheduler.RequestOutsideRenderPassOperationContext(); + } if (IsBuilt() && !pipeline) { return false; } diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index adf6d763ac..598bbd3633 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -37,6 +37,12 @@ using Tegra::Engines::Maxwell3D; using VideoCommon::QueryType; namespace { +bool LacksQueryWriteBack(const Device& device) { + const VkDriverId driver_id = device.GetDriverID(); + return driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || + driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP; +} + class SamplesQueryBank : public VideoCommon::BankBase { public: static constexpr size_t BANK_SIZE = 256; @@ -235,9 +241,7 @@ public: return; } PauseCounter(); - const auto driver_id = device.GetDriverID(); - if (driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || - driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) { + if (LacksQueryWriteBack(device)) { pending_sync.clear(); sync_values_stash.clear(); return; @@ -1467,6 +1471,10 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValue(VideoCommon::Lookup if (!impl->device.IsExtConditionalRendering()) { return false; } + if (LacksQueryWriteBack(impl->device)) { + EndHostConditionalRendering(); + return true; + } HostConditionalRenderingCompareBCImpl(object_1.address, true, true); return true; } @@ -1516,7 +1524,8 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku auto driver_id = impl->device.GetDriverID(); const bool is_gpu_high = Settings::IsGPULevelHigh(); - if ((!is_gpu_high && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) || driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) { + if ((!is_gpu_high && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) || + LacksQueryWriteBack(impl->device)) { EndHostConditionalRendering(); return true; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 4c63d0b890..cde7da2bcb 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -30,6 +30,8 @@ namespace Vulkan { namespace { +constexpr size_t DEPTH_VIEW = 8; + struct BeginRenderingCommand { void operator()(vk::CommandBuffer cmdbuf, vk::CommandBuffer) const { BeginRendering(cmdbuf, attachments); @@ -37,6 +39,24 @@ struct BeginRenderingCommand { RenderingAttachments attachments; }; + +VkImageView DepthStencilView(const RenderingAttachments& attachments) { + if (attachments.depth.imageView != VK_NULL_HANDLE) { + return attachments.depth.imageView; + } + return attachments.stencil.imageView; +} + +VkAccessFlags2 AttachmentWriteAccess(VkImageAspectFlags aspect_mask) { + if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) { + return VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + } + if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { + return VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + } + return VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; +} } // Anonymous namespace void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf, @@ -129,6 +149,12 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer) { state.framebuffer_id = framebuffer->Id(); ++renderpass_serial; renderpass_pristine = true; + alias_framebuffer_id = 0; + std::ranges::transform(attachments.colors, renderpass_views.begin(), + &VkRenderingAttachmentInfo::imageView); + renderpass_views[DEPTH_VIEW] = DepthStencilView(attachments); + renderpass_extent = attachments.render_area.extent; + renderpass_layers = attachments.layers; attachments_touched = 0; attachments_written = 0; @@ -153,11 +179,49 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer) { framebuffer->MarkResolveShadowsUpToDate(); } -void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u32 written) { - if (framebuffer->Id() != state.framebuffer_id) { - EndRenderPass(); - BeginRenderPassImpl(framebuffer); +void Scheduler::BindFramebuffer(const Framebuffer* framebuffer) { + if (framebuffer->Id() == state.framebuffer_id) { + return; } + if (CanAliasRenderPass(framebuffer)) { + alias_framebuffer_id = framebuffer->Id(); + return; + } + EndRenderPass(); + BeginRenderPassImpl(framebuffer); +} + +bool Scheduler::CanAliasRenderPass(const Framebuffer* framebuffer) const { + const u64 id = framebuffer->Id(); + if (id == alias_framebuffer_id) { + return true; + } + if (id == state.framebuffer_id || state.framebuffer_id == 0 || + !device.IsExtDynamicRenderingUnusedAttachmentsSupported()) { + return false; + } + const RenderingAttachments& attachments = framebuffer->Attachments(); + if (attachments.layers != renderpass_layers || + attachments.render_area.extent.width != renderpass_extent.width || + attachments.render_area.extent.height != renderpass_extent.height) { + return false; + } + for (u32 slot = 0; slot < attachments.num_colors; ++slot) { + if (attachments.colors[slot].imageView != renderpass_views[slot]) { + return false; + } + } + const VkImageView depth_stencil = DepthStencilView(attachments); + return depth_stencil == VK_NULL_HANDLE || depth_stencil == renderpass_views[DEPTH_VIEW]; +} + +bool Scheduler::IsRenderPassImage(VkImage image) const { + const auto images = std::span(renderpass_images).first(num_renderpass_images); + return std::ranges::find(images, image) != images.end(); +} + +void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u32 written) { + BindFramebuffer(framebuffer); renderpass_pristine = false; attachments_touched |= touched; attachments_written |= written; @@ -165,10 +229,7 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u bool Scheduler::OverrideLoadOps(const Framebuffer* framebuffer, u32 attachments, VkAttachmentLoadOp load_op, const VkClearValue& value) { - if (framebuffer->Id() != state.framebuffer_id) { - EndRenderPass(); - BeginRenderPassImpl(framebuffer); - } + BindFramebuffer(framebuffer); if (!renderpass_pristine || recorded_attachments == nullptr) { return false; } @@ -252,6 +313,36 @@ void Scheduler::RelaxAttachmentOps(RenderingAttachments& attachments) const { } } +u32 Scheduler::RefineImageAccesses(const RenderingAttachments& attachments, + std::array& accesses) const { + const auto stores = [](const VkRenderingAttachmentInfo& attachment) { + return attachment.imageView != VK_NULL_HANDLE && + attachment.storeOp != VK_ATTACHMENT_STORE_OP_NONE; + }; + u32 unused_images = 0; + u32 image = 0; + const auto refine = [&](bool used, bool stored) { + if (!used) { + unused_images |= 1u << image; + } + if (!stored) { + accesses[image] = 0; + } + ++image; + }; + for (u32 slot = 0; slot < attachments.num_colors; ++slot) { + if (renderpass_views[slot] != VK_NULL_HANDLE) { + const VkRenderingAttachmentInfo& color = attachments.colors[slot]; + refine(color.imageView != VK_NULL_HANDLE, stores(color)); + } + } + if (renderpass_views[DEPTH_VIEW] != VK_NULL_HANDLE) { + refine(DepthStencilView(attachments) != VK_NULL_HANDLE, + stores(attachments.depth) || stores(attachments.stencil)); + } + return unused_images; +} + void Scheduler::PublishComputeWrites() { if (!std::exchange(compute_writes, false)) { return; @@ -428,78 +519,68 @@ void Scheduler::EndPendingOperations() { EndRenderPass(); } -void Scheduler::EndRenderPass() - { - if (state.framebuffer_id == 0) { - return; - } - if (recorded_attachments != nullptr) { - RelaxAttachmentOps(*recorded_attachments); - } - ended_attachments = std::exchange(recorded_attachments, nullptr); +void Scheduler::EndRenderPass() { + if (state.framebuffer_id == 0) { + return; + } + std::array accesses{}; + for (u32 index = 0; index < num_renderpass_images; ++index) { + accesses[index] = AttachmentWriteAccess(renderpass_image_ranges[index].aspectMask); + } + u32 unused_images = 0; + if (recorded_attachments != nullptr) { + RelaxAttachmentOps(*recorded_attachments); + unused_images = RefineImageAccesses(*recorded_attachments, accesses); + } + ended_attachments = std::exchange(recorded_attachments, nullptr); - query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount); + query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount); - // Log render pass end - if (GPU::Logging::IsActive() && - Settings::values.gpu_log_vulkan_calls.GetValue()) { - GPU::Logging::GPULogger::GetInstance().LogRenderPassEnd(); - } - - query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false); - query_cache->NotifySegment(false); - - Record([num_images = num_renderpass_images, - images = renderpass_images, - ranges = renderpass_image_ranges, - write_barrier = &renderpass_write_barrier, - num_memory_barriers = - static_cast(std::exchange(renderpass_writes, false))]( - vk::CommandBuffer cmdbuf) { - std::array barriers; - for (size_t i = 0; i < num_images; ++i) { - const VkImageSubresourceRange& range = ranges[i]; - const bool is_color = (range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0; - const bool is_depth_stencil = (range.aspectMask - & (VK_IMAGE_ASPECT_DEPTH_BIT - | VK_IMAGE_ASPECT_STENCIL_BIT)) !=0; - - VkAccessFlags2 src_access = 0; - - if (is_color) - src_access |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; - else if (is_depth_stencil) - src_access |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - else - src_access |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT - | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - - barriers[i] = VkImageMemoryBarrier2{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .pNext = nullptr, - .srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT - | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT - | VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccessMask = src_access, - .dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, - .dstAccessMask = vk::ACCESS_IMAGE_USERS, - .oldLayout = VK_IMAGE_LAYOUT_GENERAL, - .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = images[i], - .subresourceRange = range, - }; - } - cmdbuf.EndRendering(); - cmdbuf.PipelineBarrier(0, vk::Span(write_barrier, num_memory_barriers), {}, - vk::Span(barriers.data(), num_images)); - }); - - state.framebuffer_id = 0; - num_renderpass_images = 0; + // Log render pass end + if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) { + GPU::Logging::GPULogger::GetInstance().LogRenderPassEnd(); } + query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false); + query_cache->NotifySegment(false); + + Record([num_images = num_renderpass_images, images = renderpass_images, + ranges = renderpass_image_ranges, accesses, unused_images, + write_barrier = &renderpass_write_barrier, + num_memory_barriers = static_cast(std::exchange(renderpass_writes, false))]( + vk::CommandBuffer cmdbuf) { + std::array barriers; + size_t num_barriers = 0; + for (size_t i = 0; i < num_images; ++i) { + if (((unused_images >> i) & 1) != 0) { + continue; + } + barriers[num_barriers++] = VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = vk::PIPELINE_STAGE_ATTACHMENTS, + .srcAccessMask = accesses[i], + .dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, + .dstAccessMask = vk::ACCESS_IMAGE_USERS, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = images[i], + .subresourceRange = ranges[i], + }; + } + cmdbuf.EndRendering(); + if (num_barriers + num_memory_barriers != 0) { + cmdbuf.PipelineBarrier(0, vk::Span(write_barrier, num_memory_barriers), {}, + vk::Span(barriers.data(), num_barriers)); + } + }); + + state.framebuffer_id = 0; + alias_framebuffer_id = 0; + num_renderpass_images = 0; +} void Scheduler::AcquireNewChunk() { std::scoped_lock rl{reserve_mutex}; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index e6917998ea..ef04062b49 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -71,6 +71,10 @@ public: void DiscardResolvedAttachments(VkImageView resolve_view); + bool CanAliasRenderPass(const Framebuffer* framebuffer) const; + + bool IsRenderPassImage(VkImage image) const; + /// Requests the current execution context to be able to execute operations only allowed outside /// of a renderpass. void RequestOutsideRenderPassOperationContext(); @@ -300,6 +304,8 @@ private: void BeginRenderPassImpl(const Framebuffer* framebuffer); + void BindFramebuffer(const Framebuffer* framebuffer); + void WorkerThread(std::stop_token stop_token); void AllocateWorkerCommandBuffer(); @@ -314,6 +320,9 @@ private: void RelaxAttachmentOps(RenderingAttachments& attachments) const; + u32 RefineImageAccesses(const RenderingAttachments& attachments, + std::array& accesses) const; + void AcquireNewChunk(); const Device& device; @@ -333,6 +342,7 @@ private: State state; u64 renderpass_serial = 0; + u64 alias_framebuffer_id = 0; u64 wfi_serial = 0; bool renderpass_writes = false; bool renderpass_pristine = false; @@ -347,6 +357,9 @@ private: u32 num_renderpass_images = 0; std::array renderpass_images{}; std::array renderpass_image_ranges{}; + std::array renderpass_views{}; + VkExtent2D renderpass_extent{}; + u32 renderpass_layers = 0; std::queue> work_queue; std::vector> chunk_reserve; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 330c414b4e..e73d6c1598 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1373,7 +1373,24 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst return; } ASSERT(src.format == dst.format); - if (is_src_msaa && !is_dst_msaa && + const bool is_resolve = is_src_msaa && !is_dst_msaa; + if (ENABLE_MSAA_RESOLVE_CONSUME && is_resolve && HaveSameExtent(dst_region, src_region)) { + const VkImageResolve2 resolve = MakeImageResolve( + dst_region, src_region, MakeSubresourceLayers(&dst), MakeSubresourceLayers(&src)); + const VkImageCopy2 region{ + .sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2, + .pNext = nullptr, + .srcSubresource = resolve.srcSubresource, + .srcOffset = resolve.srcOffset, + .dstSubresource = resolve.dstSubresource, + .dstOffset = resolve.dstOffset, + .extent = resolve.extent, + }; + if (CopyResolveShadow(src.ImageHandle(), dst.ImageHandle(), region)) { + return; + } + } + if (is_resolve && (aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) == 0) { UNIMPLEMENTED_MSG("Stencil-only MSAA resolve is not supported"); @@ -1416,7 +1433,6 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst return; } - const bool is_resolve = is_src_msaa && !is_dst_msaa; if (is_resolve && !HaveSameExtent(dst_region, src_region)) { blit_image_helper.BlitColorMSAA(dst_framebuffer, src, dst_region, src_region); return; @@ -1729,120 +1745,126 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src, }); } +bool TextureCacheRuntime::CopyResolveShadow(VkImage msaa_image, VkImage dst_image, + const VkImageCopy2& region) { + const ResolveShadow* const shadow = GetValidResolveShadow(msaa_image); + if (shadow == nullptr || shadow->aspect_mask != region.srcSubresource.aspectMask || + region.srcSubresource.mipLevel != 0 || region.srcOffset.x < 0 || region.srcOffset.y < 0 || + static_cast(region.srcOffset.x) + region.extent.width > shadow->extent.width || + static_cast(region.srcOffset.y) + region.extent.height > shadow->extent.height || + region.srcSubresource.baseArrayLayer + region.srcSubresource.layerCount > + shadow->layers) { + return false; + } + const VkImageAspectFlags aspect_mask = shadow->aspect_mask; + const VkImage shadow_image = *shadow->image; + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([shadow_image, dst_image, region, aspect_mask](vk::CommandBuffer cmdbuf) { + const std::array pre_barriers{ + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, + .srcAccessMask = vk::ACCESS_IMAGE_WRITES, + .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = shadow_image, + .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, + VK_REMAINING_ARRAY_LAYERS}, + }, + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, + .srcAccessMask = vk::ACCESS_IMAGE_WRITES, + .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, + VK_REMAINING_ARRAY_LAYERS}, + }, + }; + const std::array post_barriers{ + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .srcAccessMask = 0, + .dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, + .dstAccessMask = vk::ACCESS_IMAGE_USERS, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = shadow_image, + .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, + VK_REMAINING_ARRAY_LAYERS}, + }, + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, + .dstAccessMask = vk::ACCESS_IMAGE_USERS, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, + VK_REMAINING_ARRAY_LAYERS}, + }, + }; + cmdbuf.PipelineBarrier(0, {}, {}, pre_barriers); + cmdbuf.CopyImage(shadow_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region); + cmdbuf.PipelineBarrier(0, {}, {}, post_barriers); + }); + const bool is_color = aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT; + if ((is_color && ENABLE_MSAA_COLOR_DISCARD) || + (!is_color && ENABLE_MSAA_DEPTH_STENCIL_DISCARD)) { + scheduler.DiscardResolvedAttachments(*shadow->view); + } + return true; +} + void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, std::span copies) { const bool msaa_to_non_msaa = src.info.num_samples > 1 && dst.info.num_samples == 1; const u32 num_samples = msaa_to_non_msaa ? src.info.num_samples : dst.info.num_samples; if (ENABLE_MSAA_RESOLVE_CONSUME && msaa_to_non_msaa && copies.size() == 1 && - src.info.format == dst.info.format) { + src.info.format == dst.info.format && copies.front().src_offset.x == 0 && + copies.front().src_offset.y == 0) { const VideoCommon::ImageCopy& copy = copies.front(); - const ResolveShadow* const shadow = GetValidResolveShadow(src.Handle()); - if (shadow != nullptr && shadow->aspect_mask == dst.AspectMask() && - copy.src_offset.x == 0 && copy.src_offset.y == 0 && - copy.src_subresource.base_level == 0 && - static_cast(copy.extent.width) <= shadow->extent.width && - static_cast(copy.extent.height) <= shadow->extent.height && - static_cast(copy.src_subresource.base_layer + copy.src_subresource.num_layers) <= - shadow->layers) { - const VkImageAspectFlags aspect_mask = shadow->aspect_mask; - const VkImage shadow_image = *shadow->image; - const VkImage dst_image = dst.Handle(); - const VkImageCopy2 region{ - .sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2, - .pNext = nullptr, - .srcSubresource{ - .aspectMask = aspect_mask, - .mipLevel = 0, - .baseArrayLayer = static_cast(copy.src_subresource.base_layer), - .layerCount = static_cast(copy.src_subresource.num_layers), - }, - .srcOffset = {0, 0, 0}, - .dstSubresource{ - .aspectMask = aspect_mask, - .mipLevel = static_cast(copy.dst_subresource.base_level), - .baseArrayLayer = static_cast(copy.dst_subresource.base_layer), - .layerCount = static_cast(copy.dst_subresource.num_layers), - }, - .dstOffset = {copy.dst_offset.x, copy.dst_offset.y, copy.dst_offset.z}, - .extent = {copy.extent.width, copy.extent.height, 1}, - }; - scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([shadow_image, dst_image, region, - aspect_mask](vk::CommandBuffer cmdbuf) { - const std::array pre_barriers{ - VkImageMemoryBarrier2{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .pNext = nullptr, - .srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, - .srcAccessMask = vk::ACCESS_IMAGE_WRITES, - .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, - .dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_GENERAL, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = shadow_image, - .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, - VK_REMAINING_ARRAY_LAYERS}, - }, - VkImageMemoryBarrier2{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .pNext = nullptr, - .srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, - .srcAccessMask = vk::ACCESS_IMAGE_WRITES, - .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, - .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, - .oldLayout = VK_IMAGE_LAYOUT_GENERAL, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = dst_image, - .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, - VK_REMAINING_ARRAY_LAYERS}, - }, - }; - const std::array post_barriers{ - VkImageMemoryBarrier2{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .pNext = nullptr, - .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, - .srcAccessMask = 0, - .dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, - .dstAccessMask = vk::ACCESS_IMAGE_USERS, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = shadow_image, - .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, - VK_REMAINING_ARRAY_LAYERS}, - }, - VkImageMemoryBarrier2{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .pNext = nullptr, - .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, - .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, - .dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS, - .dstAccessMask = vk::ACCESS_IMAGE_USERS, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = dst_image, - .subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0, - VK_REMAINING_ARRAY_LAYERS}, - }, - }; - cmdbuf.PipelineBarrier(0, {}, {}, pre_barriers); - cmdbuf.CopyImage(shadow_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region); - cmdbuf.PipelineBarrier(0, {}, {}, post_barriers); - }); - const bool is_color = aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT; - if ((is_color && ENABLE_MSAA_COLOR_DISCARD) || - (!is_color && ENABLE_MSAA_DEPTH_STENCIL_DISCARD)) { - scheduler.DiscardResolvedAttachments(*shadow->view); - } + const VkImageCopy2 region{ + .sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2, + .pNext = nullptr, + .srcSubresource{ + .aspectMask = dst.AspectMask(), + .mipLevel = static_cast(copy.src_subresource.base_level), + .baseArrayLayer = static_cast(copy.src_subresource.base_layer), + .layerCount = static_cast(copy.src_subresource.num_layers), + }, + .srcOffset = {0, 0, 0}, + .dstSubresource{ + .aspectMask = dst.AspectMask(), + .mipLevel = static_cast(copy.dst_subresource.base_level), + .baseArrayLayer = static_cast(copy.dst_subresource.base_layer), + .layerCount = static_cast(copy.dst_subresource.num_layers), + }, + .dstOffset = {copy.dst_offset.x, copy.dst_offset.y, copy.dst_offset.z}, + .extent = {copy.extent.width, copy.extent.height, 1}, + }; + if (CopyResolveShadow(src.Handle(), dst.Handle(), region)) { return; } } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 67f31f1156..ea8ecc4df6 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -130,6 +130,8 @@ public: void EraseResolveShadow(VkImage msaa_image); + bool CopyResolveShadow(VkImage msaa_image, VkImage dst_image, const VkImageCopy2& region); + std::span ViewFormats(PixelFormat format) { return view_formats[static_cast(format)]; }