Skip to content

Commit 2d4a4bd

Browse files
committed
[d3d9] Implement latency tracking
1 parent 2c34039 commit 2d4a4bd

File tree

4 files changed

+96
-13
lines changed

4 files changed

+96
-13
lines changed

src/d3d9/d3d9_device.cpp

+22-4
Original file line numberDiff line numberDiff line change
@@ -4270,7 +4270,7 @@ namespace dxvk {
42704270
m_implicitSwapchain->Invalidate(pPresentationParameters->hDeviceWindow);
42714271

42724272
try {
4273-
auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
4273+
auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode, false);
42744274
*ppSwapChain = ref(swapchain);
42754275
m_losableResourceCounter++;
42764276
}
@@ -6098,11 +6098,29 @@ namespace dxvk {
60986098
}
60996099

61006100

6101-
void D3D9DeviceEx::EndFrame() {
6101+
void D3D9DeviceEx::BeginFrame(Rc<DxvkLatencyTracker> LatencyTracker, uint64_t FrameId) {
61026102
D3D9DeviceLock lock = LockDevice();
61036103

6104-
EmitCs<false>([] (DxvkContext* ctx) {
6104+
if (LatencyTracker)
6105+
LatencyTracker->notifyCpuFrameBegin(FrameId);
6106+
6107+
EmitCs<false>([
6108+
cTracker = std::move(LatencyTracker),
6109+
cFrameId = FrameId
6110+
] (DxvkContext* ctx) {
6111+
ctx->beginLatencyTracking(cTracker, cFrameId);
6112+
});
6113+
}
6114+
6115+
6116+
void D3D9DeviceEx::EndFrame(Rc<DxvkLatencyTracker> LatencyTracker) {
6117+
D3D9DeviceLock lock = LockDevice();
6118+
6119+
EmitCs<false>([
6120+
cTracker = std::move(LatencyTracker)
6121+
] (DxvkContext* ctx) {
61056122
ctx->endFrame();
6123+
ctx->endLatencyTracking(cTracker);
61066124
});
61076125
}
61086126

@@ -8445,7 +8463,7 @@ namespace dxvk {
84458463
return hr;
84468464
}
84478465
else {
8448-
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
8466+
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode, true);
84498467
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
84508468
}
84518469

src/d3d9/d3d9_device.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,8 @@ namespace dxvk {
800800
void Flush();
801801
void FlushAndSync9On12();
802802

803-
void EndFrame();
803+
void BeginFrame(Rc<DxvkLatencyTracker> LatencyTracker, uint64_t FrameId);
804+
void EndFrame(Rc<DxvkLatencyTracker> LatencyTracker);
804805

805806
void UpdateActiveRTs(uint32_t index);
806807

src/d3d9/d3d9_swapchain.cpp

+63-7
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ namespace dxvk {
2323
D3D9SwapChainEx::D3D9SwapChainEx(
2424
D3D9DeviceEx* pDevice,
2525
D3DPRESENT_PARAMETERS* pPresentParams,
26-
const D3DDISPLAYMODEEX* pFullscreenDisplayMode)
26+
const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
27+
bool EnableLatencyTracking)
2728
: D3D9SwapChainExBase(pDevice)
2829
, m_device (pDevice->GetDXVKDevice())
2930
, m_frameLatencyCap (pDevice->GetOptions()->maxFrameLatency)
31+
, m_latencyTracking (EnableLatencyTracking)
3032
, m_swapchainExt (this) {
3133
this->NormalizePresentParameters(pPresentParams);
3234
m_presentParams = *pPresentParams;
@@ -186,7 +188,7 @@ namespace dxvk {
186188
#define DCX_USESTYLE 0x00010000
187189

188190
HRESULT D3D9SwapChainEx::PresentImageGDI(HWND Window) {
189-
m_parent->EndFrame();
191+
m_parent->EndFrame(nullptr);
190192
m_parent->Flush();
191193

192194
if (!std::exchange(m_warnedAboutGDIFallback, true))
@@ -717,6 +719,9 @@ namespace dxvk {
717719
if (entry->second.presenter) {
718720
entry->second.presenter->destroyResources();
719721
entry->second.presenter = nullptr;
722+
723+
if (m_presentParams.hDeviceWindow == hWindow)
724+
DestroyLatencyTracker();
720725
}
721726

722727
if (m_wctx == &entry->second)
@@ -802,10 +807,15 @@ namespace dxvk {
802807

803808

804809
void D3D9SwapChainEx::PresentImage(UINT SyncInterval) {
805-
m_parent->EndFrame();
810+
m_parent->EndFrame(m_latencyTracker);
806811
m_parent->Flush();
807812

813+
if (m_latencyTracker)
814+
m_latencyTracker->notifyCpuPresentBegin(m_wctx->frameId + 1u);
815+
808816
// Retrieve the image and image view to present
817+
VkResult status = VK_SUCCESS;
818+
809819
Rc<DxvkImage> swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
810820
Rc<DxvkImageView> swapImageView = m_backBuffers[0]->GetImageView(false);
811821

@@ -814,10 +824,12 @@ namespace dxvk {
814824
PresenterSync sync = { };
815825
Rc<DxvkImage> backBuffer;
816826

817-
VkResult status = m_wctx->presenter->acquireNextImage(sync, backBuffer);
827+
status = m_wctx->presenter->acquireNextImage(sync, backBuffer);
818828

819-
if (status < 0 || status == VK_NOT_READY)
829+
if (status < 0 || status == VK_NOT_READY) {
830+
status = i ? VK_SUCCESS : status;
820831
break;
832+
}
821833

822834
VkRect2D srcRect = {
823835
{ int32_t(m_srcRect.left), int32_t(m_srcRect.top) },
@@ -854,7 +866,8 @@ namespace dxvk {
854866
cDstRect = dstRect,
855867
cRepeat = i,
856868
cSync = sync,
857-
cFrameId = m_wctx->frameId
869+
cFrameId = m_wctx->frameId,
870+
cLatency = m_latencyTracker
858871
] (DxvkContext* ctx) {
859872
// Update back buffer color space as necessary
860873
if (cSrcView->image()->info().colorSpace != cColorSpace) {
@@ -876,14 +889,37 @@ namespace dxvk {
876889

877890
uint64_t frameId = cRepeat ? 0 : cFrameId;
878891

879-
cDevice->presentImage(cPresenter, nullptr, frameId, nullptr);
892+
cDevice->presentImage(cPresenter, cLatency, frameId, nullptr);
880893
});
881894

882895
m_parent->FlushCsChunk();
883896
}
884897

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+
885909
SyncFrameLatency();
886910

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+
887923
// Rotate swap chain buffers so that the back
888924
// buffer at index 0 becomes the front buffer.
889925
for (uint32_t i = 1; i < m_backBuffers.size(); i++)
@@ -941,6 +977,9 @@ namespace dxvk {
941977

942978
entry->second.frameLatencySignal = new sync::Fence(entry->second.frameId);
943979
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);
944983
}
945984

946985
m_wctx = &entry->second;
@@ -1017,6 +1056,10 @@ namespace dxvk {
10171056

10181057
if (hud) {
10191058
m_apiHud = hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
1059+
1060+
if (m_latencyTracking)
1061+
m_latencyHud = hud->addItem<hud::HudLatencyItem>("latency", 4);
1062+
10201063
hud->addItem<hud::HudSamplerCount>("samplers", -1, m_parent);
10211064
hud->addItem<hud::HudFixedFunctionShaders>("ffshaders", -1, m_parent);
10221065
hud->addItem<hud::HudSWVPState>("swvp", -1, m_parent);
@@ -1041,6 +1084,18 @@ namespace dxvk {
10411084
}
10421085

10431086

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+
10441099
void D3D9SwapChainEx::UpdateTargetFrameRate(uint32_t SyncInterval) {
10451100
double frameRateOption = double(m_parent->GetOptions()->maxFrameRate);
10461101
double frameRate = std::max(frameRateOption, 0.0);
@@ -1049,6 +1104,7 @@ namespace dxvk {
10491104
frameRate = -m_displayRefreshRate / double(SyncInterval);
10501105

10511106
m_wctx->presenter->setFrameRateLimit(frameRate, GetActualFrameLatency());
1107+
m_targetFrameRate = frameRate;
10521108
}
10531109

10541110

src/d3d9/d3d9_swapchain.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ namespace dxvk {
6969
D3D9SwapChainEx(
7070
D3D9DeviceEx* pDevice,
7171
D3DPRESENT_PARAMETERS* pPresentParams,
72-
const D3DDISPLAYMODEEX* pFullscreenDisplayMode);
72+
const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
73+
bool EnableLatencyTracking);
7374

7475
~D3D9SwapChainEx();
7576

@@ -173,12 +174,17 @@ namespace dxvk {
173174
wsi::DxvkWindowState m_windowState;
174175

175176
double m_displayRefreshRate = 0.0;
177+
double m_targetFrameRate = 0.0;
176178

177179
bool m_warnedAboutGDIFallback = false;
178180

179181
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
180182

183+
bool m_latencyTracking = false;
184+
Rc<DxvkLatencyTracker> m_latencyTracker = nullptr;
185+
181186
Rc<hud::HudClientApiItem> m_apiHud;
187+
Rc<hud::HudLatencyItem> m_latencyHud;
182188

183189
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
184190
bool m_unlockAdditionalFormats = false;
@@ -197,6 +203,8 @@ namespace dxvk {
197203

198204
void CreateBlitter();
199205

206+
void DestroyLatencyTracker();
207+
200208
void InitRamp();
201209

202210
void UpdateTargetFrameRate(uint32_t SyncInterval);

0 commit comments

Comments
 (0)