Skip to content

Commit 3bbcf05

Browse files
committed
Guard acquire-semaphore reuse before re-acquire (VUID-01779)
Secondary swapchains presented via vhPresentSwapchain reused an acquire semaphore slot whose prior GPU wait could still be in flight, tripping VUID-vkAcquireNextImageKHR-semaphore-01779. Track the graphics-queue timeline instance per acquire slot (acquireInstances, parallel to acquireSemaphores) and vkWaitSemaphores on the previous instance before reusing the slot. Mirrors the primary frame-instance wait but lives on each swapchain, so it covers primary and secondaries alike. The global frame-instance pacing is kept: it bounds in-flight flushes to g_vhFramesInFlight, which the transient uniform ring (sized to VRHI_MAX_FRAMES_INFLIGHT) depends on. Also drain the backend (vhFlush(true)) at the top of vhPresentSwapchain so the present path does not submit before the frame's recorded draws, making it symmetric with vhFrame.
1 parent 0ac8364 commit 3bbcf05

3 files changed

Lines changed: 27 additions & 0 deletions

File tree

src/vrhi_device.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,7 @@ void vhSwapchainCreate_Internal( vhSwapchain& sc, int width, int height )
16081608
int newImageCount = ( int ) sc.images.size();
16091609
int acquireSemaphoreCount = std::max( newImageCount, ( int ) g_vhFramesInFlight );
16101610
sc.acquireSemaphores.resize( acquireSemaphoreCount );
1611+
sc.acquireInstances.assign( acquireSemaphoreCount, 0 );
16111612
sc.presentSemaphores.resize( newImageCount );
16121613

16131614
VkSemaphoreCreateInfo sci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
@@ -1630,6 +1631,7 @@ void vhSwapchainDestroy_Internal( vhSwapchain& sc )
16301631
vkDestroySemaphore( g_vulkanDevice, sem, nullptr );
16311632
}
16321633
sc.acquireSemaphores.clear();
1634+
sc.acquireInstances.clear();
16331635
sc.presentSemaphores.clear();
16341636

16351637
for ( vhTexture texture : sc.textures )
@@ -1675,6 +1677,7 @@ bool vhSwapchainPresentAndAcquire_Internal( vhSwapchain& sc, uint64_t& outInstan
16751677
}
16761678

16771679
outInstance = vhCmdListFlush( nvrhi::CommandQueue::Graphics );
1680+
sc.acquireInstances[sc.acquireSemaphoreIndex] = outInstance;
16781681

16791682
VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
16801683
presentInfo.waitSemaphoreCount = 1;
@@ -1699,6 +1702,24 @@ bool vhSwapchainPresentAndAcquire_Internal( vhSwapchain& sc, uint64_t& outInstan
16991702

17001703
sc.acquireSemaphoreIndex = ( sc.acquireSemaphoreIndex + 1 ) % sc.acquireSemaphores.size();
17011704

1705+
// VUID-vkAcquireNextImageKHR-semaphore-01779: the acquire semaphore being reused must be idle.
1706+
uint64_t prevInstance = sc.acquireInstances[sc.acquireSemaphoreIndex];
1707+
if ( prevInstance )
1708+
{
1709+
VkSemaphore queueSem;
1710+
{
1711+
std::lock_guard< std::mutex > lock( g_nvRHIStateMutex );
1712+
queueSem = nvrhiDevice->getQueueSemaphore( nvrhi::CommandQueue::Graphics );
1713+
}
1714+
VkSemaphoreWaitInfo waitInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO };
1715+
waitInfo.semaphoreCount = 1;
1716+
waitInfo.pSemaphores = &queueSem;
1717+
waitInfo.pValues = &prevInstance;
1718+
vhProfile( "vhFrame_WaitSemaphore", true );
1719+
vkWaitSemaphores( g_vulkanDevice, &waitInfo, UINT64_MAX );
1720+
vhProfile( "vhFrame_WaitSemaphore", false );
1721+
}
1722+
17021723
// Acquire next image for this swapchain.
17031724
uint32_t idx = 0;
17041725
vhProfile( "vhFrame_AcquireNextImage", true );
@@ -1909,6 +1930,8 @@ bool vhPresentSwapchain( vhSwapchainID swapchain )
19091930
{
19101931
auto it = g_vhSwapchains.find( swapchain );
19111932
if ( it == g_vhSwapchains.end() ) return false;
1933+
// Drain backend so the main thread can use the same nvrhi command list for swapchain semaphore ops below.
1934+
vhFlush( true );
19121935
uint64_t instance;
19131936
return vhSwapchainPresentAndAcquire_Internal( it->second, instance );
19141937
}

src/vrhi_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ struct vhSwapchain
272272
std::vector< vhTexture > textures;
273273
std::vector< nvrhi::TextureHandle > nvrhiHandles;
274274
std::vector< VkSemaphore > acquireSemaphores;
275+
std::vector< uint64_t > acquireInstances;
275276
std::vector< VkSemaphore > presentSemaphores;
276277
uint32_t currentSwapchainIndex = 0;
277278
uint32_t acquireSemaphoreIndex = 0;

test/test_window.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,9 @@ UTEST( Swapchain, SemaphoreArraysCoverFrameSlots )
10031003
EXPECT_TRUE( vhFrame() );
10041004
}
10051005

1006+
for ( uint64_t inst : g_vhSwapchains[sc].acquireInstances )
1007+
EXPECT_GT( inst, 0ull );
1008+
10061009
vhDestroySwapchain( sc );
10071010
TestEnsureShutdown();
10081011
RGFW_window_close( secondary );

0 commit comments

Comments
 (0)