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
This commit is contained in:
parent
272df1fa83
commit
01111e84bb
15 changed files with 491 additions and 70 deletions
|
@ -5,6 +5,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#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<u32>(range.base.level),
|
||||
.levelCount = static_cast<u32>(range.extent.levels),
|
||||
.baseArrayLayer = static_cast<u32>(range.base.layer),
|
||||
.layerCount = static_cast<u32>(range.extent.layers),
|
||||
};
|
||||
}
|
||||
|
||||
struct PushConstants {
|
||||
std::array<float, 2> tex_scale;
|
||||
std::array<float, 2> 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<VkImageMemoryBarrier, 9> 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<VkImageMemoryBarrier, 9> 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -175,11 +175,47 @@ public:
|
|||
std::array<f32, 4> 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -901,6 +903,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(
|
||||
{
|
||||
|
|
|
@ -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<u32>(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<u32>(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;
|
||||
}
|
||||
|
|
|
@ -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<VkImageMemoryBarrier, 9> 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<VkImageMemoryBarrier, 9> 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
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
@ -249,6 +250,7 @@ private:
|
|||
u32 num_renderpass_images = 0;
|
||||
std::array<VkImage, 9> renderpass_images{};
|
||||
std::array<VkImageSubresourceRange, 9> renderpass_image_ranges{};
|
||||
std::array<VkImageLayout, 9> renderpass_image_layouts{};
|
||||
|
||||
std::queue<std::unique_ptr<CommandChunk>> work_queue;
|
||||
std::vector<std::unique_ptr<CommandChunk>> chunk_reserve;
|
||||
|
|
|
@ -125,6 +125,28 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& 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<float, 4>& 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<float, 4>& color) {
|
|||
.arrayLayers = static_cast<u32>(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<const VkFormat> 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;
|
||||
}
|
||||
}
|
||||
|
@ -1968,17 +1997,14 @@ bool Image::BlitScaleHelper(bool scale_up) {
|
|||
blit_framebuffer =
|
||||
std::make_unique<Framebuffer>(*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<Framebuffer>(*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
|
||||
|
@ -2294,6 +2320,9 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||
boost::container::small_vector<VkImageView, NUM_RT + 1> 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;
|
||||
|
@ -2314,7 +2343,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;
|
||||
|
@ -2331,6 +2363,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;
|
||||
|
@ -2396,3 +2430,4 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
|
|||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
|
|
|
@ -359,6 +359,10 @@ public:
|
|||
[[nodiscard]] const std::array<VkImageSubresourceRange, 9>& ImageRanges() const noexcept {
|
||||
return image_ranges;
|
||||
}
|
||||
[[nodiscard]] const std::array<VkImageLayout, 9>& 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<VkImage, 9> images{};
|
||||
std::array<VkImageSubresourceRange, 9> image_ranges{};
|
||||
std::array<VkImageLayout, 9> image_layouts{};
|
||||
std::array<size_t, NUM_RT> rt_map{};
|
||||
bool has_depth{};
|
||||
bool has_stencil{};
|
||||
|
@ -411,3 +416,4 @@ struct TextureCacheParams {
|
|||
using TextureCache = VideoCommon::TextureCache<TextureCacheParams>;
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -17,6 +17,16 @@
|
|||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue