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

Reduced flickering when changing display modes in scaled fullscreen mode

This commit is contained in:
narzoul 2023-07-15 10:47:38 +02:00
parent 4a40d97fe9
commit 4c4051a844
5 changed files with 91 additions and 93 deletions

View File

@ -371,10 +371,8 @@ namespace D3dDdi
void fixPresent(D3DKMT_PRESENT& data)
{
static RECT rect = {};
HWND devicePresentationWindow = DDraw::RealPrimarySurface::getDevicePresentationWindow();
HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow();
if (devicePresentationWindow && devicePresentationWindow == data.hWindow ||
presentationWindow && presentationWindow == data.hWindow)
if (presentationWindow && presentationWindow == data.hWindow)
{
rect = DDraw::RealPrimarySurface::getMonitorRect();
OffsetRect(&rect, -rect.left, -rect.top);

View File

@ -42,6 +42,7 @@ namespace
const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200;
void onRelease();
void updatePresentationWindow();
CompatWeakPtr<IDirectDrawSurface7> g_defaultPrimary;
@ -69,10 +70,10 @@ namespace
UINT g_flipEndVsyncCount = 0;
UINT g_presentEndVsyncCount = 0;
HWND g_devicePresentationWindow = nullptr;
HWND g_deviceWindow = nullptr;
HWND* g_deviceWindowPtr = nullptr;
HWND g_presentationWindow = nullptr;
long long g_qpcUpdatePresentationWindow = 0;
CompatPtr<IDirectDrawSurface7> getBackBuffer();
CompatPtr<IDirectDrawSurface7> getLastSurface();
@ -98,6 +99,7 @@ namespace
bbResource->presentationBlt(blt, srcResource);
}
updatePresentationWindow();
Gdi::Window::present(*g_frontBuffer, *g_windowedBackBuffer, *g_clipper);
return;
}
@ -258,20 +260,31 @@ namespace
return 1;
}
bool isProcessActive()
{
const HWND foregroundWindow = GetForegroundWindow();
if (foregroundWindow)
{
DWORD pid = 0;
GetWindowThreadProcessId(foregroundWindow, &pid);
return GetCurrentProcessId() == pid;
}
return false;
}
void onRelease()
{
LOG_FUNC("RealPrimarySurface::onRelease");
if (g_presentationWindow)
if (g_windowedBackBuffer)
{
auto resource = D3dDdi::Device::findResource(
DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer));
resource->setFullscreenMode(false);
Gdi::GuiThread::destroyWindow(g_presentationWindow);
g_presentationWindow = nullptr;
}
DDraw::RealPrimarySurface::schedulePresentationWindowUpdate();
g_defaultPrimary = nullptr;
g_frontBuffer = nullptr;
g_lastFlipSurface = nullptr;
@ -281,8 +294,6 @@ namespace
g_surfaceDesc = {};
g_tagSurface = nullptr;
DDraw::RealPrimarySurface::updateDevicePresentationWindowPos();
g_devicePresentationWindow = nullptr;
g_deviceWindow = nullptr;
g_deviceWindowPtr = nullptr;
g_monitorRect = {};
@ -316,6 +327,8 @@ namespace
D3dDdi::Device::setGdiResourceHandle(gdiResource);
}
updatePresentationWindow();
Compat::ScopedCriticalSection lock(g_presentCs);
g_isOverlayUpdatePending = false;
g_isUpdatePending = false;
@ -378,49 +391,46 @@ namespace
presentToPrimaryChain(src);
if (g_isFullscreen && g_devicePresentationWindow)
if (g_isFullscreen)
{
*g_deviceWindowPtr = g_devicePresentationWindow;
updatePresentationWindow();
*g_deviceWindowPtr = g_presentationWindow;
g_frontBuffer->Flip(g_frontBuffer, getBackBuffer(), DDFLIP_WAIT);
*g_deviceWindowPtr = g_deviceWindow;
}
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1;
}
void updatePresentationWindowPos()
void updatePresentationWindow()
{
if (!g_presentationWindow)
{
return;
}
LOG_FUNC("RealPrimarySurface::updatePresentationWindow");
const bool isFullscreen = isProcessActive() && (g_isFullscreen ||
g_frontBuffer && DDraw::PrimarySurface::getPrimary() && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer)) &&
Gdi::Window::hasFullscreenWindow());
bool isFullscreen = false;
if (SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer)) && DDraw::PrimarySurface::getPrimary())
if (g_windowedBackBuffer)
{
HWND foregroundWindow = GetForegroundWindow();
if (foregroundWindow)
{
DWORD pid = 0;
GetWindowThreadProcessId(foregroundWindow, &pid);
isFullscreen = GetCurrentProcessId() == pid && Gdi::Window::hasFullscreenWindow();
}
auto resource = D3dDdi::Device::findResource(
DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer));
resource->setFullscreenMode(isFullscreen);
}
auto resource = D3dDdi::Device::findResource(
DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer));
resource->setFullscreenMode(isFullscreen);
Gdi::GuiThread::execute([&]()
{
if (isFullscreen)
{
if (!g_presentationWindow)
{
g_presentationWindow = Gdi::PresentationWindow::create(nullptr);
}
CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top,
g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top,
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW);
}
else if (IsWindowVisible(g_presentationWindow))
else if (g_presentationWindow)
{
ShowWindow(g_presentationWindow, SW_HIDE);
DestroyWindow(g_presentationWindow);
g_presentationWindow = nullptr;
}
});
}
@ -513,21 +523,8 @@ namespace DDraw
g_deviceWindowPtr = (0 != desc.dwBackBufferCount) ? DDraw::DirectDraw::getDeviceWindowPtr(dd.get()) : nullptr;
g_deviceWindow = g_deviceWindowPtr ? *g_deviceWindowPtr : nullptr;
g_devicePresentationWindow = g_deviceWindow ? Gdi::Window::getPresentationWindow(g_deviceWindow) : nullptr;
if (0 == desc.dwBackBufferCount)
{
auto mr = DDraw::PrimarySurface::getMonitorRect();
if (!EqualRect(&mr, &g_monitorRect))
{
g_presentationWindow = Gdi::PresentationWindow::create(nullptr);
updatePresentationWindowPos();
}
}
onRestore();
updateDevicePresentationWindowPos();
return DD_OK;
}
@ -598,6 +595,21 @@ namespace DDraw
lastOverlayCheckVsyncCount = vsyncCount;
}
bool isPresentationWindowUpdateNeeded = false;
{
Compat::ScopedCriticalSection lock(g_presentCs);
isPresentationWindowUpdateNeeded =
0 != g_qpcUpdatePresentationWindow && Time::queryPerformanceCounter() - g_qpcUpdatePresentationWindow >= 0 ||
g_presentationWindow && !isProcessActive();
}
if (isPresentationWindowUpdateNeeded)
{
g_qpcUpdatePresentationWindow = 0;
updatePresentationWindow();
}
{
Compat::ScopedCriticalSection lock(g_presentCs);
if (!g_isUpdateReady)
@ -639,7 +651,6 @@ namespace DDraw
{
restore();
}
updatePresentationWindowPos();
auto primary(DDraw::PrimarySurface::getPrimary());
CompatWeakPtr<IDirectDrawSurface7> src;
@ -667,11 +678,6 @@ namespace DDraw
return 0;
}
HWND RealPrimarySurface::getDevicePresentationWindow()
{
return g_devicePresentationWindow;
}
HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData)
{
DDraw::ScopedThreadLock lock;
@ -701,15 +707,7 @@ namespace DDraw
HWND RealPrimarySurface::getTopmost()
{
if (g_isFullscreen && g_devicePresentationWindow)
{
return g_devicePresentationWindow;
}
if (g_presentationWindow && IsWindowVisible(g_presentationWindow))
{
return g_presentationWindow;
}
return HWND_TOPMOST;
return g_presentationWindow ? g_presentationWindow : HWND_TOPMOST;
}
void RealPrimarySurface::init()
@ -774,6 +772,12 @@ namespace DDraw
g_isUpdateReady = false;
}
void RealPrimarySurface::schedulePresentationWindowUpdate()
{
Compat::ScopedCriticalSection lock(g_presentCs);
g_qpcUpdatePresentationWindow = Time::queryPerformanceCounter() + Time::g_qpcFrequency / 5;
}
HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
{
DDraw::ScopedThreadLock lock;
@ -786,6 +790,18 @@ namespace DDraw
return gammaControl->SetGammaRamp(gammaControl, 0, rampData);
}
void RealPrimarySurface::setPresentationWindowTopmost()
{
Gdi::GuiThread::execute([&]()
{
if (g_presentationWindow)
{
CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER);
}
});
}
void RealPrimarySurface::setUpdateReady()
{
Compat::ScopedCriticalSection lock(g_presentCs);
@ -796,28 +812,6 @@ namespace DDraw
}
}
void RealPrimarySurface::updateDevicePresentationWindowPos()
{
if (!g_devicePresentationWindow)
{
return;
}
Gdi::GuiThread::execute([&]()
{
if (IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow))
{
CALL_ORIG_FUNC(SetWindowPos)(g_devicePresentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top,
g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top,
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW);
}
else
{
Gdi::Window::updatePresentationWindowPos(g_devicePresentationWindow, g_deviceWindow);
}
});
}
bool RealPrimarySurface::waitForFlip(CompatWeakPtr<IDirectDrawSurface7> surface)
{
auto primary(DDraw::PrimarySurface::getPrimary());

View File

@ -16,7 +16,6 @@ namespace DDraw
static void destroyDefaultPrimary();
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static int flush();
static HWND getDevicePresentationWindow();
static HWND getPresentationWindow();
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
static RECT getMonitorRect();
@ -29,9 +28,10 @@ namespace DDraw
static HRESULT restore();
static void scheduleOverlayUpdate();
static void scheduleUpdate();
static void schedulePresentationWindowUpdate();
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
static void setPresentationWindowTopmost();
static void setUpdateReady();
static void updateDevicePresentationWindowPos();
static bool waitForFlip(CompatWeakPtr<IDirectDrawSurface7> surface);
static void waitForFlipFpsLimit();
};

