From 842b5e0b3ab99b50117269923f25305d6aa7a677 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Tue, 18 Aug 2026 23:03:37 -0400 Subject: [PATCH] [TEST] New MSAA shader for UINT/SINT color --- src/video_core/host_shaders/CMakeLists.txt | 4 + .../convert_msaa_to_non_msaa_sint.frag | 22 + .../convert_msaa_to_non_msaa_uint.frag | 22 + .../convert_non_msaa_to_msaa_sint.frag | 21 + .../convert_non_msaa_to_msaa_uint.frag | 21 + src/video_core/renderer_vulkan/blit_image.cpp | 570 ++++++++++-------- src/video_core/renderer_vulkan/blit_image.h | 11 + .../renderer_vulkan/vk_texture_cache.cpp | 11 +- 8 files changed, 406 insertions(+), 276 deletions(-) create mode 100644 src/video_core/host_shaders/convert_msaa_to_non_msaa_sint.frag create mode 100644 src/video_core/host_shaders/convert_msaa_to_non_msaa_uint.frag create mode 100644 src/video_core/host_shaders/convert_non_msaa_to_msaa_sint.frag create mode 100644 src/video_core/host_shaders/convert_non_msaa_to_msaa_uint.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 35d092c3bc..4ee2c86418 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -33,8 +33,12 @@ set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/convert_float_to_depth.frag ${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.comp ${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.frag + ${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa_sint.frag + ${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa_uint.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_sint.frag + ${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa_uint.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 diff --git a/src/video_core/host_shaders/convert_msaa_to_non_msaa_sint.frag b/src/video_core/host_shaders/convert_msaa_to_non_msaa_sint.frag new file mode 100644 index 0000000000..fedd064cb0 --- /dev/null +++ b/src/video_core/host_shaders/convert_msaa_to_non_msaa_sint.frag @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 450 core + +layout(binding = 0) uniform isampler2DMS msaa_in; + +layout(push_constant) uniform PushConstants { + ivec2 dst_offset; + ivec2 src_offset; + ivec2 scale; +}; + +layout(location = 0) out ivec4 frag_color; + +void main() { + const ivec2 coord = ivec2(gl_FragCoord.xy) - dst_offset + src_offset; + const ivec2 msaa_coord = coord / scale; + const ivec2 sample_offset = coord % scale; + const int sample_id = sample_offset.x + scale.x * sample_offset.y; + frag_color = texelFetch(msaa_in, msaa_coord, sample_id); +} diff --git a/src/video_core/host_shaders/convert_msaa_to_non_msaa_uint.frag b/src/video_core/host_shaders/convert_msaa_to_non_msaa_uint.frag new file mode 100644 index 0000000000..ec692752a0 --- /dev/null +++ b/src/video_core/host_shaders/convert_msaa_to_non_msaa_uint.frag @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 450 core + +layout(binding = 0) uniform usampler2DMS msaa_in; + +layout(push_constant) uniform PushConstants { + ivec2 dst_offset; + ivec2 src_offset; + ivec2 scale; +}; + +layout(location = 0) out uvec4 frag_color; + +void main() { + const ivec2 coord = ivec2(gl_FragCoord.xy) - dst_offset + src_offset; + const ivec2 msaa_coord = coord / scale; + const ivec2 sample_offset = coord % scale; + const int sample_id = sample_offset.x + scale.x * sample_offset.y; + frag_color = texelFetch(msaa_in, msaa_coord, sample_id); +} diff --git a/src/video_core/host_shaders/convert_non_msaa_to_msaa_sint.frag b/src/video_core/host_shaders/convert_non_msaa_to_msaa_sint.frag new file mode 100644 index 0000000000..491c1bf5cc --- /dev/null +++ b/src/video_core/host_shaders/convert_non_msaa_to_msaa_sint.frag @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 450 core + +layout(binding = 0) uniform isampler2D img_in; + +layout(push_constant) uniform PushConstants { + ivec2 dst_offset; + ivec2 src_offset; + ivec2 scale; +}; + +layout(location = 0) out ivec4 frag_color; + +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; + frag_color = texelFetch(img_in, coord, 0); +} diff --git a/src/video_core/host_shaders/convert_non_msaa_to_msaa_uint.frag b/src/video_core/host_shaders/convert_non_msaa_to_msaa_uint.frag new file mode 100644 index 0000000000..08eb0cc843 --- /dev/null +++ b/src/video_core/host_shaders/convert_non_msaa_to_msaa_uint.frag @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 450 core + +layout(binding = 0) uniform usampler2D img_in; + +layout(push_constant) uniform PushConstants { + ivec2 dst_offset; + ivec2 src_offset; + ivec2 scale; +}; + +layout(location = 0) out uvec4 frag_color; + +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; + frag_color = texelFetch(img_in, coord, 0); +} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 482c5d7255..b6d395ebc4 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -22,7 +22,11 @@ #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_msaa_to_non_msaa_sint_frag_spv.h" +#include "video_core/host_shaders/convert_msaa_to_non_msaa_uint_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_sint_frag_spv.h" +#include "video_core/host_shaders/convert_non_msaa_to_msaa_uint_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" @@ -521,8 +525,18 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view) } } +[[nodiscard]] MSAACopyFormatClass FormatClass(VideoCore::Surface::PixelFormat format) { + if (!VideoCore::Surface::IsPixelFormatInteger(format)) { + return MSAACopyFormatClass::Float; + } + if (VideoCore::Surface::IsPixelFormatSignedInteger(format)) { + return MSAACopyFormatClass::SignedInteger; + } + return MSAACopyFormatClass::UnsignedInteger; +} + [[nodiscard]] vk::ImageView MakeMSAACopyView(const vk::Device& device, VkImage image, - VkFormat format, u32 base_level, + VkFormat format, u32 base_level, u32 base_layer, VkImageAspectFlags aspect_mask) { return device.CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -541,7 +555,7 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view) .aspectMask = aspect_mask, .baseMipLevel = base_level, .levelCount = 1, - .baseArrayLayer = 0, + .baseArrayLayer = base_layer, .layerCount = 1, }, }); @@ -618,7 +632,15 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), 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_msaa_to_non_msaa_sint_frag( + BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_SINT_FRAG_SPV)), + convert_msaa_to_non_msaa_uint_frag( + BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_UINT_FRAG_SPV)), convert_non_msaa_to_msaa_frag(BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_FRAG_SPV)), + convert_non_msaa_to_msaa_sint_frag( + BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_SINT_FRAG_SPV)), + convert_non_msaa_to_msaa_uint_frag( + BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_UINT_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( @@ -982,6 +1004,7 @@ void BlitImageHelper::CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_i .renderpass = renderpass, .samples = samples, .msaa_to_non_msaa = msaa_to_non_msaa, + .format_class = FormatClass(dst_format), }; const VkPipeline pipeline = FindOrEmplaceMSAACopyPipeline(key); const VkPipelineLayout layout = *msaa_copy_pipeline_layout; @@ -991,140 +1014,142 @@ void BlitImageHelper::CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_i const VkFormat dst_vk_format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, dst_format).format; 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_COLOR_BIT); - vk::ImageView dst_view = - MakeMSAACopyView(device.GetLogical(), dst_image, dst_vk_format, - 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{ - .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(); - scheduler.Record([this, pipeline, layout, sampler, renderpass, - framebuffer_handle = *framebuffer, src_view_handle = *src_view, - src = src_image, dst = dst_image, render_area, - push_constants](vk::CommandBuffer cmdbuf) { - constexpr VkImageSubresourceRange color_range{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = VK_REMAINING_MIP_LEVELS, - .baseArrayLayer = 0, - .layerCount = VK_REMAINING_ARRAY_LAYERS, + const s32 num_layers = (std::min)(copy.src_subresource.num_layers, + copy.dst_subresource.num_layers); + for (s32 layer = 0; layer < num_layers; ++layer) { + 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_layer + layer), + 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_layer + layer), + 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{ + .offset = dst_offset, + .extent = dst_extent, }; - const std::array pre_barriers{ - VkImageMemoryBarrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + 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(); + scheduler.Record([this, pipeline, layout, sampler, renderpass, + framebuffer_handle = *framebuffer, src_view_handle = *src_view, + src = src_image, dst = dst_image, render_area, + push_constants](vk::CommandBuffer cmdbuf) { + constexpr VkImageSubresourceRange color_range{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .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_COLOR_ATTACHMENT_WRITE_BIT | + 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, + }, + 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, + .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, + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_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, + 0, nullptr, nullptr, pre_barriers); + const VkRenderPassBeginInfo renderpass_bi{ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .pNext = nullptr, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - 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, - }, - VkImageMemoryBarrier{ + .renderPass = renderpass, + .framebuffer = framebuffer_handle, + .renderArea = render_area, + .clearValueCount = 0, + .pClearValues = nullptr, + }; + cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); + const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); + 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_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 = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .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, - }, - }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_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, - 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 = one_texture_descriptor_allocator.Commit(); - 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_COLOR_ATTACHMENT_WRITE_BIT, - .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, - }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | - VK_PIPELINE_STAGE_TRANSFER_BIT, - 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), - }); + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_TRANSFER_BIT, + 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), + }); + } } scheduler.InvalidateState(); } @@ -1598,6 +1623,7 @@ void BlitImageHelper::CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage .renderpass = renderpass, .samples = samples, .msaa_to_non_msaa = false, + .format_class = MSAACopyFormatClass::Float, }; const VkPipeline pipeline = FindOrEmplaceMSAACopyDepthPipeline(key, copy_stencil); const VkPipelineLayout layout = copy_stencil ? *msaa_copy_depth_stencil_pipeline_layout @@ -1613,158 +1639,161 @@ void BlitImageHelper::CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage attachment_aspect |= VK_IMAGE_ASPECT_STENCIL_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 s32 num_layers = (std::min)(copy.src_subresource.num_layers, + copy.dst_subresource.num_layers); + for (s32 layer = 0; layer < num_layers; ++layer) { + 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_layer + layer), + 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), + static_cast(copy.src_subresource.base_layer + layer), + 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), + static_cast(copy.dst_subresource.base_layer + layer), + 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, }; - const std::array pre_barriers{ - VkImageMemoryBarrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + 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, - .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{ + .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 | - VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .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_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) { + }; + 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_stencil_view), - .dst_view = vk::ImageView{}, - .framebuffer = vk::Framebuffer{}, + .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{}, + }); + } } } } @@ -1775,9 +1804,16 @@ 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); + VkShaderModule frag_module = key.msaa_to_non_msaa ? *convert_msaa_to_non_msaa_frag + : *convert_non_msaa_to_msaa_frag; + if (key.format_class == MSAACopyFormatClass::SignedInteger) { + frag_module = key.msaa_to_non_msaa ? *convert_msaa_to_non_msaa_sint_frag + : *convert_non_msaa_to_msaa_sint_frag; + } else if (key.format_class == MSAACopyFormatClass::UnsignedInteger) { + frag_module = key.msaa_to_non_msaa ? *convert_msaa_to_non_msaa_uint_frag + : *convert_non_msaa_to_msaa_uint_frag; + } + const std::array stages = MakeStages(*clear_color_vert, frag_module); const VkPipelineMultisampleStateCreateInfo multisample_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 3b073f2825..66a70c6215 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -45,12 +45,19 @@ struct BlitDepthStencilPipelineKey { u32 stencil_ref; }; +enum class MSAACopyFormatClass : u32 { + Float, + SignedInteger, + UnsignedInteger, +}; + struct MSAACopyPipelineKey { constexpr auto operator<=>(const MSAACopyPipelineKey&) const noexcept = default; VkRenderPass renderpass; VkSampleCountFlagBits samples; bool msaa_to_non_msaa; + MSAACopyFormatClass format_class; }; struct BlitMSAAPipelineKey { @@ -198,7 +205,11 @@ private: vk::ShaderModule convert_d24s8_to_abgr8_frag; vk::ShaderModule convert_s8d24_to_abgr8_frag; vk::ShaderModule convert_msaa_to_non_msaa_frag; + vk::ShaderModule convert_msaa_to_non_msaa_sint_frag; + vk::ShaderModule convert_msaa_to_non_msaa_uint_frag; vk::ShaderModule convert_non_msaa_to_msaa_frag; + vk::ShaderModule convert_non_msaa_to_msaa_sint_frag; + vk::ShaderModule convert_non_msaa_to_msaa_uint_frag; vk::ShaderModule convert_non_msaa_to_msaa_depth_frag; vk::ShaderModule convert_non_msaa_to_msaa_depth_stencil_frag; vk::Sampler linear_sampler; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index b12fab0482..796039be38 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1766,13 +1766,7 @@ u64 TextureCacheRuntime::GetDeviceMemoryUsage() const { } bool TextureCacheRuntime::CanDownloadMsaa(const VideoCommon::ImageInfo& info) const { - if (ImageAspectMask(info.format) != VK_IMAGE_ASPECT_COLOR_BIT) { - return false; - } - if (VideoCore::Surface::IsPixelFormatInteger(info.format)) { - return false; - } - return info.resources.layers == 1; + return ImageAspectMask(info.format) == VK_IMAGE_ASPECT_COLOR_BIT; } bool TextureCacheRuntime::CanReportMemoryUsage() const { @@ -1905,8 +1899,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, 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 || msaa_upload_is_depth) - && !VideoCore::Surface::IsPixelFormatInteger(info.format); + && ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0 || msaa_upload_is_depth); if (wants_msaa_upload) { const bool msaa_upload_copies_stencil =