2021-05-15 16:06:26 +02:00
|
|
|
#include <atomic>
|
2018-12-09 14:23:36 +01:00
|
|
|
#include <string>
|
2016-11-29 00:00:49 +01:00
|
|
|
|
2020-04-23 20:22:00 +02:00
|
|
|
#include <Common/Log.h>
|
|
|
|
#include <Common/Hook.h>
|
2020-07-13 23:44:05 +02:00
|
|
|
#include <Common/ScopedSrwLock.h>
|
2020-04-23 20:22:00 +02:00
|
|
|
#include <Common/Time.h>
|
|
|
|
#include <D3dDdi/Device.h>
|
|
|
|
#include <D3dDdi/KernelModeThunks.h>
|
|
|
|
#include <D3dDdi/Log/KernelModeThunksLog.h>
|
|
|
|
#include <D3dDdi/Resource.h>
|
|
|
|
#include <D3dDdi/ScopedCriticalSection.h>
|
|
|
|
#include <DDraw/RealPrimarySurface.h>
|
|
|
|
#include <DDraw/ScopedThreadLock.h>
|
|
|
|
#include <DDraw/Surfaces/PrimarySurface.h>
|
|
|
|
#include <Gdi/Palette.h>
|
|
|
|
#include <Win32/DisplayMode.h>
|
2016-11-29 00:00:49 +01:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2019-04-23 12:44:13 +02:00
|
|
|
D3DDDIFORMAT g_dcFormatOverride = D3DDDIFMT_UNKNOWN;
|
2019-08-02 22:16:44 +02:00
|
|
|
bool g_dcPaletteOverride = false;
|
2021-06-05 17:29:51 +02:00
|
|
|
D3dDdi::KernelModeThunks::AdapterInfo g_gdiAdapterInfo = {};
|
|
|
|
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
|
2020-07-13 23:44:05 +02:00
|
|
|
Compat::SrwLock g_lastOpenAdapterInfoSrwLock;
|
2021-06-12 20:49:36 +02:00
|
|
|
std::string g_lastDDrawDeviceName;
|
2016-11-29 00:00:49 +01:00
|
|
|
|
2021-05-15 16:06:26 +02:00
|
|
|
std::atomic<long long> g_qpcLastVsync = 0;
|
2020-07-13 23:44:05 +02:00
|
|
|
UINT g_vsyncCounter = 0;
|
|
|
|
CONDITION_VARIABLE g_vsyncCounterCv = CONDITION_VARIABLE_INIT;
|
|
|
|
Compat::SrwLock g_vsyncCounterSrwLock;
|
2017-05-17 20:41:05 +02:00
|
|
|
|
2020-07-13 23:44:05 +02:00
|
|
|
void waitForVerticalBlank();
|
2020-04-23 20:22:00 +02:00
|
|
|
|
2018-10-03 20:49:50 +02:00
|
|
|
NTSTATUS APIENTRY closeAdapter(const D3DKMT_CLOSEADAPTER* pData)
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
2018-10-03 20:49:50 +02:00
|
|
|
if (pData && pData->hAdapter == g_lastOpenAdapterInfo.adapter)
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2018-10-03 20:49:50 +02:00
|
|
|
g_lastOpenAdapterInfo = {};
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
2019-08-28 21:04:28 +02:00
|
|
|
return D3DKMTCloseAdapter(pData);
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
|
|
|
|
2018-03-11 18:42:06 +01:00
|
|
|
NTSTATUS APIENTRY createDcFromMemory(D3DKMT_CREATEDCFROMMEMORY* pData)
|
|
|
|
{
|
2018-11-03 01:36:38 +01:00
|
|
|
LOG_FUNC("D3DKMTCreateDCFromMemory", pData);
|
2019-04-23 12:44:13 +02:00
|
|
|
|
|
|
|
auto origFormat = pData->Format;
|
|
|
|
if (D3DDDIFMT_UNKNOWN != g_dcFormatOverride)
|
|
|
|
{
|
|
|
|
pData->Format = g_dcFormatOverride;
|
|
|
|
}
|
|
|
|
|
2019-08-02 22:16:44 +02:00
|
|
|
std::vector<PALETTEENTRY> palette;
|
|
|
|
auto origColorTable = pData->pColorTable;
|
|
|
|
|
|
|
|
if (D3DDDIFMT_P8 == pData->Format)
|
2018-03-11 18:42:06 +01:00
|
|
|
{
|
2019-08-02 22:16:44 +02:00
|
|
|
if (g_dcPaletteOverride)
|
|
|
|
{
|
|
|
|
palette = Gdi::Palette::getHardwarePalette();
|
|
|
|
pData->pColorTable = palette.data();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DDraw::ScopedThreadLock ddLock;
|
|
|
|
D3dDdi::ScopedCriticalSection driverLock;
|
2019-08-19 22:42:48 +02:00
|
|
|
auto primaryResource = D3dDdi::Device::findResource(DDraw::PrimarySurface::getFrontResource());
|
2019-08-02 22:16:44 +02:00
|
|
|
if (primaryResource && pData->pMemory == primaryResource->getLockPtr(0) &&
|
|
|
|
(DDraw::PrimarySurface::getOrigCaps() & DDSCAPS_COMPLEX))
|
|
|
|
{
|
|
|
|
pData->pColorTable = Gdi::Palette::getDefaultPalette();
|
|
|
|
}
|
|
|
|
else if (pData->pColorTable)
|
|
|
|
{
|
|
|
|
palette.assign(pData->pColorTable, pData->pColorTable + 256);
|
|
|
|
auto sysPal = Gdi::Palette::getSystemPalette();
|
|
|
|
for (UINT i = 0; i < 256; ++i)
|
|
|
|
{
|
|
|
|
if (palette[i].peFlags & PC_EXPLICIT)
|
|
|
|
{
|
|
|
|
palette[i] = sysPal[palette[i].peRed];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pData->pColorTable = palette.data();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
palette = Gdi::Palette::getHardwarePalette();
|
|
|
|
pData->pColorTable = palette.data();
|
|
|
|
}
|
|
|
|
}
|
2018-03-11 18:42:06 +01:00
|
|
|
}
|
2019-04-23 12:44:13 +02:00
|
|
|
|
2019-08-28 21:04:28 +02:00
|
|
|
auto result = D3DKMTCreateDCFromMemory(pData);
|
2019-04-23 12:44:13 +02:00
|
|
|
pData->Format = origFormat;
|
2019-08-02 22:16:44 +02:00
|
|
|
pData->pColorTable = origColorTable;
|
2018-11-03 01:36:38 +01:00
|
|
|
return LOG_RESULT(result);
|
2018-03-11 18:42:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-09 14:23:36 +01:00
|
|
|
HDC WINAPI ddrawCreateDcA(LPCSTR pwszDriver, LPCSTR pwszDevice, LPCSTR pszPort, const DEVMODEA* pdm)
|
|
|
|
{
|
|
|
|
LOG_FUNC("ddrawCreateDCA", pwszDriver, pwszDevice, pszPort, pdm);
|
2021-06-05 17:29:51 +02:00
|
|
|
if (pwszDevice)
|
|
|
|
{
|
2021-06-12 20:49:36 +02:00
|
|
|
g_lastDDrawDeviceName = pwszDevice;
|
2021-06-05 17:29:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MONITORINFOEXA mi = {};
|
|
|
|
mi.cbSize = sizeof(mi);
|
|
|
|
CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
|
2021-06-12 20:49:36 +02:00
|
|
|
g_lastDDrawDeviceName = mi.szDevice;
|
2021-06-05 17:29:51 +02:00
|
|
|
}
|
2019-08-28 21:04:28 +02:00
|
|
|
return LOG_RESULT(CreateDCA(pwszDriver, pwszDevice, pszPort, pdm));
|
2018-12-09 14:23:36 +01:00
|
|
|
}
|
|
|
|
|
2021-06-12 20:49:36 +02:00
|
|
|
BOOL CALLBACK findMonitorInfo(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
2018-12-09 14:23:36 +01:00
|
|
|
{
|
2021-06-12 20:49:36 +02:00
|
|
|
MONITORINFOEXW mi = {};
|
2018-12-09 14:23:36 +01:00
|
|
|
mi.cbSize = sizeof(mi);
|
2021-06-12 20:49:36 +02:00
|
|
|
CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi);
|
|
|
|
if (0 == wcscmp(reinterpret_cast<MONITORINFOEXW*>(dwData)->szDevice, mi.szDevice))
|
2018-12-09 14:23:36 +01:00
|
|
|
{
|
2021-06-12 20:49:36 +02:00
|
|
|
*reinterpret_cast<MONITORINFOEXW*>(dwData) = mi;
|
2018-12-09 14:23:36 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2021-06-12 20:49:36 +02:00
|
|
|
D3dDdi::KernelModeThunks::AdapterInfo getAdapterInfo(const std::string& deviceName, const D3DKMT_OPENADAPTERFROMHDC& data)
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2021-06-05 17:29:51 +02:00
|
|
|
D3dDdi::KernelModeThunks::AdapterInfo adapterInfo = {};
|
2018-10-03 20:49:50 +02:00
|
|
|
adapterInfo.adapter = data.hAdapter;
|
|
|
|
adapterInfo.vidPnSourceId = data.VidPnSourceId;
|
2021-06-05 17:29:51 +02:00
|
|
|
adapterInfo.luid = data.AdapterLuid;
|
2021-06-12 20:49:36 +02:00
|
|
|
wcscpy_s(adapterInfo.monitorInfo.szDevice, std::wstring(deviceName.begin(), deviceName.end()).c_str());
|
|
|
|
EnumDisplayMonitors(nullptr, nullptr, findMonitorInfo, reinterpret_cast<LPARAM>(&adapterInfo.monitorInfo));
|
2018-10-03 20:49:50 +02:00
|
|
|
return adapterInfo;
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
|
|
|
|
2018-07-17 20:46:38 +02:00
|
|
|
NTSTATUS APIENTRY openAdapterFromHdc(D3DKMT_OPENADAPTERFROMHDC* pData)
|
|
|
|
{
|
2018-11-03 01:36:38 +01:00
|
|
|
LOG_FUNC("D3DKMTOpenAdapterFromHdc", pData);
|
2019-08-28 21:04:28 +02:00
|
|
|
NTSTATUS result = D3DKMTOpenAdapterFromHdc(pData);
|
2018-10-03 20:49:50 +02:00
|
|
|
if (SUCCEEDED(result))
|
2018-07-17 20:46:38 +02:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
2021-06-12 20:49:36 +02:00
|
|
|
g_lastOpenAdapterInfo = getAdapterInfo(g_lastDDrawDeviceName, *pData);
|
2018-07-17 20:46:38 +02:00
|
|
|
}
|
2018-11-03 01:36:38 +01:00
|
|
|
return LOG_RESULT(result);
|
2018-07-17 20:46:38 +02:00
|
|
|
}
|
|
|
|
|
2016-11-29 00:00:49 +01:00
|
|
|
NTSTATUS APIENTRY queryAdapterInfo(const D3DKMT_QUERYADAPTERINFO* pData)
|
|
|
|
{
|
2018-11-03 01:36:38 +01:00
|
|
|
LOG_FUNC("D3DKMTQueryAdapterInfo", pData);
|
2019-08-28 21:04:28 +02:00
|
|
|
NTSTATUS result = D3DKMTQueryAdapterInfo(pData);
|
2019-07-29 23:13:52 +02:00
|
|
|
if (SUCCEEDED(result))
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2019-07-29 23:13:52 +02:00
|
|
|
switch (pData->Type)
|
|
|
|
{
|
|
|
|
case KMTQAITYPE_GETSEGMENTSIZE:
|
|
|
|
{
|
|
|
|
auto info = static_cast<D3DKMT_SEGMENTSIZEINFO*>(pData->pPrivateDriverData);
|
|
|
|
const ULONGLONG maxMem = 0x3FFF0000;
|
|
|
|
if (info->DedicatedVideoMemorySize > maxMem)
|
|
|
|
{
|
|
|
|
info->DedicatedVideoMemorySize = maxMem;
|
|
|
|
}
|
|
|
|
if (info->DedicatedVideoMemorySize + info->DedicatedSystemMemorySize > maxMem)
|
|
|
|
{
|
|
|
|
info->DedicatedSystemMemorySize = maxMem - info->DedicatedVideoMemorySize;
|
|
|
|
}
|
|
|
|
if (info->SharedSystemMemorySize > maxMem)
|
|
|
|
{
|
|
|
|
info->SharedSystemMemorySize = maxMem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
2018-11-03 01:36:38 +01:00
|
|
|
return LOG_RESULT(result);
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
|
|
|
|
2020-04-23 20:22:00 +02:00
|
|
|
NTSTATUS APIENTRY setGammaRamp(const D3DKMT_SETGAMMARAMP* pData)
|
|
|
|
{
|
|
|
|
LOG_FUNC("D3DKMTSetGammaRamp", pData);
|
2020-07-13 23:44:05 +02:00
|
|
|
UINT vsyncCounter = D3dDdi::KernelModeThunks::getVsyncCounter();
|
2020-04-23 20:22:00 +02:00
|
|
|
DDraw::RealPrimarySurface::flush();
|
|
|
|
HRESULT result = D3DKMTSetGammaRamp(pData);
|
2020-07-13 23:44:05 +02:00
|
|
|
if (SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCounter + 1);
|
|
|
|
}
|
2020-04-23 20:22:00 +02:00
|
|
|
return LOG_RESULT(result);
|
|
|
|
}
|
|
|
|
|
2018-10-03 20:49:50 +02:00
|
|
|
void updateGdiAdapterInfo()
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2018-10-03 20:49:50 +02:00
|
|
|
static auto lastDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
|
|
|
|
const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
|
|
|
|
if (currentDisplaySettingsUniqueness != lastDisplaySettingsUniqueness)
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2018-10-03 20:49:50 +02:00
|
|
|
if (g_gdiAdapterInfo.adapter)
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2018-10-03 20:49:50 +02:00
|
|
|
D3DKMT_CLOSEADAPTER data = {};
|
|
|
|
data.hAdapter = g_gdiAdapterInfo.adapter;
|
2019-08-28 21:04:28 +02:00
|
|
|
D3DKMTCloseAdapter(&data);
|
2018-10-03 20:49:50 +02:00
|
|
|
g_gdiAdapterInfo = {};
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
|
|
|
|
2018-12-30 13:07:55 +01:00
|
|
|
MONITORINFOEX mi = {};
|
|
|
|
mi.cbSize = sizeof(mi);
|
|
|
|
GetMonitorInfo(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
|
|
|
|
|
2018-10-03 20:49:50 +02:00
|
|
|
D3DKMT_OPENADAPTERFROMHDC data = {};
|
2018-12-30 13:07:55 +01:00
|
|
|
data.hDc = CreateDC(mi.szDevice, mi.szDevice, nullptr, nullptr);
|
2019-08-28 21:04:28 +02:00
|
|
|
if (SUCCEEDED(D3DKMTOpenAdapterFromHdc(&data)))
|
2018-10-03 20:49:50 +02:00
|
|
|
{
|
2021-06-12 20:49:36 +02:00
|
|
|
g_gdiAdapterInfo = getAdapterInfo(mi.szDevice, data);
|
2018-10-03 20:49:50 +02:00
|
|
|
}
|
2018-12-30 13:07:55 +01:00
|
|
|
DeleteDC(data.hDc);
|
2016-11-29 00:00:49 +01:00
|
|
|
|
2018-10-03 20:49:50 +02:00
|
|
|
lastDisplaySettingsUniqueness = currentDisplaySettingsUniqueness;
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-23 20:22:00 +02:00
|
|
|
|
2021-02-28 22:34:47 +01:00
|
|
|
unsigned WINAPI vsyncThreadProc(LPVOID /*lpParameter*/)
|
2020-04-23 20:22:00 +02:00
|
|
|
{
|
2021-03-01 22:59:07 +01:00
|
|
|
while (true)
|
2020-07-13 23:44:05 +02:00
|
|
|
{
|
|
|
|
waitForVerticalBlank();
|
2021-05-15 16:06:26 +02:00
|
|
|
g_qpcLastVsync = Time::queryPerformanceCounter();
|
2020-07-13 23:44:05 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
Compat::ScopedSrwLockExclusive lock(g_vsyncCounterSrwLock);
|
|
|
|
++g_vsyncCounter;
|
|
|
|
}
|
|
|
|
|
|
|
|
WakeAllConditionVariable(&g_vsyncCounterCv);
|
|
|
|
}
|
2020-04-23 20:22:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2016-11-29 00:00:49 +01:00
|
|
|
|
2020-07-13 23:44:05 +02:00
|
|
|
void waitForVerticalBlank()
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
|
|
|
|
2018-07-17 20:46:38 +02:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
Compat::ScopedSrwLockShared lock(g_lastOpenAdapterInfoSrwLock);
|
|
|
|
data.hAdapter = g_lastOpenAdapterInfo.adapter;
|
|
|
|
data.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
2018-07-17 20:46:38 +02:00
|
|
|
}
|
|
|
|
|
2020-07-13 23:44:05 +02:00
|
|
|
if (!data.hAdapter)
|
2017-05-17 20:41:05 +02:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
updateGdiAdapterInfo();
|
|
|
|
data.hAdapter = g_gdiAdapterInfo.adapter;
|
|
|
|
data.VidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
|
2018-10-03 20:49:50 +02:00
|
|
|
}
|
|
|
|
|
2020-07-13 23:44:05 +02:00
|
|
|
if (!data.hAdapter || FAILED(D3DKMTWaitForVerticalBlankEvent(&data)))
|
2018-10-03 20:49:50 +02:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
Sleep(16);
|
2018-10-03 20:49:50 +02:00
|
|
|
}
|
2020-07-13 23:44:05 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-03 20:49:50 +02:00
|
|
|
|
2020-07-13 23:44:05 +02:00
|
|
|
namespace D3dDdi
|
|
|
|
{
|
|
|
|
namespace KernelModeThunks
|
|
|
|
{
|
2021-06-05 17:29:51 +02:00
|
|
|
AdapterInfo getAdapterInfo(CompatRef<IDirectDraw7> dd)
|
|
|
|
{
|
|
|
|
DDraw::ScopedThreadLock lock;
|
|
|
|
DDDEVICEIDENTIFIER2 di = {};
|
|
|
|
dd.get().lpVtbl->GetDeviceIdentifier(&dd, &di, 0);
|
|
|
|
return getLastOpenAdapterInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
AdapterInfo getLastOpenAdapterInfo()
|
|
|
|
{
|
|
|
|
Compat::ScopedSrwLockShared srwLock(g_lastOpenAdapterInfoSrwLock);
|
|
|
|
return g_lastOpenAdapterInfo;
|
|
|
|
}
|
|
|
|
|
2021-05-15 16:06:26 +02:00
|
|
|
long long getQpcLastVsync()
|
|
|
|
{
|
|
|
|
return g_qpcLastVsync;
|
|
|
|
}
|
|
|
|
|
2020-07-13 23:44:05 +02:00
|
|
|
UINT getVsyncCounter()
|
2018-10-03 20:49:50 +02:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
Compat::ScopedSrwLockShared lock(g_vsyncCounterSrwLock);
|
|
|
|
return g_vsyncCounter;
|
2017-05-17 20:41:05 +02:00
|
|
|
}
|
|
|
|
|
2021-03-14 18:48:26 +01:00
|
|
|
void installHooks()
|
2016-11-29 00:00:49 +01:00
|
|
|
{
|
2021-03-14 18:48:26 +01:00
|
|
|
Compat::hookIatFunction(Dll::g_origDDrawModule, "CreateDCA", ddrawCreateDcA);
|
|
|
|
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTCloseAdapter", closeAdapter);
|
|
|
|
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTCreateDCFromMemory", createDcFromMemory);
|
|
|
|
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc);
|
|
|
|
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTQueryAdapterInfo", queryAdapterInfo);
|
|
|
|
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSetGammaRamp", setGammaRamp);
|
2016-12-13 22:27:01 +01:00
|
|
|
|
2021-03-01 22:59:07 +01:00
|
|
|
Dll::createThread(&vsyncThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
|
2017-05-17 20:41:05 +02:00
|
|
|
}
|
|
|
|
|
2019-04-23 12:44:13 +02:00
|
|
|
void setDcFormatOverride(UINT format)
|
|
|
|
{
|
|
|
|
g_dcFormatOverride = static_cast<D3DDDIFORMAT>(format);
|
|
|
|
}
|
|
|
|
|
2019-08-02 22:16:44 +02:00
|
|
|
void setDcPaletteOverride(bool enable)
|
|
|
|
{
|
|
|
|
g_dcPaletteOverride = enable;
|
|
|
|
}
|
|
|
|
|
2020-07-13 23:44:05 +02:00
|
|
|
void waitForVsync()
|
|
|
|
{
|
|
|
|
waitForVsyncCounter(getVsyncCounter() + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool waitForVsyncCounter(UINT counter)
|
|
|
|
{
|
|
|
|
bool waited = false;
|
|
|
|
Compat::ScopedSrwLockShared lock(g_vsyncCounterSrwLock);
|
|
|
|
while (static_cast<INT>(g_vsyncCounter - counter) < 0)
|
2018-10-03 20:49:50 +02:00
|
|
|
{
|
2020-07-13 23:44:05 +02:00
|
|
|
SleepConditionVariableSRW(&g_vsyncCounterCv, &g_vsyncCounterSrwLock, INFINITE,
|
|
|
|
CONDITION_VARIABLE_LOCKMODE_SHARED);
|
|
|
|
waited = true;
|
2018-10-03 20:49:50 +02:00
|
|
|
}
|
2020-07-13 23:44:05 +02:00
|
|
|
return waited;
|
2016-12-13 22:27:01 +01:00
|
|
|
}
|
2016-11-29 00:00:49 +01:00
|
|
|
}
|
|
|
|
}
|