View File

@ -431,6 +431,7 @@ namespace
if (Gdi::Window::isTopLevelWindow(hwnd))
{
DDraw::RealPrimarySurface::setPresentationWindowTopmost();
Gdi::Window::updateAll();
}
@ -578,6 +579,7 @@ namespace
BOOL WINAPI setWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags)
{
LOG_FUNC("SetWindowPos", hWnd, hWndInsertAfter, X, Y, cx, cy, Compat::hex(uFlags));
if (uFlags & SWP_NOSENDCHANGING)
{
WINDOWPOS wp = {};
@ -591,6 +593,18 @@ namespace
onWindowPosChanging(hWnd, wp);
uFlags = wp.flags;
}
if ((uFlags & SWP_NOACTIVATE) && !(uFlags && SWP_NOZORDER) &&
(HWND_TOP == hWndInsertAfter || HWND_TOPMOST == hWndInsertAfter) &&
(GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST))
{
const HWND topmost = DDraw::RealPrimarySurface::getTopmost();
if (topmost != HWND_TOPMOST)
{
hWndInsertAfter = topmost;
}
}
return LOG_RESULT(CALL_ORIG_FUNC(SetWindowPos)(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags));
}

View File

@ -350,15 +350,7 @@ namespace
Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, it->second.windowRegion);
}
const HWND devicePresentationWindow = DDraw::RealPrimarySurface::getDevicePresentationWindow();
if (DDraw::RealPrimarySurface::isFullscreen() && devicePresentationWindow == it->second.presentationWindow)
{
DDraw::RealPrimarySurface::updateDevicePresentationWindowPos();
}
else
{
Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd);
}
Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd);
}
}
return TRUE;