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"
struct _D3DDDI_ADAPTERCALLBACKS;
struct _D3DDDI_ADAPTERFUNCS;
struct _D3DDDI_DEVICEALLBACKS;
struct _D3DDDI_DEVICEFUNCS;
template <typename Vtable>
class ScopedVtableFuncLock : public DDraw::ScopedThreadLock {};
@ -14,9 +16,15 @@ class ScopedVtableFuncLock : public DDraw::ScopedThreadLock {};
template <>
class ScopedVtableFuncLock<_D3DDDI_ADAPTERCALLBACKS> : public D3dDdi::ScopedCriticalSection {};
template <>
class ScopedVtableFuncLock<_D3DDDI_ADAPTERFUNCS> : public D3dDdi::ScopedCriticalSection {};
template <>
class ScopedVtableFuncLock<_D3DDDI_DEVICEALLBACKS> : public D3dDdi::ScopedCriticalSection {};
template <>
class ScopedVtableFuncLock<_D3DDDI_DEVICEFUNCS> : public D3dDdi::ScopedCriticalSection {};
template <typename Vtable, int instanceId = 0>
class VtableHookVisitor
{

View File

@ -6,34 +6,13 @@
#include "D3dDdi/Device.h"
#include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/Resource.h"
#include "Gdi/AccessGuard.h"
namespace
{
HANDLE g_gdiResourceHandle = nullptr;
D3dDdi::Resource* g_gdiResource = nullptr;
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>
void erase_if(Container& container, Predicate pred)
{
@ -69,14 +48,13 @@ namespace D3dDdi
{
return it->second.blt(data);
}
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex);
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource, data.DstSubResourceIndex);
prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex, true);
return m_origVtable.pfnBlt(m_device, &data);
}
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);
}
@ -87,7 +65,6 @@ namespace D3dDdi
{
return it->second.colorFill(data);
}
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE, data.hResource, data.SubResourceIndex);
return m_origVtable.pfnColorFill(m_device, &data);
}
@ -118,6 +95,17 @@ namespace D3dDdi
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)
{
D3DKMTReleaseProcessVidPnSourceOwners(GetCurrentProcess());
@ -145,6 +133,7 @@ namespace D3dDdi
if (resource == g_gdiResourceHandle)
{
g_gdiResourceHandle = nullptr;
g_gdiResource = nullptr;
}
}
@ -153,55 +142,50 @@ namespace D3dDdi
HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data)
{
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
prepareForRendering();
return m_origVtable.pfnDrawIndexedPrimitive(m_device, &data);
}
HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data,
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);
}
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);
}
HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data)
{
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
prepareForRendering();
return m_origVtable.pfnDrawPrimitive2(m_device, &data);
}
HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info,
const FLOAT* patch)
{
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
prepareForRendering();
return m_origVtable.pfnDrawRectPatch(m_device, &data, info, patch);
}
HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info,
const FLOAT* patch)
{
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
prepareForRendering();
return m_origVtable.pfnDrawTriPatch(m_device, &data, info, patch);
}
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);
if (it != m_resources.end())
{
return it->second.lock(data);
}
return m_origVtable.pfnLock(m_device, &data);
}
@ -217,53 +201,40 @@ namespace D3dDdi
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);
}
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)
{
const bool isReadOnly = true;
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex, isReadOnly);
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex, true);
}
return m_origVtable.pfnPresent1(m_device, &data);
}
HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data)
{
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource);
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource);
prepareForRendering(data.hDstResource, UINT_MAX, false);
prepareForRendering(data.hSrcResource, UINT_MAX, true);
return m_origVtable.pfnTexBlt(m_device, &data);
}
HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data)
{
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource);
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource);
prepareForRendering(data.hDstResource, UINT_MAX, false);
prepareForRendering(data.hSrcResource, UINT_MAX, true);
return m_origVtable.pfnTexBlt1(m_device, &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);
if (it != m_resources.end())
{
return it->second.unlock(data);
}
return m_origVtable.pfnUnlock(m_device, &data);
}
@ -289,6 +260,11 @@ namespace D3dDdi
m_dirtyTextures.emplace(std::make_pair(resource, subResourceIndex), resource);
}
Resource* Device::getGdiResource()
{
return g_gdiResource;
}
void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly)
{
auto it = m_resources.find(resource);
@ -366,6 +342,11 @@ namespace D3dDdi
void Device::setGdiResourceHandle(HANDLE resource)
{
g_gdiResourceHandle = resource;
g_gdiResource = getResource(resource);
if (g_gdiResource)
{
g_gdiResource->resync();
}
}
void Device::setReadOnlyGdiLock(bool enable)

View File

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

View File

@ -467,6 +467,18 @@ namespace D3dDdi
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)
{
if (!m_lockResource == !lockResource)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,11 +8,14 @@
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurfaceImpl.h"
#include "Gdi/VirtualScreen.h"
namespace
{
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
std::vector<CompatWeakPtr<IDirectDrawSurface7>> g_lockBackBuffers;
HANDLE g_gdiResourceHandle = nullptr;
HANDLE g_frontResource = nullptr;
DWORD g_origCaps = 0;
}
@ -23,11 +26,18 @@ namespace DDraw
LOG_FUNC("PrimarySurface::~PrimarySurface");
g_gdiResourceHandle = nullptr;
g_frontResource = nullptr;
g_primarySurface = nullptr;
g_origCaps = 0;
s_palette = nullptr;
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
for (auto& lockBuffer : g_lockBackBuffers)
{
lockBuffer.release();
}
g_lockBackBuffers.clear();
DDraw::RealPrimarySurface::release();
}
@ -50,7 +60,9 @@ namespace DDraw
desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
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))
{
Compat::Log() << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result);
@ -58,11 +70,32 @@ namespace DDraw
return result;
}
g_primarySurface = CompatPtr<IDirectDrawSurface7>::from(surface);
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;
}
@ -152,6 +185,11 @@ namespace DDraw
return g_primarySurface;
}
HANDLE PrimarySurface::getFrontResource()
{
return g_frontResource;
}
DWORD PrimarySurface::getOrigCaps()
{
return g_origCaps;
@ -169,10 +207,28 @@ namespace DDraw
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*);
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);
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()

