1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-24 04:54:14 +01:00

[d3d9] Implement latency tracking

This commit is contained in:
Philip Rebohle 2025-01-17 22:22:10 +01:00
parent 970378a267
commit a537ecf421
4 changed files with 92 additions and 13 deletions

View File

@ -4270,7 +4270,7 @@ namespace dxvk {
m_implicitSwapchain->Invalidate(pPresentationParameters->hDeviceWindow); m_implicitSwapchain->Invalidate(pPresentationParameters->hDeviceWindow);
try { try {
auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode); auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode, false);
*ppSwapChain = ref(swapchain); *ppSwapChain = ref(swapchain);
m_losableResourceCounter++; m_losableResourceCounter++;
} }
@ -6098,11 +6098,29 @@ namespace dxvk {
} }
void D3D9DeviceEx::EndFrame() { void D3D9DeviceEx::BeginFrame(Rc<DxvkLatencyTracker> LatencyTracker, uint64_t FrameId) {
D3D9DeviceLock lock = LockDevice(); D3D9DeviceLock lock = LockDevice();
EmitCs<false>([] (DxvkContext* ctx) { EmitCs<false>([
cTracker = std::move(LatencyTracker),
cFrameId = FrameId
] (DxvkContext* ctx) {
if (cTracker && cTracker->needsAutoMarkers())
ctx->beginLatencyTracking(cTracker, cFrameId);
});
}
void D3D9DeviceEx::EndFrame(Rc<DxvkLatencyTracker> LatencyTracker) {
D3D9DeviceLock lock = LockDevice();
EmitCs<false>([
cTracker = std::move(LatencyTracker)
] (DxvkContext* ctx) {
ctx->endFrame(); ctx->endFrame();
if (cTracker && cTracker->needsAutoMarkers())
ctx->endLatencyTracking(cTracker);
}); });
} }
@ -8445,7 +8463,7 @@ namespace dxvk {
return hr; return hr;
} }
else { else {
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode); m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode, true);
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr(); m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
} }

View File

