mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Removed dependency on D3DKMTPresent
Fixes presentation issues when Hardware Accelerated GPU Scheduling is enabled (issue #73).
This commit is contained in:
parent
b8bff744e5
commit
799e9a95ae
48
DDrawCompat/Common/ScopedSrwLock.h
Normal file
48
DDrawCompat/Common/ScopedSrwLock.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
class SrwLock : public SRWLOCK
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrwLock() : SRWLOCK(SRWLOCK_INIT)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedSrwLockExclusive
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScopedSrwLockExclusive(SRWLOCK& lock) : m_lock(lock)
|
||||||
|
{
|
||||||
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedSrwLockExclusive()
|
||||||
|
{
|
||||||
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SRWLOCK& m_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedSrwLockShared
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScopedSrwLockShared(SRWLOCK& lock) : m_lock(lock)
|
||||||
|
{
|
||||||
|
AcquireSRWLockShared(&m_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedSrwLockShared()
|
||||||
|
{
|
||||||
|
ReleaseSRWLockShared(&m_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SRWLOCK& m_lock;
|
||||||
|
};
|
||||||
|
}
|
@ -100,5 +100,6 @@ namespace D3dDdi
|
|||||||
void uninstallHooks()
|
void uninstallHooks()
|
||||||
{
|
{
|
||||||
unhookOpenAdapter();
|
unhookOpenAdapter();
|
||||||
|
KernelModeThunks::stopVsyncThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
#include <atomic>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <d3d.h>
|
|
||||||
#include <d3dumddi.h>
|
|
||||||
#include <winternl.h>
|
|
||||||
#include <../km/d3dkmthk.h>
|
|
||||||
|
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
#include <Common/Hook.h>
|
#include <Common/Hook.h>
|
||||||
#include <Common/ScopedCriticalSection.h>
|
#include <Common/ScopedSrwLock.h>
|
||||||
#include <Common/Time.h>
|
#include <Common/Time.h>
|
||||||
#include <D3dDdi/Device.h>
|
#include <D3dDdi/Device.h>
|
||||||
#include <D3dDdi/Hooks.h>
|
#include <D3dDdi/Hooks.h>
|
||||||
@ -32,33 +25,24 @@ namespace
|
|||||||
RECT monitorRect;
|
RECT monitorRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContextInfo
|
|
||||||
{
|
|
||||||
D3DKMT_HANDLE device;
|
|
||||||
|
|
||||||
ContextInfo() : device(0) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<D3DKMT_HANDLE, ContextInfo> g_contexts;
|
|
||||||
D3DDDIFORMAT g_dcFormatOverride = D3DDDIFMT_UNKNOWN;
|
D3DDDIFORMAT g_dcFormatOverride = D3DDDIFMT_UNKNOWN;
|
||||||
bool g_dcPaletteOverride = false;
|
bool g_dcPaletteOverride = false;
|
||||||
AdapterInfo g_gdiAdapterInfo = {};
|
AdapterInfo g_gdiAdapterInfo = {};
|
||||||
AdapterInfo g_lastOpenAdapterInfo = {};
|
AdapterInfo g_lastOpenAdapterInfo = {};
|
||||||
|
Compat::SrwLock g_lastOpenAdapterInfoSrwLock;
|
||||||
std::string g_lastDDrawCreateDcDevice;
|
std::string g_lastDDrawCreateDcDevice;
|
||||||
UINT g_lastFlipInterval = 0;
|
|
||||||
UINT g_flipIntervalOverride = 0;
|
|
||||||
D3DKMT_HANDLE g_lastPresentContext = 0;
|
|
||||||
UINT g_presentCount = 0;
|
|
||||||
std::atomic<long long> g_qpcLastVerticalBlank = 0;
|
|
||||||
Compat::CriticalSection g_vblankCs;
|
|
||||||
|
|
||||||
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
HANDLE g_vsyncThread = nullptr;
|
||||||
|
bool g_stopVsyncThread = false;
|
||||||
|
UINT g_vsyncCounter = 0;
|
||||||
|
CONDITION_VARIABLE g_vsyncCounterCv = CONDITION_VARIABLE_INIT;
|
||||||
|
Compat::SrwLock g_vsyncCounterSrwLock;
|
||||||
|
|
||||||
DWORD WINAPI waitForVsyncThreadProc(LPVOID lpParameter);
|
void waitForVerticalBlank();
|
||||||
|
|
||||||
NTSTATUS APIENTRY closeAdapter(const D3DKMT_CLOSEADAPTER* pData)
|
NTSTATUS APIENTRY closeAdapter(const D3DKMT_CLOSEADAPTER* pData)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_vblankCs);
|
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
||||||
if (pData && pData->hAdapter == g_lastOpenAdapterInfo.adapter)
|
if (pData && pData->hAdapter == g_lastOpenAdapterInfo.adapter)
|
||||||
{
|
{
|
||||||
g_lastOpenAdapterInfo = {};
|
g_lastOpenAdapterInfo = {};
|
||||||
@ -66,30 +50,6 @@ namespace
|
|||||||
return D3DKMTCloseAdapter(pData);
|
return D3DKMTCloseAdapter(pData);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY createContext(D3DKMT_CREATECONTEXT* pData)
|
|
||||||
{
|
|
||||||
LOG_FUNC("D3DKMTCreateContext", pData);
|
|
||||||
NTSTATUS result = D3DKMTCreateContext(pData);
|
|
||||||
if (SUCCEEDED(result))
|
|
||||||
{
|
|
||||||
g_contexts[pData->hContext].device = pData->hDevice;
|
|
||||||
}
|
|
||||||
return LOG_RESULT(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS APIENTRY createContextVirtual(D3DKMT_CREATECONTEXTVIRTUAL* pData)
|
|
||||||
{
|
|
||||||
LOG_FUNC("D3DKMTCreateContextVirtual", pData);
|
|
||||||
static auto d3dKmtCreateContextVirtual = reinterpret_cast<decltype(D3DKMTCreateContextVirtual)*>(
|
|
||||||
GetProcAddress(GetModuleHandle("gdi32"), "D3DKMTCreateContextVirtual"));
|
|
||||||
NTSTATUS result = d3dKmtCreateContextVirtual(pData);
|
|
||||||
if (SUCCEEDED(result))
|
|
||||||
{
|
|
||||||
g_contexts[pData->hContext].device = pData->hDevice;
|
|
||||||
}
|
|
||||||
return LOG_RESULT(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS APIENTRY createDcFromMemory(D3DKMT_CREATEDCFROMMEMORY* pData)
|
NTSTATUS APIENTRY createDcFromMemory(D3DKMT_CREATEDCFROMMEMORY* pData)
|
||||||
{
|
{
|
||||||
LOG_FUNC("D3DKMTCreateDCFromMemory", pData);
|
LOG_FUNC("D3DKMTCreateDCFromMemory", pData);
|
||||||
@ -154,21 +114,6 @@ namespace
|
|||||||
return LOG_RESULT(CreateDCA(pwszDriver, pwszDevice, pszPort, pdm));
|
return LOG_RESULT(CreateDCA(pwszDriver, pwszDevice, pszPort, pdm));
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY destroyContext(const D3DKMT_DESTROYCONTEXT* pData)
|
|
||||||
{
|
|
||||||
LOG_FUNC("D3DKMTDestroyContext", pData);
|
|
||||||
NTSTATUS result = D3DKMTDestroyContext(pData);
|
|
||||||
if (SUCCEEDED(result))
|
|
||||||
{
|
|
||||||
g_contexts.erase(pData->hContext);
|
|
||||||
if (g_lastPresentContext == pData->hContext)
|
|
||||||
{
|
|
||||||
g_lastPresentContext = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return LOG_RESULT(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL CALLBACK findDDrawMonitorRect(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
BOOL CALLBACK findDDrawMonitorRect(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
||||||
{
|
{
|
||||||
MONITORINFOEX mi = {};
|
MONITORINFOEX mi = {};
|
||||||
@ -208,40 +153,12 @@ namespace
|
|||||||
NTSTATUS result = D3DKMTOpenAdapterFromHdc(pData);
|
NTSTATUS result = D3DKMTOpenAdapterFromHdc(pData);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_vblankCs);
|
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
||||||
g_lastOpenAdapterInfo = getAdapterInfo(*pData);
|
g_lastOpenAdapterInfo = getAdapterInfo(*pData);
|
||||||
}
|
}
|
||||||
return LOG_RESULT(result);
|
return LOG_RESULT(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData)
|
|
||||||
{
|
|
||||||
LOG_FUNC("D3DKMTPresent", pData);
|
|
||||||
|
|
||||||
if (pData->Flags.Flip)
|
|
||||||
{
|
|
||||||
g_lastFlipInterval = pData->FlipInterval;
|
|
||||||
g_lastPresentContext = pData->hContext;
|
|
||||||
|
|
||||||
if (UINT_MAX == g_flipIntervalOverride)
|
|
||||||
{
|
|
||||||
return LOG_RESULT(S_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
++g_presentCount;
|
|
||||||
if (0 == g_presentCount)
|
|
||||||
{
|
|
||||||
g_presentCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pData->PresentCount = g_presentCount;
|
|
||||||
pData->Flags.PresentCountValid = 1;
|
|
||||||
pData->FlipInterval = static_cast<D3DDDI_FLIPINTERVAL_TYPE>(g_flipIntervalOverride);
|
|
||||||
}
|
|
||||||
|
|
||||||
return LOG_RESULT(D3DKMTPresent(pData));
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS APIENTRY queryAdapterInfo(const D3DKMT_QUERYADAPTERINFO* pData)
|
NTSTATUS APIENTRY queryAdapterInfo(const D3DKMT_QUERYADAPTERINFO* pData)
|
||||||
{
|
{
|
||||||
LOG_FUNC("D3DKMTQueryAdapterInfo", pData);
|
LOG_FUNC("D3DKMTQueryAdapterInfo", pData);
|
||||||
@ -283,12 +200,13 @@ namespace
|
|||||||
NTSTATUS APIENTRY setGammaRamp(const D3DKMT_SETGAMMARAMP* pData)
|
NTSTATUS APIENTRY setGammaRamp(const D3DKMT_SETGAMMARAMP* pData)
|
||||||
{
|
{
|
||||||
LOG_FUNC("D3DKMTSetGammaRamp", pData);
|
LOG_FUNC("D3DKMTSetGammaRamp", pData);
|
||||||
HANDLE vsyncThread = CreateThread(nullptr, 0, &waitForVsyncThreadProc, nullptr, 0, nullptr);
|
UINT vsyncCounter = D3dDdi::KernelModeThunks::getVsyncCounter();
|
||||||
SetThreadPriority(vsyncThread, THREAD_PRIORITY_TIME_CRITICAL);
|
|
||||||
DDraw::RealPrimarySurface::flush();
|
DDraw::RealPrimarySurface::flush();
|
||||||
HRESULT result = D3DKMTSetGammaRamp(pData);
|
HRESULT result = D3DKMTSetGammaRamp(pData);
|
||||||
WaitForSingleObject(vsyncThread, INFINITE);
|
if (SUCCEEDED(result))
|
||||||
CloseHandle(vsyncThread);
|
{
|
||||||
|
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCounter + 1);
|
||||||
|
}
|
||||||
return LOG_RESULT(result);
|
return LOG_RESULT(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,49 +240,50 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI waitForVsyncThreadProc(LPVOID /*lpParameter*/)
|
DWORD WINAPI vsyncThreadProc(LPVOID /*lpParameter*/)
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
while (!g_stopVsyncThread)
|
||||||
|
{
|
||||||
|
waitForVerticalBlank();
|
||||||
|
|
||||||
|
{
|
||||||
|
Compat::ScopedSrwLockExclusive lock(g_vsyncCounterSrwLock);
|
||||||
|
++g_vsyncCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
WakeAllConditionVariable(&g_vsyncCounterCv);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waitForVerticalBlank()
|
||||||
|
{
|
||||||
|
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
||||||
|
|
||||||
|
{
|
||||||
|
Compat::ScopedSrwLockShared lock(g_lastOpenAdapterInfoSrwLock);
|
||||||
|
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 || FAILED(D3DKMTWaitForVerticalBlankEvent(&data)))
|
||||||
|
{
|
||||||
|
Sleep(16);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace D3dDdi
|
namespace D3dDdi
|
||||||
{
|
{
|
||||||
namespace KernelModeThunks
|
namespace KernelModeThunks
|
||||||
{
|
{
|
||||||
UINT getLastFlipInterval()
|
|
||||||
{
|
|
||||||
return g_lastFlipInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT getLastDisplayedFrameCount()
|
|
||||||
{
|
|
||||||
auto contextIter = g_contexts.find(g_lastPresentContext);
|
|
||||||
if (contextIter == g_contexts.end())
|
|
||||||
{
|
|
||||||
return g_presentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DKMT_GETDEVICESTATE data = {};
|
|
||||||
data.hDevice = contextIter->second.device;
|
|
||||||
data.StateType = D3DKMT_DEVICESTATE_PRESENT;
|
|
||||||
data.PresentState.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
|
||||||
D3DKMTGetDeviceState(&data);
|
|
||||||
|
|
||||||
if (0 == data.PresentState.PresentStats.PresentCount)
|
|
||||||
{
|
|
||||||
return g_presentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.PresentState.PresentStats.PresentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT getLastSubmittedFrameCount()
|
|
||||||
{
|
|
||||||
return g_presentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT getMonitorRect()
|
RECT getMonitorRect()
|
||||||
{
|
{
|
||||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||||
@ -389,28 +308,23 @@ namespace D3dDdi
|
|||||||
return g_lastOpenAdapterInfo.monitorRect;
|
return g_lastOpenAdapterInfo.monitorRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long getQpcLastVerticalBlank()
|
UINT getVsyncCounter()
|
||||||
{
|
{
|
||||||
return g_qpcLastVerticalBlank;
|
Compat::ScopedSrwLockShared lock(g_vsyncCounterSrwLock);
|
||||||
|
return g_vsyncCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void installHooks(HMODULE origDDrawModule)
|
void installHooks(HMODULE origDDrawModule)
|
||||||
{
|
{
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "CreateDCA", ddrawCreateDcA);
|
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "CreateDCA", ddrawCreateDcA);
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTCloseAdapter", closeAdapter);
|
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTCloseAdapter", closeAdapter);
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTCreateContext", createContext);
|
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTCreateContextVirtual", createContextVirtual);
|
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTCreateDCFromMemory", createDcFromMemory);
|
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTCreateDCFromMemory", createDcFromMemory);
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTDestroyContext", destroyContext);
|
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc);
|
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc);
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTQueryAdapterInfo", queryAdapterInfo);
|
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTQueryAdapterInfo", queryAdapterInfo);
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTPresent", present);
|
|
||||||
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTSetGammaRamp", setGammaRamp);
|
Compat::hookIatFunction(origDDrawModule, "gdi32.dll", "D3DKMTSetGammaRamp", setGammaRamp);
|
||||||
}
|
|
||||||
|
|
||||||
void setFlipIntervalOverride(UINT flipInterval)
|
g_vsyncThread = CreateThread(nullptr, 0, &vsyncThreadProc, nullptr, 0, nullptr);
|
||||||
{
|
SetThreadPriority(g_vsyncThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||||
g_flipIntervalOverride = flipInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDcFormatOverride(UINT format)
|
void setDcFormatOverride(UINT format)
|
||||||
@ -423,30 +337,33 @@ namespace D3dDdi
|
|||||||
g_dcPaletteOverride = enable;
|
g_dcPaletteOverride = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitForVerticalBlank()
|
void stopVsyncThread()
|
||||||
{
|
{
|
||||||
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
g_stopVsyncThread = true;
|
||||||
|
if (WAIT_OBJECT_0 != WaitForSingleObject(g_vsyncThread, 100))
|
||||||
|
{
|
||||||
|
TerminateThread(g_vsyncThread, 0);
|
||||||
|
Compat::Log() << "The vsync thread was terminated forcefully";
|
||||||
|
}
|
||||||
|
g_vsyncThread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_vblankCs);
|
SleepConditionVariableSRW(&g_vsyncCounterCv, &g_vsyncCounterSrwLock, INFINITE,
|
||||||
if (g_lastOpenAdapterInfo.adapter)
|
CONDITION_VARIABLE_LOCKMODE_SHARED);
|
||||||
{
|
waited = true;
|
||||||
data.hAdapter = g_lastOpenAdapterInfo.adapter;
|
|
||||||
data.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
updateGdiAdapterInfo();
|
|
||||||
data.hAdapter = g_gdiAdapterInfo.adapter;
|
|
||||||
data.VidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.hAdapter)
|
|
||||||
{
|
|
||||||
D3DKMTWaitForVerticalBlankEvent(&data);
|
|
||||||
g_qpcLastVerticalBlank = Time::queryPerformanceCounter();
|
|
||||||
}
|
}
|
||||||
|
return waited;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,13 @@ namespace D3dDdi
|
|||||||
{
|
{
|
||||||
namespace KernelModeThunks
|
namespace KernelModeThunks
|
||||||
{
|
{
|
||||||
UINT getLastFlipInterval();
|
|
||||||
UINT getLastDisplayedFrameCount();
|
|
||||||
UINT getLastSubmittedFrameCount();
|
|
||||||
RECT getMonitorRect();
|
RECT getMonitorRect();
|
||||||
long long getQpcLastVerticalBlank();
|
UINT getVsyncCounter();
|
||||||
void installHooks(HMODULE origDDrawModule);
|
void installHooks(HMODULE origDDrawModule);
|
||||||
void setFlipIntervalOverride(UINT flipInterval);
|
|
||||||
void setDcFormatOverride(UINT format);
|
void setDcFormatOverride(UINT format);
|
||||||
void setDcPaletteOverride(bool enable);
|
void setDcPaletteOverride(bool enable);
|
||||||
void waitForVerticalBlank();
|
void stopVsyncThread();
|
||||||
|
void waitForVsync();
|
||||||
|
bool waitForVsyncCounter(UINT counter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ namespace DDraw
|
|||||||
DWORD scanLine = 0;
|
DWORD scanLine = 0;
|
||||||
if (DDERR_VERTICALBLANKINPROGRESS != s_origVtable.GetScanLine(This, &scanLine))
|
if (DDERR_VERTICALBLANKINPROGRESS != s_origVtable.GetScanLine(This, &scanLine))
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
D3dDdi::KernelModeThunks::waitForVsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DDWAITVB_BLOCKEND == dwFlags)
|
if (DDWAITVB_BLOCKEND == dwFlags)
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CompatPtr.h"
|
#include <Common/CompatPtr.h>
|
||||||
#include "Common/Hook.h"
|
#include <Common/Hook.h>
|
||||||
#include "Common/Time.h"
|
#include <Common/Time.h>
|
||||||
#include "Config/Config.h"
|
#include <Config/Config.h>
|
||||||
#include "D3dDdi/Device.h"
|
#include <D3dDdi/Device.h>
|
||||||
#include "D3dDdi/KernelModeThunks.h"
|
#include <D3dDdi/KernelModeThunks.h>
|
||||||
#include "DDraw/DirectDraw.h"
|
#include <DDraw/DirectDraw.h>
|
||||||
#include "DDraw/DirectDrawSurface.h"
|
#include <DDraw/DirectDrawSurface.h>
|
||||||
#include "DDraw/IReleaseNotifier.h"
|
#include <DDraw/IReleaseNotifier.h>
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include <DDraw/RealPrimarySurface.h>
|
||||||
#include "DDraw/ScopedThreadLock.h"
|
#include <DDraw/ScopedThreadLock.h>
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||||
#include "DDraw/Types.h"
|
#include <DDraw/Types.h>
|
||||||
#include "Gdi/AccessGuard.h"
|
#include <Gdi/AccessGuard.h>
|
||||||
#include "Gdi/Caret.h"
|
#include <Gdi/Caret.h>
|
||||||
#include "Gdi/Gdi.h"
|
#include <Gdi/Gdi.h>
|
||||||
#include "Gdi/VirtualScreen.h"
|
#include <Gdi/VirtualScreen.h>
|
||||||
#include "Gdi/Window.h"
|
#include <Gdi/Window.h>
|
||||||
#include "Win32/DisplayMode.h"
|
#include <Win32/DisplayMode.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void onRelease();
|
void onRelease();
|
||||||
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
|
||||||
|
|
||||||
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
||||||
CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter;
|
CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter;
|
||||||
@ -34,16 +34,15 @@ namespace
|
|||||||
|
|
||||||
bool g_stopUpdateThread = false;
|
bool g_stopUpdateThread = false;
|
||||||
HANDLE g_updateThread = nullptr;
|
HANDLE g_updateThread = nullptr;
|
||||||
bool g_isGdiUpdatePending = false;
|
|
||||||
bool g_isFlipPending = false;
|
|
||||||
bool g_isPresentPending = false;
|
|
||||||
bool g_isUpdatePending = false;
|
|
||||||
bool g_isFullScreen = false;
|
bool g_isFullScreen = false;
|
||||||
bool g_waitingForPrimaryUnlock = false;
|
|
||||||
UINT g_flipIntervalDriverOverride = UINT_MAX;
|
|
||||||
UINT g_lastFlipFrameCount = 0;
|
|
||||||
DDraw::Surface* g_lastFlipSurface = nullptr;
|
DDraw::Surface* g_lastFlipSurface = nullptr;
|
||||||
long long g_qpcLastUpdate = 0;
|
|
||||||
|
bool g_isUpdatePending = false;
|
||||||
|
bool g_waitingForPrimaryUnlock = false;
|
||||||
|
std::atomic<long long> g_qpcLastUpdate = 0;
|
||||||
|
long long g_qpcFlipEnd = 0;
|
||||||
|
UINT g_flipEndVsyncCount = 0;
|
||||||
|
UINT g_presentEndVsyncCount = 0;
|
||||||
|
|
||||||
CompatPtr<IDirectDrawSurface7> getBackBuffer();
|
CompatPtr<IDirectDrawSurface7> getBackBuffer();
|
||||||
CompatPtr<IDirectDrawSurface7> getLastSurface();
|
CompatPtr<IDirectDrawSurface7> getLastSurface();
|
||||||
@ -246,13 +245,13 @@ namespace
|
|||||||
return lastSurface;
|
return lastSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT getFlipIntervalFromFlags(DWORD flags)
|
UINT getFlipInterval(DWORD flags)
|
||||||
{
|
{
|
||||||
if (flags & DDFLIP_NOVSYNC)
|
if (flags & DDFLIP_NOVSYNC)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & (DDFLIP_INTERVAL2 | DDFLIP_INTERVAL3 | DDFLIP_INTERVAL4))
|
if (flags & (DDFLIP_INTERVAL2 | DDFLIP_INTERVAL3 | DDFLIP_INTERVAL4))
|
||||||
{
|
{
|
||||||
UINT flipInterval = (flags & (DDFLIP_INTERVAL2 | DDFLIP_INTERVAL3 | DDFLIP_INTERVAL4)) >> 24;
|
UINT flipInterval = (flags & (DDFLIP_INTERVAL2 | DDFLIP_INTERVAL3 | DDFLIP_INTERVAL4)) >> 24;
|
||||||
@ -266,39 +265,14 @@ namespace
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT getFlipInterval(DWORD flags)
|
|
||||||
{
|
|
||||||
if (0 == g_flipIntervalDriverOverride)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT flipInterval = getFlipIntervalFromFlags(flags);
|
|
||||||
if (UINT_MAX != g_flipIntervalDriverOverride)
|
|
||||||
{
|
|
||||||
return max(flipInterval, g_flipIntervalDriverOverride);
|
|
||||||
}
|
|
||||||
return flipInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFlipPending()
|
bool isFlipPending()
|
||||||
{
|
{
|
||||||
if (g_isFlipPending)
|
return static_cast<INT>(D3dDdi::KernelModeThunks::getVsyncCounter() - g_flipEndVsyncCount) < 0;
|
||||||
{
|
|
||||||
g_isFlipPending = static_cast<int>(D3dDdi::KernelModeThunks::getLastDisplayedFrameCount() -
|
|
||||||
g_lastFlipFrameCount) < 0;
|
|
||||||
}
|
|
||||||
return g_isFlipPending;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPresentPending()
|
bool isPresentPending()
|
||||||
{
|
{
|
||||||
if (g_isPresentPending)
|
return static_cast<INT>(D3dDdi::KernelModeThunks::getVsyncCounter() - g_presentEndVsyncCount) < 0;
|
||||||
{
|
|
||||||
g_isPresentPending = static_cast<int>(D3dDdi::KernelModeThunks::getLastDisplayedFrameCount() -
|
|
||||||
D3dDdi::KernelModeThunks::getLastSubmittedFrameCount()) < 0;
|
|
||||||
}
|
|
||||||
return g_isPresentPending;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRelease()
|
void onRelease()
|
||||||
@ -308,8 +282,6 @@ namespace
|
|||||||
g_frontBuffer = nullptr;
|
g_frontBuffer = nullptr;
|
||||||
g_clipper.release();
|
g_clipper.release();
|
||||||
g_isFullScreen = false;
|
g_isFullScreen = false;
|
||||||
g_isFlipPending = false;
|
|
||||||
g_isPresentPending = false;
|
|
||||||
g_waitingForPrimaryUnlock = false;
|
g_waitingForPrimaryUnlock = false;
|
||||||
g_paletteConverter.release();
|
g_paletteConverter.release();
|
||||||
g_surfaceDesc = {};
|
g_surfaceDesc = {};
|
||||||
@ -332,32 +304,16 @@ namespace
|
|||||||
|
|
||||||
g_surfaceDesc = desc;
|
g_surfaceDesc = desc;
|
||||||
g_isFullScreen = isFlippable;
|
g_isFullScreen = isFlippable;
|
||||||
g_flipIntervalDriverOverride = UINT_MAX;
|
|
||||||
g_isFlipPending = false;
|
|
||||||
g_isPresentPending = false;
|
|
||||||
g_isUpdatePending = false;
|
g_isUpdatePending = false;
|
||||||
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(Config::delayedFlipModeTimeout);
|
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(Config::delayedFlipModeTimeout);
|
||||||
|
|
||||||
if (isFlippable)
|
if (isFlippable)
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::setFlipIntervalOverride(UINT_MAX);
|
g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT);
|
||||||
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT | DDFLIP_NOVSYNC);
|
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1;
|
||||||
g_flipIntervalDriverOverride = D3dDdi::KernelModeThunks::getLastFlipInterval();
|
g_presentEndVsyncCount = g_flipEndVsyncCount;
|
||||||
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
D3dDdi::KernelModeThunks::waitForVsyncCounter(g_flipEndVsyncCount);
|
||||||
if (0 == g_flipIntervalDriverOverride)
|
|
||||||
{
|
|
||||||
g_flipIntervalDriverOverride = D3dDdi::KernelModeThunks::getLastFlipInterval();
|
|
||||||
if (1 == g_flipIntervalDriverOverride)
|
|
||||||
{
|
|
||||||
g_flipIntervalDriverOverride = UINT_MAX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
|
||||||
D3dDdi::KernelModeThunks::setFlipIntervalOverride(0);
|
|
||||||
g_lastFlipFrameCount = D3dDdi::KernelModeThunks::getLastSubmittedFrameCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void presentToPrimaryChain(CompatWeakPtr<IDirectDrawSurface7> src)
|
void presentToPrimaryChain(CompatWeakPtr<IDirectDrawSurface7> src)
|
||||||
@ -410,47 +366,19 @@ namespace
|
|||||||
|
|
||||||
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, UINT flipInterval)
|
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, UINT flipInterval)
|
||||||
{
|
{
|
||||||
DDraw::ScopedThreadLock lock;
|
|
||||||
if (flipInterval <= 1 && isPresentPending())
|
|
||||||
{
|
|
||||||
g_isUpdatePending = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
presentToPrimaryChain(src);
|
presentToPrimaryChain(src);
|
||||||
g_isUpdatePending = false;
|
g_isUpdatePending = false;
|
||||||
|
g_waitingForPrimaryUnlock = false;
|
||||||
|
|
||||||
if (!g_isFullScreen)
|
if (g_isFullScreen)
|
||||||
{
|
{
|
||||||
g_isPresentPending = true;
|
g_frontBuffer->Flip(g_frontBuffer, getBackBuffer(), DDFLIP_WAIT);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + max(flipInterval, 1);
|
||||||
if (flipInterval > 1 && isPresentPending())
|
|
||||||
{
|
|
||||||
--flipInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3dDdi::KernelModeThunks::setFlipIntervalOverride(flipInterval);
|
|
||||||
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
|
||||||
|
|
||||||
// Workaround for Windows 8 multimon display glitches when presenting from GDI shared primary surface
|
|
||||||
D3dDdi::KernelModeThunks::setFlipIntervalOverride(UINT_MAX);
|
|
||||||
g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT);
|
|
||||||
D3dDdi::KernelModeThunks::setFlipIntervalOverride(0);
|
|
||||||
|
|
||||||
g_isPresentPending = 0 != flipInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateNowIfNotBusy()
|
void updateNowIfNotBusy()
|
||||||
{
|
{
|
||||||
if (g_isGdiUpdatePending)
|
|
||||||
{
|
|
||||||
g_qpcLastUpdate = Time::queryPerformanceCounter();
|
|
||||||
g_isUpdatePending = true;
|
|
||||||
g_isGdiUpdatePending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||||
RECT emptyRect = {};
|
RECT emptyRect = {};
|
||||||
HRESULT result = primary ? primary->BltFast(primary, 0, 0, primary, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
|
HRESULT result = primary ? primary->BltFast(primary, 0, 0, primary, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
|
||||||
@ -465,16 +393,30 @@ namespace
|
|||||||
|
|
||||||
DWORD WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
DWORD WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
||||||
{
|
{
|
||||||
|
bool skipWaitForVsync = false;
|
||||||
|
|
||||||
while (!g_stopUpdateThread)
|
while (!g_stopUpdateThread)
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
if (!skipWaitForVsync)
|
||||||
if (!g_isFullScreen)
|
|
||||||
{
|
{
|
||||||
g_isPresentPending = false;
|
D3dDdi::KernelModeThunks::waitForVsync();
|
||||||
}
|
}
|
||||||
|
skipWaitForVsync = false;
|
||||||
|
Gdi::Caret::blink();
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
DDraw::RealPrimarySurface::flush();
|
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
|
if (g_isUpdatePending && !isPresentPending())
|
||||||
|
{
|
||||||
|
if (Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcFlipEnd) < 1)
|
||||||
|
{
|
||||||
|
skipWaitForVsync = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateNowIfNotBusy();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -533,62 +475,53 @@ namespace DDraw
|
|||||||
|
|
||||||
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
|
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
|
||||||
{
|
{
|
||||||
DDraw::ScopedThreadLock lock;
|
const DWORD flipInterval = getFlipInterval(flags);
|
||||||
|
if (0 == flipInterval)
|
||||||
|
{
|
||||||
|
g_isUpdatePending = true;
|
||||||
|
return DD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD flipInterval = getFlipInterval(flags);
|
|
||||||
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
|
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
|
||||||
const bool isFlipDelayed = msSinceLastUpdate >= 0 && msSinceLastUpdate <= Config::delayedFlipModeTimeout;
|
const bool isFlipDelayed = msSinceLastUpdate >= 0 && msSinceLastUpdate <= Config::delayedFlipModeTimeout;
|
||||||
if (isFlipDelayed)
|
if (isFlipDelayed)
|
||||||
{
|
{
|
||||||
CompatPtr<IDirectDrawSurface7> prevPrimarySurface(
|
if (!isPresentPending())
|
||||||
surfaceTargetOverride ? surfaceTargetOverride : PrimarySurface::getLastSurface());
|
{
|
||||||
updateNow(prevPrimarySurface, flipInterval);
|
CompatPtr<IDirectDrawSurface7> prevPrimarySurface(
|
||||||
|
surfaceTargetOverride ? surfaceTargetOverride : PrimarySurface::getLastSurface());
|
||||||
|
updateNow(prevPrimarySurface, 0);
|
||||||
|
}
|
||||||
g_isUpdatePending = true;
|
g_isUpdatePending = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
|
|
||||||
if (isFlipEmulated)
|
|
||||||
{
|
|
||||||
surfaceTargetOverride.get()->lpVtbl->Blt(
|
|
||||||
surfaceTargetOverride, nullptr, PrimarySurface::getPrimary(), nullptr, DDBLT_WAIT, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isFlipDelayed)
|
|
||||||
{
|
{
|
||||||
updateNow(PrimarySurface::getPrimary(), flipInterval);
|
updateNow(PrimarySurface::getPrimary(), flipInterval);
|
||||||
}
|
}
|
||||||
|
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + flipInterval;
|
||||||
|
g_presentEndVsyncCount = g_flipEndVsyncCount;
|
||||||
|
|
||||||
if (0 != flipInterval)
|
if (0 != flipInterval)
|
||||||
{
|
|
||||||
g_isFlipPending = true;
|
|
||||||
g_lastFlipFrameCount = D3dDdi::KernelModeThunks::getLastSubmittedFrameCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
g_lastFlipSurface = nullptr;
|
|
||||||
if (g_isFlipPending && !isFlipEmulated)
|
|
||||||
{
|
{
|
||||||
g_lastFlipSurface = Surface::getSurface(
|
g_lastFlipSurface = Surface::getSurface(
|
||||||
surfaceTargetOverride ? *surfaceTargetOverride : *PrimarySurface::getLastSurface());
|
surfaceTargetOverride ? *surfaceTargetOverride : *PrimarySurface::getLastSurface());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_lastFlipSurface = nullptr;
|
||||||
|
}
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::flush()
|
void RealPrimarySurface::flush()
|
||||||
{
|
{
|
||||||
DDraw::ScopedThreadLock lock;
|
DDraw::ScopedThreadLock lock;
|
||||||
Gdi::Caret::blink();
|
if (g_isUpdatePending && !isPresentPending())
|
||||||
if ((g_isUpdatePending || g_isGdiUpdatePending) && !isPresentPending())
|
|
||||||
{
|
{
|
||||||
updateNowIfNotBusy();
|
updateNowIfNotBusy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::gdiUpdate()
|
|
||||||
{
|
|
||||||
g_isGdiUpdatePending = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData)
|
HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData)
|
||||||
{
|
{
|
||||||
DDraw::ScopedThreadLock lock;
|
DDraw::ScopedThreadLock lock;
|
||||||
@ -656,6 +589,12 @@ namespace DDraw
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RealPrimarySurface::scheduleUpdate()
|
||||||
|
{
|
||||||
|
g_qpcLastUpdate = Time::queryPerformanceCounter();
|
||||||
|
g_isUpdatePending = true;
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
|
HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
|
||||||
{
|
{
|
||||||
DDraw::ScopedThreadLock lock;
|
DDraw::ScopedThreadLock lock;
|
||||||
@ -694,11 +633,10 @@ namespace DDraw
|
|||||||
return !isFlipPending();
|
return !isFlipPending();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (isFlipPending())
|
if (D3dDdi::KernelModeThunks::waitForVsyncCounter(g_flipEndVsyncCount))
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
g_qpcFlipEnd = Time::queryPerformanceCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include <ddraw.h>
|
#include <ddraw.h>
|
||||||
|
|
||||||
#include "Common/CompatPtr.h"
|
#include <Common/CompatPtr.h>
|
||||||
#include "Common/CompatRef.h"
|
#include <Common/CompatRef.h>
|
||||||
|
|
||||||
namespace DDraw
|
namespace DDraw
|
||||||
{
|
{
|
||||||
@ -17,7 +17,6 @@ namespace DDraw
|
|||||||
|
|
||||||
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
|
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
|
||||||
static void flush();
|
static void flush();
|
||||||
static void gdiUpdate();
|
|
||||||
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
||||||
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
||||||
static void init();
|
static void init();
|
||||||
@ -26,6 +25,7 @@ namespace DDraw
|
|||||||
static void release();
|
static void release();
|
||||||
static void removeUpdateThread();
|
static void removeUpdateThread();
|
||||||
static HRESULT restore();
|
static HRESULT restore();
|
||||||
|
static void scheduleUpdate();
|
||||||
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
|
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
|
||||||
static void update();
|
static void update();
|
||||||
static bool waitForFlip(Surface* surface, bool wait = true);
|
static bool waitForFlip(Surface* surface, bool wait = true);
|
||||||
|
@ -120,20 +120,22 @@ namespace DDraw
|
|||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
|
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
const bool wait = (dwFlags & DDFLIP_WAIT) || !(dwFlags & DDFLIP_DONOTWAIT) &&
|
if (!waitForFlip(This, dwFlags, DDFLIP_WAIT, DDFLIP_DONOTWAIT))
|
||||||
CompatVtable<IDirectDrawSurface7Vtbl>::s_origVtablePtr == static_cast<void*>(This->lpVtbl);
|
|
||||||
if (!DDraw::RealPrimarySurface::waitForFlip(Surface::getSurface(*This), wait))
|
|
||||||
{
|
{
|
||||||
return DDERR_WASSTILLDRAWING;
|
return DDERR_WASSTILLDRAWING;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto surfaceTargetOverride(CompatPtr<TSurface>::from(lpDDSurfaceTargetOverride));
|
auto surfaceTargetOverride(CompatPtr<TSurface>::from(lpDDSurfaceTargetOverride));
|
||||||
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
|
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
|
||||||
if (isFlipEmulated && !surfaceTargetOverride)
|
if (isFlipEmulated)
|
||||||
{
|
{
|
||||||
TDdsCaps caps = {};
|
if (!surfaceTargetOverride)
|
||||||
caps.dwCaps = DDSCAPS_BACKBUFFER;
|
{
|
||||||
s_origVtable.GetAttachedSurface(This, &caps, &surfaceTargetOverride.getRef());
|
TDdsCaps caps = {};
|
||||||
|
caps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||||
|
s_origVtable.GetAttachedSurface(This, &caps, &surfaceTargetOverride.getRef());
|
||||||
|
}
|
||||||
|
return Blt(This, nullptr, surfaceTargetOverride.get(), nullptr, DDBLT_WAIT, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT result = SurfaceImpl::Flip(This, surfaceTargetOverride, DDFLIP_WAIT);
|
HRESULT result = SurfaceImpl::Flip(This, surfaceTargetOverride, DDFLIP_WAIT);
|
||||||
|
@ -35,6 +35,10 @@ namespace DDraw
|
|||||||
HRESULT SurfaceImpl<TSurface>::BltFast(
|
HRESULT SurfaceImpl<TSurface>::BltFast(
|
||||||
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
|
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
|
||||||
{
|
{
|
||||||
|
if (!waitForFlip(This, dwTrans, DDBLTFAST_WAIT, DDBLTFAST_DONOTWAIT))
|
||||||
|
{
|
||||||
|
return DDERR_WASSTILLDRAWING;
|
||||||
|
}
|
||||||
return s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
return s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,11 +42,11 @@ namespace DDraw
|
|||||||
virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect);
|
virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool waitForFlip(TSurface* This, DWORD flags, DWORD waitFlag, DWORD doNotWaitFlag);
|
||||||
|
|
||||||
static const Vtable<TSurface>& s_origVtable;
|
static const Vtable<TSurface>& s_origVtable;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool waitForFlip(TSurface* This, DWORD flags, DWORD waitFlag, DWORD doNotWaitFlag);
|
|
||||||
|
|
||||||
Surface* m_data;
|
Surface* m_data;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,7 @@
|
|||||||
<ClInclude Include="Common\HResultException.h" />
|
<ClInclude Include="Common\HResultException.h" />
|
||||||
<ClInclude Include="Common\Log.h" />
|
<ClInclude Include="Common\Log.h" />
|
||||||
<ClInclude Include="Common\LogWrapperVisitor.h" />
|
<ClInclude Include="Common\LogWrapperVisitor.h" />
|
||||||
|
<ClInclude Include="Common\ScopedSrwLock.h" />
|
||||||
<ClInclude Include="Common\VtableHookVisitor.h" />
|
<ClInclude Include="Common\VtableHookVisitor.h" />
|
||||||
<ClInclude Include="Common\VtableUpdateVisitor.h" />
|
<ClInclude Include="Common\VtableUpdateVisitor.h" />
|
||||||
<ClInclude Include="Common\VtableVisitor.h" />
|
<ClInclude Include="Common\VtableVisitor.h" />
|
||||||
|
@ -396,6 +396,9 @@
|
|||||||
<ClInclude Include="Win32\MemoryManagement.h">
|
<ClInclude Include="Win32\MemoryManagement.h">
|
||||||
<Filter>Header Files\Win32</Filter>
|
<Filter>Header Files\Win32</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Common\ScopedSrwLock.h">
|
||||||
|
<Filter>Header Files\Common</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Gdi\Gdi.cpp">
|
<ClCompile Include="Gdi\Gdi.cpp">
|
||||||
|
@ -34,7 +34,7 @@ namespace Gdi
|
|||||||
if (ACCESS_WRITE == m_access &&
|
if (ACCESS_WRITE == m_access &&
|
||||||
(!gdiResource || DDraw::PrimarySurface::getFrontResource() == *gdiResource))
|
(!gdiResource || DDraw::PrimarySurface::getFrontResource() == *gdiResource))
|
||||||
{
|
{
|
||||||
DDraw::RealPrimarySurface::gdiUpdate();
|
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ namespace Gdi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DDraw::RealPrimarySurface::gdiUpdate();
|
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
m_presentationWindow = hwnd;
|
m_presentationWindow = hwnd;
|
||||||
SendNotifyMessage(m_presentationWindow, WM_SETPRESENTATIONWINDOWPOS, 0, reinterpret_cast<LPARAM>(m_hwnd));
|
SendNotifyMessage(m_presentationWindow, WM_SETPRESENTATIONWINDOWPOS, 0, reinterpret_cast<LPARAM>(m_hwnd));
|
||||||
DDraw::RealPrimarySurface::gdiUpdate();
|
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,7 +477,7 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
window->m_colorKey = colorKey;
|
window->m_colorKey = colorKey;
|
||||||
window->m_alpha = alpha;
|
window->m_alpha = alpha;
|
||||||
DDraw::RealPrimarySurface::gdiUpdate();
|
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user