From 6d9e4b97a6bba8accb8bd4158f2d653cf2c9e90b Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 12 Aug 2026 00:44:14 -0400 Subject: [PATCH] [TEST] MSAA uploads --- src/video_core/host_shaders/CMakeLists.txt | 2 + .../convert_non_msaa_to_msaa_depth.frag | 19 ++ ...onvert_non_msaa_to_msaa_depth_stencil.frag | 22 ++ src/video_core/renderer_vulkan/blit_image.cpp | 288 +++++++++++++++++- src/video_core/renderer_vulkan/blit_image.h | 15 + .../renderer_vulkan/vk_texture_cache.cpp | 29 +- 6 files changed, 365 insertions(+), 10 deletions(-) create mode 100644 src/video_core/host_shaders/convert_non_msaa_to_msaa_depth.frag create mode 100644 src/video_core/host_shaders/convert_non_msaa_to_msaa_depth_stencil.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 6be3e3bd06..be46842cd9 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -34,6 +34,8 @@ 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_non_msaa_to_msaa_depth_stencil.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/host_shaders/convert_non_msaa_to_msaa_depth_stencil.frag b/src/video_core/host_shaders/convert_non_msaa_to_msaa_depth_stencil.frag new file mode 100644 index 0000000000..d9a308f5c3 --- /dev/null +++ b/src/video_core/host_shaders/convert_non_msaa_to_msaa_depth_stencil.frag @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 450 core +#extension GL_ARB_shader_stencil_export : require + +layout(binding = 0) uniform sampler2D depth_tex; +layout(binding = 1) uniform usampler2D stencil_tex; + +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(depth_tex, coord, 0).r; + gl_FragStencilRefARB = int(texelFetch(stencil_tex, coord, 0).r); +} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index e06226e918..c4560177b8 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -22,6 +22,8 @@ #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_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_depth_stencil_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" #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" @@ -519,7 +521,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 +537,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, @@ -586,6 +589,10 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, msaa_copy_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo( one_texture_set_layout.address(), PUSH_CONSTANT_RANGE))), + msaa_copy_depth_stencil_pipeline_layout( + device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo( + two_textures_set_layout.address(), + PUSH_CONSTANT_RANGE))), full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)), blit_color_msaa_frag(BuildShader(device, BLIT_COLOR_MSAA_FRAG_SPV)), @@ -610,6 +617,12 @@ 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)), + convert_non_msaa_to_msaa_depth_stencil_frag( + device.IsExtShaderStencilExportSupported() + ? BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_DEPTH_STENCIL_FRAG_SPV) + : vk::ShaderModule{}), linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)), nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) {} @@ -920,10 +933,12 @@ 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), + VK_IMAGE_ASPECT_COLOR_BIT); 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), + VK_IMAGE_ASPECT_COLOR_BIT); 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{ @@ -1417,6 +1432,198 @@ VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline(VkRenderPas return *pipelines.back(); } +void BlitImageHelper::CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage dst_image, + VideoCore::Surface::PixelFormat dst_format, VkImage src_image, + VideoCore::Surface::PixelFormat src_format, u32 num_samples, + std::span copies, + bool copy_stencil) { + while (!msaa_copy_resources.empty() && scheduler.IsFree(msaa_copy_resources.front().tick)) { + msaa_copy_resources.pop_front(); + } + const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(static_cast(num_samples)); + const s32 scale_x = 1 << samples_x; + const s32 scale_y = 1 << samples_y; + const VkSampleCountFlagBits samples = SampleCountFlag(num_samples); + RenderPassKey renderpass_key{}; + renderpass_key.color_formats.fill(VideoCore::Surface::PixelFormat::Invalid); + renderpass_key.depth_format = dst_format; + renderpass_key.samples = samples; + const VkRenderPass renderpass = render_pass_cache.Get(renderpass_key); + const MSAACopyPipelineKey key{ + .renderpass = renderpass, + .samples = samples, + .msaa_to_non_msaa = false, + }; + const VkPipeline pipeline = FindOrEmplaceMSAACopyDepthPipeline(key, copy_stencil); + const VkPipelineLayout layout = copy_stencil ? *msaa_copy_depth_stencil_pipeline_layout + : *msaa_copy_pipeline_layout; + const VkSampler sampler = *nearest_sampler; + const VkFormat src_vk_format = + MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, src_format).format; + const VkFormat dst_vk_format = + MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, dst_format).format; + const VkImageAspectFlags attachment_aspect = + VideoCore::Surface::GetFormatType(dst_format) == + VideoCore::Surface::SurfaceType::DepthStencil + ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT + : VK_IMAGE_ASPECT_DEPTH_BIT; + for (const VideoCommon::ImageCopy& copy : copies) { + ASSERT(copy.src_subresource.base_layer == 0); + ASSERT(copy.src_subresource.num_layers == 1); + ASSERT(copy.dst_subresource.base_layer == 0); + 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), + VK_IMAGE_ASPECT_DEPTH_BIT); + vk::ImageView src_stencil_view = + copy_stencil ? MakeMSAACopyView(device.GetLogical(), src_image, src_vk_format, + static_cast(copy.src_subresource.base_level), + VK_IMAGE_ASPECT_STENCIL_BIT) + : vk::ImageView{}; + vk::ImageView dst_view = + MakeMSAACopyView(device.GetLogical(), dst_image, dst_vk_format, + static_cast(copy.dst_subresource.base_level), + attachment_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{ + .offset = dst_offset, + .extent = dst_extent, + }; + vk::Framebuffer framebuffer = device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .renderPass = renderpass, + .attachmentCount = 1, + .pAttachments = dst_view.address(), + .width = static_cast(dst_offset.x) + dst_extent.width, + .height = static_cast(dst_offset.y) + dst_extent.height, + .layers = 1, + }); + const MSAACopyPushConstants push_constants{ + .dst_offset = {dst_offset.x, dst_offset.y}, + .src_offset = {copy.src_offset.x, copy.src_offset.y}, + .scale = {scale_x, scale_y}, + }; + scheduler.RequestOutsideRenderPassOperationContext(); + const VkImageView src_stencil_handle = copy_stencil ? *src_stencil_view : VK_NULL_HANDLE; + scheduler.Record([this, pipeline, layout, sampler, renderpass, + framebuffer_handle = *framebuffer, src_view_handle = *src_view, + src_stencil_handle, src = src_image, dst = dst_image, render_area, + attachment_aspect, push_constants](vk::CommandBuffer cmdbuf) { + const VkImageSubresourceRange src_range{ + .aspectMask = attachment_aspect, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }; + const std::array pre_barriers{ + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_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 = src_range, + }, + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst, + .subresourceRange = src_range, + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + 0, nullptr, nullptr, pre_barriers); + const VkRenderPassBeginInfo renderpass_bi{ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .pNext = nullptr, + .renderPass = renderpass, + .framebuffer = framebuffer_handle, + .renderArea = render_area, + .clearValueCount = 0, + .pClearValues = nullptr, + }; + cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); + const VkDescriptorSet descriptor_set = + src_stencil_handle != VK_NULL_HANDLE + ? two_textures_descriptor_allocator.Commit() + : one_texture_descriptor_allocator.Commit(); + if (src_stencil_handle != VK_NULL_HANDLE) { + UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_view_handle, + src_stencil_handle); + } else { + UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view_handle); + } + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, + nullptr); + const VkViewport viewport{ + .x = static_cast(render_area.offset.x), + .y = static_cast(render_area.offset.y), + .width = static_cast(render_area.extent.width), + .height = static_cast(render_area.extent.height), + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; + cmdbuf.SetViewport(0, viewport); + cmdbuf.SetScissor(0, render_area); + cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, push_constants); + cmdbuf.Draw(3, 1, 0, 0); + cmdbuf.EndRenderPass(); + const VkImageMemoryBarrier post_barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_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 = src_range, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, 0, post_barrier); + }); + msaa_copy_resources.push_back(MSAACopyResources{ + .tick = scheduler.CurrentTick(), + .src_view = std::move(src_view), + .dst_view = std::move(dst_view), + .framebuffer = std::move(framebuffer), + }); + if (copy_stencil) { + msaa_copy_resources.push_back(MSAACopyResources{ + .tick = scheduler.CurrentTick(), + .src_view = std::move(src_stencil_view), + .dst_view = vk::ImageView{}, + .framebuffer = vk::Framebuffer{}, + }); + } + } +} + VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key) { const auto it = std::ranges::find(msaa_copy_keys, key); if (it != msaa_copy_keys.end()) { @@ -1462,6 +1669,79 @@ VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipeline return *msaa_copy_pipelines.back(); } +VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyDepthPipeline(const MSAACopyPipelineKey& key, + bool copy_stencil) { + auto& keys = copy_stencil ? msaa_copy_depth_stencil_keys : msaa_copy_depth_keys; + auto& pipelines = copy_stencil ? msaa_copy_depth_stencil_pipelines : msaa_copy_depth_pipelines; + const auto it = std::ranges::find(keys, key); + if (it != keys.end()) { + return *pipelines[std::distance(keys.begin(), it)]; + } + keys.push_back(key); + const std::array stages = + MakeStages(*clear_color_vert, copy_stencil ? *convert_non_msaa_to_msaa_depth_stencil_frag + : *convert_non_msaa_to_msaa_depth_frag); + const VkPipelineMultisampleStateCreateInfo multisample_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = key.samples, + .sampleShadingEnable = VK_TRUE, + .minSampleShading = 1.0f, + .pSampleMask = nullptr, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + static constexpr VkStencilOpState REPLACE_STENCIL_OP{ + .failOp = VK_STENCIL_OP_REPLACE, + .passOp = VK_STENCIL_OP_REPLACE, + .depthFailOp = VK_STENCIL_OP_REPLACE, + .compareOp = VK_COMPARE_OP_ALWAYS, + .compareMask = 0xFF, + .writeMask = 0xFF, + .reference = 0, + }; + 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 = copy_stencil ? VK_TRUE : VK_FALSE, + .front = copy_stencil ? REPLACE_STENCIL_OP : VkStencilOpState{}, + .back = copy_stencil ? REPLACE_STENCIL_OP : VkStencilOpState{}, + .minDepthBounds = 0.0f, + .maxDepthBounds = 0.0f, + }; + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = + GetPipelineInputAssemblyStateCreateInfo(device); + pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stageCount = static_cast(stages.size()), + .pStages = stages.data(), + .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, + .pTessellationState = nullptr, + .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pMultisampleState = &multisample_ci, + .pDepthStencilState = &depth_stencil_ci, + .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, + .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .layout = copy_stencil ? *msaa_copy_depth_stencil_pipeline_layout + : *msaa_copy_pipeline_layout, + .renderPass = key.renderpass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = 0, + }, device.StaticPipelineCache())); + return *pipelines.back(); +} + void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) { ConvertPipeline(pipeline, renderpass, false); } diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 67294d594b..3e6c2b09dd 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -116,6 +116,11 @@ public: VideoCore::Surface::PixelFormat src_format, u32 num_samples, std::span copies, bool msaa_to_non_msaa); + void CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage dst_image, + VideoCore::Surface::PixelFormat dst_format, VkImage src_image, + VideoCore::Surface::PixelFormat src_format, u32 num_samples, + std::span copies, bool copy_stencil); + private: void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view); @@ -131,6 +136,9 @@ private: [[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline( const BlitDepthStencilPipelineKey& key); [[nodiscard]] VkPipeline FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key); + + [[nodiscard]] VkPipeline FindOrEmplaceMSAACopyDepthPipeline(const MSAACopyPipelineKey& key, + bool copy_stencil); [[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key); [[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass, bool resolve_stencil); @@ -162,6 +170,7 @@ private: vk::PipelineLayout two_textures_pipeline_layout; vk::PipelineLayout clear_color_pipeline_layout; vk::PipelineLayout msaa_copy_pipeline_layout; + vk::PipelineLayout msaa_copy_depth_stencil_pipeline_layout; vk::ShaderModule full_screen_vert; vk::ShaderModule blit_color_to_color_frag; vk::ShaderModule blit_color_msaa_frag; @@ -180,6 +189,8 @@ 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::ShaderModule convert_non_msaa_to_msaa_depth_stencil_frag; vk::Sampler linear_sampler; vk::Sampler nearest_sampler; @@ -193,6 +204,10 @@ private: std::vector clear_stencil_pipelines; std::vector msaa_copy_keys; std::vector msaa_copy_pipelines; + std::vector msaa_copy_depth_keys; + std::vector msaa_copy_depth_pipelines; + std::vector msaa_copy_depth_stencil_keys; + std::vector msaa_copy_depth_stencil_pipelines; std::vector blit_msaa_color_keys; std::vector blit_msaa_color_pipelines; std::vector resolve_depth_keys; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 22990cf95d..bcf4fa1021 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1838,11 +1838,21 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, ScaleDown(true); } + const bool msaa_upload_is_depth = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; const bool wants_msaa_upload = info.num_samples > 1 - && (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0 + && ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0 || msaa_upload_is_depth) && !VideoCore::Surface::IsPixelFormatInteger(info.format); if (wants_msaa_upload) { + const bool msaa_upload_copies_stencil = + msaa_upload_is_depth && (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 && + runtime->device.IsExtShaderStencilExportSupported(); + const VkImageAspectFlags upload_aspect_mask = + msaa_upload_is_depth + ? (msaa_upload_copies_stencil + ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT + : VK_IMAGE_ASPECT_DEPTH_BIT) + : aspect_mask; ImageInfo temp_info = info; temp_info.num_samples = 1; @@ -1854,10 +1864,10 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, vk::Image temp_image = runtime->memory_allocator.CreateImage(image_ci); scheduler->RequestOutsideRenderPassOperationContext(); - auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); + auto vk_copies = TransformBufferImageCopies(copies, offset, upload_aspect_mask); const VkBuffer src_buffer = buffer; const VkImage temp_vk_image = *temp_image; - const VkImageAspectFlags vk_aspect_mask = aspect_mask; + const VkImageAspectFlags vk_aspect_mask = upload_aspect_mask; scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { @@ -1879,9 +1889,16 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, image_copies.push_back(image_copy); } - runtime->blit_image_helper.CopyMSAA(runtime->render_pass_cache, Handle(), info.format, - temp_vk_image, info.format, info.num_samples, - image_copies, false); + if (msaa_upload_is_depth) { + runtime->blit_image_helper.CopyMSAADepth(runtime->render_pass_cache, Handle(), + info.format, temp_vk_image, info.format, + info.num_samples, image_copies, + msaa_upload_copies_stencil); + } else { + runtime->blit_image_helper.CopyMSAA(runtime->render_pass_cache, Handle(), info.format, + temp_vk_image, info.format, info.num_samples, + image_copies, false); + } initialized = true; runtime->pending_msaa_images.emplace_back(scheduler->CurrentTick(), std::move(temp_image));