mirror of https://github.com/PCSX2/pcsx2.git
GS/Vulkan: Use VK_EXT_attachment_feedback_loop_layout when supported
This commit is contained in:
parent
4a7b641bc3
commit
e2fc68ff2d
|
@ -336,12 +336,12 @@ layout(set = 1, binding = 1) uniform texture2D Palette;
|
|||
#endif
|
||||
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED
|
||||
#ifndef DISABLE_TEXTURE_BARRIER
|
||||
layout(input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput RtSampler;
|
||||
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
|
||||
#else
|
||||
#if defined(DISABLE_TEXTURE_BARRIER) || defined(HAS_FEEDBACK_LOOP_LAYOUT)
|
||||
layout(set = 2, binding = 0) uniform texture2D RtSampler;
|
||||
vec4 sample_from_rt() { return texelFetch(RtSampler, ivec2(gl_FragCoord.xy), 0); }
|
||||
#else
|
||||
layout(input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput RtSampler;
|
||||
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -1218,7 +1218,7 @@ void main()
|
|||
#endif
|
||||
|
||||
#if (SW_AD_TO_HW)
|
||||
vec4 RT = trunc(subpassLoad(RtSampler) * 255.0f + 0.1f);
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
vec4 alpha_blend = vec4(RT.a / 128.0f);
|
||||
#else
|
||||
vec4 alpha_blend = vec4(C.a / 128.0f);
|
||||
|
|
|
@ -662,6 +662,8 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
|
|||
instance_cleanup.Cancel();
|
||||
library_cleanup.Cancel();
|
||||
|
||||
m_has_feedback_loop_layout = g_vulkan_context->UseFeedbackLoopLayout();
|
||||
|
||||
// Render a frame as soon as possible to clear out whatever was previously being displayed.
|
||||
if (m_window_info.type != WindowInfo::Type::Surfaceless)
|
||||
RenderBlankFrame();
|
||||
|
@ -1622,6 +1624,8 @@ static void AddShaderHeader(std::stringstream& ss)
|
|||
ss << "#define DISABLE_TEXTURE_BARRIER 1\n";
|
||||
if (!features.dual_source_blend)
|
||||
ss << "#define DISABLE_DUAL_SOURCE 1\n";
|
||||
if (features.texture_barrier && g_vulkan_context->UseFeedbackLoopLayout())
|
||||
ss << "#define HAS_FEEDBACK_LOOP_LAYOUT 1\n";
|
||||
}
|
||||
|
||||
static void AddShaderStageMacro(std::stringstream& ss, bool vs, bool gs, bool fs)
|
||||
|
@ -1771,7 +1775,10 @@ bool GSDeviceVK::CreatePipelineLayouts()
|
|||
if ((m_tfx_sampler_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::SetObjectName(dev, m_tfx_sampler_ds_layout, "TFX sampler descriptor layout");
|
||||
dslb.AddBinding(0, m_features.texture_barrier ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
dslb.AddBinding(0,
|
||||
(m_features.texture_barrier && !m_has_feedback_loop_layout) ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT :
|
||||
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
dslb.AddBinding(1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
if ((m_tfx_rt_texture_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
@ -3367,7 +3374,7 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed)
|
|||
return ApplyTFXState(true);
|
||||
}
|
||||
|
||||
if (m_features.texture_barrier)
|
||||
if (m_features.texture_barrier && !m_has_feedback_loop_layout)
|
||||
{
|
||||
dsub.AddInputAttachmentDescriptorWrite(
|
||||
m_tfx_rt_descriptor_set, 0, m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetView(), VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
@ -3485,17 +3492,6 @@ void GSDeviceVK::SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb)
|
|||
m_dirty_flags |= DIRTY_FLAG_PS_CONSTANT_BUFFER;
|
||||
}
|
||||
|
||||
static void ColorBufferBarrier(GSTextureVK* rt)
|
||||
{
|
||||
const VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
rt->GetImage(), {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
|
||||
|
||||
vkCmdPipelineBarrier(g_vulkan_context->GetCurrentCommandBuffer(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
void GSDeviceVK::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVector4i& bbox)
|
||||
{
|
||||
GL_PUSH("SetupDATE {%d,%d} %dx%d", bbox.left, bbox.top, bbox.width(), bbox.height());
|
||||
|
@ -3952,15 +3948,35 @@ void GSDeviceVK::UploadHWDrawVerticesAndIndices(const GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier GSDeviceVK::GetColorBufferBarrier(GSTextureVK* rt) const
|
||||
{
|
||||
const VkImageLayout layout =
|
||||
m_has_feedback_loop_layout ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL;
|
||||
const VkAccessFlags dst_access =
|
||||
m_has_feedback_loop_layout ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
return {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, dst_access, layout, layout,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, rt->GetImage(), {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
|
||||
}
|
||||
|
||||
VkDependencyFlags GSDeviceVK::GetColorBufferBarrierFlags() const
|
||||
{
|
||||
return m_has_feedback_loop_layout ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) :
|
||||
VK_DEPENDENCY_BY_REGION_BIT;
|
||||
}
|
||||
|
||||
void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, bool skip_first_barrier)
|
||||
{
|
||||
if (config.drawlist)
|
||||
{
|
||||
GL_PUSH("Split the draw (SPRITE)");
|
||||
g_perfmon.Put(GSPerfMon::Barriers, static_cast<u32>(config.drawlist->size()) - static_cast<u32>(skip_first_barrier));
|
||||
g_perfmon.Put(
|
||||
GSPerfMon::Barriers, static_cast<u32>(config.drawlist->size()) - static_cast<u32>(skip_first_barrier));
|
||||
|
||||
const u32 indices_per_prim = config.indices_per_prim;
|
||||
const u32 draw_list_size = static_cast<u32>(config.drawlist->size());
|
||||
const VkImageMemoryBarrier barrier = GetColorBufferBarrier(draw_rt);
|
||||
const VkDependencyFlags barrier_flags = GetColorBufferBarrierFlags();
|
||||
u32 p = 0;
|
||||
u32 n = 0;
|
||||
|
||||
|
@ -3974,8 +3990,11 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
|||
|
||||
for (; n < draw_list_size; n++)
|
||||
{
|
||||
vkCmdPipelineBarrier(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags, 0,
|
||||
nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
const u32 count = (*config.drawlist)[n] * indices_per_prim;
|
||||
ColorBufferBarrier(draw_rt);
|
||||
DrawIndexedPrimitive(p, count);
|
||||
p += count;
|
||||
}
|
||||
|
@ -3985,12 +4004,16 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
|||
|
||||
if (m_features.texture_barrier && m_pipeline_selector.ps.IsFeedbackLoop())
|
||||
{
|
||||
const VkImageMemoryBarrier barrier = GetColorBufferBarrier(draw_rt);
|
||||
const VkDependencyFlags barrier_flags = GetColorBufferBarrierFlags();
|
||||
|
||||
if (config.require_full_barrier)
|
||||
{
|
||||
const u32 indices_per_prim = config.indices_per_prim;
|
||||
|
||||
GL_PUSH("Split single draw in %d draw", config.nindices / indices_per_prim);
|
||||
g_perfmon.Put(GSPerfMon::Barriers, (config.nindices / indices_per_prim) - static_cast<u32>(skip_first_barrier));
|
||||
g_perfmon.Put(
|
||||
GSPerfMon::Barriers, (config.nindices / indices_per_prim) - static_cast<u32>(skip_first_barrier));
|
||||
|
||||
u32 p = 0;
|
||||
if (skip_first_barrier)
|
||||
|
@ -4001,7 +4024,10 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
|||
|
||||
for (; p < config.nindices; p += indices_per_prim)
|
||||
{
|
||||
ColorBufferBarrier(draw_rt);
|
||||
vkCmdPipelineBarrier(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags,
|
||||
0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
DrawIndexedPrimitive(p, indices_per_prim);
|
||||
}
|
||||
|
||||
|
@ -4011,7 +4037,9 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
|||
if (config.require_one_barrier && !skip_first_barrier)
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
ColorBufferBarrier(draw_rt);
|
||||
vkCmdPipelineBarrier(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags, 0,
|
||||
nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -309,6 +309,8 @@ public:
|
|||
void RenderHW(GSHWDrawConfig& config) override;
|
||||
void UpdateHWPipelineSelector(GSHWDrawConfig& config, PipelineSelector& pipe);
|
||||
void UploadHWDrawVerticesAndIndices(const GSHWDrawConfig& config);
|
||||
VkImageMemoryBarrier GetColorBufferBarrier(GSTextureVK* rt) const;
|
||||
VkDependencyFlags GetColorBufferBarrierFlags() const;
|
||||
void SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, bool skip_first_barrier);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -395,6 +397,7 @@ private:
|
|||
// Which bindings/state has to be updated before the next draw.
|
||||
u32 m_dirty_flags = 0;
|
||||
FeedbackLoopFlag m_current_framebuffer_feedback_loop = FeedbackLoopFlag_None;
|
||||
bool m_has_feedback_loop_layout = false;
|
||||
bool m_warned_slow_spin = false;
|
||||
|
||||
// input assembly
|
||||
|
|
|
@ -29,22 +29,33 @@
|
|||
static constexpr const VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
|
||||
|
||||
static constexpr std::array<VkImageLayout, static_cast<u32>(GSTextureVK::Layout::Count)> s_vk_layout_mapping = {{
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, // Undefined
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED, // Preinitialized
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // ColorAttachment
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // DepthStencilAttachment
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // ShaderReadOnly
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // ClearDst
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TransferSrc
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TransferDst
|
||||
VK_IMAGE_LAYOUT_GENERAL, // TransferSelf
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // PresentSrc
|
||||
VK_IMAGE_LAYOUT_GENERAL, // FeedbackLoop
|
||||
VK_IMAGE_LAYOUT_GENERAL, // ReadWriteImage
|
||||
VK_IMAGE_LAYOUT_GENERAL, // ComputeReadWriteImage
|
||||
VK_IMAGE_LAYOUT_GENERAL, // General
|
||||
}};
|
||||
static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout)
|
||||
{
|
||||
static constexpr std::array<VkImageLayout, static_cast<u32>(GSTextureVK::Layout::Count)> s_vk_layout_mapping = {{
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, // Undefined
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED, // Preinitialized
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // ColorAttachment
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // DepthStencilAttachment
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // ShaderReadOnly
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // ClearDst
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TransferSrc
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TransferDst
|
||||
VK_IMAGE_LAYOUT_GENERAL, // TransferSelf
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // PresentSrc
|
||||
VK_IMAGE_LAYOUT_GENERAL, // FeedbackLoop
|
||||
VK_IMAGE_LAYOUT_GENERAL, // ReadWriteImage
|
||||
VK_IMAGE_LAYOUT_GENERAL, // ComputeReadWriteImage
|
||||
VK_IMAGE_LAYOUT_GENERAL, // General
|
||||
}};
|
||||
return (layout == GSTextureVK::Layout::FeedbackLoop && g_vulkan_context->UseFeedbackLoopLayout()) ?
|
||||
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
|
||||
s_vk_layout_mapping[static_cast<u32>(layout)];
|
||||
}
|
||||
|
||||
static VkAccessFlagBits GetFeedbackLoopInputAccessBits()
|
||||
{
|
||||
return g_vulkan_context->UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
}
|
||||
|
||||
GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image,
|
||||
VmaAllocation allocation, VkImageView view, VkFormat vk_format)
|
||||
|
@ -104,15 +115,18 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
|
|||
pxAssert(levels == 1);
|
||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||
(g_vulkan_context->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT :
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::DepthStencil:
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
ici.usage =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
(g_vulkan_context->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT : 0);
|
||||
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
break;
|
||||
|
@ -264,7 +278,7 @@ void GSTextureVK::Destroy(bool defer)
|
|||
|
||||
VkImageLayout GSTextureVK::GetVkLayout() const
|
||||
{
|
||||
return s_vk_layout_mapping[static_cast<u32>(m_layout)];
|
||||
return GetVkImageLayout(m_layout);
|
||||
}
|
||||
|
||||
void* GSTextureVK::GetNativeHandle() const
|
||||
|
@ -589,9 +603,8 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
|||
aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, 0, 0,
|
||||
s_vk_layout_mapping[static_cast<u32>(old_layout)], s_vk_layout_mapping[static_cast<u32>(new_layout)],
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, m_image,
|
||||
VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, 0, 0, GetVkImageLayout(old_layout),
|
||||
GetVkImageLayout(new_layout), VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, m_image,
|
||||
{aspect, static_cast<u32>(start_level), static_cast<u32>(num_levels), 0u, 1u}};
|
||||
|
||||
// srcStageMask -> Stages that must complete before the barrier
|
||||
|
@ -657,7 +670,7 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
|||
case Layout::FeedbackLoop:
|
||||
barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) :
|
||||
GetFeedbackLoopInputAccessBits()) :
|
||||
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
|
@ -733,7 +746,7 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
|||
case Layout::FeedbackLoop:
|
||||
barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) :
|
||||
GetFeedbackLoopInputAccessBits()) :
|
||||
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
|
|
|
@ -386,6 +386,8 @@ bool VKContext::SelectDeviceExtensions(ExtensionList* extension_list, bool enabl
|
|||
SupportsExtension(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_shader_draw_parameters =
|
||||
SupportsExtension(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_attachment_feedback_loop_layout =
|
||||
SupportsExtension(VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME, false);
|
||||
|
||||
#ifdef _WIN32
|
||||
m_optional_extensions.vk_ext_full_screen_exclusive =
|
||||
|
@ -581,6 +583,8 @@ bool VKContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer,
|
|||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT};
|
||||
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
{
|
||||
|
@ -597,6 +601,11 @@ bool VKContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer,
|
|||
rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &rasterization_order_access_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout)
|
||||
{
|
||||
attachment_feedback_loop_feature.attachmentFeedbackLoopLayout = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &attachment_feedback_loop_feature);
|
||||
}
|
||||
|
||||
VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
|
||||
if (res != VK_SUCCESS)
|
||||
|
@ -661,6 +670,8 @@ void VKContext::ProcessDeviceExtensions()
|
|||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT};
|
||||
|
||||
// add in optional feature structs
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
|
@ -669,6 +680,8 @@ void VKContext::ProcessDeviceExtensions()
|
|||
Vulkan::AddPointerToChain(&features2, &line_rasterization_feature);
|
||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout)
|
||||
Vulkan::AddPointerToChain(&features2, &attachment_feedback_loop_feature);
|
||||
|
||||
// query
|
||||
vkGetPhysicalDeviceFeatures2(m_physical_device, &features2);
|
||||
|
@ -678,6 +691,8 @@ void VKContext::ProcessDeviceExtensions()
|
|||
m_optional_extensions.vk_ext_rasterization_order_attachment_access &=
|
||||
(rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_line_rasterization &= (line_rasterization_feature.bresenhamLines == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_attachment_feedback_loop_layout &=
|
||||
(attachment_feedback_loop_feature.attachmentFeedbackLoopLayout == VK_TRUE);
|
||||
|
||||
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
void** pNext = &properties2.pNext;
|
||||
|
@ -734,6 +749,8 @@ void VKContext::ProcessDeviceExtensions()
|
|||
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s",
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_attachment_feedback_loop_layout is %s",
|
||||
m_optional_extensions.vk_ext_attachment_feedback_loop_layout ? "supported" : "NOT supported");
|
||||
}
|
||||
|
||||
bool VKContext::CreateAllocator()
|
||||
|
@ -968,6 +985,30 @@ bool VKContext::CreateTextureStreamBuffer()
|
|||
return true;
|
||||
}
|
||||
|
||||
VkRenderPass VKContext::GetRenderPass(VkFormat color_format, VkFormat depth_format, VkAttachmentLoadOp color_load_op,
|
||||
VkAttachmentStoreOp color_store_op, VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op,
|
||||
VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op, bool color_feedback_loop,
|
||||
bool depth_sampling)
|
||||
{
|
||||
RenderPassCacheKey key = {};
|
||||
key.color_format = color_format;
|
||||
key.depth_format = depth_format;
|
||||
key.color_load_op = color_load_op;
|
||||
key.color_store_op = color_store_op;
|
||||
key.depth_load_op = depth_load_op;
|
||||
key.depth_store_op = depth_store_op;
|
||||
key.stencil_load_op = stencil_load_op;
|
||||
key.stencil_store_op = stencil_store_op;
|
||||
key.color_feedback_loop = color_feedback_loop;
|
||||
key.depth_sampling = depth_sampling;
|
||||
|
||||
auto it = m_render_pass_cache.find(key.key);
|
||||
if (it != m_render_pass_cache.end())
|
||||
return it->second;
|
||||
|
||||
return CreateCachedRenderPass(key);
|
||||
}
|
||||
|
||||
VkRenderPass VKContext::GetRenderPassForRestarting(VkRenderPass pass)
|
||||
{
|
||||
for (const auto& it : m_render_pass_cache)
|
||||
|
@ -1640,23 +1681,27 @@ VkRenderPass VKContext::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
u32 num_attachments = 0;
|
||||
if (key.color_format != VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
const VkImageLayout layout =
|
||||
key.color_feedback_loop ? (UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
|
||||
VK_IMAGE_LAYOUT_GENERAL) :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[num_attachments] = {0, static_cast<VkFormat>(key.color_format), VK_SAMPLE_COUNT_1_BIT,
|
||||
static_cast<VkAttachmentLoadOp>(key.color_load_op), static_cast<VkAttachmentStoreOp>(key.color_store_op),
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
key.color_feedback_loop ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
key.color_feedback_loop ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, layout, layout};
|
||||
color_reference.attachment = num_attachments;
|
||||
color_reference.layout =
|
||||
key.color_feedback_loop ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
color_reference.layout = layout;
|
||||
color_reference_ptr = &color_reference;
|
||||
|
||||
if (key.color_feedback_loop)
|
||||
{
|
||||
input_reference.attachment = num_attachments;
|
||||
input_reference.layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
input_reference_ptr = &input_reference;
|
||||
if (!UseFeedbackLoopLayout())
|
||||
{
|
||||
input_reference.attachment = num_attachments;
|
||||
input_reference.layout = layout;
|
||||
input_reference_ptr = &input_reference;
|
||||
}
|
||||
|
||||
if (!g_vulkan_context->GetOptionalExtensions().vk_ext_rasterization_order_attachment_access)
|
||||
if (!m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
{
|
||||
// don't need the framebuffer-local dependency when we have rasterization order attachment access
|
||||
subpass_dependency.srcSubpass = 0;
|
||||
|
@ -1665,8 +1710,11 @@ VkRenderPass VKContext::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
subpass_dependency.srcAccessMask =
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
subpass_dependency.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
subpass_dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
subpass_dependency.dstAccessMask =
|
||||
UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
subpass_dependency.dependencyFlags =
|
||||
UseFeedbackLoopLayout() ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) :
|
||||
VK_DEPENDENCY_BY_REGION_BIT;
|
||||
subpass_dependency_ptr = &subpass_dependency;
|
||||
}
|
||||
}
|
||||
|
@ -1675,8 +1723,9 @@ VkRenderPass VKContext::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
}
|
||||
if (key.depth_format != VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
const VkImageLayout layout =
|
||||
key.depth_sampling ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
const VkImageLayout layout = key.depth_sampling ? (UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
|
||||
VK_IMAGE_LAYOUT_GENERAL) :
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[num_attachments] = {0, static_cast<VkFormat>(key.depth_format), VK_SAMPLE_COUNT_1_BIT,
|
||||
static_cast<VkAttachmentLoadOp>(key.depth_load_op), static_cast<VkAttachmentStoreOp>(key.depth_store_op),
|
||||
static_cast<VkAttachmentLoadOp>(key.stencil_load_op),
|
||||
|
@ -1688,8 +1737,7 @@ VkRenderPass VKContext::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
}
|
||||
|
||||
const VkSubpassDescriptionFlags subpass_flags =
|
||||
(key.color_feedback_loop &&
|
||||
g_vulkan_context->GetOptionalExtensions().vk_ext_rasterization_order_attachment_access) ?
|
||||
(key.color_feedback_loop && m_optional_extensions.vk_ext_rasterization_order_attachment_access) ?
|
||||
VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT :
|
||||
0;
|
||||
const VkSubpassDescription subpass = {subpass_flags, VK_PIPELINE_BIND_POINT_GRAPHICS, input_reference_ptr ? 1u : 0u,
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
bool vk_ext_calibrated_timestamps : 1;
|
||||
bool vk_ext_line_rasterization : 1;
|
||||
bool vk_ext_rasterization_order_attachment_access : 1;
|
||||
bool vk_ext_attachment_feedback_loop_layout : 1;
|
||||
bool vk_ext_full_screen_exclusive : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_khr_fragment_shader_barycentric : 1;
|
||||
|
@ -98,6 +99,13 @@ public:
|
|||
__fi const VkPhysicalDeviceDriverProperties& GetDeviceDriverProperties() const { return m_device_driver_properties; }
|
||||
__fi const OptionalExtensions& GetOptionalExtensions() const { return m_optional_extensions; }
|
||||
|
||||
// The interaction between raster order attachment access and fbfetch is unclear.
|
||||
__fi bool UseFeedbackLoopLayout() const
|
||||
{
|
||||
return (m_optional_extensions.vk_ext_attachment_feedback_loop_layout &&
|
||||
!m_optional_extensions.vk_ext_rasterization_order_attachment_access);
|
||||
}
|
||||
|
||||
// Helpers for getting constants
|
||||
__fi u32 GetUniformBufferAlignment() const
|
||||
{
|
||||
|
@ -132,33 +140,14 @@ public:
|
|||
__fi bool IsDeviceNVIDIA() const { return (m_device_properties.vendorID == 0x10DE); }
|
||||
|
||||
// Creates a simple render pass.
|
||||
__ri VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format,
|
||||
VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format,
|
||||
VkAttachmentLoadOp color_load_op = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VkAttachmentStoreOp color_store_op = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VkAttachmentLoadOp depth_load_op = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VkAttachmentStoreOp depth_store_op = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VkAttachmentLoadOp stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
bool color_feedback_loop = false, bool depth_sampling = false)
|
||||
{
|
||||
RenderPassCacheKey key = {};
|
||||
key.color_format = color_format;
|
||||
key.depth_format = depth_format;
|
||||
key.color_load_op = color_load_op;
|
||||
key.color_store_op = color_store_op;
|
||||
key.depth_load_op = depth_load_op;
|
||||
key.depth_store_op = depth_store_op;
|
||||
key.stencil_load_op = stencil_load_op;
|
||||
key.stencil_store_op = stencil_store_op;
|
||||
key.color_feedback_loop = color_feedback_loop;
|
||||
key.depth_sampling = depth_sampling;
|
||||
|
||||
auto it = m_render_pass_cache.find(key.key);
|
||||
if (it != m_render_pass_cache.end())
|
||||
return it->second;
|
||||
|
||||
return CreateCachedRenderPass(key);
|
||||
}
|
||||
bool color_feedback_loop = false, bool depth_sampling = false);
|
||||
|
||||
// Gets a non-clearing version of the specified render pass. Slow, don't call in hot path.
|
||||
VkRenderPass GetRenderPassForRestarting(VkRenderPass pass);
|
||||
|
|
|
@ -15,4 +15,4 @@
|
|||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 26;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 27;
|
||||
|
|
Loading…
Reference in New Issue