1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Added SupportedResolutions setting

This commit is contained in:
narzoul 2021-06-30 23:42:27 +02:00
parent ee350c7f08
commit ffc8e04a35
17 changed files with 263 additions and 124 deletions

View File

@ -5,5 +5,6 @@ namespace Config
Settings::CpuAffinity cpuAffinity; Settings::CpuAffinity cpuAffinity;
Settings::DesktopColorDepth desktopColorDepth; Settings::DesktopColorDepth desktopColorDepth;
Settings::DisplayResolution displayResolution; Settings::DisplayResolution displayResolution;
Settings::SupportedResolutions supportedResolutions;
Settings::ThreadPriorityBoost threadPriorityBoost; Settings::ThreadPriorityBoost threadPriorityBoost;
} }

View File

@ -3,6 +3,7 @@
#include <Config/Settings/CpuAffinity.h> #include <Config/Settings/CpuAffinity.h>
#include <Config/Settings/DesktopColorDepth.h> #include <Config/Settings/DesktopColorDepth.h>
#include <Config/Settings/DisplayResolution.h> #include <Config/Settings/DisplayResolution.h>
#include <Config/Settings/SupportedResolutions.h>
#include <Config/Settings/ThreadPriorityBoost.h> #include <Config/Settings/ThreadPriorityBoost.h>
namespace Config namespace Config
@ -14,5 +15,6 @@ namespace Config
extern Settings::CpuAffinity cpuAffinity; extern Settings::CpuAffinity cpuAffinity;
extern Settings::DesktopColorDepth desktopColorDepth; extern Settings::DesktopColorDepth desktopColorDepth;
extern Settings::DisplayResolution displayResolution; extern Settings::DisplayResolution displayResolution;
extern Settings::SupportedResolutions supportedResolutions;
extern Settings::ThreadPriorityBoost threadPriorityBoost; extern Settings::ThreadPriorityBoost threadPriorityBoost;
} }

View File

@ -21,7 +21,7 @@ namespace
namespace Config namespace Config
{ {
EnumSetting::EnumSetting(const std::string& name, unsigned default, const std::vector<std::string>& enumNames) EnumSetting::EnumSetting(const std::string& name, const std::string& default, const std::vector<std::string>& enumNames)
: MappedSetting(name, default, createMapping(enumNames)) : MappedSetting(name, default, createMapping(enumNames))
{ {
} }

View File

@ -9,6 +9,6 @@ namespace Config
class EnumSetting : public MappedSetting<unsigned> class EnumSetting : public MappedSetting<unsigned>
{ {
protected: protected:
EnumSetting(const std::string& name, unsigned default, const std::vector<std::string>& enumNames); EnumSetting(const std::string& name, const std::string& default, const std::vector<std::string>& enumNames);
}; };
} }

View File

@ -4,16 +4,10 @@
namespace Config namespace Config
{ {
ListSetting::ListSetting(const std::string& name, const std::string& default) ListSetting::ListSetting(const std::string& name, const std::string& default)
: Setting(name) : Setting(name, default)
, m_default(default)
{ {
} }
void ListSetting::resetValue()
{
setValue(m_default);
}
void ListSetting::setValue(const std::string& value) void ListSetting::setValue(const std::string& value)
{ {
std::vector<std::string> values; std::vector<std::string> values;

View File

@ -11,11 +11,7 @@ namespace Config
protected: protected:
ListSetting(const std::string& name, const std::string& default); ListSetting(const std::string& name, const std::string& default);
void resetValue() override;
void setValue(const std::string& value) override; void setValue(const std::string& value) override;
virtual void setValues(const std::vector<std::string>& values) = 0; virtual void setValues(const std::vector<std::string>& values) = 0;
private:
std::string m_default;
}; };
} }

View File

