1
0
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:
narzoul 2021-11-21 16:32:55 +01:00
parent 175d7e7c53
commit 664c573d91
4 changed files with 78 additions and 46 deletions

View File

@ -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;

View File

@ -23,7 +23,6 @@ namespace D3dDdi
void installHooks();
void setDcFormatOverride(UINT format);
void setDcPaletteOverride(PALETTEENTRY* palette);
void waitForVsync();
bool waitForVsyncCounter(UINT counter);
}
}

View File

@ -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>

View File

@ -214,7 +214,7 @@ namespace
{
if (!skipWaitForVsync)
{
D3dDdi::KernelModeThunks::waitForVsync();
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
}
skipWaitForVsync = false;
Sleep(1);