From 67bd2b5e76539a272581386aba4c3b177af1b546 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 15 Sep 2022 16:05:45 +0200 Subject: [PATCH] [dxgi] Report swap chain frame statistics --- src/dxgi/dxgi_swapchain.cpp | 69 ++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index df4575b08..9d7bb47f2 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -18,7 +18,7 @@ namespace dxvk { m_descFs (*pFullscreenDesc), m_presentCount(0u), m_presenter (pPresenter), - m_monitor (nullptr) { + m_monitor (wsi::getWindowMonitor(m_window)) { if (FAILED(m_presenter->GetAdapter(__uuidof(IDXGIAdapter), reinterpret_cast(&m_adapter)))) throw DxvkError("DXGI: Failed to get adapter for present device"); @@ -32,7 +32,8 @@ namespace dxvk { DxgiSwapChain::~DxgiSwapChain() { - RestoreDisplayMode(m_monitor); + if (!m_descFs.Windowed) + RestoreDisplayMode(m_monitor); // Decouple swap chain from monitor if necessary DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; @@ -174,14 +175,36 @@ namespace dxvk { static bool s_errorShown = false; if (!std::exchange(s_errorShown, true)) - Logger::warn("DxgiSwapChain::GetFrameStatistics: Semi-stub"); + Logger::warn("DxgiSwapChain::GetFrameStatistics: Frame statistics may be inaccurate"); + + // If possible, use the monitor's frame statistics + DXGI_VK_MONITOR_DATA* monitorData = nullptr; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorData))) { + auto refreshPeriod = computeRefreshPeriod( + monitorData->LastMode.RefreshRate.Numerator, + monitorData->LastMode.RefreshRate.Denominator); + + auto t1Counter = dxvk::high_resolution_clock::get_counter(); + + auto t0 = dxvk::high_resolution_clock::get_time_from_counter(monitorData->FrameStats.SyncQPCTime.QuadPart); + auto t1 = dxvk::high_resolution_clock::get_time_from_counter(t1Counter); + + pStats->PresentCount = monitorData->FrameStats.PresentCount; + pStats->PresentRefreshCount = monitorData->FrameStats.PresentRefreshCount; + pStats->SyncRefreshCount = monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod); + pStats->SyncQPCTime.QuadPart = t1Counter; + pStats->SyncGPUTime.QuadPart = 0; + + ReleaseMonitorData(); + } else { + pStats->PresentCount = m_presentCount; + pStats->PresentRefreshCount = 0; + pStats->SyncRefreshCount = 0; + pStats->SyncQPCTime.QuadPart = dxvk::high_resolution_clock::get_counter(); + pStats->SyncGPUTime.QuadPart = 0; + } - // TODO deal with the refresh counts at some point - pStats->PresentCount = m_presentCount; - pStats->PresentRefreshCount = 0; - pStats->SyncRefreshCount = 0; - pStats->SyncQPCTime.QuadPart = dxvk::high_resolution_clock::get_counter(); - pStats->SyncGPUTime.QuadPart = 0; return S_OK; } @@ -268,13 +291,33 @@ namespace dxvk { try { HRESULT hr = m_presenter->Present(SyncInterval, PresentFlags, nullptr); - if (hr == S_OK && !(PresentFlags & DXGI_PRESENT_TEST)) - m_presentCount++; - return hr; + + if (hr != S_OK || (PresentFlags & DXGI_PRESENT_TEST)) + return hr; } catch (const DxvkError& err) { Logger::err(err.message()); return DXGI_ERROR_DRIVER_INTERNAL_ERROR; } + + // Update frame statistics + DXGI_VK_MONITOR_DATA* monitorData; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorData))) { + auto refreshPeriod = computeRefreshPeriod( + monitorData->LastMode.RefreshRate.Numerator, + monitorData->LastMode.RefreshRate.Denominator); + + auto t0 = dxvk::high_resolution_clock::get_time_from_counter(monitorData->FrameStats.SyncQPCTime.QuadPart); + auto t1 = dxvk::high_resolution_clock::now(); + + monitorData->FrameStats.PresentCount += 1; + monitorData->FrameStats.PresentRefreshCount = monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod); + ReleaseMonitorData(); + } else { + m_presentCount += 1; + } + + return S_OK; } @@ -633,8 +676,8 @@ namespace dxvk { HMONITOR monitor = m_monitor; m_descFs.Windowed = TRUE; - m_monitor = nullptr; m_target = nullptr; + m_monitor = wsi::getWindowMonitor(m_window); if (!wsi::isWindow(m_window)) return S_OK;