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(); SIZE ar = Config::displayAspectRatio.get();
if (Config::Settings::DisplayAspectRatio::APP == ar) if (Config::Settings::DisplayAspectRatio::APP == ar)
@ -79,7 +79,7 @@ namespace D3dDdi
return ar; return ar;
} }
Int2 Adapter::getAspectRatio() const SIZE Adapter::getAspectRatio() const
{ {
return getAspectRatio({}, {}); return getAspectRatio({}, {});
} }
@ -330,14 +330,14 @@ namespace D3dDdi
targetResolution *= abs(multiplier); targetResolution *= abs(multiplier);
const Int2 ar = getAspectRatio(appRes, displayRes); const SIZE ar = getAspectRatio(appRes, displayRes);
if (targetResolution.y * ar.x / ar.y <= targetResolution.x) 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 else
{ {
targetResolution.y = targetResolution.x * ar.y / ar.x; targetResolution.y = targetResolution.x * ar.cy / ar.cx;
} }
const auto scaleFactor = Float2(targetResolution) / Float2(appRes); const auto scaleFactor = Float2(targetResolution) / Float2(appRes);
@ -507,7 +507,7 @@ namespace D3dDdi
surfaceRepo.setRepository(repository); surfaceRepo.setRepository(repository);
if (isPrimary) if (isPrimary)
{ {
surfaceRepo.setAsPrimary(); surfaceRepo.setAsPrimaryRepo();
} }
} }
} }

View File

@ -35,7 +35,7 @@ namespace D3dDdi
operator HANDLE() const { return m_adapter; } operator HANDLE() const { return m_adapter; }
Int2 getAspectRatio() const; SIZE getAspectRatio() const;
const AdapterInfo& getInfo() const { return m_info; } const AdapterInfo& getInfo() const { return m_info; }
LUID getLuid() const { return m_luid; } LUID getLuid() const { return m_luid; }
const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); } const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); }
@ -61,7 +61,7 @@ namespace D3dDdi
template <typename Data> template <typename Data>
HRESULT getCaps(D3DDDICAPS_TYPE type, Data& data, UINT size = sizeof(Data)) const; 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> getFixedFormatOps(const AdapterInfo& info) const;
std::map<D3DDDIFORMAT, FORMATOP> getFormatOps() const; std::map<D3DDDIFORMAT, FORMATOP> getFormatOps() const;
Float2 getScaleFactor() const; Float2 getScaleFactor() const;

View File

