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

Reworked presentation handling during lost primary suface

Fixes video problems in Prince of Persia 3D (issue #273).
This commit is contained in:
narzoul 2024-03-31 17:30:03 +02:00
parent c344ec3408
commit d5a89cad94
24 changed files with 371 additions and 550 deletions

View File

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

View File

@ -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 <typename Data>
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<D3DDDIFORMAT, FORMATOP> getFixedFormatOps(const AdapterInfo& info) const;
std::map<D3DDDIFORMAT, FORMATOP> getFormatOps() const;
Float2 getScaleFactor() const;

View File

@ -14,6 +14,7 @@
#include <D3dDdi/Resource.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <D3dDdi/ShaderAssembler.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/ScopedThreadLock.h>
#include <Gdi/DcFunctions.h>
@ -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);

View File

@ -3,12 +3,14 @@
#include <string>
#include <Windows.h>
#include <VersionHelpers.h>
#include <Common/Log.h>
#include <Common/Hook.h>
#include <Common/ScopedSrwLock.h>
#include <Common/Time.h>
#include <Config/Settings/ForceD3D9On12.h>
#include <Config/Settings/FullscreenMode.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/Log/KernelModeThunksLog.h>
@ -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);

View File

@ -25,38 +25,36 @@
#include <Gdi/Palette.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
#include <Win32/DisplayMode.h>
namespace
{
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
RECT g_presentationRect = {};
bool g_enableConfig = true;
D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN;
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> 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;
}

View File

@ -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

View File

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

View File

@ -13,6 +13,7 @@
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/DirectDrawSurface.h>
#include <DDraw/LogUsedResourceFormat.h>
#include <Gdi/VirtualScreen.h>
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<IDirectDrawSurface7> SurfaceRepository::getWindowedBackBuffer(DWORD width, DWORD height)
{
return getSurface(m_windowedBackBuffer, width, height, D3DDDIFMT_X8R8G8B8,
DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY).surface;
}
CompatWeakPtr<IDirectDrawSurface7> 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<IDirectDrawSurface7> SurfaceRepository::getWindowedSrc(RECT rect)
{
CompatPtr<IDirectDrawSurface7> src;
auto desc = Gdi::VirtualScreen::getSurfaceDesc(rect);
m_dd->CreateSurface(m_dd, &desc, &src.getRef(), nullptr);
return src;
}
bool SurfaceRepository::hasAlpha(CompatRef<IDirectDrawSurface7> surface)
{
DDSURFACEDESC2 desc = {};
@ -392,7 +431,7 @@ namespace D3dDdi
}
}
void SurfaceRepository::setAsPrimary()
void SurfaceRepository::setAsPrimaryRepo()
{
g_primaryRepository = this;
}

View File

@ -40,6 +40,7 @@ namespace D3dDdi
SurfaceRepository();
Cursor getCursor(HCURSOR cursor);
CompatWeakPtr<IDirectDraw7> 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<IDirectDrawSurface7> getWindowedBackBuffer(DWORD width, DWORD height);
CompatWeakPtr<IDirectDrawSurface7> getWindowedPrimary();
CompatPtr<IDirectDrawSurface7> getWindowedSrc(RECT rect);
void release(Surface& surface);
void setAsPrimary();
void setAsPrimaryRepo();
void setRepository(CompatWeakPtr<IDirectDraw7> 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<D3DDDIFORMAT, Surface> m_textures;
std::vector<Surface> m_releasedSurfaces;
Surface m_sysMemSurface;
Surface m_windowedBackBuffer;
CompatPtr<IDirectDrawSurface7> m_windowedPrimary;
static bool s_inCreateSurface;
};

View File

@ -142,10 +142,6 @@ namespace
if (wasFullscreen != isFullscreen)
{
tagSurface->setFullscreenWindow(isFullscreen ? hWnd : nullptr);
if (DDraw::RealPrimarySurface::getSurface())
{
DDraw::RealPrimarySurface::restore();
}
}
}
}

View File

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

View File

