mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Updated presentation logic
This commit is contained in:
parent
55eab96f78
commit
80863f77a7
@ -5,11 +5,26 @@
|
||||
namespace Time
|
||||
{
|
||||
long long g_qpcFrequency = 0;
|
||||
HANDLE g_waitableTimer = nullptr;
|
||||
|
||||
void init()
|
||||
{
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceFrequency(&qpc);
|
||||
g_qpcFrequency = qpc.QuadPart;
|
||||
|
||||
g_waitableTimer = CreateWaitableTimer(nullptr, FALSE, nullptr);
|
||||
}
|
||||
|
||||
void waitForNextTick()
|
||||
{
|
||||
LARGE_INTEGER due = {};
|
||||
due.QuadPart = -1;
|
||||
if (!g_waitableTimer ||
|
||||
!SetWaitableTimer(g_waitableTimer, &due, 0, nullptr, nullptr, FALSE) ||
|
||||
WAIT_OBJECT_0 != WaitForSingleObject(g_waitableTimer, INFINITE))
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,5 @@ namespace Time
|
||||
return qpc.QuadPart;
|
||||
}
|
||||
|
||||
inline ULONG64 queryThreadCycleTime()
|
||||
{
|
||||
ULONG64 cycleTime = 0;
|
||||
QueryThreadCycleTime(GetCurrentThread(), &cycleTime);
|
||||
return cycleTime;
|
||||
}
|
||||
void waitForNextTick();
|
||||
}
|
||||
|
@ -21,9 +21,6 @@
|
||||
|
||||
namespace Config
|
||||
{
|
||||
const unsigned delayedFlipModeTimeout = 200;
|
||||
const unsigned maxPaletteUpdatesPerMs = 5;
|
||||
|
||||
extern Settings::AlternatePixelCenter alternatePixelCenter;
|
||||
extern Settings::Antialiasing antialiasing;
|
||||
extern Settings::ConfigHotKey configHotKey;
|
||||
|
@ -27,6 +27,7 @@ namespace D3dDdi
|
||||
: m_origVtable(CompatVtable<D3DDDI_DEVICEFUNCS>::s_origVtable)
|
||||
, m_adapter(adapter)
|
||||
, m_device(device)
|
||||
, m_eventQuery(nullptr)
|
||||
, m_renderTarget(nullptr)
|
||||
, m_renderTargetSubResourceIndex(0)
|
||||
, m_sharedPrimary(nullptr)
|
||||
@ -34,6 +35,10 @@ namespace D3dDdi
|
||||
, m_state(*this)
|
||||
, m_shaderBlitter(*this)
|
||||
{
|
||||
D3DDDIARG_CREATEQUERY createQuery = {};
|
||||
createQuery.QueryType = D3DDDIQUERYTYPE_EVENT;
|
||||
m_origVtable.pfnCreateQuery(m_device, &createQuery);
|
||||
m_eventQuery = createQuery.hQuery;
|
||||
}
|
||||
|
||||
void Device::add(Adapter& adapter, HANDLE device)
|
||||
@ -388,6 +393,33 @@ namespace D3dDdi
|
||||
m_state.updateConfig();
|
||||
}
|
||||
|
||||
void Device::waitForIdle()
|
||||
{
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
flushPrimitives();
|
||||
D3DDDIARG_ISSUEQUERY issueQuery = {};
|
||||
issueQuery.hQuery = m_eventQuery;
|
||||
issueQuery.Flags.End = 1;
|
||||
m_origVtable.pfnIssueQuery(m_device, &issueQuery);
|
||||
|
||||
if (m_origVtable.pfnFlush1)
|
||||
{
|
||||
m_origVtable.pfnFlush1(m_device, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_origVtable.pfnFlush(m_device);
|
||||
}
|
||||
|
||||
BOOL result = FALSE;
|
||||
D3DDDIARG_GETQUERYDATA getQueryData = {};
|
||||
getQueryData.hQuery = m_eventQuery;
|
||||
getQueryData.pData = &result;
|
||||
while (S_FALSE == m_origVtable.pfnGetQueryData(m_device, &getQueryData))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
std::map<HANDLE, Device> Device::s_devices;
|
||||
bool Device::s_isFlushEnabled = true;
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ namespace D3dDdi
|
||||
void prepareForGpuWrite();
|
||||
void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data);
|
||||
void updateConfig();
|
||||
void waitForIdle();
|
||||
|
||||
static void add(Adapter& adapter, HANDLE device);
|
||||
static Device& get(HANDLE device) { return s_devices.find(device)->second; }
|
||||
@ -75,6 +76,7 @@ namespace D3dDdi
|
||||
D3DDDI_DEVICEFUNCS m_origVtable;
|
||||
Adapter& m_adapter;
|
||||
HANDLE m_device;
|
||||
HANDLE m_eventQuery;
|
||||
std::map<HANDLE, std::unique_ptr<Resource>> m_resources;
|
||||
Resource* m_renderTarget;
|
||||
UINT m_renderTargetSubResourceIndex;
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#include <Common/Log.h>
|
||||
#include <Common/Hook.h>
|
||||
@ -107,6 +106,21 @@ namespace
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData)
|
||||
{
|
||||
LOG_FUNC("D3DKMTCreateDevice", pData);
|
||||
NTSTATUS result = D3DKMTCreateDevice(pData);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
D3DKMT_SETQUEUEDLIMIT limit = {};
|
||||
limit.hDevice = pData->hDevice;
|
||||
limit.Type = D3DKMT_SET_QUEUEDLIMIT_PRESENT;
|
||||
limit.QueuedPresentLimit = 1;
|
||||
D3DKMTSetQueuedLimit(&limit);
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
HDC WINAPI ddrawCreateDcA(LPCSTR pwszDriver, LPCSTR pwszDevice, LPCSTR pszPort, const DEVMODEA* pdm)
|
||||
{
|
||||
LOG_FUNC("ddrawCreateDCA", pwszDriver, pwszDevice, pszPort, pdm);
|
||||
@ -152,7 +166,7 @@ namespace
|
||||
{
|
||||
D3DKMT_GETSCANLINE data = {};
|
||||
getVidPnSource(data.hAdapter, data.VidPnSourceId);
|
||||
if (!data.hAdapter || FAILED(D3DKMTGetScanLine(&data)) || data.InVerticalBlank)
|
||||
if (!data.hAdapter || FAILED(D3DKMTGetScanLine(&data)))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -189,19 +203,6 @@ namespace
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
void pollForVerticalBlank()
|
||||
{
|
||||
int scanLine = getScanLine();
|
||||
int prevScanLine = scanLine;
|
||||
auto qpcStart = Time::queryPerformanceCounter();
|
||||
while (scanLine >= prevScanLine && Time::queryPerformanceCounter() - qpcStart < Time::g_qpcFrequency / 60)
|
||||
{
|
||||
Sleep(1);
|
||||
prevScanLine = scanLine;
|
||||
scanLine = getScanLine();
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData)
|
||||
{
|
||||
LOG_FUNC("D3DKMTPresent", pData);
|
||||
@ -252,6 +253,7 @@ namespace
|
||||
{
|
||||
LOG_FUNC("D3DKMTSetGammaRamp", pData);
|
||||
UINT vsyncCounter = D3dDdi::KernelModeThunks::getVsyncCounter();
|
||||
DDraw::RealPrimarySurface::setUpdateReady();
|
||||
DDraw::RealPrimarySurface::flush();
|
||||
HRESULT result = D3DKMTSetGammaRamp(pData);
|
||||
if (SUCCEEDED(result))
|
||||
@ -324,30 +326,24 @@ namespace
|
||||
|
||||
void waitForVerticalBlank()
|
||||
{
|
||||
if (IsWindows8OrGreater())
|
||||
auto qpcStart = Time::queryPerformanceCounter();
|
||||
int scanLine = getScanLine();
|
||||
int prevScanLine = 0;
|
||||
while (scanLine >= prevScanLine)
|
||||
{
|
||||
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
||||
|
||||
{
|
||||
Compat::ScopedSrwLockShared lock(g_adapterInfoSrwLock);
|
||||
data.hAdapter = g_lastOpenAdapterInfo.adapter;
|
||||
data.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
||||
}
|
||||
|
||||
if (!data.hAdapter)
|
||||
{
|
||||
updateGdiAdapterInfo();
|
||||
data.hAdapter = g_gdiAdapterInfo.adapter;
|
||||
data.VidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
|
||||
}
|
||||
|
||||
if (data.hAdapter && SUCCEEDED(D3DKMTWaitForVerticalBlankEvent(&data)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time::waitForNextTick();
|
||||
prevScanLine = scanLine;
|
||||
scanLine = getScanLine();
|
||||
}
|
||||
|
||||
pollForVerticalBlank();
|
||||
if (scanLine < 0)
|
||||
{
|
||||
auto msElapsed = static_cast<DWORD>(Time::qpcToMs(Time::queryPerformanceCounter() - qpcStart));
|
||||
if (msElapsed < 16)
|
||||
{
|
||||
Sleep(16 - msElapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,6 +408,7 @@ namespace D3dDdi
|
||||
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, "D3DKMTCreateDevice", createDevice);
|
||||
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc);
|
||||
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTPresent", present);
|
||||
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTQueryAdapterInfo", queryAdapterInfo);
|
||||
|
@ -832,6 +832,16 @@ namespace D3dDdi
|
||||
auto rtIndex = rtSurface.resource ? 0 : data.DstSubResourceIndex;
|
||||
auto rtRect = rtSurface.resource ? data.SrcRect : data.DstRect;
|
||||
|
||||
if (D3DDDIPOOL_SYSTEMMEM == srcResource->m_fixedData.Pool)
|
||||
{
|
||||
srcResource = repo.getTempTexture(srcWidth, srcHeight, getPixelFormat(srcResource->m_fixedData.Format)).resource;
|
||||
if (!srcResource)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
copySubResourceRegion(*srcResource, 0, data.SrcRect, data.hSrcResource, data.SrcSubResourceIndex, data.SrcRect);
|
||||
}
|
||||
|
||||
if (D3DDDIFMT_P8 == srcResource->m_origData.Format)
|
||||
{
|
||||
auto entries(Gdi::Palette::getHardwarePalette());
|
||||
|
@ -27,6 +27,7 @@ namespace D3dDdi
|
||||
|
||||
operator HANDLE() const { return m_handle; }
|
||||
const Resource* getCustomResource() { return m_msaaSurface.resource ? m_msaaSurface.resource : m_msaaResolvedSurface.resource; }
|
||||
Device& getDevice() const { return m_device; }
|
||||
const D3DDDIARG_CREATERESOURCE2& getFixedDesc() const { return m_fixedData; }
|
||||
const D3DDDIARG_CREATERESOURCE2& getOrigDesc() const { return m_origData; }
|
||||
bool isClampable() const { return m_isClampable; }
|
||||
|
@ -73,6 +73,7 @@ namespace
|
||||
template <typename TDirectDraw>
|
||||
HRESULT STDMETHODCALLTYPE WaitForVerticalBlank(TDirectDraw* This, DWORD dwFlags, HANDLE hEvent)
|
||||
{
|
||||
DDraw::RealPrimarySurface::setUpdateReady();
|
||||
DDraw::RealPrimarySurface::flush();
|
||||
return getOrigVtable(This).WaitForVerticalBlank(This, dwFlags, hEvent);
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ namespace DDraw
|
||||
updatesInLastMs.pop_front();
|
||||
}
|
||||
|
||||
if (updatesInLastMs.size() >= Config::maxPaletteUpdatesPerMs)
|
||||
const unsigned maxPaletteUpdatesPerMs = 5;
|
||||
if (updatesInLastMs.size() >= maxPaletteUpdatesPerMs)
|
||||
{
|
||||
Sleep(1);
|
||||
updatesInLastMs.clear();
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
#include <Common/CompatPtr.h>
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/ScopedCriticalSection.h>
|
||||
#include <Common/Time.h>
|
||||
#include <Config/Config.h>
|
||||
#include <D3dDdi/Device.h>
|
||||
@ -29,6 +29,8 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200;
|
||||
|
||||
void onRelease();
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
||||
@ -40,11 +42,18 @@ namespace
|
||||
bool g_isFullscreen = false;
|
||||
DDraw::Surface* g_lastFlipSurface = nullptr;
|
||||
|
||||
Compat::CriticalSection g_presentCs;
|
||||
bool g_isDelayedFlipPending = false;
|
||||
bool g_isUpdatePending = false;
|
||||
bool g_waitingForPrimaryUnlock = false;
|
||||
std::atomic<long long> g_qpcLastUpdate = 0;
|
||||
bool g_isUpdateReady = false;
|
||||
DWORD g_lastUpdateThreadId = 0;
|
||||
long long g_qpcLastUpdate = 0;
|
||||
long long g_qpcUpdateStart = 0;
|
||||
|
||||
long long g_qpcDelayedFlipEnd = 0;
|
||||
UINT g_flipEndVsyncCount = 0;
|
||||
UINT g_presentEndVsyncCount = 0;
|
||||
|
||||
HWND g_devicePresentationWindow = nullptr;
|
||||
HWND g_deviceWindow = nullptr;
|
||||
HWND* g_deviceWindowPtr = nullptr;
|
||||
@ -112,24 +121,14 @@ namespace
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool isFlipPending()
|
||||
{
|
||||
return static_cast<INT>(D3dDdi::KernelModeThunks::getVsyncCounter() - g_flipEndVsyncCount) < 0;
|
||||
}
|
||||
|
||||
bool isPresentPending()
|
||||
{
|
||||
return static_cast<INT>(D3dDdi::KernelModeThunks::getVsyncCounter() - g_presentEndVsyncCount) < 0;
|
||||
}
|
||||
|
||||
void onRelease()
|
||||
{
|
||||
LOG_FUNC("RealPrimarySurface::onRelease");
|
||||
|
||||
g_frontBuffer = nullptr;
|
||||
g_lastFlipSurface = nullptr;
|
||||
g_clipper.release();
|
||||
g_isFullscreen = false;
|
||||
g_waitingForPrimaryUnlock = false;
|
||||
g_surfaceDesc = {};
|
||||
|
||||
DDraw::RealPrimarySurface::updateDevicePresentationWindowPos();
|
||||
@ -152,16 +151,20 @@ namespace
|
||||
const bool isFlippable = 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP);
|
||||
g_surfaceDesc = desc;
|
||||
g_isFullscreen = isFlippable;
|
||||
g_isUpdatePending = true;
|
||||
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(Config::delayedFlipModeTimeout);
|
||||
|
||||
if (isFlippable)
|
||||
{
|
||||
g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT);
|
||||
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1;
|
||||
g_presentEndVsyncCount = g_flipEndVsyncCount;
|
||||
D3dDdi::KernelModeThunks::waitForVsyncCounter(g_flipEndVsyncCount);
|
||||
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
|
||||
}
|
||||
|
||||
Compat::ScopedCriticalSection lock(g_presentCs);
|
||||
g_isUpdatePending = false;
|
||||
g_isUpdateReady = false;
|
||||
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(DELAYED_FLIP_MODE_TIMEOUT_MS);
|
||||
g_qpcUpdateStart = g_qpcLastUpdate;
|
||||
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
|
||||
g_flipEndVsyncCount = g_presentEndVsyncCount;
|
||||
}
|
||||
|
||||
void presentToPrimaryChain(CompatWeakPtr<IDirectDrawSurface7> src)
|
||||
@ -202,11 +205,15 @@ namespace
|
||||
D3dDdi::KernelModeThunks::setDcPaletteOverride(nullptr);
|
||||
}
|
||||
|
||||
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, UINT flipInterval)
|
||||
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src)
|
||||
{
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_presentCs);
|
||||
g_isUpdatePending = false;
|
||||
g_isUpdateReady = false;
|
||||
}
|
||||
|
||||
presentToPrimaryChain(src);
|
||||
g_isUpdatePending = false;
|
||||
g_waitingForPrimaryUnlock = false;
|
||||
|
||||
if (g_isFullscreen && g_devicePresentationWindow)
|
||||
{
|
||||
@ -214,60 +221,26 @@ namespace
|
||||
g_frontBuffer->Flip(g_frontBuffer, getBackBuffer(), DDFLIP_WAIT);
|
||||
*g_deviceWindowPtr = g_deviceWindow;
|
||||
}
|
||||
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + max(flipInterval, 1);
|
||||
}
|
||||
|
||||
void updateNowIfNotBusy()
|
||||
{
|
||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||
RECT emptyRect = {};
|
||||
HRESULT result = primary ? primary->BltFast(primary, 0, 0, primary, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
|
||||
g_waitingForPrimaryUnlock = DDERR_SURFACEBUSY == result || DDERR_LOCKEDSURFACES == result;
|
||||
|
||||
if (!g_waitingForPrimaryUnlock)
|
||||
{
|
||||
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
|
||||
updateNow(primary, msSinceLastUpdate > Config::delayedFlipModeTimeout ? 0 : 1);
|
||||
}
|
||||
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1;
|
||||
}
|
||||
|
||||
unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
||||
{
|
||||
bool skipWaitForVsync = false;
|
||||
|
||||
int msUntilUpdateReady = 0;
|
||||
while (true)
|
||||
{
|
||||
if (!skipWaitForVsync)
|
||||
if (msUntilUpdateReady > 0)
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
|
||||
}
|
||||
skipWaitForVsync = false;
|
||||
Sleep(1);
|
||||
|
||||
DDraw::ScopedThreadLock lock;
|
||||
Gdi::Caret::blink();
|
||||
if (Gdi::Cursor::update())
|
||||
{
|
||||
g_isUpdatePending = true;
|
||||
}
|
||||
|
||||
if (g_isUpdatePending && !isPresentPending())
|
||||
{
|
||||
auto qpcNow = Time::queryPerformanceCounter();
|
||||
auto qpcLastVsync = D3dDdi::KernelModeThunks::getQpcLastVsync();
|
||||
if (Time::qpcToMs(qpcNow - qpcLastVsync) < 1 ||
|
||||
Time::qpcToMs(qpcNow - g_qpcLastUpdate) < 1 && Time::qpcToMs(qpcNow - qpcLastVsync) <= 3)
|
||||
{
|
||||
skipWaitForVsync = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
updateNowIfNotBusy();
|
||||
}
|
||||
}
|
||||
msUntilUpdateReady = DDraw::RealPrimarySurface::flush();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,27 +298,19 @@ namespace DDraw
|
||||
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
|
||||
{
|
||||
const DWORD flipInterval = getFlipInterval(flags);
|
||||
if (0 == flipInterval)
|
||||
if (0 == flipInterval ||
|
||||
Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate) < DELAYED_FLIP_MODE_TIMEOUT_MS)
|
||||
{
|
||||
g_isUpdatePending = true;
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
|
||||
const bool isFlipDelayed = msSinceLastUpdate >= 0 && msSinceLastUpdate <= Config::delayedFlipModeTimeout;
|
||||
if (isFlipDelayed)
|
||||
{
|
||||
if (!isPresentPending())
|
||||
{
|
||||
CompatPtr<IDirectDrawSurface7> prevPrimarySurface(
|
||||
surfaceTargetOverride ? surfaceTargetOverride : PrimarySurface::getLastSurface());
|
||||
updateNow(prevPrimarySurface, 0);
|
||||
}
|
||||
g_isUpdatePending = true;
|
||||
PrimarySurface::waitForIdle();
|
||||
Compat::ScopedCriticalSection lock(g_presentCs);
|
||||
g_isDelayedFlipPending = true;
|
||||
g_isUpdatePending = false;
|
||||
g_isUpdateReady = false;
|
||||
g_lastUpdateThreadId = GetCurrentThreadId();
|
||||
}
|
||||
else
|
||||
{
|
||||
updateNow(PrimarySurface::getPrimary(), flipInterval);
|
||||
updateNow(PrimarySurface::getPrimary());
|
||||
}
|
||||
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + flipInterval;
|
||||
|
||||
@ -358,16 +323,60 @@ namespace DDraw
|
||||
{
|
||||
g_lastFlipSurface = nullptr;
|
||||
}
|
||||
|
||||
g_qpcDelayedFlipEnd = Time::queryPerformanceCounter();
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
void RealPrimarySurface::flush()
|
||||
int RealPrimarySurface::flush()
|
||||
{
|
||||
DDraw::ScopedThreadLock lock;
|
||||
if (g_isUpdatePending && !isPresentPending())
|
||||
auto vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
|
||||
if (static_cast<int>(vsyncCount - g_presentEndVsyncCount) < 0)
|
||||
{
|
||||
updateNowIfNotBusy();
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_presentCs);
|
||||
if (!g_isUpdateReady)
|
||||
{
|
||||
if (g_isUpdatePending)
|
||||
{
|
||||
auto msSinceUpdateStart = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcUpdateStart);
|
||||
if (msSinceUpdateStart < 10)
|
||||
{
|
||||
return 10 - static_cast<int>(msSinceUpdateStart);
|
||||
}
|
||||
g_isUpdateReady = true;
|
||||
}
|
||||
else if (g_isDelayedFlipPending)
|
||||
{
|
||||
auto msSinceDelayedFlipEnd = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcDelayedFlipEnd);
|
||||
if (msSinceDelayedFlipEnd < 3)
|
||||
{
|
||||
return 3 - static_cast<int>(msSinceDelayedFlipEnd);
|
||||
}
|
||||
g_isDelayedFlipPending = false;
|
||||
g_isUpdateReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_isUpdateReady)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto src(g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : DDraw::PrimarySurface::getPrimary());
|
||||
RECT emptyRect = {};
|
||||
HRESULT result = src ? src->BltFast(src, 0, 0, src, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
|
||||
if (DDERR_SURFACEBUSY == result || DDERR_LOCKEDSURFACES == result)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
updateNow(src);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HWND RealPrimarySurface::getDevicePresentationWindow()
|
||||
@ -441,8 +450,16 @@ namespace DDraw
|
||||
|
||||
void RealPrimarySurface::scheduleUpdate()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_presentCs);
|
||||
g_qpcLastUpdate = Time::queryPerformanceCounter();
|
||||
g_isUpdatePending = true;
|
||||
if (!g_isUpdatePending)
|
||||
{
|
||||
g_qpcUpdateStart = g_qpcLastUpdate;
|
||||
g_isUpdatePending = true;
|
||||
g_isDelayedFlipPending = false;
|
||||
g_lastUpdateThreadId = GetCurrentThreadId();
|
||||
}
|
||||
g_isUpdateReady = false;
|
||||
}
|
||||
|
||||
HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
|
||||
@ -457,14 +474,13 @@ namespace DDraw
|
||||
return gammaControl->SetGammaRamp(gammaControl, 0, rampData);
|
||||
}
|
||||
|
||||
void RealPrimarySurface::update()
|
||||
void RealPrimarySurface::setUpdateReady()
|
||||
{
|
||||
DDraw::ScopedThreadLock lock;
|
||||
g_qpcLastUpdate = Time::queryPerformanceCounter();
|
||||
g_isUpdatePending = true;
|
||||
if (g_waitingForPrimaryUnlock)
|
||||
Compat::ScopedCriticalSection lock(g_presentCs);
|
||||
if ((g_isUpdatePending || g_isDelayedFlipPending) && GetCurrentThreadId() == g_lastUpdateThreadId)
|
||||
{
|
||||
updateNowIfNotBusy();
|
||||
g_isUpdateReady = true;
|
||||
g_isDelayedFlipPending = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,17 +506,23 @@ namespace DDraw
|
||||
});
|
||||
}
|
||||
|
||||
bool RealPrimarySurface::waitForFlip(Surface* surface)
|
||||
bool RealPrimarySurface::waitForFlip(CompatWeakPtr<IDirectDrawSurface7> surface)
|
||||
{
|
||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||
if (!surface || !primary ||
|
||||
surface != g_lastFlipSurface &&
|
||||
surface != Surface::getSurface(*DDraw::PrimarySurface::getPrimary()))
|
||||
if (!surface || !primary || !g_lastFlipSurface ||
|
||||
surface != primary && surface != g_lastFlipSurface->getDDS())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
D3dDdi::KernelModeThunks::waitForVsyncCounter(g_flipEndVsyncCount);
|
||||
auto vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
|
||||
while (static_cast<int>(vsyncCount - g_flipEndVsyncCount) < 0)
|
||||
{
|
||||
flush();
|
||||
++vsyncCount;
|
||||
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCount);
|
||||
g_qpcDelayedFlipEnd = Time::queryPerformanceCounter();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace DDraw
|
||||
static HRESULT create(CompatRef<DirectDraw> dd);
|
||||
|
||||
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
|
||||
static void flush();
|
||||
static int flush();
|
||||
static HWND getDevicePresentationWindow();
|
||||
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
||||
static RECT getMonitorRect();
|
||||
@ -29,8 +29,8 @@ namespace DDraw
|
||||
static HRESULT restore();
|
||||
static void scheduleUpdate();
|
||||
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
|
||||
static void update();
|
||||
static void setUpdateReady();
|
||||
static void updateDevicePresentationWindowPos();
|
||||
static bool waitForFlip(Surface* surface);
|
||||
static bool waitForFlip(CompatWeakPtr<IDirectDrawSurface7> surface);
|
||||
};
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
namespace
|
||||
{
|
||||
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
|
||||
D3dDdi::Device* g_device = nullptr;
|
||||
HANDLE g_gdiResourceHandle = nullptr;
|
||||
HANDLE g_frontResource = nullptr;
|
||||
DWORD g_origCaps = 0;
|
||||
@ -28,6 +29,7 @@ namespace DDraw
|
||||
{
|
||||
LOG_FUNC("PrimarySurface::~PrimarySurface");
|
||||
|
||||
g_device = nullptr;
|
||||
g_gdiResourceHandle = nullptr;
|
||||
g_frontResource = nullptr;
|
||||
g_primarySurface = nullptr;
|
||||
@ -91,6 +93,7 @@ namespace DDraw
|
||||
ResizePalette(g_palette, 256);
|
||||
}
|
||||
|
||||
g_device = D3dDdi::Device::findDeviceByResource(DirectDrawSurface::getDriverResourceHandle(*surface));
|
||||
data->restore();
|
||||
D3dDdi::Device::updateAllConfig();
|
||||
return DD_OK;
|
||||
@ -265,7 +268,15 @@ namespace DDraw
|
||||
ReleaseDC(g_deviceWindow, dc);
|
||||
}
|
||||
|
||||
RealPrimarySurface::update();
|
||||
RealPrimarySurface::scheduleUpdate();
|
||||
}
|
||||
|
||||
void PrimarySurface::waitForIdle()
|
||||
{
|
||||
if (g_device)
|
||||
{
|
||||
g_device->waitForIdle();
|
||||
}
|
||||
}
|
||||
|
||||
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;
|
||||
|
@ -31,6 +31,7 @@ namespace DDraw
|
||||
static bool isGdiSurface(TSurface* surface);
|
||||
|
||||
static void updateFrontResource();
|
||||
static void waitForIdle();
|
||||
|
||||
virtual void restore();
|
||||
|
||||
|
@ -91,11 +91,13 @@ namespace DDraw
|
||||
return DDERR_SURFACELOST;
|
||||
}
|
||||
|
||||
RealPrimarySurface::flush();
|
||||
HRESULT result = SurfaceImpl::Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
bltToGdi(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||
RealPrimarySurface::update();
|
||||
RealPrimarySurface::scheduleUpdate();
|
||||
PrimarySurface::waitForIdle();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -109,10 +111,12 @@ namespace DDraw
|
||||
return DDERR_SURFACELOST;
|
||||
}
|
||||
|
||||
RealPrimarySurface::flush();
|
||||
HRESULT result = SurfaceImpl::BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
RealPrimarySurface::scheduleUpdate();
|
||||
PrimarySurface::waitForIdle();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -120,7 +124,9 @@ namespace DDraw
|
||||
template <typename TSurface>
|
||||
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
|
||||
{
|
||||
DDraw::RealPrimarySurface::waitForFlip(m_data);
|
||||
RealPrimarySurface::setUpdateReady();
|
||||
RealPrimarySurface::flush();
|
||||
RealPrimarySurface::waitForFlip(m_data->getDDS());
|
||||
auto surfaceTargetOverride(CompatPtr<TSurface>::from(lpDDSurfaceTargetOverride));
|
||||
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
|
||||
if (isFlipEmulated)
|
||||
@ -155,6 +161,13 @@ namespace DDraw
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT PrimarySurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
|
||||
{
|
||||
RealPrimarySurface::flush();
|
||||
return SurfaceImpl::GetDC(This, lphDC);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT PrimarySurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)
|
||||
{
|
||||
@ -187,6 +200,7 @@ namespace DDraw
|
||||
return DDERR_SURFACELOST;
|
||||
}
|
||||
|
||||
RealPrimarySurface::flush();
|
||||
HRESULT result = SurfaceImpl::Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
@ -201,7 +215,7 @@ namespace DDraw
|
||||
HRESULT result = SurfaceImpl::ReleaseDC(This, hDC);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
RealPrimarySurface::scheduleUpdate();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -244,7 +258,7 @@ namespace DDraw
|
||||
HRESULT result = SurfaceImpl::Unlock(This, lpRect);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
RealPrimarySurface::scheduleUpdate();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ namespace DDraw
|
||||
TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans) override;
|
||||
virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags) override;
|
||||
virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps) override;
|
||||
virtual HRESULT GetDC(TSurface* This, HDC* lphDC);
|
||||
virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc) override;
|
||||
virtual HRESULT IsLost(TSurface* This) override;
|
||||
virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||
|
@ -30,6 +30,8 @@ namespace DDraw
|
||||
template <typename TSurface>
|
||||
static Surface* getSurface(TSurface& dds);
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> getDDS() const { return m_surface; };
|
||||
|
||||
template <typename TSurface>
|
||||
SurfaceImpl<TSurface>* getImpl() const;
|
||||
|
||||
|
@ -109,7 +109,7 @@ namespace DDraw
|
||||
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
|
||||
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
|
||||
{
|
||||
RealPrimarySurface::waitForFlip(m_data);
|
||||
RealPrimarySurface::waitForFlip(m_data->getDDS());
|
||||
DirectDrawClipper::update();
|
||||
return blt(This, lpDDSrcSurface, lpSrcRect, [=](TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect)
|
||||
{ return getOrigVtable(This).Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); });
|
||||
@ -119,7 +119,7 @@ namespace DDraw
|
||||
HRESULT SurfaceImpl<TSurface>::BltFast(
|
||||
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
|
||||
{
|
||||
RealPrimarySurface::waitForFlip(m_data);
|
||||
RealPrimarySurface::waitForFlip(m_data->getDDS());
|
||||
return blt(This, lpDDSrcSurface, lpSrcRect, [=](TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect)
|
||||
{ return getOrigVtable(This).BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans); });
|
||||
}
|
||||
@ -144,7 +144,7 @@ namespace DDraw
|
||||
template <typename TSurface>
|
||||
HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
|
||||
{
|
||||
RealPrimarySurface::waitForFlip(m_data);
|
||||
RealPrimarySurface::waitForFlip(m_data->getDDS());
|
||||
HRESULT result = getOrigVtable(This).GetDC(This, lphDC);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
@ -181,7 +181,7 @@ namespace DDraw
|
||||
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||
DWORD dwFlags, HANDLE hEvent)
|
||||
{
|
||||
RealPrimarySurface::waitForFlip(m_data);
|
||||
RealPrimarySurface::waitForFlip(m_data->getDDS());
|
||||
HRESULT result = getOrigVtable(This).Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
@ -222,7 +223,7 @@ namespace Gdi
|
||||
}
|
||||
}
|
||||
|
||||
bool update()
|
||||
void update()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (!IsRectEmpty(&g_monitorClipRect))
|
||||
@ -238,11 +239,9 @@ namespace Gdi
|
||||
(cursorInfo.hCursor != g_prevCursorInfo.hCursor || cursorInfo.ptScreenPos != g_prevCursorInfo.ptScreenPos))
|
||||
{
|
||||
g_prevCursorInfo = cursorInfo;
|
||||
return true;
|
||||
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,6 @@ namespace Gdi
|
||||
HCURSOR setCursor(HCURSOR cursor);
|
||||
void setMonitorClipRect(const RECT& rect);
|
||||
void setEmulated(bool isEmulated);
|
||||
bool update();
|
||||
void update();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <D3dDdi/ScopedCriticalSection.h>
|
||||
#include <Dll/Dll.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <Gdi/Caret.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/GuiThread.h>
|
||||
#include <Gdi/Region.h>
|
||||
#include <Gdi/WinProc.h>
|
||||
@ -83,7 +86,7 @@ namespace
|
||||
}
|
||||
|
||||
MSG msg = {};
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
while (CALL_ORIG_FUNC(GetMessageA)(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
@ -91,6 +94,16 @@ namespace
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Sleep(5);
|
||||
Gdi::Caret::blink();
|
||||
Gdi::Cursor::update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
@ -154,6 +167,7 @@ namespace Gdi
|
||||
void start()
|
||||
{
|
||||
Dll::createThread(messageWindowThreadProc, &g_threadId, THREAD_PRIORITY_TIME_CRITICAL, 0);
|
||||
Dll::createThread(updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,23 @@ namespace
|
||||
return ddcWindowProc(hwnd, uMsg, wParam, lParam, CallWindowProcW, getWindowProc(hwnd).wndProcW);
|
||||
}
|
||||
|
||||
BOOL WINAPI getMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
|
||||
decltype(&GetMessageA) origGetMessage)
|
||||
{
|
||||
DDraw::RealPrimarySurface::setUpdateReady();
|
||||
return origGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
|
||||
}
|
||||
|
||||
BOOL WINAPI getMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
|
||||
{
|
||||
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageA));
|
||||
}
|
||||
|
||||
BOOL WINAPI getMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
|
||||
{
|
||||
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageW));
|
||||
}
|
||||
|
||||
LONG getWindowLong(HWND hWnd, int nIndex,
|
||||
decltype(&GetWindowLongA) origGetWindowLong, WNDPROC(WindowProc::* wndProc))
|
||||
{
|
||||
@ -290,6 +307,23 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
BOOL peekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg,
|
||||
decltype(&PeekMessageA) origPeekMessage)
|
||||
{
|
||||
DDraw::RealPrimarySurface::setUpdateReady();
|
||||
return origPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
|
||||
}
|
||||
|
||||
BOOL WINAPI peekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
|
||||
{
|
||||
return peekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, CALL_ORIG_FUNC(PeekMessageA));
|
||||
}
|
||||
|
||||
BOOL WINAPI peekMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
|
||||
{
|
||||
return peekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, CALL_ORIG_FUNC(PeekMessageW));
|
||||
}
|
||||
|
||||
BOOL WINAPI setLayeredWindowAttributes(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags)
|
||||
{
|
||||
LOG_FUNC("SetLayeredWindowAttributes", hwnd, crKey, bAlpha, dwFlags);
|
||||
@ -455,8 +489,12 @@ namespace Gdi
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
HOOK_FUNCTION(user32, GetMessageA, getMessageA);
|
||||
HOOK_FUNCTION(user32, GetMessageW, getMessageW);
|
||||
HOOK_FUNCTION(user32, GetWindowLongA, getWindowLongA);
|
||||
HOOK_FUNCTION(user32, GetWindowLongW, getWindowLongW);
|
||||
HOOK_FUNCTION(user32, PeekMessageA, peekMessageA);
|
||||
HOOK_FUNCTION(user32, PeekMessageW, peekMessageW);
|
||||
HOOK_FUNCTION(user32, SetLayeredWindowAttributes, setLayeredWindowAttributes);
|
||||
HOOK_FUNCTION(user32, SetWindowLongA, setWindowLongA);
|
||||
HOOK_FUNCTION(user32, SetWindowLongW, setWindowLongW);
|
||||
|
Loading…
x
Reference in New Issue
Block a user