From a0eea7bb4d79125b0e62315425702f5f88217a50 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Sat, 18 Apr 2026 21:08:24 -0700 Subject: [PATCH] vk_blit_helper: Add `d24s8_to_rgba8_ms_comp` Helper host-shader for blitting multi-sampled DS24S8 textures to multi-sampled RGBA8 --- src/video_core/host_shaders/CMakeLists.txt | 3 +- .../vulkan_d24s8_to_rgba8_ms.comp | 31 +++++++++++++++++++ .../renderer_vulkan/vk_blit_helper.cpp | 24 +++++++++++--- .../renderer_vulkan/vk_blit_helper.h | 2 ++ 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_ms.comp diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 964000d92..8018a9c55 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2023 Citra Emulator Project +# Copyright Citra Emulator Project / Azahar Emulator Project # Licensed under GPLv2 or any later version # Refer to the license.txt file included. @@ -6,6 +6,7 @@ set(SHADER_FILES format_reinterpreter/d24s8_to_rgba8.frag format_reinterpreter/rgba4_to_rgb5a1.frag format_reinterpreter/vulkan_d24s8_to_rgba8.comp + format_reinterpreter/vulkan_d24s8_to_rgba8_ms.comp texture_filtering/bicubic.frag texture_filtering/refine.frag texture_filtering/scale_force.frag diff --git a/src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_ms.comp b/src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_ms.comp new file mode 100644 index 000000000..3dca7c91e --- /dev/null +++ b/src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_ms.comp @@ -0,0 +1,31 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core +#extension GL_EXT_samplerless_texture_functions : require + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +layout(set = 0, binding = 0) uniform highp texture2DMS depth; +layout(set = 0, binding = 1) uniform lowp utexture2DMS stencil; +layout(set = 0, binding = 2, rgba8) uniform highp writeonly image2DMS color; + +layout(push_constant, std140) uniform ComputeInfo { + mediump ivec2 src_offset; + mediump ivec2 dst_offset; + mediump ivec2 extent; +}; + +void main() { + int sample_count = textureSamples(depth); + + ivec2 src_coord = src_offset + ivec2(gl_GlobalInvocationID.xy); + ivec2 dst_coord = dst_offset + ivec2(gl_GlobalInvocationID.xy); + for(int sample_index = 0; sample_index < sample_count; ++sample_index) + { + highp uint depth_val = uint(texelFetch(depth, src_coord, sample_index).x * (exp2(32.0) - 1.0)); + lowp uint stencil_val = texelFetch(stencil, src_coord, sample_index).x; + highp uvec4 components = uvec4(stencil_val, (uvec3(depth_val) >> uvec3(24u, 16u, 8u)) & 0x000000FFu); + imageStore(color, dst_coord, sample_index, vec4(components) / (exp2(8.0) - 1.0)); + } +} diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.cpp b/src/video_core/renderer_vulkan/vk_blit_helper.cpp index 9982948b3..7903d671d 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_helper.cpp @@ -14,6 +14,7 @@ #include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_comp.h" +#include "video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_ms_comp.h" #include "video_core/host_shaders/full_screen_triangle_vert.h" #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag.h" #include "video_core/host_shaders/vulkan_depth_to_buffer_comp.h" @@ -248,6 +249,8 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, vk::ShaderStageFlagBits::eVertex, device)}, d24s8_to_rgba8_comp{Compile(HostShaders::VULKAN_D24S8_TO_RGBA8_COMP, vk::ShaderStageFlagBits::eCompute, device)}, + d24s8_to_rgba8_ms_comp{Compile(HostShaders::VULKAN_D24S8_TO_RGBA8_MS_COMP, + vk::ShaderStageFlagBits::eCompute, device)}, depth_to_buffer_comp{Compile(HostShaders::VULKAN_DEPTH_TO_BUFFER_COMP, vk::ShaderStageFlagBits::eCompute, device)}, blit_depth_stencil_frag{VK_NULL_HANDLE}, @@ -260,6 +263,8 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, mmpx_frag{Compile(HostShaders::MMPX_FRAG, vk::ShaderStageFlagBits::eFragment, device)}, refine_frag{Compile(HostShaders::REFINE_FRAG, vk::ShaderStageFlagBits::eFragment, device)}, d24s8_to_rgba8_pipeline{MakeComputePipeline(d24s8_to_rgba8_comp, compute_pipeline_layout)}, + d24s8_to_rgba8_ms_pipeline{ + MakeComputePipeline(d24s8_to_rgba8_ms_comp, compute_pipeline_layout)}, depth_to_buffer_pipeline{ MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)}, depth_blit_pipeline{VK_NULL_HANDLE}, @@ -289,6 +294,7 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, SetObjectName(device, blit_depth_stencil_frag, "BlitHelper: blit_depth_stencil_frag"); } SetObjectName(device, d24s8_to_rgba8_pipeline, "BlitHelper: d24s8_to_rgba8_pipeline"); + SetObjectName(device, d24s8_to_rgba8_ms_pipeline, "BlitHelper: d24s8_to_rgba8_ms_pipeline"); SetObjectName(device, depth_to_buffer_pipeline, "BlitHelper: depth_to_buffer_pipeline"); if (depth_blit_pipeline) { SetObjectName(device, depth_blit_pipeline, "BlitHelper: depth_blit_pipeline"); @@ -322,6 +328,7 @@ BlitHelper::~BlitHelper() { device.destroyShaderModule(refine_frag); device.destroyPipeline(depth_to_buffer_pipeline); device.destroyPipeline(d24s8_to_rgba8_pipeline); + device.destroyPipeline(d24s8_to_rgba8_ms_pipeline); device.destroyPipeline(depth_blit_pipeline); device.destroySampler(linear_sampler); device.destroySampler(nearest_sampler); @@ -401,15 +408,22 @@ bool BlitHelper::BlitDepthStencil(Surface& source, Surface& dest, bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy) { + + const bool multisample = (source.sample_count > 1) && (dest.sample_count > 1); + const Type src_type = multisample ? Type::MultiSampled : Type::Current; + const auto pipeline = multisample ? d24s8_to_rgba8_ms_pipeline : d24s8_to_rgba8_pipeline; + const auto descriptor_set = compute_provider.Commit(); - update_queue.AddImageSampler(descriptor_set, 0, 0, source.DepthView(), VK_NULL_HANDLE, - vk::ImageLayout::eDepthStencilReadOnlyOptimal); - update_queue.AddImageSampler(descriptor_set, 1, 0, source.StencilView(), VK_NULL_HANDLE, + update_queue.AddImageSampler(descriptor_set, 0, 0, source.ImageView(ViewType::Depth, src_type), + VK_NULL_HANDLE, vk::ImageLayout::eDepthStencilReadOnlyOptimal); + update_queue.AddImageSampler(descriptor_set, 1, 0, + source.ImageView(ViewType::Stencil, src_type), VK_NULL_HANDLE, vk::ImageLayout::eDepthStencilReadOnlyOptimal); update_queue.AddStorageImage(descriptor_set, 2, dest.ImageView()); renderpass_cache.EndRendering(); - scheduler.Record([this, descriptor_set, copy, src_image = source.Image(), + + scheduler.Record([this, pipeline, descriptor_set, copy, src_image = source.Image(), dst_image = dest.Image()](vk::CommandBuffer cmdbuf) { const std::array pre_barriers = { vk::ImageMemoryBarrier{ @@ -488,7 +502,7 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest, cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, 0, descriptor_set, {}); - cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, d24s8_to_rgba8_pipeline); + cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline); const ComputeInfo info = { .src_offset = Common::Vec2i{static_cast(copy.src_offset.x), diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.h b/src/video_core/renderer_vulkan/vk_blit_helper.h index 59aee655f..16e0090b0 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.h +++ b/src/video_core/renderer_vulkan/vk_blit_helper.h @@ -83,6 +83,7 @@ private: vk::ShaderModule full_screen_vert; vk::ShaderModule d24s8_to_rgba8_comp; + vk::ShaderModule d24s8_to_rgba8_ms_comp; vk::ShaderModule depth_to_buffer_comp; vk::ShaderModule blit_depth_stencil_frag; vk::ShaderModule bicubic_frag; @@ -92,6 +93,7 @@ private: vk::ShaderModule refine_frag; vk::Pipeline d24s8_to_rgba8_pipeline; + vk::Pipeline d24s8_to_rgba8_ms_pipeline; vk::Pipeline depth_to_buffer_pipeline; vk::Pipeline depth_blit_pipeline; vk::Sampler linear_sampler;