diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index 4c710b8..54fd640 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -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{} { } diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 5429ec9..91b662d 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -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(dwData)->szDevice, mi.szDevice)) - { - *reinterpret_cast(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(&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(); diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.h b/DDrawCompat/D3dDdi/KernelModeThunks.h index 063a4a6..4c4eb51 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.h +++ b/DDrawCompat/D3dDdi/KernelModeThunks.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -17,7 +19,7 @@ namespace D3dDdi UINT adapter; UINT vidPnSourceId; LUID luid; - MONITORINFOEXW monitorInfo; + std::wstring deviceName; }; void fixPresent(D3DKMT_PRESENT& data); diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 9788446..51bb76f 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -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) diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 5c2a10e..d244837 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -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::from(&dd)).monitorInfo.rcMonitor; + g_monitorRect = Win32::DisplayMode::getMonitorInfo( + D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::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 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) diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index 6f00b87..640cc6a 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -4,24 +4,60 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include +#include namespace { CompatWeakPtr g_primarySurface; + CompatWeakPtr 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 createGdiPrimarySurface(CompatRef 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::from(&dd)); - g_monitorRect = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::from(&dd)).monitorInfo.rcMonitor; + g_deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::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::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::from(&dd)).detach(); if (desc.ddpfPixelFormat.dwRGBBitCount <= 8) { @@ -190,6 +233,51 @@ namespace DDraw return surface; } + CompatWeakPtr 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 PrimarySurface::getPrimary() { return g_primarySurface; diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h index a2d8aa0..099ad09 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h @@ -22,6 +22,7 @@ namespace DDraw static CompatPtr getBackBuffer(); static CompatPtr getLastSurface(); static RECT getMonitorRect(); + static CompatWeakPtr getGdiPrimary(); static CompatWeakPtr getPrimary(); static HANDLE getFrontResource(); static DWORD getOrigCaps(); diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index 8fc2dc8..04165ef 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -73,7 +73,6 @@ namespace std::wstring getDeviceName(const Char* deviceName); HMONITOR getMonitorFromDc(HDC dc); - MONITORINFO getMonitorInfo(const std::wstring& deviceName); template std::map> 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(&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(&mi)); + return mi; + } + ULONG queryDisplaySettingsUniqueness() { return CALL_ORIG_FUNC(GdiEntry13)(); diff --git a/DDrawCompat/Win32/DisplayMode.h b/DDrawCompat/Win32/DisplayMode.h index 08ad4b8..d472c8f 100644 --- a/DDrawCompat/Win32/DisplayMode.h +++ b/DDrawCompat/Win32/DisplayMode.h @@ -27,6 +27,7 @@ namespace Win32 DWORD getBpp(); EmulatedDisplayMode getEmulatedDisplayMode(); + MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName); ULONG queryDisplaySettingsUniqueness(); void installHooks();