mirror of https://github.com/PCSX2/pcsx2.git
Common: Add WindowInfo
This commit is contained in:
parent
09764393e0
commit
fadd97c021
|
@ -123,6 +123,7 @@ else()
|
||||||
check_lib(EGL EGL EGL/egl.h)
|
check_lib(EGL EGL EGL/egl.h)
|
||||||
check_lib(X11_XCB X11-xcb X11/Xlib-xcb.h)
|
check_lib(X11_XCB X11-xcb X11/Xlib-xcb.h)
|
||||||
check_lib(XCB xcb xcb/xcb.h)
|
check_lib(XCB xcb xcb/xcb.h)
|
||||||
|
check_lib(XRANDR xrandr)
|
||||||
|
|
||||||
if(Linux)
|
if(Linux)
|
||||||
check_lib(AIO aio libaio.h)
|
check_lib(AIO aio libaio.h)
|
||||||
|
|
|
@ -32,6 +32,7 @@ target_sources(common PRIVATE
|
||||||
StringHelpers.cpp
|
StringHelpers.cpp
|
||||||
StringUtil.cpp
|
StringUtil.cpp
|
||||||
ThreadTools.cpp
|
ThreadTools.cpp
|
||||||
|
WindowInfo.cpp
|
||||||
emitter/bmi.cpp
|
emitter/bmi.cpp
|
||||||
emitter/cpudetect.cpp
|
emitter/cpudetect.cpp
|
||||||
emitter/fpu.cpp
|
emitter/fpu.cpp
|
||||||
|
@ -85,6 +86,7 @@ target_sources(common PRIVATE
|
||||||
StringUtil.h
|
StringUtil.h
|
||||||
Threading.h
|
Threading.h
|
||||||
TraceLog.h
|
TraceLog.h
|
||||||
|
WindowInfo.h
|
||||||
wxBaseTools.h
|
wxBaseTools.h
|
||||||
emitter/cpudetect_internal.h
|
emitter/cpudetect_internal.h
|
||||||
emitter/implement/dwshift.h
|
emitter/implement/dwshift.h
|
||||||
|
@ -121,6 +123,11 @@ if(WIN32)
|
||||||
enable_language(ASM_MASM)
|
enable_language(ASM_MASM)
|
||||||
target_sources(common PRIVATE FastJmp.asm)
|
target_sources(common PRIVATE FastJmp.asm)
|
||||||
target_link_libraries(common PUBLIC pthreads4w Winmm.lib)
|
target_link_libraries(common PUBLIC pthreads4w Winmm.lib)
|
||||||
|
elseif(NOT APPLE)
|
||||||
|
if(TARGET PkgConfig::XRANDR)
|
||||||
|
target_link_libraries(common PRIVATE PkgConfig::XRANDR)
|
||||||
|
target_compile_definitions(common PRIVATE "HAS_XRANDR=1")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(common PRIVATE ${LIBC_LIBRARIES} PUBLIC wxWidgets::all)
|
target_link_libraries(common PRIVATE ${LIBC_LIBRARIES} PUBLIC wxWidgets::all)
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "WindowInfo.h"
|
||||||
|
#include "Console.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_UWP)
|
||||||
|
|
||||||
|
#include "RedtapeWindows.h"
|
||||||
|
#include <dwmapi.h>
|
||||||
|
|
||||||
|
static bool GetRefreshRateFromDWM(HWND hwnd, float* refresh_rate)
|
||||||
|
{
|
||||||
|
static HMODULE dwm_module = nullptr;
|
||||||
|
static HRESULT(STDAPICALLTYPE * is_composition_enabled)(BOOL * pfEnabled) = 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 = LoadLibraryW(L"dwmapi.dll");
|
||||||
|
if (dwm_module)
|
||||||
|
{
|
||||||
|
std::atexit([]() {
|
||||||
|
FreeLibrary(dwm_module);
|
||||||
|
dwm_module = nullptr;
|
||||||
|
});
|
||||||
|
is_composition_enabled =
|
||||||
|
reinterpret_cast<decltype(is_composition_enabled)>(GetProcAddress(dwm_module, "DwmIsCompositionEnabled"));
|
||||||
|
get_timing_info =
|
||||||
|
reinterpret_cast<decltype(get_timing_info)>(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL composition_enabled;
|
||||||
|
if (!is_composition_enabled || FAILED(is_composition_enabled(&composition_enabled) || !get_timing_info))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool GetRefreshRateFromMonitor(HWND hwnd, float* refresh_rate)
|
||||||
|
{
|
||||||
|
HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||||
|
if (!mon)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MONITORINFOEXW mi = {};
|
||||||
|
mi.cbSize = sizeof(mi);
|
||||||
|
if (GetMonitorInfoW(mon, &mi))
|
||||||
|
{
|
||||||
|
DEVMODEW dm = {};
|
||||||
|
dm.dmSize = sizeof(dm);
|
||||||
|
|
||||||
|
// 0/1 are reserved for "defaults".
|
||||||
|
if (EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm) && dm.dmDisplayFrequency > 1)
|
||||||
|
{
|
||||||
|
*refresh_rate = static_cast<float>(dm.dmDisplayFrequency);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate)
|
||||||
|
{
|
||||||
|
if (wi.type != Type::Win32 || !wi.window_handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Try DWM first, then fall back to integer values.
|
||||||
|
const HWND hwnd = static_cast<HWND>(wi.window_handle);
|
||||||
|
return GetRefreshRateFromDWM(hwnd, refresh_rate) || GetRefreshRateFromMonitor(hwnd, refresh_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(X11_API) && defined(HAS_XRANDR)
|
||||||
|
|
||||||
|
#include "common/ScopedGuard.h"
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
static bool GetRefreshRateFromXRandR(const WindowInfo& wi, float* refresh_rate)
|
||||||
|
{
|
||||||
|
Display* display = static_cast<Display*>(wi.display_connection);
|
||||||
|
Window window = static_cast<Window>(reinterpret_cast<uintptr_t>(wi.window_handle));
|
||||||
|
if (!display || !window)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
XRRScreenResources* res = XRRGetScreenResources(display, window);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
Console.Error("(GetRefreshRateFromXRandR) XRRGetScreenResources() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedGuard res_guard([res]() { XRRFreeScreenResources(res); });
|
||||||
|
|
||||||
|
int num_monitors;
|
||||||
|
XRRMonitorInfo* mi = XRRGetMonitors(display, window, True, &num_monitors);
|
||||||
|
if (num_monitors < 0)
|
||||||
|
{
|
||||||
|
Console.Error("(GetRefreshRateFromXRandR) XRRGetMonitors() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (num_monitors > 1)
|
||||||
|
{
|
||||||
|
Console.Warning("(GetRefreshRateFromXRandR) XRRGetMonitors() returned %d monitors, using first", num_monitors);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedGuard mi_guard([mi]() { XRRFreeMonitors(mi); });
|
||||||
|
if (mi->noutput <= 0)
|
||||||
|
{
|
||||||
|
Console.Error("(GetRefreshRateFromXRandR) Monitor has no outputs");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (mi->noutput > 1)
|
||||||
|
{
|
||||||
|
Console.Warning("(GetRefreshRateFromXRandR) Monitor has %d outputs, using first", mi->noutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
XRROutputInfo* oi = XRRGetOutputInfo(display, res, mi->outputs[0]);
|
||||||
|
if (!oi)
|
||||||
|
{
|
||||||
|
Console.Error("(GetRefreshRateFromXRandR) XRRGetOutputInfo() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedGuard oi_guard([oi]() { XRRFreeOutputInfo(oi); });
|
||||||
|
|
||||||
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(display, res, oi->crtc);
|
||||||
|
if (!ci)
|
||||||
|
{
|
||||||
|
Console.Error("(GetRefreshRateFromXRandR) XRRGetCrtcInfo() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedGuard ci_guard([ci]() { XRRFreeCrtcInfo(ci); });
|
||||||
|
|
||||||
|
XRRModeInfo* mode = nullptr;
|
||||||
|
for (int i = 0; i < res->nmode; i++)
|
||||||
|
{
|
||||||
|
if (res->modes[i].id == ci->mode)
|
||||||
|
{
|
||||||
|
mode = &res->modes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mode)
|
||||||
|
{
|
||||||
|
Console.Error("(GetRefreshRateFromXRandR) Failed to look up mode %d (of %d)", static_cast<int>(ci->mode), res->nmode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode->dotClock == 0 || mode->hTotal == 0 || mode->vTotal == 0)
|
||||||
|
{
|
||||||
|
Console.Error("(GetRefreshRateFromXRandR) Modeline is invalid: %ld/%d/%d", mode->dotClock, mode->hTotal, mode->vTotal);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*refresh_rate =
|
||||||
|
static_cast<double>(mode->dotClock) / (static_cast<double>(mode->hTotal) * static_cast<double>(mode->vTotal));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // X11_API && defined(HAS_XRANDR)
|
||||||
|
|
||||||
|
bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate)
|
||||||
|
{
|
||||||
|
#if defined(X11_API) && defined(HAS_XRANDR)
|
||||||
|
if (wi.type == WindowInfo::Type::X11)
|
||||||
|
return GetRefreshRateFromXRandR(wi, refresh_rate);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "Pcsx2Defs.h"
|
||||||
|
|
||||||
|
/// Contains the information required to create a graphics context in a window.
|
||||||
|
struct WindowInfo
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Surfaceless,
|
||||||
|
Win32,
|
||||||
|
X11,
|
||||||
|
Wayland,
|
||||||
|
MacOS
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The type of the surface. Surfaceless indicates it will not be displayed on screen at all.
|
||||||
|
Type type = Type::Surfaceless;
|
||||||
|
|
||||||
|
/// Connection to the display server. On most platforms except X11/Wayland, this is implicit and null.
|
||||||
|
void* display_connection = nullptr;
|
||||||
|
|
||||||
|
/// Abstract handle to the window. This depends on the surface type.
|
||||||
|
void* window_handle = nullptr;
|
||||||
|
|
||||||
|
/// Width of the surface in pixels.
|
||||||
|
u32 surface_width = 0;
|
||||||
|
|
||||||
|
/// Height of the surface in pixels.
|
||||||
|
u32 surface_height = 0;
|
||||||
|
|
||||||
|
/// DPI scale for the surface.
|
||||||
|
float surface_scale = 1.0f;
|
||||||
|
|
||||||
|
/// Refresh rate of the surface, if available.
|
||||||
|
float surface_refresh_rate = 0.0f;
|
||||||
|
|
||||||
|
/// Returns the host's refresh rate for the given window, if available.
|
||||||
|
static bool QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate);
|
||||||
|
};
|
|
@ -54,6 +54,7 @@
|
||||||
<ClCompile Include="StringUtil.cpp" />
|
<ClCompile Include="StringUtil.cpp" />
|
||||||
<ClCompile Include="SettingsWrapper.cpp" />
|
<ClCompile Include="SettingsWrapper.cpp" />
|
||||||
<ClCompile Include="VirtualMemory.cpp" />
|
<ClCompile Include="VirtualMemory.cpp" />
|
||||||
|
<ClCompile Include="WindowInfo.cpp" />
|
||||||
<ClCompile Include="x86\MemcpyFast.cpp" />
|
<ClCompile Include="x86\MemcpyFast.cpp" />
|
||||||
<ClCompile Include="PathUtils.cpp" />
|
<ClCompile Include="PathUtils.cpp" />
|
||||||
<ClCompile Include="Perf.cpp" />
|
<ClCompile Include="Perf.cpp" />
|
||||||
|
@ -117,6 +118,7 @@
|
||||||
<ClInclude Include="RedtapeWindows.h" />
|
<ClInclude Include="RedtapeWindows.h" />
|
||||||
<ClInclude Include="SafeArray.h" />
|
<ClInclude Include="SafeArray.h" />
|
||||||
<ClInclude Include="StringHelpers.h" />
|
<ClInclude Include="StringHelpers.h" />
|
||||||
|
<ClInclude Include="WindowInfo.h" />
|
||||||
<ClInclude Include="wxBaseTools.h" />
|
<ClInclude Include="wxBaseTools.h" />
|
||||||
<ClInclude Include="Threading.h" />
|
<ClInclude Include="Threading.h" />
|
||||||
<ClInclude Include="PersistentThread.h" />
|
<ClInclude Include="PersistentThread.h" />
|
||||||
|
|
|
@ -118,6 +118,9 @@
|
||||||
<ClCompile Include="SettingsWrapper.cpp">
|
<ClCompile Include="SettingsWrapper.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="WindowInfo.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Assertions.h">
|
<ClInclude Include="Assertions.h">
|
||||||
|
@ -276,6 +279,9 @@
|
||||||
<ClInclude Include="Align.h">
|
<ClInclude Include="Align.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="WindowInfo.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Source Files">
|
<Filter Include="Source Files">
|
||||||
|
|
Loading…
Reference in New Issue