mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Handle display scaling while primary surface is lost
This commit is contained in:
parent
9bca0a6ba0
commit
524f708a7f
@ -37,7 +37,7 @@ namespace D3dDdi
|
||||
, m_runtimeVersion(data.Version)
|
||||
, m_driverVersion(data.DriverVersion)
|
||||
, m_luid(KernelModeThunks::getLastOpenAdapterInfo().luid)
|
||||
, m_deviceName(KernelModeThunks::getLastOpenAdapterInfo().monitorInfo.szDevice)
|
||||
, m_deviceName(KernelModeThunks::getLastOpenAdapterInfo().deviceName)
|
||||
, m_repository{}
|
||||
{
|
||||
}
|
||||
|
@ -139,27 +139,13 @@ namespace
|
||||
return LOG_RESULT(CreateDCA(pwszDriver, pwszDevice, pszPort, pdm));
|
||||
}
|
||||
|
||||
BOOL CALLBACK findMonitorInfo(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
|
||||
{
|
||||
MONITORINFOEXW mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi);
|
||||
if (0 == wcscmp(reinterpret_cast<MONITORINFOEXW*>(dwData)->szDevice, mi.szDevice))
|
||||
{
|
||||
*reinterpret_cast<MONITORINFOEXW*>(dwData) = mi;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
D3dDdi::KernelModeThunks::AdapterInfo getAdapterInfo(const std::string& deviceName, const D3DKMT_OPENADAPTERFROMHDC& data)
|
||||
{
|
||||
D3dDdi::KernelModeThunks::AdapterInfo adapterInfo = {};
|
||||
adapterInfo.adapter = data.hAdapter;
|
||||
adapterInfo.vidPnSourceId = data.VidPnSourceId;
|
||||
adapterInfo.luid = data.AdapterLuid;
|
||||
wcscpy_s(adapterInfo.monitorInfo.szDevice, std::wstring(deviceName.begin(), deviceName.end()).c_str());
|
||||
EnumDisplayMonitors(nullptr, nullptr, findMonitorInfo, reinterpret_cast<LPARAM>(&adapterInfo.monitorInfo));
|
||||
adapterInfo.deviceName = std::wstring(deviceName.begin(), deviceName.end());
|
||||
return adapterInfo;
|
||||
}
|
||||
|
||||
@ -266,8 +252,6 @@ namespace
|
||||
LOG_FUNC("D3DKMTSetGammaRamp", pData);
|
||||
NTSTATUS result = 0;
|
||||
UINT vsyncCounter = D3dDdi::KernelModeThunks::getVsyncCounter();
|
||||
DDraw::RealPrimarySurface::setUpdateReady();
|
||||
DDraw::RealPrimarySurface::flush();
|
||||
if (g_isExclusiveFullscreen || D3DDDI_GAMMARAMP_RGB256x3x16 != pData->Type || !pData->pGammaRampRgb256x3x16)
|
||||
{
|
||||
D3dDdi::ShaderBlitter::resetGammaRamp();
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <winternl.h>
|
||||
#include <d3dkmthk.h>
|
||||
@ -17,7 +19,7 @@ namespace D3dDdi
|
||||
UINT adapter;
|
||||
UINT vidPnSourceId;
|
||||
LUID luid;
|
||||
MONITORINFOEXW monitorInfo;
|
||||
std::wstring deviceName;
|
||||
};
|
||||
|
||||
void fixPresent(D3DKMT_PRESENT& data);
|
||||
|
@ -273,7 +273,8 @@ namespace D3dDdi
|
||||
|
||||
const SurfaceRepository::Surface& SurfaceRepository::getTempTexture(DWORD width, DWORD height, const DDPIXELFORMAT& pf)
|
||||
{
|
||||
return getTempSurface(m_textures[pf], width, height, pf, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
return getTempSurface(m_textures[pf], width, height, pf,
|
||||
(pf.dwRGBBitCount > 8 ? DDSCAPS_TEXTURE : 0) | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
|
||||
bool SurfaceRepository::isLost(Surface& surface)
|
||||
|
@ -372,18 +372,14 @@ namespace
|
||||
}
|
||||
|
||||
bool isFullscreen = false;
|
||||
if (SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer)))
|
||||
if (SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer)) && DDraw::PrimarySurface::getPrimary())
|
||||
{
|
||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||
if (primary && SUCCEEDED(primary->IsLost(primary)))
|
||||
HWND foregroundWindow = GetForegroundWindow();
|
||||
if (foregroundWindow)
|
||||
{
|
||||
HWND foregroundWindow = GetForegroundWindow();
|
||||
if (foregroundWindow)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(foregroundWindow, &pid);
|
||||
isFullscreen = GetCurrentProcessId() == pid && Gdi::Window::hasFullscreenWindow();
|
||||
}
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(foregroundWindow, &pid);
|
||||
isFullscreen = GetCurrentProcessId() == pid && Gdi::Window::hasFullscreenWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,7 +428,8 @@ namespace DDraw
|
||||
{
|
||||
LOG_FUNC("RealPrimarySurface::create", &dd);
|
||||
DDraw::ScopedThreadLock lock;
|
||||
g_monitorRect = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).monitorInfo.rcMonitor;
|
||||
g_monitorRect = Win32::DisplayMode::getMonitorInfo(
|
||||
D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName).rcMonitor;
|
||||
|
||||
DDSURFACEDESC desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
@ -593,7 +590,21 @@ namespace DDraw
|
||||
}
|
||||
updatePresentationWindowPos();
|
||||
|
||||
auto src(g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : DDraw::PrimarySurface::getPrimary());
|
||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||
CompatWeakPtr<IDirectDrawSurface7> src;
|
||||
if (g_isDelayedFlipPending)
|
||||
{
|
||||
src = g_lastFlipSurface->getDDS();
|
||||
}
|
||||
else if (primary && SUCCEEDED(primary->IsLost(primary)))
|
||||
{
|
||||
src = primary;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = DDraw::PrimarySurface::getGdiPrimary();
|
||||
}
|
||||
|
||||
RECT emptyRect = {};
|
||||
HRESULT result = src ? src->BltFast(src, 0, 0, src, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
|
||||
if (DDERR_SURFACEBUSY == result || DDERR_LOCKEDSURFACES == result)
|
||||
|
@ -4,24 +4,60 @@
|
||||
#include <D3dDdi/Device.h>
|
||||
#include <D3dDdi/KernelModeThunks.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <D3dDdi/SurfaceRepository.h>
|
||||
#include <DDraw/DirectDraw.h>
|
||||
#include <DDraw/DirectDrawSurface.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurfaceImpl.h>
|
||||
#include <DDraw/Surfaces/TagSurface.h>
|
||||
#include <Gdi/Palette.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
|
||||
CompatWeakPtr<IDirectDrawSurface7> g_gdiPrimarySurface;
|
||||
D3dDdi::Device* g_device = nullptr;
|
||||
HANDLE g_gdiResourceHandle = nullptr;
|
||||
HANDLE g_frontResource = nullptr;
|
||||
DWORD g_origCaps = 0;
|
||||
HWND g_deviceWindow = nullptr;
|
||||
HPALETTE g_palette = nullptr;
|
||||
std::wstring g_deviceName;
|
||||
RECT g_monitorRect = {};
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> createGdiPrimarySurface(CompatRef<IDirectDraw> dd)
|
||||
{
|
||||
LOG_FUNC("PrimarySurface::createGdiPrimarySurface", &dd);
|
||||
|
||||
auto ddLcl = DDraw::DirectDraw::getInt(dd.get()).lpLcl;
|
||||
auto tagSurface = DDraw::TagSurface::get(ddLcl);
|
||||
if (!tagSurface)
|
||||
{
|
||||
return LOG_RESULT(nullptr);
|
||||
}
|
||||
|
||||
auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*tagSurface->getDDS());
|
||||
if (!resource)
|
||||
{
|
||||
return LOG_RESULT(nullptr);
|
||||
}
|
||||
|
||||
auto device = D3dDdi::Device::findDeviceByResource(resource);
|
||||
if (!device)
|
||||
{
|
||||
return LOG_RESULT(nullptr);
|
||||
}
|
||||
|
||||
auto& repo = D3dDdi::SurfaceRepository::get(device->getAdapter());
|
||||
D3dDdi::SurfaceRepository::Surface surface = {};
|
||||
repo.getSurface(surface, 1, 1, DDraw::DirectDraw::getRgbPixelFormat(32), DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY);
|
||||
|
||||
LOG_RESULT(surface.surface.get());
|
||||
return surface.surface;
|
||||
}
|
||||
}
|
||||
|
||||
namespace DDraw
|
||||
@ -34,6 +70,7 @@ namespace DDraw
|
||||
g_gdiResourceHandle = nullptr;
|
||||
g_frontResource = nullptr;
|
||||
g_primarySurface = nullptr;
|
||||
g_gdiPrimarySurface.release();
|
||||
g_origCaps = 0;
|
||||
g_deviceWindow = nullptr;
|
||||
if (g_palette)
|
||||
@ -41,6 +78,7 @@ namespace DDraw
|
||||
DeleteObject(g_palette);
|
||||
g_palette = nullptr;
|
||||
}
|
||||
g_deviceName.clear();
|
||||
g_monitorRect = {};
|
||||
s_palette = nullptr;
|
||||
|
||||
@ -59,13 +97,16 @@ namespace DDraw
|
||||
}
|
||||
|
||||
const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd));
|
||||
g_monitorRect = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).monitorInfo.rcMonitor;
|
||||
g_deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName;
|
||||
g_monitorRect = Win32::DisplayMode::getMonitorInfo(g_deviceName).rcMonitor;
|
||||
g_monitorRect.right = g_monitorRect.left + dm.dwWidth;
|
||||
g_monitorRect.bottom = g_monitorRect.top + dm.dwHeight;
|
||||
|
||||
HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd));
|
||||
if (FAILED(result))
|
||||
{
|
||||
g_deviceName.clear();
|
||||
g_monitorRect = {};
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
@ -85,6 +126,7 @@ namespace DDraw
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_INFO << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result);
|
||||
g_deviceName.clear();
|
||||
g_monitorRect = {};
|
||||
RealPrimarySurface::release();
|
||||
return LOG_RESULT(result);
|
||||
@ -92,6 +134,7 @@ namespace DDraw
|
||||
|
||||
g_origCaps = origCaps;
|
||||
g_deviceWindow = *DDraw::DirectDraw::getDeviceWindowPtr(dd.get());
|
||||
g_gdiPrimarySurface = createGdiPrimarySurface(*CompatPtr<IDirectDraw>::from(&dd)).detach();
|
||||
|
||||
if (desc.ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
@ -190,6 +233,51 @@ namespace DDraw
|
||||
return surface;
|
||||
}
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getGdiPrimary()
|
||||
{
|
||||
LOG_FUNC("PrimarySurface::getGdiPrimary");
|
||||
if (!g_primarySurface || !g_gdiPrimarySurface)
|
||||
{
|
||||
return LOG_RESULT(nullptr);
|
||||
}
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
g_primarySurface->GetSurfaceDesc(g_primarySurface, &desc);
|
||||
|
||||
g_monitorRect = Win32::DisplayMode::getMonitorInfo(g_deviceName).rcMonitor;
|
||||
g_monitorRect.right = g_monitorRect.left + desc.dwWidth;
|
||||
g_monitorRect.bottom = g_monitorRect.top + desc.dwHeight;
|
||||
|
||||
desc = Gdi::VirtualScreen::getSurfaceDesc(g_monitorRect);
|
||||
|
||||
DDSURFACEDESC2 prevDesc = {};
|
||||
prevDesc.dwSize = sizeof(prevDesc);
|
||||
g_gdiPrimarySurface->Lock(g_gdiPrimarySurface, nullptr, &prevDesc, DDLOCK_WAIT, nullptr);
|
||||
g_gdiPrimarySurface->Unlock(g_gdiPrimarySurface, nullptr);
|
||||
|
||||
if (desc.dwWidth != prevDesc.dwWidth ||
|
||||
desc.dwHeight != prevDesc.dwHeight ||
|
||||
desc.lPitch != prevDesc.lPitch ||
|
||||
desc.lpSurface != prevDesc.lpSurface ||
|
||||
0 != memcmp(&desc.ddpfPixelFormat, &prevDesc.ddpfPixelFormat, sizeof(desc.ddpfPixelFormat)))
|
||||
{
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
|
||||
if (FAILED(g_gdiPrimarySurface->SetSurfaceDesc(g_gdiPrimarySurface, &desc, 0)))
|
||||
{
|
||||
return LOG_RESULT(nullptr);
|
||||
}
|
||||
|
||||
if (desc.dwWidth != prevDesc.dwWidth ||
|
||||
desc.dwHeight != prevDesc.dwHeight)
|
||||
{
|
||||
DDraw::RealPrimarySurface::restore();
|
||||
}
|
||||
}
|
||||
|
||||
return LOG_RESULT(g_gdiPrimarySurface.get());
|
||||
}
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
|
||||
{
|
||||
return g_primarySurface;
|
||||
|
@ -22,6 +22,7 @@ namespace DDraw
|
||||
static CompatPtr<IDirectDrawSurface7> getBackBuffer();
|
||||
static CompatPtr<IDirectDrawSurface7> getLastSurface();
|
||||
static RECT getMonitorRect();
|
||||
static CompatWeakPtr<IDirectDrawSurface7> getGdiPrimary();
|
||||
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
|
||||
static HANDLE getFrontResource();
|
||||
static DWORD getOrigCaps();
|
||||
|
@ -73,7 +73,6 @@ namespace
|
||||
std::wstring getDeviceName(const Char* deviceName);
|
||||
|
||||
HMONITOR getMonitorFromDc(HDC dc);
|
||||
MONITORINFO getMonitorInfo(const std::wstring& deviceName);
|
||||
|
||||
template <typename Char>
|
||||
std::map<SIZE, std::set<DWORD>> getSupportedDisplayModeMap(const Char* deviceName, DWORD flags);
|
||||
@ -224,7 +223,7 @@ namespace
|
||||
g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency;
|
||||
|
||||
g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName);
|
||||
g_emulatedDisplayMode.rect = getMonitorInfo(g_emulatedDisplayMode.deviceName).rcMonitor;
|
||||
g_emulatedDisplayMode.rect = Win32::DisplayMode::getMonitorInfo(g_emulatedDisplayMode.deviceName).rcMonitor;
|
||||
g_emulatedDisplayMode.rect.right = g_emulatedDisplayMode.rect.left + emulatedResolution.cx;
|
||||
g_emulatedDisplayMode.rect.bottom = g_emulatedDisplayMode.rect.top + emulatedResolution.cy;
|
||||
g_emulatedDisplayMode.diff.cx = emulatedResolution.cx - currDevMode.dmPelsWidth;
|
||||
@ -542,14 +541,6 @@ namespace
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MONITORINFO getMonitorInfo(const std::wstring& deviceName)
|
||||
{
|
||||
MONITORINFOEXW mi = {};
|
||||
wcscpy_s(mi.szDevice, deviceName.c_str());
|
||||
EnumDisplayMonitors(nullptr, nullptr, &getMonitorInfoEnum, reinterpret_cast<LPARAM>(&mi));
|
||||
return mi;
|
||||
}
|
||||
|
||||
BOOL WINAPI getMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi)
|
||||
{
|
||||
LOG_FUNC("GetMonitorInfoA", hMonitor, lpmi);
|
||||
@ -739,6 +730,14 @@ namespace Win32
|
||||
return g_emulatedDisplayMode;
|
||||
}
|
||||
|
||||
MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName)
|
||||
{
|
||||
MONITORINFOEXW mi = {};
|
||||
wcscpy_s(mi.szDevice, deviceName.c_str());
|
||||
EnumDisplayMonitors(nullptr, nullptr, &getMonitorInfoEnum, reinterpret_cast<LPARAM>(&mi));
|
||||
return mi;
|
||||
}
|
||||
|
||||
ULONG queryDisplaySettingsUniqueness()
|
||||
{
|
||||
return CALL_ORIG_FUNC(GdiEntry13)();
|
||||
|
@ -27,6 +27,7 @@ namespace Win32
|
||||
|
||||
DWORD getBpp();
|
||||
EmulatedDisplayMode getEmulatedDisplayMode();
|
||||
MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName);
|
||||
ULONG queryDisplaySettingsUniqueness();
|
||||
|
||||
void installHooks();
|
||||
|
Loading…
x
Reference in New Issue
Block a user