@ -800,7 +800,8 @@ namespace dxvk {
void Flush(); void Flush();
void FlushAndSync9On12(); void FlushAndSync9On12();
void EndFrame(); void BeginFrame(Rc<DxvkLatencyTracker> LatencyTracker, uint64_t FrameId);
void EndFrame(Rc<DxvkLatencyTracker> LatencyTracker);
void UpdateActiveRTs(uint32_t index); void UpdateActiveRTs(uint32_t index);

View File

@ -23,10 +23,12 @@ namespace dxvk {
D3D9SwapChainEx::D3D9SwapChainEx( D3D9SwapChainEx::D3D9SwapChainEx(
D3D9DeviceEx* pDevice, D3D9DeviceEx* pDevice,
D3DPRESENT_PARAMETERS* pPresentParams, D3DPRESENT_PARAMETERS* pPresentParams,
const D3DDISPLAYMODEEX* pFullscreenDisplayMode) const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
bool EnableLatencyTracking)
: D3D9SwapChainExBase(pDevice) : D3D9SwapChainExBase(pDevice)
, m_device (pDevice->GetDXVKDevice()) , m_device (pDevice->GetDXVKDevice())
, m_frameLatencyCap (pDevice->GetOptions()->maxFrameLatency) , m_frameLatencyCap (pDevice->GetOptions()->maxFrameLatency)
, m_latencyTracking (EnableLatencyTracking)
, m_swapchainExt (this) { , m_swapchainExt (this) {
this->NormalizePresentParameters(pPresentParams); this->NormalizePresentParameters(pPresentParams);
m_presentParams = *pPresentParams; m_presentParams = *pPresentParams;
@ -186,7 +188,7 @@ namespace dxvk {
#define DCX_USESTYLE 0x00010000 #define DCX_USESTYLE 0x00010000
HRESULT D3D9SwapChainEx::PresentImageGDI(HWND Window) { HRESULT D3D9SwapChainEx::PresentImageGDI(HWND Window) {
m_parent->EndFrame(); m_parent->EndFrame(nullptr);
m_parent->Flush(); m_parent->Flush();
if (!std::exchange(m_warnedAboutGDIFallback, true)) if (!std::exchange(m_warnedAboutGDIFallback, true))
@ -717,6 +719,9 @@ namespace dxvk {
if (entry->second.presenter) { if (entry->second.presenter) {
entry->second.presenter->destroyResources(); entry->second.presenter->destroyResources();
entry->second.presenter = nullptr; entry->second.presenter = nullptr;
if (m_presentParams.hDeviceWindow == hWindow)
DestroyLatencyTracker();
} }
if (m_wctx == &entry->second) if (m_wctx == &entry->second)
@ -802,10 +807,15 @@ namespace dxvk {
void D3D9SwapChainEx::PresentImage(UINT SyncInterval) { void D3D9SwapChainEx::PresentImage(UINT SyncInterval) {
m_parent->EndFrame(); m_parent->EndFrame(m_latencyTracker);
m_parent->Flush(); m_parent->Flush();
if (m_latencyTracker)
m_latencyTracker->notifyCpuPresentBegin(m_wctx->frameId + 1u);
// Retrieve the image and image view to present // Retrieve the image and image view to present
VkResult status = VK_SUCCESS;
Rc<DxvkImage> swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage(); Rc<DxvkImage> swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
Rc<DxvkImageView> swapImageView = m_backBuffers[0]->GetImageView(false); Rc<DxvkImageView> swapImageView = m_backBuffers[0]->GetImageView(false);
@ -814,10 +824,12 @@ namespace dxvk {
PresenterSync sync = { }; PresenterSync sync = { };
Rc<DxvkImage> backBuffer; Rc<DxvkImage> backBuffer;
VkResult status = m_wctx->presenter->acquireNextImage(sync, backBuffer); status = m_wctx->presenter->acquireNextImage(sync, backBuffer);
if (status < 0 || status == VK_NOT_READY) if (status < 0 || status == VK_NOT_READY) {
status = i ? VK_SUCCESS : status;
break; break;
}
VkRect2D srcRect = { VkRect2D srcRect = {
{ int32_t(m_srcRect.left), int32_t(m_srcRect.top) }, { int32_t(m_srcRect.left), int32_t(m_srcRect.top) },
@ -854,7 +866,8 @@ namespace dxvk {
cDstRect = dstRect, cDstRect = dstRect,
cRepeat = i, cRepeat = i,
cSync = sync, cSync = sync,
cFrameId = m_wctx->frameId cFrameId = m_wctx->frameId,
cLatency = m_latencyTracker
] (DxvkContext* ctx) { ] (DxvkContext* ctx) {
// Update back buffer color space as necessary // Update back buffer color space as necessary
if (cSrcView->image()->info().colorSpace != cColorSpace) { if (cSrcView->image()->info().colorSpace != cColorSpace) {
@ -876,14 +889,33 @@ namespace dxvk {
uint64_t frameId = cRepeat ? 0 : cFrameId; uint64_t frameId = cRepeat ? 0 : cFrameId;
cDevice->presentImage(cPresenter, nullptr, frameId, nullptr); cDevice->presentImage(cPresenter, cLatency, frameId, nullptr);
}); });
m_parent->FlushCsChunk(); m_parent->FlushCsChunk();
} }
if (m_latencyTracker) {
if (status == VK_SUCCESS)
m_latencyTracker->notifyCpuPresentEnd(m_wctx->frameId);
else
m_latencyTracker->discardTimings();
}
SyncFrameLatency(); SyncFrameLatency();
DxvkLatencyStats latencyStats = { };
if (m_latencyTracker && status == VK_SUCCESS) {
latencyStats = m_latencyTracker->getStatistics(m_wctx->frameId);
m_latencyTracker->sleepAndBeginFrame(m_wctx->frameId + 1, std::abs(m_targetFrameRate));
m_parent->BeginFrame(m_latencyTracker, m_wctx->frameId + 1u);
}
if (m_latencyHud)
m_latencyHud->accumulateStats(latencyStats);
// Rotate swap chain buffers so that the back // Rotate swap chain buffers so that the back
// buffer at index 0 becomes the front buffer. // buffer at index 0 becomes the front buffer.
for (uint32_t i = 1; i < m_backBuffers.size(); i++) for (uint32_t i = 1; i < m_backBuffers.size(); i++)
@ -941,6 +973,9 @@ namespace dxvk {
entry->second.frameLatencySignal = new sync::Fence(entry->second.frameId); entry->second.frameLatencySignal = new sync::Fence(entry->second.frameId);
entry->second.presenter = CreatePresenter(m_window, entry->second.frameLatencySignal); 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_wctx = &entry->second; m_wctx = &entry->second;
@ -1017,6 +1052,10 @@ namespace dxvk {
if (hud) { if (hud) {
m_apiHud = hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName()); m_apiHud = hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
if (m_latencyTracking)
m_latencyHud = hud->addItem<hud::HudLatencyItem>("latency", 4);
hud->addItem<hud::HudSamplerCount>("samplers", -1, m_parent); hud->addItem<hud::HudSamplerCount>("samplers", -1, m_parent);
hud->addItem<hud::HudFixedFunctionShaders>("ffshaders", -1, m_parent); hud->addItem<hud::HudFixedFunctionShaders>("ffshaders", -1, m_parent);
hud->addItem<hud::HudSWVPState>("swvp", -1, m_parent); hud->addItem<hud::HudSWVPState>("swvp", -1, m_parent);
@ -1041,6 +1080,18 @@ namespace dxvk {
} }
void D3D9SwapChainEx::DestroyLatencyTracker() {
if (!m_latencyTracker)
return;
m_parent->InjectCs([
cTracker = std::move(m_latencyTracker)
] (DxvkContext* ctx) {
ctx->endLatencyTracking(cTracker);
});
}
void D3D9SwapChainEx::UpdateTargetFrameRate(uint32_t SyncInterval) { void D3D9SwapChainEx::UpdateTargetFrameRate(uint32_t SyncInterval) {
double frameRateOption = double(m_parent->GetOptions()->maxFrameRate); double frameRateOption = double(m_parent->GetOptions()->maxFrameRate);
double frameRate = std::max(frameRateOption, 0.0); double frameRate = std::max(frameRateOption, 0.0);
@ -1049,6 +1100,7 @@ namespace dxvk {
frameRate = -m_displayRefreshRate / double(SyncInterval); frameRate = -m_displayRefreshRate / double(SyncInterval);
m_wctx->presenter->setFrameRateLimit(frameRate, GetActualFrameLatency()); m_wctx->presenter->setFrameRateLimit(frameRate, GetActualFrameLatency());
m_targetFrameRate = frameRate;
} }

View File

@ -69,7 +69,8 @@ namespace dxvk {
D3D9SwapChainEx( D3D9SwapChainEx(
D3D9DeviceEx* pDevice, D3D9DeviceEx* pDevice,
D3DPRESENT_PARAMETERS* pPresentParams, D3DPRESENT_PARAMETERS* pPresentParams,
const D3DDISPLAYMODEEX* pFullscreenDisplayMode); const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
bool EnableLatencyTracking);
~D3D9SwapChainEx(); ~D3D9SwapChainEx();
@ -173,12 +174,17 @@ namespace dxvk {
wsi::DxvkWindowState m_windowState; wsi::DxvkWindowState m_windowState;
double m_displayRefreshRate = 0.0; double m_displayRefreshRate = 0.0;
double m_targetFrameRate = 0.0;
bool m_warnedAboutGDIFallback = false; bool m_warnedAboutGDIFallback = false;
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
bool m_latencyTracking = false;
Rc<DxvkLatencyTracker> m_latencyTracker = nullptr;
Rc<hud::HudClientApiItem> m_apiHud; Rc<hud::HudClientApiItem> m_apiHud;
Rc<hud::HudLatencyItem> m_latencyHud;
std::optional<VkHdrMetadataEXT> m_hdrMetadata; std::optional<VkHdrMetadataEXT> m_hdrMetadata;
bool m_unlockAdditionalFormats = false; bool m_unlockAdditionalFormats = false;
@ -197,6 +203,8 @@ namespace dxvk {
void CreateBlitter(); void CreateBlitter();
void DestroyLatencyTracker();
void InitRamp(); void InitRamp();
void UpdateTargetFrameRate(uint32_t SyncInterval); void UpdateTargetFrameRate(uint32_t SyncInterval);