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

Moved GDI synchronization to UMD level

Fixes deadlock when starting Rayman 2 (issue #30).
This commit is contained in:
narzoul 2019-07-29 19:12:37 +02:00
parent 7b6b7c911c
commit e83371afed
27 changed files with 240 additions and 347 deletions

View File

@ -6,7 +6,9 @@
#include "DDraw/ScopedThreadLock.h" #include "DDraw/ScopedThreadLock.h"
struct _D3DDDI_ADAPTERCALLBACKS; struct _D3DDDI_ADAPTERCALLBACKS;
struct _D3DDDI_ADAPTERFUNCS;
struct _D3DDDI_DEVICEALLBACKS; struct _D3DDDI_DEVICEALLBACKS;
struct _D3DDDI_DEVICEFUNCS;
template <typename Vtable> template <typename Vtable>
class ScopedVtableFuncLock : public DDraw::ScopedThreadLock {}; class ScopedVtableFuncLock : public DDraw::ScopedThreadLock {};
@ -14,9 +16,15 @@ class ScopedVtableFuncLock : public DDraw::ScopedThreadLock {};
template <> template <>
class ScopedVtableFuncLock<_D3DDDI_ADAPTERCALLBACKS> : public D3dDdi::ScopedCriticalSection {}; class ScopedVtableFuncLock<_D3DDDI_ADAPTERCALLBACKS> : public D3dDdi::ScopedCriticalSection {};
template <>
class ScopedVtableFuncLock<_D3DDDI_ADAPTERFUNCS> : public D3dDdi::ScopedCriticalSection {};
template <> template <>
class ScopedVtableFuncLock<_D3DDDI_DEVICEALLBACKS> : public D3dDdi::ScopedCriticalSection {}; class ScopedVtableFuncLock<_D3DDDI_DEVICEALLBACKS> : public D3dDdi::ScopedCriticalSection {};
template <>
class ScopedVtableFuncLock<_D3DDDI_DEVICEFUNCS> : public D3dDdi::ScopedCriticalSection {};
template <typename Vtable, int instanceId = 0> template <typename Vtable, int instanceId = 0>
class VtableHookVisitor class VtableHookVisitor
{ {

View File

@ -6,34 +6,13 @@
#include "D3dDdi/Device.h" #include "D3dDdi/Device.h"
#include "D3dDdi/DeviceFuncs.h" #include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/Resource.h" #include "D3dDdi/Resource.h"
#include "Gdi/AccessGuard.h"
namespace namespace
{ {
HANDLE g_gdiResourceHandle = nullptr; HANDLE g_gdiResourceHandle = nullptr;
D3dDdi::Resource* g_gdiResource = nullptr;
bool g_isReadOnlyGdiLockEnabled = false; bool g_isReadOnlyGdiLockEnabled = false;
class RenderGuard : public Gdi::DDrawAccessGuard
{
public:
RenderGuard(D3dDdi::Device& device, Gdi::Access access)
: Gdi::DDrawAccessGuard(access)
, m_device(device)
{
device.prepareForRendering();
}
RenderGuard(D3dDdi::Device& device, Gdi::Access access, HANDLE resource, UINT subResourceIndex = UINT_MAX)
: Gdi::DDrawAccessGuard(access, g_gdiResourceHandle == resource)
, m_device(device)
{
device.prepareForRendering(resource, subResourceIndex, Gdi::ACCESS_READ == access);
}
private:
D3dDdi::Device& m_device;
};
template <typename Container, typename Predicate> template <typename Container, typename Predicate>
void erase_if(Container& container, Predicate pred) void erase_if(Container& container, Predicate pred)
{ {
@ -69,14 +48,13 @@ namespace D3dDdi
{ {
return it->second.blt(data); return it->second.blt(data);
} }
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex); prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex, true);
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource, data.DstSubResourceIndex);
return m_origVtable.pfnBlt(m_device, &data); return m_origVtable.pfnBlt(m_device, &data);
} }
HRESULT Device::clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect) HRESULT Device::clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE); prepareForRendering();
return m_origVtable.pfnClear(m_device, &data, numRect, rect); return m_origVtable.pfnClear(m_device, &data, numRect, rect);
} }
@ -87,7 +65,6 @@ namespace D3dDdi
{ {
return it->second.colorFill(data); return it->second.colorFill(data);
} }
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE, data.hResource, data.SubResourceIndex);
return m_origVtable.pfnColorFill(m_device, &data); return m_origVtable.pfnColorFill(m_device, &data);
} }
@ -118,6 +95,17 @@ namespace D3dDdi
HRESULT Device::destroyResource(HANDLE resource) HRESULT Device::destroyResource(HANDLE resource)
{ {
if (g_gdiResource && resource == *g_gdiResource)
{
D3DDDIARG_LOCK lock = {};
lock.hResource = *g_gdiResource;
g_gdiResource->lock(lock);
D3DDDIARG_UNLOCK unlock = {};
unlock.hResource = *g_gdiResource;
g_gdiResource->unlock(unlock);
}
if (resource == m_sharedPrimary) if (resource == m_sharedPrimary)
{ {
D3DKMTReleaseProcessVidPnSourceOwners(GetCurrentProcess()); D3DKMTReleaseProcessVidPnSourceOwners(GetCurrentProcess());
@ -145,6 +133,7 @@ namespace D3dDdi
if (resource == g_gdiResourceHandle) if (resource == g_gdiResourceHandle)
{ {
g_gdiResourceHandle = nullptr; g_gdiResourceHandle = nullptr;
g_gdiResource = nullptr;
} }
} }
@ -153,55 +142,50 @@ namespace D3dDdi
HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data) HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE); prepareForRendering();
return m_origVtable.pfnDrawIndexedPrimitive(m_device, &data); return m_origVtable.pfnDrawIndexedPrimitive(m_device, &data);
} }
HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data, HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data,
UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer) UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE); prepareForRendering();
return m_origVtable.pfnDrawIndexedPrimitive2(m_device, &data, indicesSize, indexBuffer, flagBuffer); return m_origVtable.pfnDrawIndexedPrimitive2(m_device, &data, indicesSize, indexBuffer, flagBuffer);
} }
HRESULT Device::drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer) HRESULT Device::drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE); prepareForRendering();
return m_origVtable.pfnDrawPrimitive(m_device, &data, flagBuffer); return m_origVtable.pfnDrawPrimitive(m_device, &data, flagBuffer);
} }
HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data) HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE); prepareForRendering();
return m_origVtable.pfnDrawPrimitive2(m_device, &data); return m_origVtable.pfnDrawPrimitive2(m_device, &data);
} }
HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info, HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info,
const FLOAT* patch) const FLOAT* patch)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE); prepareForRendering();
return m_origVtable.pfnDrawRectPatch(m_device, &data, info, patch); return m_origVtable.pfnDrawRectPatch(m_device, &data, info, patch);
} }
HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info, HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info,
const FLOAT* patch) const FLOAT* patch)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE); prepareForRendering();
return m_origVtable.pfnDrawTriPatch(m_device, &data, info, patch); return m_origVtable.pfnDrawTriPatch(m_device, &data, info, patch);
} }
HRESULT Device::lock(D3DDDIARG_LOCK& data) HRESULT Device::lock(D3DDDIARG_LOCK& data)
{ {
Gdi::DDrawAccessGuard accessGuard(
(data.Flags.ReadOnly || g_isReadOnlyGdiLockEnabled) ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE,
data.hResource == g_gdiResourceHandle);
auto it = m_resources.find(data.hResource); auto it = m_resources.find(data.hResource);
if (it != m_resources.end()) if (it != m_resources.end())
{ {
return it->second.lock(data); return it->second.lock(data);
} }
return m_origVtable.pfnLock(m_device, &data); return m_origVtable.pfnLock(m_device, &data);
} }
@ -217,53 +201,40 @@ namespace D3dDdi
HRESULT Device::present(const D3DDDIARG_PRESENT& data) HRESULT Device::present(const D3DDDIARG_PRESENT& data)
{ {
RenderGuard renderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex); prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex, true);
return m_origVtable.pfnPresent(m_device, &data); return m_origVtable.pfnPresent(m_device, &data);
} }
HRESULT Device::present1(D3DDDIARG_PRESENT1& data) HRESULT Device::present1(D3DDDIARG_PRESENT1& data)
{ {
bool isGdiResourceInvolved = false;
for (UINT i = 0; i < data.SrcResources && !isGdiResourceInvolved; ++i)
{
isGdiResourceInvolved = data.phSrcResources[i].hResource == g_gdiResourceHandle;
}
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, isGdiResourceInvolved);
for (UINT i = 0; i < data.SrcResources; ++i) for (UINT i = 0; i < data.SrcResources; ++i)
{ {
const bool isReadOnly = true; prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex, true);
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex, isReadOnly);
} }
return m_origVtable.pfnPresent1(m_device, &data); return m_origVtable.pfnPresent1(m_device, &data);
} }
HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data) HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data)
{ {
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource); prepareForRendering(data.hDstResource, UINT_MAX, false);
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource); prepareForRendering(data.hSrcResource, UINT_MAX, true);
return m_origVtable.pfnTexBlt(m_device, &data); return m_origVtable.pfnTexBlt(m_device, &data);
} }
HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data) HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data)
{ {
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource); prepareForRendering(data.hDstResource, UINT_MAX, false);
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource); prepareForRendering(data.hSrcResource, UINT_MAX, true);
return m_origVtable.pfnTexBlt1(m_device, &data); return m_origVtable.pfnTexBlt1(m_device, &data);
} }
HRESULT Device::unlock(const D3DDDIARG_UNLOCK& data) HRESULT Device::unlock(const D3DDDIARG_UNLOCK& data)
{ {
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, data.hResource == g_gdiResourceHandle);
auto it = m_resources.find(data.hResource); auto it = m_resources.find(data.hResource);
if (it != m_resources.end()) if (it != m_resources.end())
{ {
return it->second.unlock(data); return it->second.unlock(data);
} }
return m_origVtable.pfnUnlock(m_device, &data); return m_origVtable.pfnUnlock(m_device, &data);
} }
@ -289,6 +260,11 @@ namespace D3dDdi
m_dirtyTextures.emplace(std::make_pair(resource, subResourceIndex), resource); m_dirtyTextures.emplace(std::make_pair(resource, subResourceIndex), resource);
} }
Resource* Device::getGdiResource()
{
return g_gdiResource;
}
void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly) void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly)
{ {
auto it = m_resources.find(resource); auto it = m_resources.find(resource);
@ -366,6 +342,11 @@ namespace D3dDdi
void Device::setGdiResourceHandle(HANDLE resource) void Device::setGdiResourceHandle(HANDLE resource)
{ {
g_gdiResourceHandle = resource; g_gdiResourceHandle = resource;
g_gdiResource = getResource(resource);
if (g_gdiResource)
{
g_gdiResource->resync();
}
} }
void Device::setReadOnlyGdiLock(bool enable) void Device::setReadOnlyGdiLock(bool enable)

View File

@ -56,6 +56,7 @@ namespace D3dDdi
static Device& get(HANDLE device); static Device& get(HANDLE device);
static void remove(HANDLE device); static void remove(HANDLE device);
static Resource* getGdiResource();
static Resource* getResource(HANDLE resource); static Resource* getResource(HANDLE resource);
static void setGdiResourceHandle(HANDLE resource); static void setGdiResourceHandle(HANDLE resource);
static void setReadOnlyGdiLock(bool enable); static void setReadOnlyGdiLock(bool enable);

View File

@ -467,6 +467,18 @@ namespace D3dDdi
return m_device.getOrigVtable().pfnBlt(m_device, &data); return m_device.getOrigVtable().pfnBlt(m_device, &data);
} }
void Resource::resync()
{
if (!m_lockData.empty() && m_lockData[0].isSysMemUpToDate)
{
copySubResource(*this, *m_lockResource, 0);
if (!m_lockData[0].isVidMemUpToDate)
{
setVidMemUpToDate(0, true);
}
}
}
void Resource::setLockResource(Resource* lockResource) void Resource::setLockResource(Resource* lockResource)
{ {
if (!m_lockResource == !lockResource) if (!m_lockResource == !lockResource)

View File

@ -30,6 +30,7 @@ namespace D3dDdi
void destroy(); void destroy();
HRESULT lock(D3DDDIARG_LOCK& data); HRESULT lock(D3DDDIARG_LOCK& data);
void prepareForRendering(UINT subResourceIndex, bool isReadOnly); void prepareForRendering(UINT subResourceIndex, bool isReadOnly);
void resync();
void setLockResource(Resource* lockResource); void setLockResource(Resource* lockResource);
void setRootSurface(DDraw::Surface* rootSurface); void setRootSurface(DDraw::Surface* rootSurface);
HRESULT unlock(const D3DDDIARG_UNLOCK& data); HRESULT unlock(const D3DDDIARG_UNLOCK& data);

View File

@ -1,5 +1,3 @@
#include <atomic>
#include <ddraw.h> #include <ddraw.h>
#include "Common/Hook.h" #include "Common/Hook.h"
@ -14,8 +12,6 @@ namespace
{ {
Win32::FontSmoothing::SystemSettings g_fontSmoothingSettings = {}; Win32::FontSmoothing::SystemSettings g_fontSmoothingSettings = {};
WNDPROC g_origDdWndProc = nullptr; WNDPROC g_origDdWndProc = nullptr;
std::atomic<DWORD> g_activateAppThreadId = 0;
HWND g_delayedFocusWnd = nullptr;
void activateApp() void activateApp()
{ {
@ -37,7 +33,6 @@ namespace
{ {
case WM_ACTIVATEAPP: case WM_ACTIVATEAPP:
{ {
DDraw::RealPrimarySurface::disableUpdates();
isDisplayChangeNotificationEnabled = false; isDisplayChangeNotificationEnabled = false;
if (TRUE == wParam) if (TRUE == wParam)
{ {
@ -48,17 +43,9 @@ namespace
deactivateApp(); deactivateApp();
} }
g_activateAppThreadId = GetCurrentThreadId();
g_delayedFocusWnd = nullptr;
LRESULT result = g_origDdWndProc(hwnd, uMsg, wParam, lParam); LRESULT result = g_origDdWndProc(hwnd, uMsg, wParam, lParam);
g_activateAppThreadId = 0;
if (g_delayedFocusWnd)
{
CALL_ORIG_FUNC(SetFocus)(g_delayedFocusWnd);
}
isDisplayChangeNotificationEnabled = true; isDisplayChangeNotificationEnabled = true;
DDraw::RealPrimarySurface::enableUpdates();
return LOG_RESULT(result); return LOG_RESULT(result);
} }
@ -75,39 +62,12 @@ namespace
return LOG_RESULT(g_origDdWndProc(hwnd, uMsg, wParam, lParam)); return LOG_RESULT(g_origDdWndProc(hwnd, uMsg, wParam, lParam));
} }
HWND WINAPI setFocus(HWND hWnd)
{
if (GetCurrentThreadId() == g_activateAppThreadId && IsWindow(hWnd))
{
g_delayedFocusWnd = hWnd;
return GetFocus();
}
return CALL_ORIG_FUNC(SetFocus)(hWnd);
}
BOOL WINAPI showWindow(HWND hWnd, int nCmdShow)
{
if (GetCurrentThreadId() == g_activateAppThreadId && IsWindow(hWnd))
{
BOOL result = IsWindowVisible(hWnd);
ShowWindowAsync(hWnd, nCmdShow);
return result;
}
return CALL_ORIG_FUNC(ShowWindow)(hWnd, nCmdShow);
}
} }
namespace DDraw namespace DDraw
{ {
namespace ActivateAppHandler namespace ActivateAppHandler
{ {
void installHooks()
{
HOOK_FUNCTION(user32, SetFocus, setFocus);
HOOK_FUNCTION(user32, ShowWindow, showWindow);
}
void setCooperativeLevel(HWND hwnd, DWORD flags) void setCooperativeLevel(HWND hwnd, DWORD flags)
{ {
static bool isDdWndProcHooked = false; static bool isDdWndProcHooked = false;

View File

@ -8,7 +8,6 @@ namespace DDraw
{ {
namespace ActivateAppHandler namespace ActivateAppHandler
{ {
void installHooks();
void setCooperativeLevel(HWND hwnd, DWORD flags); void setCooperativeLevel(HWND hwnd, DWORD flags);
} }
} }

View File

@ -1,6 +1,5 @@
#include "Common/CompatRef.h" #include "Common/CompatRef.h"
#include "Common/Log.h" #include "Common/Log.h"
#include "DDraw/ActivateAppHandler.h"
#include "DDraw/DirectDraw.h" #include "DDraw/DirectDraw.h"
#include "DDraw/DirectDrawClipper.h" #include "DDraw/DirectDrawClipper.h"
#include "DDraw/DirectDrawGammaControl.h" #include "DDraw/DirectDrawGammaControl.h"
@ -95,7 +94,6 @@ namespace DDraw
void installHooks(CompatPtr<IDirectDraw7> dd7) void installHooks(CompatPtr<IDirectDraw7> dd7)
{ {
RealPrimarySurface::init(); RealPrimarySurface::init();
ActivateAppHandler::installHooks();
Win32::Registry::unsetValue( Win32::Registry::unsetValue(
HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\DirectDraw", "EmulationOnly"); HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\DirectDraw", "EmulationOnly");

View File

@ -34,7 +34,7 @@ namespace
bool g_stopUpdateThread = false; bool g_stopUpdateThread = false;
HANDLE g_updateThread = nullptr; HANDLE g_updateThread = nullptr;
unsigned int g_disableUpdateCount = 0; bool g_isGdiUpdatePending = false;
bool g_isFlipPending = false; bool g_isFlipPending = false;
bool g_isPresentPending = false; bool g_isPresentPending = false;
bool g_isUpdatePending = false; bool g_isUpdatePending = false;
@ -91,7 +91,7 @@ namespace
} }
} }
Gdi::GdiAccessGuard gdiAccessGuard(Gdi::ACCESS_READ, !primaryRegion); Gdi::AccessGuard accessGuard(Gdi::ACCESS_READ, !primaryRegion);
HWND presentationWindow = windowPair.second->getPresentationWindow(); HWND presentationWindow = windowPair.second->getPresentationWindow();
HDC dc = GetWindowDC(presentationWindow); HDC dc = GetWindowDC(presentationWindow);
RECT rect = windowPair.second->getWindowRect(); RECT rect = windowPair.second->getWindowRect();
@ -369,7 +369,6 @@ namespace
Gdi::Region primaryRegion(D3dDdi::KernelModeThunks::getMonitorRect()); Gdi::Region primaryRegion(D3dDdi::KernelModeThunks::getMonitorRect());
bltToWindowViaGdi(&primaryRegion); bltToWindowViaGdi(&primaryRegion);
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(src.get()));
if (Win32::DisplayMode::getBpp() <= 8) if (Win32::DisplayMode::getBpp() <= 8)
{ {
HDC paletteConverterDc = nullptr; HDC paletteConverterDc = nullptr;
@ -437,12 +436,19 @@ namespace
void updateNowIfNotBusy() void updateNowIfNotBusy()
{ {
if (g_isGdiUpdatePending)
{
g_qpcLastUpdate = Time::queryPerformanceCounter();
g_isUpdatePending = true;
g_isGdiUpdatePending = false;
}
auto primary(DDraw::PrimarySurface::getPrimary()); auto primary(DDraw::PrimarySurface::getPrimary());
RECT emptyRect = {}; RECT emptyRect = {};
HRESULT result = primary ? primary->BltFast(primary, 0, 0, primary, &emptyRect, DDBLTFAST_WAIT) : DD_OK; HRESULT result = primary ? primary->BltFast(primary, 0, 0, primary, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
g_waitingForPrimaryUnlock = DDERR_SURFACEBUSY == result || DDERR_LOCKEDSURFACES == result; g_waitingForPrimaryUnlock = DDERR_SURFACEBUSY == result || DDERR_LOCKEDSURFACES == result;
if (!g_waitingForPrimaryUnlock && DDERR_SURFACELOST != result) if (!g_waitingForPrimaryUnlock)
{ {
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate); const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
updateNow(primary, msSinceLastUpdate > Config::delayedFlipModeTimeout ? 0 : 1); updateNow(primary, msSinceLastUpdate > Config::delayedFlipModeTimeout ? 0 : 1);
@ -472,7 +478,7 @@ namespace
waitForVBlank = Time::qpcToMs(Time::queryPerformanceCounter() - waitForVBlank = Time::qpcToMs(Time::queryPerformanceCounter() -
D3dDdi::KernelModeThunks::getQpcLastVerticalBlank()) >= msPresentDelayAfterVBlank; D3dDdi::KernelModeThunks::getQpcLastVerticalBlank()) >= msPresentDelayAfterVBlank;
if (waitForVBlank && g_isUpdatePending && 0 == g_disableUpdateCount && !isPresentPending()) if (waitForVBlank && (g_isUpdatePending || g_isGdiUpdatePending) && !isPresentPending())
{ {
updateNowIfNotBusy(); updateNowIfNotBusy();
} }
@ -532,18 +538,6 @@ namespace DDraw
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw4>); template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw4>);
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw7>); template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw7>);
void RealPrimarySurface::disableUpdates()
{
DDraw::ScopedThreadLock lock;
--g_disableUpdateCount;
}
void RealPrimarySurface::enableUpdates()
{
DDraw::ScopedThreadLock lock;
++g_disableUpdateCount;
}
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags) HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
{ {
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;
@ -587,6 +581,11 @@ namespace DDraw
return DD_OK; return DD_OK;
} }
void RealPrimarySurface::gdiUpdate()
{
g_isGdiUpdatePending = true;
}
HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData) HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData)
{ {
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;

View File

@ -15,9 +15,8 @@ namespace DDraw
template <typename DirectDraw> template <typename DirectDraw>
static HRESULT create(CompatRef<DirectDraw> dd); static HRESULT create(CompatRef<DirectDraw> dd);
static void disableUpdates();
static void enableUpdates();
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags); static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static void gdiUpdate();
static HRESULT getGammaRamp(DDGAMMARAMP* rampData); static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
static CompatWeakPtr<IDirectDrawSurface7> getSurface(); static CompatWeakPtr<IDirectDrawSurface7> getSurface();
static void init(); static void init();

View File

@ -8,11 +8,14 @@
#include "DDraw/RealPrimarySurface.h" #include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurfaceImpl.h" #include "DDraw/Surfaces/PrimarySurfaceImpl.h"
#include "Gdi/VirtualScreen.h"
namespace namespace
{ {
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface; CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
std::vector<CompatWeakPtr<IDirectDrawSurface7>> g_lockBackBuffers;
HANDLE g_gdiResourceHandle = nullptr; HANDLE g_gdiResourceHandle = nullptr;
HANDLE g_frontResource = nullptr;
DWORD g_origCaps = 0; DWORD g_origCaps = 0;
} }
@ -23,11 +26,18 @@ namespace DDraw
LOG_FUNC("PrimarySurface::~PrimarySurface"); LOG_FUNC("PrimarySurface::~PrimarySurface");
g_gdiResourceHandle = nullptr; g_gdiResourceHandle = nullptr;
g_frontResource = nullptr;
g_primarySurface = nullptr; g_primarySurface = nullptr;
g_origCaps = 0; g_origCaps = 0;
s_palette = nullptr; s_palette = nullptr;
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries)); ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
for (auto& lockBuffer : g_lockBackBuffers)
{
lockBuffer.release();
}
g_lockBackBuffers.clear();
DDraw::RealPrimarySurface::release(); DDraw::RealPrimarySurface::release();
} }
@ -50,7 +60,9 @@ namespace DDraw
desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
desc.ddpfPixelFormat = dm.ddpfPixelFormat; desc.ddpfPixelFormat = dm.ddpfPixelFormat;
result = Surface::create(dd, desc, surface, std::make_unique<PrimarySurface>()); auto privateData(std::make_unique<PrimarySurface>());
auto data = privateData.get();
result = Surface::create(dd, desc, surface, std::move(privateData));
if (FAILED(result)) if (FAILED(result))
{ {
Compat::Log() << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result); Compat::Log() << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result);
@ -58,11 +70,32 @@ namespace DDraw
return result; return result;
} }
g_primarySurface = CompatPtr<IDirectDrawSurface7>::from(surface);
g_origCaps = origCaps; g_origCaps = origCaps;
onRestore(); data->m_lockSurface.release();
data->m_attachedLockSurfaces.clear();
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
CompatPtr<TSurface> lockSurface;
dd->CreateSurface(&dd, &desc, &lockSurface.getRef(), nullptr);
data->m_lockSurface = lockSurface;
if (g_origCaps & DDSCAPS_FLIP)
{
for (std::size_t i = 0; i < desc.dwBackBufferCount; ++i)
{
CompatPtr<TSurface> lockBuffer;
dd->CreateSurface(&dd, &desc, &lockBuffer.getRef(), nullptr);
if (lockBuffer)
{
g_lockBackBuffers.push_back(CompatPtr<IDirectDrawSurface7>::from(lockBuffer.get()).detach());
data->m_attachedLockSurfaces.push_back(g_lockBackBuffers.back());
}
}
}
data->restore();
return DD_OK; return DD_OK;
} }
@ -152,6 +185,11 @@ namespace DDraw
return g_primarySurface; return g_primarySurface;
} }
HANDLE PrimarySurface::getFrontResource()
{
return g_frontResource;
}
DWORD PrimarySurface::getOrigCaps() DWORD PrimarySurface::getOrigCaps()
{ {
return g_origCaps; return g_origCaps;
@ -169,10 +207,28 @@ namespace DDraw
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*); template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*);
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface7*); template bool PrimarySurface::isGdiSurface(IDirectDrawSurface7*);
void PrimarySurface::onRestore() void PrimarySurface::restore()
{ {
LOG_FUNC("PrimarySurface::restore");
clearResources();
Gdi::VirtualScreen::update();
auto desc = Gdi::VirtualScreen::getSurfaceDesc(D3dDdi::KernelModeThunks::getMonitorRect());
desc.dwFlags &= ~DDSD_CAPS;
m_lockSurface->SetSurfaceDesc(m_lockSurface, &desc, 0);
g_primarySurface = m_surface;
g_gdiResourceHandle = getRuntimeResourceHandle(*g_primarySurface); g_gdiResourceHandle = getRuntimeResourceHandle(*g_primarySurface);
D3dDdi::Device::setGdiResourceHandle(*reinterpret_cast<HANDLE*>(g_gdiResourceHandle)); updateFrontResource();
D3dDdi::Device::setGdiResourceHandle(g_frontResource);
Surface::restore();
}
void PrimarySurface::updateFrontResource()
{
g_frontResource = getDriverResourceHandle(*g_primarySurface);
} }
void PrimarySurface::updatePalette() void PrimarySurface::updatePalette()