@ -46,22 +46,15 @@ namespace
{
const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200;
CompatPtr<IDirectDrawSurface7> getBackBuffer();
CompatPtr<IDirectDrawSurface7> getLastSurface();
void onRelease();
void presentationBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src);
void updatePresentationWindow();
CompatWeakPtr<IDirectDrawSurface7> g_defaultPrimary;
void updatePresentationParams();
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_windowedBackBuffer;
CompatWeakPtr<IDirectDrawClipper> 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<IDirectDrawSurface7> 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<std::wstring*>(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<IDirectDraw> dd(tagSurface->getDD());
CompatPtr<IDirectDrawSurface> primary;
dd.get()->lpVtbl->CreateSurface(dd, &desc, &primary.getRef(), nullptr);
g_defaultPrimary = CompatPtr<IDirectDrawSurface7>(primary).detach();
}
else
{
CompatPtr<IDirectDraw7> dd;
if (FAILED(CALL_ORIG_PROC(DirectDrawCreateEx)(
lpGUID, reinterpret_cast<void**>(&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<IDirectDrawSurface7> 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<IDirectDrawSurface7> 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<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> 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<IDirectDrawSurface7> src, bool isOverlayOnly)
void present(CompatWeakPtr<IDirectDrawSurface7> 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<IDirectDrawSurface7> frontBuffer;
CompatPtr<IDirectDrawSurface7> backBuffer;
CompatPtr<IDirectDrawSurface7> 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<IDirectDrawSurface7> 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<IDirectDraw> dd)
{
LOG_FUNC("RealPrimarySurface::create", &dd);
DDraw::ScopedThreadLock lock;
const auto& mi = Win32::DisplayMode::getMonitorInfo(
D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::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<IDirectDrawSurface> 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<IDirectDrawSurface7>::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<IDirectDrawSurface7> 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<IDirectDrawSurface7> 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<IDirectDraw>::from(dd.get()));
HRESULT result = g_frontBuffer->Restore(g_frontBuffer);
if (SUCCEEDED(result))
{
release();
return create(*CompatPtr<IDirectDraw>::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;

View File

@ -13,23 +13,20 @@ namespace DDraw
{
public:
static HRESULT create(CompatRef<IDirectDraw> dd);
static void destroyDefaultPrimary();
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static int flush();
static HWND getPresentationWindow();
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
static RECT getMonitorRect();
static HWND getPresentationWindow();
static CompatWeakPtr<IDirectDrawSurface7> 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();

View File

@ -17,7 +17,6 @@
namespace
{
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
CompatWeakPtr<IDirectDrawSurface7> 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<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 = 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<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface)
{
LOG_FUNC("PrimarySurface::create", &dd, desc, surface);
DDraw::RealPrimarySurface::destroyDefaultPrimary();
auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::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<IDirectDraw>::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<IDirectDraw>::from(&dd)).detach();
if (desc.ddpfPixelFormat.dwRGBBitCount <= 8)
{
@ -234,49 +198,9 @@ namespace DDraw
return surface;
}
CompatWeakPtr<IDirectDrawSurface7> 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<IDirectDrawSurface7> 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);
}

View File

@ -5,6 +5,7 @@
#include <Common/CompatPtr.h>
#include <Common/CompatRef.h>
#include <DDraw/Surfaces/Surface.h>
#include <Win32/DisplayMode.h>
namespace DDraw
{
@ -21,12 +22,12 @@ namespace DDraw
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
static CompatPtr<IDirectDrawSurface7> getBackBuffer();
static CompatPtr<IDirectDrawSurface7> getLastSurface();
static RECT getMonitorRect();
static CompatWeakPtr<IDirectDrawSurface7> getGdiPrimary();
static const Win32::DisplayMode::MonitorInfo& getMonitorInfo();
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
static HANDLE getFrontResource();
static HANDLE getGdiResource();
static DWORD getOrigCaps();
static void onLost();
static void updatePalette();
template <typename TSurface>

View File

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

View File

@ -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))
{

View File

@ -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 = {};

View File

@ -6,6 +6,7 @@
#include <D3dDdi/Resource.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/DirectDraw.h>
#include <DDraw/DirectDrawSurface.h>
#include <DDraw/LogUsedResourceFormat.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/ScopedThreadLock.h>
@ -147,13 +148,31 @@ namespace Gdi
}
auto primary(DDraw::PrimarySurface::getPrimary());
CompatPtr<IUnknown> ddUnk;
primary->GetDDInterface(primary, reinterpret_cast<void**>(&ddUnk.getRef()));
CompatPtr<IDirectDraw7> 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<IDirectDrawSurface7> 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
{

View File

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

View File

@ -125,6 +125,7 @@ namespace
std::map<HWND, Window> g_windows;
std::vector<Window*> 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<HWND, Window>::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<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
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;
}
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;

View File

@ -1,9 +1,5 @@
#pragma once
#include <ddraw.h>
#include <Common/CompatWeakPtr.h>
#include <Common/CompatRef.h>
#include <Gdi/Region.h>
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<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion);
void setDpiAwareness(HWND hwnd, bool dpiAware);
void updateAll();

View File

@ -68,6 +68,7 @@ namespace
ULONG g_monitorInfoUniqueness = 0;
std::map<HMONITOR, Win32::DisplayMode::MonitorInfo> 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)();

View File

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