diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 60e147a5ed..741f424401 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -107,6 +107,9 @@ void Scheduler::BeginDynamicRendering(const Framebuffer* framebuffer, const Defe state.attachment_views = attachment_views; state.color_resolve_views = framebuffer->ColorResolveAttachments(); state.color_resolve_modes = framebuffer->ColorResolveModes(); + state.depth_resolve_view = framebuffer->DepthResolveAttachment(); + state.depth_resolve_mode = framebuffer->DepthResolveMode(); + state.stencil_resolve_mode = framebuffer->StencilResolveMode(); state.discards_msaa_color = framebuffer->DiscardsMsaaColor(); state.discards_msaa_depth = framebuffer->DiscardsMsaaDepth(); state.render_area = render_area; @@ -453,9 +456,13 @@ void Scheduler::RecordDynamicBegin(const DeferredClear* clear) { const bool ds_clear = clear != nullptr && clear->depth_stencil; const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{}; const bool ds_discard = state.discards_msaa_depth; + const VkImageView ds_resolve_view = state.depth_resolve_view; + const VkResolveModeFlagBits depth_resolve_mode = state.depth_resolve_mode; + const VkResolveModeFlagBits stencil_resolve_mode = state.stencil_resolve_mode; Record([views, resolve_views, resolve_modes, num_color, has_depth, has_stencil, layers, render_area, color_clear_mask, color_discard_mask, color_clear_values, ds_clear, - ds_clear_value, ds_discard](vk::CommandBuffer cmdbuf) { + ds_clear_value, ds_discard, ds_resolve_view, depth_resolve_mode, + stencil_resolve_mode](vk::CommandBuffer cmdbuf) { std::array color_infos{}; for (u32 index = 0; index < num_color; ++index) { const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0; @@ -477,17 +484,37 @@ void Scheduler::RecordDynamicBegin(const DeferredClear* clear) { .clearValue = clear_slot ? color_clear_values[index] : VkClearValue{}, }; } + const bool has_ds_resolve = ds_resolve_view != VK_NULL_HANDLE; + const VkAttachmentLoadOp ds_load_op = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR + : ds_discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE + : VK_ATTACHMENT_LOAD_OP_LOAD; + const VkAttachmentStoreOp ds_store_op = + ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; const VkRenderingAttachmentInfo depth_info{ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .pNext = nullptr, .imageView = views[8], .imageLayout = VK_IMAGE_LAYOUT_GENERAL, - .resolveMode = VK_RESOLVE_MODE_NONE, - .resolveImageView = VK_NULL_HANDLE, - .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .loadOp = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, - .storeOp = ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE - : VK_ATTACHMENT_STORE_OP_STORE, + .resolveMode = has_ds_resolve ? depth_resolve_mode : VK_RESOLVE_MODE_NONE, + .resolveImageView = has_ds_resolve ? ds_resolve_view : VK_NULL_HANDLE, + .resolveImageLayout = + has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, + .loadOp = ds_load_op, + .storeOp = ds_store_op, + .clearValue = ds_clear ? ds_clear_value : VkClearValue{}, + }; + // Stencil gets its own struct because its resolve mode may differ from depth's. + const VkRenderingAttachmentInfo stencil_info{ + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .pNext = nullptr, + .imageView = views[8], + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + .resolveMode = has_ds_resolve ? stencil_resolve_mode : VK_RESOLVE_MODE_NONE, + .resolveImageView = has_ds_resolve ? ds_resolve_view : VK_NULL_HANDLE, + .resolveImageLayout = + has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, + .loadOp = ds_load_op, + .storeOp = ds_store_op, .clearValue = ds_clear ? ds_clear_value : VkClearValue{}, }; const VkRenderingInfo rendering_info{ @@ -504,7 +531,7 @@ void Scheduler::RecordDynamicBegin(const DeferredClear* clear) { .colorAttachmentCount = num_color, .pColorAttachments = color_infos.data(), .pDepthAttachment = has_depth ? &depth_info : nullptr, - .pStencilAttachment = has_stencil ? &depth_info : nullptr, + .pStencilAttachment = has_stencil ? &stencil_info : nullptr, }; cmdbuf.BeginRendering(rendering_info); }); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index c4a3107c60..3732fc6171 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -270,6 +270,9 @@ private: std::array attachment_views{}; std::array color_resolve_views{}; std::array color_resolve_modes{}; + VkImageView depth_resolve_view{}; + VkResolveModeFlagBits depth_resolve_mode = VK_RESOLVE_MODE_NONE; + VkResolveModeFlagBits stencil_resolve_mode = VK_RESOLVE_MODE_NONE; VkExtent2D render_area = {0, 0}; GraphicsPipeline* graphics_pipeline = nullptr; bool rendering = false; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 5ee6d1fd9d..81a48ba48c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1005,7 +1005,10 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { } VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format, - VkExtent2D extent, u32 layers) { + VkExtent2D extent, u32 layers, + VkImageAspectFlags aspect) { + const bool is_depth_stencil = + (aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0; ResolveShadow& shadow = resolve_shadows[msaa_image]; if (shadow.image && shadow.format == format && shadow.extent.width == extent.width && shadow.extent.height == extent.height && shadow.layers == layers) { @@ -1023,8 +1026,9 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk .arrayLayers = layers, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .usage = (is_depth_stencil ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, @@ -1039,7 +1043,7 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk .format = format, .components{}, .subresourceRange{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .aspectMask = aspect, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, @@ -1052,28 +1056,33 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk shadow.up_to_date = true; if (device.IsKhrDynamicRenderingSupported()) { scheduler.RecordWithUploadBuffer( - [image = *shadow.image, layers](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) { + [image = *shadow.image, layers, aspect, is_depth_stencil]( + vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) { const VkImageMemoryBarrier barrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, .srcAccessMask = 0, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = is_depth_stencil + ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT + : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_GENERAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = image, .subresourceRange{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .aspectMask = aspect, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = layers, }, }; - upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, - barrier); + upload_cmdbuf.PipelineBarrier( + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + is_depth_stencil ? VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT + : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + 0, barrier); }); } return *shadow.view; @@ -1668,18 +1677,6 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, std::span copies) { const bool msaa_to_non_msaa = src.info.num_samples > 1 && dst.info.num_samples == 1; const u32 num_samples = msaa_to_non_msaa ? src.info.num_samples : dst.info.num_samples; - if (dst.AspectMask() != VK_IMAGE_ASPECT_COLOR_BIT || - VideoCore::Surface::IsPixelFormatInteger(dst.info.format)) { - const u64 key{(static_cast(dst.AspectMask()) << 32) | - static_cast(dst.info.format)}; - if (unsupported_msaa_resolves.insert(key).second) { - LOG_WARNING(Render_Vulkan, - "MSAA resolve unsupported: format={}, aspect={:#x}, samples {}->{}", - dst.info.format, dst.AspectMask(), src.info.num_samples, - dst.info.num_samples); - } - return; - } if (ENABLE_MSAA_RESOLVE_CONSUME && msaa_to_non_msaa && copies.size() == 1 && src.info.format == dst.info.format) { const VideoCommon::ImageCopy& copy = copies.front(); @@ -1690,16 +1687,19 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, static_cast(copy.extent.height) <= shadow->extent.height) { const VkImage shadow_image = *shadow->image; const VkImage dst_image = dst.Handle(); + const VkImageAspectFlags aspect = dst.AspectMask(); + const bool is_depth_stencil = + (aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0; const VkImageCopy region{ .srcSubresource{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .aspectMask = aspect, .mipLevel = 0, .baseArrayLayer = static_cast(copy.src_subresource.base_layer), .layerCount = static_cast(copy.src_subresource.num_layers), }, .srcOffset = {0, 0, 0}, .dstSubresource{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .aspectMask = aspect, .mipLevel = static_cast(copy.dst_subresource.base_level), .baseArrayLayer = static_cast(copy.dst_subresource.base_layer), .layerCount = static_cast(copy.dst_subresource.num_layers), @@ -1708,34 +1708,38 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, .extent = {copy.extent.width, copy.extent.height, 1}, }; scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([shadow_image, dst_image, region](vk::CommandBuffer cmdbuf) { + scheduler.Record([shadow_image, dst_image, region, aspect, + is_depth_stencil](vk::CommandBuffer cmdbuf) { + const VkAccessFlags attachment_write = + is_depth_stencil ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT + : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; const std::array pre_barriers{ VkImageMemoryBarrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .srcAccessMask = attachment_write, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, .oldLayout = VK_IMAGE_LAYOUT_GENERAL, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = shadow_image, - .subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, + .subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, }, VkImageMemoryBarrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, - .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_TRANSFER_WRITE_BIT, + .srcAccessMask = + VK_ACCESS_SHADER_WRITE_BIT | attachment_write | + VK_ACCESS_TRANSFER_WRITE_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_GENERAL, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = dst_image, - .subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, + .subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, }, }; @@ -1750,7 +1754,7 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = shadow_image, - .subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, + .subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, }, VkImageMemoryBarrier{ @@ -1760,17 +1764,20 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_GENERAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = dst_image, - .subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, + .subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, }, }; cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, nullptr, nullptr, pre_barriers); @@ -1783,6 +1790,18 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, return; } } + if (dst.AspectMask() != VK_IMAGE_ASPECT_COLOR_BIT || + VideoCore::Surface::IsPixelFormatInteger(dst.info.format)) { + const u64 key{(static_cast(dst.AspectMask()) << 32) | + static_cast(dst.info.format)}; + if (unsupported_msaa_resolves.insert(key).second) { + LOG_WARNING(Render_Vulkan, + "MSAA resolve unsupported: format={}, aspect={:#x}, samples {}->{}", + dst.info.format, dst.AspectMask(), src.info.num_samples, + dst.info.num_samples); + } + return; + } blit_image_helper.CopyMSAA(render_pass_cache, dst.Handle(), dst.info.format, src.Handle(), src.info.format, num_samples, copies, msaa_to_non_msaa); } @@ -2806,10 +2825,21 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0 && runtime.device.IsTiler(); renderpass_key.resolve_color = do_resolve_color; + const VkResolveModeFlagBits depth_mode = runtime.device.GetDepthResolveMode(); + const VkResolveModeFlagBits stencil_mode = runtime.device.GetStencilResolveMode(); + const bool resolve_modes_compatible = + depth_mode != VK_RESOLVE_MODE_NONE && + (!has_stencil || (stencil_mode != VK_RESOLVE_MODE_NONE && + (runtime.device.IsIndependentResolveSupported() || + depth_mode == stencil_mode))); + const bool do_resolve_depth = + samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler() && + runtime.device.IsKhrDynamicRenderingSupported() && resolve_modes_compatible; + discard_msaa_color = ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color; - discard_msaa_depth = ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD && - samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler(); + discard_msaa_depth = + ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD && do_resolve_depth; render_pass_key = renderpass_key; render_pass_cache = &runtime.render_pass_cache; @@ -2831,7 +2861,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, if (ENABLE_MSAA_RESOLVE_CONSUME) { const VkImage msaa_image = images[rt_map[index]]; const VkImageView shadow_view = runtime.GetOrCreateResolveShadow( - msaa_image, vk_format, render_area, layers); + msaa_image, vk_format, render_area, layers, VK_IMAGE_ASPECT_COLOR_BIT); color_resolve_attachments[index] = shadow_view; attachments.push_back(shadow_view); continue; @@ -2905,6 +2935,22 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, } } + if (do_resolve_depth && depth_buffer != nullptr) { + const u32 layers = static_cast((std::max)(num_layers, 1)); + VkImageAspectFlags aspect = 0; + if (has_depth) { + aspect |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + if (has_stencil) { + aspect |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + depth_resolve_attachment = + runtime.GetOrCreateResolveShadow(depth_buffer->ImageHandle(), depth_attachment_format, + render_area, layers, aspect); + depth_resolve_mode = depth_mode; + stencil_resolve_mode = has_stencil ? stencil_mode : VK_RESOLVE_MODE_NONE; + } + num_color_buffers = static_cast(num_colors); layer_count = static_cast((std::max)(num_layers, 1)); if (runtime.device.IsKhrDynamicRenderingSupported()) { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index f7267ba098..dd13aee53b 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -133,7 +133,8 @@ public: }; [[nodiscard]] VkImageView GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format, - VkExtent2D extent, u32 layers); + VkExtent2D extent, u32 layers, + VkImageAspectFlags aspect); [[nodiscard]] const ResolveShadow* GetValidResolveShadow(VkImage msaa_image) const; @@ -233,6 +234,18 @@ public: return depth_attachment; } + [[nodiscard]] VkImageView DepthResolveAttachment() const noexcept { + return depth_resolve_attachment; + } + + [[nodiscard]] VkResolveModeFlagBits DepthResolveMode() const noexcept { + return depth_resolve_mode; + } + + [[nodiscard]] VkResolveModeFlagBits StencilResolveMode() const noexcept { + return stencil_resolve_mode; + } + [[nodiscard]] VkFormat DepthAttachmentFormat() const noexcept { return depth_attachment_format; } @@ -312,6 +325,9 @@ private: std::array color_resolve_attachments{}; std::array color_resolve_modes{}; VkImageView depth_attachment{}; + VkImageView depth_resolve_attachment{}; + VkResolveModeFlagBits depth_resolve_mode = VK_RESOLVE_MODE_NONE; + VkResolveModeFlagBits stencil_resolve_mode = VK_RESOLVE_MODE_NONE; VkFormat depth_attachment_format = VK_FORMAT_UNDEFINED; u32 num_color_attachments = 0; u32 layer_count = 1; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 55e8ce5bd1..4e8e23e6d2 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1120,6 +1120,11 @@ bool Device::GetSuitability(bool requires_swapchain) { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR; SetNext(next, properties.maintenance5); } + if (instance_version >= VK_API_VERSION_1_2) { + properties.depth_stencil_resolve.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES; + SetNext(next, properties.depth_stencil_resolve); + } // Perform the property fetch. physical.GetProperties2(properties2); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 1a5a0a0ab9..4d12a73901 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -1006,6 +1006,26 @@ FN_MAX_LIMIT_LIST return ENABLE_DYNAMIC_RENDERING && extensions.dynamic_rendering; } + /// Returns the resolve mode to use for multisampled depth. + VkResolveModeFlagBits GetDepthResolveMode() const { + return PickResolveMode(properties.depth_stencil_resolve.supportedDepthResolveModes); + } + + /// Same as GetDepthResolveMode, for the stencil aspect. + VkResolveModeFlagBits GetStencilResolveMode() const { + return PickResolveMode(properties.depth_stencil_resolve.supportedStencilResolveModes); + } + + /// Returns true if depth and stencil may resolve with independent modes. + bool IsIndependentResolveSupported() const { + return properties.depth_stencil_resolve.independentResolve == VK_TRUE; + } + + /// Returns true if one aspect may resolve while the other does not. + bool IsIndependentResolveNoneSupported() const { + return properties.depth_stencil_resolve.independentResolveNone == VK_TRUE; + } + /// Returns true if the device supports VK_KHR_maintenance4. bool IsKhrMaintenance4Supported() const { return extensions.maintenance4; @@ -1087,6 +1107,22 @@ FN_MAX_LIMIT_LIST void ShutdownGPULogging(); private: + /// Picks a usable resolve mode out of a supported-modes mask. SAMPLE_ZERO is preferred because + /// it is the only mode the spec guarantees whenever any depth/stencil resolve is supported, + /// and averaging depth samples is not meaningful for depth testing anyway. + static VkResolveModeFlagBits PickResolveMode(VkResolveModeFlags supported) { + if ((supported & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) { + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; + } + if ((supported & VK_RESOLVE_MODE_MIN_BIT) != 0) { + return VK_RESOLVE_MODE_MIN_BIT; + } + if ((supported & VK_RESOLVE_MODE_MAX_BIT) != 0) { + return VK_RESOLVE_MODE_MAX_BIT; + } + return VK_RESOLVE_MODE_NONE; + } + /// Checks if the physical device is suitable and configures the object state /// with all necessary info about its properties. bool GetSuitability(bool requires_swapchain); @@ -1176,6 +1212,7 @@ private: VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{}; VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{}; + VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve{}; VkPhysicalDeviceProperties properties{}; };