@ -14,6 +14,7 @@
#include <D3dDdi/Resource.h> #include <D3dDdi/Resource.h>
#include <D3dDdi/ScopedCriticalSection.h> #include <D3dDdi/ScopedCriticalSection.h>
#include <D3dDdi/ShaderAssembler.h> #include <D3dDdi/ShaderAssembler.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/ScopedThreadLock.h> #include <DDraw/ScopedThreadLock.h>
#include <Gdi/DcFunctions.h> #include <Gdi/DcFunctions.h>
@ -221,8 +222,7 @@ namespace D3dDdi
{ {
LOG_FUNC("Device::setGdiResourceHandle", resource); LOG_FUNC("Device::setGdiResourceHandle", resource);
ScopedCriticalSection lock; ScopedCriticalSection lock;
if ((!resource && !g_gdiResource) || if (resource == g_gdiResourceHandle)
(g_gdiResource && resource == *g_gdiResource))
{ {
return; return;
} }
@ -393,6 +393,7 @@ namespace D3dDdi
{ {
g_gdiResourceHandle = nullptr; g_gdiResourceHandle = nullptr;
g_gdiResource = nullptr; g_gdiResource = nullptr;
DDraw::PrimarySurface::onLost();
} }
m_drawPrimitive.removeSysMemVertexBuffer(resource); m_drawPrimitive.removeSysMemVertexBuffer(resource);
m_state.onDestroyResource(res, resource); m_state.onDestroyResource(res, resource);

View File

@ -3,12 +3,14 @@
#include <string> #include <string>
#include <Windows.h> #include <Windows.h>
#include <VersionHelpers.h>
#include <Common/Log.h> #include <Common/Log.h>
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Common/ScopedSrwLock.h> #include <Common/ScopedSrwLock.h>
#include <Common/Time.h> #include <Common/Time.h>
#include <Config/Settings/ForceD3D9On12.h> #include <Config/Settings/ForceD3D9On12.h>
#include <Config/Settings/FullscreenMode.h>
#include <D3dDdi/Device.h> #include <D3dDdi/Device.h>
#include <D3dDdi/KernelModeThunks.h> #include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/Log/KernelModeThunksLog.h> #include <D3dDdi/Log/KernelModeThunksLog.h>
@ -398,7 +400,7 @@ namespace D3dDdi
{ {
static RECT rect = {}; static RECT rect = {};
HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow();
if (presentationWindow && presentationWindow == data.hWindow) if (presentationWindow)
{ {
Win32::ScopedDpiAwareness dpiAwareness; Win32::ScopedDpiAwareness dpiAwareness;
GetWindowRect(presentationWindow, &rect); GetWindowRect(presentationWindow, &rect);

View File

@ -25,38 +25,36 @@
#include <Gdi/Palette.h> #include <Gdi/Palette.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h> #include <Gdi/Window.h>
#include <Win32/DisplayMode.h>
namespace namespace
{ {
D3DDDI_RESOURCEFLAGS getResourceTypeFlags(); D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
RECT g_presentationRect = {};
bool g_enableConfig = true; bool g_enableConfig = true;
D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN; D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN;
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> g_msaaOverride = {}; 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; LONG width = rect.right;
const int srcHeight = srcRect.bottom - srcRect.top; LONG height = rect.bottom;
const int dstWidth = dstRect.right - dstRect.left; SIZE offset = {};
const int dstHeight = dstRect.bottom - dstRect.top;
RECT rect = { 0, 0, dstWidth, dstHeight }; if (width * ar.cy > height * ar.cx)
if (dstWidth * srcHeight > dstHeight * srcWidth)
{ {
rect.right = dstHeight * srcWidth / srcHeight; width = height * ar.cx / ar.cy;
offset.cx = (rect.right - width) / 2;
} }
else 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 { offset.cx, offset.cy, offset.cx + width, offset.cy + height };
return rect;
} }
LONG divCeil(LONG n, LONG d) LONG divCeil(LONG n, LONG d)
@ -151,11 +149,6 @@ namespace D3dDdi
throw HResultException(E_FAIL); throw HResultException(E_FAIL);
} }
if (m_origData.Flags.MatchGdiPrimary)
{
setFullscreenMode(true);
}
fixResourceData(); fixResourceData();
m_formatInfo = getFormatInfo(m_fixedData.Format); m_formatInfo = getFormatInfo(m_fixedData.Format);
m_formatConfig = m_fixedData.Format; m_formatConfig = m_fixedData.Format;
@ -209,11 +202,6 @@ namespace D3dDdi
Resource::~Resource() Resource::~Resource()
{ {
if (m_origData.Flags.MatchGdiPrimary)
{
setFullscreenMode(false);
}
if (m_msaaSurface.surface || m_msaaResolvedSurface.surface || m_lockRefSurface.surface) if (m_msaaSurface.surface || m_msaaResolvedSurface.surface || m_lockRefSurface.surface)
{ {
auto& repo = m_device.getRepo(); auto& repo = m_device.getRepo();
@ -225,7 +213,7 @@ namespace D3dDdi
HRESULT Resource::blt(D3DDDIARG_BLT data) 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; return S_OK;
} }
@ -243,11 +231,6 @@ namespace D3dDdi
return S_OK; return S_OK;
} }
if (m_fixedData.Flags.MatchGdiPrimary)
{
return presentationBlt(data, srcResource);
}
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool && if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool &&
D3DDDIPOOL_SYSTEMMEM == srcResource->m_fixedData.Pool) D3DDDIPOOL_SYSTEMMEM == srcResource->m_fixedData.Pool)
{ {
@ -570,7 +553,7 @@ namespace D3dDdi
void Resource::createGdiLockResource() void Resource::createGdiLockResource()
{ {
LOG_FUNC("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) if (!gdiSurfaceDesc.lpSurface)
{ {
return; return;
@ -716,7 +699,8 @@ namespace D3dDdi
{ {
if (m_fixedData.Flags.MatchGdiPrimary) 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)) if (!IsRectEmpty(&r))
{ {
for (auto& surface : m_fixedData.surfaceData) for (auto& surface : m_fixedData.surfaceData)
@ -1042,6 +1026,11 @@ namespace D3dDdi
return E_ABORT; return E_ABORT;
} }
if (g_readOnlyLock)
{
data.Flags.ReadOnly = true;
}
if (m_lockResource || m_isOversized) if (m_lockResource || m_isOversized)
{ {
return bltLock(data); return bltLock(data);
@ -1264,6 +1253,7 @@ namespace D3dDdi
HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource* srcResource) HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource* srcResource)
{ {
LOG_FUNC("Resource::presentationBlt", data, *srcResource); LOG_FUNC("Resource::presentationBlt", data, *srcResource);
m_device.flushPrimitives();
if (srcResource->m_lockResource) if (srcResource->m_lockResource)
{ {
if (srcResource->m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate && if (srcResource->m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate &&
@ -1279,10 +1269,7 @@ namespace D3dDdi
LONG srcWidth = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Width; LONG srcWidth = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Width;
LONG srcHeight = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Height; LONG srcHeight = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Height;
data.SrcRect = { 0, 0, srcWidth, srcHeight }; data.SrcRect = { 0, 0, srcWidth, srcHeight };
if (!IsRectEmpty(&g_presentationRect)) data.DstRect = applyDisplayAspectRatio(data.DstRect, m_device.getAdapter().getAspectRatio());
{
data.DstRect = g_presentationRect;
}
auto& repo = m_device.getRepo(); auto& repo = m_device.getRepo();
const auto& rtSurface = repo.getNextRenderTarget(srcWidth, srcHeight, srcResource->m_fixedData.Format); 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); copySubResourceRegion(*rt, rtIndex, rtRect, *srcResource, data.SrcSubResourceIndex, data.SrcRect);
} }
if (!IsRectEmpty(&g_presentationRect)) auto& mi = m_device.getAdapter().getMonitorInfo();
{ presentLayeredWindows(*rt, rtIndex, rtRect, Gdi::Window::getVisibleLayeredWindows(), mi.rcEmulated);
presentLayeredWindows(*rt, rtIndex, rtRect,
Gdi::Window::getVisibleLayeredWindows(), DDraw::PrimarySurface::getMonitorRect());
}
const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo(); const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo();
const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor; const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor;
@ -1338,11 +1322,8 @@ namespace D3dDdi
clearRectExterior(data.DstSubResourceIndex, data.DstRect); 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); return LOG_RESULT(S_OK);
} }
@ -1499,41 +1480,6 @@ namespace D3dDdi
g_formatOverride = format; 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) void Resource::setPaletteHandle(UINT paletteHandle)
{ {
m_paletteHandle = paletteHandle; m_paletteHandle = paletteHandle;
@ -1546,6 +1492,11 @@ namespace D3dDdi
resource.m_isPalettizedTextureUpToDate = false; 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) HRESULT Resource::shaderBlt(const D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource, UINT filter)
{ {
LOG_FUNC("Resource::shaderBlt", data, dstResource, srcResource); 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 || if (m_isSurfaceRepoResource || D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || D3DDDIFMT_P8 == m_fixedData.Format ||
m_fixedData.Flags.MatchGdiPrimary || m_fixedData.Flags.MatchGdiPrimary ||
!m_isPrimary && !m_origData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer || !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; return;
} }

View File

@ -59,7 +59,6 @@ namespace D3dDdi
void scaleRect(RECT& rect); void scaleRect(RECT& rect);
void setAsGdiResource(bool isGdiResource); void setAsGdiResource(bool isGdiResource);
void setAsPrimary(); void setAsPrimary();
void setFullscreenMode(bool isFullscreen);
void setPaletteHandle(UINT paletteHandle); void setPaletteHandle(UINT paletteHandle);
void setPalettizedTexture(Resource& resource); void setPalettizedTexture(Resource& resource);
HRESULT unlock(const D3DDDIARG_UNLOCK& data); HRESULT unlock(const D3DDDIARG_UNLOCK& data);
@ -68,6 +67,7 @@ namespace D3dDdi
static void enableConfig(bool enable); static void enableConfig(bool enable);
static void setFormatOverride(D3DDDIFORMAT format); static void setFormatOverride(D3DDDIFORMAT format);
static void setReadOnlyLock(bool readOnly);
private: private:
class Data : public D3DDDIARG_CREATERESOURCE2 class Data : public D3DDDIARG_CREATERESOURCE2

View File

@ -567,7 +567,7 @@ namespace D3dDdi
pt.y -= cur.hotspot.y; pt.y -= cur.hotspot.y;
RECT srcRect = { pt.x, pt.y, pt.x + cur.size.cx, pt.y + cur.size.cy }; 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 = {}; RECT clippedSrcRect = {};
IntersectRect(&clippedSrcRect, &srcRect, &monitorRect); IntersectRect(&clippedSrcRect, &srcRect, &monitorRect);
if (IsRectEmpty(&clippedSrcRect)) if (IsRectEmpty(&clippedSrcRect))

View File

@ -13,6 +13,7 @@
#include <D3dDdi/SurfaceRepository.h> #include <D3dDdi/SurfaceRepository.h>
#include <DDraw/DirectDrawSurface.h> #include <DDraw/DirectDrawSurface.h>
#include <DDraw/LogUsedResourceFormat.h> #include <DDraw/LogUsedResourceFormat.h>
#include <Gdi/VirtualScreen.h>
namespace namespace
{ {
@ -298,7 +299,7 @@ namespace D3dDdi
return getSurface(m_paletteTexture, 256, 1, D3DDDIFMT_A8R8G8B8, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource; return getSurface(m_paletteTexture, 256, 1, D3DDDIFMT_A8R8G8B8, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource;
} }
SurfaceRepository& SurfaceRepository::getPrimary() SurfaceRepository& SurfaceRepository::getPrimaryRepo()
{ {
return *g_primaryRepository; return *g_primaryRepository;
} }
@ -351,6 +352,44 @@ namespace D3dDdi
(D3DDDIFMT_P8 == format ? 0 : DDSCAPS_TEXTURE) | DDSCAPS_VIDEOMEMORY); (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) bool SurfaceRepository::hasAlpha(CompatRef<IDirectDrawSurface7> surface)
{ {
DDSURFACEDESC2 desc = {}; DDSURFACEDESC2 desc = {};
@ -392,7 +431,7 @@ namespace D3dDdi
} }
} }
void SurfaceRepository::setAsPrimary() void SurfaceRepository::setAsPrimaryRepo()
{ {
g_primaryRepository = this; g_primaryRepository = this;
} }

View File

@ -40,6 +40,7 @@ namespace D3dDdi
SurfaceRepository(); SurfaceRepository();
Cursor getCursor(HCURSOR cursor); Cursor getCursor(HCURSOR cursor);
CompatWeakPtr<IDirectDraw7> getDirectDraw() { return m_dd; }
Resource* getDitherTexture(DWORD size); Resource* getDitherTexture(DWORD size);
Resource* getLogicalXorTexture(); Resource* getLogicalXorTexture();
Resource* getPaletteTexture(); Resource* getPaletteTexture();
@ -52,12 +53,15 @@ namespace D3dDdi
Surface& getTempSurface(Surface& surface, DWORD width, DWORD height, Surface& getTempSurface(Surface& surface, DWORD width, DWORD height,
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1); D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1);
const Surface& getTempTexture(DWORD width, DWORD height, D3DDDIFORMAT format); 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 release(Surface& surface);
void setAsPrimary(); void setAsPrimaryRepo();
void setRepository(CompatWeakPtr<IDirectDraw7> dd) { m_dd = dd; } void setRepository(CompatWeakPtr<IDirectDraw7> dd) { m_dd = dd; }
static SurfaceRepository& get(const Adapter& adapter); static SurfaceRepository& get(const Adapter& adapter);
static SurfaceRepository& getPrimary(); static SurfaceRepository& getPrimaryRepo();
static bool inCreateSurface() { return s_inCreateSurface; } static bool inCreateSurface() { return s_inCreateSurface; }
static void enableSurfaceCheck(bool enable); static void enableSurfaceCheck(bool enable);
@ -86,6 +90,8 @@ namespace D3dDdi
std::map<D3DDDIFORMAT, Surface> m_textures; std::map<D3DDDIFORMAT, Surface> m_textures;
std::vector<Surface> m_releasedSurfaces; std::vector<Surface> m_releasedSurfaces;
Surface m_sysMemSurface; Surface m_sysMemSurface;
Surface m_windowedBackBuffer;
CompatPtr<IDirectDrawSurface7> m_windowedPrimary;
static bool s_inCreateSurface; static bool s_inCreateSurface;
}; };

View File

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

View File

@ -46,10 +46,10 @@ namespace
GetRandomRgn(dc, rgn, SYSRGN); GetRandomRgn(dc, rgn, SYSRGN);
CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc); CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc);
RECT primaryRect = DDraw::PrimarySurface::getMonitorRect(); auto& mi = DDraw::PrimarySurface::getMonitorInfo();
if (0 != primaryRect.left || 0 != primaryRect.top) 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); DWORD rgnSize = GetRegionData(rgn, 0, nullptr);

View File

@ -46,22 +46,15 @@ namespace
{ {
const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200; const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200;
CompatPtr<IDirectDrawSurface7> getBackBuffer();
CompatPtr<IDirectDrawSurface7> getLastSurface();
void onRelease(); void onRelease();
void presentationBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src); void updatePresentationParams();
void updatePresentationWindow();
CompatWeakPtr<IDirectDrawSurface7> g_defaultPrimary;
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer; CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_windowedBackBuffer; CompatWeakPtr<IDirectDrawSurface7> g_windowedBackBuffer;
CompatWeakPtr<IDirectDrawClipper> g_clipper; CompatWeakPtr<IDirectDrawClipper> g_clipper;
RECT g_monitorRect = {}; RECT g_monitorRect = {};
DDSURFACEDESC2 g_surfaceDesc = {};
DDraw::IReleaseNotifier g_releaseNotifier(onRelease); DDraw::IReleaseNotifier g_releaseNotifier(onRelease);
bool g_emulatedCursor = false;
bool g_isFullscreen = false; bool g_isFullscreen = false;
bool g_isExclusiveFullscreen = false; bool g_isExclusiveFullscreen = false;
DDraw::Surface* g_lastFlipSurface = nullptr; DDraw::Surface* g_lastFlipSurface = nullptr;
@ -83,127 +76,6 @@ namespace
HWND g_deviceWindow = nullptr; HWND g_deviceWindow = nullptr;
HWND* g_deviceWindowPtr = nullptr; HWND* g_deviceWindowPtr = nullptr;
HWND g_presentationWindow = 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() CompatPtr<IDirectDrawSurface7> getBackBuffer()
{ {
@ -272,27 +144,14 @@ namespace
{ {
LOG_FUNC("RealPrimarySurface::onRelease"); 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_frontBuffer = nullptr;
g_lastFlipSurface = nullptr; g_lastFlipSurface = nullptr;
g_windowedBackBuffer.release(); g_windowedBackBuffer.release();
g_clipper.release();
g_isFullscreen = false; g_isFullscreen = false;
g_surfaceDesc = {};
g_tagSurface = nullptr; g_tagSurface = nullptr;
g_deviceWindow = nullptr; g_deviceWindow = nullptr;
g_deviceWindowPtr = nullptr; g_deviceWindowPtr = nullptr;
g_monitorRect = {};
} }
void onRestore() void onRestore()
@ -301,29 +160,19 @@ namespace
desc.dwSize = sizeof(desc); desc.dwSize = sizeof(desc);
g_frontBuffer->GetSurfaceDesc(g_frontBuffer, &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)) if (g_isExclusiveFullscreen && 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP))
{ {
g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT); g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT);
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1); D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
} }
if (g_windowedBackBuffer)
{
g_windowedBackBuffer->Restore(g_windowedBackBuffer);
}
auto gdiResource = DDraw::PrimarySurface::getGdiResource(); auto gdiResource = DDraw::PrimarySurface::getGdiResource();
if (gdiResource) if (gdiResource)
{ {
D3dDdi::Device::setGdiResourceHandle(gdiResource); D3dDdi::Device::setGdiResourceHandle(gdiResource);
} }
updatePresentationWindow(); updatePresentationParams();
Compat::ScopedCriticalSection lock(g_presentCs); Compat::ScopedCriticalSection lock(g_presentCs);
g_isOverlayUpdatePending = false; g_isOverlayUpdatePending = false;
@ -337,6 +186,7 @@ namespace
void presentationBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src) void presentationBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src)
{ {
LOG_FUNC("RealPrimarySurface::presentationBlt", dst, src);
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
auto srcResource = D3dDdi::Device::findResource( auto srcResource = D3dDdi::Device::findResource(
DDraw::DirectDrawSurface::getDriverResourceHandle(src.get())); DDraw::DirectDrawSurface::getDriverResourceHandle(src.get()));
@ -350,16 +200,16 @@ namespace
D3DDDIARG_BLT blt = {}; D3DDDIARG_BLT blt = {};
blt.hSrcResource = *srcResource; blt.hSrcResource = *srcResource;
blt.SrcSubResourceIndex = DDraw::DirectDrawSurface::getSubResourceIndex(src.get()); blt.SrcSubResourceIndex = DDraw::DirectDrawSurface::getSubResourceIndex(src.get());
blt.SrcRect = DDraw::PrimarySurface::getMonitorRect(); blt.SrcRect = srcResource->getRect(blt.SrcSubResourceIndex);
blt.hDstResource = *dstResource; blt.hDstResource = *dstResource;
blt.DstSubResourceIndex = DDraw::DirectDrawSurface::getSubResourceIndex(dst.get()); blt.DstSubResourceIndex = DDraw::DirectDrawSurface::getSubResourceIndex(dst.get());
blt.DstRect = g_monitorRect; blt.DstRect = dstResource->getRect(blt.DstSubResourceIndex);
dstResource->presentationBlt(blt, srcResource); 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(); Gdi::VirtualScreen::update();
@ -391,19 +241,137 @@ namespace
Input::updateCursor(); Input::updateCursor();
}); });
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost()) if (src ? !g_isFullscreen : !g_presentationWindow)
{ {
Gdi::Window::present(nullptr); Gdi::Window::present(nullptr);
return; 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); 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) void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, bool isOverlayOnly)
{ {
present(src, isOverlayOnly);
{ {
Compat::ScopedCriticalSection lock(g_presentCs); Compat::ScopedCriticalSection lock(g_presentCs);
g_isOverlayUpdatePending = false; g_isOverlayUpdatePending = false;
@ -411,40 +379,28 @@ namespace
g_isUpdateReady = false; 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; g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1;
} }
void updatePresentationWindow() void updatePresentationParams()
{ {
LOG_FUNC("RealPrimarySurface::updatePresentationWindow"); LOG_FUNC("RealPrimarySurface::updatePresentationParams");
HWND fullscreenWindow = nullptr; HWND fullscreenWindow = nullptr;
if (isProcessActive()) if (isProcessActive())
{ {
if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow)) if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow))
{ {
if (g_isExclusiveFullscreen)
{
return;
}
fullscreenWindow = g_deviceWindow; fullscreenWindow = g_deviceWindow;
} }
else if (g_frontBuffer && DDraw::PrimarySurface::getPrimary() && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer))) else
{ {
fullscreenWindow = Gdi::Window::getFullscreenWindow(); fullscreenWindow = Gdi::Window::getFullscreenWindow();
} }
} }
else if (g_isFullscreen) else if (g_isFullscreen)
{ {
setFullscreenPresentationMode({});
return; return;
} }
@ -455,26 +411,27 @@ namespace
fullscreenPresentationWindow = Gdi::Window::getPresentationWindow(fullscreenWindow); fullscreenPresentationWindow = Gdi::Window::getPresentationWindow(fullscreenWindow);
} }
if (g_windowedBackBuffer)
{
auto resource = D3dDdi::Device::findResource(
DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer));
resource->setFullscreenMode(fullscreenPresentationWindow);
}
g_presentationWindow = fullscreenPresentationWindow; g_presentationWindow = fullscreenPresentationWindow;
if (g_presentationWindow) if (g_presentationWindow)
{ {
auto& mi = Win32::DisplayMode::getMonitorInfo(MonitorFromWindow(g_presentationWindow, MONITOR_DEFAULTTOPRIMARY));
auto& mr = mi.rcDpiAware;
Gdi::GuiThread::execute([&]() Gdi::GuiThread::execute([&]()
{ {
Win32::ScopedDpiAwareness dpiAwareness; 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); SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOSIZE);
CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, nullptr, 0, 0, CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, nullptr, 0, 0, mr.right - mr.left, mr.bottom - mr.top,
g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top,
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE); SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE);
}); });
setFullscreenPresentationMode(mi);
}
else
{
setFullscreenPresentationMode({});
} }
static HWND prevFullscreenWindow = nullptr; static HWND prevFullscreenWindow = nullptr;
@ -488,11 +445,6 @@ namespace
} }
} }
prevFullscreenWindow = fullscreenWindow; prevFullscreenWindow = fullscreenWindow;
if (Gdi::Cursor::isEmulated() != g_emulatedCursor)
{
Gdi::Cursor::setEmulated(g_emulatedCursor);
}
} }
unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/) unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/)
@ -521,11 +473,6 @@ namespace DDraw
HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw> dd) HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw> dd)
{ {
LOG_FUNC("RealPrimarySurface::create", &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 = {}; DDSURFACEDESC desc = {};
desc.dwSize = sizeof(desc); desc.dwSize = sizeof(desc);
@ -533,15 +480,11 @@ namespace DDraw
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
desc.dwBackBufferCount = g_isExclusiveFullscreen ? 2 : 1; desc.dwBackBufferCount = g_isExclusiveFullscreen ? 2 : 1;
auto prevIsFullscreen = g_isFullscreen;
g_isFullscreen = true;
CompatPtr<IDirectDrawSurface> surface; CompatPtr<IDirectDrawSurface> surface;
HRESULT result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr); HRESULT result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr);
if (DDERR_NOEXCLUSIVEMODE == result) if (DDERR_NOEXCLUSIVEMODE == result)
{ {
g_isFullscreen = false;
g_monitorRect = mi.rcDpiAware;
desc.dwFlags = DDSD_CAPS; desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
desc.dwBackBufferCount = 0; desc.dwBackBufferCount = 0;
@ -550,9 +493,7 @@ namespace DDraw
if (FAILED(result)) if (FAILED(result))
{ {
LOG_INFO << "ERROR: Failed to create the real primary surface: " << Compat::hex(result); LOG_ONCE("ERROR: Failed to create the real primary surface: " << Compat::hex(result));
g_monitorRect = prevMonitorRect;
g_isFullscreen = prevIsFullscreen;
return result; return result;
} }
@ -560,23 +501,13 @@ namespace DDraw
auto tagSurface = DDraw::TagSurface::get(ddLcl); auto tagSurface = DDraw::TagSurface::get(ddLcl);
if (!tagSurface) if (!tagSurface)
{ {
LOG_INFO << "ERROR: TagSurface not found"; LOG_ONCE("ERROR: TagSurface not found");
g_monitorRect = prevMonitorRect;
g_isFullscreen = prevIsFullscreen;
return DDERR_GENERIC; return DDERR_GENERIC;
} }
if (0 == desc.dwBackBufferCount) g_isFullscreen = 0 != desc.dwBackBufferCount;
{ auto& mi = PrimarySurface::getMonitorInfo();
g_windowedBackBuffer = createWindowedBackBuffer(*tagSurface, g_monitorRect = g_isFullscreen && g_isExclusiveFullscreen ? mi.rcReal : mi.rcDpiAware;
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_tagSurface = tagSurface; g_tagSurface = tagSurface;
g_frontBuffer = CompatPtr<IDirectDrawSurface7>::from(surface.get()).detach(); g_frontBuffer = CompatPtr<IDirectDrawSurface7>::from(surface.get()).detach();
@ -590,15 +521,6 @@ namespace DDraw
return DD_OK; 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) HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
{ {
const DWORD flipInterval = getFlipInterval(flags); const DWORD flipInterval = getFlipInterval(flags);
@ -658,20 +580,7 @@ namespace DDraw
lastOverlayCheckVsyncCount = vsyncCount; lastOverlayCheckVsyncCount = vsyncCount;
} }
bool isPresentationWindowUpdateNeeded = false; updatePresentationParams();
{
Compat::ScopedCriticalSection lock(g_presentCs);
isPresentationWindowUpdateNeeded =
0 != g_qpcUpdatePresentationWindow && Time::queryPerformanceCounter() - g_qpcUpdatePresentationWindow >= 0 ||
!isProcessActive();
}
if (isPresentationWindowUpdateNeeded)
{
g_qpcUpdatePresentationWindow = 0;
updatePresentationWindow();
}
bool isOverlayOnly = false; 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()); auto primary(DDraw::PrimarySurface::getPrimary());
CompatWeakPtr<IDirectDrawSurface7> src; 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; src = g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : primary;
} }
else
{
src = DDraw::PrimarySurface::getGdiPrimary();
}
updateNow(src, isOverlayOnly); updateNow(src, isOverlayOnly);
@ -753,11 +653,6 @@ namespace DDraw
return gammaControl->GetGammaRamp(gammaControl, 0, rampData); return gammaControl->GetGammaRamp(gammaControl, 0, rampData);
} }
RECT RealPrimarySurface::getMonitorRect()
{
return g_monitorRect;
}
HWND RealPrimarySurface::getPresentationWindow() HWND RealPrimarySurface::getPresentationWindow()
{ {
return g_presentationWindow; return g_presentationWindow;
@ -780,6 +675,11 @@ namespace DDraw
Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL); Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
} }
bool RealPrimarySurface::isExclusiveFullscreen()
{
return g_isExclusiveFullscreen;
}
bool RealPrimarySurface::isFullscreen() bool RealPrimarySurface::isFullscreen()
{ {
return g_isFullscreen; return g_isFullscreen;
@ -799,22 +699,21 @@ namespace DDraw
HRESULT RealPrimarySurface::restore() HRESULT RealPrimarySurface::restore()
{ {
LOG_FUNC("RealPrimarySurface::restore");
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;
if (g_defaultPrimary)
{
destroyDefaultPrimary();
createDefaultPrimary();
return DD_OK;
}
auto dd(g_tagSurface->getDD()); auto dd(g_tagSurface->getDD());
if (g_isFullscreen && FAILED(dd->TestCooperativeLevel(dd))) if (g_isFullscreen && FAILED(dd->TestCooperativeLevel(dd)))
{ {
return DDERR_NOEXCLUSIVEMODE; return DDERR_NOEXCLUSIVEMODE;
} }
release(); HRESULT result = g_frontBuffer->Restore(g_frontBuffer);
return create(*CompatPtr<IDirectDraw>::from(dd.get())); if (SUCCEEDED(result))
{
release();
return create(*CompatPtr<IDirectDraw>::from(dd.get()));
}
return LOG_RESULT(result);
} }
void RealPrimarySurface::scheduleOverlayUpdate() void RealPrimarySurface::scheduleOverlayUpdate()
@ -837,17 +736,6 @@ namespace DDraw
g_isUpdateReady = false; 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) HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
{ {
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;

View File

@ -13,23 +13,20 @@ namespace DDraw
{ {
public: public:
static HRESULT create(CompatRef<IDirectDraw> dd); static HRESULT create(CompatRef<IDirectDraw> dd);
static void destroyDefaultPrimary();
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags); static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static int flush(); static int flush();
static HWND getPresentationWindow();
static HRESULT getGammaRamp(DDGAMMARAMP* rampData); static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
static RECT getMonitorRect(); static HWND getPresentationWindow();
static CompatWeakPtr<IDirectDrawSurface7> getSurface(); static CompatWeakPtr<IDirectDrawSurface7> getSurface();
static HWND getTopmost(); static HWND getTopmost();
static void init(); static void init();
static bool isExclusiveFullscreen();
static bool isFullscreen(); static bool isFullscreen();
static bool isLost(); static bool isLost();
static void release(); static void release();
static HRESULT restore(); static HRESULT restore();
static void scheduleOverlayUpdate(); static void scheduleOverlayUpdate();
static void scheduleUpdate(); static void scheduleUpdate();
static void schedulePresentationWindowUpdate();
static void setEmulatedCursor(bool emulated);
static HRESULT setGammaRamp(DDGAMMARAMP* rampData); static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
static void setPresentationWindowTopmost(); static void setPresentationWindowTopmost();
static void setUpdateReady(); static void setUpdateReady();

View File

@ -17,7 +17,6 @@
namespace namespace
{ {
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface; CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
CompatWeakPtr<IDirectDrawSurface7> g_gdiPrimarySurface;
D3dDdi::Device* g_device = nullptr; D3dDdi::Device* g_device = nullptr;
HANDLE g_gdiDriverResource = nullptr; HANDLE g_gdiDriverResource = nullptr;
HANDLE g_gdiRuntimeResource = nullptr; HANDLE g_gdiRuntimeResource = nullptr;
@ -26,38 +25,7 @@ namespace
HWND g_deviceWindow = nullptr; HWND g_deviceWindow = nullptr;
HPALETTE g_palette = nullptr; HPALETTE g_palette = nullptr;
std::wstring g_deviceName; std::wstring g_deviceName;
RECT g_monitorRect = {}; Win32::DisplayMode::MonitorInfo g_monitorInfo = {};
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;
}
} }
namespace DDraw namespace DDraw
@ -71,7 +39,6 @@ namespace DDraw
g_gdiDriverResource = nullptr; g_gdiDriverResource = nullptr;
g_frontResource = nullptr; g_frontResource = nullptr;
g_primarySurface = nullptr; g_primarySurface = nullptr;
g_gdiPrimarySurface.release();
g_origCaps = 0; g_origCaps = 0;
g_deviceWindow = nullptr; g_deviceWindow = nullptr;
if (g_palette) if (g_palette)
@ -80,7 +47,7 @@ namespace DDraw
g_palette = nullptr; g_palette = nullptr;
} }
g_deviceName.clear(); g_deviceName.clear();
g_monitorRect = {}; g_monitorInfo = {};
s_palette = nullptr; s_palette = nullptr;
DDraw::RealPrimarySurface::release(); DDraw::RealPrimarySurface::release();
@ -91,17 +58,15 @@ namespace DDraw
HRESULT PrimarySurface::create(CompatRef<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface) HRESULT PrimarySurface::create(CompatRef<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface)
{ {
LOG_FUNC("PrimarySurface::create", &dd, desc, surface); LOG_FUNC("PrimarySurface::create", &dd, desc, surface);
DDraw::RealPrimarySurface::destroyDefaultPrimary();
auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName; auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName;
const auto& mi = Win32::DisplayMode::getMonitorInfo(deviceName); auto prevMonitorInfo = g_monitorInfo;
auto prevMonitorRect = g_monitorRect; g_monitorInfo = Win32::DisplayMode::getMonitorInfo(deviceName);
g_monitorRect = mi.rcEmulated;
HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd)); HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd));
if (FAILED(result)) if (FAILED(result))
{ {
g_monitorRect = prevMonitorRect; g_monitorInfo = prevMonitorInfo;
return LOG_RESULT(result); return LOG_RESULT(result);
} }
@ -112,26 +77,25 @@ namespace DDraw
auto data = privateData.get(); auto data = privateData.get();
desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
desc.dwWidth = g_monitorRect.right - g_monitorRect.left; desc.dwWidth = g_monitorInfo.rcEmulated.right - g_monitorInfo.rcEmulated.left;
desc.dwHeight = g_monitorRect.bottom - g_monitorRect.top; desc.dwHeight = g_monitorInfo.rcEmulated.bottom - g_monitorInfo.rcEmulated.top;
desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY | desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM); DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; 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)); result = Surface::create(dd, desc, surface, std::move(privateData));
if (FAILED(result)) if (FAILED(result))
{ {
LOG_INFO << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result); LOG_ONCE("ERROR: Failed to create the compat primary surface: " << Compat::hex(result));
g_monitorRect = prevMonitorRect;
RealPrimarySurface::release(); RealPrimarySurface::release();
g_monitorInfo = {};
return LOG_RESULT(result); return LOG_RESULT(result);
} }
g_deviceName = deviceName; g_deviceName = deviceName;
g_origCaps = origCaps; g_origCaps = origCaps;
g_deviceWindow = *DDraw::DirectDraw::getDeviceWindowPtr(dd.get()); g_deviceWindow = *DDraw::DirectDraw::getDeviceWindowPtr(dd.get());
g_gdiPrimarySurface = createGdiPrimarySurface(*CompatPtr<IDirectDraw>::from(&dd)).detach();
if (desc.ddpfPixelFormat.dwRGBBitCount <= 8) if (desc.ddpfPixelFormat.dwRGBBitCount <= 8)
{ {
@ -234,49 +198,9 @@ namespace DDraw
return surface; return surface;
} }
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getGdiPrimary() const Win32::DisplayMode::MonitorInfo& PrimarySurface::getMonitorInfo()
{ {
LOG_FUNC("PrimarySurface::getGdiPrimary"); return g_monitorInfo;
if (!g_primarySurface || !g_gdiPrimarySurface)
{
return LOG_RESULT(nullptr);
}
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
g_primarySurface->GetSurfaceDesc(g_primarySurface, &desc);
g_monitorRect = Win32::DisplayMode::getMonitorInfo(g_deviceName).rcMonitor;
g_monitorRect.right = g_monitorRect.left + desc.dwWidth;
g_monitorRect.bottom = g_monitorRect.top + desc.dwHeight;
desc = Gdi::VirtualScreen::getSurfaceDesc(g_monitorRect);
DDSURFACEDESC2 prevDesc = {};
prevDesc.dwSize = sizeof(prevDesc);
g_gdiPrimarySurface->Lock(g_gdiPrimarySurface, nullptr, &prevDesc, DDLOCK_WAIT, nullptr);
g_gdiPrimarySurface->Unlock(g_gdiPrimarySurface, nullptr);
if (desc.dwWidth != prevDesc.dwWidth ||
desc.dwHeight != prevDesc.dwHeight ||
desc.lPitch != prevDesc.lPitch ||
desc.lpSurface != prevDesc.lpSurface ||
0 != memcmp(&desc.ddpfPixelFormat, &prevDesc.ddpfPixelFormat, sizeof(desc.ddpfPixelFormat)))
{
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
if (FAILED(g_gdiPrimarySurface->SetSurfaceDesc(g_gdiPrimarySurface, &desc, 0)))
{
return LOG_RESULT(nullptr);
}
if (desc.dwWidth != prevDesc.dwWidth ||
desc.dwHeight != prevDesc.dwHeight)
{
DDraw::RealPrimarySurface::restore();
}
}
return LOG_RESULT(g_gdiPrimarySurface.get());
} }
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary() CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
@ -294,11 +218,6 @@ namespace DDraw
return g_gdiDriverResource; return g_gdiDriverResource;
} }
RECT PrimarySurface::getMonitorRect()
{
return g_monitorRect;
}
DWORD PrimarySurface::getOrigCaps() DWORD PrimarySurface::getOrigCaps()
{ {
return g_origCaps; return g_origCaps;
@ -316,10 +235,21 @@ namespace DDraw
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*); template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*);
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface7*); 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() void PrimarySurface::restore()
{ {
LOG_FUNC("PrimarySurface::restore"); LOG_FUNC("PrimarySurface::restore");
updatePalette();
Gdi::VirtualScreen::update(); Gdi::VirtualScreen::update();
g_primarySurface = m_surface; g_primarySurface = m_surface;
g_gdiRuntimeResource = DirectDrawSurface::getRuntimeResourceHandle(*g_primarySurface); g_gdiRuntimeResource = DirectDrawSurface::getRuntimeResourceHandle(*g_primarySurface);
@ -366,7 +296,7 @@ namespace DDraw
PALETTEENTRY entries[256] = {}; PALETTEENTRY entries[256] = {};
PrimarySurface::s_palette->GetEntries(s_palette, 0, 0, 256, entries); 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); Gdi::Palette::setHardwarePalette(entries);
} }