View File

@ -21,13 +21,17 @@ namespace DDraw
static CompatPtr<IDirectDrawSurface7> getBackBuffer(); static CompatPtr<IDirectDrawSurface7> getBackBuffer();
static CompatPtr<IDirectDrawSurface7> getLastSurface(); static CompatPtr<IDirectDrawSurface7> getLastSurface();
static CompatWeakPtr<IDirectDrawSurface7> getPrimary(); static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
static HANDLE getFrontResource();
static DWORD getOrigCaps(); static DWORD getOrigCaps();
static void onRestore();
static void updatePalette(); static void updatePalette();
template <typename TSurface> template <typename TSurface>
static bool isGdiSurface(TSurface* surface); static bool isGdiSurface(TSurface* surface);
static void updateFrontResource();
virtual void restore();
static CompatWeakPtr<IDirectDrawPalette> s_palette; static CompatWeakPtr<IDirectDrawPalette> s_palette;
static PALETTEENTRY s_paletteEntries[256]; static PALETTEENTRY s_paletteEntries[256];

View File

@ -134,6 +134,7 @@ namespace DDraw
return result; return result;
} }
PrimarySurface::updateFrontResource();
return RealPrimarySurface::flip(surfaceTargetOverride, dwFlags); return RealPrimarySurface::flip(surfaceTargetOverride, dwFlags);
} }
@ -208,11 +209,7 @@ namespace DDraw
result = RealPrimarySurface::restore(); result = RealPrimarySurface::restore();
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
result = SurfaceImpl::Restore(This); return SurfaceImpl::Restore(This);
if (SUCCEEDED(result))
{
PrimarySurface::onRestore();
}
} }
} }
return result; return result;

