diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 7e67006..db18871 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -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); diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 04f8dba..76a6ddf 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -42,6 +42,7 @@ namespace const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200; void onRelease(); + void updatePresentationWindow(); CompatWeakPtr 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 getBackBuffer(); CompatPtr 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 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 surface) { auto primary(DDraw::PrimarySurface::getPrimary()); diff --git a/DDrawCompat/DDraw/RealPrimarySurface.h b/DDrawCompat/DDraw/RealPrimarySurface.h index 312ede9..c053dec 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.h +++ b/DDrawCompat/DDraw/RealPrimarySurface.h @@ -16,7 +16,6 @@ namespace DDraw static void destroyDefaultPrimary(); static HRESULT flip(CompatPtr 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 surface); static void waitForFlipFpsLimit(); }; diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 96ba62e..c982d76 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -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)); } diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index 3b6daa4..3eef34f 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -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;