diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 2b78086..5429ec9 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -387,20 +387,19 @@ namespace D3dDdi void fixPresent(D3DKMT_PRESENT& data) { static RECT rect = {}; - if (DDraw::RealPrimarySurface::isFullscreen()) + HWND devicePresentationWindow = DDraw::RealPrimarySurface::getDevicePresentationWindow(); + HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); + if (devicePresentationWindow && devicePresentationWindow == data.hWindow || + presentationWindow && presentationWindow == data.hWindow) { - HWND devicePresentationWindow = DDraw::RealPrimarySurface::getDevicePresentationWindow(); - if (devicePresentationWindow && devicePresentationWindow == data.hWindow) + rect = DDraw::RealPrimarySurface::getMonitorRect(); + OffsetRect(&rect, -rect.left, -rect.top); + data.SrcRect = rect; + data.DstRect.right = data.DstRect.left + rect.right; + data.DstRect.bottom = data.DstRect.top + rect.bottom; + if (1 == data.SubRectCnt) { - rect = DDraw::RealPrimarySurface::getMonitorRect(); - OffsetRect(&rect, -rect.left, -rect.top); - data.SrcRect = rect; - data.DstRect.right = data.DstRect.left + rect.right; - data.DstRect.bottom = data.DstRect.top + rect.bottom; - if (1 == data.SubRectCnt) - { - data.pSrcSubRects = ▭ - } + data.pSrcSubRects = ▭ } } } diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 0a5584f..540fd30 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -131,16 +131,7 @@ namespace D3dDdi if (m_origData.Flags.MatchGdiPrimary) { - g_presentationRect = calculatePresentationRect(); - auto& si = m_origData.pSurfList[0]; - RECT primaryRect = { 0, 0, static_cast(si.Width), static_cast(si.Height) }; - - Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect()); - if (!EqualRect(&g_presentationRect, &primaryRect)) - { - Gdi::Cursor::setEmulated(true); - } - Gdi::VirtualScreen::setFullscreenMode(true); + setFullscreenMode(true); } fixResourceData(); @@ -180,9 +171,7 @@ namespace D3dDdi { if (m_origData.Flags.MatchGdiPrimary) { - Gdi::VirtualScreen::setFullscreenMode(false); - Gdi::Cursor::setEmulated(false); - Gdi::Cursor::setMonitorClipRect({}); + setFullscreenMode(false); } if (m_msaaSurface.surface || m_msaaResolvedSurface.surface || m_lockRefSurface.surface) @@ -1036,6 +1025,7 @@ namespace D3dDdi HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource* srcResource) { + LOG_FUNC("Resource::presentationBlt", data, *srcResource); if (srcResource->m_lockResource) { if (srcResource->m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate && @@ -1066,7 +1056,7 @@ namespace D3dDdi srcResource = repo.getTempTexture(srcWidth, srcHeight, getPixelFormat(srcResource->m_fixedData.Format)).resource; if (!srcResource) { - return E_OUTOFMEMORY; + return LOG_RESULT(E_OUTOFMEMORY); } copySubResourceRegion(*srcResource, 0, data.SrcRect, data.hSrcResource, data.SrcSubResourceIndex, data.SrcRect); } @@ -1103,7 +1093,7 @@ namespace D3dDdi if (!rtSurface.resource) { - return S_OK; + return LOG_RESULT(S_OK); } const LONG dstWidth = data.DstRect.right - data.DstRect.left; @@ -1147,7 +1137,7 @@ namespace D3dDdi } clearRectExterior(data.DstSubResourceIndex, data.DstRect); - return S_OK; + return LOG_RESULT(S_OK); } void Resource::presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect) @@ -1244,6 +1234,35 @@ namespace D3dDdi } } + void Resource::setFullscreenMode(bool isFullscreen) + { + if (!IsRectEmpty(&g_presentationRect) == isFullscreen) + { + return; + } + + if (isFullscreen) + { + g_presentationRect = calculatePresentationRect(); + auto& si = m_origData.pSurfList[0]; + RECT primaryRect = { 0, 0, static_cast(si.Width), static_cast(si.Height) }; + + Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect()); + if (!EqualRect(&g_presentationRect, &primaryRect)) + { + Gdi::Cursor::setEmulated(true); + } + Gdi::VirtualScreen::setFullscreenMode(m_origData.Flags.MatchGdiPrimary); + } + else + { + g_presentationRect = {}; + Gdi::VirtualScreen::setFullscreenMode(false); + Gdi::Cursor::setEmulated(false); + Gdi::Cursor::setMonitorClipRect({}); + } + } + HRESULT Resource::shaderBlt(D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource) { LOG_FUNC("Resource::shaderBlt", data, srcResource); diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index ee16abe..70d164f 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -49,6 +49,7 @@ namespace D3dDdi void scaleRect(RECT& rect); void setAsGdiResource(bool isGdiResource); void setAsPrimary(); + void setFullscreenMode(bool isFullscreen); HRESULT unlock(const D3DDDIARG_UNLOCK& data); void updateConfig(); diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index c5dde47..5e97de1 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,7 @@ namespace HWND g_devicePresentationWindow = nullptr; HWND g_deviceWindow = nullptr; HWND* g_deviceWindowPtr = nullptr; + HWND g_presentationWindow = nullptr; CompatPtr getBackBuffer(); CompatPtr getLastSurface(); @@ -195,6 +197,16 @@ namespace { LOG_FUNC("RealPrimarySurface::onRelease"); + if (g_presentationWindow) + { + auto resource = D3dDdi::Device::findResource( + DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer)); + resource->setFullscreenMode(false); + + Gdi::GuiThread::destroyWindow(g_presentationWindow); + g_presentationWindow = nullptr; + } + g_frontBuffer = nullptr; g_lastFlipSurface = nullptr; g_windowedBackBuffer.release(); @@ -296,6 +308,44 @@ namespace g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1; } + void updatePresentationWindowPos() + { + if (!g_presentationWindow) + { + return; + } + + bool isFullscreen = false; + if (SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer))) + { + 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); + + Gdi::GuiThread::execute([&]() + { + if (isFullscreen) + { + 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)) + { + ShowWindow(g_presentationWindow, SW_HIDE); + } + }); + } + unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/) { int msUntilUpdateReady = 0; @@ -311,6 +361,7 @@ namespace } DDraw::ScopedThreadLock lock; + updatePresentationWindowPos(); msUntilUpdateReady = DDraw::RealPrimarySurface::flush(); } } @@ -363,9 +414,19 @@ namespace DDraw g_frontBuffer->SetPrivateData(g_frontBuffer, IID_IReleaseNotifier, &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER); - g_deviceWindowPtr = DDraw::DirectDraw::getDeviceWindowPtr(dd.get()); + g_deviceWindowPtr = (0 != desc.dwBackBufferCount) ? DDraw::DirectDraw::getDeviceWindowPtr(dd.get()) : nullptr; g_deviceWindow = g_deviceWindowPtr ? *g_deviceWindowPtr : nullptr; - g_devicePresentationWindow = Gdi::Window::getPresentationWindow(g_deviceWindow); + 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(); @@ -484,6 +545,11 @@ namespace DDraw return g_monitorRect; } + HWND RealPrimarySurface::getPresentationWindow() + { + return g_presentationWindow; + } + CompatWeakPtr RealPrimarySurface::getSurface() { return g_frontBuffer; @@ -495,6 +561,10 @@ namespace DDraw { return g_devicePresentationWindow; } + if (g_presentationWindow && IsWindowVisible(g_presentationWindow)) + { + return g_presentationWindow; + } return HWND_TOPMOST; } @@ -576,7 +646,7 @@ namespace DDraw Gdi::GuiThread::execute([&]() { - if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow)) + 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, diff --git a/DDrawCompat/DDraw/RealPrimarySurface.h b/DDrawCompat/DDraw/RealPrimarySurface.h index 9ddd7a2..9469bd8 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.h +++ b/DDrawCompat/DDraw/RealPrimarySurface.h @@ -18,6 +18,7 @@ namespace DDraw static HRESULT flip(CompatPtr surfaceTargetOverride, DWORD flags); static int flush(); static HWND getDevicePresentationWindow(); + static HWND getPresentationWindow(); static HRESULT getGammaRamp(DDGAMMARAMP* rampData); static RECT getMonitorRect(); static CompatWeakPtr getSurface(); diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index ac7d210..b855d2d 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -419,6 +420,26 @@ namespace Gdi return layeredWindows; } + bool hasFullscreenWindow() + { + D3dDdi::ScopedCriticalSection lock; + RECT mr = DDraw::PrimarySurface::getMonitorRect(); + for (auto& window : g_windows) + { + if (!window.second.isLayered && + window.second.windowRect.left <= mr.left && + window.second.windowRect.top <= mr.top && + window.second.windowRect.right >= mr.right && + window.second.windowRect.bottom >= mr.bottom && + IsWindowVisible(window.first) && + !IsIconic(window.first)) + { + return true; + } + } + return false; + } + bool isTopLevelWindow(HWND hwnd) { return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT); @@ -492,6 +513,14 @@ namespace Gdi CompatRef clipper) { D3dDdi::ScopedCriticalSection lock; + auto presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); + if (presentationWindow && IsWindowVisible(presentationWindow)) + { + clipper->SetHWnd(&clipper, 0, presentationWindow); + dst->Blt(&dst, nullptr, &src, nullptr, DDBLT_WAIT, nullptr); + return; + } + for (auto window : g_windowZOrder) { if (window->presentationWindow && !window->visibleRegion.isEmpty()) diff --git a/DDrawCompat/Gdi/Window.h b/DDrawCompat/Gdi/Window.h index aeaabfd..47c6402 100644 --- a/DDrawCompat/Gdi/Window.h +++ b/DDrawCompat/Gdi/Window.h @@ -19,6 +19,7 @@ namespace Gdi HWND getPresentationWindow(HWND hwnd); std::vector getVisibleLayeredWindows(); + bool hasFullscreenWindow(); bool isTopLevelWindow(HWND hwnd); void onStyleChanged(HWND hwnd, WPARAM wParam); void onSyncPaint(HWND hwnd);