View File

@ -213,8 +213,6 @@ namespace DDraw
return LOG_RESULT(nullptr); return LOG_RESULT(nullptr);
} }
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = desc.ddpfPixelFormat;
desc.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM); desc.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;

View File

@ -34,7 +34,7 @@ namespace DDraw
SurfaceImpl<TSurface>* getImpl() const; SurfaceImpl<TSurface>* getImpl() const;
void clearResources(); void clearResources();
void restore(); virtual void restore();
protected: protected:
static void attach(CompatRef<IDirectDrawSurface7> dds, std::unique_ptr<Surface> privateData); static void attach(CompatRef<IDirectDrawSurface7> dds, std::unique_ptr<Surface> privateData);
@ -48,6 +48,11 @@ namespace DDraw
std::unique_ptr<SurfaceImpl<IDirectDrawSurface4>> m_impl4; std::unique_ptr<SurfaceImpl<IDirectDrawSurface4>> m_impl4;
std::unique_ptr<SurfaceImpl<IDirectDrawSurface7>> m_impl7; std::unique_ptr<SurfaceImpl<IDirectDrawSurface7>> m_impl7;
CompatWeakPtr<IDirectDrawSurface7> m_surface;
std::vector<Surface*> m_attachedSurfaces;
CompatPtr<IDirectDrawSurface7> m_lockSurface;
std::vector<CompatWeakPtr<IDirectDrawSurface7>> m_attachedLockSurfaces;
private: private:
template <typename TDirectDrawSurface> template <typename TDirectDrawSurface>
friend class SurfaceImpl; friend class SurfaceImpl;
@ -61,9 +66,5 @@ namespace DDraw
DWORD m_refCount; DWORD m_refCount;
Surface* m_rootSurface; Surface* m_rootSurface;
CompatWeakPtr<IDirectDrawSurface7> m_surface;
std::vector<Surface*> m_attachedSurfaces;
CompatPtr<IDirectDrawSurface7> m_lockSurface;
std::vector<CompatWeakPtr<IDirectDrawSurface7>> m_attachedLockSurfaces;
}; };
} }

