From d754fef20e64654ed02c0e979379588160b576dd Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Tue, 28 Jul 2026 03:38:25 -0400 Subject: [PATCH] [TEST] Upload on depth MSAACopy pass --- src/video_core/host_shaders/CMakeLists.txt | 1 + .../convert_non_msaa_to_msaa_depth.frag | 19 +++ src/video_core/renderer_vulkan/blit_image.cpp | 112 +++++++++++++----- src/video_core/renderer_vulkan/blit_image.h | 2 + .../renderer_vulkan/vk_texture_cache.cpp | 6 +- 5 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 src/video_core/host_shaders/convert_non_msaa_to_msaa_depth.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 0d342c463d..7f1d0079da 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -32,6 +32,7 @@ set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.frag ${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa.comp ${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa.frag + ${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa_depth.frag ${CMAKE_CURRENT_SOURCE_DIR}/convert_s8d24_to_abgr8.frag ${CMAKE_CURRENT_SOURCE_DIR}/full_screen_triangle.vert ${CMAKE_CURRENT_SOURCE_DIR}/fxaa.frag diff --git a/src/video_core/host_shaders/convert_non_msaa_to_msaa_depth.frag b/src/video_core/host_shaders/convert_non_msaa_to_msaa_depth.frag new file mode 100644 index 0000000000..f883b3196f --- /dev/null +++ b/src/video_core/host_shaders/convert_non_msaa_to_msaa_depth.frag @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 450 core + +layout(binding = 0) uniform sampler2D img_in; + +layout(push_constant) uniform PushConstants { + ivec2 dst_offset; + ivec2 src_offset; + ivec2 scale; +}; + +void main() { + const ivec2 msaa_coord = ivec2(gl_FragCoord.xy) - dst_offset; + const ivec2 sample_offset = ivec2(gl_SampleID % scale.x, gl_SampleID / scale.x); + const ivec2 coord = msaa_coord * scale + sample_offset + src_offset; + gl_FragDepth = texelFetch(img_in, coord, 0).r; +} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 89083d29fb..6bbfe6adc8 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -21,6 +21,7 @@ #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" #include "video_core/host_shaders/convert_msaa_to_non_msaa_frag_spv.h" +#include "video_core/host_shaders/convert_non_msaa_to_msaa_depth_frag_spv.h" #include "video_core/host_shaders/convert_non_msaa_to_msaa_frag_spv.h" #include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h" #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" @@ -519,7 +520,8 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view) } [[nodiscard]] vk::ImageView MakeMSAACopyView(const vk::Device& device, VkImage image, - VkFormat format, u32 base_level) { + VkFormat format, u32 base_level, + VkImageAspectFlags aspect_mask) { return device.CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, @@ -534,7 +536,7 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view) .a = VK_COMPONENT_SWIZZLE_IDENTITY, }, .subresourceRange{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .aspectMask = aspect_mask, .baseMipLevel = base_level, .levelCount = 1, .baseArrayLayer = 0, @@ -610,6 +612,8 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)), convert_msaa_to_non_msaa_frag(BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_FRAG_SPV)), convert_non_msaa_to_msaa_frag(BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_FRAG_SPV)), + convert_non_msaa_to_msaa_depth_frag( + BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_DEPTH_FRAG_SPV)), linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)), nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) {} @@ -895,16 +899,31 @@ void BlitImageHelper::CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_i const s32 scale_y = 1 << samples_y; const VkSampleCountFlagBits samples = msaa_to_non_msaa ? VK_SAMPLE_COUNT_1_BIT : SampleCountFlag(num_samples); + const auto dst_surface_type = VideoCore::Surface::GetFormatType(dst_format); + const bool is_depth = dst_surface_type == VideoCore::Surface::SurfaceType::Depth || + dst_surface_type == VideoCore::Surface::SurfaceType::DepthStencil; + const bool has_stencil = dst_surface_type == VideoCore::Surface::SurfaceType::DepthStencil; + const VkImageAspectFlags view_aspect = + is_depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + const VkImageAspectFlags barrier_aspect = + is_depth ? (VK_IMAGE_ASPECT_DEPTH_BIT | + (has_stencil ? VK_IMAGE_ASPECT_STENCIL_BIT : 0u)) + : VK_IMAGE_ASPECT_COLOR_BIT; RenderPassKey renderpass_key{}; renderpass_key.color_formats.fill(VideoCore::Surface::PixelFormat::Invalid); - renderpass_key.color_formats[0] = dst_format; - renderpass_key.depth_format = VideoCore::Surface::PixelFormat::Invalid; + if (is_depth) { + renderpass_key.depth_format = dst_format; + } else { + renderpass_key.color_formats[0] = dst_format; + renderpass_key.depth_format = VideoCore::Surface::PixelFormat::Invalid; + } renderpass_key.samples = samples; const VkRenderPass renderpass = render_pass_cache.Get(renderpass_key); const MSAACopyPipelineKey key{ .renderpass = renderpass, .samples = samples, .msaa_to_non_msaa = msaa_to_non_msaa, + .is_depth = is_depth, }; const VkPipeline pipeline = FindOrEmplaceMSAACopyPipeline(key); const VkPipelineLayout layout = *msaa_copy_pipeline_layout; @@ -920,10 +939,10 @@ void BlitImageHelper::CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_i ASSERT(copy.dst_subresource.num_layers == 1); vk::ImageView src_view = MakeMSAACopyView(device.GetLogical(), src_image, src_vk_format, - static_cast(copy.src_subresource.base_level)); + static_cast(copy.src_subresource.base_level), view_aspect); vk::ImageView dst_view = MakeMSAACopyView(device.GetLogical(), dst_image, dst_vk_format, - static_cast(copy.dst_subresource.base_level)); + static_cast(copy.dst_subresource.base_level), view_aspect); const VkOffset2D dst_offset{copy.dst_offset.x, copy.dst_offset.y}; const VkExtent2D dst_extent{copy.extent.width, copy.extent.height}; const VkRect2D render_area{ @@ -949,50 +968,61 @@ void BlitImageHelper::CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_i scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([this, pipeline, layout, sampler, renderpass, framebuffer_handle = *framebuffer, src_view_handle = *src_view, - src = src_image, dst = dst_image, render_area, + src = src_image, dst = dst_image, render_area, is_depth, barrier_aspect, push_constants](vk::CommandBuffer cmdbuf) { - constexpr VkImageSubresourceRange color_range{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + const VkImageSubresourceRange src_range{ + .aspectMask = barrier_aspect, .baseMipLevel = 0, .levelCount = VK_REMAINING_MIP_LEVELS, .baseArrayLayer = 0, .layerCount = VK_REMAINING_ARRAY_LAYERS, }; + const VkImageSubresourceRange dst_range = src_range; + const VkAccessFlags attachment_read = + is_depth ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + : VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + const VkAccessFlags attachment_write = + is_depth ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT + : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + const VkPipelineStageFlags attachment_stage = + is_depth ? VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT + : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; const std::array pre_barriers{ VkImageMemoryBarrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, + .srcAccessMask = attachment_write | VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT, .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, .oldLayout = VK_IMAGE_LAYOUT_GENERAL, .newLayout = VK_IMAGE_LAYOUT_GENERAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = src, - .subresourceRange = color_range, + .subresourceRange = src_range, }, VkImageMemoryBarrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .srcAccessMask = attachment_write | VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = attachment_read | attachment_write, .oldLayout = VK_IMAGE_LAYOUT_GENERAL, .newLayout = VK_IMAGE_LAYOUT_GENERAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = dst, - .subresourceRange = color_range, + .subresourceRange = dst_range, }, }; cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | attachment_stage, 0, nullptr, nullptr, pre_barriers); const VkRenderPassBeginInfo renderpass_bi{ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, @@ -1025,16 +1055,16 @@ void BlitImageHelper::CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_i const VkImageMemoryBarrier post_barrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .srcAccessMask = attachment_write, .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, .oldLayout = VK_IMAGE_LAYOUT_GENERAL, .newLayout = VK_IMAGE_LAYOUT_GENERAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = dst, - .subresourceRange = color_range, + .subresourceRange = dst_range, }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + cmdbuf.PipelineBarrier(attachment_stage, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -1423,9 +1453,36 @@ VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipeline return *msaa_copy_pipelines[std::distance(msaa_copy_keys.begin(), it)]; } msaa_copy_keys.push_back(key); - const std::array stages = MakeStages(*clear_color_vert, key.msaa_to_non_msaa - ? *convert_msaa_to_non_msaa_frag - : *convert_non_msaa_to_msaa_frag); + const VkShaderModule frag_module = + key.msaa_to_non_msaa + ? *convert_msaa_to_non_msaa_frag + : (key.is_depth ? *convert_non_msaa_to_msaa_depth_frag + : *convert_non_msaa_to_msaa_frag); + const std::array stages = MakeStages(*clear_color_vert, frag_module); + const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = VK_COMPARE_OP_ALWAYS, + .depthBoundsTestEnable = VK_FALSE, + .stencilTestEnable = VK_FALSE, + .front = {}, + .back = {}, + .minDepthBounds = 0.0f, + .maxDepthBounds = 0.0f, + }; + static constexpr VkPipelineColorBlendStateCreateInfo no_color_blend_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_CLEAR, + .attachmentCount = 0, + .pAttachments = nullptr, + .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, + }; const VkPipelineMultisampleStateCreateInfo multisample_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = nullptr, @@ -1450,8 +1507,9 @@ VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipeline .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &multisample_ci, - .pDepthStencilState = nullptr, - .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, + .pDepthStencilState = key.is_depth ? &depth_stencil_ci : nullptr, + .pColorBlendState = key.is_depth ? &no_color_blend_ci + : &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, .layout = *msaa_copy_pipeline_layout, .renderPass = key.renderpass, diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 67294d594b..3c5b9e129a 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -51,6 +51,7 @@ struct MSAACopyPipelineKey { VkRenderPass renderpass; VkSampleCountFlagBits samples; bool msaa_to_non_msaa; + bool is_depth; }; struct BlitMSAAPipelineKey { @@ -180,6 +181,7 @@ private: vk::ShaderModule convert_s8d24_to_abgr8_frag; vk::ShaderModule convert_msaa_to_non_msaa_frag; vk::ShaderModule convert_non_msaa_to_msaa_frag; + vk::ShaderModule convert_non_msaa_to_msaa_depth_frag; vk::Sampler linear_sampler; vk::Sampler nearest_sampler; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 8ccfad0820..a620f6b15e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1922,9 +1922,11 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, ScaleDown(true); } - const bool wants_msaa_upload = info.num_samples > 1 - && (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0 + const bool is_color_upload = (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0 && !VideoCore::Surface::IsPixelFormatInteger(info.format); + const bool is_depth_upload = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; + const bool wants_msaa_upload = + info.num_samples > 1 && (is_color_upload || is_depth_upload); if (wants_msaa_upload) { ImageInfo temp_info = info;