From e003ea641f53152f2ae2a9616e9b79aa9ded52db Mon Sep 17 00:00:00 2001 From: Ribbit Date: Mon, 22 Sep 2025 20:15:04 -0700 Subject: [PATCH] ShaderReadBarrier & VK_EXT_attachment_feedback_loop_layout: Initial Implementation - Track framebuffer images, subresource ranges, and intended layouts in the Vulkan scheduler so render passes enter/leave attachment feedback loop layouts correctly - Surface VK_EXT_attachment_feedback_loop_layout through device feature filtering, render-pass construction, pipeline create flags, image usage bits, and descriptor/image layout selection - Teach the texture cache runtime to tag render targets with their feedback layouts, expose the runtime to descriptor helpers, and skip legacy feedback barriers when the extension is active - Add shader read barriers and generalized layout transitions to blit/conversion paths so recently written attachments can be safely sampled or converted by subsequent shaders --- src/video_core/renderer_vulkan/blit_image.cpp | 235 ++++++++++++++++-- src/video_core/renderer_vulkan/blit_image.h | 8 +- .../renderer_vulkan/pipeline_helper.h | 47 +++- .../renderer_vulkan/vk_compute_pipeline.cpp | 3 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 18 +- .../renderer_vulkan/vk_render_pass_cache.cpp | 65 +++-- .../renderer_vulkan/vk_scheduler.cpp | 73 +++++- src/video_core/renderer_vulkan/vk_scheduler.h | 2 + .../renderer_vulkan/vk_texture_cache.cpp | 59 ++++- .../renderer_vulkan/vk_texture_cache.h | 6 + .../renderer_vulkan/vk_update_descriptor.h | 13 +- .../texture_cache/texture_cache_base.h | 8 + src/video_core/vulkan_common/vulkan.h | 10 + .../vulkan_common/vulkan_device.cpp | 7 + src/video_core/vulkan_common/vulkan_device.h | 7 + 15 files changed, 491 insertions(+), 70 deletions(-) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 7bfcd6503b..da5d0be80f 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -5,6 +5,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include "video_core/renderer_vulkan/vk_texture_cache.h" @@ -43,9 +44,43 @@ namespace Vulkan { +using VideoCommon::ImageViewFlagBits; using VideoCommon::ImageViewType; +using VideoCommon::SubresourceRange; namespace { + +[[nodiscard]] constexpr VkImageAspectFlags ImageAspectMask(VideoCore::Surface::PixelFormat format) { + using VideoCore::Surface::SurfaceType; + switch (VideoCore::Surface::GetFormatType(format)) { + case SurfaceType::ColorTexture: + return VK_IMAGE_ASPECT_COLOR_BIT; + case SurfaceType::Depth: + return VK_IMAGE_ASPECT_DEPTH_BIT; + case SurfaceType::Stencil: + return VK_IMAGE_ASPECT_STENCIL_BIT; + case SurfaceType::DepthStencil: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + default: + return VkImageAspectFlags{}; + } +} + +[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(const ImageView* image_view) { + SubresourceRange range = image_view->range; + if ((image_view->flags & ImageViewFlagBits::Slice) != ImageViewFlagBits{}) { + range.base.layer = 0; + range.extent.layers = 1; + } + return VkImageSubresourceRange{ + .aspectMask = ImageAspectMask(image_view->format), + .baseMipLevel = static_cast(range.base.level), + .levelCount = static_cast(range.extent.levels), + .baseArrayLayer = static_cast(range.base.layer), + .layerCount = static_cast(range.extent.layers), + }; +} + struct PushConstants { std::array tex_scale; std::array tex_offset; @@ -393,34 +428,128 @@ VkExtent2D GetConversionExtent(const ImageView& src_image_view) { void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL) { - constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}; + constexpr VkAccessFlags access_flags = + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_SHADER_READ_BIT; + constexpr VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + const VkImageSubresourceRange subresource_range{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }; const VkImageMemoryBarrier barrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, - .srcAccessMask = flags, - .dstAccessMask = flags, + .srcAccessMask = access_flags, + .dstAccessMask = access_flags, .oldLayout = source_layout, .newLayout = target_layout, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = image, - .subresourceRange{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, + .subresourceRange = subresource_range, }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - 0, barrier); + cmdbuf.PipelineBarrier(stage_flags, stage_flags, 0, barrier); +} + +void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view) { + const VkImage image = image_view.ImageHandle(); + const VkImageSubresourceRange subresource_range = MakeSubresourceRange(&image_view); + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([image, subresource_range](vk::CommandBuffer cmdbuf) { + const VkImageMemoryBarrier barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_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 = image, + .subresourceRange = subresource_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_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + 0, + barrier); + }); } void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) { const VkRenderPass render_pass = framebuffer->RenderPass(); const VkFramebuffer framebuffer_handle = framebuffer->Handle(); const VkExtent2D render_area = framebuffer->RenderArea(); + const u32 num_images = framebuffer->NumImages(); + + if (num_images > 0) { + std::array barriers{}; + u32 barrier_count = 0; + VkPipelineStageFlags dst_stages = 0; + const auto& images = framebuffer->Images(); + const auto& ranges = framebuffer->ImageRanges(); + const auto& layouts = framebuffer->ImageLayouts(); + + for (u32 i = 0; i < num_images; ++i) { + const VkImageLayout layout = layouts[i]; + if (layout == VK_IMAGE_LAYOUT_GENERAL) { + continue; + } + const VkImageSubresourceRange& range = ranges[i]; + VkAccessFlags dst_access = 0; + VkPipelineStageFlags dst_stage = 0; + if ((range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) { + dst_access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dst_stage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + if ((range.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { + dst_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dst_stage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + } + if (dst_access == 0) { + continue; + } + barriers[barrier_count++] = VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_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, + .dstAccessMask = dst_access, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = images[i], + .subresourceRange = range, + }; + dst_stages |= dst_stage; + } + + if (barrier_count > 0) { + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, dst_stages, 0, {}, {}, + {barriers.data(), barrier_count}); + } + } + const VkRenderPassBeginInfo renderpass_bi{ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .pNext = nullptr, @@ -435,6 +564,60 @@ void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) }; cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); } +void EndRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) { + const u32 num_images = framebuffer->NumImages(); + const auto& images = framebuffer->Images(); + const auto& ranges = framebuffer->ImageRanges(); + const auto& layouts = framebuffer->ImageLayouts(); + + std::array barriers{}; + VkPipelineStageFlags src_stages = 0; + u32 barrier_count = 0; + + for (u32 i = 0; i < num_images; ++i) { + const VkImageSubresourceRange& range = ranges[i]; + const VkImageLayout layout = layouts[i]; + VkAccessFlags src_access = 0; + VkPipelineStageFlags stage = 0; + if ((range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) { + src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + stage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + if ((range.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { + src_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + stage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + } + if (stage == 0) { + continue; + } + src_stages |= stage; + barriers[barrier_count++] = VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = src_access, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_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 = layout, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = images[i], + .subresourceRange = range, + }; + } + + cmdbuf.EndRenderPass(); + + if (barrier_count > 0) { + cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, {}, {}, + {barriers.data(), barrier_count}); + } +} + } // Anonymous namespace BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, @@ -484,7 +667,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, BlitImageHelper::~BlitImageHelper() = default; -void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_view, +void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { @@ -496,10 +679,13 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView const VkPipelineLayout layout = *one_texture_pipeline_layout; const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler; const VkPipeline pipeline = FindOrEmplaceColorPipeline(key); + const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D); + + RecordShaderReadBarrier(scheduler, src_image_view); + scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler, src_view](vk::CommandBuffer cmdbuf) { - // TODO: Barriers const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); @@ -524,7 +710,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region, src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) { - TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_GENERAL); BeginRenderPass(cmdbuf, dst_framebuffer); const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view); @@ -533,12 +719,12 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView nullptr); BindBlitState(cmdbuf, layout, dst_region, src_region, src_size); cmdbuf.Draw(3, 1, 0, 0); - cmdbuf.EndRenderPass(); + EndRenderPass(cmdbuf, dst_framebuffer); }); } void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, - VkImageView src_depth_view, VkImageView src_stencil_view, + ImageView& src_image_view, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { @@ -554,10 +740,14 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, const VkPipelineLayout layout = *two_textures_pipeline_layout; const VkSampler sampler = *nearest_sampler; const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key); + const VkImageView src_depth_view = src_image_view.DepthView(); + const VkImageView src_stencil_view = src_image_view.StencilView(); + + RecordShaderReadBarrier(scheduler, src_image_view); + scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view, src_stencil_view, this](vk::CommandBuffer cmdbuf) { - // TODO: Barriers const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit(); UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, src_stencil_view); @@ -692,6 +882,8 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb const VkSampler sampler = *nearest_sampler; const VkExtent2D extent = GetConversionExtent(src_image_view); + RecordShaderReadBarrier(scheduler, src_image_view); + scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) { const VkOffset2D offset{ @@ -716,8 +908,6 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb }; const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view); - - // TODO: Barriers cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); @@ -737,6 +927,8 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer const VkSampler sampler = *nearest_sampler; const VkExtent2D extent = GetConversionExtent(src_image_view); + RecordShaderReadBarrier(scheduler, src_image_view); + scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, this](vk::CommandBuffer cmdbuf) { @@ -763,7 +955,6 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit(); UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, src_stencil_view); - // TODO: Barriers cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 3d400be6a9..bee54c46ee 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -43,7 +43,7 @@ public: StateTracker& state_tracker, DescriptorPool& descriptor_pool); ~BlitImageHelper(); - void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view, + void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation); @@ -52,9 +52,9 @@ public: VkImage src_image, VkSampler src_sampler, const Region2D& dst_region, const Region2D& src_region, const Extent3D& src_size); - void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, - VkImageView src_stencil_view, const Region2D& dst_region, - const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, + void BlitDepthStencil(const Framebuffer* dst_framebuffer, ImageView& src_image_view, + const Region2D& dst_region, const Region2D& src_region, + Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation); void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 910e07a606..6ab061873d 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -175,11 +175,47 @@ public: std::array words{}; }; +inline VkImageLayout DescriptorImageLayout(TextureCache& texture_cache, + const Framebuffer* framebuffer, + ImageView& image_view) { + const auto& runtime = texture_cache.GetRuntime(); + if (!framebuffer || !runtime.device.SupportsAttachmentFeedbackLoopLayout()) { + return VK_IMAGE_LAYOUT_GENERAL; + } + + const VkImage image_handle = image_view.ImageHandle(); + const auto& images = framebuffer->Images(); + const auto& ranges = framebuffer->ImageRanges(); + const u32 num_images = framebuffer->NumImages(); + for (u32 index = 0; index < num_images; ++index) { + if (images[index] != image_handle) { + continue; + } + const VkImageAspectFlags aspect = ranges[index].aspectMask; + if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) { + return VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + const bool has_depth = (aspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; + const bool has_stencil = (aspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; + if (has_depth && has_stencil) { + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + if (has_depth) { + return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + if (has_stencil) { + return VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + } + return VK_IMAGE_LAYOUT_GENERAL; +} + inline void PushImageDescriptors(TextureCache& texture_cache, GuestDescriptorQueue& guest_descriptor_queue, const Shader::Info& info, RescalingPushConstant& rescaling, const VideoCommon::SamplerId*& samplers, - const VideoCommon::ImageViewInOut*& views) { + const VideoCommon::ImageViewInOut*& views, + const Framebuffer* framebuffer) { const u32 num_texture_buffers = Shader::NumDescriptors(info.texture_buffer_descriptors); const u32 num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors); views += num_texture_buffers; @@ -195,7 +231,9 @@ inline void PushImageDescriptors(TextureCache& texture_cache, !image_view.SupportsAnisotropy()}; const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() : sampler.Handle()}; - guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler); + const VkImageLayout image_layout = + DescriptorImageLayout(texture_cache, framebuffer, image_view); + guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler, image_layout); rescaling.PushTexture(texture_cache.IsRescaling(image_view)); } } @@ -206,10 +244,13 @@ inline void PushImageDescriptors(TextureCache& texture_cache, texture_cache.MarkModification(image_view.image_id); } const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)}; - guest_descriptor_queue.AddImage(vk_image_view); + const VkImageLayout image_layout = + DescriptorImageLayout(texture_cache, framebuffer, image_view); + guest_descriptor_queue.AddImage(vk_image_view, image_layout); rescaling.PushImage(texture_cache.IsRescaling(image_view)); } } } } // namespace Vulkan + diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 2d9c5d4148..6ae1e87240 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -198,7 +198,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, const VideoCommon::SamplerId* samplers_it{samplers.data()}; const VideoCommon::ImageViewInOut* views_it{views.data()}; PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it, - views_it); + views_it, nullptr); if (!is_built.load(std::memory_order::relaxed)) { // Wait for the pipeline to be built @@ -229,3 +229,4 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, } } // namespace Vulkan + diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index f5594450c2..cdbbb9e767 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -460,6 +460,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { buffer_cache.UpdateGraphicsBuffers(is_indexed); buffer_cache.BindHostGeometryBuffers(is_indexed); + texture_cache.UpdateRenderTargets(false); + Framebuffer* const active_framebuffer = texture_cache.GetFramebuffer(); + guest_descriptor_queue.Acquire(); RescalingPushConstant rescaling; @@ -469,7 +472,7 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { buffer_cache.BindHostStageBuffers(stage); PushImageDescriptors(texture_cache, guest_descriptor_queue, stage_infos[stage], rescaling, - samplers_it, views_it); + samplers_it, views_it, active_framebuffer); const auto& info{stage_infos[0]}; if (info.uses_render_area) { render_area.uses_render_area = true; @@ -492,7 +495,6 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { if constexpr (Spec::enabled_stages[4]) { prepare_stage(4); } - texture_cache.UpdateRenderTargets(false); texture_cache.CheckFeedbackLoop(views); ConfigureDraw(rescaling, render_area); @@ -906,6 +908,18 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { if (device.IsKhrPipelineExecutablePropertiesEnabled() && Settings::values.renderer_debug.GetValue()) { flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; } + if (device.SupportsAttachmentFeedbackLoopLayout()) { + const RenderPassKey render_pass_key = MakeRenderPassKey(key.state); + const bool has_color_feedback = std::ranges::any_of(render_pass_key.color_formats, [](PixelFormat format) { + return format != PixelFormat::Invalid; + }); + if (has_color_feedback) { + flags |= VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT; + } + if (render_pass_key.depth_format != PixelFormat::Invalid) { + flags |= VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT; + } + } pipeline = device.GetLogical().CreateGraphicsPipeline( { diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp index 80ff75e3b9..5be5cbad04 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp @@ -43,6 +43,24 @@ using VideoCore::Surface::SurfaceType; } } + VkImageLayout AttachmentLayout(const Device& device, SurfaceType surface_type) { + if (!device.SupportsAttachmentFeedbackLoopLayout()) { + return VK_IMAGE_LAYOUT_GENERAL; + } + switch (surface_type) { + case SurfaceType::ColorTexture: + return VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + case SurfaceType::Depth: + return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + case SurfaceType::Stencil: + return VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + case SurfaceType::DepthStencil: + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + default: + return VK_IMAGE_LAYOUT_GENERAL; + } + } + VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat format, VkSampleCountFlagBits samples) { using MaxwellToVK::SurfaceFormat; @@ -50,7 +68,7 @@ using VideoCore::Surface::SurfaceType; const SurfaceType surface_type = GetSurfaceType(format); const bool has_stencil = surface_type == SurfaceType::DepthStencil || surface_type == SurfaceType::Stencil; - + const VkImageLayout layout = AttachmentLayout(device, surface_type); return { .flags = {}, .format = SurfaceFormat(device, FormatType::Optimal, true, format).format, @@ -61,8 +79,8 @@ using VideoCore::Surface::SurfaceType; : VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = has_stencil ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_GENERAL, - .finalLayout = VK_IMAGE_LAYOUT_GENERAL, + .initialLayout = layout, + .finalLayout = layout, }; } } // Anonymous namespace @@ -81,28 +99,41 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) { u32 num_colors{}; for (size_t index = 0; index < key.color_formats.size(); ++index) { const PixelFormat format{key.color_formats[index]}; - const bool is_valid{format != PixelFormat::Invalid}; - references[index] = VkAttachmentReference{ - .attachment = is_valid ? num_colors : VK_ATTACHMENT_UNUSED, - .layout = VK_IMAGE_LAYOUT_GENERAL, - }; - if (is_valid) { - descriptions.push_back(AttachmentDescription(*device, format, key.samples)); - num_attachments = static_cast(index + 1); - ++num_colors; + if (format == PixelFormat::Invalid) { + references[index] = VkAttachmentReference{ + .attachment = VK_ATTACHMENT_UNUSED, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }; + continue; } + + const SurfaceType surface_type = GetSurfaceType(format); + const VkImageLayout layout = AttachmentLayout(*device, surface_type); + references[index] = VkAttachmentReference{ + .attachment = num_colors, + .layout = layout, + }; + descriptions.push_back(AttachmentDescription(*device, format, key.samples)); + num_attachments = static_cast(index + 1); + ++num_colors; } + const bool has_depth{key.depth_format != PixelFormat::Invalid}; VkAttachmentReference depth_reference{}; - if (key.depth_format != PixelFormat::Invalid) { + if (has_depth) { + const SurfaceType depth_type = GetSurfaceType(key.depth_format); + const VkImageLayout depth_layout = AttachmentLayout(*device, depth_type); depth_reference = VkAttachmentReference{ .attachment = num_colors, - .layout = VK_IMAGE_LAYOUT_GENERAL, + .layout = depth_layout, }; descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples)); } + const bool supports_feedback_loop = device->SupportsAttachmentFeedbackLoopLayout(); const VkSubpassDescription subpass{ - .flags = 0, + .flags = supports_feedback_loop + ? VK_SUBPASS_DESCRIPTION_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT + : 0u, .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, .inputAttachmentCount = 0, .pInputAttachments = nullptr, @@ -133,8 +164,8 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) { .pAttachments = descriptions.empty() ? nullptr : descriptions.data(), .subpassCount = 1, .pSubpasses = &subpass, - .dependencyCount = 1, - .pDependencies = &dependency, + .dependencyCount = supports_feedback_loop ? 1u : 0u, + .pDependencies = supports_feedback_loop ? &dependency : nullptr, }); return *pair->second; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 530d161dfe..e60d03910e 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -103,6 +103,68 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) { state.framebuffer = framebuffer_handle; state.render_area = render_area; + num_renderpass_images = framebuffer->NumImages(); + renderpass_images = framebuffer->Images(); + renderpass_image_ranges = framebuffer->ImageRanges(); + renderpass_image_layouts = framebuffer->ImageLayouts(); + + if (device.SupportsAttachmentFeedbackLoopLayout()) { + Record([num_images = num_renderpass_images, images = renderpass_images, + ranges = renderpass_image_ranges, + layouts = renderpass_image_layouts](vk::CommandBuffer cmdbuf) { + std::array barriers{}; + u32 barrier_count = 0; + VkPipelineStageFlags dst_stages = 0; + + for (size_t i = 0; i < num_images; ++i) { + const VkImageLayout layout = layouts[i]; + if (layout == VK_IMAGE_LAYOUT_GENERAL) { + continue; + } + const VkImageSubresourceRange& range = ranges[i]; + VkAccessFlags dst_access = 0; + VkPipelineStageFlags dst_stage = 0; + if ((range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) { + dst_access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dst_stage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + if ((range.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { + dst_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dst_stage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + } + if (dst_access == 0) { + continue; + } + barriers[barrier_count++] = VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_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, + .dstAccessMask = dst_access, + .oldLayout = layout, + .newLayout = layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = images[i], + .subresourceRange = range, + }; + dst_stages |= dst_stage; + } + + if (barrier_count == 0) { + return; + } + + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, dst_stages, 0, {}, {}, + {barriers.data(), barrier_count}); + }); + } + Record([renderpass, framebuffer_handle, render_area](vk::CommandBuffer cmdbuf) { const VkRenderPassBeginInfo renderpass_bi{ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, @@ -119,9 +181,6 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) { }; cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); }); - num_renderpass_images = framebuffer->NumImages(); - renderpass_images = framebuffer->Images(); - renderpass_image_ranges = framebuffer->ImageRanges(); } void Scheduler::RequestOutsideRenderPassOperationContext() { @@ -281,12 +340,14 @@ void Scheduler::EndRenderPass() Record([num_images = num_renderpass_images, images = renderpass_images, - ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) { + ranges = renderpass_image_ranges, + layouts = renderpass_image_layouts](vk::CommandBuffer cmdbuf) { std::array barriers; VkPipelineStageFlags src_stages = 0; for (size_t i = 0; i < num_images; ++i) { const VkImageSubresourceRange& range = ranges[i]; + const VkImageLayout layout = layouts[i]; const bool is_color = range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT; const bool is_depth_stencil = range.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT @@ -317,7 +378,7 @@ void Scheduler::EndRenderPass() | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .oldLayout = layout, .newLayout = VK_IMAGE_LAYOUT_GENERAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, @@ -356,3 +417,5 @@ void Scheduler::AcquireNewChunk() { } } // namespace Vulkan + + diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 54ab8ba52b..c7290613f9 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -249,6 +250,7 @@ private: u32 num_renderpass_images = 0; std::array renderpass_images{}; std::array renderpass_image_ranges{}; + std::array renderpass_image_layouts{}; std::queue> work_queue; std::vector> chunk_reserve; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 7befe235c4..e4fef2998e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -125,6 +125,28 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { return usage; } +[[nodiscard]] VkImageLayout AttachmentFeedbackLoopLayout(const Device& device, + VkImageAspectFlags aspect_mask) { + if (!device.SupportsAttachmentFeedbackLoopLayout()) { + return VK_IMAGE_LAYOUT_GENERAL; + } + if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) { + return VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + const bool has_depth = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; + const bool has_stencil = (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; + if (has_depth && has_stencil) { + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + if (has_depth) { + return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + if (has_stencil) { + return VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT; + } + return VK_IMAGE_LAYOUT_GENERAL; +} + [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, info.format); @@ -137,6 +159,11 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; } const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); + VkImageUsageFlags usage = ImageUsageFlags(format_info, info.format); + if (device.SupportsAttachmentFeedbackLoopLayout() && + (usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))) { + usage |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT; + } return VkImageCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, @@ -152,14 +179,13 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { .arrayLayers = static_cast(info.resources.layers), .samples = ConvertSampleCount(info.num_samples), .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = ImageUsageFlags(format_info, info.format), + .usage = usage, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }; } - [[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator, const ImageInfo& info, std::span view_formats) { if (info.type == ImageType::Buffer) { @@ -940,6 +966,9 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { } void TextureCacheRuntime::BarrierFeedbackLoop() { + if (device.SupportsAttachmentFeedbackLoopLayout()) { + return; + } scheduler.RequestOutsideRenderPassOperationContext(); } @@ -1086,8 +1115,8 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst return; } if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) { - blit_image_helper.BlitColor(dst_framebuffer, src.Handle(Shader::TextureType::Color2D), - dst_region, src_region, filter, operation); + blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter, + operation); return; } ASSERT(src.format == dst.format); @@ -1106,8 +1135,8 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst }(); if (!can_blit_depth_stencil) { UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa); - blit_image_helper.BlitDepthStencil(dst_framebuffer, src.DepthView(), src.StencilView(), - dst_region, src_region, filter, operation); + blit_image_helper.BlitDepthStencil(dst_framebuffer, src, dst_region, src_region, + filter, operation); return; } } @@ -1965,17 +1994,14 @@ bool Image::BlitScaleHelper(bool scale_up) { blit_framebuffer = std::make_unique(*runtime, view_ptr, nullptr, extent, scale_up); } - const auto color_view = blit_view->Handle(Shader::TextureType::Color2D); - - runtime->blit_image_helper.BlitColor(blit_framebuffer.get(), color_view, dst_region, + runtime->blit_image_helper.BlitColor(blit_framebuffer.get(), *blit_view, dst_region, src_region, operation, BLIT_OPERATION); } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (!blit_framebuffer) { blit_framebuffer = std::make_unique(*runtime, nullptr, view_ptr, extent, scale_up); } - runtime->blit_image_helper.BlitDepthStencil(blit_framebuffer.get(), blit_view->DepthView(), - blit_view->StencilView(), dst_region, + runtime->blit_image_helper.BlitDepthStencil(blit_framebuffer.get(), *blit_view, dst_region, src_region, operation, BLIT_OPERATION); } else { // TODO: Use helper blits where applicable @@ -2291,6 +2317,9 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, boost::container::small_vector attachments; RenderPassKey renderpass_key{}; s32 num_layers = 1; + num_images = 0; + num_color_buffers = 0; + image_layouts.fill(VK_IMAGE_LAYOUT_GENERAL); is_rescaled = is_rescaled_; const auto& resolution = runtime.resolution; @@ -2311,7 +2340,10 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, renderpass_key.color_formats[index] = color_buffer->format; num_layers = (std::max)(num_layers, color_buffer->range.extent.layers); images[num_images] = color_buffer->ImageHandle(); - image_ranges[num_images] = MakeSubresourceRange(color_buffer); + const VkImageSubresourceRange subresource_range = MakeSubresourceRange(color_buffer); + image_ranges[num_images] = subresource_range; + image_layouts[num_images] = + AttachmentFeedbackLoopLayout(runtime.device, subresource_range.aspectMask); rt_map[index] = num_images; samples = color_buffer->Samples(); ++num_images; @@ -2328,6 +2360,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, images[num_images] = depth_buffer->ImageHandle(); const VkImageSubresourceRange subresource_range = MakeSubresourceRange(depth_buffer); image_ranges[num_images] = subresource_range; + image_layouts[num_images] = + AttachmentFeedbackLoopLayout(runtime.device, subresource_range.aspectMask); samples = depth_buffer->Samples(); ++num_images; has_depth = (subresource_range.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; @@ -2393,3 +2427,4 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) { } } // namespace Vulkan + diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index cd11cc8fc7..d707011ce2 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -359,6 +359,10 @@ public: [[nodiscard]] const std::array& ImageRanges() const noexcept { return image_ranges; } + [[nodiscard]] const std::array& ImageLayouts() const noexcept { + return image_layouts; + } + [[nodiscard]] bool HasAspectColorBit(size_t index) const noexcept { return (image_ranges.at(rt_map[index]).aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0; @@ -385,6 +389,7 @@ private: u32 num_images = 0; std::array images{}; std::array image_ranges{}; + std::array image_layouts{}; std::array rt_map{}; bool has_depth{}; bool has_stencil{}; @@ -411,3 +416,4 @@ struct TextureCacheParams { using TextureCache = VideoCommon::TextureCache; } // namespace Vulkan + diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h index 82fce298da..a3a3300654 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.h +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h @@ -47,19 +47,21 @@ public: return upload_start; } - void AddSampledImage(VkImageView image_view, VkSampler sampler) { + void AddSampledImage(VkImageView image_view, VkSampler sampler, + VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL) { *(payload_cursor++) = VkDescriptorImageInfo{ .sampler = sampler, .imageView = image_view, - .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + .imageLayout = layout, }; } - void AddImage(VkImageView image_view) { + void AddImage(VkImageView image_view, + VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL) { *(payload_cursor++) = VkDescriptorImageInfo{ .sampler = VK_NULL_HANDLE, .imageView = image_view, - .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + .imageLayout = layout, }; } @@ -91,3 +93,6 @@ using GuestDescriptorQueue = UpdateDescriptorQueue; using ComputePassDescriptorQueue = UpdateDescriptorQueue; } // namespace Vulkan + + + diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 6210d63940..c7314d9cb6 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -137,6 +137,14 @@ public: /// Notify the cache that a new frame has been queued void TickFrame(); + [[nodiscard]] Runtime& GetRuntime() noexcept { + return runtime; + } + + [[nodiscard]] const Runtime& GetRuntime() const noexcept { + return runtime; + } + /// Return a constant reference to the given image view id [[nodiscard]] const ImageView& GetImageView(ImageViewId id) const noexcept; diff --git a/src/video_core/vulkan_common/vulkan.h b/src/video_core/vulkan_common/vulkan.h index 62aa132915..2cffb25411 100644 --- a/src/video_core/vulkan_common/vulkan.h +++ b/src/video_core/vulkan_common/vulkan.h @@ -17,6 +17,16 @@ #include +#ifndef VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT +#define VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT +#endif +#ifndef VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT +#define VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT +#endif +#ifndef VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT +#define VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT +#endif + // Sanitize macros #undef CreateEvent #undef CreateSemaphore diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 41917a1b90..477d38f455 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1213,6 +1213,13 @@ void Device::RemoveUnsuitableExtensions() { RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); + // VK_EXT_attachment_feedback_loop_layout + extensions.attachment_feedback_loop_layout = + features.attachment_feedback_loop_layout.attachmentFeedbackLoopLayout; + RemoveExtensionFeatureIfUnsuitable(extensions.attachment_feedback_loop_layout, + features.attachment_feedback_loop_layout, + VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME); + /* */ // VK_EXT_extended_dynamic_state extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState; RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state, diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index bd54144480..d3a4bb0a96 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -46,6 +46,8 @@ VK_DEFINE_HANDLE(VmaAllocator) FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \ FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \ FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \ + FEATURE(EXT, AttachmentFeedbackLoopLayout, ATTACHMENT_FEEDBACK_LOOP_LAYOUT, \ + attachment_feedback_loop_layout) \ FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \ FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \ FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \ @@ -562,6 +564,11 @@ public: bool IsExtLineRasterizationSupported() const { return extensions.line_rasterization; } + bool SupportsAttachmentFeedbackLoopLayout() const { + return extensions.attachment_feedback_loop_layout && + features.attachment_feedback_loop_layout.attachmentFeedbackLoopLayout; + } + /// Returns true if the device supports VK_EXT_vertex_input_dynamic_state. bool IsExtVertexInputDynamicStateSupported() const {