mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed performance issues caused by D3DKMTWaitForVerticalBlankEvent
See issue #104 and #120.
This commit is contained in:
parent
175d7e7c53
commit
664c573d91
@ -1,6 +1,9 @@
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#include <Common/Log.h>
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/ScopedSrwLock.h>
|
||||
@ -22,19 +25,21 @@ namespace
|
||||
PALETTEENTRY* g_dcPaletteOverride = nullptr;
|
||||
D3dDdi::KernelModeThunks::AdapterInfo g_gdiAdapterInfo = {};
|
||||
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
|
||||
Compat::SrwLock g_lastOpenAdapterInfoSrwLock;
|
||||
Compat::SrwLock g_adapterInfoSrwLock;
|
||||
std::string g_lastDDrawDeviceName;
|
||||
|
||||
std::atomic<long long> g_qpcLastVsync = 0;
|
||||
long long g_qpcLastVsync = 0;
|
||||
UINT g_vsyncCounter = 0;
|
||||
CONDITION_VARIABLE g_vsyncCounterCv = CONDITION_VARIABLE_INIT;
|
||||
Compat::SrwLock g_vsyncCounterSrwLock;
|
||||
|
||||
void getVidPnSource(D3DKMT_HANDLE& adapter, UINT& vidPnSourceId);
|
||||
void updateGdiAdapterInfo();
|
||||
void waitForVerticalBlank();
|
||||
|
||||
NTSTATUS APIENTRY closeAdapter(const D3DKMT_CLOSEADAPTER* pData)
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
||||
Compat::ScopedSrwLockExclusive lock(g_adapterInfoSrwLock);
|
||||
if (pData && pData->hAdapter == g_lastOpenAdapterInfo.adapter)
|
||||
{
|
||||
g_lastOpenAdapterInfo = {};
|
||||
@ -139,18 +144,60 @@ namespace
|
||||
return adapterInfo;
|
||||
}
|
||||
|
||||
int getScanLine()
|
||||
{
|
||||
D3DKMT_GETSCANLINE data = {};
|
||||
getVidPnSource(data.hAdapter, data.VidPnSourceId);
|
||||
if (!data.hAdapter || FAILED(D3DKMTGetScanLine(&data)) || data.InVerticalBlank)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return data.ScanLine;
|
||||
}
|
||||
|
||||
void getVidPnSource(D3DKMT_HANDLE& adapter, UINT& vidPnSourceId)
|
||||
{
|
||||
{
|
||||
Compat::ScopedSrwLockShared lock(g_adapterInfoSrwLock);
|
||||
if (g_lastOpenAdapterInfo.adapter)
|
||||
{
|
||||
adapter = g_lastOpenAdapterInfo.adapter;
|
||||
vidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Compat::ScopedSrwLockExclusive lock(g_adapterInfoSrwLock);
|
||||
updateGdiAdapterInfo();
|
||||
adapter = g_gdiAdapterInfo.adapter;
|
||||
vidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
|
||||
}
|
||||
|
||||
NTSTATUS APIENTRY openAdapterFromHdc(D3DKMT_OPENADAPTERFROMHDC* pData)
|
||||
{
|
||||
LOG_FUNC("D3DKMTOpenAdapterFromHdc", pData);
|
||||
NTSTATUS result = D3DKMTOpenAdapterFromHdc(pData);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
||||
Compat::ScopedSrwLockExclusive lock(g_adapterInfoSrwLock);
|
||||
g_lastOpenAdapterInfo = getAdapterInfo(g_lastDDrawDeviceName, *pData);
|
||||
}
|
||||
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 queryAdapterInfo(const D3DKMT_QUERYADAPTERINFO* pData)
|
||||
{
|
||||
LOG_FUNC("D3DKMTQueryAdapterInfo", pData);
|
||||
@ -230,10 +277,10 @@ namespace
|
||||
while (true)
|
||||
{
|
||||
waitForVerticalBlank();
|
||||
g_qpcLastVsync = Time::queryPerformanceCounter();
|
||||
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive lock(g_vsyncCounterSrwLock);
|
||||
g_qpcLastVsync = Time::queryPerformanceCounter();
|
||||
++g_vsyncCounter;
|
||||
}
|
||||
|
||||
@ -244,25 +291,30 @@ namespace
|
||||
|
||||
void waitForVerticalBlank()
|
||||
{
|
||||
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
||||
|
||||
if (IsWindows8OrGreater())
|
||||
{
|
||||
Compat::ScopedSrwLockShared lock(g_lastOpenAdapterInfoSrwLock);
|
||||
data.hAdapter = g_lastOpenAdapterInfo.adapter;
|
||||
data.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.hAdapter)
|
||||
{
|
||||
updateGdiAdapterInfo();
|
||||
data.hAdapter = g_gdiAdapterInfo.adapter;
|
||||
data.VidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
|
||||
}
|
||||
|
||||
if (!data.hAdapter || FAILED(D3DKMTWaitForVerticalBlankEvent(&data)))
|
||||
{
|
||||
Sleep(16);
|
||||
}
|
||||
pollForVerticalBlank();
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,12 +332,13 @@ namespace D3dDdi
|
||||
|
||||
AdapterInfo getLastOpenAdapterInfo()
|
||||
{
|
||||
Compat::ScopedSrwLockShared srwLock(g_lastOpenAdapterInfoSrwLock);
|
||||
Compat::ScopedSrwLockShared srwLock(g_adapterInfoSrwLock);
|
||||
return g_lastOpenAdapterInfo;
|
||||
}
|
||||
|
||||
long long getQpcLastVsync()
|
||||
{
|
||||
Compat::ScopedSrwLockShared lock(g_vsyncCounterSrwLock);
|
||||
return g_qpcLastVsync;
|
||||
}
|
||||
|
||||
@ -317,11 +370,6 @@ namespace D3dDdi
|
||||
g_dcPaletteOverride = palette;
|
||||
}
|
||||
|
||||
void waitForVsync()
|
||||
{
|
||||
waitForVsyncCounter(getVsyncCounter() + 1);
|
||||
}
|
||||
|
||||
bool waitForVsyncCounter(UINT counter)
|
||||
{
|
||||
bool waited = false;
|
||||
|
@ -23,7 +23,6 @@ namespace D3dDdi
|
||||
void installHooks();
|
||||
void setDcFormatOverride(UINT format);
|
||||
void setDcPaletteOverride(PALETTEENTRY* palette);
|
||||
void waitForVsync();
|
||||
bool waitForVsyncCounter(UINT counter);
|
||||
}
|
||||
}
|
||||
|
@ -172,23 +172,8 @@ namespace
|
||||
template <typename TDirectDraw>
|
||||
HRESULT STDMETHODCALLTYPE WaitForVerticalBlank(TDirectDraw* This, DWORD dwFlags, HANDLE hEvent)
|
||||
{
|
||||
if (!This || (DDWAITVB_BLOCKBEGIN != dwFlags && DDWAITVB_BLOCKEND != dwFlags))
|
||||
{
|
||||
return getOrigVtable(This).WaitForVerticalBlank(This, dwFlags, hEvent);
|
||||
}
|
||||
|
||||
DWORD scanLine = 0;
|
||||
if (DDERR_VERTICALBLANKINPROGRESS != getOrigVtable(This).GetScanLine(This, &scanLine))
|
||||
{
|
||||
D3dDdi::KernelModeThunks::waitForVsync();
|
||||
}
|
||||
|
||||
if (DDWAITVB_BLOCKEND == dwFlags)
|
||||
{
|
||||
while (DDERR_VERTICALBLANKINPROGRESS == getOrigVtable(This).GetScanLine(This, &scanLine));
|
||||
}
|
||||
|
||||
return DD_OK;
|
||||
DDraw::RealPrimarySurface::flush();
|
||||
return getOrigVtable(This).WaitForVerticalBlank(This, dwFlags, hEvent);
|
||||
}
|
||||
|
||||
template <typename Vtable>
|
||||
|
@ -214,7 +214,7 @@ namespace
|
||||
{
|
||||
if (!skipWaitForVsync)
|
||||
{
|
||||
D3dDdi::KernelModeThunks::waitForVsync();
|
||||
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
|
||||
}
|
||||
skipWaitForVsync = false;
|
||||
Sleep(1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user