diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index 49775d3..b5d8f27 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -65,7 +65,7 @@ namespace D3dDdi { } - Int2 Adapter::getAspectRatio(SIZE appRes, SIZE displayRes) const + SIZE Adapter::getAspectRatio(SIZE appRes, SIZE displayRes) const { SIZE ar = Config::displayAspectRatio.get(); if (Config::Settings::DisplayAspectRatio::APP == ar) @@ -79,7 +79,7 @@ namespace D3dDdi return ar; } - Int2 Adapter::getAspectRatio() const + SIZE Adapter::getAspectRatio() const { return getAspectRatio({}, {}); } @@ -330,14 +330,14 @@ namespace D3dDdi targetResolution *= abs(multiplier); - const Int2 ar = getAspectRatio(appRes, displayRes); - if (targetResolution.y * ar.x / ar.y <= targetResolution.x) + const SIZE ar = getAspectRatio(appRes, displayRes); + if (targetResolution.y * ar.cx / ar.cy <= targetResolution.x) { - targetResolution.x = targetResolution.y * ar.x / ar.y; + targetResolution.x = targetResolution.y * ar.cx / ar.cy; } else { - targetResolution.y = targetResolution.x * ar.y / ar.x; + targetResolution.y = targetResolution.x * ar.cy / ar.cx; } const auto scaleFactor = Float2(targetResolution) / Float2(appRes); @@ -507,7 +507,7 @@ namespace D3dDdi surfaceRepo.setRepository(repository); if (isPrimary) { - surfaceRepo.setAsPrimary(); + surfaceRepo.setAsPrimaryRepo(); } } } diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index 16f21be..a5d2cb6 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -35,7 +35,7 @@ namespace D3dDdi operator HANDLE() const { return m_adapter; } - Int2 getAspectRatio() const; + SIZE getAspectRatio() const; const AdapterInfo& getInfo() const { return m_info; } LUID getLuid() const { return m_luid; } const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); } @@ -61,7 +61,7 @@ namespace D3dDdi template HRESULT getCaps(D3DDDICAPS_TYPE type, Data& data, UINT size = sizeof(Data)) const; - Int2 getAspectRatio(SIZE appRes, SIZE displayRes) const; + SIZE getAspectRatio(SIZE appRes, SIZE displayRes) const; std::map getFixedFormatOps(const AdapterInfo& info) const; std::map getFormatOps() const; Float2 getScaleFactor() const; diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index aac085f..6080b14 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -221,8 +222,7 @@ namespace D3dDdi { LOG_FUNC("Device::setGdiResourceHandle", resource); ScopedCriticalSection lock; - if ((!resource && !g_gdiResource) || - (g_gdiResource && resource == *g_gdiResource)) + if (resource == g_gdiResourceHandle) { return; } @@ -393,6 +393,7 @@ namespace D3dDdi { g_gdiResourceHandle = nullptr; g_gdiResource = nullptr; + DDraw::PrimarySurface::onLost(); } m_drawPrimitive.removeSysMemVertexBuffer(resource); m_state.onDestroyResource(res, resource); diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 7956a4a..61b905c 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -3,12 +3,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -398,7 +400,7 @@ namespace D3dDdi { static RECT rect = {}; HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); - if (presentationWindow && presentationWindow == data.hWindow) + if (presentationWindow) { Win32::ScopedDpiAwareness dpiAwareness; GetWindowRect(presentationWindow, &rect); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index bf9c167..a43224b 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -25,38 +25,36 @@ #include #include #include -#include namespace { D3DDDI_RESOURCEFLAGS getResourceTypeFlags(); const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; - RECT g_presentationRect = {}; bool g_enableConfig = true; D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN; std::pair g_msaaOverride = {}; + bool g_readOnlyLock = false; - RECT calculateScaledRect(const RECT& srcRect, const RECT& dstRect) + RECT applyDisplayAspectRatio(const RECT& rect, const SIZE& ar) { - const int srcWidth = srcRect.right - srcRect.left; - const int srcHeight = srcRect.bottom - srcRect.top; - const int dstWidth = dstRect.right - dstRect.left; - const int dstHeight = dstRect.bottom - dstRect.top; + LONG width = rect.right; + LONG height = rect.bottom; + SIZE offset = {}; - RECT rect = { 0, 0, dstWidth, dstHeight }; - if (dstWidth * srcHeight > dstHeight * srcWidth) + if (width * ar.cy > height * ar.cx) { - rect.right = dstHeight * srcWidth / srcHeight; + width = height * ar.cx / ar.cy; + offset.cx = (rect.right - width) / 2; } else { - rect.bottom = dstWidth * srcHeight / srcWidth; + height = width * ar.cy / ar.cx; + offset.cy = (rect.bottom - height) / 2; } - OffsetRect(&rect, (dstWidth - rect.right) / 2, (dstHeight - rect.bottom) / 2); - return rect; + return { offset.cx, offset.cy, offset.cx + width, offset.cy + height }; } LONG divCeil(LONG n, LONG d) @@ -151,11 +149,6 @@ namespace D3dDdi throw HResultException(E_FAIL); } - if (m_origData.Flags.MatchGdiPrimary) - { - setFullscreenMode(true); - } - fixResourceData(); m_formatInfo = getFormatInfo(m_fixedData.Format); m_formatConfig = m_fixedData.Format; @@ -209,11 +202,6 @@ namespace D3dDdi Resource::~Resource() { - if (m_origData.Flags.MatchGdiPrimary) - { - setFullscreenMode(false); - } - if (m_msaaSurface.surface || m_msaaResolvedSurface.surface || m_lockRefSurface.surface) { auto& repo = m_device.getRepo(); @@ -225,7 +213,7 @@ namespace D3dDdi HRESULT Resource::blt(D3DDDIARG_BLT data) { - if (!m_fixedData.Flags.MatchGdiPrimary && !isValidRect(data.DstSubResourceIndex, data.DstRect)) + if (!isValidRect(data.DstSubResourceIndex, data.DstRect)) { return S_OK; } @@ -243,11 +231,6 @@ namespace D3dDdi return S_OK; } - if (m_fixedData.Flags.MatchGdiPrimary) - { - return presentationBlt(data, srcResource); - } - if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool && D3DDDIPOOL_SYSTEMMEM == srcResource->m_fixedData.Pool) { @@ -570,7 +553,7 @@ namespace D3dDdi void Resource::createGdiLockResource() { LOG_FUNC("Resource::createGdiLockResource"); - auto gdiSurfaceDesc(Gdi::VirtualScreen::getSurfaceDesc(DDraw::PrimarySurface::getMonitorRect())); + auto gdiSurfaceDesc(Gdi::VirtualScreen::getSurfaceDesc(DDraw::PrimarySurface::getMonitorInfo().rcEmulated)); if (!gdiSurfaceDesc.lpSurface) { return; @@ -716,7 +699,8 @@ namespace D3dDdi { if (m_fixedData.Flags.MatchGdiPrimary) { - RECT r = DDraw::RealPrimarySurface::getMonitorRect(); + auto& mi = DDraw::PrimarySurface::getMonitorInfo(); + RECT r = DDraw::RealPrimarySurface::isExclusiveFullscreen() ? mi.rcReal : mi.rcDpiAware; if (!IsRectEmpty(&r)) { for (auto& surface : m_fixedData.surfaceData) @@ -1042,6 +1026,11 @@ namespace D3dDdi return E_ABORT; } + if (g_readOnlyLock) + { + data.Flags.ReadOnly = true; + } + if (m_lockResource || m_isOversized) { return bltLock(data); @@ -1264,6 +1253,7 @@ namespace D3dDdi HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource* srcResource) { LOG_FUNC("Resource::presentationBlt", data, *srcResource); + m_device.flushPrimitives(); if (srcResource->m_lockResource) { if (srcResource->m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate && @@ -1279,10 +1269,7 @@ namespace D3dDdi LONG srcWidth = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Width; LONG srcHeight = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Height; data.SrcRect = { 0, 0, srcWidth, srcHeight }; - if (!IsRectEmpty(&g_presentationRect)) - { - data.DstRect = g_presentationRect; - } + data.DstRect = applyDisplayAspectRatio(data.DstRect, m_device.getAdapter().getAspectRatio()); auto& repo = m_device.getRepo(); const auto& rtSurface = repo.getNextRenderTarget(srcWidth, srcHeight, srcResource->m_fixedData.Format); @@ -1319,11 +1306,8 @@ namespace D3dDdi copySubResourceRegion(*rt, rtIndex, rtRect, *srcResource, data.SrcSubResourceIndex, data.SrcRect); } - if (!IsRectEmpty(&g_presentationRect)) - { - presentLayeredWindows(*rt, rtIndex, rtRect, - Gdi::Window::getVisibleLayeredWindows(), DDraw::PrimarySurface::getMonitorRect()); - } + auto& mi = m_device.getAdapter().getMonitorInfo(); + presentLayeredWindows(*rt, rtIndex, rtRect, Gdi::Window::getVisibleLayeredWindows(), mi.rcEmulated); const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo(); const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor; @@ -1338,11 +1322,8 @@ namespace D3dDdi clearRectExterior(data.DstSubResourceIndex, data.DstRect); } - if (!IsRectEmpty(&g_presentationRect)) - { - presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex), - Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor); - } + presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex), + Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor); return LOG_RESULT(S_OK); } @@ -1499,41 +1480,6 @@ namespace D3dDdi g_formatOverride = format; } - void Resource::setFullscreenMode(bool isFullscreen) - { - if (!IsRectEmpty(&g_presentationRect) == isFullscreen) - { - return; - } - - if (isFullscreen) - { - DDraw::PrimarySurface::updatePalette(); - - const Int2 ar = m_device.getAdapter().getAspectRatio(); - g_presentationRect = calculateScaledRect({ 0, 0, ar.x, ar.y }, DDraw::RealPrimarySurface::getMonitorRect()); - - const auto& mi = m_device.getAdapter().getMonitorInfo(); - auto clipRect = mi.rcEmulated; - if (!EqualRect(&mi.rcMonitor, &mi.rcReal)) - { - InflateRect(&clipRect, -1, -1); - } - - Gdi::Cursor::setMonitorClipRect(clipRect); - DDraw::RealPrimarySurface::setEmulatedCursor(0 != g_presentationRect.left || 0 != g_presentationRect.top || - Rect::getSize(mi.rcEmulated) != Rect::getSize(g_presentationRect)); - } - else - { - Gdi::Palette::setHardwarePalette(Gdi::Palette::getSystemPalette().data()); - - g_presentationRect = {}; - DDraw::RealPrimarySurface::setEmulatedCursor(false); - Gdi::Cursor::setMonitorClipRect({}); - } - } - void Resource::setPaletteHandle(UINT paletteHandle) { m_paletteHandle = paletteHandle; @@ -1546,6 +1492,11 @@ namespace D3dDdi resource.m_isPalettizedTextureUpToDate = false; } + void Resource::setReadOnlyLock(bool readOnly) + { + g_readOnlyLock = readOnly; + } + HRESULT Resource::shaderBlt(const D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource, UINT filter) { LOG_FUNC("Resource::shaderBlt", data, dstResource, srcResource); @@ -1716,7 +1667,8 @@ namespace D3dDdi if (m_isSurfaceRepoResource || D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || D3DDDIFMT_P8 == m_fixedData.Format || m_fixedData.Flags.MatchGdiPrimary || !m_isPrimary && !m_origData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer || - !m_fixedData.Flags.ZBuffer && !m_lockResource) + !m_fixedData.Flags.ZBuffer && !m_lockResource || + m_fixedData.MipLevels > 1) { return; } diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 2d8a229..269cf95 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -59,7 +59,6 @@ namespace D3dDdi void scaleRect(RECT& rect); void setAsGdiResource(bool isGdiResource); void setAsPrimary(); - void setFullscreenMode(bool isFullscreen); void setPaletteHandle(UINT paletteHandle); void setPalettizedTexture(Resource& resource); HRESULT unlock(const D3DDDIARG_UNLOCK& data); @@ -68,6 +67,7 @@ namespace D3dDdi static void enableConfig(bool enable); static void setFormatOverride(D3DDDIFORMAT format); + static void setReadOnlyLock(bool readOnly); private: class Data : public D3DDDIARG_CREATERESOURCE2 diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 1aef51e..0c6c55a 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -567,7 +567,7 @@ namespace D3dDdi pt.y -= cur.hotspot.y; RECT srcRect = { pt.x, pt.y, pt.x + cur.size.cx, pt.y + cur.size.cy }; - RECT monitorRect = DDraw::PrimarySurface::getMonitorRect(); + RECT monitorRect = m_device.getAdapter().getMonitorInfo().rcEmulated; RECT clippedSrcRect = {}; IntersectRect(&clippedSrcRect, &srcRect, &monitorRect); if (IsRectEmpty(&clippedSrcRect)) diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 0eb4110..3212025 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace { @@ -298,7 +299,7 @@ namespace D3dDdi return getSurface(m_paletteTexture, 256, 1, D3DDDIFMT_A8R8G8B8, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource; } - SurfaceRepository& SurfaceRepository::getPrimary() + SurfaceRepository& SurfaceRepository::getPrimaryRepo() { return *g_primaryRepository; } @@ -351,6 +352,44 @@ namespace D3dDdi (D3DDDIFMT_P8 == format ? 0 : DDSCAPS_TEXTURE) | DDSCAPS_VIDEOMEMORY); } + CompatPtr SurfaceRepository::getWindowedBackBuffer(DWORD width, DWORD height) + { + return getSurface(m_windowedBackBuffer, width, height, D3DDDIFMT_X8R8G8B8, + DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY).surface; + } + + CompatWeakPtr SurfaceRepository::getWindowedPrimary() + { + if (m_windowedPrimary) + { + if (SUCCEEDED(m_windowedPrimary->IsLost(m_windowedPrimary))) + { + return m_windowedPrimary; + } + m_windowedPrimary.release(); + } + + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_CAPS; + desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + HRESULT result = m_dd->CreateSurface(m_dd, &desc, &m_windowedPrimary.getRef(), nullptr); + if (FAILED(result)) + { + LOG_ONCE("ERROR: Failed to create primary surface in repository: " << Compat::hex(result) << " " << desc); + } + + return m_windowedPrimary; + } + + CompatPtr SurfaceRepository::getWindowedSrc(RECT rect) + { + CompatPtr src; + auto desc = Gdi::VirtualScreen::getSurfaceDesc(rect); + m_dd->CreateSurface(m_dd, &desc, &src.getRef(), nullptr); + return src; + } + bool SurfaceRepository::hasAlpha(CompatRef surface) { DDSURFACEDESC2 desc = {}; @@ -392,7 +431,7 @@ namespace D3dDdi } } - void SurfaceRepository::setAsPrimary() + void SurfaceRepository::setAsPrimaryRepo() { g_primaryRepository = this; } diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.h b/DDrawCompat/D3dDdi/SurfaceRepository.h index 7b3a265..7779143 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.h +++ b/DDrawCompat/D3dDdi/SurfaceRepository.h @@ -40,6 +40,7 @@ namespace D3dDdi SurfaceRepository(); Cursor getCursor(HCURSOR cursor); + CompatWeakPtr getDirectDraw() { return m_dd; } Resource* getDitherTexture(DWORD size); Resource* getLogicalXorTexture(); Resource* getPaletteTexture(); @@ -52,12 +53,15 @@ namespace D3dDdi Surface& getTempSurface(Surface& surface, DWORD width, DWORD height, D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1); const Surface& getTempTexture(DWORD width, DWORD height, D3DDDIFORMAT format); + CompatPtr getWindowedBackBuffer(DWORD width, DWORD height); + CompatWeakPtr getWindowedPrimary(); + CompatPtr getWindowedSrc(RECT rect); void release(Surface& surface); - void setAsPrimary(); + void setAsPrimaryRepo(); void setRepository(CompatWeakPtr dd) { m_dd = dd; } static SurfaceRepository& get(const Adapter& adapter); - static SurfaceRepository& getPrimary(); + static SurfaceRepository& getPrimaryRepo(); static bool inCreateSurface() { return s_inCreateSurface; } static void enableSurfaceCheck(bool enable); @@ -86,6 +90,8 @@ namespace D3dDdi std::map m_textures; std::vector m_releasedSurfaces; Surface m_sysMemSurface; + Surface m_windowedBackBuffer; + CompatPtr m_windowedPrimary; static bool s_inCreateSurface; }; diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index 8c587dc..47b5b4a 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -142,10 +142,6 @@ namespace if (wasFullscreen != isFullscreen) { tagSurface->setFullscreenWindow(isFullscreen ? hWnd : nullptr); - if (DDraw::RealPrimarySurface::getSurface()) - { - DDraw::RealPrimarySurface::restore(); - } } } } diff --git a/DDrawCompat/DDraw/DirectDrawClipper.cpp b/DDrawCompat/DDraw/DirectDrawClipper.cpp index 62ca0c2..569906c 100644 --- a/DDrawCompat/DDraw/DirectDrawClipper.cpp +++ b/DDrawCompat/DDraw/DirectDrawClipper.cpp @@ -46,10 +46,10 @@ namespace GetRandomRgn(dc, rgn, SYSRGN); CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc); - RECT primaryRect = DDraw::PrimarySurface::getMonitorRect(); - if (0 != primaryRect.left || 0 != primaryRect.top) + auto& mi = DDraw::PrimarySurface::getMonitorInfo(); + if (0 != mi.rcEmulated.left || 0 != mi.rcEmulated.top) { - rgn.offset(-primaryRect.left, -primaryRect.top); + rgn.offset(-mi.rcEmulated.left, -mi.rcEmulated.top); } DWORD rgnSize = GetRegionData(rgn, 0, nullptr); diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index ff3d12d..dda2535 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -46,22 +46,15 @@ namespace { const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200; - CompatPtr getBackBuffer(); - CompatPtr getLastSurface(); void onRelease(); - void presentationBlt(CompatRef dst, CompatRef src); - void updatePresentationWindow(); - - CompatWeakPtr g_defaultPrimary; + void updatePresentationParams(); CompatWeakPtr g_frontBuffer; CompatWeakPtr g_windowedBackBuffer; CompatWeakPtr g_clipper; RECT g_monitorRect = {}; - DDSURFACEDESC2 g_surfaceDesc = {}; DDraw::IReleaseNotifier g_releaseNotifier(onRelease); - bool g_emulatedCursor = false; bool g_isFullscreen = false; bool g_isExclusiveFullscreen = false; DDraw::Surface* g_lastFlipSurface = nullptr; @@ -83,127 +76,6 @@ namespace HWND g_deviceWindow = nullptr; HWND* g_deviceWindowPtr = nullptr; HWND g_presentationWindow = nullptr; - long long g_qpcUpdatePresentationWindow = 0; - - void bltToPrimaryChain(CompatRef src) - { - if (!g_isFullscreen) - { - updatePresentationWindow(); - - if (g_presentationWindow) - { - presentationBlt(*g_windowedBackBuffer, src); - } - - Gdi::Window::present(*g_frontBuffer, g_presentationWindow ? *g_windowedBackBuffer : src, *g_clipper); - return; - } - - auto backBuffer(getBackBuffer()); - if (backBuffer) - { - presentationBlt(*backBuffer, src); - } - } - - BOOL WINAPI createDefaultPrimaryEnum( - GUID* lpGUID, LPSTR /*lpDriverDescription*/, LPSTR lpDriverName, LPVOID lpContext, HMONITOR /*hm*/) - { - auto& deviceName = *static_cast(lpContext); - if (deviceName != std::wstring(lpDriverName, lpDriverName + strlen(lpDriverName))) - { - return TRUE; - } - - auto tagSurface = DDraw::TagSurface::findFullscreenWindow(); - LOG_DEBUG << "Creating " << (tagSurface ? "fullscreen" : "windowed") << " default primary"; - - DDraw::SuppressResourceFormatLogs suppressResourceFormatLogs; - if (tagSurface) - { - DDSURFACEDESC desc = {}; - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_CAPS; - desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - CompatPtr dd(tagSurface->getDD()); - CompatPtr primary; - dd.get()->lpVtbl->CreateSurface(dd, &desc, &primary.getRef(), nullptr); - g_defaultPrimary = CompatPtr(primary).detach(); - } - else - { - CompatPtr dd; - if (FAILED(CALL_ORIG_PROC(DirectDrawCreateEx)( - lpGUID, reinterpret_cast(&dd.getRef()), IID_IDirectDraw7, nullptr))) - { - return FALSE; - } - DDraw::DirectDraw::onCreate(lpGUID, *dd); - - if (FAILED(dd.get()->lpVtbl->SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL))) - { - return FALSE; - } - - DDSURFACEDESC2 desc = {}; - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_CAPS; - desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - dd.get()->lpVtbl->CreateSurface(dd, &desc, &g_defaultPrimary.getRef(), nullptr); - } - - return nullptr != g_defaultPrimary; - } - - void createDefaultPrimary() - { - if (!Dll::g_isHooked || - (g_defaultPrimary ? SUCCEEDED(g_defaultPrimary->IsLost(g_defaultPrimary)) : g_frontBuffer)) - { - return; - } - - DDraw::RealPrimarySurface::destroyDefaultPrimary(); - - auto dm = Win32::DisplayMode::getEmulatedDisplayMode(); - if (dm.deviceName.empty()) - { - return; - } - - CALL_ORIG_PROC(DirectDrawEnumerateExA)(createDefaultPrimaryEnum, &dm.deviceName, DDENUM_ATTACHEDSECONDARYDEVICES); - } - - CompatPtr createWindowedBackBuffer(DDraw::TagSurface& tagSurface, DWORD width, DWORD height) - { - auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*tagSurface.getDDS()); - if (!resource) - { - LOG_INFO << "ERROR: createWindowedBackBuffer: driver resource handle not found"; - return nullptr; - } - - auto device = D3dDdi::Device::findDeviceByResource(resource); - if (!device) - { - LOG_INFO << "ERROR: createWindowedBackBuffer: device not found"; - return nullptr; - } - - auto& repo = device->getRepo(); - D3dDdi::SurfaceRepository::Surface surface = {}; - repo.getSurface(surface, width, height, D3DDDIFMT_X8R8G8B8, - DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY); - if (!surface.surface) - { - LOG_INFO << "ERROR: createWindowedBackBuffer: surface creation failed"; - return nullptr; - } - - return surface.surface; - } CompatPtr getBackBuffer() { @@ -272,27 +144,14 @@ namespace { LOG_FUNC("RealPrimarySurface::onRelease"); - if (g_windowedBackBuffer) - { - auto resource = D3dDdi::Device::findResource( - DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer)); - resource->setFullscreenMode(false); - } - - DDraw::RealPrimarySurface::schedulePresentationWindowUpdate(); - - g_defaultPrimary = nullptr; g_frontBuffer = nullptr; g_lastFlipSurface = nullptr; g_windowedBackBuffer.release(); - g_clipper.release(); g_isFullscreen = false; - g_surfaceDesc = {}; g_tagSurface = nullptr; g_deviceWindow = nullptr; g_deviceWindowPtr = nullptr; - g_monitorRect = {}; } void onRestore() @@ -301,29 +160,19 @@ namespace desc.dwSize = sizeof(desc); g_frontBuffer->GetSurfaceDesc(g_frontBuffer, &desc); - g_clipper.release(); - CALL_ORIG_PROC(DirectDrawCreateClipper)(0, &g_clipper.getRef(), nullptr); - g_frontBuffer->SetClipper(g_frontBuffer, g_clipper); - g_surfaceDesc = desc; - if (g_isExclusiveFullscreen && 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP)) { g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT); D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1); } - if (g_windowedBackBuffer) - { - g_windowedBackBuffer->Restore(g_windowedBackBuffer); - } - auto gdiResource = DDraw::PrimarySurface::getGdiResource(); if (gdiResource) { D3dDdi::Device::setGdiResourceHandle(gdiResource); } - updatePresentationWindow(); + updatePresentationParams(); Compat::ScopedCriticalSection lock(g_presentCs); g_isOverlayUpdatePending = false; @@ -337,6 +186,7 @@ namespace void presentationBlt(CompatRef dst, CompatRef src) { + LOG_FUNC("RealPrimarySurface::presentationBlt", dst, src); D3dDdi::ScopedCriticalSection lock; auto srcResource = D3dDdi::Device::findResource( DDraw::DirectDrawSurface::getDriverResourceHandle(src.get())); @@ -350,16 +200,16 @@ namespace D3DDDIARG_BLT blt = {}; blt.hSrcResource = *srcResource; blt.SrcSubResourceIndex = DDraw::DirectDrawSurface::getSubResourceIndex(src.get()); - blt.SrcRect = DDraw::PrimarySurface::getMonitorRect(); + blt.SrcRect = srcResource->getRect(blt.SrcSubResourceIndex); blt.hDstResource = *dstResource; blt.DstSubResourceIndex = DDraw::DirectDrawSurface::getSubResourceIndex(dst.get()); - blt.DstRect = g_monitorRect; + blt.DstRect = dstResource->getRect(blt.DstSubResourceIndex); dstResource->presentationBlt(blt, srcResource); } - void presentToPrimaryChain(CompatWeakPtr src, bool isOverlayOnly) + void present(CompatWeakPtr src, bool isOverlayOnly) { - LOG_FUNC("RealPrimarySurface::presentToPrimaryChain", src, isOverlayOnly); + LOG_FUNC("RealPrimarySurface::present", src, isOverlayOnly); Gdi::VirtualScreen::update(); @@ -391,19 +241,137 @@ namespace Input::updateCursor(); }); - if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost()) + if (src ? !g_isFullscreen : !g_presentationWindow) { Gdi::Window::present(nullptr); return; } - Gdi::Region excludeRegion(DDraw::PrimarySurface::getMonitorRect()); + const bool useFlip = src && g_isFullscreen; + Win32::DisplayMode::MonitorInfo mi = {}; + CompatWeakPtr frontBuffer; + CompatPtr backBuffer; + CompatPtr windowedSrc; + + if (src) + { + mi = DDraw::PrimarySurface::getMonitorInfo(); + frontBuffer = g_frontBuffer; + if (g_isFullscreen) + { + backBuffer = getBackBuffer(); + } + } + else + { + mi = Win32::DisplayMode::getMonitorInfo(MonitorFromWindow(g_presentationWindow, MONITOR_DEFAULTTOPRIMARY)); + if (!DDraw::TagSurface::findFullscreenWindow()) + { + frontBuffer = D3dDdi::SurfaceRepository::getPrimaryRepo().getWindowedPrimary(); + } + } + + if (g_presentationWindow && !backBuffer) + { + D3dDdi::SurfaceRepository* repo = nullptr; + if (src) + { + auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*frontBuffer); + if (!resource) + { + return; + } + + auto device = D3dDdi::Device::findDeviceByResource(resource); + if (!device) + { + return; + } + repo = &device->getRepo(); + } + else + { + repo = &D3dDdi::SurfaceRepository::getPrimaryRepo(); + windowedSrc = repo->getWindowedSrc(mi.rcEmulated); + if (!windowedSrc) + { + return; + } + src = windowedSrc; + } + + backBuffer = repo->getWindowedBackBuffer( + mi.rcDpiAware.right - mi.rcDpiAware.left, mi.rcDpiAware.bottom - mi.rcDpiAware.top); + if (!backBuffer) + { + return; + } + } + + Gdi::Region excludeRegion(mi.rcEmulated); Gdi::Window::present(excludeRegion); - bltToPrimaryChain(*src); + presentationBlt(*backBuffer, *src); + if (useFlip) + { + if (g_isExclusiveFullscreen) + { + frontBuffer->Flip(frontBuffer, backBuffer, DDFLIP_WAIT); + } + else + { + *g_deviceWindowPtr = g_presentationWindow; + frontBuffer->Flip(frontBuffer, nullptr, DDFLIP_WAIT); + *g_deviceWindowPtr = g_deviceWindow; + } + } + else if (frontBuffer) + { + if (!g_clipper) + { + CALL_ORIG_PROC(DirectDrawCreateClipper)(0, &g_clipper.getRef(), nullptr); + } + g_clipper->SetHWnd(g_clipper, 0, g_presentationWindow); + frontBuffer->SetClipper(frontBuffer, g_clipper); + frontBuffer->Blt(frontBuffer, nullptr, backBuffer, nullptr, DDBLT_WAIT, nullptr); + } + else + { + HDC dstDc = GetWindowDC(g_presentationWindow); + HDC srcDc = nullptr; + D3dDdi::Resource::setReadOnlyLock(true); + backBuffer->GetDC(backBuffer, &srcDc); + D3dDdi::Resource::setReadOnlyLock(false); + CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, mi.rcDpiAware.right - mi.rcDpiAware.left, mi.rcDpiAware.bottom - mi.rcDpiAware.top, + srcDc, 0, 0, SRCCOPY); + backBuffer->ReleaseDC(backBuffer, srcDc); + ReleaseDC(g_presentationWindow, dstDc); + } + } + + void setFullscreenPresentationMode(const Win32::DisplayMode::MonitorInfo& mi) + { + if (IsRectEmpty(&mi.rcDpiAware)) + { + Gdi::Cursor::setEmulated(false); + Gdi::Cursor::setMonitorClipRect({}); + } + else + { + auto clipRect = mi.rcEmulated; + if (!EqualRect(&mi.rcMonitor, &mi.rcReal)) + { + InflateRect(&clipRect, -1, -1); + } + + Gdi::Cursor::setMonitorClipRect(clipRect); + Gdi::Cursor::setEmulated(true); + } } void updateNow(CompatWeakPtr src, bool isOverlayOnly) { + present(src, isOverlayOnly); + { Compat::ScopedCriticalSection lock(g_presentCs); g_isOverlayUpdatePending = false; @@ -411,40 +379,28 @@ namespace g_isUpdateReady = false; } - presentToPrimaryChain(src, isOverlayOnly); - - if (g_isFullscreen) - { - updatePresentationWindow(); - *g_deviceWindowPtr = g_presentationWindow; - g_frontBuffer->Flip(g_frontBuffer, g_isExclusiveFullscreen ? getBackBuffer() : nullptr, DDFLIP_WAIT); - *g_deviceWindowPtr = g_deviceWindow; - } g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1; } - void updatePresentationWindow() + void updatePresentationParams() { - LOG_FUNC("RealPrimarySurface::updatePresentationWindow"); + LOG_FUNC("RealPrimarySurface::updatePresentationParams"); HWND fullscreenWindow = nullptr; if (isProcessActive()) { if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow)) { - if (g_isExclusiveFullscreen) - { - return; - } fullscreenWindow = g_deviceWindow; } - else if (g_frontBuffer && DDraw::PrimarySurface::getPrimary() && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer))) + else { fullscreenWindow = Gdi::Window::getFullscreenWindow(); } } else if (g_isFullscreen) { + setFullscreenPresentationMode({}); return; } @@ -455,26 +411,27 @@ namespace fullscreenPresentationWindow = Gdi::Window::getPresentationWindow(fullscreenWindow); } - if (g_windowedBackBuffer) - { - auto resource = D3dDdi::Device::findResource( - DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer)); - resource->setFullscreenMode(fullscreenPresentationWindow); - } - g_presentationWindow = fullscreenPresentationWindow; if (g_presentationWindow) { + auto& mi = Win32::DisplayMode::getMonitorInfo(MonitorFromWindow(g_presentationWindow, MONITOR_DEFAULTTOPRIMARY)); + auto& mr = mi.rcDpiAware; + Gdi::GuiThread::execute([&]() { Win32::ScopedDpiAwareness dpiAwareness; - CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top, 0, 0, + CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, mr.left, mr.top, 0, 0, SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOSIZE); - CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, nullptr, 0, 0, - g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top, + CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, nullptr, 0, 0, mr.right - mr.left, mr.bottom - mr.top, SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE); }); + + setFullscreenPresentationMode(mi); + } + else + { + setFullscreenPresentationMode({}); } static HWND prevFullscreenWindow = nullptr; @@ -488,11 +445,6 @@ namespace } } prevFullscreenWindow = fullscreenWindow; - - if (Gdi::Cursor::isEmulated() != g_emulatedCursor) - { - Gdi::Cursor::setEmulated(g_emulatedCursor); - } } unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/) @@ -521,11 +473,6 @@ namespace DDraw HRESULT RealPrimarySurface::create(CompatRef dd) { LOG_FUNC("RealPrimarySurface::create", &dd); - DDraw::ScopedThreadLock lock; - const auto& mi = Win32::DisplayMode::getMonitorInfo( - D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::from(&dd)).deviceName); - auto prevMonitorRect = g_monitorRect; - g_monitorRect = g_isExclusiveFullscreen ? mi.rcReal : mi.rcDpiAware; DDSURFACEDESC desc = {}; desc.dwSize = sizeof(desc); @@ -533,15 +480,11 @@ namespace DDraw desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; desc.dwBackBufferCount = g_isExclusiveFullscreen ? 2 : 1; - auto prevIsFullscreen = g_isFullscreen; - g_isFullscreen = true; CompatPtr surface; HRESULT result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr); if (DDERR_NOEXCLUSIVEMODE == result) { - g_isFullscreen = false; - g_monitorRect = mi.rcDpiAware; desc.dwFlags = DDSD_CAPS; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; desc.dwBackBufferCount = 0; @@ -550,9 +493,7 @@ namespace DDraw if (FAILED(result)) { - LOG_INFO << "ERROR: Failed to create the real primary surface: " << Compat::hex(result); - g_monitorRect = prevMonitorRect; - g_isFullscreen = prevIsFullscreen; + LOG_ONCE("ERROR: Failed to create the real primary surface: " << Compat::hex(result)); return result; } @@ -560,23 +501,13 @@ namespace DDraw auto tagSurface = DDraw::TagSurface::get(ddLcl); if (!tagSurface) { - LOG_INFO << "ERROR: TagSurface not found"; - g_monitorRect = prevMonitorRect; - g_isFullscreen = prevIsFullscreen; + LOG_ONCE("ERROR: TagSurface not found"); return DDERR_GENERIC; } - if (0 == desc.dwBackBufferCount) - { - g_windowedBackBuffer = createWindowedBackBuffer(*tagSurface, - g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top).detach(); - if (!g_windowedBackBuffer) - { - g_monitorRect = prevMonitorRect; - g_isFullscreen = prevIsFullscreen; - return DDERR_GENERIC; - } - } + g_isFullscreen = 0 != desc.dwBackBufferCount; + auto& mi = PrimarySurface::getMonitorInfo(); + g_monitorRect = g_isFullscreen && g_isExclusiveFullscreen ? mi.rcReal : mi.rcDpiAware; g_tagSurface = tagSurface; g_frontBuffer = CompatPtr::from(surface.get()).detach(); @@ -590,15 +521,6 @@ namespace DDraw return DD_OK; } - void RealPrimarySurface::destroyDefaultPrimary() - { - if (g_defaultPrimary) - { - LOG_DEBUG << "Destroying default primary"; - g_defaultPrimary.release(); - } - } - HRESULT RealPrimarySurface::flip(CompatPtr surfaceTargetOverride, DWORD flags) { const DWORD flipInterval = getFlipInterval(flags); @@ -658,20 +580,7 @@ namespace DDraw lastOverlayCheckVsyncCount = vsyncCount; } - bool isPresentationWindowUpdateNeeded = false; - - { - Compat::ScopedCriticalSection lock(g_presentCs); - isPresentationWindowUpdateNeeded = - 0 != g_qpcUpdatePresentationWindow && Time::queryPerformanceCounter() - g_qpcUpdatePresentationWindow >= 0 || - !isProcessActive(); - } - - if (isPresentationWindowUpdateNeeded) - { - g_qpcUpdatePresentationWindow = 0; - updatePresentationWindow(); - } + updatePresentationParams(); bool isOverlayOnly = false; @@ -712,22 +621,13 @@ namespace DDraw } } - createDefaultPrimary(); - if (!g_defaultPrimary && g_frontBuffer && FAILED(g_frontBuffer->IsLost(g_frontBuffer))) - { - restore(); - } - auto primary(DDraw::PrimarySurface::getPrimary()); CompatWeakPtr src; - if (primary && SUCCEEDED(primary->IsLost(primary))) + if (primary && SUCCEEDED(primary->IsLost(primary)) && + g_frontBuffer && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer))) { src = g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : primary; } - else - { - src = DDraw::PrimarySurface::getGdiPrimary(); - } updateNow(src, isOverlayOnly); @@ -753,11 +653,6 @@ namespace DDraw return gammaControl->GetGammaRamp(gammaControl, 0, rampData); } - RECT RealPrimarySurface::getMonitorRect() - { - return g_monitorRect; - } - HWND RealPrimarySurface::getPresentationWindow() { return g_presentationWindow; @@ -780,6 +675,11 @@ namespace DDraw Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL); } + bool RealPrimarySurface::isExclusiveFullscreen() + { + return g_isExclusiveFullscreen; + } + bool RealPrimarySurface::isFullscreen() { return g_isFullscreen; @@ -799,22 +699,21 @@ namespace DDraw HRESULT RealPrimarySurface::restore() { + LOG_FUNC("RealPrimarySurface::restore"); DDraw::ScopedThreadLock lock; - if (g_defaultPrimary) - { - destroyDefaultPrimary(); - createDefaultPrimary(); - return DD_OK; - } - auto dd(g_tagSurface->getDD()); if (g_isFullscreen && FAILED(dd->TestCooperativeLevel(dd))) { return DDERR_NOEXCLUSIVEMODE; } - release(); - return create(*CompatPtr::from(dd.get())); + HRESULT result = g_frontBuffer->Restore(g_frontBuffer); + if (SUCCEEDED(result)) + { + release(); + return create(*CompatPtr::from(dd.get())); + } + return LOG_RESULT(result); } void RealPrimarySurface::scheduleOverlayUpdate() @@ -837,17 +736,6 @@ namespace DDraw g_isUpdateReady = false; } - void RealPrimarySurface::schedulePresentationWindowUpdate() - { - Compat::ScopedCriticalSection lock(g_presentCs); - g_qpcUpdatePresentationWindow = Time::queryPerformanceCounter() + Time::g_qpcFrequency / 5; - } - - void RealPrimarySurface::setEmulatedCursor(bool emulated) - { - g_emulatedCursor = emulated; - } - HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData) { DDraw::ScopedThreadLock lock; diff --git a/DDrawCompat/DDraw/RealPrimarySurface.h b/DDrawCompat/DDraw/RealPrimarySurface.h index cb41fa1..d885616 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.h +++ b/DDrawCompat/DDraw/RealPrimarySurface.h @@ -13,23 +13,20 @@ namespace DDraw { public: static HRESULT create(CompatRef dd); - static void destroyDefaultPrimary(); static HRESULT flip(CompatPtr surfaceTargetOverride, DWORD flags); static int flush(); - static HWND getPresentationWindow(); static HRESULT getGammaRamp(DDGAMMARAMP* rampData); - static RECT getMonitorRect(); + static HWND getPresentationWindow(); static CompatWeakPtr getSurface(); static HWND getTopmost(); static void init(); + static bool isExclusiveFullscreen(); static bool isFullscreen(); static bool isLost(); static void release(); static HRESULT restore(); static void scheduleOverlayUpdate(); static void scheduleUpdate(); - static void schedulePresentationWindowUpdate(); - static void setEmulatedCursor(bool emulated); static HRESULT setGammaRamp(DDGAMMARAMP* rampData); static void setPresentationWindowTopmost(); static void setUpdateReady(); diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index 0e3824d..5d9ffee 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -17,7 +17,6 @@ namespace { CompatWeakPtr g_primarySurface; - CompatWeakPtr g_gdiPrimarySurface; D3dDdi::Device* g_device = nullptr; HANDLE g_gdiDriverResource = nullptr; HANDLE g_gdiRuntimeResource = nullptr; @@ -26,38 +25,7 @@ namespace 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 = device->getRepo(); - D3dDdi::SurfaceRepository::Surface surface = {}; - repo.getSurface(surface, 1, 1, D3DDDIFMT_X8R8G8B8, DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY); - - LOG_RESULT(surface.surface.get()); - return surface.surface; - } + Win32::DisplayMode::MonitorInfo g_monitorInfo = {}; } namespace DDraw @@ -71,7 +39,6 @@ namespace DDraw g_gdiDriverResource = nullptr; g_frontResource = nullptr; g_primarySurface = nullptr; - g_gdiPrimarySurface.release(); g_origCaps = 0; g_deviceWindow = nullptr; if (g_palette) @@ -80,7 +47,7 @@ namespace DDraw g_palette = nullptr; } g_deviceName.clear(); - g_monitorRect = {}; + g_monitorInfo = {}; s_palette = nullptr; DDraw::RealPrimarySurface::release(); @@ -91,17 +58,15 @@ namespace DDraw HRESULT PrimarySurface::create(CompatRef dd, TSurfaceDesc desc, TSurface*& surface) { LOG_FUNC("PrimarySurface::create", &dd, desc, surface); - DDraw::RealPrimarySurface::destroyDefaultPrimary(); auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::from(&dd)).deviceName; - const auto& mi = Win32::DisplayMode::getMonitorInfo(deviceName); - auto prevMonitorRect = g_monitorRect; - g_monitorRect = mi.rcEmulated; + auto prevMonitorInfo = g_monitorInfo; + g_monitorInfo = Win32::DisplayMode::getMonitorInfo(deviceName); HRESULT result = RealPrimarySurface::create(*CompatPtr::from(&dd)); if (FAILED(result)) { - g_monitorRect = prevMonitorRect; + g_monitorInfo = prevMonitorInfo; return LOG_RESULT(result); } @@ -112,26 +77,25 @@ namespace DDraw auto data = privateData.get(); desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - desc.dwWidth = g_monitorRect.right - g_monitorRect.left; - desc.dwHeight = g_monitorRect.bottom - g_monitorRect.top; + desc.dwWidth = g_monitorInfo.rcEmulated.right - g_monitorInfo.rcEmulated.left; + desc.dwHeight = g_monitorInfo.rcEmulated.bottom - g_monitorInfo.rcEmulated.top; desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM); desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; - desc.ddpfPixelFormat = DirectDraw::getRgbPixelFormat(mi.bpp); + desc.ddpfPixelFormat = DirectDraw::getRgbPixelFormat(g_monitorInfo.bpp); result = Surface::create(dd, desc, surface, std::move(privateData)); if (FAILED(result)) { - LOG_INFO << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result); - g_monitorRect = prevMonitorRect; + LOG_ONCE("ERROR: Failed to create the compat primary surface: " << Compat::hex(result)); RealPrimarySurface::release(); + g_monitorInfo = {}; return LOG_RESULT(result); } g_deviceName = deviceName; g_origCaps = origCaps; g_deviceWindow = *DDraw::DirectDraw::getDeviceWindowPtr(dd.get()); - g_gdiPrimarySurface = createGdiPrimarySurface(*CompatPtr::from(&dd)).detach(); if (desc.ddpfPixelFormat.dwRGBBitCount <= 8) { @@ -234,49 +198,9 @@ namespace DDraw return surface; } - CompatWeakPtr PrimarySurface::getGdiPrimary() + const Win32::DisplayMode::MonitorInfo& PrimarySurface::getMonitorInfo() { - 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()); + return g_monitorInfo; } CompatWeakPtr PrimarySurface::getPrimary() @@ -294,11 +218,6 @@ namespace DDraw return g_gdiDriverResource; } - RECT PrimarySurface::getMonitorRect() - { - return g_monitorRect; - } - DWORD PrimarySurface::getOrigCaps() { return g_origCaps; @@ -316,10 +235,21 @@ namespace DDraw template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*); template bool PrimarySurface::isGdiSurface(IDirectDrawSurface7*); + void PrimarySurface::onLost() + { + if (s_palette) + { + Gdi::Palette::setHardwarePalette(Gdi::Palette::getSystemPalette().data()); + } + g_gdiRuntimeResource = nullptr; + g_gdiDriverResource = nullptr; + } + void PrimarySurface::restore() { LOG_FUNC("PrimarySurface::restore"); + updatePalette(); Gdi::VirtualScreen::update(); g_primarySurface = m_surface; g_gdiRuntimeResource = DirectDrawSurface::getRuntimeResourceHandle(*g_primarySurface); @@ -366,7 +296,7 @@ namespace DDraw PALETTEENTRY entries[256] = {}; PrimarySurface::s_palette->GetEntries(s_palette, 0, 0, 256, entries); - if (RealPrimarySurface::isFullscreen()) + if (RealPrimarySurface::isFullscreen() && SUCCEEDED(g_primarySurface->IsLost(g_primarySurface))) { Gdi::Palette::setHardwarePalette(entries); } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h index aedde00..80472ce 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace DDraw { @@ -21,12 +22,12 @@ namespace DDraw static CompatPtr getGdiSurface(); static CompatPtr getBackBuffer(); static CompatPtr getLastSurface(); - static RECT getMonitorRect(); - static CompatWeakPtr getGdiPrimary(); + static const Win32::DisplayMode::MonitorInfo& getMonitorInfo(); static CompatWeakPtr getPrimary(); static HANDLE getFrontResource(); static HANDLE getGdiResource(); static DWORD getOrigCaps(); + static void onLost(); static void updatePalette(); template diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index 4b13f07..8a889b7 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -35,7 +35,7 @@ namespace D3dDdi::ScopedCriticalSection lock; Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper)); - RECT monitorRect = DDraw::PrimarySurface::getMonitorRect(); + RECT monitorRect = DDraw::PrimarySurface::getMonitorInfo().rcEmulated; RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds(); clipRgn.offset(monitorRect.left, monitorRect.top); clipRgn &= virtualScreenBounds; diff --git a/DDrawCompat/Gdi/Cursor.cpp b/DDrawCompat/Gdi/Cursor.cpp index ccc9037..01849e5 100644 --- a/DDrawCompat/Gdi/Cursor.cpp +++ b/DDrawCompat/Gdi/Cursor.cpp @@ -26,16 +26,15 @@ namespace { LOG_FUNC("ClipCursor", lpRect); Compat::ScopedCriticalSection lock(g_cs); - BOOL result = CALL_ORIG_FUNC(ClipCursor)(lpRect); - if (!result || IsRectEmpty(&g_monitorClipRect)) + if (IsRectEmpty(&g_monitorClipRect)) { - return LOG_RESULT(result); + return LOG_RESULT(CALL_ORIG_FUNC(ClipCursor)(lpRect)); } - CALL_ORIG_FUNC(GetClipCursor)(&g_clipRect); - RECT rect = intersectRect(g_clipRect, g_monitorClipRect); + g_clipRect = lpRect ? *lpRect : Win32::DisplayMode::getRealBounds(); + const RECT rect = intersectRect(g_clipRect, g_monitorClipRect); CALL_ORIG_FUNC(ClipCursor)(&rect); - return LOG_RESULT(result); + return LOG_RESULT(TRUE); } BOOL WINAPI getClipCursor(LPRECT lpRect) @@ -180,13 +179,13 @@ namespace Gdi void setEmulated(bool isEmulated) { - LOG_FUNC("Cursor::setEmulated", isEmulated); Compat::ScopedCriticalSection lock(g_cs); if (isEmulated == g_isEmulated) { return; } + LOG_DEBUG << "Cursor::setEmulated: " << isEmulated; g_isEmulated = isEmulated; g_prevCursorInfo = {}; @@ -197,7 +196,12 @@ namespace Gdi void setMonitorClipRect(const RECT& rect) { - LOG_FUNC("Cursor::setMonitorClipRect", rect); + if (EqualRect(&rect, &g_monitorClipRect)) + { + return; + } + + LOG_DEBUG << "Cursor::setMonitorClipRect: " << rect; Compat::ScopedCriticalSection lock(g_cs); if (IsRectEmpty(&rect)) { diff --git a/DDrawCompat/Gdi/User32WndProcs.cpp b/DDrawCompat/Gdi/User32WndProcs.cpp index 14f4193..d24cc87 100644 --- a/DDrawCompat/Gdi/User32WndProcs.cpp +++ b/DDrawCompat/Gdi/User32WndProcs.cpp @@ -318,12 +318,7 @@ namespace void fixPopupMenuPosition(WINDOWPOS& wp) { - RECT mr = DDraw::PrimarySurface::getMonitorRect(); - if (IsRectEmpty(&mr)) - { - return; - } - + RECT mr = Win32::DisplayMode::getMonitorInfo(MonitorFromWindow(wp.hwnd, MONITOR_DEFAULTTOPRIMARY)).rcEmulated; if (wp.flags & SWP_NOSIZE) { RECT r = {}; diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 4f45b0b..99b5b5b 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -147,13 +148,31 @@ namespace Gdi } auto primary(DDraw::PrimarySurface::getPrimary()); - CompatPtr ddUnk; - primary->GetDDInterface(primary, reinterpret_cast(&ddUnk.getRef())); - CompatPtr dd(ddUnk); + if (!primary) + { + return nullptr; + } + + auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*primary); + if (!resource) + { + return nullptr; + } + + auto device = D3dDdi::Device::findDeviceByResource(resource); + if (!device) + { + return nullptr; + } + + auto dd(device->getRepo().getDirectDraw()); + if (!dd) + { + return nullptr; + } - DDraw::SuppressResourceFormatLogs suppressResourceFormatLogs; CompatPtr surface; - dd.get()->lpVtbl->CreateSurface(dd, &desc, &surface.getRef(), nullptr); + dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr); return surface; } @@ -248,7 +267,7 @@ namespace Gdi if (g_isFullscreen) { - g_bounds = DDraw::PrimarySurface::getMonitorRect(); + g_bounds = DDraw::PrimarySurface::getMonitorInfo().rcEmulated; } else { diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index feedfcf..43c2333 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -517,11 +517,12 @@ namespace void onInitMenuPopup(HMENU menu) { - RECT mr = DDraw::PrimarySurface::getMonitorRect(); - if (IsRectEmpty(&mr)) + auto deviceName = Win32::DisplayMode::getEmulatedDisplayMode().deviceName; + if (deviceName.empty()) { return; } + const RECT& mr = Win32::DisplayMode::getMonitorInfo(deviceName).rcEmulated; MENUINFO mi = {}; mi.cbSize = sizeof(mi); diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index 437deab..f9babb5 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -125,6 +125,7 @@ namespace std::map g_windows; std::vector g_windowZOrder; + HWND g_fullscreenWindow = nullptr; bool bltWindow(const RECT& dst, const RECT& src, const Gdi::Region& clipRegion) { @@ -141,6 +142,25 @@ namespace return true; } + HWND findFullscreenWindow() + { + D3dDdi::ScopedCriticalSection lock; + auto allMi = Win32::DisplayMode::getAllMonitorInfo(); + for (auto& window : g_windows) + { + for (const auto& mi : allMi) + if (!window.second.isLayered && + window.second.windowRect.left <= mi.second.rcEmulated.left && + window.second.windowRect.top <= mi.second.rcEmulated.top && + window.second.windowRect.right >= mi.second.rcEmulated.right && + window.second.windowRect.bottom >= mi.second.rcEmulated.bottom) + { + return window.first; + } + } + return nullptr; + } + auto removeWindow(std::map::iterator it) { if (it->second.presentationWindow) @@ -447,21 +467,7 @@ namespace Gdi HWND getFullscreenWindow() { 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 window.first; - } - } - return nullptr; + return g_fullscreenWindow; } int getRandomRgn(HDC hdc, HRGN hrgn, INT i) @@ -548,29 +554,6 @@ namespace Gdi RedrawWindow(hwnd, &emptyRect, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ERASENOW); } - void present(CompatRef dst, CompatRef src, - 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; - } - - auto mr = DDraw::PrimarySurface::getMonitorRect(); - for (auto window : g_windowZOrder) - { - if (window->presentationWindow && !window->visibleRegion.isEmpty()) - { - clipper->SetHWnd(&clipper, 0, window->presentationWindow); - dst->Blt(&dst, &mr, &src, nullptr, DDBLT_WAIT, nullptr); - } - } - } - void present(Gdi::Region excludeRegion) { D3dDdi::ScopedCriticalSection lock; @@ -644,6 +627,8 @@ namespace Gdi } } + g_fullscreenWindow = findFullscreenWindow(); + for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it) { auto& window = **it; diff --git a/DDrawCompat/Gdi/Window.h b/DDrawCompat/Gdi/Window.h index e2764a6..270bafe 100644 --- a/DDrawCompat/Gdi/Window.h +++ b/DDrawCompat/Gdi/Window.h @@ -1,9 +1,5 @@ #pragma once -#include - -#include -#include #include namespace Gdi @@ -31,8 +27,6 @@ namespace Gdi bool isTopLevelWindow(HWND hwnd); void onStyleChanged(HWND hwnd, WPARAM wParam); void onSyncPaint(HWND hwnd); - void present(CompatRef dst, CompatRef src, - CompatRef clipper); void present(Gdi::Region excludeRegion); void setDpiAwareness(HWND hwnd, bool dpiAware); void updateAll(); diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index 68da7f6..a2e1574 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -68,6 +68,7 @@ namespace ULONG g_monitorInfoUniqueness = 0; std::map g_monitorInfo; Win32::DisplayMode::MonitorInfo g_emptyMonitorInfo = {}; + RECT g_realBounds = {}; Compat::CriticalSection g_cs; BOOL WINAPI dwm8And16BitIsShimAppliedCallOut(); @@ -710,6 +711,7 @@ namespace g_monitorInfo[nullptr] = mi; } + UnionRect(&g_realBounds, &g_realBounds, &mi.rcReal); LOG_DEBUG << "updateMonitorInfoEnum: " << hMonitor << " " << mi; return TRUE; } @@ -721,6 +723,7 @@ namespace { g_monitorInfo.clear(); g_monitorInfoUniqueness = uniqueness; + g_realBounds = {}; EnumDisplayMonitors(nullptr, nullptr, &updateMonitorInfoEnum, 0); } } @@ -798,6 +801,13 @@ namespace Win32 return g_emptyMonitorInfo; } + RECT getRealBounds() + { + Compat::ScopedCriticalSection lock(g_cs); + updateMonitorInfo(); + return g_realBounds; + } + ULONG queryDisplaySettingsUniqueness() { return CALL_ORIG_FUNC(GdiEntry13)(); diff --git a/DDrawCompat/Win32/DisplayMode.h b/DDrawCompat/Win32/DisplayMode.h index 5f7cf04..a4eaf96 100644 --- a/DDrawCompat/Win32/DisplayMode.h +++ b/DDrawCompat/Win32/DisplayMode.h @@ -43,6 +43,7 @@ namespace Win32 const MonitorInfo& getMonitorInfo(HWND hwnd); const MonitorInfo& getMonitorInfo(POINT pt); const MonitorInfo& getMonitorInfo(const std::wstring& deviceName); + RECT getRealBounds(); ULONG queryDisplaySettingsUniqueness(); ULONG queryEmulatedDisplaySettingsUniqueness();