@@ -23,10 +23,12 @@ namespace dxvk {
23
23
D3D9SwapChainEx::D3D9SwapChainEx (
24
24
D3D9DeviceEx* pDevice,
25
25
D3DPRESENT_PARAMETERS* pPresentParams,
26
- const D3DDISPLAYMODEEX* pFullscreenDisplayMode)
26
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
27
+ bool EnableLatencyTracking)
27
28
: D3D9SwapChainExBase(pDevice)
28
29
, m_device (pDevice->GetDXVKDevice ())
29
30
, m_frameLatencyCap (pDevice->GetOptions ()->maxFrameLatency)
31
+ , m_latencyTracking (EnableLatencyTracking)
30
32
, m_swapchainExt (this ) {
31
33
this ->NormalizePresentParameters (pPresentParams);
32
34
m_presentParams = *pPresentParams;
@@ -186,7 +188,7 @@ namespace dxvk {
186
188
#define DCX_USESTYLE 0x00010000
187
189
188
190
HRESULT D3D9SwapChainEx::PresentImageGDI (HWND Window) {
189
- m_parent->EndFrame ();
191
+ m_parent->EndFrame (nullptr );
190
192
m_parent->Flush ();
191
193
192
194
if (!std::exchange (m_warnedAboutGDIFallback, true ))
@@ -717,6 +719,9 @@ namespace dxvk {
717
719
if (entry->second .presenter ) {
718
720
entry->second .presenter ->destroyResources ();
719
721
entry->second .presenter = nullptr ;
722
+
723
+ if (m_presentParams.hDeviceWindow == hWindow)
724
+ DestroyLatencyTracker ();
720
725
}
721
726
722
727
if (m_wctx == &entry->second )
@@ -802,10 +807,15 @@ namespace dxvk {
802
807
803
808
804
809
void D3D9SwapChainEx::PresentImage (UINT SyncInterval) {
805
- m_parent->EndFrame ();
810
+ m_parent->EndFrame (m_latencyTracker );
806
811
m_parent->Flush ();
807
812
813
+ if (m_latencyTracker)
814
+ m_latencyTracker->notifyCpuPresentBegin (m_wctx->frameId + 1u );
815
+
808
816
// Retrieve the image and image view to present
817
+ VkResult status = VK_SUCCESS;
818
+
809
819
Rc<DxvkImage> swapImage = m_backBuffers[0 ]->GetCommonTexture ()->GetImage ();
810
820
Rc<DxvkImageView> swapImageView = m_backBuffers[0 ]->GetImageView (false );
811
821
@@ -814,10 +824,12 @@ namespace dxvk {
814
824
PresenterSync sync = { };
815
825
Rc<DxvkImage> backBuffer;
816
826
817
- VkResult status = m_wctx->presenter ->acquireNextImage (sync , backBuffer);
827
+ status = m_wctx->presenter ->acquireNextImage (sync , backBuffer);
818
828
819
- if (status < 0 || status == VK_NOT_READY)
829
+ if (status < 0 || status == VK_NOT_READY) {
830
+ status = i ? VK_SUCCESS : status;
820
831
break ;
832
+ }
821
833
822
834
VkRect2D srcRect = {
823
835
{ int32_t (m_srcRect.left ), int32_t (m_srcRect.top ) },
@@ -854,7 +866,8 @@ namespace dxvk {
854
866
cDstRect = dstRect,
855
867
cRepeat = i,
856
868
cSync = sync ,
857
- cFrameId = m_wctx->frameId
869
+ cFrameId = m_wctx->frameId ,
870
+ cLatency = m_latencyTracker
858
871
] (DxvkContext* ctx) {
859
872
// Update back buffer color space as necessary
860
873
if (cSrcView->image ()->info ().colorSpace != cColorSpace) {
@@ -876,14 +889,37 @@ namespace dxvk {
876
889
877
890
uint64_t frameId = cRepeat ? 0 : cFrameId;
878
891
879
- cDevice->presentImage (cPresenter, nullptr , frameId, nullptr );
892
+ cDevice->presentImage (cPresenter, cLatency , frameId, nullptr );
880
893
});
881
894
882
895
m_parent->FlushCsChunk ();
883
896
}
884
897
898
+ if (m_latencyTracker) {
899
+ if (status == VK_SUCCESS) {
900
+ m_latencyTracker->notifyCpuPresentEnd (m_wctx->frameId );
901
+
902
+ if (m_latencyTracker->isLatencySleepEnabled ())
903
+ m_parent->SynchronizeCsThread (DxvkCsThread::SynchronizeAll);
904
+ } else {
905
+ m_latencyTracker->discardFrame (m_wctx->frameId + 1u );
906
+ }
907
+ }
908
+
885
909
SyncFrameLatency ();
886
910
911
+ DxvkLatencyStats latencyStats = { };
912
+
913
+ if (m_latencyTracker && status == VK_SUCCESS) {
914
+ latencyStats = m_latencyTracker->getStatistics (m_wctx->frameId );
915
+ m_latencyTracker->sleep (m_wctx->frameId , std::abs (m_targetFrameRate));
916
+
917
+ m_parent->BeginFrame (m_latencyTracker, m_wctx->frameId + 1u );
918
+ }
919
+
920
+ if (m_latencyHud)
921
+ m_latencyHud->accumulateStats (latencyStats);
922
+
887
923
// Rotate swap chain buffers so that the back
888
924
// buffer at index 0 becomes the front buffer.
889
925
for (uint32_t i = 1 ; i < m_backBuffers.size (); i++)
@@ -941,6 +977,9 @@ namespace dxvk {
941
977
942
978
entry->second .frameLatencySignal = new sync ::Fence (entry->second .frameId );
943
979
entry->second .presenter = CreatePresenter (m_window, entry->second .frameLatencySignal );
980
+
981
+ if (m_presentParams.hDeviceWindow == m_window && m_latencyTracking)
982
+ m_latencyTracker = m_device->createLatencyTracker (entry->second .presenter );
944
983
}
945
984
946
985
m_wctx = &entry->second ;
@@ -1017,6 +1056,10 @@ namespace dxvk {
1017
1056
1018
1057
if (hud) {
1019
1058
m_apiHud = hud->addItem <hud::HudClientApiItem>(" api" , 1 , GetApiName ());
1059
+
1060
+ if (m_latencyTracking)
1061
+ m_latencyHud = hud->addItem <hud::HudLatencyItem>(" latency" , 4 );
1062
+
1020
1063
hud->addItem <hud::HudSamplerCount>(" samplers" , -1 , m_parent);
1021
1064
hud->addItem <hud::HudFixedFunctionShaders>(" ffshaders" , -1 , m_parent);
1022
1065
hud->addItem <hud::HudSWVPState>(" swvp" , -1 , m_parent);
@@ -1041,6 +1084,18 @@ namespace dxvk {
1041
1084
}
1042
1085
1043
1086
1087
+ void D3D9SwapChainEx::DestroyLatencyTracker () {
1088
+ if (!m_latencyTracker)
1089
+ return ;
1090
+
1091
+ m_parent->InjectCs ([
1092
+ cTracker = std::move (m_latencyTracker)
1093
+ ] (DxvkContext* ctx) {
1094
+ ctx->endLatencyTracking (cTracker);
1095
+ });
1096
+ }
1097
+
1098
+
1044
1099
void D3D9SwapChainEx::UpdateTargetFrameRate (uint32_t SyncInterval) {
1045
1100
double frameRateOption = double (m_parent->GetOptions ()->maxFrameRate );
1046
1101
double frameRate = std::max (frameRateOption, 0.0 );
@@ -1049,6 +1104,7 @@ namespace dxvk {
1049
1104
frameRate = -m_displayRefreshRate / double (SyncInterval);
1050
1105
1051
1106
m_wctx->presenter ->setFrameRateLimit (frameRate, GetActualFrameLatency ());
1107
+ m_targetFrameRate = frameRate;
1052
1108
}
1053
1109
1054
1110
0 commit comments