@ -14,10 +14,9 @@ namespace Config
Value get() const { return m_value; } Value get() const { return m_value; }
protected: protected:
MappedSetting(const std::string& name, Value default, const std::map<std::string, Value>& valueMapping) MappedSetting(const std::string& name, const std::string& default, const std::map<std::string, Value>& valueMapping)
: Setting(name) : Setting(name, default)
, m_default(default) , m_value{}
, m_value(default)
, m_valueMapping(valueMapping) , m_valueMapping(valueMapping)
{ {
} }
@ -34,11 +33,6 @@ namespace Config
throw ParsingError("MappedSetting::getValueStr(): value not found in mapping"); throw ParsingError("MappedSetting::getValueStr(): value not found in mapping");
} }
void resetValue() override
{
m_value = m_default;
}
void setValue(const std::string& value) override void setValue(const std::string& value) override
{ {
auto it = m_valueMapping.find(value); auto it = m_valueMapping.find(value);
@ -49,7 +43,6 @@ namespace Config
m_value = it->second; m_value = it->second;
} }
Value m_default;
Value m_value; Value m_value;
const std::map<std::string, Value> m_valueMapping; const std::map<std::string, Value> m_valueMapping;
}; };

View File

@ -3,28 +3,21 @@
namespace Config namespace Config
{ {
Setting::Setting(const std::string& name) Setting::Setting(const std::string& name, const std::string& default)
: m_name(name) : m_name(name)
, m_default(default)
{ {
Parser::registerSetting(*this); Parser::registerSetting(*this);
} }
void Setting::reset() void Setting::reset()
{ {
resetValue(); set("default", "default");
m_source = "default";
} }
void Setting::set(const std::string& value, const std::string& source) void Setting::set(const std::string& value, const std::string& source)
{ {
if ("default" == value) setValue("default" == value ? m_default : value);
{
resetValue();
}
else
{
setValue(value);
}
m_source = source; m_source = source;
} }
} }

View File

@ -7,7 +7,7 @@ namespace Config
class Setting class Setting
{ {
public: public:
Setting(const std::string& name); Setting(const std::string& name, const std::string& default);
Setting(const Setting&) = delete; Setting(const Setting&) = delete;
Setting(Setting&&) = delete; Setting(Setting&&) = delete;
@ -23,11 +23,11 @@ namespace Config
protected: protected:
virtual std::string getValueStr() const = 0; virtual std::string getValueStr() const = 0;
virtual void resetValue() = 0;
virtual void setValue(const std::string& value) = 0; virtual void setValue(const std::string& value) = 0;
private: private:
std::string m_name; std::string m_name;
std::string m_default;
std::string m_source; std::string m_source;
}; };
} }

View File

@ -12,7 +12,7 @@ namespace Config
static const UINT INITIAL = 0; static const UINT INITIAL = 0;
DesktopColorDepth() DesktopColorDepth()
: MappedSetting("DesktopColorDepth", INITIAL, { {"initial", INITIAL}, {"8", 8}, {"16", 16}, {"32", 32} }) : MappedSetting("DesktopColorDepth", "initial", { {"initial", INITIAL}, {"8", 8}, {"16", 16}, {"32", 32} })
{ {
} }
}; };

View File

