GPUDevice: Update last presented time after present

Instead of before.

Makes present skipping much more effective against NVIDIA's global
framerate cap if enabled, on my system with the cap at 60fps it
went from 120fps to 1400fps. Still about half of the true uncapped
speed, but when the present call blocks for a few milliseconds this
is all you can do. Can't stop presenting frames entirely.
This commit is contained in:
Stenzek
2026-01-14 21:36:52 +10:00
parent d02382da79
commit 09926a3769
8 changed files with 17 additions and 1 deletions

View File

@@ -1275,6 +1275,7 @@ bool GPUPresenter::PresentFrame(GPUPresenter* presenter, GPUBackend* backend, bo
g_gpu_device->SubmitPresent(swap_chain);
}
swap_chain->UpdateLastFramePresentedTime();
ImGuiManager::NewFrame();
}
else

View File

@@ -734,6 +734,7 @@ void D3D11Device::EndPresent(GPUSwapChain* swap_chain, bool explicit_present, u6
const UINT flags =
(SC->GetVSyncMode() == GPUVSyncMode::Disabled && SC->IsUsingAllowTearing()) ? DXGI_PRESENT_ALLOW_TEARING : 0;
SC->GetSwapChain()->Present(sync_interval, flags);
SC->UpdateLastFramePresentedTime();
if (m_gpu_timing_enabled)
StartTimestampQuery();

View File

@@ -1266,6 +1266,7 @@ void D3D12Device::SubmitPresent(GPUSwapChain* swap_chain)
const UINT flags =
(SC->GetVSyncMode() == GPUVSyncMode::Disabled && SC->IsUsingAllowTearing()) ? DXGI_PRESENT_ALLOW_TEARING : 0;
SC->GetSwapChain()->Present(sync_interval, flags);
SC->UpdateLastFramePresentedTime();
}
#ifdef ENABLE_GPU_OBJECT_NAMES

View File

@@ -300,10 +300,15 @@ bool GPUSwapChain::ShouldSkipPresentingFrame()
if (diff < throttle_period)
return true;
m_last_frame_displayed_time = now;
return false;
}
void GPUSwapChain::UpdateLastFramePresentedTime(u64 presented_time)
{
if (m_allow_present_throttle)
m_last_frame_displayed_time = (presented_time != 0) ? presented_time : Timer::GetCurrentValue();
}
void GPUSwapChain::ThrottlePresentation()
{
const float throttle_rate = (m_window_info.surface_refresh_rate > 0.0f) ? m_window_info.surface_refresh_rate : 60.0f;

View File

@@ -488,6 +488,7 @@ public:
virtual bool IsExclusiveFullscreen() const;
bool ShouldSkipPresentingFrame();
void UpdateLastFramePresentedTime(u64 presented_time = 0);
void ThrottlePresentation();
static GSVector4i PreRotateClipRect(WindowInfo::PreRotation prerotation, const GSVector2i surface_size,

View File

@@ -2592,16 +2592,19 @@ void MetalDevice::EndPresent(GPUSwapChain* swap_chain, bool explicit_present, u6
EndAnyEncoding();
Timer::Value current_time;
Timer::Value presented_time;
if (present_time != 0 && (current_time = Timer::GetCurrentValue()) < present_time)
{
// Need to convert to mach absolute time. Time values should already be in nanoseconds.
const u64 mach_time_nanoseconds = CocoaTools::ConvertMachTimeBaseToNanoseconds(mach_absolute_time());
const double mach_present_time = static_cast<double>(mach_time_nanoseconds + (present_time - current_time)) / 1e+9;
[m_render_cmdbuf presentDrawable:m_layer_drawable atTime:mach_present_time];
presented_time = present_time;
}
else
{
[m_render_cmdbuf presentDrawable:m_layer_drawable];
presented_time = 0;
}
DeferRelease(m_layer_drawable);
@@ -2609,6 +2612,8 @@ void MetalDevice::EndPresent(GPUSwapChain* swap_chain, bool explicit_present, u6
SubmitCommandBuffer();
TrimTexturePool();
swap_chain->UpdateLastFramePresentedTime(presented_time);
}
void MetalDevice::SubmitPresent(GPUSwapChain* swap_chainwel)

View File

@@ -803,6 +803,7 @@ void OpenGLDevice::EndPresent(GPUSwapChain* swap_chain, bool explicit_present, u
}
m_gl_context->SwapBuffers();
swap_chain->UpdateLastFramePresentedTime();
if (swap_chain == m_main_swap_chain.get() && m_gpu_timing_enabled)
StartTimestampQuery();

View File

@@ -1254,6 +1254,7 @@ void VulkanDevice::QueuePresent(VulkanSwapChain* present_swap_chain)
// submission. Don't care if it fails, we'll deal with that at the presentation call site.
// Credit to dxvk for the idea.
present_swap_chain->AcquireNextImage(false);
present_swap_chain->UpdateLastFramePresentedTime();
}
void VulkanDevice::BeginCommandBuffer(u32 index)