From 04d08f0cf10ea88416403854726a04ee7a8f2669 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 16 Aug 2026 22:41:06 -0400 Subject: [PATCH] [TEST] Blitting on MSAA --- .../host_shaders/blit_depth_msaa.frag | 2 +- .../host_shaders/blit_depth_stencil_msaa.frag | 4 +- src/video_core/renderer_vulkan/blit_image.cpp | 89 +++++++++++++++++++ src/video_core/renderer_vulkan/blit_image.h | 9 ++ .../renderer_vulkan/vk_texture_cache.cpp | 49 ++++++---- .../vulkan_common/vulkan_device.cpp | 7 -- src/video_core/vulkan_common/vulkan_device.h | 5 -- 7 files changed, 134 insertions(+), 31 deletions(-) diff --git a/src/video_core/host_shaders/blit_depth_msaa.frag b/src/video_core/host_shaders/blit_depth_msaa.frag index 064289ad04..9e955d471e 100644 --- a/src/video_core/host_shaders/blit_depth_msaa.frag +++ b/src/video_core/host_shaders/blit_depth_msaa.frag @@ -8,5 +8,5 @@ layout(binding = 0) uniform sampler2DMS depth_tex; layout(location = 0) in vec2 texcoord; void main() { - gl_FragDepth = texelFetch(depth_tex, ivec2(texcoord), 0).r; + gl_FragDepth = texelFetch(depth_tex, ivec2(texcoord), gl_SampleID).r; } diff --git a/src/video_core/host_shaders/blit_depth_stencil_msaa.frag b/src/video_core/host_shaders/blit_depth_stencil_msaa.frag index d4264f2d14..7d4555bfd4 100644 --- a/src/video_core/host_shaders/blit_depth_stencil_msaa.frag +++ b/src/video_core/host_shaders/blit_depth_stencil_msaa.frag @@ -10,6 +10,6 @@ layout(binding = 1) uniform usampler2DMS stencil_tex; layout(location = 0) in vec2 texcoord; void main() { - gl_FragDepth = texelFetch(depth_tex, ivec2(texcoord), 0).r; - gl_FragStencilRefARB = int(texelFetch(stencil_tex, ivec2(texcoord), 0).r); + gl_FragDepth = texelFetch(depth_tex, ivec2(texcoord), gl_SampleID).r; + gl_FragStencilRefARB = int(texelFetch(stencil_tex, ivec2(texcoord), gl_SampleID).r); } diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index c4560177b8..d0d64d936a 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -710,6 +710,46 @@ void BlitImageHelper::BlitColorMSAA(const Framebuffer* dst_framebuffer, scheduler.InvalidateState(); } +void BlitImageHelper::BlitDepthStencilMSAA(const Framebuffer* dst_framebuffer, + ImageView& src_image_view, const Region2D& dst_region, + const Region2D& src_region) { + const bool blit_stencil = + dst_framebuffer->HasAspectStencilBit() && device.IsExtShaderStencilExportSupported(); + const BlitMSAAPipelineKey key{ + .renderpass = dst_framebuffer->RenderPass(), + .samples = dst_framebuffer->Samples(), + }; + const VkPipeline pipeline = FindOrEmplaceBlitDepthStencilMSAAPipeline(key, blit_stencil); + const VkPipelineLayout layout = + blit_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout; + const VkSampler sampler = *nearest_sampler; + const VkImageView src_depth_view = src_image_view.DepthView(); + const VkImageView src_stencil_view = + blit_stencil ? src_image_view.StencilView() : VK_NULL_HANDLE; + + RecordShaderReadBarrier(scheduler, src_image_view); + scheduler.RequestRenderpass(dst_framebuffer); + scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler, src_depth_view, + src_stencil_view, blit_stencil](vk::CommandBuffer cmdbuf) { + if (blit_stencil) { + const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit(); + UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, + src_stencil_view); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, + nullptr); + } else { + const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); + UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_depth_view); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, + nullptr); + } + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + BindBlitState(cmdbuf, layout, dst_region, src_region); + cmdbuf.Draw(3, 1, 0, 0); + }); + scheduler.InvalidateState(); +} + void BlitImageHelper::ResolveDepthStencil(const Framebuffer* dst_framebuffer, ImageView& src_image_view, const Region2D& dst_region, const Region2D& src_region) { @@ -1394,6 +1434,55 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip return *blit_msaa_color_pipelines.back(); } +VkPipeline BlitImageHelper::FindOrEmplaceBlitDepthStencilMSAAPipeline( + const BlitMSAAPipelineKey& key, bool blit_stencil) { + auto& keys = blit_stencil ? blit_msaa_depth_stencil_keys : blit_msaa_depth_keys; + auto& pipelines = blit_stencil ? blit_msaa_depth_stencil_pipelines : blit_msaa_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(*full_screen_vert, + blit_stencil ? *blit_depth_stencil_msaa_frag : *blit_depth_msaa_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, + }; + 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 = blit_stencil ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO + : &PIPELINE_DEPTH_ONLY_STATE_CREATE_INFO, + .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, + .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .layout = blit_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout, + .renderPass = key.renderpass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = 0, + }, device.StaticPipelineCache())); + return *pipelines.back(); +} + VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass, bool resolve_stencil) { auto& keys = resolve_stencil ? resolve_depth_stencil_keys : resolve_depth_keys; diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 3e6c2b09dd..0ff73064a1 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -78,6 +78,9 @@ public: void BlitColorMSAA(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, const Region2D& dst_region, const Region2D& src_region); + void BlitDepthStencilMSAA(const Framebuffer* dst_framebuffer, ImageView& src_image_view, + const Region2D& dst_region, const Region2D& src_region); + void ResolveDepthStencil(const Framebuffer* dst_framebuffer, ImageView& src_image_view, const Region2D& dst_region, const Region2D& src_region); @@ -140,6 +143,8 @@ private: [[nodiscard]] VkPipeline FindOrEmplaceMSAACopyDepthPipeline(const MSAACopyPipelineKey& key, bool copy_stencil); [[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key); + [[nodiscard]] VkPipeline FindOrEmplaceBlitDepthStencilMSAAPipeline( + const BlitMSAAPipelineKey& key, bool blit_stencil); [[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass, bool resolve_stencil); @@ -210,6 +215,10 @@ private: std::vector msaa_copy_depth_stencil_pipelines; std::vector blit_msaa_color_keys; std::vector blit_msaa_color_pipelines; + std::vector blit_msaa_depth_keys; + std::vector blit_msaa_depth_pipelines; + std::vector blit_msaa_depth_stencil_keys; + std::vector blit_msaa_depth_stencil_pipelines; std::vector resolve_depth_keys; std::vector resolve_depth_pipelines; std::vector resolve_depth_stencil_keys; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 2e37a99497..bfac4c5071 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -682,6 +682,11 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im }; } +[[nodiscard]] bool HaveSameExtent(const Region2D& dst_region, const Region2D& src_region) { + return dst_region.end.x - dst_region.start.x == src_region.end.x - src_region.start.x && + dst_region.end.y - dst_region.start.y == src_region.end.y - src_region.start.y; +} + [[nodiscard]] VkImageResolve MakeImageResolve(const Region2D& dst_region, const Region2D& src_region, const VkImageSubresourceLayers& dst_layers, @@ -779,15 +784,15 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d, vk_filter, up_scaling](vk::CommandBuffer cmdbuf) { + const u32 scaled_width = resolution.ScaleUp(extent.width); + const u32 scaled_height = is_2d ? resolution.ScaleUp(extent.height) : extent.height; const VkOffset2D src_size{ - .x = static_cast(up_scaling ? extent.width : resolution.ScaleUp(extent.width)), - .y = static_cast(is_2d && up_scaling ? extent.height - : resolution.ScaleUp(extent.height)), + .x = static_cast(up_scaling ? extent.width : scaled_width), + .y = static_cast(up_scaling ? extent.height : scaled_height), }; const VkOffset2D dst_size{ - .x = static_cast(up_scaling ? resolution.ScaleUp(extent.width) : extent.width), - .y = static_cast(is_2d && up_scaling ? resolution.ScaleUp(extent.height) - : extent.height), + .x = static_cast(up_scaling ? scaled_width : extent.width), + .y = static_cast(up_scaling ? scaled_height : extent.height), }; boost::container::small_vector regions; regions.reserve(resources.levels); @@ -1286,8 +1291,14 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst blit_image_helper.BlitColorMSAA(dst_framebuffer, src, dst_region, src_region); return; } - if (is_msaa_to_msaa && device.CantBlitMSAA()) { - UNIMPLEMENTED_MSG("MSAA to MSAA depth-stencil blit is not supported on this driver"); + if (is_msaa_to_msaa) { + blit_image_helper.BlitDepthStencilMSAA(dst_framebuffer, src, dst_region, src_region); + return; + } + + const bool is_resolve = is_src_msaa && !is_dst_msaa; + if (is_resolve && !HaveSameExtent(dst_region, src_region)) { + blit_image_helper.BlitColorMSAA(dst_framebuffer, src, dst_region, src_region); return; } @@ -1295,7 +1306,6 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst const VkImage src_image = src.ImageHandle(); const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst); const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src); - const bool is_resolve = is_src_msaa && !is_dst_msaa; scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers, aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) { @@ -2335,12 +2345,21 @@ bool Image::BlitScaleHelper(bool scale_up) { runtime->blit_image_helper.BlitColor(&*blit_framebuffer, *blit_view, dst_region, src_region, operation, BLIT_OPERATION); } - } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) && - info.num_samples == 1) { + } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (!blit_framebuffer) blit_framebuffer.emplace(*runtime, nullptr, view_ptr, extent, scale_up); - runtime->blit_image_helper.BlitDepthStencil(&*blit_framebuffer, *blit_view, - dst_region, src_region, operation, BLIT_OPERATION); + if (info.num_samples > 1) { + runtime->blit_image_helper.BlitDepthStencilMSAA(&*blit_framebuffer, *blit_view, + dst_region, src_region); + } else { + runtime->blit_image_helper.BlitDepthStencil(&*blit_framebuffer, *blit_view, + dst_region, src_region, operation, BLIT_OPERATION); + } + } else if (aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT && info.num_samples > 1) { + if (!blit_framebuffer) + blit_framebuffer.emplace(*runtime, nullptr, view_ptr, extent, scale_up); + runtime->blit_image_helper.BlitDepthStencilMSAA(&*blit_framebuffer, *blit_view, dst_region, + src_region); } else { // TODO: Use helper blits where applicable flags &= ~ImageFlagBits::Rescaled; @@ -2352,9 +2371,7 @@ bool Image::BlitScaleHelper(bool scale_up) { bool Image::NeedsScaleHelper() const { const auto& device = runtime->device; - const bool needs_msaa_helper = info.num_samples > 1 && - (device.CantBlitMSAA() || aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT); - if (needs_msaa_helper) { + if (info.num_samples > 1) { return true; } static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 092d985f4f..4d9d9f7d28 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -659,13 +659,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR features.shader_float16_int8.shaderFloat16 = false; } - if (is_intel_windows) { - LOG_WARNING(Render_Vulkan, - "Intel proprietary drivers do not support MSAA->MSAA image blits. " - "MSAA scaling will use 3D helpers. MSAA resolves work normally."); - cant_blit_msaa = true; - } - has_broken_compute = CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) && !Settings::values.enable_compute_pipelines.GetValue(); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 7e40f8eeb6..a271c11319 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -955,10 +955,6 @@ FN_MAX_LIMIT_LIST return supports_d24_depth; } - bool CantBlitMSAA() const { - return cant_blit_msaa; - } - bool MustEmulateScaledFormats() const { return must_emulate_scaled_formats; } @@ -1230,7 +1226,6 @@ private: bool has_nsight_graphics{}; ///< Has Nsight Graphics attached bool has_radeon_gpu_profiler{}; ///< Has Radeon GPU Profiler attached. bool supports_d24_depth{}; ///< Supports D24 depth buffers. - bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. bool must_emulate_scaled_formats{}; ///< Requires scaled vertex format emulation bool dynamic_state3_blending{}; ///< Has blending features of dynamic_state3. bool dynamic_state3_enables{}; ///< Has at least one enable feature of dynamic_state3.