GS/VK: Restart present pass when uploading large textures

This commit is contained in:
TheLastRar
2026-03-20 13:03:57 +01:00
committed by lightningterror
parent 6aadbc18a9
commit faf6c04dee
3 changed files with 61 additions and 4 deletions
+34
View File
@@ -2408,6 +2408,7 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
{0, 0}, {static_cast<u32>(swap_chain_texture->GetWidth()), static_cast<u32>(swap_chain_texture->GetHeight())}};
vkCmdSetViewport(GetCurrentCommandBuffer(), 0, 1, &vp);
vkCmdSetScissor(GetCurrentCommandBuffer(), 0, 1, &scissor);
m_is_presenting = true;
return PresentResult::OK;
}
@@ -2417,6 +2418,7 @@ void GSDeviceVK::EndPresent()
VkCommandBuffer cmdbuffer = GetCurrentCommandBuffer();
vkCmdEndRenderPass(cmdbuffer);
m_is_presenting = false;
m_swap_chain->GetCurrentTexture()->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::PresentSrc);
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
@@ -2426,6 +2428,11 @@ void GSDeviceVK::EndPresent()
InvalidateCachedState();
}
bool GSDeviceVK::IsPresenting() const
{
return m_is_presenting;
}
#ifdef ENABLE_OGL_DEBUG
static std::array<float, 3> Palette(float phase, const std::array<float, 3>& a, const std::array<float, 3>& b,
const std::array<float, 3>& c, const std::array<float, 3>& d)
@@ -5108,6 +5115,33 @@ void GSDeviceVK::ExecuteCommandBufferAndRestartRenderPass(bool wait_for_completi
}
}
void GSDeviceVK::ExecuteCommandBufferAndRestartPresent(bool wait_for_completion, const char* reason, ...)
{
std::va_list ap;
va_start(ap, reason);
const std::string reason_str(StringUtil::StdStringFromFormatV(reason, ap));
va_end(ap);
Console.Warning("VK: Executing command buffer due to '%s'", reason_str.c_str());
pxAssert(m_is_presenting);
vkCmdEndRenderPass(GetCurrentCommandBuffer());
ExecuteCommandBuffer(wait_for_completion);
GSTextureVK* swap_chain_texture = m_swap_chain->GetCurrentTexture();
const VkFramebuffer fb = swap_chain_texture->GetFramebuffer(false);
pxAssert(fb);
const VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr,
GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE),
fb,
{{0, 0}, {static_cast<u32>(swap_chain_texture->GetWidth()), static_cast<u32>(swap_chain_texture->GetHeight())}},
0u, nullptr};
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
}
void GSDeviceVK::ExecuteCommandBufferForReadback()
{
ExecuteCommandBuffer(true);
+3
View File
@@ -372,6 +372,7 @@ public:
private:
std::unique_ptr<VKSwapChain> m_swap_chain;
bool m_resize_requested = false;
bool m_is_presenting = false;
VkDescriptorSetLayout m_utility_ds_layout = VK_NULL_HANDLE;
VkPipelineLayout m_utility_pipeline_layout = VK_NULL_HANDLE;
@@ -518,6 +519,7 @@ public:
PresentResult BeginPresent(bool frame_skip) override;
void EndPresent() override;
bool IsPresenting() const;
bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
@@ -593,6 +595,7 @@ public:
void ExecuteCommandBuffer(bool wait_for_completion);
void ExecuteCommandBuffer(bool wait_for_completion, const char* reason, ...);
void ExecuteCommandBufferAndRestartRenderPass(bool wait_for_completion, const char* reason);
void ExecuteCommandBufferAndRestartPresent(bool wait_for_completion, const char* reason, ...);
void ExecuteCommandBufferForReadback();
/// Set dirty flags on everything to force re-bind at next draw time.
+24 -4
View File
@@ -349,8 +349,18 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l
VKStreamBuffer& sbuffer = GSDeviceVK::GetInstance()->GetTextureUploadBuffer();
if (!sbuffer.ReserveMemory(required_size, GSDeviceVK::GetInstance()->GetBufferCopyOffsetAlignment()))
{
GSDeviceVK::GetInstance()->ExecuteCommandBuffer(
false, "While waiting for %u bytes in texture upload buffer", required_size);
GSDeviceVK* dev = GSDeviceVK::GetInstance();
if (!dev->IsPresenting())
{
dev->ExecuteCommandBuffer(
false, "While waiting for %u bytes in texture upload buffer", required_size);
}
else
{
dev->ExecuteCommandBufferAndRestartPresent(
false, "While waiting for %u bytes in texture upload buffer", required_size);
}
if (!sbuffer.ReserveMemory(required_size, GSDeviceVK::GetInstance()->GetBufferCopyOffsetAlignment()))
{
Console.Error("Failed to reserve texture upload memory (%u bytes).", required_size);
@@ -410,8 +420,18 @@ bool GSTextureVK::Map(GSMap& m, const GSVector4i* r, int layer)
if (!buffer.ReserveMemory(required_size, GSDeviceVK::GetInstance()->GetBufferCopyOffsetAlignment()))
{
GSDeviceVK::GetInstance()->ExecuteCommandBuffer(
false, "While waiting for %u bytes in texture upload buffer", required_size);
GSDeviceVK* dev = GSDeviceVK::GetInstance();
if (!dev->IsPresenting())
{
dev->ExecuteCommandBuffer(
false, "While waiting for %u bytes in texture upload buffer", required_size);
}
else
{
dev->ExecuteCommandBufferAndRestartPresent(
false, "While waiting for %u bytes in texture upload buffer", required_size);
}
if (!buffer.ReserveMemory(required_size, GSDeviceVK::GetInstance()->GetBufferCopyOffsetAlignment()))
pxFailRel("Failed to reserve texture upload memory");
}