View File

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

View File

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

View File

@ -213,8 +213,6 @@ namespace DDraw
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_SYSTEMMEMORY;

View File

@ -34,7 +34,7 @@ namespace DDraw
SurfaceImpl<TSurface>* getImpl() const;
void clearResources();
void restore();
virtual void restore();
protected:
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<IDirectDrawSurface7>> m_impl7;
CompatWeakPtr<IDirectDrawSurface7> m_surface;
std::vector<Surface*> m_attachedSurfaces;
CompatPtr<IDirectDrawSurface7> m_lockSurface;
std::vector<CompatWeakPtr<IDirectDrawSurface7>> m_attachedLockSurfaces;
private:
template <typename TDirectDrawSurface>
friend class SurfaceImpl;
@ -61,9 +66,5 @@ namespace DDraw
DWORD m_refCount;
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/Surface.h"
#include "DDraw/Surfaces/SurfaceImpl.h"
#include "Gdi/AccessGuard.h"
namespace
{
@ -36,9 +35,6 @@ namespace DDraw
{
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);
}
@ -46,8 +42,6 @@ namespace DDraw
HRESULT SurfaceImpl<TSurface>::BltFast(
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);
}
@ -81,18 +75,11 @@ namespace DDraw
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
{
HRESULT result = DD_OK;
{
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = s_origVtable.GetDC(This, lphDC);
}
HRESULT result = s_origVtable.GetDC(This, lphDC);
if (SUCCEEDED(result))
{
RealPrimarySurface::waitForFlip(m_data);
}
return result;
}
@ -143,8 +130,6 @@ namespace DDraw
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);
if (DDERR_SURFACELOST == result)
{
@ -164,7 +149,6 @@ namespace DDraw
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
{
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
return s_origVtable.ReleaseDC(This, hDC);
}
@ -188,7 +172,6 @@ namespace DDraw
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
{
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
return s_origVtable.Unlock(This, lpRect);
}

View File

@ -1,151 +1,43 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "D3dDdi/KernelModeThunks.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/Resource.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/ScopedThreadLock.h"
#include "DDraw/Surfaces/PrimarySurface.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
{
AccessGuard::AccessGuard(User user, Access access, bool condition)
: m_user(user)
, m_access(access)
AccessGuard::AccessGuard(Access access, bool condition)
: m_access(access)
, m_condition(condition)
{
if (m_condition)
{
DDraw::ScopedThreadLock lock;
if (g_isSyncing)
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{
m_condition = false;
return;
}
D3DDDIARG_LOCK lockData = {};
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()
{
if (m_condition)
if (m_condition && ACCESS_WRITE == m_access)
{
DDraw::ScopedThreadLock lock;
endAccess(m_user, m_access);
D3dDdi::ScopedCriticalSection lock;
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
namespace D3dDdi
{
class Resource;
}
namespace Gdi
{
enum Access
@ -8,33 +13,14 @@ namespace Gdi
ACCESS_WRITE
};
enum User
{
USER_DDRAW,
USER_GDI
};
class AccessGuard
{
protected:
AccessGuard(User user, Access access, bool condition = true);
public:
AccessGuard(Access access, bool condition = true);
~AccessGuard();
private:
User m_user;
Access m_access;
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/Time.h"
#include "DDraw/ScopedThreadLock.h"
#include "D3dDdi/ScopedCriticalSection.h"
#include "Gdi/Caret.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
@ -34,7 +34,6 @@ namespace
{
if (OBJID_CARET == idObject)
{
DDraw::ScopedThreadLock lock;
updateCaret(GetWindowThreadProcessId(hwnd, nullptr));
}
}
@ -64,7 +63,7 @@ namespace
void updateCaret(DWORD threadId)
{
DDraw::ScopedThreadLock lock;
D3dDdi::ScopedCriticalSection lock;
if (g_caret.isDrawn)
{
drawCaret();
@ -87,7 +86,7 @@ namespace Gdi
{
void blink()
{
DDraw::ScopedThreadLock lock;
D3dDdi::ScopedCriticalSection lock;
if (!g_caret.isVisible)
{
return;

View File

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

View File

@ -105,7 +105,7 @@ namespace
if (hasDisplayDcArg(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)...));
}
@ -140,7 +140,7 @@ namespace
}
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));
}
}

View File

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

View File

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

View File

@ -1,6 +1,8 @@
#include <set>
#include "Common/ScopedCriticalSection.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/ScopedCriticalSection.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/ScopedThreadLock.h"
#include "DDraw/Surfaces/PrimarySurface.h"
@ -119,24 +121,12 @@ namespace Gdi
DDraw::ScopedThreadLock ddLock;
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)
auto desc = getSurfaceDesc(rect);
if (!desc.lpSurface)
{
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());
CompatPtr<IUnknown> ddUnk;
primary.get()->lpVtbl->GetDDInterface(primary, reinterpret_cast<void**>(&ddUnk.getRef()));
@ -172,6 +162,29 @@ namespace Gdi
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()
{
update();
@ -192,6 +205,11 @@ namespace Gdi
prevDisplaySettingsUniqueness = currentDisplaySettingsUniqueness;
{
D3dDdi::ScopedCriticalSection driverLock;
D3dDdi::Device::setGdiResourceHandle(nullptr);
}
g_region = Region();
EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(&g_region));
GetRgnBox(g_region, &g_bounds);

View File

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

View File

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

View File

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