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

Handle DisplayResolution scaling in windowed mode

This commit is contained in:
narzoul 2022-06-06 21:52:39 +02:00
parent fc16184256
commit 5ce5ea0668
7 changed files with 151 additions and 31 deletions

View File

@ -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 = ▭
}
}
}

View File

@ -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<LONG>(si.Width), static_cast<LONG>(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<LONG>(si.Width), static_cast<LONG>(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);

View File

@ -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();

View File

@ -25,6 +25,7 @@
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/Palette.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
#include <Gdi/WinProc.h>
@ -62,6 +63,7 @@ namespace
HWND g_devicePresentationWindow = nullptr;
HWND g_deviceWindow = nullptr;
HWND* g_deviceWindowPtr = nullptr;
HWND g_presentationWindow = nullptr;
CompatPtr<IDirectDrawSurface7> getBackBuffer();
CompatPtr<IDirectDrawSurface7> 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<IDirectDrawSurface7> 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,

View File

@ -18,6 +18,7 @@ namespace DDraw
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();
static CompatWeakPtr<IDirectDrawSurface7> getSurface();

View File

@ -8,6 +8,7 @@
#include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
@ -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<IDirectDrawClipper> 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())

View File

@ -19,6 +19,7 @@ namespace Gdi
HWND getPresentationWindow(HWND hwnd);
std::vector<LayeredWindow> getVisibleLayeredWindows();
bool hasFullscreenWindow();
bool isTopLevelWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd);