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:
parent
c344ec3408
commit
d5a89cad94
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
|
@ -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 = {};
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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)();
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user