@@ -163,22 +163,42 @@ vk::CommandBuffer GPUDisplayBackendVulkan::getSingleTimeCommandBuffer()
163163 return commandBuffer;
164164}
165165
166+ template <class ... Args>
167+ uint64_t GPUDisplayBackendVulkan::queueSubmit (uint64_t * timelineSignalValue, Args&&... args)
168+ {
169+ std::lock_guard<std::mutex> guard (mQueueMutex );
170+ if (timelineSignalValue) {
171+ *timelineSignalValue = ++mTimelineValue ;
172+ }
173+ CHKERR (mGraphicsQueue .submit (std::forward<Args>(args)...));
174+ return mTimelineValue ;
175+ }
176+
166177void GPUDisplayBackendVulkan::submitSingleTimeCommandBuffer (vk::CommandBuffer commandBuffer)
167178{
168179 commandBuffer.end ();
169180 vk::SubmitInfo submitInfo{};
170181 submitInfo.commandBufferCount = 1 ;
171182 submitInfo.pCommandBuffers = &commandBuffer;
172- static std::mutex fenceMutex;
173- {
174- std::lock_guard<std::mutex> guard (fenceMutex);
175- CHKERR (mGraphicsQueue .submit (1 , &submitInfo, mSingleCommitFence ));
176- CHKERR (mDevice .waitForFences (1 , &mSingleCommitFence , true , UINT64_MAX ));
177- CHKERR (mDevice .resetFences (1 , &mSingleCommitFence ));
178- }
183+ uint64_t signalValue;
184+ vk::TimelineSemaphoreSubmitInfo timelineInfo{};
185+ timelineInfo.signalSemaphoreValueCount = 1 ;
186+ timelineInfo.pSignalSemaphoreValues = &signalValue;
187+ submitInfo.pNext = &timelineInfo;
188+ submitInfo.signalSemaphoreCount = 1 ;
189+ submitInfo.pSignalSemaphores = &mTimelineSemaphore ;
190+ waitTimeline (queueSubmit (&signalValue, 1 , &submitInfo, VkFence (VK_NULL_HANDLE )));
179191 mDevice .freeCommandBuffers (mCommandPool , 1 , &commandBuffer);
180192}
181193
194+ void GPUDisplayBackendVulkan::waitTimeline (uint64_t value)
195+ {
196+ if (value) {
197+ vk::SemaphoreWaitInfo waitInfo{{}, 1 , &mTimelineSemaphore , &value};
198+ CHKERR (mDevice .waitSemaphores (&waitInfo, UINT64_MAX ));
199+ }
200+ }
201+
182202static vk::ImageView createImageViewI (vk::Device device, vk::Image image, vk::Format format, vk::ImageAspectFlags aspectFlags = vk::ImageAspectFlagBits::eColor, uint32_t mipLevels = 1 )
183203{
184204 vk::ImageViewCreateInfo viewInfo{};
@@ -477,6 +497,7 @@ void GPUDisplayBackendVulkan::createDevice()
477497 clearFeatures (reqDeviceFeatures);
478498 auto & reqFeatures10 = reqDeviceFeatures.get <vk::PhysicalDeviceFeatures2>().features ;
479499 reqFeatures10.geometryShader = reqFeatures10.wideLines = reqFeatures10.largePoints = reqFeatures10.multiDrawIndirect = VK_TRUE ;
500+ reqDeviceFeatures.get <vk::PhysicalDeviceVulkan12Features>().timelineSemaphore = VK_TRUE ;
480501 reqDeviceFeatures.get <vk::PhysicalDeviceSwapchainMaintenance1FeaturesKHR>().swapchainMaintenance1 = VK_TRUE ;
481502 reqDeviceFeatures.get <vk::PhysicalDevicePresentIdFeaturesKHR>().presentId = VK_TRUE ;
482503 reqDeviceFeatures.get <vk::PhysicalDevicePresentWaitFeaturesKHR>().presentWait = VK_TRUE ;
@@ -583,33 +604,30 @@ void GPUDisplayBackendVulkan::clearCommandBuffers()
583604
584605// ---------------------------- VULKAN SEMAPHORES AND FENCES ----------------------------
585606
586- void GPUDisplayBackendVulkan::createSemaphoresAndFences ()
607+ void GPUDisplayBackendVulkan::createSemaphores ()
587608{
588609 vk::SemaphoreCreateInfo semaphoreInfo{};
589- vk::FenceCreateInfo fenceInfo{};
590- fenceInfo.flags = vk::FenceCreateFlagBits::eSignaled;
591610 mImageAvailableSemaphore .resize (mFramesInFlight );
592611 mPresentSemaphore .resize (mImageCount );
593- mInFlightFence .resize (mFramesInFlight );
594- mImageFence .resize (mImageCount );
595612 for (uint32_t i = 0 ; i < mFramesInFlight ; i++) {
596613 mImageAvailableSemaphore [i] = mDevice .createSemaphore (semaphoreInfo, nullptr );
597- mInFlightFence [i] = mDevice .createFence (fenceInfo, nullptr );
598614 }
599615 for (uint32_t i = 0 ; i < mImageCount ; i++) {
600616 mPresentSemaphore [i] = mDevice .createSemaphore (semaphoreInfo, nullptr );
601- mImageFence [i] = VkFence (VK_NULL_HANDLE );
602617 }
603- fenceInfo.flags = {};
604- mSingleCommitFence = mDevice .createFence (fenceInfo, nullptr );
618+ vk::SemaphoreTypeCreateInfo timelineTypeInfo{vk::SemaphoreType::eTimeline, 0 };
619+ semaphoreInfo.pNext = &timelineTypeInfo;
620+ mTimelineSemaphore = mDevice .createSemaphore (semaphoreInfo, nullptr );
621+ mTimelineValue = 0 ;
622+ mFrameTimelineValue .assign (mFramesInFlight , 0 );
623+ mImageTimelineValue .assign (mImageCount , 0 );
605624}
606625
607- void GPUDisplayBackendVulkan::clearSemaphoresAndFences ()
626+ void GPUDisplayBackendVulkan::clearSemaphores ()
608627{
609628 clearVector (mImageAvailableSemaphore , [&](auto & x) { mDevice .destroySemaphore (x, nullptr ); });
610629 clearVector (mPresentSemaphore , [&](auto & x) { mDevice .destroySemaphore (x, nullptr ); });
611- clearVector (mInFlightFence , [&](auto & x) { mDevice .destroyFence (x, nullptr ); });
612- mDevice .destroyFence (mSingleCommitFence , nullptr );
630+ mDevice .destroySemaphore (mTimelineSemaphore , nullptr );
613631}
614632
615633// ---------------------------- VULKAN UNIFORM LAYOUTS AND BUFFERS ----------------------------
@@ -802,11 +820,11 @@ void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing
802820 if (mCommandInfrastructureCreated ) {
803821 clearUniformLayoutsAndBuffers (); // TODO: Check what must actually be cleaned up if frames in flight changes
804822 clearCommandBuffers ();
805- clearSemaphoresAndFences ();
823+ clearSemaphores ();
806824 }
807825 createUniformLayoutsAndBuffers ();
808826 createCommandBuffers ();
809- createSemaphoresAndFences ();
827+ createSemaphores ();
810828 mCommandInfrastructureCreated = true ;
811829 }
812830
@@ -1468,7 +1486,7 @@ void GPUDisplayBackendVulkan::ExitBackendA()
14681486 clearOffscreenBuffers ();
14691487 clearSwapChain ();
14701488 if (mCommandInfrastructureCreated ) {
1471- clearSemaphoresAndFences ();
1489+ clearSemaphores ();
14721490 clearCommandBuffers ();
14731491 clearUniformLayoutsAndBuffers ();
14741492 }
@@ -1539,7 +1557,7 @@ void GPUDisplayBackendVulkan::prepareDraw(const hmm_mat4& proj, const hmm_mat4&
15391557
15401558 if (includeMixImage == 0 .f ) {
15411559 mCurrentFrame = (mCurrentFrame + 1 ) % mFramesInFlight ;
1542- CHKERR ( mDevice . waitForFences ( 1 , & mInFlightFence [mCurrentFrame ], true , UINT64_MAX ) );
1560+ waitTimeline ( mFrameTimelineValue [mCurrentFrame ]);
15431561 auto getImage = [&]() {
15441562 return mDevice .acquireNextImageKHR (mSwapChain , UINT64_MAX , mImageAvailableSemaphore [mCurrentFrame ], VkFence (VK_NULL_HANDLE ), &mCurrentImageIndex );
15451563 };
@@ -1558,11 +1576,7 @@ void GPUDisplayBackendVulkan::prepareDraw(const hmm_mat4& proj, const hmm_mat4&
15581576 }
15591577 mMustUpdateSwapChain = retVal == vk::Result::eSuboptimalKHR;
15601578 CHKERR (retVal);
1561- if (mImageFence [mCurrentImageIndex ]) {
1562- CHKERR (mDevice .waitForFences (1 , &mImageFence [mCurrentImageIndex ], true , UINT64_MAX ));
1563- }
1564- mImageFence [mCurrentImageIndex ] = mInFlightFence [mCurrentFrame ];
1565- CHKERR (mDevice .resetFences (1 , &mInFlightFence [mCurrentFrame ]));
1579+ waitTimeline (mImageTimelineValue [mCurrentImageIndex ]); // Previous frame using this image's resources (command buffers, uniform buffer, ...) finished
15661580
15671581 mHasDrawnText = false ;
15681582 mFrameCommandBuffers .clear ();
@@ -1608,7 +1622,7 @@ void GPUDisplayBackendVulkan::finishFrame(bool doScreenshot, bool toMixBuffer, f
16081622 if (doScreenshot) {
16091623 submitInfo.commandBufferCount = mFrameCommandBuffers .size ();
16101624 submitInfo.pCommandBuffers = mFrameCommandBuffers .data ();
1611- CHKERR ( mGraphicsQueue . submit ( 1 , &submitInfo, VkFence (VK_NULL_HANDLE ) ));
1625+ queueSubmit ( nullptr , 1 , &submitInfo, VkFence (VK_NULL_HANDLE ));
16121626 mDevice .waitIdle ();
16131627 if (mDisplay ->cfgR ().screenshotScaleFactor != 1 ) {
16141628 readImageToPixels (mDownsampleImages [mCurrentImageIndex ].image , vk::ImageLayout::eColorAttachmentOptimal, mScreenshotPixels );
@@ -1623,9 +1637,15 @@ void GPUDisplayBackendVulkan::finishFrame(bool doScreenshot, bool toMixBuffer, f
16231637 }
16241638 submitInfo.commandBufferCount = mFrameCommandBuffers .size ();
16251639 submitInfo.pCommandBuffers = mFrameCommandBuffers .data ();
1626- submitInfo.signalSemaphoreCount = 1 ;
1627- submitInfo.pSignalSemaphores = &mPresentSemaphore [mCurrentImageIndex ];
1628- CHKERR (mGraphicsQueue .submit (1 , &submitInfo, mInFlightFence [mCurrentFrame ]));
1640+ const vk::Semaphore signalSemaphores[2 ] = {mPresentSemaphore [mCurrentImageIndex ], mTimelineSemaphore };
1641+ uint64_t signalValues[2 ] = {0 , 0 }; // First value ignored for the binary present semaphore
1642+ vk::TimelineSemaphoreSubmitInfo timelineInfo{};
1643+ timelineInfo.signalSemaphoreValueCount = 2 ;
1644+ timelineInfo.pSignalSemaphoreValues = signalValues;
1645+ submitInfo.pNext = &timelineInfo;
1646+ submitInfo.signalSemaphoreCount = 2 ;
1647+ submitInfo.pSignalSemaphores = signalSemaphores;
1648+ mFrameTimelineValue [mCurrentFrame ] = mImageTimelineValue [mCurrentImageIndex ] = queueSubmit (&signalValues[1 ], 1 , &submitInfo, VkFence (VK_NULL_HANDLE ));
16291649
16301650 vk::PresentInfoKHR presentInfo{};
16311651 presentInfo.waitSemaphoreCount = 1 ;
0 commit comments