View File

@ -5,7 +5,6 @@
#include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/Surface.h" #include "DDraw/Surfaces/Surface.h"
#include "DDraw/Surfaces/SurfaceImpl.h" #include "DDraw/Surfaces/SurfaceImpl.h"
#include "Gdi/AccessGuard.h"
namespace namespace
{ {
@ -36,9 +35,6 @@ namespace DDraw
{ {
return DDERR_WASSTILLDRAWING; return DDERR_WASSTILLDRAWING;
} }
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
return s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); return s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
} }
@ -46,8 +42,6 @@ namespace DDraw
HRESULT SurfaceImpl<TSurface>::BltFast( HRESULT SurfaceImpl<TSurface>::BltFast(
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans) TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
{ {
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
return s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans); return s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
} }
@ -81,18 +75,11 @@ namespace DDraw
template <typename TSurface> template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC) HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
{ {
HRESULT result = DD_OK; HRESULT result = s_origVtable.GetDC(This, lphDC);
{
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = s_origVtable.GetDC(This, lphDC);
}
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
RealPrimarySurface::waitForFlip(m_data); RealPrimarySurface::waitForFlip(m_data);
} }
return result; return result;
} }
@ -143,8 +130,6 @@ namespace DDraw
return DDERR_WASSTILLDRAWING; return DDERR_WASSTILLDRAWING;
} }
Gdi::DDrawAccessGuard accessGuard((dwFlags & DDLOCK_READONLY) ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE,
PrimarySurface::isGdiSurface(This));
HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent); HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
if (DDERR_SURFACELOST == result) if (DDERR_SURFACELOST == result)
{ {
@ -164,7 +149,6 @@ namespace DDraw
template <typename TSurface> template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::ReleaseDC(TSurface* This, HDC hDC) HRESULT SurfaceImpl<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
{ {
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
return s_origVtable.ReleaseDC(This, hDC); return s_origVtable.ReleaseDC(This, hDC);
} }
@ -188,7 +172,6 @@ namespace DDraw
template <typename TSurface> template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect) HRESULT SurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
{ {
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
return s_origVtable.Unlock(This, lpRect); return s_origVtable.Unlock(This, lpRect);
} }

View File

@ -1,151 +1,43 @@
#define WIN32_LEAN_AND_MEAN #include "D3dDdi/Device.h"
#include "D3dDdi/Resource.h"
#include <Windows.h>
#include "D3dDdi/KernelModeThunks.h"
#include "DDraw/RealPrimarySurface.h" #include "DDraw/RealPrimarySurface.h"
#include "DDraw/ScopedThreadLock.h"
#include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h"
#include "Gdi/AccessGuard.h" #include "Gdi/AccessGuard.h"
#include "Gdi/VirtualScreen.h"
namespace
{
struct Accessor
{
DWORD readAccessDepth;
DWORD writeAccessDepth;
bool isSynced;
Accessor(bool isSynced) : readAccessDepth(0), writeAccessDepth(0), isSynced(isSynced) {}
};
Accessor g_ddrawAccessor(false);
Accessor g_gdiAccessor(true);
bool g_isSyncing = false;
bool synchronize(Gdi::User user);
void beginAccess(Gdi::User user, Gdi::Access access)
{
LOG_FUNC("beginAccess", user, access);
Accessor& accessor = Gdi::USER_DDRAW == user ? g_ddrawAccessor : g_gdiAccessor;
DWORD& accessDepth = Gdi::ACCESS_READ == access ? accessor.readAccessDepth : accessor.writeAccessDepth;
++accessDepth;
accessor.isSynced = accessor.isSynced || synchronize(user);
if (accessor.isSynced && Gdi::ACCESS_WRITE == access)
{
Accessor& otherAccessor = Gdi::USER_DDRAW == user ? g_gdiAccessor : g_ddrawAccessor;
otherAccessor.isSynced = false;
}
LOG_RESULT(accessor.isSynced);
}
void endAccess(Gdi::User user, Gdi::Access access)
{
LOG_FUNC("endAccess", user, access);
Accessor& accessor = Gdi::USER_DDRAW == user ? g_ddrawAccessor : g_gdiAccessor;
DWORD& accessDepth = Gdi::ACCESS_READ == access ? accessor.readAccessDepth : accessor.writeAccessDepth;
--accessDepth;
if (Gdi::USER_DDRAW == user &&
0 == g_ddrawAccessor.readAccessDepth && 0 == g_ddrawAccessor.writeAccessDepth &&
(0 != g_gdiAccessor.readAccessDepth || 0 != g_gdiAccessor.writeAccessDepth))
{
g_gdiAccessor.isSynced = g_gdiAccessor.isSynced || synchronize(Gdi::USER_GDI);
if (g_gdiAccessor.isSynced && 0 != g_gdiAccessor.writeAccessDepth)
{
g_ddrawAccessor.isSynced = false;
}
}
if (0 == accessDepth && Gdi::ACCESS_WRITE == access && Gdi::USER_GDI == user &&
0 == g_ddrawAccessor.writeAccessDepth)
{
auto primary(DDraw::PrimarySurface::getPrimary());
if (!primary || DDraw::PrimarySurface::isGdiSurface(primary.get()))
{
DDraw::RealPrimarySurface::update();
}
}
}
bool synchronize(Gdi::User user)
{
auto ddrawSurface(DDraw::PrimarySurface::getGdiSurface());
if (!ddrawSurface)
{
return false;
}
auto gdiSurface(Gdi::VirtualScreen::createSurface(D3dDdi::KernelModeThunks::getMonitorRect()));
if (!gdiSurface)
{
return false;
}
bool result = true;
g_isSyncing = true;
if (Gdi::USER_DDRAW == user)
{
CompatPtr<IDirectDrawClipper> clipper;
ddrawSurface->GetClipper(ddrawSurface, &clipper.getRef());
ddrawSurface->SetClipper(ddrawSurface, nullptr);
result = SUCCEEDED(ddrawSurface.get()->lpVtbl->Blt(
ddrawSurface, nullptr, gdiSurface, nullptr, DDBLT_WAIT, nullptr));
ddrawSurface->SetClipper(ddrawSurface, clipper);
}
else
{
result = SUCCEEDED(gdiSurface.get()->lpVtbl->BltFast(
gdiSurface, 0, 0, ddrawSurface, nullptr, DDBLTFAST_WAIT));
}
g_isSyncing = false;
return result;
}
}
namespace Gdi namespace Gdi
{ {
AccessGuard::AccessGuard(User user, Access access, bool condition) AccessGuard::AccessGuard(Access access, bool condition)
: m_user(user) : m_access(access)
, m_access(access)
, m_condition(condition) , m_condition(condition)
{ {
if (m_condition) if (m_condition)
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
if (g_isSyncing) auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{ {
m_condition = false; D3DDDIARG_LOCK lockData = {};
return; lockData.hResource = gdiResource;
} lockData.Flags.ReadOnly = ACCESS_READ == access;
gdiResource->lock(lockData);
beginAccess(user, access); D3DDDIARG_UNLOCK unlockData = {};
unlockData.hResource = gdiResource;
gdiResource->unlock(unlockData);
}
} }
} }
AccessGuard::~AccessGuard() AccessGuard::~AccessGuard()
{ {
if (m_condition) if (m_condition && ACCESS_WRITE == m_access)
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
endAccess(m_user, m_access); auto gdiResource = D3dDdi::Device::getGdiResource();
if (!gdiResource || DDraw::PrimarySurface::getFrontResource() == *gdiResource)
{
DDraw::RealPrimarySurface::gdiUpdate();
}
} }
} }
DDrawAccessGuard::DDrawAccessGuard(Access access, bool condition)
: AccessGuard(USER_DDRAW, access, condition)
{
}
GdiAccessGuard::GdiAccessGuard(Access access, bool condition)
: AccessGuard(USER_GDI, access, condition)
{
}
} }

