diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index bac43529f..e1682f070 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -15,6 +15,11 @@ #include <vector> Log_SetChannel(HostDisplay); +#ifdef _WIN32 +#include "common/windows_headers.h" +#include <dwmapi.h> +#endif + HostDisplayTexture::~HostDisplayTexture() = default; HostDisplay::~HostDisplay() = default; @@ -85,6 +90,43 @@ bool HostDisplay::SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 return true; } +bool HostDisplay::GetHostRefreshRate(float* refresh_rate) +{ +#ifdef _WIN32 + static HMODULE dwm_module = nullptr; + static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr; + static bool load_tried = false; + if (!load_tried) + { + load_tried = true; + dwm_module = LoadLibrary("dwmapi.dll"); + if (dwm_module) + { + std::atexit([]() { + FreeLibrary(dwm_module); + dwm_module = nullptr; + }); + get_timing_info = + reinterpret_cast<decltype(get_timing_info)>(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo")); + } + } + + DWM_TIMING_INFO ti = {}; + ti.cbSize = sizeof(ti); + HRESULT hr = get_timing_info(nullptr, &ti); + if (SUCCEEDED(hr)) + { + if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0) + return false; + + *refresh_rate = static_cast<float>(ti.rateRefresh.uiNumerator) / static_cast<float>(ti.rateRefresh.uiDenominator); + return true; + } +#endif + + return false; +} + void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/) { m_cursor_texture = std::move(texture); diff --git a/src/core/host_display.h b/src/core/host_display.h index c4024ca5c..1458a0666 100644 --- a/src/core/host_display.h +++ b/src/core/host_display.h @@ -163,6 +163,7 @@ public: static u32 GetDisplayPixelFormatSize(HostDisplayPixelFormat format); + virtual bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const = 0; virtual bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer, @@ -170,6 +171,8 @@ public: virtual void EndSetDisplayPixels() = 0; virtual bool SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, const void* buffer, u32 pitch); + virtual bool GetHostRefreshRate(float* refresh_rate); + void SetDisplayLinearFiltering(bool enabled) { m_display_linear_filtering = enabled; } void SetDisplayTopMargin(s32 height) { m_display_top_margin = height; } void SetDisplayIntegerScaling(bool enabled) { m_display_integer_scaling = enabled; } diff --git a/src/frontend-common/d3d11_host_display.cpp b/src/frontend-common/d3d11_host_display.cpp index 2381b4594..e635d3b95 100644 --- a/src/frontend-common/d3d11_host_display.cpp +++ b/src/frontend-common/d3d11_host_display.cpp @@ -226,6 +226,25 @@ void D3D11HostDisplay::EndSetDisplayPixels() m_context->Unmap(m_display_pixels_texture.GetD3DTexture(), 0); } +bool D3D11HostDisplay::GetHostRefreshRate(float* refresh_rate) +{ + if (m_swap_chain && IsFullscreen()) + { + DXGI_SWAP_CHAIN_DESC desc; + if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 && + desc.BufferDesc.RefreshRate.Denominator > 0) + { + Log_InfoPrintf("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, + desc.BufferDesc.RefreshRate.Denominator); + *refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / + static_cast<float>(desc.BufferDesc.RefreshRate.Denominator); + return true; + } + } + + return HostDisplay::GetHostRefreshRate(refresh_rate); +} + void D3D11HostDisplay::SetVSync(bool enabled) { m_vsync = enabled; diff --git a/src/frontend-common/d3d11_host_display.h b/src/frontend-common/d3d11_host_display.h index 9623e8093..91497ddbe 100644 --- a/src/frontend-common/d3d11_host_display.h +++ b/src/frontend-common/d3d11_host_display.h @@ -61,6 +61,8 @@ public: u32* out_pitch) override; void EndSetDisplayPixels() override; + bool GetHostRefreshRate(float* refresh_rate) override; + virtual void SetVSync(bool enabled) override; virtual bool Render() override;