1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Fixed stuttering fullscreen presentation

See issue #298.
This commit is contained in:
narzoul 2024-06-22 15:37:44 +02:00
parent 29a2b9246b
commit f2ea02b960

View File

@ -45,8 +45,6 @@
namespace namespace
{ {
const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200;
void onRelease(); void onRelease();
void updatePresentationParams(); void updatePresentationParams();
@ -62,15 +60,11 @@ namespace
DDraw::TagSurface* g_tagSurface = nullptr; DDraw::TagSurface* g_tagSurface = nullptr;
Compat::CriticalSection g_presentCs; Compat::CriticalSection g_presentCs;
bool g_isDelayedFlipPending = false;
bool g_isOverlayUpdatePending = false; bool g_isOverlayUpdatePending = false;
bool g_isUpdatePending = false; bool g_isUpdatePending = false;
bool g_isUpdateReady = false; bool g_isUpdateReady = false;
DWORD g_lastUpdateThreadId = 0;
long long g_qpcLastUpdate = 0;
long long g_qpcUpdateStart = 0; long long g_qpcUpdateStart = 0;
long long g_qpcDelayedFlipEnd = 0;
UINT g_flipEndVsyncCount = 0; UINT g_flipEndVsyncCount = 0;
UINT g_presentEndVsyncCount = 0; UINT g_presentEndVsyncCount = 0;
@ -179,8 +173,7 @@ namespace
g_isOverlayUpdatePending = false; g_isOverlayUpdatePending = false;
g_isUpdatePending = false; g_isUpdatePending = false;
g_isUpdateReady = false; g_isUpdateReady = false;
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(DELAYED_FLIP_MODE_TIMEOUT_MS); g_qpcUpdateStart = Time::queryPerformanceCounter();
g_qpcUpdateStart = g_qpcLastUpdate;
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter(); g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
g_flipEndVsyncCount = g_presentEndVsyncCount; g_flipEndVsyncCount = g_presentEndVsyncCount;
} }
@ -519,23 +512,10 @@ namespace DDraw
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags) HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
{ {
const DWORD flipInterval = getFlipInterval(flags); const DWORD flipInterval = getFlipInterval(flags);
if (0 == flipInterval || PrimarySurface::waitForIdle();
Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate) < DELAYED_FLIP_MODE_TIMEOUT_MS)
{ Compat::ScopedCriticalSection lock(g_presentCs);
PrimarySurface::waitForIdle(); scheduleUpdate();
Compat::ScopedCriticalSection lock(g_presentCs);
g_isDelayedFlipPending = true;
g_isOverlayUpdatePending = false;
g_isUpdatePending = false;
g_isUpdateReady = false;
g_lastUpdateThreadId = GetCurrentThreadId();
}
else
{
D3dDdi::KernelModeThunks::waitForVsyncCounter(g_presentEndVsyncCount);
g_isUpdateReady = true;
flush();
}
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + flipInterval; g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + flipInterval;
if (0 != flipInterval) if (0 != flipInterval)
@ -548,7 +528,6 @@ namespace DDraw
g_lastFlipSurface = nullptr; g_lastFlipSurface = nullptr;
} }
g_qpcDelayedFlipEnd = Time::queryPerformanceCounter();
return DD_OK; return DD_OK;
} }
@ -570,7 +549,6 @@ namespace DDraw
if (statsWindow && statsWindow->isVisible()) if (statsWindow && statsWindow->isVisible())
{ {
statsWindow->updateStats(); statsWindow->updateStats();
g_qpcLastUpdate = Time::queryPerformanceCounter();
} }
Overlay::Steam::flush(); Overlay::Steam::flush();
lastOverlayCheckVsyncCount = vsyncCount; lastOverlayCheckVsyncCount = vsyncCount;
@ -591,19 +569,8 @@ namespace DDraw
} }
g_isUpdateReady = true; g_isUpdateReady = true;
} }
else if (g_isDelayedFlipPending)
{
auto msSinceDelayedFlipEnd = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcDelayedFlipEnd);
if (msSinceDelayedFlipEnd < 3)
{
return 3 - static_cast<int>(msSinceDelayedFlipEnd);
}
g_isDelayedFlipPending = false;
g_isUpdateReady = true;
}
else if (g_isOverlayUpdatePending) else if (g_isOverlayUpdatePending)
{ {
g_qpcLastUpdate = Time::queryPerformanceCounter();
g_isUpdateReady = true; g_isUpdateReady = true;
isOverlayOnly = true; isOverlayOnly = true;
} }
@ -620,7 +587,7 @@ namespace DDraw
if (primary && SUCCEEDED(primary->IsLost(primary)) && if (primary && SUCCEEDED(primary->IsLost(primary)) &&
g_frontBuffer && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer))) g_frontBuffer && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer)))
{ {
src = g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : primary; src = primary;
} }
updateNow(src, isOverlayOnly); updateNow(src, isOverlayOnly);
@ -719,13 +686,10 @@ namespace DDraw
void RealPrimarySurface::scheduleUpdate() void RealPrimarySurface::scheduleUpdate()
{ {
Compat::ScopedCriticalSection lock(g_presentCs); Compat::ScopedCriticalSection lock(g_presentCs);
g_qpcLastUpdate = Time::queryPerformanceCounter();
if (!g_isUpdatePending) if (!g_isUpdatePending)
{ {
g_qpcUpdateStart = g_qpcLastUpdate; g_qpcUpdateStart = Time::queryPerformanceCounter();
g_isUpdatePending = true; g_isUpdatePending = true;
g_isDelayedFlipPending = false;
g_lastUpdateThreadId = GetCurrentThreadId();
} }
g_isUpdateReady = false; g_isUpdateReady = false;
} }
@ -758,10 +722,9 @@ namespace DDraw
void RealPrimarySurface::setUpdateReady() void RealPrimarySurface::setUpdateReady()
{ {
Compat::ScopedCriticalSection lock(g_presentCs); Compat::ScopedCriticalSection lock(g_presentCs);
if ((g_isUpdatePending || g_isDelayedFlipPending) && GetCurrentThreadId() == g_lastUpdateThreadId) if (g_isUpdatePending)
{ {
g_isUpdateReady = true; g_isUpdateReady = true;
g_isDelayedFlipPending = false;
} }
} }
@ -774,13 +737,19 @@ namespace DDraw
return true; return true;
} }
auto qpcStart = Time::queryPerformanceCounter();
auto vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter(); auto vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
while (static_cast<int>(vsyncCount - g_flipEndVsyncCount) < 0) while (static_cast<int>(vsyncCount - g_flipEndVsyncCount) < 0)
{ {
flush();
++vsyncCount; ++vsyncCount;
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCount); D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCount);
g_qpcDelayedFlipEnd = Time::queryPerformanceCounter(); }
Compat::ScopedCriticalSection lock(g_presentCs);
auto qpcEnd = Time::queryPerformanceCounter();
if (g_isUpdatePending)
{
g_qpcUpdateStart += qpcEnd - qpcStart;
} }
return true; return true;
} }
@ -793,17 +762,15 @@ namespace DDraw
if (qpcNow - qpcWaitEnd >= 0) if (qpcNow - qpcWaitEnd >= 0)
{ {
g_qpcPrevWaitEnd = qpcNow; g_qpcPrevWaitEnd = qpcNow;
g_qpcDelayedFlipEnd = qpcNow;
return; return;
} }
g_qpcPrevWaitEnd = qpcWaitEnd; g_qpcPrevWaitEnd = qpcWaitEnd;
g_qpcDelayedFlipEnd = qpcWaitEnd;
Compat::ScopedThreadPriority prio(THREAD_PRIORITY_TIME_CRITICAL); Compat::ScopedThreadPriority prio(THREAD_PRIORITY_TIME_CRITICAL);
auto qpcStart = Time::queryPerformanceCounter();
while (Time::qpcToMs(qpcWaitEnd - qpcNow) > 0) while (Time::qpcToMs(qpcWaitEnd - qpcNow) > 0)
{ {
Time::waitForNextTick(); Time::waitForNextTick();
flush();
qpcNow = Time::queryPerformanceCounter(); qpcNow = Time::queryPerformanceCounter();
} }
@ -811,6 +778,12 @@ namespace DDraw
{ {
qpcNow = Time::queryPerformanceCounter(); qpcNow = Time::queryPerformanceCounter();
} }
g_qpcDelayedFlipEnd = Time::queryPerformanceCounter();
Compat::ScopedCriticalSection lock(g_presentCs);
auto qpcEnd = Time::queryPerformanceCounter();
if (g_isUpdatePending)
{
g_qpcUpdateStart += qpcEnd - qpcStart;
}
} }
} }