View File

@ -1,5 +1,10 @@
#pragma once #pragma once
namespace D3dDdi
{
class Resource;
}
namespace Gdi namespace Gdi
{ {
enum Access enum Access
@ -8,33 +13,14 @@ namespace Gdi
ACCESS_WRITE ACCESS_WRITE
}; };
enum User
{
USER_DDRAW,
USER_GDI
};
class AccessGuard class AccessGuard
{ {
protected: public:
AccessGuard(User user, Access access, bool condition = true); AccessGuard(Access access, bool condition = true);
~AccessGuard(); ~AccessGuard();
private: private:
User m_user;
Access m_access; Access m_access;
bool m_condition; bool m_condition;
}; };
class DDrawAccessGuard : public AccessGuard
{
public:
DDrawAccessGuard(Access access, bool condition = true);
};
class GdiAccessGuard : public AccessGuard
{
public:
GdiAccessGuard(Access access, bool condition = true);
};
} }

View File

@ -4,7 +4,7 @@
#include "Common/Hook.h" #include "Common/Hook.h"
#include "Common/Time.h" #include "Common/Time.h"
#include "DDraw/ScopedThreadLock.h" #include "D3dDdi/ScopedCriticalSection.h"
#include "Gdi/Caret.h" #include "Gdi/Caret.h"
extern "C" IMAGE_DOS_HEADER __ImageBase; extern "C" IMAGE_DOS_HEADER __ImageBase;
@ -34,7 +34,6 @@ namespace
{ {
if (OBJID_CARET == idObject) if (OBJID_CARET == idObject)
{ {
DDraw::ScopedThreadLock lock;
updateCaret(GetWindowThreadProcessId(hwnd, nullptr)); updateCaret(GetWindowThreadProcessId(hwnd, nullptr));
} }
} }
@ -64,7 +63,7 @@ namespace
void updateCaret(DWORD threadId) void updateCaret(DWORD threadId)
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
if (g_caret.isDrawn) if (g_caret.isDrawn)
{ {
drawCaret(); drawCaret();
@ -87,7 +86,7 @@ namespace Gdi
{ {
void blink() void blink()
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
if (!g_caret.isVisible) if (!g_caret.isVisible)
{ {
return; return;

View File

@ -5,7 +5,7 @@
#include "Common/Hook.h" #include "Common/Hook.h"
#include "Common/Log.h" #include "Common/Log.h"
#include "Common/ScopedCriticalSection.h" #include "Common/ScopedCriticalSection.h"
#include "DDraw/ScopedThreadLock.h" #include "D3dDdi/ScopedCriticalSection.h"
#include "Gdi/Dc.h" #include "Gdi/Dc.h"
#include "Gdi/DcCache.h" #include "Gdi/DcCache.h"
#include "Gdi/Gdi.h" #include "Gdi/Gdi.h"
@ -185,7 +185,7 @@ namespace Gdi
return nullptr; return nullptr;
} }
DDraw::ScopedThreadLock ddLock; D3dDdi::ScopedCriticalSection driverLock;
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
auto it = g_origDcToCompatDc.find(origDc); auto it = g_origDcToCompatDc.find(origDc);
if (it != g_origDcToCompatDc.end()) if (it != g_origDcToCompatDc.end())

View File

@ -105,7 +105,7 @@ namespace
if (hasDisplayDcArg(params...)) if (hasDisplayDcArg(params...))
{ {
const bool isReadOnlyAccess = !hasDisplayDcArg(getDestinationDc<OrigFuncPtr, origFunc>(params...)); const bool isReadOnlyAccess = !hasDisplayDcArg(getDestinationDc<OrigFuncPtr, origFunc>(params...));
Gdi::GdiAccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
return LOG_RESULT(Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...)); return LOG_RESULT(Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...));
} }
@ -140,7 +140,7 @@ namespace
} }
else else
{ {
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
return LOG_RESULT(CALL_ORIG_FUNC(ExtTextOutW)(replaceDc(hdc), x, y, options, lprect, lpString, c, lpDx)); return LOG_RESULT(CALL_ORIG_FUNC(ExtTextOutW)(replaceDc(hdc), x, y, options, lprect, lpString, c, lpDx));
} }
} }

