@@ -169,6 +169,8 @@ namespace dxvk {
169169 VkResult Presenter::presentImage (uint64_t frameId, const Rc<DxvkLatencyTracker>& tracker) {
170170 PresenterSync& currSync = m_semaphores.at (m_frameIndex);
171171
172+ uint64_t frameDeadline = 0u ;
173+
172174 VkPresentIdKHR presentId = { VK_STRUCTURE_TYPE_PRESENT_ID_KHR };
173175 presentId.swapchainCount = 1 ;
174176 presentId.pPresentIds = &frameId;
@@ -185,6 +187,33 @@ namespace dxvk {
185187 modeInfo.swapchainCount = 1 ;
186188 modeInfo.pPresentModes = &m_presentMode;
187189
190+ VkPresentTimingInfoEXT timingInfo = { VK_STRUCTURE_TYPE_PRESENT_TIMING_INFO_EXT };
191+ timingInfo.presentStageQueries = m_timingMode.presentStage ;
192+
193+ if (m_timingMode.presentStage ) {
194+ std::lock_guard lock (m_timingMutex);
195+
196+ if (m_timingMode.relativeTiming ) {
197+ timingInfo.flags |= VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT;
198+ timingInfo.targetTime = m_timingMode.frameIntervalNs ;
199+ timingInfo.targetTimeDomainPresentStage = m_timingMode.presentStage ;
200+ timingInfo.timeDomainId = m_timingMode.timeDomainId ;
201+ } else if (m_timingMode.absoluteTiming && m_timingMode.referenceFrameId ) {
202+ frameDeadline = m_timingMode.referenceTime + (frameId - m_timingMode.referenceFrameId ) * m_timingMode.frameIntervalNs ;
203+
204+ timingInfo.targetTime = frameDeadline;
205+ timingInfo.targetTimeDomainPresentStage = m_timingMode.presentStage ;
206+ timingInfo.timeDomainId = m_timingMode.timeDomainId ;
207+
208+ if (m_timingDisplayInfo && !m_timingDisplayInfo->isVariableRefresh )
209+ timingInfo.flags |= VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT;
210+ }
211+ }
212+
213+ VkPresentTimingsInfoEXT timingsInfo = { VK_STRUCTURE_TYPE_PRESENT_TIMINGS_INFO_EXT };
214+ timingsInfo.swapchainCount = 1u ;
215+ timingsInfo.pTimingInfos = &timingInfo;
216+
188217 VkPresentInfoKHR info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
189218 info.waitSemaphoreCount = 1 ;
190219 info.pWaitSemaphores = &currSync.present ;
@@ -197,6 +226,9 @@ namespace dxvk {
197226 presentId2.pNext = const_cast <void *>(std::exchange (info.pNext , &presentId2));
198227 else
199228 presentId.pNext = const_cast <void *>(std::exchange (info.pNext , &presentId));
229+
230+ if (timingInfo.presentStageQueries )
231+ timingsInfo.pNext = std::exchange (info.pNext , &timingsInfo);
200232 }
201233
202234 if (m_hasSwapchainMaintenance1) {
@@ -241,6 +273,7 @@ namespace dxvk {
241273 frame.tracker = tracker;
242274 frame.mode = m_presentMode;
243275 frame.result = status;
276+ frame.deadline = frameDeadline;
244277
245278 pushFrame (frame);
246279 }
@@ -1456,6 +1489,7 @@ namespace dxvk {
14561489 if (m_timingMode.presentStage )
14571490 return false ;
14581491
1492+ // Need to access both timing stuff and the frame queue here
14591493 std::lock_guard lock (m_timingMutex);
14601494
14611495 // Still need to drain the queue even if everything is messed up
@@ -1503,8 +1537,11 @@ namespace dxvk {
15031537 if (updateMode)
15041538 updateTimingMode (presentMode);
15051539
1506- // Find latest available report and update present statistics
1507- bool hasValidReport = false ;
1540+ // Find latest available report and update present statistics. If we run
1541+ // absolute timing and any given frame missed its deadline, restart the
1542+ // sequence.
1543+ std::lock_guard frameLock (m_frameMutex);
1544+ bool hasMissedDeadline = false ;
15081545
15091546 for (size_t i = 0u ; i < timingProperties.presentationTimingCount ; i++) {
15101547 const auto & time = stageTimes[i];
@@ -1530,11 +1567,14 @@ namespace dxvk {
15301567 m_timingMode.lastFrameTimeLocal = reportTimeLocal;
15311568 m_timingMode.lastFrameTimeQpc = reportTimeQpc;
15321569
1533- hasValidReport = true ;
1570+ for (const auto & frame : m_frameQueue) {
1571+ if (frame.frameId == report.presentId )
1572+ hasMissedDeadline = reportTimeLocal > frame.deadline ;
1573+ }
15341574 }
15351575 }
15361576
1537- if (!m_timingMode.referenceFrameId && hasValidReport ) {
1577+ if (!m_timingMode.referenceFrameId || hasMissedDeadline ) {
15381578 m_timingMode.referenceFrameId = m_timingMode.lastFrameId ;
15391579 m_timingMode.referenceTime = m_timingMode.lastFrameTimeLocal ;
15401580 }
0 commit comments