View File

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

View File

@ -35,7 +35,7 @@ namespace
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper)); Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper));
RECT monitorRect = DDraw::PrimarySurface::getMonitorRect(); RECT monitorRect = DDraw::PrimarySurface::getMonitorInfo().rcEmulated;
RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds(); RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds();
clipRgn.offset(monitorRect.left, monitorRect.top); clipRgn.offset(monitorRect.left, monitorRect.top);
clipRgn &= virtualScreenBounds; clipRgn &= virtualScreenBounds;

View File

@ -26,16 +26,15 @@ namespace
{ {
LOG_FUNC("ClipCursor", lpRect); LOG_FUNC("ClipCursor", lpRect);
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
BOOL result = CALL_ORIG_FUNC(ClipCursor)(lpRect); if (IsRectEmpty(&g_monitorClipRect))
if (!result || IsRectEmpty(&g_monitorClipRect))
{ {
return LOG_RESULT(result); return LOG_RESULT(CALL_ORIG_FUNC(ClipCursor)(lpRect));
} }
CALL_ORIG_FUNC(GetClipCursor)(&g_clipRect); g_clipRect = lpRect ? *lpRect : Win32::DisplayMode::getRealBounds();
RECT rect = intersectRect(g_clipRect, g_monitorClipRect); const RECT rect = intersectRect(g_clipRect, g_monitorClipRect);
CALL_ORIG_FUNC(ClipCursor)(&rect); CALL_ORIG_FUNC(ClipCursor)(&rect);
return LOG_RESULT(result); return LOG_RESULT(TRUE);
} }
BOOL WINAPI getClipCursor(LPRECT lpRect) BOOL WINAPI getClipCursor(LPRECT lpRect)
@ -180,13 +179,13 @@ namespace Gdi
void setEmulated(bool isEmulated) void setEmulated(bool isEmulated)
{ {
LOG_FUNC("Cursor::setEmulated", isEmulated);
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
if (isEmulated == g_isEmulated) if (isEmulated == g_isEmulated)
{ {
return; return;
} }
LOG_DEBUG << "Cursor::setEmulated: " << isEmulated;
g_isEmulated = isEmulated; g_isEmulated = isEmulated;
g_prevCursorInfo = {}; g_prevCursorInfo = {};
@ -197,7 +196,12 @@ namespace Gdi
void setMonitorClipRect(const RECT& rect) 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); Compat::ScopedCriticalSection lock(g_cs);
if (IsRectEmpty(&rect)) if (IsRectEmpty(&rect))
{ {

View File

@ -318,12 +318,7 @@ namespace
void fixPopupMenuPosition(WINDOWPOS& wp) void fixPopupMenuPosition(WINDOWPOS& wp)
{ {
RECT mr = DDraw::PrimarySurface::getMonitorRect(); RECT mr = Win32::DisplayMode::getMonitorInfo(MonitorFromWindow(wp.hwnd, MONITOR_DEFAULTTOPRIMARY)).rcEmulated;
if (IsRectEmpty(&mr))
{
return;
}
if (wp.flags & SWP_NOSIZE) if (wp.flags & SWP_NOSIZE)
{ {
RECT r = {}; RECT r = {};

View File

@ -6,6 +6,7 @@
#include <D3dDdi/Resource.h> #include <D3dDdi/Resource.h>
#include <D3dDdi/ScopedCriticalSection.h> #include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/DirectDraw.h> #include <DDraw/DirectDraw.h>
#include <DDraw/DirectDrawSurface.h>
#include <DDraw/LogUsedResourceFormat.h> #include <DDraw/LogUsedResourceFormat.h>
#include <DDraw/RealPrimarySurface.h> #include <DDraw/RealPrimarySurface.h>
#include <DDraw/ScopedThreadLock.h> #include <DDraw/ScopedThreadLock.h>
@ -147,13 +148,31 @@ namespace Gdi
} }
auto primary(DDraw::PrimarySurface::getPrimary()); auto primary(DDraw::PrimarySurface::getPrimary());
CompatPtr<IUnknown> ddUnk; if (!primary)
primary->GetDDInterface(primary, reinterpret_cast<void**>(&ddUnk.getRef())); {
CompatPtr<IDirectDraw7> dd(ddUnk); 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; CompatPtr<IDirectDrawSurface7> surface;
dd.get()->lpVtbl->CreateSurface(dd, &desc, &surface.getRef(), nullptr); dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
return surface; return surface;
} }
@ -248,7 +267,7 @@ namespace Gdi
if (g_isFullscreen) if (g_isFullscreen)
{ {
g_bounds = DDraw::PrimarySurface::getMonitorRect(); g_bounds = DDraw::PrimarySurface::getMonitorInfo().rcEmulated;
} }
else else
{ {

View File

@ -517,11 +517,12 @@ namespace
void onInitMenuPopup(HMENU menu) void onInitMenuPopup(HMENU menu)
{ {
RECT mr = DDraw::PrimarySurface::getMonitorRect(); auto deviceName = Win32::DisplayMode::getEmulatedDisplayMode().deviceName;
if (IsRectEmpty(&mr)) if (deviceName.empty())
{ {
return; return;
} }
const RECT& mr = Win32::DisplayMode::getMonitorInfo(deviceName).rcEmulated;
MENUINFO mi = {}; MENUINFO mi = {};
mi.cbSize = sizeof(mi); mi.cbSize = sizeof(mi);

View File

@ -125,6 +125,7 @@ namespace
std::map<HWND, Window> g_windows; std::map<HWND, Window> g_windows;
std::vector<Window*> g_windowZOrder; std::vector<Window*> g_windowZOrder;
HWND g_fullscreenWindow = nullptr;
bool bltWindow(const RECT& dst, const RECT& src, const Gdi::Region& clipRegion) bool bltWindow(const RECT& dst, const RECT& src, const Gdi::Region& clipRegion)
{ {
@ -141,6 +142,25 @@ namespace
return true; 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) auto removeWindow(std::map<HWND, Window>::iterator it)
{ {
if (it->second.presentationWindow) if (it->second.presentationWindow)
@ -447,21 +467,7 @@ namespace Gdi
HWND getFullscreenWindow() HWND getFullscreenWindow()
{ {
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
RECT mr = DDraw::PrimarySurface::getMonitorRect(); return g_fullscreenWindow;
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;
} }
int getRandomRgn(HDC hdc, HRGN hrgn, INT i) 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); 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) void present(Gdi::Region excludeRegion)
{ {
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
@ -644,6 +627,8 @@ namespace Gdi
} }
} }
g_fullscreenWindow = findFullscreenWindow();
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it) for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{ {
auto& window = **it; auto& window = **it;

View File

@ -1,9 +1,5 @@
#pragma once #pragma once
#include <ddraw.h>
#include <Common/CompatWeakPtr.h>
#include <Common/CompatRef.h>
#include <Gdi/Region.h> #include <Gdi/Region.h>
namespace Gdi namespace Gdi
@ -31,8 +27,6 @@ namespace Gdi
bool isTopLevelWindow(HWND hwnd); bool isTopLevelWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam); void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd); void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion); void present(Gdi::Region excludeRegion);
void setDpiAwareness(HWND hwnd, bool dpiAware); void setDpiAwareness(HWND hwnd, bool dpiAware);
void updateAll(); void updateAll();

View File

@ -68,6 +68,7 @@ namespace
ULONG g_monitorInfoUniqueness = 0; ULONG g_monitorInfoUniqueness = 0;
std::map<HMONITOR, Win32::DisplayMode::MonitorInfo> g_monitorInfo; std::map<HMONITOR, Win32::DisplayMode::MonitorInfo> g_monitorInfo;
Win32::DisplayMode::MonitorInfo g_emptyMonitorInfo = {}; Win32::DisplayMode::MonitorInfo g_emptyMonitorInfo = {};
RECT g_realBounds = {};
Compat::CriticalSection g_cs; Compat::CriticalSection g_cs;
BOOL WINAPI dwm8And16BitIsShimAppliedCallOut(); BOOL WINAPI dwm8And16BitIsShimAppliedCallOut();
@ -710,6 +711,7 @@ namespace
g_monitorInfo[nullptr] = mi; g_monitorInfo[nullptr] = mi;
} }
UnionRect(&g_realBounds, &g_realBounds, &mi.rcReal);
LOG_DEBUG << "updateMonitorInfoEnum: " << hMonitor << " " << mi; LOG_DEBUG << "updateMonitorInfoEnum: " << hMonitor << " " << mi;
return TRUE; return TRUE;
} }
@ -721,6 +723,7 @@ namespace
{ {
g_monitorInfo.clear(); g_monitorInfo.clear();
g_monitorInfoUniqueness = uniqueness; g_monitorInfoUniqueness = uniqueness;
g_realBounds = {};
EnumDisplayMonitors(nullptr, nullptr, &updateMonitorInfoEnum, 0); EnumDisplayMonitors(nullptr, nullptr, &updateMonitorInfoEnum, 0);
} }
} }
@ -798,6 +801,13 @@ namespace Win32
return g_emptyMonitorInfo; return g_emptyMonitorInfo;
} }
RECT getRealBounds()
{
Compat::ScopedCriticalSection lock(g_cs);
updateMonitorInfo();
return g_realBounds;
}
ULONG queryDisplaySettingsUniqueness() ULONG queryDisplaySettingsUniqueness()
{ {
return CALL_ORIG_FUNC(GdiEntry13)(); return CALL_ORIG_FUNC(GdiEntry13)();

View File

@ -43,6 +43,7 @@ namespace Win32
const MonitorInfo& getMonitorInfo(HWND hwnd); const MonitorInfo& getMonitorInfo(HWND hwnd);
const MonitorInfo& getMonitorInfo(POINT pt); const MonitorInfo& getMonitorInfo(POINT pt);
const MonitorInfo& getMonitorInfo(const std::wstring& deviceName); const MonitorInfo& getMonitorInfo(const std::wstring& deviceName);
RECT getRealBounds();
ULONG queryDisplaySettingsUniqueness(); ULONG queryDisplaySettingsUniqueness();
ULONG queryEmulatedDisplaySettingsUniqueness(); ULONG queryEmulatedDisplaySettingsUniqueness();