View File

@ -2,6 +2,7 @@
#include "Common/Hook.h" #include "Common/Hook.h"
#include "Common/Log.h" #include "Common/Log.h"
#include "D3dDdi/ScopedCriticalSection.h"
#include "DDraw/RealPrimarySurface.h" #include "DDraw/RealPrimarySurface.h"
#include "Gdi/AccessGuard.h" #include "Gdi/AccessGuard.h"
#include "Gdi/Dc.h" #include "Gdi/Dc.h"
@ -254,7 +255,7 @@ namespace
HDC compatDc = Gdi::Dc::getDc(dc); HDC compatDc = Gdi::Dc::getDc(dc);
if (compatDc) if (compatDc)
{ {
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0); result = CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
Gdi::Dc::releaseDc(dc); Gdi::Dc::releaseDc(dc);
return result; return result;
@ -276,7 +277,7 @@ namespace
if (compatDc) if (compatDc)
{ {
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
Gdi::TitleBar titleBar(hwnd, compatDc); Gdi::TitleBar titleBar(hwnd, compatDc);
titleBar.drawAll(); titleBar.drawAll();
titleBar.excludeFromClipRegion(); titleBar.excludeFromClipRegion();
@ -301,14 +302,13 @@ namespace
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0); return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
} }
DDraw::ScopedThreadLock lock;
PAINTSTRUCT paint = {}; PAINTSTRUCT paint = {};
HDC dc = BeginPaint(hwnd, &paint); HDC dc = BeginPaint(hwnd, &paint);
HDC compatDc = Gdi::Dc::getDc(dc); HDC compatDc = Gdi::Dc::getDc(dc);
if (compatDc) if (compatDc)
{ {
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT, CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
reinterpret_cast<WPARAM>(compatDc), PRF_CLIENT); reinterpret_cast<WPARAM>(compatDc), PRF_CLIENT);
Gdi::Dc::releaseDc(dc); Gdi::Dc::releaseDc(dc);
@ -329,7 +329,7 @@ namespace
HDC compatDc = Gdi::Dc::getDc(dc); HDC compatDc = Gdi::Dc::getDc(dc);
if (compatDc) if (compatDc)
{ {
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(compatDc), flags); result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(compatDc), flags);
Gdi::Dc::releaseDc(dc); Gdi::Dc::releaseDc(dc);
} }

