Vulkan: Experimental barrier skip when the game does not request it
Some checks failed
Build check / build (push) Has been cancelled
Generate translation template / generate-pot (push) Has been cancelled

This commit is contained in:
Exzap
2026-09-10 02:35:50 +02:00
parent 57c89d62c1
commit 3310f3b8b1
6 changed files with 24 additions and 6 deletions

View File

@@ -214,6 +214,10 @@ LatteCMDPtr LatteCP_itSurfaceSync(LatteCMDPtr cmd)
MPTR addressPhys = LatteReadCMD() << 8;
uint32 pollInterval = LatteReadCMD();
// let the renderer know about colorbuffer invalidation
if (static_cast<uint32>(invalidationFlags & (Latte::E_COHER_CNTL::CB_ACTION_ENA | Latte::E_COHER_CNTL::CB_ALL_DEST_BASE_ENA)) != 0)
g_renderer->SurfaceSync(invalidationFlags, addressPhys, size);
if (addressPhys == MPTR_NULL || size == 0xFFFFFFFF)
return cmd; // block global invalidations because they are too expensive

View File

@@ -359,7 +359,7 @@ namespace Latte
SO1_DEST_BASE_ENA = (1<<3),
SO2_DEST_BASE_ENA = (1<<4),
SO3_DEST_BASE_ENA = (1<<5),
CB0_DEST_BASE_ENA = (1<<6),
CB0_DEST_BASE_ENA = (1<<6), // flush color buffer 0
CB1_DEST_BASE_ENA = (1<<7),
CB2_DEST_BASE_ENA = (1<<8),
CB3_DEST_BASE_ENA = (1<<9),
@@ -367,6 +367,8 @@ namespace Latte
CB5_DEST_BASE_ENA = (1<<11),
CB6_DEST_BASE_ENA = (1<<12),
CB7_DEST_BASE_ENA = (1<<13),
CB_ALL_DEST_BASE_ENA = (0xFF<<6), // CB0-CB7 combined
DB_DEST_BASE_ENA = (1<<14),
FULL_CACHE_ENA = (1<<20),

View File

@@ -82,6 +82,7 @@ public:
// flush control
virtual void Flush(bool waitIdle = false) = 0; // called when explicit flush is required (e.g. by imgui)
virtual void NotifyLatteCommandProcessorIdle() = 0; // called when command processor has no more commands available or when stalled
virtual void SurfaceSync(Latte::E_COHER_CNTL coher, MPTR address, uint32 size) {} // triggered by game via GX2Invalidate, can be utilized by the render backend as an optimization hint
// imgui
virtual bool ImguiBegin(bool mainWindow);

View File

@@ -240,6 +240,7 @@ public:
void Flush(bool waitIdle = false) override;
void NotifyLatteCommandProcessorIdle() override;
void SurfaceSync(Latte::E_COHER_CNTL coher, MPTR address, uint32 size) override;
uint64 GenUniqueId(); // return unique id (uses incrementing counter)
@@ -419,6 +420,7 @@ private:
// invalidation / flushing
uint64 currentFlushIndex{0};
bool colorBufferSyncPending{false}; // guest color-buffer sync since the previous draw; survives command-buffer resets
bool requestFlush{ false }; // flush after every draw operation. The renderpass dependencies dont handle dependencies across multiple drawcalls inside a single renderpass
// draw sequence

View File

@@ -995,6 +995,12 @@ VkDescriptorSetInfo* VulkanRenderer::draw_getOrCreateDescriptorSet(PipelineInfo*
return dsInfo;
}
void VulkanRenderer::SurfaceSync(Latte::E_COHER_CNTL coher, MPTR address, uint32 size)
{
if (static_cast<uint32>(coher & Latte::E_COHER_CNTL::CB_ALL_DEST_BASE_ENA) != 0)
m_state.colorBufferSyncPending = true;
}
void VulkanRenderer::sync_inputTexturesChanged(bool withinFeedbackLoopRenderPass)
{
bool writeFlushRequired = withinFeedbackLoopRenderPass; // feedback loop still requires us to emit a barrier
@@ -1029,6 +1035,12 @@ void VulkanRenderer::sync_inputTexturesChanged(bool withinFeedbackLoopRenderPass
// barrier here
if (writeFlushRequired)
{
// Continued draws with unchanged descriptors in the same renderpass only introduce feedback hazards.
// Relax color feedback without a guest sync, but keep the read indices above updated for later passes.
if (withinFeedbackLoopRenderPass && !m_state.descriptorSetsChanged && !m_state.colorBufferSyncPending
&& m_state.m_curRenderpassSelfDependencyInfo.GetAspectMask() == VK_IMAGE_ASPECT_COLOR_BIT)
return;
VkMemoryBarrier memoryBarrier{};
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memoryBarrier.srcAccessMask = 0;
@@ -1740,6 +1752,7 @@ void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
draw_execute_first(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType, drawcallContext);
else
draw_execute_continued(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType, drawcallContext);
m_state.colorBufferSyncPending = false;
LatteGPUState.drawCallCounter++;
}

View File

@@ -286,11 +286,7 @@ namespace GX2
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_COLOR_BUFFER))
{
coherCntl |= Latte::E_COHER_CNTL::CB_ACTION_ENA
| Latte::E_COHER_CNTL::CB0_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB1_DEST_BASE_ENA
| Latte::E_COHER_CNTL::CB2_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB3_DEST_BASE_ENA
| Latte::E_COHER_CNTL::CB4_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB5_DEST_BASE_ENA
| Latte::E_COHER_CNTL::CB6_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB7_DEST_BASE_ENA;
coherCntl |= Latte::E_COHER_CNTL::CB_ACTION_ENA | Latte::E_COHER_CNTL::CB_ALL_DEST_BASE_ENA;
}
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_DEPTH_BUFFER))