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 <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <VersionHelpers.h>
|
||||||
|
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
#include <Common/Hook.h>
|
#include <Common/Hook.h>
|
||||||
#include <Common/ScopedSrwLock.h>
|
#include <Common/ScopedSrwLock.h>
|
||||||
@ -22,19 +25,21 @@ namespace
|
|||||||
PALETTEENTRY* g_dcPaletteOverride = nullptr;
|
PALETTEENTRY* g_dcPaletteOverride = nullptr;
|
||||||
D3dDdi::KernelModeThunks::AdapterInfo g_gdiAdapterInfo = {};
|
D3dDdi::KernelModeThunks::AdapterInfo g_gdiAdapterInfo = {};
|
||||||
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
|
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
|
||||||
Compat::SrwLock g_lastOpenAdapterInfoSrwLock;
|
Compat::SrwLock g_adapterInfoSrwLock;
|
||||||
std::string g_lastDDrawDeviceName;
|
std::string g_lastDDrawDeviceName;
|
||||||
|
|
||||||
std::atomic<long long> g_qpcLastVsync = 0;
|
long long g_qpcLastVsync = 0;
|
||||||
UINT g_vsyncCounter = 0;
|
UINT g_vsyncCounter = 0;
|
||||||
CONDITION_VARIABLE g_vsyncCounterCv = CONDITION_VARIABLE_INIT;
|
CONDITION_VARIABLE g_vsyncCounterCv = CONDITION_VARIABLE_INIT;
|
||||||
Compat::SrwLock g_vsyncCounterSrwLock;
|
Compat::SrwLock g_vsyncCounterSrwLock;
|
||||||
|
|
||||||
|
void getVidPnSource(D3DKMT_HANDLE& adapter, UINT& vidPnSourceId);
|
||||||
|
void updateGdiAdapterInfo();
|
||||||
void waitForVerticalBlank();
|
void waitForVerticalBlank();
|
||||||
|
|
||||||
NTSTATUS APIENTRY closeAdapter(const D3DKMT_CLOSEADAPTER* pData)
|
NTSTATUS APIENTRY closeAdapter(const D3DKMT_CLOSEADAPTER* pData)
|
||||||
{
|
{
|
||||||
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
Compat::ScopedSrwLockExclusive lock(g_adapterInfoSrwLock);
|
||||||
if (pData && pData->hAdapter == g_lastOpenAdapterInfo.adapter)
|
if (pData && pData->hAdapter == g_lastOpenAdapterInfo.adapter)
|
||||||
{
|
{
|
||||||
g_lastOpenAdapterInfo = {};
|
g_lastOpenAdapterInfo = {};
|
||||||
@ -139,18 +144,60 @@ namespace
|
|||||||
return adapterInfo;
|
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)
|
NTSTATUS APIENTRY openAdapterFromHdc(D3DKMT_OPENADAPTERFROMHDC* pData)
|
||||||
{
|
{
|
||||||
LOG_FUNC("D3DKMTOpenAdapterFromHdc", pData);
|
LOG_FUNC("D3DKMTOpenAdapterFromHdc", pData);
|
||||||
NTSTATUS result = D3DKMTOpenAdapterFromHdc(pData);
|
NTSTATUS result = D3DKMTOpenAdapterFromHdc(pData);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
Compat::ScopedSrwLockExclusive lock(g_lastOpenAdapterInfoSrwLock);
|
Compat::ScopedSrwLockExclusive lock(g_adapterInfoSrwLock);
|
||||||
g_lastOpenAdapterInfo = getAdapterInfo(g_lastDDrawDeviceName, *pData);
|
g_lastOpenAdapterInfo = getAdapterInfo(g_lastDDrawDeviceName, *pData);
|
||||||
}
|
}
|
||||||
return LOG_RESULT(result);
|
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)
|
NTSTATUS APIENTRY queryAdapterInfo(const D3DKMT_QUERYADAPTERINFO* pData)
|
||||||
{
|
{
|
||||||
LOG_FUNC("D3DKMTQueryAdapterInfo", pData);
|
LOG_FUNC("D3DKMTQueryAdapterInfo", pData);
|
||||||
@ -230,10 +277,10 @@ namespace
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
waitForVerticalBlank();
|
waitForVerticalBlank();
|
||||||
g_qpcLastVsync = Time::queryPerformanceCounter();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Compat::ScopedSrwLockExclusive lock(g_vsyncCounterSrwLock);
|
Compat::ScopedSrwLockExclusive lock(g_vsyncCounterSrwLock);
|
||||||
|
g_qpcLastVsync = Time::queryPerformanceCounter();
|
||||||
++g_vsyncCounter;
|
++g_vsyncCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,25 +291,30 @@ namespace
|
|||||||
|
|
||||||
void waitForVerticalBlank()
|
void waitForVerticalBlank()
|
||||||
{
|
{
|
||||||
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
if (IsWindows8OrGreater())
|
||||||
|
|
||||||
{
|
{
|
||||||
Compat::ScopedSrwLockShared lock(g_lastOpenAdapterInfoSrwLock);
|
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
||||||
data.hAdapter = g_lastOpenAdapterInfo.adapter;
|
|
||||||
data.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
{
|
||||||
|
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)
|
pollForVerticalBlank();
|
||||||
{
|
|
||||||
updateGdiAdapterInfo();
|
|
||||||
data.hAdapter = g_gdiAdapterInfo.adapter;
|
|
||||||
data.VidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.hAdapter || FAILED(D3DKMTWaitForVerticalBlankEvent(&data)))
|
|
||||||
{
|
|
||||||
Sleep(16);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,12 +332,13 @@ namespace D3dDdi
|
|||||||
|
|
||||||
AdapterInfo getLastOpenAdapterInfo()
|
AdapterInfo getLastOpenAdapterInfo()
|
||||||
{
|
{
|
||||||
Compat::ScopedSrwLockShared srwLock(g_lastOpenAdapterInfoSrwLock);
|
Compat::ScopedSrwLockShared srwLock(g_adapterInfoSrwLock);
|
||||||
return g_lastOpenAdapterInfo;
|
return g_lastOpenAdapterInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long getQpcLastVsync()
|
long long getQpcLastVsync()
|
||||||
{
|
{
|
||||||
|
Compat::ScopedSrwLockShared lock(g_vsyncCounterSrwLock);
|
||||||
return g_qpcLastVsync;
|
return g_qpcLastVsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,11 +370,6 @@ namespace D3dDdi
|
|||||||
g_dcPaletteOverride = palette;
|
g_dcPaletteOverride = palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitForVsync()
|
|
||||||
{
|
|
||||||
waitForVsyncCounter(getVsyncCounter() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool waitForVsyncCounter(UINT counter)
|
bool waitForVsyncCounter(UINT counter)
|
||||||
{
|
{
|
||||||
bool waited = false;
|
bool waited = false;
|
||||||
|
@ -23,7 +23,6 @@ namespace D3dDdi
|
|||||||
void installHooks();
|
void installHooks();
|
||||||
void setDcFormatOverride(UINT format);
|
void setDcFormatOverride(UINT format);
|
||||||
void setDcPaletteOverride(PALETTEENTRY* palette);
|
void setDcPaletteOverride(PALETTEENTRY* palette);
|
||||||
void waitForVsync();
|
|
||||||
bool waitForVsyncCounter(UINT counter);
|
bool waitForVsyncCounter(UINT counter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,23 +172,8 @@ namespace
|
|||||||
template <typename TDirectDraw>
|
template <typename TDirectDraw>
|
||||||
HRESULT STDMETHODCALLTYPE WaitForVerticalBlank(TDirectDraw* This, DWORD dwFlags, HANDLE hEvent)
|
HRESULT STDMETHODCALLTYPE WaitForVerticalBlank(TDirectDraw* This, DWORD dwFlags, HANDLE hEvent)
|
||||||
{
|
{
|
||||||
if (!This || (DDWAITVB_BLOCKBEGIN != dwFlags && DDWAITVB_BLOCKEND != dwFlags))
|
DDraw::RealPrimarySurface::flush();
|
||||||
{
|
return getOrigVtable(This).WaitForVerticalBlank(This, dwFlags, hEvent);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Vtable>
|
template <typename Vtable>
|
||||||
|
@ -214,7 +214,7 @@ namespace
|
|||||||
{
|
{
|
||||||
if (!skipWaitForVsync)
|
if (!skipWaitForVsync)
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::waitForVsync();
|
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
|
||||||
}
|
}
|
||||||
skipWaitForVsync = false;
|
skipWaitForVsync = false;
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user