View File

@ -1,6 +1,6 @@
#include "Common/Hook.h" #include "Common/Hook.h"
#include "Common/Log.h" #include "Common/Log.h"
#include "DDraw/ScopedThreadLock.h" #include "D3dDdi/ScopedCriticalSection.h"
#include "Gdi/Gdi.h" #include "Gdi/Gdi.h"
#include "Gdi/ScrollFunctions.h" #include "Gdi/ScrollFunctions.h"
#include "Gdi/Window.h" #include "Gdi/Window.h"
@ -52,7 +52,7 @@ namespace Gdi
void updateScrolledWindow(HWND hwnd) void updateScrolledWindow(HWND hwnd)
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
auto window(Gdi::Window::get(hwnd)); auto window(Gdi::Window::get(hwnd));
UINT flags = RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW; UINT flags = RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW;
if (!window || window->getPresentationWindow() != hwnd) if (!window || window->getPresentationWindow() != hwnd)

View File

@ -1,6 +1,8 @@
#include <set> #include <set>
#include "Common/ScopedCriticalSection.h" #include "Common/ScopedCriticalSection.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/ScopedCriticalSection.h"
#include "DDraw/DirectDraw.h" #include "DDraw/DirectDraw.h"
#include "DDraw/ScopedThreadLock.h" #include "DDraw/ScopedThreadLock.h"
#include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h"
@ -119,24 +121,12 @@ namespace Gdi
DDraw::ScopedThreadLock ddLock; DDraw::ScopedThreadLock ddLock;
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
if (rect.left < g_bounds.left || rect.top < g_bounds.top || auto desc = getSurfaceDesc(rect);
rect.right > g_bounds.right || rect.bottom > g_bounds.bottom) if (!desc.lpSurface)
{ {
return nullptr; return nullptr;
} }
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
desc.dwWidth = rect.right - rect.left;
desc.dwHeight = rect.bottom - rect.top;
desc.ddpfPixelFormat = DDraw::getRgbPixelFormat(g_bpp);
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
desc.lPitch = g_pitch;
desc.lpSurface = static_cast<unsigned char*>(g_surfaceView) +
(rect.top - g_bounds.top) * g_pitch +
(rect.left - g_bounds.left) * g_bpp / 8;
auto primary(DDraw::PrimarySurface::getPrimary()); auto primary(DDraw::PrimarySurface::getPrimary());
CompatPtr<IUnknown> ddUnk; CompatPtr<IUnknown> ddUnk;
primary.get()->lpVtbl->GetDDInterface(primary, reinterpret_cast<void**>(&ddUnk.getRef())); primary.get()->lpVtbl->GetDDInterface(primary, reinterpret_cast<void**>(&ddUnk.getRef()));
@ -172,6 +162,29 @@ namespace Gdi
return g_region; return g_region;
} }
DDSURFACEDESC2 getSurfaceDesc(const RECT& rect)
{
Compat::ScopedCriticalSection lock(g_cs);
if (rect.left < g_bounds.left || rect.top < g_bounds.top ||
rect.right > g_bounds.right || rect.bottom > g_bounds.bottom)
{
return {};
}
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
desc.dwWidth = rect.right - rect.left;
desc.dwHeight = rect.bottom - rect.top;
desc.ddpfPixelFormat = DDraw::getRgbPixelFormat(g_bpp);
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
desc.lPitch = g_pitch;
desc.lpSurface = static_cast<unsigned char*>(g_surfaceView) +
(rect.top - g_bounds.top) * g_pitch +
(rect.left - g_bounds.left) * g_bpp / 8;
return desc;
}
void init() void init()
{ {
update(); update();
@ -192,6 +205,11 @@ namespace Gdi
prevDisplaySettingsUniqueness = currentDisplaySettingsUniqueness; prevDisplaySettingsUniqueness = currentDisplaySettingsUniqueness;
{
D3dDdi::ScopedCriticalSection driverLock;
D3dDdi::Device::setGdiResourceHandle(nullptr);
}
g_region = Region(); g_region = Region();
EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(&g_region)); EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(&g_region));
GetRgnBox(g_region, &g_bounds); GetRgnBox(g_region, &g_bounds);

View File

@ -20,6 +20,7 @@ namespace Gdi
RECT getBounds(); RECT getBounds();
Region getRegion(); Region getRegion();
DDSURFACEDESC2 getSurfaceDesc(const RECT& rect);
void init(); void init();
bool update(); bool update();

View File

@ -139,7 +139,7 @@ namespace
HDC compatDc = Gdi::Dc::getDc(windowDc); HDC compatDc = Gdi::Dc::getDc(windowDc);
if (compatDc) if (compatDc)
{ {
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
if (OBJID_TITLEBAR == idObject) if (OBJID_TITLEBAR == idObject)
{ {
Gdi::TitleBar(hwnd, compatDc).drawButtons(); Gdi::TitleBar(hwnd, compatDc).drawButtons();

View File

@ -1,7 +1,7 @@
#include "Common/Hook.h" #include "Common/Hook.h"
#include "Common/Log.h" #include "Common/Log.h"
#include "D3dDdi/ScopedCriticalSection.h"
#include "DDraw/RealPrimarySurface.h" #include "DDraw/RealPrimarySurface.h"
#include "DDraw/ScopedThreadLock.h"
#include "Gdi/Gdi.h" #include "Gdi/Gdi.h"
#include "Gdi/Window.h" #include "Gdi/Window.h"
@ -155,7 +155,7 @@ namespace Gdi
{ {
if (isTopLevelWindow(hwnd) && !get(hwnd)) if (isTopLevelWindow(hwnd) && !get(hwnd))
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
s_windows.emplace(hwnd, std::make_shared<Window>(hwnd)); s_windows.emplace(hwnd, std::make_shared<Window>(hwnd));
return true; return true;
} }
@ -196,20 +196,20 @@ namespace Gdi
std::shared_ptr<Window> Window::get(HWND hwnd) std::shared_ptr<Window> Window::get(HWND hwnd)
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
auto it = s_windows.find(hwnd); auto it = s_windows.find(hwnd);
return it != s_windows.end() ? it->second : nullptr; return it != s_windows.end() ? it->second : nullptr;
} }
BYTE Window::getAlpha() const BYTE Window::getAlpha() const
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
return m_alpha; return m_alpha;
} }
COLORREF Window::getColorKey() const COLORREF Window::getColorKey() const
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
return m_colorKey; return m_colorKey;
} }
@ -220,19 +220,19 @@ namespace Gdi
Region Window::getVisibleRegion() const Region Window::getVisibleRegion() const
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
return m_visibleRegion; return m_visibleRegion;
} }
RECT Window::getWindowRect() const RECT Window::getWindowRect() const
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
return m_windowRect; return m_windowRect;
} }
std::map<HWND, std::shared_ptr<Window>> Window::getWindows() std::map<HWND, std::shared_ptr<Window>> Window::getWindows()
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
return s_windows; return s_windows;
} }
@ -282,7 +282,7 @@ namespace Gdi
void Window::remove(HWND hwnd) void Window::remove(HWND hwnd)
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
s_windows.erase(hwnd); s_windows.erase(hwnd);
} }
@ -301,7 +301,7 @@ namespace Gdi
void Window::update() void Window::update()
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
if (m_isUpdating) if (m_isUpdating)
{ {
return; return;
@ -364,13 +364,13 @@ namespace Gdi
void Window::updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha) void Window::updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha)
{ {
DDraw::ScopedThreadLock lock; D3dDdi::ScopedCriticalSection lock;
auto window(get(hwnd)); auto window(get(hwnd));
if (window) if (window)
{ {
window->m_colorKey = colorKey; window->m_colorKey = colorKey;
window->m_alpha = alpha; window->m_alpha = alpha;
DDraw::RealPrimarySurface::update(); DDraw::RealPrimarySurface::gdiUpdate();
} }
} }