@ -5,7 +5,7 @@ namespace Config
namespace Settings namespace Settings
{ {
DisplayResolution::DisplayResolution() DisplayResolution::DisplayResolution()
: MappedSetting("DisplayResolution", DESKTOP, { {"app", APP}, {"desktop", DESKTOP} }) : MappedSetting("DisplayResolution", "desktop", { {"app", APP}, {"desktop", DESKTOP} })
{ {
} }

View File

@ -0,0 +1,37 @@
#include <Common/Comparison.h>
#include <Config/Parser.h>
#include <Config/Settings/SupportedResolutions.h>
namespace Config
{
namespace Settings
{
SupportedResolutions::SupportedResolutions()
: ListSetting("SupportedResolutions", "native, 640x480, 800x600, 1024x768")
{
}
std::string SupportedResolutions::getValueStr() const
{
std::string result;
for (const auto& res : m_resolutions)
{
result += ", ";
result += NATIVE == res ? "native" : std::to_string(res.cx) + 'x' + std::to_string(res.cy);
}
return result.substr(2);
}
void SupportedResolutions::setValues(const std::vector<std::string>& values)
{
std::set<SIZE> result;
for (const auto& v : values)
{
result.insert("native" == v ? NATIVE : Parser::parseResolution(v));
}
m_resolutions = result;
}
const SIZE SupportedResolutions::NATIVE = { 0, 0 };
}
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <set>
#include <Windows.h>
#include <Config/ListSetting.h>
namespace Config
{
namespace Settings
{
class SupportedResolutions : public ListSetting
{
public:
static const SIZE NATIVE;
SupportedResolutions();
std::set<SIZE> get() const { return m_resolutions; }
private:
std::string getValueStr() const override;
void setValues(const std::vector<std::string>& values) override;
std::set<SIZE> m_resolutions;
};
}
}

View File

@ -12,7 +12,7 @@ namespace Config
enum Value { OFF, ON, MAIN, APP }; enum Value { OFF, ON, MAIN, APP };
ThreadPriorityBoost() ThreadPriorityBoost()
: EnumSetting("ThreadPriorityBoost", OFF, { "off", "on", "main", "app" }) : EnumSetting("ThreadPriorityBoost", "off", { "off", "on", "main", "app" })
{ {
} }
}; };

View File

@ -216,6 +216,7 @@
<ClInclude Include="Config\Settings\CpuAffinity.h" /> <ClInclude Include="Config\Settings\CpuAffinity.h" />
<ClInclude Include="Config\Settings\DesktopColorDepth.h" /> <ClInclude Include="Config\Settings\DesktopColorDepth.h" />
<ClInclude Include="Config\Settings\DisplayResolution.h" /> <ClInclude Include="Config\Settings\DisplayResolution.h" />
<ClInclude Include="Config\Settings\SupportedResolutions.h" />
<ClInclude Include="Config\Settings\ThreadPriorityBoost.h" /> <ClInclude Include="Config\Settings\ThreadPriorityBoost.h" />
<ClInclude Include="D3dDdi\Adapter.h" /> <ClInclude Include="D3dDdi\Adapter.h" />
<ClInclude Include="D3dDdi\AdapterCallbacks.h" /> <ClInclude Include="D3dDdi\AdapterCallbacks.h" />
@ -320,6 +321,7 @@
<ClCompile Include="Config\Setting.cpp" /> <ClCompile Include="Config\Setting.cpp" />
<ClCompile Include="Config\Settings\CpuAffinity.cpp" /> <ClCompile Include="Config\Settings\CpuAffinity.cpp" />
<ClCompile Include="Config\Settings\DisplayResolution.cpp" /> <ClCompile Include="Config\Settings\DisplayResolution.cpp" />
<ClCompile Include="Config\Settings\SupportedResolutions.cpp" />
<ClCompile Include="D3dDdi\Adapter.cpp" /> <ClCompile Include="D3dDdi\Adapter.cpp" />
<ClCompile Include="D3dDdi\AdapterCallbacks.cpp" /> <ClCompile Include="D3dDdi\AdapterCallbacks.cpp" />
<ClCompile Include="D3dDdi\AdapterFuncs.cpp" /> <ClCompile Include="D3dDdi\AdapterFuncs.cpp" />

View File

@ -441,6 +441,9 @@
<ClInclude Include="Config\Settings\DesktopColorDepth.h"> <ClInclude Include="Config\Settings\DesktopColorDepth.h">
<Filter>Header Files\Config\Settings</Filter> <Filter>Header Files\Config\Settings</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Config\Settings\SupportedResolutions.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp"> <ClCompile Include="Gdi\Gdi.cpp">
@ -692,6 +695,9 @@
<ClCompile Include="Gdi\Cursor.cpp"> <ClCompile Include="Gdi\Cursor.cpp">
<Filter>Source Files\Gdi</Filter> <Filter>Source Files\Gdi</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Config\Settings\SupportedResolutions.cpp">
<Filter>Source Files\Config\Settings</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="DDrawCompat.rc"> <ResourceCompile Include="DDrawCompat.rc">

View File

@ -1,3 +1,4 @@
#include <map>
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
@ -22,6 +23,11 @@ namespace
using Win32::DisplayMode::DisplayMode; using Win32::DisplayMode::DisplayMode;
using Win32::DisplayMode::EmulatedDisplayMode; using Win32::DisplayMode::EmulatedDisplayMode;
template <typename Char> struct DevModeType;
template <> struct DevModeType<CHAR> { typedef DEVMODEA Type; };
template <> struct DevModeType<WCHAR> { typedef DEVMODEW Type; };
template <typename Char> using DevMode = typename DevModeType<Char>::Type;
template <typename Char> template <typename Char>
struct EnumParams struct EnumParams
{ {
@ -53,8 +59,8 @@ namespace
BOOL WINAPI dwm8And16BitIsShimAppliedCallOut(); BOOL WINAPI dwm8And16BitIsShimAppliedCallOut();
BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2); BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2);
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char> template <typename Char>
SIZE getConfiguredResolution(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName); SIZE getConfiguredResolution(const Char* deviceName);
template <typename Char> template <typename Char>
std::wstring getDeviceName(const Char* deviceName); std::wstring getDeviceName(const Char* deviceName);
@ -62,9 +68,19 @@ namespace
HMONITOR getMonitorFromDc(HDC dc); HMONITOR getMonitorFromDc(HDC dc);
MONITORINFO getMonitorInfo(const std::wstring& deviceName); MONITORINFO getMonitorInfo(const std::wstring& deviceName);
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char> template <typename Char>
std::vector<DisplayMode> getSupportedDisplayModes( std::map<SIZE, std::set<DWORD>> getSupportedDisplayModeMap(const Char* deviceName, DWORD flags);
EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName, DWORD flags); template <typename Char>
std::vector<DisplayMode> getSupportedDisplayModes(const Char* deviceName, DWORD flags);
SIZE makeSize(DWORD width, DWORD height);
LONG origChangeDisplaySettingsEx(LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
LONG origChangeDisplaySettingsEx(LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
BOOL origEnumDisplaySettingsEx(LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags);
BOOL origEnumDisplaySettingsEx(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags);
void setDwmDxFullscreenTransitionEvent();
void adjustMonitorInfo(MONITORINFO& mi) void adjustMonitorInfo(MONITORINFO& mi)
{ {
@ -80,27 +96,65 @@ namespace
} }
} }
template <typename CStr, typename DevMode, typename ChangeDisplaySettingsExFunc, typename EnumDisplaySettingsExFunc> template <typename Char>
LONG changeDisplaySettingsEx( LONG changeDisplaySettingsEx(const Char* lpszDeviceName, typename DevMode<Char>* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
ChangeDisplaySettingsExFunc origChangeDisplaySettingsEx,
EnumDisplaySettingsExFunc origEnumDisplaySettingsEx,
CStr lpszDeviceName, DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{ {
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;
DevMode targetDevMode = {}; DevMode<Char> targetDevMode = {};
SIZE emulatedResolution = {};
if (lpDevMode) if (lpDevMode)
{ {
DevMode<Char> currDevMode = {};
currDevMode.dmSize = sizeof(currDevMode);
enumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0);
targetDevMode = *lpDevMode; targetDevMode = *lpDevMode;
targetDevMode.dmFields |= DM_BITSPERPEL;
targetDevMode.dmBitsPerPel = 32; targetDevMode.dmBitsPerPel = 32;
SIZE resolutionOverride = getConfiguredResolution<DevMode>(origEnumDisplaySettingsEx, lpszDeviceName); if (!(targetDevMode.dmFields & DM_PELSWIDTH))
{
targetDevMode.dmFields |= DM_PELSWIDTH;
targetDevMode.dmPelsWidth = currDevMode.dmPelsWidth;
}
if (!(targetDevMode.dmFields & DM_PELSHEIGHT))
{
targetDevMode.dmFields |= DM_PELSHEIGHT;
targetDevMode.dmPelsHeight = currDevMode.dmPelsHeight;
}
emulatedResolution = makeSize(targetDevMode.dmPelsWidth, targetDevMode.dmPelsHeight);
auto supportedDisplayModeMap(getSupportedDisplayModeMap(lpszDeviceName, 0));
if (supportedDisplayModeMap.find(emulatedResolution) == supportedDisplayModeMap.end())
{
if (!(dwflags & CDS_TEST))
{
setDwmDxFullscreenTransitionEvent();
}
return DISP_CHANGE_BADMODE;
}
SIZE resolutionOverride = getConfiguredResolution(lpszDeviceName);
if (0 != resolutionOverride.cx) if (0 != resolutionOverride.cx)
{ {
targetDevMode.dmPelsWidth = resolutionOverride.cx; DevMode<Char> dm = {};
targetDevMode.dmPelsHeight = resolutionOverride.cy; dm.dmSize = sizeof(dm);
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
dm.dmPelsWidth = resolutionOverride.cx;
dm.dmPelsHeight = resolutionOverride.cy;
LONG result = origChangeDisplaySettingsEx(lpszDeviceName, &dm, nullptr, CDS_TEST, nullptr);
if (DISP_CHANGE_SUCCESSFUL == result)
{
targetDevMode.dmPelsWidth = resolutionOverride.cx;
targetDevMode.dmPelsHeight = resolutionOverride.cy;
}
else
{
LOG_ONCE("Failed to apply setting: DisplayResolution = " << dm.dmPelsWidth << 'x' << dm.dmPelsHeight);
}
} }
} }
DevMode prevDevMode = {}; DevMode<Char> prevDevMode = {};
if (!(dwflags & CDS_TEST)) if (!(dwflags & CDS_TEST))
{ {
prevDevMode.dmSize = sizeof(prevDevMode); prevDevMode.dmSize = sizeof(prevDevMode);
@ -111,14 +165,6 @@ namespace
if (lpDevMode) if (lpDevMode)
{ {
result = origChangeDisplaySettingsEx(lpszDeviceName, &targetDevMode, hwnd, dwflags, lParam); result = origChangeDisplaySettingsEx(lpszDeviceName, &targetDevMode, hwnd, dwflags, lParam);
if (DISP_CHANGE_SUCCESSFUL != result &&
(lpDevMode->dmPelsWidth != targetDevMode.dmPelsWidth || lpDevMode->dmPelsHeight != targetDevMode.dmPelsHeight))
{
LOG_ONCE("Failed to apply setting: DisplayResolution = " << targetDevMode.dmPelsWidth << 'x' << targetDevMode.dmPelsHeight);
targetDevMode.dmPelsWidth = lpDevMode->dmPelsWidth;
targetDevMode.dmPelsHeight = lpDevMode->dmPelsHeight;
result = origChangeDisplaySettingsEx(lpszDeviceName, &targetDevMode, hwnd, dwflags, lParam);
}
} }
else else
{ {
@ -130,16 +176,13 @@ namespace
return result; return result;
} }
DevMode currDevMode = {}; DevMode<Char> currDevMode = {};
currDevMode.dmSize = sizeof(currDevMode); currDevMode.dmSize = sizeof(currDevMode);
origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0); origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0);
if (0 == memcmp(&currDevMode, &prevDevMode, sizeof(currDevMode))) if (0 == memcmp(&currDevMode, &prevDevMode, sizeof(currDevMode)))
{ {
HANDLE dwmDxFullScreenTransitionEvent = OpenEventW( setDwmDxFullscreenTransitionEvent();
EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT");
SetEvent(dwmDxFullScreenTransitionEvent);
CloseHandle(dwmDxFullScreenTransitionEvent);
} }
if (DISP_CHANGE_SUCCESSFUL != result) if (DISP_CHANGE_SUCCESSFUL != result)
@ -152,9 +195,12 @@ namespace
++g_displaySettingsUniquenessBias; ++g_displaySettingsUniquenessBias;
if (lpDevMode) if (lpDevMode)
{ {
g_emulatedDisplayMode.width = lpDevMode->dmPelsWidth; g_emulatedDisplayMode.width = emulatedResolution.cx;
g_emulatedDisplayMode.height = lpDevMode->dmPelsHeight; g_emulatedDisplayMode.height = emulatedResolution.cy;
g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel; if (lpDevMode->dmFields & DM_BITSPERPEL)
{
g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel;
}
g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency; g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency;
g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName); g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName);
@ -171,11 +217,10 @@ namespace
} }
} }
auto& dm = lpDevMode ? *lpDevMode : currDevMode; SIZE res = lpDevMode ? emulatedResolution : makeSize(currDevMode.dmPelsWidth, currDevMode.dmPelsHeight);
LPARAM resolution = (dm.dmPelsHeight << 16) | dm.dmPelsWidth; EnumWindows(sendDisplayChange, (res.cy << 16) | res.cx);
EnumWindows(sendDisplayChange, resolution);
SetCursorPos(currDevMode.dmPosition.x + dm.dmPelsWidth / 2, currDevMode.dmPosition.y + dm.dmPelsHeight / 2); SetCursorPos(currDevMode.dmPosition.x + res.cx / 2, currDevMode.dmPosition.y + res.cy / 2);
Gdi::VirtualScreen::update(); Gdi::VirtualScreen::update();
return result; return result;
@ -185,20 +230,14 @@ namespace
LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{ {
LOG_FUNC("ChangeDisplaySettingsExA", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); LOG_FUNC("ChangeDisplaySettingsExA", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
return LOG_RESULT(changeDisplaySettingsEx( return LOG_RESULT(changeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam));
CALL_ORIG_FUNC(ChangeDisplaySettingsExA),
CALL_ORIG_FUNC(EnumDisplaySettingsExA),
lpszDeviceName, lpDevMode, hwnd, dwflags, lParam));
} }
LONG WINAPI changeDisplaySettingsExW( LONG WINAPI changeDisplaySettingsExW(
LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{ {
LOG_FUNC("ChangeDisplaySettingsExW", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); LOG_FUNC("ChangeDisplaySettingsExW", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
return LOG_RESULT(changeDisplaySettingsEx( return LOG_RESULT(changeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam));
CALL_ORIG_FUNC(ChangeDisplaySettingsExW),
CALL_ORIG_FUNC(EnumDisplaySettingsExW),
lpszDeviceName, lpDevMode, hwnd, dwflags, lParam));
} }
void disableDwm8And16BitMitigation() void disableDwm8And16BitMitigation()
@ -223,9 +262,8 @@ namespace
return LOG_RESULT(FALSE); return LOG_RESULT(FALSE);
} }
template <typename Char, typename DevMode, typename EnumDisplaySettingsExFunc> template <typename Char>
BOOL enumDisplaySettingsEx(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, BOOL enumDisplaySettingsEx(const Char* lpszDeviceName, DWORD iModeNum, DevMode<Char>* lpDevMode, DWORD dwFlags)
const Char* lpszDeviceName, DWORD iModeNum, DevMode* lpDevMode, DWORD dwFlags)
{ {
if (ENUM_REGISTRY_SETTINGS == iModeNum || !lpDevMode) if (ENUM_REGISTRY_SETTINGS == iModeNum || !lpDevMode)
{ {
@ -259,7 +297,7 @@ namespace
if (0 == iModeNum || displayModes.empty() || currentEnumParams != lastEnumParams) if (0 == iModeNum || displayModes.empty() || currentEnumParams != lastEnumParams)
{ {
displayModes = getSupportedDisplayModes<DevMode>(origEnumDisplaySettingsEx, lpszDeviceName, dwFlags); displayModes = getSupportedDisplayModes(lpszDeviceName, dwFlags);
lastEnumParams = currentEnumParams; lastEnumParams = currentEnumParams;
} }
@ -291,16 +329,14 @@ namespace
LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags) LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags)
{ {
LOG_FUNC("EnumDisplaySettingsExA", lpszDeviceName, iModeNum, lpDevMode, dwFlags); LOG_FUNC("EnumDisplaySettingsExA", lpszDeviceName, iModeNum, lpDevMode, dwFlags);
return LOG_RESULT(enumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExA), return LOG_RESULT(enumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags));
lpszDeviceName, iModeNum, lpDevMode, dwFlags));
} }
BOOL WINAPI enumDisplaySettingsExW( BOOL WINAPI enumDisplaySettingsExW(
LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags) LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags)
{ {
LOG_FUNC("EnumDisplaySettingsExW", lpszDeviceName, iModeNum, lpDevMode, dwFlags); LOG_FUNC("EnumDisplaySettingsExW", lpszDeviceName, iModeNum, lpDevMode, dwFlags);
return LOG_RESULT(enumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExW), return LOG_RESULT(enumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags));
lpszDeviceName, iModeNum, lpDevMode, dwFlags));
} }
ULONG WINAPI gdiEntry13() ULONG WINAPI gdiEntry13()
@ -309,13 +345,13 @@ namespace
return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias; return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias;
} }
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char> template <typename Char>
SIZE getConfiguredResolution(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName) SIZE getConfiguredResolution(const Char* deviceName)
{ {
auto resolution = Config::displayResolution.get(); auto resolution = Config::displayResolution.get();
if (Config::Settings::DisplayResolution::DESKTOP == resolution) if (Config::Settings::DisplayResolution::DESKTOP == resolution)
{ {
DevMode dm = {}; DevMode<Char> dm = {};
dm.dmSize = sizeof(dm); dm.dmSize = sizeof(dm);
if (origEnumDisplaySettingsEx(deviceName, ENUM_REGISTRY_SETTINGS, &dm, 0)) if (origEnumDisplaySettingsEx(deviceName, ENUM_REGISTRY_SETTINGS, &dm, 0))
{ {
@ -497,61 +533,75 @@ namespace
return LOG_RESULT(result); return LOG_RESULT(result);
} }
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char> template <typename Char>
std::vector<DisplayMode> getSupportedDisplayModes( std::map<SIZE, std::set<DWORD>> getSupportedDisplayModeMap(const Char* deviceName, DWORD flags)
EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName, DWORD flags)
{ {
std::set<DisplayMode> displayModes; std::map<SIZE, std::set<DWORD>> nativeDisplayModeMap;
DWORD modeNum = 0;
DevMode dm = {};
dm.dmSize = sizeof(dm);
DWORD modeNum = 0;
DevMode<Char> dm = {};
dm.dmSize = sizeof(dm);
while (origEnumDisplaySettingsEx(deviceName, modeNum, &dm, flags)) while (origEnumDisplaySettingsEx(deviceName, modeNum, &dm, flags))
{ {
if (32 == dm.dmBitsPerPel) if (32 == dm.dmBitsPerPel)
{ {
displayModes.insert({ dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency }); nativeDisplayModeMap[makeSize(dm.dmPelsWidth, dm.dmPelsHeight)].insert(dm.dmDisplayFrequency);
} }
++modeNum; ++modeNum;
} }
auto resolutionOverride = getConfiguredResolution<DevMode>(origEnumDisplaySettingsEx, deviceName); const auto& supportedResolutions = Config::supportedResolutions.get();
if (0 == resolutionOverride.cx) std::map<SIZE, std::set<DWORD>> displayModeMap;
if (supportedResolutions.find(Config::Settings::SupportedResolutions::NATIVE) != supportedResolutions.end())
{ {
return { displayModes.begin(), displayModes.end() }; displayModeMap = nativeDisplayModeMap;
} }
std::set<DWORD> supportedRefreshRates; const auto resolutionOverride = getConfiguredResolution(deviceName);
for (const auto& mode : displayModes) const auto it = nativeDisplayModeMap.find({ resolutionOverride.cx, resolutionOverride.cy });
if (it != nativeDisplayModeMap.end())
{ {
if (static_cast<LONG>(mode.width) == resolutionOverride.cx && for (auto& v : displayModeMap)
static_cast<LONG>(mode.height) == resolutionOverride.cy)
{ {
supportedRefreshRates.insert(mode.refreshRate); v.second = it->second;
} }
} }
if (supportedRefreshRates.empty()) for (auto& v : supportedResolutions)
{ {
return { displayModes.begin(), displayModes.end() }; if (v != Config::Settings::SupportedResolutions::NATIVE)
}
std::vector<DisplayMode> customDisplayModes;
DWORD prevWidth = 0;
DWORD prevHeight = 0;
for (const auto& mode : displayModes)
{
if (mode.width != prevWidth || mode.height != prevHeight)
{ {
for (auto refreshRate : supportedRefreshRates) if (it != nativeDisplayModeMap.end())
{ {
customDisplayModes.push_back({ mode.width, mode.height, mode.bpp, refreshRate }); displayModeMap[{ v.cx, v.cy }] = it->second;
}
else
{
auto iter = nativeDisplayModeMap.find({ v.cx, v.cy });
if (iter != nativeDisplayModeMap.end())
{
displayModeMap.insert(*iter);
}
} }
prevWidth = mode.width;
prevHeight = mode.height;
} }
} }
return customDisplayModes;
return displayModeMap;
}
template <typename Char>
std::vector<DisplayMode> getSupportedDisplayModes(const Char* deviceName, DWORD flags)
{
auto displayModeMap(getSupportedDisplayModeMap(deviceName, flags));
std::vector<DisplayMode> displayModeVector;
for (const auto& v : displayModeMap)
{
for (const auto& r : v.second)
{
displayModeVector.push_back({ static_cast<DWORD>(v.first.cx), static_cast<DWORD>(v.first.cy), 32, r });
}
}
return displayModeVector;
} }
BOOL CALLBACK initMonitor(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM /*dwData*/) BOOL CALLBACK initMonitor(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM /*dwData*/)
@ -577,6 +627,31 @@ namespace
return TRUE; return TRUE;
} }
SIZE makeSize(DWORD width, DWORD height)
{
return { static_cast<LONG>(width), static_cast<LONG>(height) };
}
LONG origChangeDisplaySettingsEx(LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{
return CALL_ORIG_FUNC(ChangeDisplaySettingsExA)(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
}
LONG origChangeDisplaySettingsEx(LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{
return CALL_ORIG_FUNC(ChangeDisplaySettingsExW)(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
}
BOOL origEnumDisplaySettingsEx(LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags)
{
return CALL_ORIG_FUNC(EnumDisplaySettingsExA)(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
}
BOOL origEnumDisplaySettingsEx(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags)
{
return CALL_ORIG_FUNC(EnumDisplaySettingsExW)(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
}
BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2) BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2)
{ {
LOG_FUNC("SE_COM_HookInterface", clsid, iid, unk1, unk2); LOG_FUNC("SE_COM_HookInterface", clsid, iid, unk1, unk2);
@ -597,6 +672,17 @@ namespace
} }
return TRUE; return TRUE;
} }
void setDwmDxFullscreenTransitionEvent()
{
HANDLE dwmDxFullscreenTransitionEvent = OpenEventW(
EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT");
if (dwmDxFullscreenTransitionEvent)
{
SetEvent(dwmDxFullscreenTransitionEvent);
CloseHandle(dwmDxFullscreenTransitionEvent);
}
}
} }
namespace Win32 namespace Win32