GS:VK: Cleanup render pass handling.

Rewrite render pass builder.

Make a begin/end present render pass function.

Rename `depth_sampling` to `depth_feedback`.
This commit is contained in:
TJnotJT
2026-10-11 19:59:12 +02:00
committed by lightningterror
parent 8fab8847f9
commit 2954ebe696
6 changed files with 388 additions and 293 deletions
+141 -165
View File
@@ -144,6 +144,13 @@ static constexpr const char* s_required_device_extensions[] = {
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
};
static constexpr VkPipelineStageFlags2 s_color_feedback_src_stage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
static constexpr VkPipelineStageFlags2 s_color_feedback_src_access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
static constexpr VkPipelineStageFlags2 s_depth_feedback_src_stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
static constexpr VkPipelineStageFlags2 s_depth_feedback_src_access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
GSDeviceVK::GSDeviceVK()
{
#ifdef ENABLE_OGL_DEBUG
@@ -1059,7 +1066,7 @@ VkRenderPass GSDeviceVK::GetRenderPass(VkFormat color_format, VkFormat depth_for
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)
bool color_feedback_loop, bool depth_feedback_loop)
{
RenderPassCacheKey key = {};
key.color_format = color_format;
@@ -1071,7 +1078,7 @@ VkRenderPass GSDeviceVK::GetRenderPass(VkFormat color_format, VkFormat depth_for
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;
key.depth_feedback_loop = depth_feedback_loop;
auto it = m_render_pass_cache.find(key.key);
if (it != m_render_pass_cache.end())
@@ -1669,129 +1676,63 @@ void GSDeviceVK::DisableDebugUtils()
VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key)
{
VkAttachmentReference color_reference;
VkAttachmentReference* color_reference_ptr = nullptr;
VkAttachmentReference depth_reference;
VkAttachmentReference* depth_reference_ptr = nullptr;
std::array<VkAttachmentReference, 2> input_reference;
u32 num_subpass_inputs = 0;
std::array<VkSubpassDependency, 2> subpass_dependencies;
u32 num_subpass_dependencies = 0;
std::array<VkAttachmentDescription, 2> attachments;
u32 num_attachments = 0;
Vulkan::RenderPassBuilder rpb;
const GSTextureVK::Layout color_layout =
key.color_feedback_loop ? GSTextureVK::Layout::FeedbackLoop : GSTextureVK::Layout::ColorAttachment;
const GSTextureVK::Layout depth_layout =
key.depth_feedback_loop ?
(m_features.depth_feedback ? GSTextureVK::Layout::FeedbackLoop : GSTextureVK::Layout::General) :
GSTextureVK::Layout::DepthStencilAttachment;
const VkDependencyFlags feedback_dependency = GetFeedbackBarrierDependencyFlags();
if (key.color_feedback_loop)
{
rpb.SetColorFeedbackBarrier(
s_color_feedback_src_stage, s_color_feedback_src_access,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, static_cast<VkAccessFlags>(GetFeedbackLoopInputAccessFlags()),
feedback_dependency);
if (m_features.framebuffer_fetch)
rpb.AddSubpassFlags(VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT);
}
if (key.depth_feedback_loop)
{
rpb.SetDepthFeedbackBarrier(
s_depth_feedback_src_stage, s_depth_feedback_src_access,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, static_cast<VkAccessFlags>(GetFeedbackLoopInputAccessFlags()),
feedback_dependency);
}
if (key.color_format != VK_FORMAT_UNDEFINED)
{
const VkImageLayout layout = key.color_feedback_loop ? GetFeedbackLoopLayout() : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentDescription& attachment = attachments[num_attachments] = {};
attachment.format = static_cast<VkFormat>(key.color_format);
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = static_cast<VkAttachmentLoadOp>(key.color_load_op);
attachment.storeOp = static_cast<VkAttachmentStoreOp>(key.color_store_op);
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.initialLayout = layout;
attachment.finalLayout = layout;
color_reference.attachment = num_attachments;
color_reference.layout = layout;
color_reference_ptr = &color_reference;
if (key.color_feedback_loop)
{
if (!UseFeedbackLoopLayout())
{
input_reference[num_subpass_inputs].attachment = num_attachments;
input_reference[num_subpass_inputs].layout = layout;
num_subpass_inputs++;
}
if (!m_features.framebuffer_fetch)
{
// don't need the framebuffer-local dependency when we have rasterization order attachment access
VkSubpassDependency& subpass_dependency = subpass_dependencies[num_subpass_dependencies++];
subpass_dependency.srcSubpass = 0;
subpass_dependency.dstSubpass = 0;
subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
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 = static_cast<VkAccessFlags>(GetFeedbackLoopInputAccessFlags());
subpass_dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags();
}
}
num_attachments++;
rpb.AddColorAttachment(
GSTextureVK::GetVkImageLayout(color_layout),
static_cast<VkFormat>(key.color_format),
static_cast<VkAttachmentLoadOp>(key.color_load_op),
static_cast<VkAttachmentStoreOp>(key.color_store_op),
key.color_feedback_loop,
!UseFeedbackLoopLayout(),
!m_features.framebuffer_fetch);
}
if (key.depth_format != VK_FORMAT_UNDEFINED)
{
const VkImageLayout layout =
key.depth_sampling ?
((m_features.depth_feedback && UseFeedbackLoopLayout()) ?
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
VK_IMAGE_LAYOUT_GENERAL) :
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentDescription& attachment = attachments[num_attachments] = {};
attachment.format = static_cast<VkFormat>(key.depth_format);
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = static_cast<VkAttachmentLoadOp>(key.depth_load_op);
attachment.storeOp = static_cast<VkAttachmentStoreOp>(key.depth_store_op);
attachment.stencilLoadOp = static_cast<VkAttachmentLoadOp>(key.stencil_load_op);
attachment.stencilStoreOp = static_cast<VkAttachmentStoreOp>(key.stencil_store_op);
attachment.initialLayout = layout;
attachment.finalLayout = layout;
depth_reference.attachment = num_attachments;
depth_reference.layout = layout;
depth_reference_ptr = &depth_reference;
if (key.depth_sampling)
{
if (!UseFeedbackLoopLayout())
{
input_reference[num_subpass_inputs].attachment = num_attachments;
input_reference[num_subpass_inputs].layout = layout;
num_subpass_inputs++;
}
if (!m_features.framebuffer_fetch)
{
// don't need the framebuffer-local dependency when we have rasterization order attachment access
VkSubpassDependency& subpass_dependency = subpass_dependencies[num_subpass_dependencies++];
subpass_dependency.srcSubpass = 0;
subpass_dependency.dstSubpass = 0;
subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
subpass_dependency.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
subpass_dependency.dstAccessMask = static_cast<VkAccessFlags>(GetFeedbackLoopInputAccessFlags());
subpass_dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags();
}
}
num_attachments++;
rpb.AddDepthStencilAttachment(
GSTextureVK::GetVkImageLayout(depth_layout),
static_cast<VkFormat>(key.depth_format),
static_cast<VkAttachmentLoadOp>(key.depth_load_op),
static_cast<VkAttachmentStoreOp>(key.depth_store_op),
static_cast<VkAttachmentLoadOp>(key.stencil_load_op),
static_cast<VkAttachmentStoreOp>(key.stencil_store_op),
key.depth_feedback_loop,
!UseFeedbackLoopLayout(),
!m_features.framebuffer_fetch);
}
VkSubpassDescription subpass = {};
if (key.color_feedback_loop && m_features.framebuffer_fetch)
subpass.flags |= VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount = num_subpass_inputs;
subpass.pInputAttachments = num_subpass_inputs ? input_reference.data() : nullptr;
subpass.colorAttachmentCount = color_reference_ptr ? 1 : 0;
subpass.pColorAttachments = color_reference_ptr;
subpass.pDepthStencilAttachment = depth_reference_ptr;
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
pass_info.attachmentCount = num_attachments;
pass_info.pAttachments = attachments.data();
pass_info.subpassCount = 1;
pass_info.pSubpasses = &subpass;
pass_info.dependencyCount = num_subpass_dependencies;
pass_info.pDependencies = num_subpass_dependencies ? subpass_dependencies.data() : nullptr;
VkRenderPass pass;
const VkResult res = vkCreateRenderPass(m_device, &pass_info, nullptr, &pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
return VK_NULL_HANDLE;
}
VkRenderPass pass = rpb.Create(m_device);
m_render_pass_cache.emplace(key.key, pass);
return pass;
@@ -2588,17 +2529,13 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
if (!frame_skip && m_current)
static_cast<GSTextureVK*>(m_current)->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
const VkFramebuffer fb = swap_chain_texture->GetFramebuffer(false);
if (fb == VK_NULL_HANDLE)
return GSDevice::PresentResult::FrameSkipped;
GSVector4i render_area(0, 0, swap_chain_texture->GetWidth(), swap_chain_texture->GetHeight());
VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
rp.renderPass = GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
rp.framebuffer = fb;
rp.renderArea = {{0, 0}, {static_cast<u32>(swap_chain_texture->GetWidth()), static_cast<u32>(swap_chain_texture->GetHeight())}};
rp.clearValueCount = 1;
rp.pClearValues = &s_present_clear_color;
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
if (!BeginPresentRenderPass(GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED,
VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE), render_area, swap_chain_texture))
{
return GSDevice::PresentResult::FrameSkipped;
}
const VkViewport vp{0.0f, 0.0f, static_cast<float>(swap_chain_texture->GetWidth()), static_cast<float>(swap_chain_texture->GetHeight()), 0.0f, 1.0f};
const VkRect2D scissor{{0, 0}, {static_cast<u32>(swap_chain_texture->GetWidth()), static_cast<u32>(swap_chain_texture->GetHeight())}};
@@ -2612,10 +2549,8 @@ void GSDeviceVK::EndPresent()
{
RenderImGui();
VkCommandBuffer cmdbuffer = GetCurrentCommandBuffer();
vkCmdEndRenderPass(cmdbuffer);
m_is_presenting = false;
m_swap_chain->GetCurrentTexture()->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::PresentSrc);
EndPresentRenderPass();
m_swap_chain->GetCurrentTexture()->TransitionToLayout(GetCurrentCommandBuffer(), GSTextureVK::Layout::PresentSrc);
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
SubmitCommandBuffer(m_swap_chain.get());
@@ -4166,24 +4101,29 @@ bool GSDeviceVK::CreatePipelineLayouts()
bool GSDeviceVK::CreateRenderPasses()
{
#define GET(dest, rt, depth, fbl, dsp, opa, opb, opc) \
const auto CreateHelper = [&](VkFormat rt, VkFormat depth, bool feedback_rt, bool feedback_depth,
VkAttachmentLoadOp load_rt, VkAttachmentLoadOp load_depth, VkAttachmentLoadOp load_stencil)
{
return GetRenderPass(
rt,
depth,
(rt != VK_FORMAT_UNDEFINED) ? load_rt : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
(rt != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE,
(depth != VK_FORMAT_UNDEFINED) ? load_depth : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
(depth != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE,
(depth != VK_FORMAT_UNDEFINED) ? load_stencil : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
feedback_rt,
feedback_depth
);
};
#define GET(dest, rt, depth, fbc, fbd, opc, opd, ops) \
do \
{ \
dest = GetRenderPass( \
(rt), (depth), ((rt) != VK_FORMAT_UNDEFINED) ? (opa) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* color load */ \
((rt) != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : \
VK_ATTACHMENT_STORE_OP_DONT_CARE, /* color store */ \
((depth) != VK_FORMAT_UNDEFINED) ? (opb) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* depth load */ \
((depth) != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : \
VK_ATTACHMENT_STORE_OP_DONT_CARE, /* depth store */ \
((depth) != VK_FORMAT_UNDEFINED) ? (opc) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* stencil load */ \
VK_ATTACHMENT_STORE_OP_DONT_CARE, /* stencil store */ \
(fbl), /* feedback loop */ \
(dsp) /* depth sampling */ \
); \
if (dest == VK_NULL_HANDLE) \
return false; \
} while (0)
(dest) = CreateHelper(rt, depth, fbc, fbd, opc, opd, ops); \
if (!(dest)) return false; \
} while (false)
const VkFormat rt_format = LookupNativeFormat(GSTexture::Format::Color);
const VkFormat colclip_rt_format = LookupNativeFormat(GSTexture::Format::ColorClip);
@@ -4197,23 +4137,24 @@ bool GSDeviceVK::CreateRenderPasses()
{
for (u32 stencil = 0; stencil < 2; stencil++)
{
for (u32 fbl = 0; fbl < 2; fbl++)
for (u32 feedback_rt = 0; feedback_rt < 2; feedback_rt++)
{
for (u32 dsp = 0; dsp < 2; dsp++)
for (u32 feedback_depth = 0; feedback_depth < 2; feedback_depth++)
{
for (u32 opa = VK_ATTACHMENT_LOAD_OP_LOAD; opa <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opa++)
for (u32 load_rt = VK_ATTACHMENT_LOAD_OP_LOAD; load_rt <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; load_rt++)
{
for (u32 opb = VK_ATTACHMENT_LOAD_OP_LOAD; opb <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opb++)
for (u32 load_depth = VK_ATTACHMENT_LOAD_OP_LOAD; load_depth <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; load_depth++)
{
const VkFormat rp_rt_format =
(rt != 0) ? ((colclip != 0) ? colclip_rt_format : rt_format) : VK_FORMAT_UNDEFINED;
const VkFormat rp_rt_format = (rt != 0) ? ((colclip != 0) ? colclip_rt_format : rt_format) : VK_FORMAT_UNDEFINED;
const VkFormat rp_depth_format = (ds != 0) ? depth_format : VK_FORMAT_UNDEFINED;
const VkAttachmentLoadOp opc = (!stencil || !m_features.stencil_buffer) ?
VK_ATTACHMENT_LOAD_OP_DONT_CARE :
VK_ATTACHMENT_LOAD_OP_LOAD;
GET(m_tfx_render_pass[rt][ds][colclip][stencil][fbl][dsp][opa][opb], rp_rt_format,
rp_depth_format, (fbl != 0), (dsp != 0), static_cast<VkAttachmentLoadOp>(opa),
static_cast<VkAttachmentLoadOp>(opb), static_cast<VkAttachmentLoadOp>(opc));
const VkAttachmentLoadOp load_stencil = (!stencil || !m_features.stencil_buffer) ?
VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_LOAD;
GET(m_tfx_render_pass[rt][ds][colclip][stencil][feedback_rt][feedback_depth][load_rt][load_depth],
rp_rt_format, rp_depth_format, feedback_rt, feedback_depth,
static_cast<VkAttachmentLoadOp>(load_rt),
static_cast<VkAttachmentLoadOp>(load_depth),
static_cast<VkAttachmentLoadOp>(load_stencil));
}
}
}
@@ -5703,9 +5644,9 @@ void GSDeviceVK::BeginRenderPass(VkRenderPass rp, const GSVector4i& rect)
begin_info.renderArea.offset.y = rect.y;
begin_info.renderArea.extent.width = rect.width();
begin_info.renderArea.extent.height = rect.height();
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
m_command_buffer_render_passes++;
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
}
void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const VkClearValue* cv, u32 cv_count)
@@ -5726,6 +5667,8 @@ void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, c
begin_info.clearValueCount = cv_count;
begin_info.pClearValues = cv;
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
m_command_buffer_render_passes++;
}
void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color)
@@ -5743,6 +5686,30 @@ void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, f
BeginClearRenderPass(rp, rect, &cv, 1);
}
bool GSDeviceVK::BeginPresentRenderPass(VkRenderPass rp, const GSVector4i& rect, GSTextureVK* swap_chain)
{
if (m_current_render_pass != VK_NULL_HANDLE)
EndRenderPass();
VkFramebuffer fb = swap_chain->GetFramebuffer(false);
if (fb == VK_NULL_HANDLE)
return false;
VkRenderPassBeginInfo begin_info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
begin_info.renderPass = rp;
begin_info.framebuffer = fb;
begin_info.renderArea.offset.x = rect.x;
begin_info.renderArea.offset.y = rect.y;
begin_info.renderArea.extent.width = rect.width();
begin_info.renderArea.extent.height = rect.height();
begin_info.clearValueCount = 1;
begin_info.pClearValues = &s_present_clear_color;
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
return true;
}
void GSDeviceVK::EndRenderPass()
{
if (m_current_render_pass == VK_NULL_HANDLE)
@@ -5754,6 +5721,15 @@ void GSDeviceVK::EndRenderPass()
vkCmdEndRenderPass(GetCurrentCommandBuffer());
}
void GSDeviceVK::EndPresentRenderPass()
{
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
vkCmdEndRenderPass(GetCurrentCommandBuffer());
m_is_presenting = false;
}
void GSDeviceVK::SetViewport(const VkViewport& viewport)
{
if (std::memcmp(&viewport, &m_viewport, sizeof(VkViewport)) == 0)
@@ -6688,8 +6664,8 @@ void GSDeviceVK::FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds)
if (rt)
{
VkImageMemoryBarrier2& barrier = barriers[num_barriers++] = barrier_template;
barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
barrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
barrier.srcStageMask = s_color_feedback_src_stage;
barrier.srcAccessMask = s_color_feedback_src_access;
barrier.image = rt->GetImage();
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
@@ -6697,8 +6673,8 @@ void GSDeviceVK::FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds)
if (ds)
{
VkImageMemoryBarrier2& barrier = barriers[num_barriers++] = barrier_template;
barrier.srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
barrier.srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
barrier.srcStageMask = s_depth_feedback_src_stage;
barrier.srcAccessMask = s_depth_feedback_src_access;
barrier.image = ds->GetImage();
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
}
+8 -6
View File
@@ -89,8 +89,8 @@ public:
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);
VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE,
bool color_feedback_loop = false, bool depth_feedback_loop = false);
// Gets a non-clearing version of the specified render pass. Slow, don't call in hot path.
VkRenderPass GetRenderPassForRestarting(VkRenderPass pass);
@@ -176,7 +176,7 @@ private:
u32 stencil_load_op : 2;
u32 stencil_store_op : 1;
u32 color_feedback_loop : 1;
u32 depth_sampling : 1;
u32 depth_feedback_loop : 1;
};
u32 key;
@@ -545,10 +545,10 @@ public:
/// Returns true if Vulkan is suitable as a default for the devices in the system.
static bool IsSuitableDefaultRenderer();
__fi VkRenderPass GetTFXRenderPass(bool rt, bool ds, bool colclip, bool stencil, bool fbl, bool dsp,
VkAttachmentLoadOp rt_op, VkAttachmentLoadOp ds_op) const
__fi VkRenderPass GetTFXRenderPass(bool rt, bool ds, bool colclip, bool stencil,
bool rt_feedback, bool depth_feedback, VkAttachmentLoadOp rt_op, VkAttachmentLoadOp ds_op) const
{
return m_tfx_render_pass[rt][ds][colclip][stencil][fbl][dsp][rt_op][ds_op];
return m_tfx_render_pass[rt][ds][colclip][stencil][rt_feedback][depth_feedback][rt_op][ds_op];
}
__fi VkSampler GetPointSampler() const { return m_point_sampler; }
__fi VkSampler GetLinearSampler() const { return m_linear_sampler; }
@@ -687,7 +687,9 @@ public:
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const VkClearValue* cv, u32 cv_count);
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color);
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, float depth, u8 stencil);
bool BeginPresentRenderPass(VkRenderPass rp, const GSVector4i& rect, GSTextureVK* swap_chain);
void EndRenderPass();
void EndPresentRenderPass();
void SetViewport(const VkViewport& viewport);
void SetScissor(const GSVector4i& scissor);
+1 -1
View File
@@ -35,7 +35,7 @@ static constexpr const VkComponentMapping s_identity_swizzle {
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
};
static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout)
VkImageLayout GSTextureVK::GetVkImageLayout(GSTextureVK::Layout layout)
{
static constexpr VkImageLayout s_vk_layout_mapping[] = {
VK_IMAGE_LAYOUT_UNDEFINED, // Undefined
+2
View File
@@ -36,6 +36,8 @@ public:
~GSTextureVK() override;
static VkImageLayout GetVkImageLayout(Layout layout);
static std::unique_ptr<GSTextureVK> Create(Usage usage, Format format, int width, int height, int levels);
static std::unique_ptr<GSTextureVK> Adopt(
VkImage image, Usage usage, Format format, int width, int height, int levels, VkFormat vk_format);
+172 -90
View File
@@ -115,6 +115,178 @@ void Vulkan::LogVulkanResult(const char* func_name, VkResult res, const char* ms
Console.Error("(%s) %s (%d: %s)", func_name, real_msg.c_str(), static_cast<int>(res), VkResultToString(res));
}
void Vulkan::RenderPassBuilder::SetColorFeedbackBarrier(
VkPipelineStageFlags src_stage, VkAccessFlags src_access,
VkPipelineStageFlags dst_stage, VkAccessFlags dst_access,
VkDependencyFlags dependency)
{
m_feedback_barriers.color_src_stage = src_stage;
m_feedback_barriers.color_src_access = src_access;
m_feedback_barriers.color_dst_stage = dst_stage;
m_feedback_barriers.color_dst_access = dst_access;
m_feedback_barriers.color_dependency = dependency;
}
void Vulkan::RenderPassBuilder::SetDepthFeedbackBarrier(
VkPipelineStageFlags src_stage, VkAccessFlags src_access,
VkPipelineStageFlags dst_stage, VkAccessFlags dst_access,
VkDependencyFlags dependency)
{
m_feedback_barriers.depth_src_stage = src_stage;
m_feedback_barriers.depth_src_access = src_access;
m_feedback_barriers.depth_dst_stage = dst_stage;
m_feedback_barriers.depth_dst_access = dst_access;
m_feedback_barriers.depth_dependency = dependency;
}
void Vulkan::RenderPassBuilder::AddColorAttachment(
VkImageLayout layout, VkFormat format, VkAttachmentLoadOp load_op, VkAttachmentStoreOp store_op,
bool feedback_loop, bool input_reference, bool subpass_self_dependency)
{
pxAssert(m_num_color_attachments < MAX_COLOR_ATTACHMENTS);
m_attachments[m_num_attachments].flags = 0;
m_attachments[m_num_attachments].format = format;
m_attachments[m_num_attachments].samples = VK_SAMPLE_COUNT_1_BIT;
m_attachments[m_num_attachments].loadOp = load_op;
m_attachments[m_num_attachments].storeOp = store_op;
m_attachments[m_num_attachments].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
m_attachments[m_num_attachments].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
m_attachments[m_num_attachments].initialLayout = layout;
m_attachments[m_num_attachments].finalLayout = layout;
m_color_reference[m_num_color_attachments].attachment = m_num_attachments;
m_color_reference[m_num_color_attachments].layout = layout;
m_num_color_attachments++;
if (feedback_loop)
{
if (input_reference)
{
m_input_reference[m_num_subpass_inputs].attachment = m_num_attachments;
m_input_reference[m_num_subpass_inputs].layout = layout;
m_num_subpass_inputs++;
}
if (subpass_self_dependency)
{
m_subpass_dependency[m_num_subpass_dependencies].srcSubpass = 0;
m_subpass_dependency[m_num_subpass_dependencies].dstSubpass = 0;
m_subpass_dependency[m_num_subpass_dependencies].srcStageMask = m_feedback_barriers.color_src_stage;
m_subpass_dependency[m_num_subpass_dependencies].dstStageMask = m_feedback_barriers.color_dst_stage;
m_subpass_dependency[m_num_subpass_dependencies].srcAccessMask = m_feedback_barriers.color_src_access;
m_subpass_dependency[m_num_subpass_dependencies].dstAccessMask = m_feedback_barriers.color_dst_access;
m_subpass_dependency[m_num_subpass_dependencies].dependencyFlags = m_feedback_barriers.color_dependency;
m_num_subpass_dependencies++;
}
}
m_num_attachments++;
}
void Vulkan::RenderPassBuilder::AddDepthStencilAttachment(
VkImageLayout layout, VkFormat depth_format, VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op,
VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op,
bool feedback_loop, bool input_reference, bool subpass_self_dependency)
{
pxAssert(m_num_attachments < std::size(m_attachments));
m_attachments[m_num_attachments].flags = 0;
m_attachments[m_num_attachments].format = depth_format;
m_attachments[m_num_attachments].samples = VK_SAMPLE_COUNT_1_BIT;
m_attachments[m_num_attachments].loadOp = depth_load_op;
m_attachments[m_num_attachments].storeOp = depth_store_op;
m_attachments[m_num_attachments].stencilLoadOp = stencil_load_op;
m_attachments[m_num_attachments].stencilStoreOp = stencil_store_op;
m_attachments[m_num_attachments].initialLayout = layout;
m_attachments[m_num_attachments].finalLayout = layout;
pxAssert(!m_has_depth_attachment);
m_depth_reference.attachment = m_num_attachments;
m_depth_reference.layout = layout;
m_has_depth_attachment = true;
if (feedback_loop)
{
if (input_reference)
{
m_input_reference[m_num_subpass_inputs].attachment = m_num_attachments;
m_input_reference[m_num_subpass_inputs].layout = layout;
m_num_subpass_inputs++;
}
if (subpass_self_dependency)
{
m_subpass_dependency[m_num_subpass_dependencies].srcSubpass = 0;
m_subpass_dependency[m_num_subpass_dependencies].dstSubpass = 0;
m_subpass_dependency[m_num_subpass_dependencies].srcStageMask = m_feedback_barriers.depth_src_stage;
m_subpass_dependency[m_num_subpass_dependencies].dstStageMask = m_feedback_barriers.depth_dst_stage;
m_subpass_dependency[m_num_subpass_dependencies].srcAccessMask = m_feedback_barriers.depth_src_access;
m_subpass_dependency[m_num_subpass_dependencies].dstAccessMask = m_feedback_barriers.depth_dst_access;
m_subpass_dependency[m_num_subpass_dependencies].dependencyFlags = m_feedback_barriers.depth_dependency;
m_num_subpass_dependencies++;
}
}
m_num_attachments++;
}
void Vulkan::RenderPassBuilder::AddSubpassFlags(VkSubpassDescriptionFlags subpass_flags)
{
m_subpass_flags |= subpass_flags;
}
VkRenderPass Vulkan::RenderPassBuilder::Create(VkDevice device)
{
VkSubpassDescription subpass = {};
subpass.flags = m_subpass_flags;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount = m_num_subpass_inputs;
subpass.pInputAttachments = m_input_reference.data();
subpass.colorAttachmentCount = m_num_color_attachments;
subpass.pColorAttachments = m_color_reference.data();
subpass.pDepthStencilAttachment = m_has_depth_attachment ? &m_depth_reference : nullptr;
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
pass_info.attachmentCount = m_num_attachments;
pass_info.pAttachments = m_attachments.data();
pass_info.subpassCount = 1u;
pass_info.pSubpasses = &subpass;
pass_info.dependencyCount = m_num_subpass_dependencies;
pass_info.pDependencies = m_subpass_dependency.data();
VkRenderPass pass;
const VkResult res = vkCreateRenderPass(device, &pass_info, nullptr, &pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass() failed: ");
}
return pass;
}
void Vulkan::RenderPassBuilder::Clear()
{
m_color_reference = {};
m_num_color_attachments = 0;
m_depth_reference = {};
m_has_depth_attachment = false;
m_input_reference = {};
m_num_subpass_inputs = 0;
m_subpass_dependency = {};
m_num_subpass_dependencies = 0;
m_attachments = {};
m_num_attachments = 0;
m_feedback_barriers = {};
m_subpass_flags = 0;
}
Vulkan::DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder()
{
Clear();
@@ -957,96 +1129,6 @@ void Vulkan::FramebufferBuilder::SetRenderPass(VkRenderPass render_pass)
m_ci.renderPass = render_pass;
}
Vulkan::RenderPassBuilder::RenderPassBuilder()
{
Clear();
}
void Vulkan::RenderPassBuilder::Clear()
{
m_ci = {};
m_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
m_attachments = {};
m_attachment_references = {};
m_num_attachment_references = 0;
m_subpasses = {};
}
VkRenderPass Vulkan::RenderPassBuilder::Create(VkDevice device, bool clear /*= true*/)
{
VkRenderPass rp;
VkResult res = vkCreateRenderPass(device, &m_ci, nullptr, &rp);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass() failed: ");
return VK_NULL_HANDLE;
}
return rp;
}
u32 Vulkan::RenderPassBuilder::AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load_op,
VkAttachmentStoreOp store_op, VkImageLayout initial_layout, VkImageLayout final_layout)
{
pxAssert(m_ci.attachmentCount < MAX_ATTACHMENTS);
const u32 index = m_ci.attachmentCount;
VkAttachmentDescription& ad = m_attachments[index];
ad.format = format;
ad.samples = samples;
ad.loadOp = load_op;
ad.storeOp = store_op;
ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
ad.initialLayout = initial_layout;
ad.finalLayout = final_layout;
m_ci.attachmentCount++;
m_ci.pAttachments = m_attachments.data();
return index;
}
u32 Vulkan::RenderPassBuilder::AddSubpass()
{
pxAssert(m_ci.subpassCount < MAX_SUBPASSES);
const u32 index = m_ci.subpassCount;
VkSubpassDescription& sp = m_subpasses[index];
sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
m_ci.subpassCount++;
m_ci.pSubpasses = m_subpasses.data();
return index;
}
void Vulkan::RenderPassBuilder::AddSubpassColorAttachment(u32 subpass, u32 attachment, VkImageLayout layout)
{
pxAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES);
VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++];
ar.attachment = attachment;
ar.layout = layout;
VkSubpassDescription& sp = m_subpasses[subpass];
if (sp.colorAttachmentCount == 0)
sp.pColorAttachments = &ar;
sp.colorAttachmentCount++;
}
void Vulkan::RenderPassBuilder::AddSubpassDepthAttachment(u32 subpass, u32 attachment, VkImageLayout layout)
{
pxAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES);
VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++];
ar.attachment = attachment;
ar.layout = layout;
VkSubpassDescription& sp = m_subpasses[subpass];
sp.pDepthStencilAttachment = &ar;
}
Vulkan::BufferViewBuilder::BufferViewBuilder()
{
Clear();
+64 -31
View File
@@ -25,6 +25,70 @@ namespace Vulkan
const char* VkResultToString(VkResult res);
void LogVulkanResult(const char* func_name, VkResult res, const char* msg, ...);
// Only allows single subpass render passes.
class RenderPassBuilder
{
public:
static constexpr u32 MAX_COLOR_ATTACHMENTS = 1;
static constexpr u32 MAX_ATTACHMENTS = MAX_COLOR_ATTACHMENTS + 1;
void AddColorAttachment(VkImageLayout layout, VkFormat format,
VkAttachmentLoadOp load_op, VkAttachmentStoreOp store_op,
bool feedback_loop, bool input_reference, bool subpass_self_dependency);
void AddDepthStencilAttachment(VkImageLayout layout, VkFormat depth_format,
VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op,
VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op,
bool feedback_loop, bool input_reference, bool subpass_self_dependency);
void SetColorFeedbackBarrier(
VkPipelineStageFlags src_stage, VkAccessFlags src_access,
VkPipelineStageFlags dst_stage, VkAccessFlags dst_access,
VkDependencyFlags dependency);
void SetDepthFeedbackBarrier(
VkPipelineStageFlags src_stage, VkAccessFlags src_access,
VkPipelineStageFlags dst_stage, VkAccessFlags dst_access,
VkDependencyFlags dependency);
void AddSubpassFlags(VkSubpassDescriptionFlags subpass_flags);
void Clear();
VkRenderPass Create(VkDevice device);
private:
std::array<VkAttachmentReference, MAX_COLOR_ATTACHMENTS> m_color_reference{};
u32 m_num_color_attachments = 0;
VkAttachmentReference m_depth_reference{};
bool m_has_depth_attachment = false;
std::array<VkAttachmentReference, MAX_ATTACHMENTS> m_input_reference{};
u32 m_num_subpass_inputs = 0;
std::array<VkSubpassDependency, MAX_ATTACHMENTS> m_subpass_dependency{};
u32 m_num_subpass_dependencies = 0;
std::array<VkAttachmentDescription, MAX_ATTACHMENTS> m_attachments{};
u32 m_num_attachments = 0;
VkSubpassDescriptionFlags m_subpass_flags = 0;
struct
{
VkPipelineStageFlags color_src_stage;
VkAccessFlags color_src_access;
VkPipelineStageFlags color_dst_stage;
VkAccessFlags color_dst_access;
VkDependencyFlags color_dependency;
VkPipelineStageFlags depth_src_stage;
VkAccessFlags depth_src_access;
VkPipelineStageFlags depth_dst_stage;
VkAccessFlags depth_dst_access;
VkDependencyFlags depth_dependency;
} m_feedback_barriers{};
};
class DescriptorSetLayoutBuilder
{
public:
@@ -293,37 +357,6 @@ namespace Vulkan
std::array<VkImageView, MAX_ATTACHMENTS> m_images;
};
class RenderPassBuilder
{
enum : u32
{
MAX_ATTACHMENTS = 2,
MAX_ATTACHMENT_REFERENCES = 2,
MAX_SUBPASSES = 1,
};
public:
RenderPassBuilder();
void Clear();
VkRenderPass Create(VkDevice device, bool clear = true);
u32 AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load_op,
VkAttachmentStoreOp store_op, VkImageLayout initial_layout, VkImageLayout final_layout);
u32 AddSubpass();
void AddSubpassColorAttachment(u32 subpass, u32 attachment, VkImageLayout layout);
void AddSubpassDepthAttachment(u32 subpass, u32 attachment, VkImageLayout layout);
private:
VkRenderPassCreateInfo m_ci;
std::array<VkAttachmentDescription, MAX_ATTACHMENTS> m_attachments;
std::array<VkAttachmentReference, MAX_ATTACHMENT_REFERENCES> m_attachment_references;
u32 m_num_attachment_references = 0;
std::array<VkSubpassDescription, MAX_SUBPASSES> m_subpasses;
};
class BufferViewBuilder
{
public: