diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 1838225..310552a 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include + #include #include #include @@ -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 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; diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.h b/DDrawCompat/D3dDdi/KernelModeThunks.h index bb57b15..fcd2747 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.h +++ b/DDrawCompat/D3dDdi/KernelModeThunks.h @@ -23,7 +23,6 @@ namespace D3dDdi void installHooks(); void setDcFormatOverride(UINT format); void setDcPaletteOverride(PALETTEENTRY* palette); - void waitForVsync(); bool waitForVsyncCounter(UINT counter); } } diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index d78d8a7..861b3c1 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -172,23 +172,8 @@ namespace template 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 diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 9d56fc9..ab5389d 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -214,7 +214,7 @@ namespace { if (!skipWaitForVsync) { - D3dDdi::KernelModeThunks::waitForVsync(); + D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1); } skipWaitForVsync = false; Sleep(1);