mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Added DisplayResolution setting
This commit is contained in:
parent
62983b19fe
commit
647a4bfcff
@ -21,3 +21,13 @@ inline auto toTuple(const LUID& luid)
|
||||
{
|
||||
return std::make_tuple(luid.LowPart, luid.HighPart);
|
||||
}
|
||||
|
||||
inline auto toTuple(const POINT& pt)
|
||||
{
|
||||
return std::make_tuple(pt.x, pt.y);
|
||||
}
|
||||
|
||||
inline auto toTuple(const SIZE& size)
|
||||
{
|
||||
return std::make_tuple(size.cx, size.cy);
|
||||
}
|
||||
|
@ -3,5 +3,6 @@
|
||||
namespace Config
|
||||
{
|
||||
Settings::CpuAffinity cpuAffinity;
|
||||
Settings::DisplayResolution displayResolution;
|
||||
Settings::ThreadPriorityBoost threadPriorityBoost;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Config/Settings/CpuAffinity.h>
|
||||
#include <Config/Settings/DisplayResolution.h>
|
||||
#include <Config/Settings/ThreadPriorityBoost.h>
|
||||
|
||||
namespace Config
|
||||
@ -10,5 +11,6 @@ namespace Config
|
||||
const unsigned maxPaletteUpdatesPerMs = 5;
|
||||
|
||||
extern Settings::CpuAffinity cpuAffinity;
|
||||
extern Settings::DisplayResolution displayResolution;
|
||||
extern Settings::ThreadPriorityBoost threadPriorityBoost;
|
||||
}
|
||||
|
@ -3,33 +3,26 @@
|
||||
#include <Config/Parser.h>
|
||||
#include <Config/EnumSetting.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::map<std::string, unsigned> createMapping(const std::vector<std::string>& enumNames)
|
||||
{
|
||||
std::map<std::string, unsigned> mapping;
|
||||
unsigned i = 0;
|
||||
for (const auto& name : enumNames)
|
||||
{
|
||||
|
||||
mapping[name] = i;
|
||||
++i;
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Config
|
||||
{
|
||||
EnumSetting::EnumSetting(const std::string& name, unsigned default, const std::vector<std::string>& enumNames)
|
||||
: Setting(name)
|
||||
, m_default(default)
|
||||
, m_value(default)
|
||||
, m_enumNames(enumNames)
|
||||
: MappedSetting(name, default, createMapping(enumNames))
|
||||
{
|
||||
}
|
||||
|
||||
std::string EnumSetting::getValueStr() const
|
||||
{
|
||||
return m_enumNames[m_value];
|
||||
}
|
||||
|
||||
void EnumSetting::resetValue()
|
||||
{
|
||||
m_value = m_default;
|
||||
}
|
||||
|
||||
void EnumSetting::setValue(const std::string& value)
|
||||
{
|
||||
auto it = std::find(m_enumNames.begin(), m_enumNames.end(), value);
|
||||
if (it == m_enumNames.end())
|
||||
{
|
||||
throw ParsingError("invalid value: '" + value + "'");
|
||||
}
|
||||
m_value = it - m_enumNames.begin();
|
||||
}
|
||||
}
|
||||
|
@ -2,25 +2,13 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Config/Setting.h>
|
||||
#include <Config/MappedSetting.h>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
class EnumSetting : public Setting
|
||||
class EnumSetting : public MappedSetting<unsigned>
|
||||
{
|
||||
public:
|
||||
unsigned get() const { return m_value; }
|
||||
|
||||
protected:
|
||||
EnumSetting(const std::string& name, unsigned default, const std::vector<std::string>& enumNames);
|
||||
|
||||
private:
|
||||
std::string getValueStr() const override;
|
||||
void resetValue() override;
|
||||
void setValue(const std::string& value) override;
|
||||
|
||||
unsigned m_default;
|
||||
unsigned m_value;
|
||||
const std::vector<std::string> m_enumNames;
|
||||
};
|
||||
}
|
||||
|
@ -11,11 +11,11 @@ namespace Config
|
||||
protected:
|
||||
ListSetting(const std::string& name, const std::string& default);
|
||||
|
||||
private:
|
||||
void resetValue() override;
|
||||
void setValue(const std::string& value) override;
|
||||
virtual void setValues(const std::vector<std::string>& values) = 0;
|
||||
|
||||
private:
|
||||
std::string m_default;
|
||||
};
|
||||
}
|
||||
|
56
DDrawCompat/Config/MappedSetting.h
Normal file
56
DDrawCompat/Config/MappedSetting.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Config/Parser.h>
|
||||
#include <Config/Setting.h>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
template <typename Value>
|
||||
class MappedSetting : public Setting
|
||||
{
|
||||
public:
|
||||
Value get() const { return m_value; }
|
||||
|
||||
protected:
|
||||
MappedSetting(const std::string& name, Value default, const std::map<std::string, Value>& valueMapping)
|
||||
: Setting(name)
|
||||
, m_default(default)
|
||||
, m_value(default)
|
||||
, m_valueMapping(valueMapping)
|
||||
{
|
||||
}
|
||||
|
||||
std::string getValueStr() const override
|
||||
{
|
||||
for (const auto& pair : m_valueMapping)
|
||||
{
|
||||
if (pair.second == m_value)
|
||||
{
|
||||
return pair.first;
|
||||
}
|
||||
}
|
||||
throw ParsingError("MappedSetting::getValueStr(): value not found in mapping");
|
||||
}
|
||||
|
||||
void resetValue() override
|
||||
{
|
||||
m_value = m_default;
|
||||
}
|
||||
|
||||
void setValue(const std::string& value) override
|
||||
{
|
||||
auto it = m_valueMapping.find(value);
|
||||
if (it == m_valueMapping.end())
|
||||
{
|
||||
throw ParsingError("invalid value: '" + value + "'");
|
||||
}
|
||||
m_value = it->second;
|
||||
}
|
||||
|
||||
Value m_default;
|
||||
Value m_value;
|
||||
const std::map<std::string, Value> m_valueMapping;
|
||||
};
|
||||
}
|
@ -142,6 +142,30 @@ namespace Config
|
||||
}
|
||||
}
|
||||
|
||||
SIZE parseResolution(const std::string& value)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto pos = value.find('x');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
SIZE resolution = {};
|
||||
resolution.cx = parseUnsigned(value.substr(0, pos));
|
||||
resolution.cy = parseUnsigned(value.substr(pos + 1));
|
||||
if (0 != resolution.cx && resolution.cx <= 65535 &&
|
||||
0 != resolution.cy && resolution.cy <= 65535)
|
||||
{
|
||||
return resolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ParsingError&)
|
||||
{
|
||||
}
|
||||
|
||||
throw ParsingError("invalid resolution: '" + value + "'");
|
||||
}
|
||||
|
||||
unsigned parseUnsigned(const std::string& value)
|
||||
{
|
||||
if (value.empty() || std::string::npos != value.find_first_not_of("0123456789"))
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
class ParsingError : public std::runtime_error
|
||||
@ -17,6 +19,7 @@ namespace Config
|
||||
namespace Parser
|
||||
{
|
||||
void loadAllConfigFiles(const std::filesystem::path& processPath);
|
||||
SIZE parseResolution(const std::string& value);
|
||||
unsigned parseUnsigned(const std::string& value);
|
||||
void registerSetting(Setting& setting);
|
||||
std::string trim(const std::string& str);
|
||||
|
@ -21,11 +21,12 @@ namespace Config
|
||||
void reset();
|
||||
void set(const std::string& value, const std::string& source);
|
||||
|
||||
private:
|
||||
protected:
|
||||
virtual std::string getValueStr() const = 0;
|
||||
virtual void resetValue() = 0;
|
||||
virtual void setValue(const std::string& value) = 0;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_source;
|
||||
};
|
||||
|
39
DDrawCompat/Config/Settings/DisplayResolution.cpp
Normal file
39
DDrawCompat/Config/Settings/DisplayResolution.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include <Config/Settings/DisplayResolution.h>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
DisplayResolution::DisplayResolution()
|
||||
: MappedSetting("DisplayResolution", DESKTOP, { {"app", APP}, {"desktop", DESKTOP} })
|
||||
{
|
||||
}
|
||||
|
||||
std::string DisplayResolution::getValueStr() const
|
||||
{
|
||||
try
|
||||
{
|
||||
return MappedSetting::getValueStr();
|
||||
}
|
||||
catch (const ParsingError&)
|
||||
{
|
||||
return std::to_string(m_value.cx) + 'x' + std::to_string(m_value.cy);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayResolution::setValue(const std::string& value)
|
||||
{
|
||||
try
|
||||
{
|
||||
MappedSetting::setValue(value);
|
||||
}
|
||||
catch (const ParsingError&)
|
||||
{
|
||||
m_value = Parser::parseResolution(value);
|
||||
}
|
||||
}
|
||||
|
||||
const SIZE DisplayResolution::APP = { 0, 0 };
|
||||
const SIZE DisplayResolution::DESKTOP = { 1, 0 };
|
||||
}
|
||||
}
|
25
DDrawCompat/Config/Settings/DisplayResolution.h
Normal file
25
DDrawCompat/Config/Settings/DisplayResolution.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
#include <Config/MappedSetting.h>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
class DisplayResolution : public MappedSetting<SIZE>
|
||||
{
|
||||
public:
|
||||
static const SIZE APP;
|
||||
static const SIZE DESKTOP;
|
||||
|
||||
DisplayResolution();
|
||||
|
||||
protected:
|
||||
std::string getValueStr() const override;
|
||||
void setValue(const std::string& value) override;
|
||||
};
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ namespace
|
||||
D3dDdi::KernelModeThunks::AdapterInfo g_gdiAdapterInfo = {};
|
||||
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
|
||||
Compat::SrwLock g_lastOpenAdapterInfoSrwLock;
|
||||
std::string g_lastDDrawCreateDcDevice;
|
||||
std::string g_lastDDrawDeviceName;
|
||||
|
||||
std::atomic<long long> g_qpcLastVsync = 0;
|
||||
UINT g_vsyncCounter = 0;
|
||||
@ -104,49 +104,39 @@ namespace
|
||||
LOG_FUNC("ddrawCreateDCA", pwszDriver, pwszDevice, pszPort, pdm);
|
||||
if (pwszDevice)
|
||||
{
|
||||
g_lastDDrawCreateDcDevice = pwszDevice;
|
||||
g_lastDDrawDeviceName = pwszDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
MONITORINFOEXA mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
|
||||
g_lastDDrawCreateDcDevice = mi.szDevice;
|
||||
g_lastDDrawDeviceName = mi.szDevice;
|
||||
}
|
||||
return LOG_RESULT(CreateDCA(pwszDriver, pwszDevice, pszPort, pdm));
|
||||
}
|
||||
|
||||
BOOL CALLBACK findDDrawMonitorRect(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
||||
BOOL CALLBACK findMonitorInfo(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
||||
{
|
||||
MONITORINFOEX mi = {};
|
||||
MONITORINFOEXW mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(hMonitor, &mi);
|
||||
if (g_lastDDrawCreateDcDevice == mi.szDevice)
|
||||
CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi);
|
||||
if (0 == wcscmp(reinterpret_cast<MONITORINFOEXW*>(dwData)->szDevice, mi.szDevice))
|
||||
{
|
||||
*reinterpret_cast<RECT*>(dwData) = mi.rcMonitor;
|
||||
*reinterpret_cast<MONITORINFOEXW*>(dwData) = mi;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
D3dDdi::KernelModeThunks::AdapterInfo getAdapterInfo(const D3DKMT_OPENADAPTERFROMHDC& data)
|
||||
D3dDdi::KernelModeThunks::AdapterInfo getAdapterInfo(const std::string& deviceName, const D3DKMT_OPENADAPTERFROMHDC& data)
|
||||
{
|
||||
D3dDdi::KernelModeThunks::AdapterInfo adapterInfo = {};
|
||||
adapterInfo.adapter = data.hAdapter;
|
||||
adapterInfo.vidPnSourceId = data.VidPnSourceId;
|
||||
adapterInfo.luid = data.AdapterLuid;
|
||||
|
||||
EnumDisplayMonitors(nullptr, nullptr, findDDrawMonitorRect,
|
||||
reinterpret_cast<LPARAM>(&adapterInfo.monitorRect));
|
||||
|
||||
if (IsRectEmpty(&adapterInfo.monitorRect))
|
||||
{
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
|
||||
adapterInfo.monitorRect = mi.rcMonitor;
|
||||
}
|
||||
|
||||
wcscpy_s(adapterInfo.monitorInfo.szDevice, std::wstring(deviceName.begin(), deviceName.end()).c_str());
|
||||
EnumDisplayMonitors(nullptr, nullptr, findMonitorInfo, reinterpret_cast<LPARAM>(&adapterInfo.monitorInfo));
|
||||
return adapterInfo;
|
||||
}
|
||||
|
||||
@ -157,7 +147,7 @@ namespace
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
||||
g_lastOpenAdapterInfo = getAdapterInfo(*pData);
|
||||
g_lastOpenAdapterInfo = getAdapterInfo(g_lastDDrawDeviceName, *pData);
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
@ -228,7 +218,7 @@ namespace
|
||||
data.hDc = CreateDC(mi.szDevice, mi.szDevice, nullptr, nullptr);
|
||||
if (SUCCEEDED(D3DKMTOpenAdapterFromHdc(&data)))
|
||||
{
|
||||
g_gdiAdapterInfo = getAdapterInfo(data);
|
||||
g_gdiAdapterInfo = getAdapterInfo(mi.szDevice, data);
|
||||
}
|
||||
DeleteDC(data.hDc);
|
||||
|
||||
@ -295,30 +285,6 @@ namespace D3dDdi
|
||||
return g_lastOpenAdapterInfo;
|
||||
}
|
||||
|
||||
RECT getMonitorRect()
|
||||
{
|
||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||
if (!primary)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
static auto lastDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
|
||||
const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
|
||||
if (currentDisplaySettingsUniqueness != lastDisplaySettingsUniqueness)
|
||||
{
|
||||
lastDisplaySettingsUniqueness = currentDisplaySettingsUniqueness;
|
||||
CompatPtr<IUnknown> ddUnk;
|
||||
primary->GetDDInterface(primary, reinterpret_cast<void**>(&ddUnk.getRef()));
|
||||
CompatPtr<IDirectDraw7> dd7(ddUnk);
|
||||
|
||||
DDDEVICEIDENTIFIER2 di = {};
|
||||
dd7.get()->lpVtbl->GetDeviceIdentifier(dd7, &di, 0);
|
||||
}
|
||||
|
||||
return getLastOpenAdapterInfo().monitorRect;
|
||||
}
|
||||
|
||||
long long getQpcLastVsync()
|
||||
{
|
||||
return g_qpcLastVsync;
|
||||
|
@ -13,12 +13,11 @@ namespace D3dDdi
|
||||
UINT adapter;
|
||||
UINT vidPnSourceId;
|
||||
LUID luid;
|
||||
RECT monitorRect;
|
||||
MONITORINFOEXW monitorInfo;
|
||||
};
|
||||
|
||||
AdapterInfo getAdapterInfo(CompatRef<IDirectDraw7> dd);
|
||||
AdapterInfo getLastOpenAdapterInfo();
|
||||
RECT getMonitorRect();
|
||||
long long getQpcLastVsync();
|
||||
UINT getVsyncCounter();
|
||||
void installHooks();
|
||||
|
@ -9,46 +9,49 @@
|
||||
#include <D3dDdi/KernelModeThunks.h>
|
||||
#include <D3dDdi/Log/DeviceFuncsLog.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <D3dDdi/SurfaceRepository.h>
|
||||
#include <DDraw/Blitter.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/Palette.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
|
||||
void splitToTiles(D3DDDIARG_CREATERESOURCE& data, const UINT tileWidth, const UINT tileHeight);
|
||||
|
||||
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
|
||||
RECT g_presentationRect = {};
|
||||
|
||||
RECT calculatePresentationRect()
|
||||
{
|
||||
const RECT srcRect = DDraw::PrimarySurface::getMonitorRect();
|
||||
const RECT dstRect = DDraw::RealPrimarySurface::getMonitorRect();
|
||||
|
||||
const int srcWidth = srcRect.right - srcRect.left;
|
||||
const int srcHeight = srcRect.bottom - srcRect.top;
|
||||
const int dstWidth = dstRect.right - dstRect.left;
|
||||
const int dstHeight = dstRect.bottom - dstRect.top;
|
||||
|
||||
RECT rect = { 0, 0, dstWidth, dstHeight };
|
||||
if (dstWidth * srcHeight > dstHeight * srcWidth)
|
||||
{
|
||||
rect.right = dstHeight * srcWidth / srcHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.bottom = dstWidth * srcHeight / srcWidth;
|
||||
}
|
||||
|
||||
OffsetRect(&rect, (dstWidth - rect.right) / 2, (dstHeight - rect.bottom) / 2);
|
||||
return rect;
|
||||
}
|
||||
|
||||
LONG divCeil(LONG n, LONG d)
|
||||
{
|
||||
return (n + d - 1) / d;
|
||||
}
|
||||
|
||||
void fixResourceData(D3dDdi::Device& device, D3DDDIARG_CREATERESOURCE& data)
|
||||
{
|
||||
if (data.Flags.Primary)
|
||||
{
|
||||
data.Format = D3DDDIFMT_X8R8G8B8;
|
||||
}
|
||||
|
||||
const bool isOffScreenPlain = 0 == (data.Flags.Value & g_resourceTypeFlags);
|
||||
if (D3DDDIPOOL_SYSTEMMEM == data.Pool &&
|
||||
(isOffScreenPlain || data.Flags.Texture) &&
|
||||
1 == data.SurfCount &&
|
||||
0 == data.pSurfList[0].Depth &&
|
||||
0 != D3dDdi::getFormatInfo(data.Format).bytesPerPixel)
|
||||
{
|
||||
const auto& caps = device.getAdapter().getD3dExtendedCaps();
|
||||
const auto& surfaceInfo = data.pSurfList[0];
|
||||
if (0 != caps.dwMaxTextureWidth && surfaceInfo.Width > caps.dwMaxTextureWidth ||
|
||||
0 != caps.dwMaxTextureHeight && surfaceInfo.Height > caps.dwMaxTextureHeight)
|
||||
{
|
||||
splitToTiles(data, caps.dwMaxTextureWidth, caps.dwMaxTextureHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3DDDI_RESOURCEFLAGS getResourceTypeFlags()
|
||||
{
|
||||
D3DDDI_RESOURCEFLAGS flags = {};
|
||||
@ -77,32 +80,6 @@ namespace
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, p);
|
||||
}
|
||||
|
||||
void splitToTiles(D3DDDIARG_CREATERESOURCE& data, const UINT tileWidth, const UINT tileHeight)
|
||||
{
|
||||
static std::vector<D3DDDI_SURFACEINFO> tiles;
|
||||
tiles.clear();
|
||||
|
||||
const UINT bytesPerPixel = D3dDdi::getFormatInfo(data.Format).bytesPerPixel;
|
||||
|
||||
for (UINT y = 0; y < data.pSurfList[0].Height; y += tileHeight)
|
||||
{
|
||||
for (UINT x = 0; x < data.pSurfList[0].Width; x += tileWidth)
|
||||
{
|
||||
D3DDDI_SURFACEINFO tile = {};
|
||||
tile.Width = min(data.pSurfList[0].Width - x, tileWidth);
|
||||
tile.Height = min(data.pSurfList[0].Height - y, tileHeight);
|
||||
tile.pSysMem = static_cast<const unsigned char*>(data.pSurfList[0].pSysMem) +
|
||||
y * data.pSurfList[0].SysMemPitch + x * bytesPerPixel;
|
||||
tile.SysMemPitch = data.pSurfList[0].SysMemPitch;
|
||||
tiles.push_back(tile);
|
||||
}
|
||||
}
|
||||
|
||||
data.SurfCount = tiles.size();
|
||||
data.pSurfList = tiles.data();
|
||||
data.Flags.Texture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace D3dDdi
|
||||
@ -133,7 +110,12 @@ namespace D3dDdi
|
||||
throw HResultException(E_FAIL);
|
||||
}
|
||||
|
||||
fixResourceData(device, reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(m_fixedData));
|
||||
if (m_origData.Flags.Primary)
|
||||
{
|
||||
g_presentationRect = calculatePresentationRect();
|
||||
}
|
||||
|
||||
fixResourceData();
|
||||
m_formatInfo = getFormatInfo(m_fixedData.Format);
|
||||
|
||||
HRESULT result = m_device.createPrivateResource(m_fixedData);
|
||||
@ -327,7 +309,7 @@ namespace D3dDdi
|
||||
|
||||
void Resource::createGdiLockResource()
|
||||
{
|
||||
auto gdiSurfaceDesc(Gdi::VirtualScreen::getSurfaceDesc(D3dDdi::KernelModeThunks::getMonitorRect()));
|
||||
auto gdiSurfaceDesc(Gdi::VirtualScreen::getSurfaceDesc(DDraw::RealPrimarySurface::getMonitorRect()));
|
||||
if (!gdiSurfaceDesc.lpSurface)
|
||||
{
|
||||
return;
|
||||
@ -431,6 +413,39 @@ namespace D3dDdi
|
||||
#endif
|
||||
}
|
||||
|
||||
void Resource::fixResourceData()
|
||||
{
|
||||
if (m_fixedData.Flags.Primary)
|
||||
{
|
||||
RECT r = DDraw::RealPrimarySurface::getMonitorRect();
|
||||
if (!IsRectEmpty(&r))
|
||||
{
|
||||
for (auto& surface : m_fixedData.surfaceData)
|
||||
{
|
||||
surface.Width = r.right - r.left;
|
||||
surface.Height = r.bottom - r.top;
|
||||
}
|
||||
}
|
||||
m_fixedData.Format = D3DDDIFMT_X8R8G8B8;
|
||||
}
|
||||
|
||||
const bool isOffScreenPlain = 0 == (m_fixedData.Flags.Value & g_resourceTypeFlags);
|
||||
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool &&
|
||||
(isOffScreenPlain || m_fixedData.Flags.Texture) &&
|
||||
1 == m_fixedData.SurfCount &&
|
||||
0 == m_fixedData.pSurfList[0].Depth &&
|
||||
0 != D3dDdi::getFormatInfo(m_fixedData.Format).bytesPerPixel)
|
||||
{
|
||||
const auto& caps = m_device.getAdapter().getD3dExtendedCaps();
|
||||
const auto& surfaceInfo = m_fixedData.pSurfList[0];
|
||||
if (0 != caps.dwMaxTextureWidth && surfaceInfo.Width > caps.dwMaxTextureWidth ||
|
||||
0 != caps.dwMaxTextureHeight && surfaceInfo.Height > caps.dwMaxTextureHeight)
|
||||
{
|
||||
splitToTiles(caps.dwMaxTextureWidth, caps.dwMaxTextureHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* Resource::getLockPtr(UINT subResourceIndex)
|
||||
{
|
||||
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
|
||||
@ -496,16 +511,24 @@ namespace D3dDdi
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT Resource::presentationBlt(const D3DDDIARG_BLT& data, Resource& srcResource)
|
||||
HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource& srcResource)
|
||||
{
|
||||
if (srcResource.m_lockResource &&
|
||||
srcResource.m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate)
|
||||
srcResource.m_lockData[0].isSysMemUpToDate)
|
||||
{
|
||||
srcResource.copyToVidMem(data.SrcSubResourceIndex);
|
||||
srcResource.copyToVidMem(0);
|
||||
}
|
||||
|
||||
if (D3DDDIFMT_P8 == srcResource.m_origData.Format)
|
||||
{
|
||||
const auto& si = srcResource.m_fixedData.pSurfList[0];
|
||||
auto palettizedBltRenderTarget(SurfaceRepository::get(m_device.getAdapter()).getPaletteBltRenderTarget(
|
||||
si.Width, si.Height));
|
||||
if (!palettizedBltRenderTarget)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
auto entries(Gdi::Palette::getHardwarePalette());
|
||||
RGBQUAD pal[256] = {};
|
||||
for (UINT i = 0; i < 256; ++i)
|
||||
@ -515,10 +538,14 @@ namespace D3dDdi
|
||||
pal[i].rgbBlue = entries[i].peBlue;
|
||||
}
|
||||
|
||||
m_device.getShaderBlitter().palettizedBlt(*this, data.DstSubResourceIndex, srcResource, pal);
|
||||
return S_OK;
|
||||
m_device.getShaderBlitter().palettizedBlt(*palettizedBltRenderTarget, 0, srcResource, pal);
|
||||
data.hSrcResource = *palettizedBltRenderTarget;
|
||||
data.SrcSubResourceIndex = 0;
|
||||
}
|
||||
|
||||
data.DstRect = g_presentationRect;
|
||||
data.Flags.Linear = 1;
|
||||
data.Flags.Point = 0;
|
||||
return m_device.getOrigVtable().pfnBlt(m_device, &data);
|
||||
}
|
||||
|
||||
@ -598,6 +625,31 @@ namespace D3dDdi
|
||||
return LOG_RESULT(S_OK);
|
||||
}
|
||||
|
||||
void Resource::splitToTiles(UINT tileWidth, UINT tileHeight)
|
||||
{
|
||||
std::vector<D3DDDI_SURFACEINFO> tiles;
|
||||
const UINT bytesPerPixel = getFormatInfo(m_fixedData.Format).bytesPerPixel;
|
||||
|
||||
for (UINT y = 0; y < m_fixedData.pSurfList[0].Height; y += tileHeight)
|
||||
{
|
||||
for (UINT x = 0; x < m_fixedData.pSurfList[0].Width; x += tileWidth)
|
||||
{
|
||||
D3DDDI_SURFACEINFO tile = {};
|
||||
tile.Width = min(m_fixedData.pSurfList[0].Width - x, tileWidth);
|
||||
tile.Height = min(m_fixedData.pSurfList[0].Height - y, tileHeight);
|
||||
tile.pSysMem = static_cast<const unsigned char*>(m_fixedData.pSurfList[0].pSysMem) +
|
||||
y * m_fixedData.pSurfList[0].SysMemPitch + x * bytesPerPixel;
|
||||
tile.SysMemPitch = m_fixedData.pSurfList[0].SysMemPitch;
|
||||
tiles.push_back(tile);
|
||||
}
|
||||
}
|
||||
|
||||
m_fixedData.surfaceData = tiles;
|
||||
m_fixedData.SurfCount = m_fixedData.surfaceData.size();
|
||||
m_fixedData.pSurfList = m_fixedData.surfaceData.data();
|
||||
m_fixedData.Flags.Texture = 0;
|
||||
}
|
||||
|
||||
HRESULT Resource::sysMemPreferredBlt(const D3DDDIARG_BLT& data, Resource& srcResource)
|
||||
{
|
||||
if (m_fixedData.Format == srcResource.m_fixedData.Format &&
|
||||
|
@ -80,14 +80,16 @@ namespace D3dDdi
|
||||
void createGdiLockResource();
|
||||
void createLockResource();
|
||||
void createSysMemResource(const std::vector<D3DDDI_SURFACEINFO>& surfaceInfo);
|
||||
void fixResourceData();
|
||||
bool isOversized() const;
|
||||
bool isValidRect(UINT subResourceIndex, const RECT& rect);
|
||||
HRESULT presentationBlt(const D3DDDIARG_BLT& data, Resource& srcResource);
|
||||
HRESULT presentationBlt(D3DDDIARG_BLT data, Resource& srcResource);
|
||||
HRESULT splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect);
|
||||
|
||||
template <typename Arg>
|
||||
HRESULT splitLock(Arg& data, HRESULT(APIENTRY *lockFunc)(HANDLE, Arg*));
|
||||
|
||||
void splitToTiles(UINT tileWidth, UINT tileHeight);
|
||||
HRESULT sysMemPreferredBlt(const D3DDDIARG_BLT& data, Resource& srcResource);
|
||||
|
||||
Device& m_device;
|
||||
|
@ -1,55 +1,15 @@
|
||||
#include <map>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
#include <Common/Log.h>
|
||||
#include <D3dDdi/Adapter.h>
|
||||
#include <D3dDdi/Device.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <D3dDdi/ShaderBlitter.h>
|
||||
#include <DDraw/DirectDrawSurface.h>
|
||||
#include <D3dDdi/SurfaceRepository.h>
|
||||
#include <Shaders/PaletteLookup.h>
|
||||
|
||||
#define CONCAT_(a, b) a##b
|
||||
#define CONCAT(a, b) CONCAT_(a, b)
|
||||
#define SCOPED_STATE(state, ...) DeviceState::Scoped##state CONCAT(scopedState, __LINE__)(m_device.getState(), __VA_ARGS__)
|
||||
|
||||
namespace
|
||||
{
|
||||
std::map<LUID, CompatWeakPtr<IDirectDrawSurface7>> g_paletteTextures;
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> getPaletteTexture(CompatWeakPtr<IDirectDraw7> dd, LUID luid)
|
||||
{
|
||||
LOG_FUNC("ShaderBlitter::getPaletteTexture", dd.get(), luid);
|
||||
if (!dd)
|
||||
{
|
||||
LOG_ONCE("Failed to create palette texture: no DirectDraw repository available")
|
||||
return LOG_RESULT(nullptr);
|
||||
}
|
||||
|
||||
auto it = g_paletteTextures.find(luid);
|
||||
if (it == g_paletteTextures.end())
|
||||
{
|
||||
CompatPtr<IDirectDrawSurface7> paletteTexture;
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
|
||||
desc.dwWidth = 256;
|
||||
desc.dwHeight = 1;
|
||||
desc.ddpfPixelFormat = DDraw::DirectDraw::getRgbPixelFormat(32);
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
|
||||
|
||||
HRESULT result = dd->CreateSurface(dd, &desc, &paletteTexture.getRef(), nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to create palette texture: " << Compat::hex(result));
|
||||
return nullptr;
|
||||
}
|
||||
it = g_paletteTextures.insert({ luid, paletteTexture.detach() }).first;
|
||||
}
|
||||
return LOG_RESULT(it->second.get());
|
||||
}
|
||||
}
|
||||
|
||||
namespace D3dDdi
|
||||
{
|
||||
ShaderBlitter::ShaderBlitter(Device& device)
|
||||
@ -124,7 +84,8 @@ namespace D3dDdi
|
||||
dp.PrimitiveType = D3DPT_TRIANGLEFAN;
|
||||
dp.VStart = 0;
|
||||
dp.PrimitiveCount = 2;
|
||||
m_device.getDrawPrimitive().draw(dp, nullptr);
|
||||
m_device.pfnDrawPrimitive(&dp, nullptr);
|
||||
m_device.flushPrimitives();
|
||||
}
|
||||
|
||||
HANDLE ShaderBlitter::createPixelShader(const BYTE* code, UINT size)
|
||||
@ -167,39 +128,33 @@ namespace D3dDdi
|
||||
LOG_FUNC("ShaderBlitter::palettizedBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex,
|
||||
static_cast<HANDLE>(srcResource), Compat::array(reinterpret_cast<void**>(palette), 256));
|
||||
|
||||
if (m_paletteTexture && FAILED(m_paletteTexture->IsLost(m_paletteTexture)))
|
||||
{
|
||||
g_paletteTextures.erase(m_device.getAdapter().getLuid());
|
||||
m_paletteTexture->Release(m_paletteTexture);
|
||||
m_paletteTexture = nullptr;
|
||||
}
|
||||
|
||||
if (!m_paletteTexture)
|
||||
{
|
||||
m_paletteTexture = getPaletteTexture(m_device.getAdapter().getRepository(), m_device.getAdapter().getLuid());
|
||||
if (!m_paletteTexture)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
m_paletteTexture->Lock(m_paletteTexture, nullptr, &desc, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, nullptr);
|
||||
if (!desc.lpSurface)
|
||||
auto paletteTexture(SurfaceRepository::get(m_device.getAdapter()).getPaletteTexture());
|
||||
if (!paletteTexture)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(desc.lpSurface, palette, 256 * sizeof(RGBQUAD));
|
||||
m_paletteTexture->Unlock(m_paletteTexture, nullptr);
|
||||
D3DDDIARG_LOCK lock = {};
|
||||
lock.hResource = *paletteTexture;
|
||||
lock.Flags.Discard = 1;
|
||||
m_device.getOrigVtable().pfnLock(m_device, &lock);
|
||||
if (!lock.pSurfData)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(lock.pSurfData, palette, 256 * sizeof(RGBQUAD));
|
||||
|
||||
D3DDDIARG_UNLOCK unlock = {};
|
||||
unlock.hResource = *paletteTexture;
|
||||
m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
|
||||
|
||||
const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex];
|
||||
const auto& srcSurface = srcResource.getFixedDesc().pSurfList[0];
|
||||
const RECT dstRect = { 0, 0, static_cast<LONG>(dstSurface.Width), static_cast<LONG>(dstSurface.Height) };
|
||||
const RECT srcRect = { 0, 0, static_cast<LONG>(srcSurface.Width), static_cast<LONG>(srcSurface.Height) };
|
||||
|
||||
SCOPED_STATE(Texture, 1, DDraw::DirectDrawSurface::getDriverResourceHandle(*m_paletteTexture), D3DTEXF_POINT);
|
||||
SCOPED_STATE(Texture, 1, *paletteTexture, D3DTEXF_POINT);
|
||||
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psPaletteLookup, D3DTEXF_POINT);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
#include <Common/CompatWeakPtr.h>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace D3dDdi
|
||||
{
|
||||
@ -29,7 +27,6 @@ namespace D3dDdi
|
||||
HANDLE createVertexShaderDecl();
|
||||
|
||||
Device& m_device;
|
||||
CompatWeakPtr<IDirectDrawSurface7> m_paletteTexture;
|
||||
HANDLE m_psPaletteLookup;
|
||||
HANDLE m_vertexShaderDecl;
|
||||
};
|
||||
|
98
DDrawCompat/D3dDdi/SurfaceRepository.cpp
Normal file
98
DDrawCompat/D3dDdi/SurfaceRepository.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include <map>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
#include <D3dDdi/Adapter.h>
|
||||
#include <D3dDdi/Device.h>
|
||||
#include <D3dDdi/SurfaceRepository.h>
|
||||
#include <DDraw/DirectDrawSurface.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::map<LUID, D3dDdi::SurfaceRepository> g_repositories;
|
||||
}
|
||||
|
||||
namespace D3dDdi
|
||||
{
|
||||
SurfaceRepository::SurfaceRepository(const Adapter& adapter)
|
||||
: m_adapter(adapter)
|
||||
{
|
||||
}
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> SurfaceRepository::createSurface(
|
||||
DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps)
|
||||
{
|
||||
auto dd(m_adapter.getRepository());
|
||||
if (!dd)
|
||||
{
|
||||
LOG_ONCE("ERROR: no DirectDraw repository available");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> surface;
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
|
||||
desc.dwWidth = width;
|
||||
desc.dwHeight = height;
|
||||
desc.ddpfPixelFormat = pf;
|
||||
desc.ddsCaps.dwCaps = caps;
|
||||
|
||||
HRESULT result = dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("ERROR: Failed to create repository surface: " << Compat::hex(result) << " " << desc);
|
||||
return nullptr;
|
||||
}
|
||||
return surface.detach();
|
||||
}
|
||||
|
||||
SurfaceRepository& SurfaceRepository::get(const Adapter& adapter)
|
||||
{
|
||||
auto it = g_repositories.find(adapter.getLuid());
|
||||
if (it != g_repositories.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return g_repositories.emplace(adapter.getLuid(), SurfaceRepository(adapter)).first->second;
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getPaletteBltRenderTarget(DWORD width, DWORD height)
|
||||
{
|
||||
return getResource(m_paletteBltRenderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32),
|
||||
DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getPaletteTexture()
|
||||
{
|
||||
return getResource(m_paletteTexture, 256, 1, DDraw::DirectDraw::getRgbPixelFormat(32),
|
||||
DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps)
|
||||
{
|
||||
if (surface.surface)
|
||||
{
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
surface.surface->GetSurfaceDesc(surface.surface, &desc);
|
||||
if (desc.dwWidth != width || desc.dwHeight != height || FAILED(surface.surface->IsLost(surface.surface)))
|
||||
{
|
||||
surface.surface->Release(surface.surface);
|
||||
surface = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!surface.surface)
|
||||
{
|
||||
surface.surface = createSurface(width, height, pf, caps);
|
||||
if (surface.surface)
|
||||
{
|
||||
surface.resource = D3dDdi::Device::findResource(
|
||||
DDraw::DirectDrawSurface::getDriverResourceHandle(*surface.surface));
|
||||
}
|
||||
}
|
||||
|
||||
return surface.resource;
|
||||
}
|
||||
}
|
36
DDrawCompat/D3dDdi/SurfaceRepository.h
Normal file
36
DDrawCompat/D3dDdi/SurfaceRepository.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
#include <Common/CompatWeakPtr.h>
|
||||
|
||||
namespace D3dDdi
|
||||
{
|
||||
class Adapter;
|
||||
class Resource;
|
||||
|
||||
class SurfaceRepository
|
||||
{
|
||||
public:
|
||||
Resource* getPaletteBltRenderTarget(DWORD width, DWORD height);
|
||||
Resource* getPaletteTexture();
|
||||
|
||||
static SurfaceRepository& get(const Adapter& adapter);
|
||||
|
||||
private:
|
||||
struct Surface
|
||||
{
|
||||
CompatWeakPtr<IDirectDrawSurface7> surface;
|
||||
Resource* resource;
|
||||
};
|
||||
|
||||
SurfaceRepository(const Adapter& adapter);
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
|
||||
Resource* getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
|
||||
|
||||
const Adapter& m_adapter;
|
||||
Surface m_paletteBltRenderTarget;
|
||||
Surface m_paletteTexture;
|
||||
};
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#include <Common/CompatVtable.h>
|
||||
#include <D3dDdi/KernelModeThunks.h>
|
||||
#include <DDraw/DirectDrawClipper.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/ScopedThreadLock.h>
|
||||
#include <DDraw/Surfaces/Surface.h>
|
||||
#include <DDraw/Visitors/DirectDrawClipperVtblVisitor.h>
|
||||
@ -45,7 +46,7 @@ namespace
|
||||
GetRandomRgn(dc, rgn, SYSRGN);
|
||||
CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc);
|
||||
|
||||
RECT primaryRect = D3dDdi::KernelModeThunks::getMonitorRect();
|
||||
RECT primaryRect = DDraw::RealPrimarySurface::getMonitorRect();
|
||||
if (0 != primaryRect.left || 0 != primaryRect.top)
|
||||
{
|
||||
rgn.offset(-primaryRect.left, -primaryRect.top);
|
||||
|
@ -27,6 +27,7 @@ namespace
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
||||
CompatWeakPtr<IDirectDrawClipper> g_clipper;
|
||||
RECT g_monitorRect = {};
|
||||
DDSURFACEDESC2 g_surfaceDesc = {};
|
||||
DDraw::IReleaseNotifier g_releaseNotifier(onRelease);
|
||||
|
||||
@ -121,6 +122,7 @@ namespace
|
||||
g_isFullScreen = false;
|
||||
g_waitingForPrimaryUnlock = false;
|
||||
g_surfaceDesc = {};
|
||||
g_monitorRect = {};
|
||||
}
|
||||
|
||||
void onRestore()
|
||||
@ -164,8 +166,7 @@ namespace
|
||||
return;
|
||||
}
|
||||
|
||||
RECT monitorRect = D3dDdi::KernelModeThunks::getMonitorRect();
|
||||
Gdi::Region excludeRegion(monitorRect);
|
||||
Gdi::Region excludeRegion(DDraw::PrimarySurface::getMonitorRect());
|
||||
Gdi::Window::present(excludeRegion);
|
||||
|
||||
D3dDdi::KernelModeThunks::setDcPaletteOverride(true);
|
||||
@ -177,7 +178,7 @@ namespace
|
||||
auto backBuffer(getBackBuffer());
|
||||
if (backBuffer)
|
||||
{
|
||||
POINT offset = { -monitorRect.left, -monitorRect.top };
|
||||
POINT offset = { -g_monitorRect.left, -g_monitorRect.top };
|
||||
Gdi::Window::presentLayered(*backBuffer, offset);
|
||||
}
|
||||
}
|
||||
@ -251,6 +252,7 @@ namespace DDraw
|
||||
HRESULT RealPrimarySurface::create(CompatRef<DirectDraw> dd)
|
||||
{
|
||||
DDraw::ScopedThreadLock lock;
|
||||
g_monitorRect = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).monitorInfo.rcMonitor;
|
||||
|
||||
typename Types<DirectDraw>::TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
@ -272,6 +274,7 @@ namespace DDraw
|
||||
if (FAILED(result))
|
||||
{
|
||||
Compat::Log() << "ERROR: Failed to create the real primary surface: " << Compat::hex(result);
|
||||
g_monitorRect = {};
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -349,6 +352,11 @@ namespace DDraw
|
||||
return gammaControl->GetGammaRamp(gammaControl, 0, rampData);
|
||||
}
|
||||
|
||||
RECT RealPrimarySurface::getMonitorRect()
|
||||
{
|
||||
return g_monitorRect;
|
||||
}
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> RealPrimarySurface::getSurface()
|
||||
{
|
||||
return g_frontBuffer;
|
||||
|
@ -18,6 +18,7 @@ namespace DDraw
|
||||
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
|
||||
static void flush();
|
||||
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
||||
static RECT getMonitorRect();
|
||||
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
||||
static void init();
|
||||
static bool isFullScreen();
|
||||
|
@ -19,6 +19,7 @@ namespace
|
||||
DWORD g_origCaps = 0;
|
||||
HWND g_deviceWindow = nullptr;
|
||||
HPALETTE g_palette = nullptr;
|
||||
RECT g_monitorRect = {};
|
||||
}
|
||||
|
||||
namespace DDraw
|
||||
@ -37,6 +38,7 @@ namespace DDraw
|
||||
DeleteObject(g_palette);
|
||||
g_palette = nullptr;
|
||||
}
|
||||
g_monitorRect = {};
|
||||
s_palette = nullptr;
|
||||
|
||||
DDraw::RealPrimarySurface::release();
|
||||
@ -45,6 +47,11 @@ namespace DDraw
|
||||
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
|
||||
HRESULT PrimarySurface::create(CompatRef<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface)
|
||||
{
|
||||
const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd));
|
||||
g_monitorRect = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).monitorInfo.rcMonitor;
|
||||
g_monitorRect.right = g_monitorRect.left + dm.dwWidth;
|
||||
g_monitorRect.bottom = g_monitorRect.top + dm.dwHeight;
|
||||
|
||||
HRESULT result = RealPrimarySurface::create(dd);
|
||||
if (FAILED(result))
|
||||
{
|
||||
@ -53,7 +60,6 @@ namespace DDraw
|
||||
|
||||
const DWORD origCaps = desc.ddsCaps.dwCaps;
|
||||
|
||||
const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd));
|
||||
desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
desc.dwWidth = dm.dwWidth;
|
||||
desc.dwHeight = dm.dwHeight;
|
||||
@ -68,6 +74,7 @@ namespace DDraw
|
||||
if (FAILED(result))
|
||||
{
|
||||
Compat::Log() << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result);
|
||||
g_monitorRect = {};
|
||||
RealPrimarySurface::release();
|
||||
return result;
|
||||
}
|
||||
@ -180,6 +187,11 @@ namespace DDraw
|
||||
return g_frontResource;
|
||||
}
|
||||
|
||||
RECT PrimarySurface::getMonitorRect()
|
||||
{
|
||||
return g_monitorRect;
|
||||
}
|
||||
|
||||
DWORD PrimarySurface::getOrigCaps()
|
||||
{
|
||||
return g_origCaps;
|
||||
@ -210,7 +222,7 @@ namespace DDraw
|
||||
m_surface->GetSurfaceDesc(m_surface, &desc);
|
||||
if (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
||||
{
|
||||
DDSURFACEDESC2 gdiDesc = Gdi::VirtualScreen::getSurfaceDesc(D3dDdi::KernelModeThunks::getMonitorRect());
|
||||
DDSURFACEDESC2 gdiDesc = Gdi::VirtualScreen::getSurfaceDesc(g_monitorRect);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE;
|
||||
desc.lPitch = gdiDesc.lPitch;
|
||||
desc.lpSurface = gdiDesc.lpSurface;
|
||||
|
@ -21,6 +21,7 @@ namespace DDraw
|
||||
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
|
||||
static CompatPtr<IDirectDrawSurface7> getBackBuffer();
|
||||
static CompatPtr<IDirectDrawSurface7> getLastSurface();
|
||||
static RECT getMonitorRect();
|
||||
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
|
||||
static HANDLE getFrontResource();
|
||||
static DWORD getOrigCaps();
|
||||
|
@ -32,7 +32,7 @@ namespace
|
||||
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper));
|
||||
RECT monitorRect = D3dDdi::KernelModeThunks::getMonitorRect();
|
||||
RECT monitorRect = DDraw::RealPrimarySurface::getMonitorRect();
|
||||
RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds();
|
||||
clipRgn.offset(monitorRect.left, monitorRect.top);
|
||||
clipRgn &= virtualScreenBounds;
|
||||
|
@ -210,9 +210,11 @@
|
||||
<ClInclude Include="Config\Config.h" />
|
||||
<ClInclude Include="Config\EnumSetting.h" />
|
||||
<ClInclude Include="Config\ListSetting.h" />
|
||||
<ClInclude Include="Config\MappedSetting.h" />
|
||||
<ClInclude Include="Config\Parser.h" />
|
||||
<ClInclude Include="Config\Setting.h" />
|
||||
<ClInclude Include="Config\Settings\CpuAffinity.h" />
|
||||
<ClInclude Include="Config\Settings\DisplayResolution.h" />
|
||||
<ClInclude Include="Config\Settings\ThreadPriorityBoost.h" />
|
||||
<ClInclude Include="D3dDdi\Adapter.h" />
|
||||
<ClInclude Include="D3dDdi\AdapterCallbacks.h" />
|
||||
@ -234,6 +236,7 @@
|
||||
<ClInclude Include="D3dDdi\Resource.h" />
|
||||
<ClInclude Include="D3dDdi\ScopedCriticalSection.h" />
|
||||
<ClInclude Include="D3dDdi\ShaderBlitter.h" />
|
||||
<ClInclude Include="D3dDdi\SurfaceRepository.h" />
|
||||
<ClInclude Include="D3dDdi\Visitors\AdapterCallbacksVisitor.h" />
|
||||
<ClInclude Include="D3dDdi\Visitors\AdapterFuncsVisitor.h" />
|
||||
<ClInclude Include="D3dDdi\Visitors\DeviceCallbacksVisitor.h" />
|
||||
@ -314,6 +317,7 @@
|
||||
<ClCompile Include="Config\Parser.cpp" />
|
||||
<ClCompile Include="Config\Setting.cpp" />
|
||||
<ClCompile Include="Config\Settings\CpuAffinity.cpp" />
|
||||
<ClCompile Include="Config\Settings\DisplayResolution.cpp" />
|
||||
<ClCompile Include="D3dDdi\Adapter.cpp" />
|
||||
<ClCompile Include="D3dDdi\AdapterCallbacks.cpp" />
|
||||
<ClCompile Include="D3dDdi\AdapterFuncs.cpp" />
|
||||
@ -334,6 +338,7 @@
|
||||
<ClCompile Include="D3dDdi\Resource.cpp" />
|
||||
<ClCompile Include="D3dDdi\ScopedCriticalSection.cpp" />
|
||||
<ClCompile Include="D3dDdi\ShaderBlitter.cpp" />
|
||||
<ClCompile Include="D3dDdi\SurfaceRepository.cpp" />
|
||||
<ClCompile Include="DDraw\Blitter.cpp" />
|
||||
<ClCompile Include="DDraw\DirectDraw.cpp" />
|
||||
<ClCompile Include="DDraw\DirectDrawClipper.cpp" />
|
||||
|
@ -426,6 +426,15 @@
|
||||
<ClInclude Include="Common\Comparison.h">
|
||||
<Filter>Header Files\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\Settings\DisplayResolution.h">
|
||||
<Filter>Header Files\Config\Settings</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\MappedSetting.h">
|
||||
<Filter>Header Files\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3dDdi\SurfaceRepository.h">
|
||||
<Filter>Header Files\D3dDdi</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -668,6 +677,12 @@
|
||||
<ClCompile Include="D3dDdi\ShaderBlitter.cpp">
|
||||
<Filter>Source Files\D3dDdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\Settings\DisplayResolution.cpp">
|
||||
<Filter>Source Files\Config\Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3dDdi\SurfaceRepository.cpp">
|
||||
<Filter>Source Files\D3dDdi</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DDrawCompat.rc">
|
||||
|
@ -3,18 +3,52 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <Gdi/Metrics.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
decltype(&GetSystemMetricsForDpi) g_origGetSystemMetricsForDpi = nullptr;
|
||||
|
||||
int getAdjustedDisplayMetrics(int nIndex, int cxIndex)
|
||||
{
|
||||
int result = CALL_ORIG_FUNC(GetSystemMetrics)(nIndex);
|
||||
auto dm = Win32::DisplayMode::getEmulatedDisplayMode();
|
||||
if (0 == dm.rect.left && 0 == dm.rect.top)
|
||||
{
|
||||
result += (nIndex == cxIndex) ? dm.diff.cx : dm.diff.cy;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int WINAPI getSystemMetrics(int nIndex)
|
||||
{
|
||||
LOG_FUNC("GetSystemMetrics", nIndex);
|
||||
if (SM_CXSIZE == nIndex)
|
||||
|
||||
switch (nIndex)
|
||||
{
|
||||
nIndex = SM_CYSIZE;
|
||||
case SM_CXSCREEN:
|
||||
case SM_CYSCREEN:
|
||||
{
|
||||
return LOG_RESULT(getAdjustedDisplayMetrics(nIndex, SM_CXSCREEN));
|
||||
}
|
||||
|
||||
case SM_CXFULLSCREEN:
|
||||
case SM_CYFULLSCREEN:
|
||||
{
|
||||
return LOG_RESULT(getAdjustedDisplayMetrics(nIndex, SM_CXFULLSCREEN));
|
||||
}
|
||||
|
||||
case SM_CXMAXIMIZED:
|
||||
case SM_CYMAXIMIZED:
|
||||
{
|
||||
return LOG_RESULT(getAdjustedDisplayMetrics(nIndex, SM_CXMAXIMIZED));
|
||||
}
|
||||
|
||||
case SM_CXSIZE:
|
||||
nIndex = SM_CYSIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
return LOG_RESULT(CALL_ORIG_FUNC(GetSystemMetrics)(nIndex));
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <Gdi/TitleBar.h>
|
||||
#include <Gdi/Window.h>
|
||||
#include <Gdi/WinProc.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -34,6 +35,7 @@ namespace
|
||||
bool isUser32ScrollBar(HWND hwnd);
|
||||
void onCreateWindow(HWND hwnd);
|
||||
void onDestroyWindow(HWND hwnd);
|
||||
void onGetMinMaxInfo(MINMAXINFO& mmi);
|
||||
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp);
|
||||
void onWindowPosChanging(HWND hwnd, WINDOWPOS& wp);
|
||||
void setWindowProc(HWND hwnd, WNDPROC wndProcA, WNDPROC wndProcW);
|
||||
@ -45,6 +47,20 @@ namespace
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_DISPLAYCHANGE:
|
||||
{
|
||||
if (0 != wParam)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
wParam = Win32::DisplayMode::getBpp();
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_GETMINMAXINFO:
|
||||
onGetMinMaxInfo(*reinterpret_cast<MINMAXINFO*>(lParam));
|
||||
break;
|
||||
|
||||
case WM_SYNCPAINT:
|
||||
if (isTopLevelWindow(hwnd))
|
||||
{
|
||||
@ -266,6 +282,15 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void onGetMinMaxInfo(MINMAXINFO& mmi)
|
||||
{
|
||||
MONITORINFOEXA mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfoA(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
|
||||
mmi.ptMaxSize.x = mi.rcMonitor.right - 2 * mmi.ptMaxPosition.x;
|
||||
mmi.ptMaxSize.y = mi.rcMonitor.bottom - 2 * mmi.ptMaxPosition.y;
|
||||
}
|
||||
|
||||
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp)
|
||||
{
|
||||
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
||||
|
@ -1,8 +1,12 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
#include <Common/CompatPtr.h>
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/ScopedSrwLock.h>
|
||||
#include <Config/Config.h>
|
||||
#include <DDraw/DirectDraw.h>
|
||||
#include <DDraw/ScopedThreadLock.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
@ -10,10 +14,14 @@
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
BOOL WINAPI DWM8And16Bit_IsShimApplied_CallOut() { return FALSE; }
|
||||
ULONG WINAPI GdiEntry13() { return 0; }
|
||||
BOOL WINAPI SE_COM_HookInterface(CLSID*, GUID*, DWORD, DWORD) { return 0; }
|
||||
|
||||
namespace
|
||||
{
|
||||
using Win32::DisplayMode::DisplayMode;
|
||||
using Win32::DisplayMode::EmulatedDisplayMode;
|
||||
|
||||
template <typename Char>
|
||||
struct EnumParams
|
||||
{
|
||||
@ -31,13 +39,48 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
DWORD g_origBpp = 0;
|
||||
DWORD g_currentBpp = 0;
|
||||
DWORD g_lastBpp = 0;
|
||||
struct GetMonitorFromDcEnumArgs
|
||||
{
|
||||
POINT org;
|
||||
HMONITOR hmonitor;
|
||||
};
|
||||
|
||||
DWORD g_desktopBpp = 0;
|
||||
RECT g_cursorRect = {};
|
||||
ULONG g_displaySettingsUniquenessBias = 0;
|
||||
EmulatedDisplayMode g_emulatedDisplayMode = {};
|
||||
Compat::SrwLock g_srwLock;
|
||||
|
||||
BOOL WINAPI dwm8And16BitIsShimAppliedCallOut();
|
||||
BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2);
|
||||
|
||||
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char>
|
||||
SIZE getConfiguredResolution(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName);
|
||||
|
||||
template <typename Char>
|
||||
std::wstring getDeviceName(const Char* deviceName);
|
||||
|
||||
HMONITOR getMonitorFromDc(HDC dc);
|
||||
MONITORINFO getMonitorInfo(const std::wstring& deviceName);
|
||||
|
||||
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char>
|
||||
std::vector<DisplayMode> getSupportedDisplayModes(
|
||||
EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName, DWORD flags);
|
||||
|
||||
void adjustMonitorInfo(MONITORINFO& mi)
|
||||
{
|
||||
Compat::ScopedSrwLockShared srwLock(g_srwLock);
|
||||
if (!g_emulatedDisplayMode.deviceName.empty() &&
|
||||
g_emulatedDisplayMode.rect.left == mi.rcMonitor.left &&
|
||||
g_emulatedDisplayMode.rect.top == mi.rcMonitor.top)
|
||||
{
|
||||
mi.rcMonitor.right += g_emulatedDisplayMode.diff.cx;
|
||||
mi.rcMonitor.bottom += g_emulatedDisplayMode.diff.cy;
|
||||
mi.rcWork.right += g_emulatedDisplayMode.diff.cx;
|
||||
mi.rcWork.bottom += g_emulatedDisplayMode.diff.cy;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CStr, typename DevMode, typename ChangeDisplaySettingsExFunc, typename EnumDisplaySettingsExFunc>
|
||||
LONG changeDisplaySettingsEx(
|
||||
ChangeDisplaySettingsExFunc origChangeDisplaySettingsEx,
|
||||
@ -45,6 +88,19 @@ namespace
|
||||
CStr lpszDeviceName, DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
|
||||
{
|
||||
DDraw::ScopedThreadLock lock;
|
||||
DevMode targetDevMode = {};
|
||||
if (lpDevMode)
|
||||
{
|
||||
targetDevMode = *lpDevMode;
|
||||
targetDevMode.dmBitsPerPel = 32;
|
||||
SIZE resolutionOverride = getConfiguredResolution<DevMode>(origEnumDisplaySettingsEx, lpszDeviceName);
|
||||
if (0 != resolutionOverride.cx)
|
||||
{
|
||||
targetDevMode.dmPelsWidth = resolutionOverride.cx;
|
||||
targetDevMode.dmPelsHeight = resolutionOverride.cy;
|
||||
}
|
||||
}
|
||||
|
||||
DevMode prevDevMode = {};
|
||||
if (!(dwflags & CDS_TEST))
|
||||
{
|
||||
@ -52,50 +108,84 @@ namespace
|
||||
origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &prevDevMode, 0);
|
||||
}
|
||||
|
||||
BOOL result = FALSE;
|
||||
LONG result = 0;
|
||||
if (lpDevMode)
|
||||
{
|
||||
DWORD origBpp = lpDevMode->dmBitsPerPel;
|
||||
lpDevMode->dmBitsPerPel = 32;
|
||||
result = origChangeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
|
||||
lpDevMode->dmBitsPerPel = origBpp;
|
||||
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
|
||||
{
|
||||
result = origChangeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
|
||||
result = origChangeDisplaySettingsEx(lpszDeviceName, nullptr, hwnd, dwflags, lParam);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(result) && !(dwflags & CDS_TEST))
|
||||
if (dwflags & CDS_TEST)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
DevMode currDevMode = {};
|
||||
currDevMode.dmSize = sizeof(currDevMode);
|
||||
origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0);
|
||||
|
||||
if (0 == memcmp(&currDevMode, &prevDevMode, sizeof(currDevMode)))
|
||||
{
|
||||
HANDLE dwmDxFullScreenTransitionEvent = OpenEventW(
|
||||
EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT");
|
||||
SetEvent(dwmDxFullScreenTransitionEvent);
|
||||
CloseHandle(dwmDxFullScreenTransitionEvent);
|
||||
}
|
||||
|
||||
if (DISP_CHANGE_SUCCESSFUL != result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
RECT clipRect = {};
|
||||
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive srwLock(g_srwLock);
|
||||
++g_displaySettingsUniquenessBias;
|
||||
clipRect = g_cursorRect;
|
||||
if (lpDevMode)
|
||||
{
|
||||
g_currentBpp = lpDevMode->dmBitsPerPel;
|
||||
g_lastBpp = lpDevMode->dmBitsPerPel;
|
||||
g_emulatedDisplayMode.width = lpDevMode->dmPelsWidth;
|
||||
g_emulatedDisplayMode.height = lpDevMode->dmPelsHeight;
|
||||
g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel;
|
||||
g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency;
|
||||
|
||||
g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName);
|
||||
g_emulatedDisplayMode.rect = getMonitorInfo(g_emulatedDisplayMode.deviceName).rcMonitor;
|
||||
g_emulatedDisplayMode.rect.right = g_emulatedDisplayMode.rect.left + lpDevMode->dmPelsWidth;
|
||||
g_emulatedDisplayMode.rect.bottom = g_emulatedDisplayMode.rect.top + lpDevMode->dmPelsHeight;
|
||||
g_emulatedDisplayMode.diff.cx = lpDevMode->dmPelsWidth - currDevMode.dmPelsWidth;
|
||||
g_emulatedDisplayMode.diff.cy = lpDevMode->dmPelsHeight - currDevMode.dmPelsHeight;
|
||||
|
||||
IntersectRect(&clipRect, &clipRect, &g_emulatedDisplayMode.rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_currentBpp = g_origBpp;
|
||||
g_emulatedDisplayMode = {};
|
||||
g_emulatedDisplayMode.bpp = g_desktopBpp;
|
||||
}
|
||||
|
||||
DevMode currDevMode = {};
|
||||
currDevMode.dmSize = sizeof(currDevMode);
|
||||
origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0);
|
||||
|
||||
if (currDevMode.dmPelsWidth == prevDevMode.dmPelsWidth &&
|
||||
currDevMode.dmPelsHeight == prevDevMode.dmPelsHeight &&
|
||||
currDevMode.dmBitsPerPel == prevDevMode.dmBitsPerPel &&
|
||||
currDevMode.dmDisplayFrequency == prevDevMode.dmDisplayFrequency &&
|
||||
currDevMode.dmDisplayFlags == prevDevMode.dmDisplayFlags)
|
||||
{
|
||||
HANDLE dwmDxFullScreenTransitionEvent = OpenEventW(
|
||||
EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT");
|
||||
SetEvent(dwmDxFullScreenTransitionEvent);
|
||||
CloseHandle(dwmDxFullScreenTransitionEvent);
|
||||
}
|
||||
|
||||
Gdi::VirtualScreen::update();
|
||||
}
|
||||
|
||||
CALL_ORIG_FUNC(ClipCursor)(&clipRect);
|
||||
|
||||
auto& dm = lpDevMode ? *lpDevMode : currDevMode;
|
||||
LPARAM resolution = (dm.dmPelsHeight << 16) | dm.dmPelsWidth;
|
||||
EnumWindows(sendDisplayChange, resolution);
|
||||
|
||||
SetCursorPos(currDevMode.dmPosition.x + dm.dmPelsWidth / 2, currDevMode.dmPosition.y + dm.dmPelsHeight / 2);
|
||||
Gdi::VirtualScreen::update();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -119,6 +209,31 @@ namespace
|
||||
lpszDeviceName, lpDevMode, hwnd, dwflags, lParam));
|
||||
}
|
||||
|
||||
BOOL WINAPI clipCursor(const RECT* lpRect)
|
||||
{
|
||||
LOG_FUNC("ClipCursor", lpRect);
|
||||
BOOL result = CALL_ORIG_FUNC(ClipCursor)(lpRect);
|
||||
if (!result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
RECT rect = {};
|
||||
CALL_ORIG_FUNC(GetClipCursor)(&rect);
|
||||
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive srwLock(g_srwLock);
|
||||
g_cursorRect = rect;
|
||||
if (!g_emulatedDisplayMode.deviceName.empty())
|
||||
{
|
||||
IntersectRect(&rect, &rect, &g_emulatedDisplayMode.rect);
|
||||
CALL_ORIG_FUNC(ClipCursor)(&rect);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void disableDwm8And16BitMitigation()
|
||||
{
|
||||
auto user32 = GetModuleHandle("user32");
|
||||
@ -147,8 +262,7 @@ namespace
|
||||
{
|
||||
if (ENUM_REGISTRY_SETTINGS == iModeNum || !lpDevMode)
|
||||
{
|
||||
BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
|
||||
return result;
|
||||
return origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
|
||||
}
|
||||
|
||||
if (ENUM_CURRENT_SETTINGS == iModeNum)
|
||||
@ -156,46 +270,53 @@ namespace
|
||||
BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
|
||||
if (result)
|
||||
{
|
||||
lpDevMode->dmBitsPerPel = g_currentBpp;
|
||||
Compat::ScopedSrwLockShared srwLock(g_srwLock);
|
||||
if (getDeviceName(lpszDeviceName) == g_emulatedDisplayMode.deviceName)
|
||||
{
|
||||
lpDevMode->dmBitsPerPel = g_emulatedDisplayMode.bpp;
|
||||
lpDevMode->dmPelsWidth = g_emulatedDisplayMode.width;
|
||||
lpDevMode->dmPelsHeight = g_emulatedDisplayMode.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpDevMode->dmBitsPerPel = g_desktopBpp;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
thread_local std::vector<DevMode> devModes;
|
||||
thread_local std::vector<DisplayMode> displayModes;
|
||||
thread_local EnumParams<Char> lastEnumParams = {};
|
||||
|
||||
EnumParams<Char> currentEnumParams = {
|
||||
lpszDeviceName ? lpszDeviceName : std::basic_string<Char>(), dwFlags };
|
||||
EnumParams<Char> currentEnumParams = { lpszDeviceName ? lpszDeviceName : std::basic_string<Char>(), dwFlags };
|
||||
|
||||
if (0 == iModeNum || devModes.empty() || currentEnumParams != lastEnumParams)
|
||||
if (0 == iModeNum || displayModes.empty() || currentEnumParams != lastEnumParams)
|
||||
{
|
||||
devModes.clear();
|
||||
displayModes = getSupportedDisplayModes<DevMode>(origEnumDisplaySettingsEx, lpszDeviceName, dwFlags);
|
||||
lastEnumParams = currentEnumParams;
|
||||
|
||||
DWORD modeNum = 0;
|
||||
DevMode dm = {};
|
||||
dm.dmSize = sizeof(dm);
|
||||
while (origEnumDisplaySettingsEx(lpszDeviceName, modeNum, &dm, dwFlags))
|
||||
{
|
||||
if (32 == dm.dmBitsPerPel)
|
||||
{
|
||||
dm.dmBitsPerPel = 8;
|
||||
devModes.push_back(dm);
|
||||
dm.dmBitsPerPel = 16;
|
||||
devModes.push_back(dm);
|
||||
dm.dmBitsPerPel = 32;
|
||||
devModes.push_back(dm);
|
||||
}
|
||||
++modeNum;
|
||||
}
|
||||
}
|
||||
|
||||
if (iModeNum >= devModes.size())
|
||||
if (iModeNum >= displayModes.size() * 3)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*lpDevMode = devModes[iModeNum];
|
||||
const auto& displayMode = displayModes[iModeNum / 3];
|
||||
lpDevMode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
|
||||
DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY;
|
||||
lpDevMode->dmDisplayOrientation = DMDO_DEFAULT;
|
||||
lpDevMode->dmPelsWidth = displayMode.width;
|
||||
lpDevMode->dmPelsHeight = displayMode.height;
|
||||
lpDevMode->dmDisplayFlags = 0;
|
||||
lpDevMode->dmDisplayFrequency = displayMode.refreshRate;
|
||||
|
||||
switch (iModeNum % 3)
|
||||
{
|
||||
case 0: lpDevMode->dmBitsPerPel = 8; break;
|
||||
case 1: lpDevMode->dmBitsPerPel = 16; break;
|
||||
case 2: lpDevMode->dmBitsPerPel = 32; break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -215,6 +336,44 @@ namespace
|
||||
lpszDeviceName, iModeNum, lpDevMode, dwFlags));
|
||||
}
|
||||
|
||||
ULONG WINAPI gdiEntry13()
|
||||
{
|
||||
Compat::ScopedSrwLockShared lock(g_srwLock);
|
||||
return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias;
|
||||
}
|
||||
|
||||
BOOL WINAPI getClipCursor(LPRECT lpRect)
|
||||
{
|
||||
LOG_FUNC("GetClipCursor", lpRect);
|
||||
BOOL result = CALL_ORIG_FUNC(GetClipCursor)(lpRect);
|
||||
if (result)
|
||||
{
|
||||
*lpRect = g_cursorRect;
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char>
|
||||
SIZE getConfiguredResolution(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName)
|
||||
{
|
||||
auto resolution = Config::displayResolution.get();
|
||||
if (Config::Settings::DisplayResolution::DESKTOP == resolution)
|
||||
{
|
||||
DevMode dm = {};
|
||||
dm.dmSize = sizeof(dm);
|
||||
if (origEnumDisplaySettingsEx(deviceName, ENUM_REGISTRY_SETTINGS, &dm, 0))
|
||||
{
|
||||
resolution.cx = dm.dmPelsWidth;
|
||||
resolution.cy = dm.dmPelsHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
resolution = {};
|
||||
}
|
||||
}
|
||||
return resolution;
|
||||
}
|
||||
|
||||
int WINAPI getDeviceCaps(HDC hdc, int nIndex)
|
||||
{
|
||||
LOG_FUNC("GetDeviceCaps", hdc, nIndex);
|
||||
@ -223,34 +382,52 @@ namespace
|
||||
case BITSPIXEL:
|
||||
if (Gdi::isDisplayDc(hdc))
|
||||
{
|
||||
return LOG_RESULT(g_currentBpp);
|
||||
return LOG_RESULT(Win32::DisplayMode::getBpp());
|
||||
}
|
||||
break;
|
||||
|
||||
case COLORRES:
|
||||
if (8 == g_currentBpp && Gdi::isDisplayDc(hdc))
|
||||
if (8 == Win32::DisplayMode::getBpp() && Gdi::isDisplayDc(hdc))
|
||||
{
|
||||
return 24;
|
||||
}
|
||||
break;
|
||||
|
||||
case HORZRES:
|
||||
case VERTRES:
|
||||
if (Gdi::isDisplayDc(hdc))
|
||||
{
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(getMonitorFromDc(hdc), &mi);
|
||||
if (HORZRES == nIndex)
|
||||
{
|
||||
return LOG_RESULT(mi.rcMonitor.right - mi.rcMonitor.left);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LOG_RESULT(mi.rcMonitor.bottom - mi.rcMonitor.top);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NUMCOLORS:
|
||||
case NUMRESERVED:
|
||||
if (8 == g_currentBpp && Gdi::isDisplayDc(hdc))
|
||||
if (8 == Win32::DisplayMode::getBpp() && Gdi::isDisplayDc(hdc))
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
break;
|
||||
|
||||
case RASTERCAPS:
|
||||
if (8 == g_currentBpp && Gdi::isDisplayDc(hdc))
|
||||
if (8 == Win32::DisplayMode::getBpp() && Gdi::isDisplayDc(hdc))
|
||||
{
|
||||
return LOG_RESULT(CALL_ORIG_FUNC(GetDeviceCaps)(hdc, nIndex) | RC_PALETTE);
|
||||
}
|
||||
break;
|
||||
|
||||
case SIZEPALETTE:
|
||||
if (8 == g_currentBpp && Gdi::isDisplayDc(hdc))
|
||||
if (8 == Win32::DisplayMode::getBpp() && Gdi::isDisplayDc(hdc))
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
@ -259,6 +436,191 @@ namespace
|
||||
return LOG_RESULT(CALL_ORIG_FUNC(GetDeviceCaps)(hdc, nIndex));
|
||||
}
|
||||
|
||||
std::size_t getDeviceNameLength(const char* deviceName)
|
||||
{
|
||||
return std::strlen(deviceName);
|
||||
}
|
||||
|
||||
std::size_t getDeviceNameLength(const wchar_t* deviceName)
|
||||
{
|
||||
return std::wcslen(deviceName);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
std::wstring getDeviceName(const Char* deviceName)
|
||||
{
|
||||
if (deviceName)
|
||||
{
|
||||
return std::wstring(deviceName, deviceName + getDeviceNameLength(deviceName));
|
||||
}
|
||||
|
||||
MONITORINFOEXW mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
CALL_ORIG_FUNC(GetMonitorInfoW)(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
|
||||
return mi.szDevice;
|
||||
}
|
||||
|
||||
BOOL CALLBACK getMonitorFromDcEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
||||
{
|
||||
auto& args = *reinterpret_cast<GetMonitorFromDcEnumArgs*>(dwData);
|
||||
|
||||
MONITORINFOEX mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, &mi);
|
||||
|
||||
HDC dc = CreateDC(mi.szDevice, nullptr, nullptr, nullptr);
|
||||
if (dc)
|
||||
{
|
||||
POINT org = {};
|
||||
GetDCOrgEx(dc, &org);
|
||||
DeleteDC(dc);
|
||||
if (org == args.org)
|
||||
{
|
||||
args.hmonitor = hMonitor;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HMONITOR getMonitorFromDc(HDC dc)
|
||||
{
|
||||
HWND hwnd = CALL_ORIG_FUNC(WindowFromDC)(dc);
|
||||
if (hwnd)
|
||||
{
|
||||
return MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
GetMonitorFromDcEnumArgs args = {};
|
||||
GetDCOrgEx(dc, &args.org);
|
||||
EnumDisplayMonitors(nullptr, nullptr, getMonitorFromDcEnum, reinterpret_cast<LPARAM>(&args));
|
||||
return args.hmonitor ? args.hmonitor : MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
BOOL CALLBACK getMonitorInfoEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
||||
{
|
||||
MONITORINFOEXW mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi);
|
||||
auto& dest = *reinterpret_cast<MONITORINFOEXW*>(dwData);
|
||||
if (0 == wcscmp(mi.szDevice, dest.szDevice))
|
||||
{
|
||||
dest = mi;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MONITORINFO getMonitorInfo(const std::wstring& deviceName)
|
||||
{
|
||||
MONITORINFOEXW mi = {};
|
||||
wcscpy_s(mi.szDevice, deviceName.c_str());
|
||||
EnumDisplayMonitors(nullptr, nullptr, &getMonitorInfoEnum, reinterpret_cast<LPARAM>(&mi));
|
||||
return mi;
|
||||
}
|
||||
|
||||
BOOL WINAPI getMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi)
|
||||
{
|
||||
LOG_FUNC("GetMonitorInfoA", hMonitor, lpmi);
|
||||
BOOL result = CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, lpmi);
|
||||
if (result)
|
||||
{
|
||||
adjustMonitorInfo(*lpmi);
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
BOOL WINAPI getMonitorInfoW(HMONITOR hMonitor, LPMONITORINFO lpmi)
|
||||
{
|
||||
LOG_FUNC("GetMonitorInfoW", hMonitor, lpmi);
|
||||
BOOL result = CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, lpmi);
|
||||
if (result)
|
||||
{
|
||||
adjustMonitorInfo(*lpmi);
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char>
|
||||
std::vector<DisplayMode> getSupportedDisplayModes(
|
||||
EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName, DWORD flags)
|
||||
{
|
||||
std::set<DisplayMode> displayModes;
|
||||
DWORD modeNum = 0;
|
||||
DevMode dm = {};
|
||||
dm.dmSize = sizeof(dm);
|
||||
|
||||
while (origEnumDisplaySettingsEx(deviceName, modeNum, &dm, flags))
|
||||
{
|
||||
if (32 == dm.dmBitsPerPel)
|
||||
{
|
||||
displayModes.insert({ dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency });
|
||||
}
|
||||
++modeNum;
|
||||
}
|
||||
|
||||
auto resolutionOverride = getConfiguredResolution<DevMode>(origEnumDisplaySettingsEx, deviceName);
|
||||
if (0 == resolutionOverride.cx)
|
||||
{
|
||||
return { displayModes.begin(), displayModes.end() };
|
||||
}
|
||||
|
||||
std::set<DWORD> supportedRefreshRates;
|
||||
for (const auto& mode : displayModes)
|
||||
{
|
||||
if (static_cast<LONG>(mode.width) == resolutionOverride.cx &&
|
||||
static_cast<LONG>(mode.height) == resolutionOverride.cy)
|
||||
{
|
||||
supportedRefreshRates.insert(mode.refreshRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (supportedRefreshRates.empty())
|
||||
{
|
||||
return { displayModes.begin(), displayModes.end() };
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
customDisplayModes.push_back({ mode.width, mode.height, mode.bpp, refreshRate });
|
||||
}
|
||||
prevWidth = mode.width;
|
||||
prevHeight = mode.height;
|
||||
}
|
||||
}
|
||||
return customDisplayModes;
|
||||
}
|
||||
|
||||
BOOL CALLBACK initMonitor(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM /*dwData*/)
|
||||
{
|
||||
MONITORINFOEX mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(hMonitor, &mi);
|
||||
|
||||
DEVMODE dm = {};
|
||||
dm.dmSize = sizeof(dm);
|
||||
if (EnumDisplaySettings(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm))
|
||||
{
|
||||
if (32 != dm.dmBitsPerPel)
|
||||
{
|
||||
dm = {};
|
||||
dm.dmSize = sizeof(dm);
|
||||
dm.dmFields = DM_BITSPERPEL;
|
||||
dm.dmBitsPerPel = 32;
|
||||
ChangeDisplaySettingsEx(mi.szDevice, &dm, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2)
|
||||
{
|
||||
LOG_FUNC("SE_COM_HookInterface", clsid, iid, unk1, unk2);
|
||||
@ -268,6 +630,17 @@ namespace
|
||||
}
|
||||
return LOG_RESULT(CALL_ORIG_FUNC(SE_COM_HookInterface)(clsid, iid, unk1, unk2));
|
||||
}
|
||||
|
||||
BOOL CALLBACK sendDisplayChange(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
if (GetCurrentProcessId() == pid)
|
||||
{
|
||||
SendNotifyMessage(hwnd, WM_DISPLAYCHANGE, 0, lParam);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Win32
|
||||
@ -276,36 +649,41 @@ namespace Win32
|
||||
{
|
||||
DWORD getBpp()
|
||||
{
|
||||
return g_currentBpp;
|
||||
return getEmulatedDisplayMode().bpp;
|
||||
}
|
||||
|
||||
EmulatedDisplayMode getEmulatedDisplayMode()
|
||||
{
|
||||
Compat::ScopedSrwLockShared lock(g_srwLock);
|
||||
return g_emulatedDisplayMode;
|
||||
}
|
||||
|
||||
ULONG queryDisplaySettingsUniqueness()
|
||||
{
|
||||
static auto ddQueryDisplaySettingsUniqueness = reinterpret_cast<ULONG(APIENTRY*)()>(
|
||||
GetProcAddress(GetModuleHandle("gdi32"), "GdiEntry13"));
|
||||
return ddQueryDisplaySettingsUniqueness();
|
||||
return CALL_ORIG_FUNC(GdiEntry13)();
|
||||
}
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
DEVMODEA devMode = {};
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
EnumDisplaySettingsEx(nullptr, ENUM_CURRENT_SETTINGS, &devMode, 0);
|
||||
g_origBpp = devMode.dmBitsPerPel;
|
||||
g_currentBpp = g_origBpp;
|
||||
g_lastBpp = g_origBpp;
|
||||
DEVMODEA dm = {};
|
||||
dm.dmSize = sizeof(dm);
|
||||
EnumDisplaySettingsEx(nullptr, ENUM_CURRENT_SETTINGS, &dm, 0);
|
||||
g_desktopBpp = dm.dmBitsPerPel;
|
||||
g_emulatedDisplayMode.bpp = dm.dmBitsPerPel;
|
||||
|
||||
if (32 != devMode.dmBitsPerPel)
|
||||
{
|
||||
devMode.dmBitsPerPel = 32;
|
||||
ChangeDisplaySettings(&devMode, 0);
|
||||
}
|
||||
GetClipCursor(&g_cursorRect);
|
||||
EnumDisplayMonitors(nullptr, nullptr, &initMonitor, 0);
|
||||
|
||||
HOOK_FUNCTION(user32, ChangeDisplaySettingsExA, changeDisplaySettingsExA);
|
||||
HOOK_FUNCTION(user32, ChangeDisplaySettingsExW, changeDisplaySettingsExW);
|
||||
HOOK_FUNCTION(user32, ClipCursor, clipCursor);
|
||||
HOOK_FUNCTION(user32, EnumDisplaySettingsExA, enumDisplaySettingsExA);
|
||||
HOOK_FUNCTION(user32, EnumDisplaySettingsExW, enumDisplaySettingsExW);
|
||||
HOOK_FUNCTION(gdi32, GdiEntry13, gdiEntry13);
|
||||
HOOK_FUNCTION(user32, GetClipCursor, getClipCursor);
|
||||
HOOK_FUNCTION(gdi32, GetDeviceCaps, getDeviceCaps);
|
||||
HOOK_FUNCTION(user32, GetMonitorInfoA, getMonitorInfoA);
|
||||
HOOK_FUNCTION(user32, GetMonitorInfoW, getMonitorInfoW);
|
||||
|
||||
disableDwm8And16BitMitigation();
|
||||
}
|
||||
|
@ -1,14 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
|
||||
namespace Win32
|
||||
{
|
||||
namespace DisplayMode
|
||||
{
|
||||
struct DisplayMode
|
||||
{
|
||||
DWORD width;
|
||||
DWORD height;
|
||||
DWORD bpp;
|
||||
DWORD refreshRate;
|
||||
};
|
||||
|
||||
struct EmulatedDisplayMode : DisplayMode
|
||||
{
|
||||
std::wstring deviceName;
|
||||
RECT rect;
|
||||
SIZE diff;
|
||||
};
|
||||
|
||||
DWORD getBpp();
|
||||
EmulatedDisplayMode getEmulatedDisplayMode();
|
||||
ULONG queryDisplaySettingsUniqueness();
|
||||
|
||||
void installHooks();
|
||||
|
||||
using ::operator<;
|
||||
|
||||
inline auto toTuple(const DisplayMode& dm)
|
||||
{
|
||||
return std::make_tuple(dm.width, dm.height, dm.bpp, dm.refreshRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace
|
||||
<< dm.dmPelsHeight
|
||||
<< dm.dmBitsPerPel
|
||||
<< dm.dmDisplayFrequency
|
||||
<< dm.dmDisplayFlags;
|
||||
<< Compat::hex(dm.dmDisplayFlags);
|
||||
}
|
||||
|
||||
template <typename MdiCreateStruct>
|
||||
|
Loading…
x
Reference in New Issue
Block a user