diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 4ab616ed7..b858df2af 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -987,7 +987,7 @@ namespace dxvk { entry->second.presenter = CreatePresenter(m_window, entry->second.frameLatencySignal); if (m_presentParams.hDeviceWindow == m_window && m_latencyTracking) - m_latencyTracker = m_device->createLatencyTracker(entry->second.presenter); + m_latencyTracker = m_device->createLatencyTracker(entry->second.presenter, entry->second.frameId+1); } m_wctx = &entry->second; diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index cdb59e6c7..b05acf034 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -309,15 +309,16 @@ namespace dxvk { Rc DxvkDevice::createLatencyTracker( - const Rc& presenter) { + const Rc& presenter, + uint64_t firstFrameId ) { if (m_options.latencySleep == Tristate::False) - return new FramePacer(m_options); + return new FramePacer(m_options, firstFrameId); if (m_options.latencySleep == Tristate::Auto) { if (m_features.nvLowLatency2) return new DxvkReflexLatencyTrackerNv(presenter); else - return new FramePacer(m_options); + return new FramePacer(m_options, firstFrameId); } return new DxvkBuiltInLatencyTracker(presenter, diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 2ec517c2e..859b30297 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -489,7 +489,8 @@ namespace dxvk { * \param [in] presenter Presenter instance */ Rc createLatencyTracker( - const Rc& presenter); + const Rc& presenter, + uint64_t firstFrameId = 17); /** * \brief Presents a swap chain image diff --git a/src/dxvk/framepacer/dxvk_framepacer.cpp b/src/dxvk/framepacer/dxvk_framepacer.cpp index c520d854d..a71b2d31d 100644 --- a/src/dxvk/framepacer/dxvk_framepacer.cpp +++ b/src/dxvk/framepacer/dxvk_framepacer.cpp @@ -8,7 +8,7 @@ namespace dxvk { - FramePacer::FramePacer( const DxvkOptions& options ) { + FramePacer::FramePacer( const DxvkOptions& options, uint64_t firstFrameId ) { // we'll default to LOW_LATENCY in the draft-PR for now, for demonstration purposes, // highlighting the generally much better input lag and medium-term time consistency. // although MAX_FRAME_LATENCY has advantages in many games and is likely the better default, @@ -53,11 +53,19 @@ namespace dxvk { gpuStart.store(0); } - // be consistent that every frame has a gpuReady event from the previous frame - uint64_t firstFrameId = DXGI_MAX_SWAP_CHAIN_BUFFERS+1; - LatencyMarkers* m = m_latencyMarkersStorage.getMarkers(firstFrameId); - m->gpuReady.push_back(high_resolution_clock::now()); + // be consistent that every frame has a gpuReady event from finishing the previous frame + LatencyMarkers* m = m_latencyMarkersStorage.getMarkers( firstFrameId ); + m->gpuReady.push_back( high_resolution_clock::now() ); m_gpuStarts[ firstFrameId % m_gpuStarts.size() ] = gpuReadyBit; + + LatencyMarkersTimeline& timeline = m_latencyMarkersStorage.m_timeline; + timeline.cpuFinished.store ( firstFrameId-1 ); + timeline.gpuStart.store ( firstFrameId-1 ); + timeline.gpuFinished.store ( firstFrameId-1 ); + timeline.frameFinished.store ( firstFrameId-1 ); + + m_mode->signalGpuStart ( firstFrameId-1 ); + m_mode->signalRenderFinished ( firstFrameId-1 ); } diff --git a/src/dxvk/framepacer/dxvk_framepacer.h b/src/dxvk/framepacer/dxvk_framepacer.h index 1a8cf63f3..38d740d1a 100644 --- a/src/dxvk/framepacer/dxvk_framepacer.h +++ b/src/dxvk/framepacer/dxvk_framepacer.h @@ -23,7 +23,7 @@ namespace dxvk { using microseconds = std::chrono::microseconds; public: - FramePacer( const DxvkOptions& options ); + FramePacer( const DxvkOptions& options, uint64_t firstFrameId ); ~FramePacer(); void sleepAndBeginFrame(