diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 27b466876..07d76a928 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -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..a3a515364 --- /dev/null +++ b/src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_ms.comp @@ -0,0 +1,31 @@ +// Copyright 2023 Citra 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 4af2f0acc..8bed843a1 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_helper.cpp @@ -11,6 +11,7 @@ #include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_comp_spv.h" +#include "video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_ms_comp_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" #include "video_core/host_shaders/vulkan_depth_to_buffer_comp_spv.h" @@ -191,9 +192,12 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, Descrip device.createPipelineLayout(PipelineLayoutCreateInfo(&two_textures_provider.Layout()))}, full_screen_vert{CompileSPV(FULL_SCREEN_TRIANGLE_VERT_SPV, device)}, d24s8_to_rgba8_comp{CompileSPV(VULKAN_D24S8_TO_RGBA8_COMP_SPV, device)}, + d24s8_to_rgba8_ms_comp{CompileSPV(VULKAN_D24S8_TO_RGBA8_COMP_SPV, device)}, depth_to_buffer_comp{CompileSPV(VULKAN_DEPTH_TO_BUFFER_COMP_SPV, device)}, blit_depth_stencil_frag{CompileSPV(VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV, 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{MakeDepthStencilBlitPipeline()}, @@ -230,6 +234,7 @@ BlitHelper::~BlitHelper() { device.destroyShaderModule(blit_depth_stencil_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); @@ -332,10 +337,18 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest, .imageLayout = vk::ImageLayout::eGeneral, }; + if (dest.sample_count != source.sample_count) { + LOG_ERROR(Render_Vulkan, "Trying to bit DS24S8->RGBA8 with different sample counts"); + return false; + } + + const bool multisample = (source.sample_count > 1) && (dest.sample_count > 1); + const auto descriptor_set = compute_provider.Acquire(textures); + const auto pipeline = multisample ? d24s8_to_rgba8_ms_pipeline : d24s8_to_rgba8_pipeline; 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{ @@ -414,7 +427,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 8060a225b..cc31d695d 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.h +++ b/src/video_core/renderer_vulkan/vk_blit_helper.h @@ -55,10 +55,12 @@ 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::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;