mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Added separate critical section for GDI emulation
GDI emulation was using the DirectDraw critical section for thread safety, but it caused a deadlock when Alt-Tabbing in Commandos BCD. Now it uses its own critical section and some atomic shared variables.
This commit is contained in:
parent
0474e7f95f
commit
9b62f21a3d
@ -1,6 +1,7 @@
|
||||
#define CINTERFACE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <oleacc.h>
|
||||
@ -13,6 +14,7 @@
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "DDrawLog.h"
|
||||
#include "DDrawProcs.h"
|
||||
#include "DDrawScopedThreadLock.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
namespace
|
||||
@ -40,7 +42,7 @@ namespace
|
||||
HWND rootWnd;
|
||||
};
|
||||
|
||||
bool g_suppressGdiHooks = false;
|
||||
std::atomic<bool> g_suppressGdiHooks = false;
|
||||
|
||||
class HookRecursionGuard
|
||||
{
|
||||
@ -72,6 +74,22 @@ namespace
|
||||
|
||||
CaretData g_caret = {};
|
||||
|
||||
CRITICAL_SECTION g_gdiCriticalSection;
|
||||
|
||||
class GdiScopedThreadLock
|
||||
{
|
||||
public:
|
||||
GdiScopedThreadLock()
|
||||
{
|
||||
EnterCriticalSection(&g_gdiCriticalSection);
|
||||
}
|
||||
|
||||
~GdiScopedThreadLock()
|
||||
{
|
||||
LeaveCriticalSection(&g_gdiCriticalSection);
|
||||
}
|
||||
};
|
||||
|
||||
POINT getClientOrigin(HWND hwnd);
|
||||
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin);
|
||||
HDC releaseCompatDc(HDC hdc);
|
||||
@ -88,6 +106,7 @@ namespace
|
||||
else if (WM_ERASEBKGND == ret->message && ret->lResult)
|
||||
{
|
||||
HDC origDc = reinterpret_cast<HDC>(ret->wParam);
|
||||
GdiScopedThreadLock gdiLock;
|
||||
if (g_dcToSurface.find(origDc) == g_dcToSurface.end())
|
||||
{
|
||||
HWND hwnd = WindowFromDC(origDc);
|
||||
@ -129,6 +148,8 @@ namespace
|
||||
|
||||
IDirectDrawSurface7* createGdiSurface()
|
||||
{
|
||||
Compat::DDrawScopedThreadLock ddLock;
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
||||
@ -184,11 +205,12 @@ namespace
|
||||
|
||||
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin)
|
||||
{
|
||||
if (!CompatPrimarySurface::surfacePtr || !origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
||||
if (!CompatPrimarySurface::surfacePtr || !origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
||||
{
|
||||
return origDc;
|
||||
}
|
||||
|
||||
GdiScopedThreadLock gdiLock;
|
||||
HookRecursionGuard recursionGuard;
|
||||
|
||||
IDirectDrawSurface7* surface = createGdiSurface();
|
||||
@ -296,6 +318,7 @@ namespace
|
||||
return hdc;
|
||||
}
|
||||
|
||||
GdiScopedThreadLock gdiLock;
|
||||
HookRecursionGuard recursionGuard;
|
||||
|
||||
auto it = g_dcToSurface.find(hdc);
|
||||
@ -360,6 +383,7 @@ namespace
|
||||
{
|
||||
if (STATE_SYSTEM_INVISIBLE == getCaretState(accessible))
|
||||
{
|
||||
GdiScopedThreadLock gdiLock;
|
||||
drawCaret();
|
||||
g_caret.isDrawn = false;
|
||||
}
|
||||
@ -369,69 +393,48 @@ namespace
|
||||
|
||||
HDC WINAPI getDc(HWND hWnd)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("GetDC", hWnd);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origGetDc(hWnd), getClientOrigin(hWnd));
|
||||
|
||||
Compat::LogLeave("GetDC", hWnd) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
HDC WINAPI getDcEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("GetDCEx", hWnd);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origGetDcEx(hWnd, hrgnClip, flags),
|
||||
flags & (DCX_WINDOW | DCX_PARENTCLIP) ? getWindowOrigin(hWnd) : getClientOrigin(hWnd));
|
||||
|
||||
Compat::LogLeave("GetDCEx", hWnd) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
HDC WINAPI getWindowDc(HWND hWnd)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("GetWindowDC", hWnd);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origGetWindowDc(hWnd), getWindowOrigin(hWnd));
|
||||
|
||||
Compat::LogLeave("GetWindowDC", hWnd) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
int WINAPI releaseDc(HWND hWnd, HDC hDC)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("ReleaseDC", hWnd, hDC);
|
||||
|
||||
int result = g_origReleaseDc(hWnd, releaseCompatDc(hDC));
|
||||
|
||||
Compat::LogLeave("ReleaseDC", hWnd, hDC) << result;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return result;
|
||||
}
|
||||
|
||||
HDC WINAPI beginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("BeginPaint", hWnd, lpPaint);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origBeginPaint(hWnd, lpPaint), getClientOrigin(hWnd));
|
||||
lpPaint->hdc = compatDc;
|
||||
|
||||
Compat::LogLeave("BeginPaint", hWnd, lpPaint) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
BOOL WINAPI endPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("EndPaint", hWnd, lpPaint);
|
||||
|
||||
BOOL result = FALSE;
|
||||
@ -447,7 +450,6 @@ namespace
|
||||
}
|
||||
|
||||
Compat::LogLeave("EndPaint", hWnd, lpPaint) << result;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -456,6 +458,7 @@ namespace
|
||||
BOOL result = g_origCreateCaret(hWnd, hBitmap, nWidth, nHeight);
|
||||
if (result)
|
||||
{
|
||||
GdiScopedThreadLock gdiLock;
|
||||
if (g_caret.isDrawn)
|
||||
{
|
||||
drawCaret();
|
||||
@ -470,6 +473,7 @@ namespace
|
||||
BOOL WINAPI showCaret(HWND hWnd)
|
||||
{
|
||||
BOOL result = g_origShowCaret(hWnd);
|
||||
GdiScopedThreadLock gdiLock;
|
||||
if (result && !g_caret.isDrawn)
|
||||
{
|
||||
IAccessible* accessible = nullptr;
|
||||
@ -496,6 +500,7 @@ namespace
|
||||
BOOL WINAPI hideCaret(HWND hWnd)
|
||||
{
|
||||
BOOL result = g_origHideCaret(hWnd);
|
||||
GdiScopedThreadLock gdiLock;
|
||||
if (result && g_caret.isDrawn)
|
||||
{
|
||||
drawCaret();
|
||||
@ -513,6 +518,7 @@ void CompatGdiSurface::hookGdi()
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||
g_directDraw = createDirectDraw();
|
||||
if (g_directDraw)
|
||||
{
|
||||
|
@ -57,6 +57,6 @@ namespace CompatPrimarySurface
|
||||
LONG height = 0;
|
||||
DDPIXELFORMAT pixelFormat = {};
|
||||
LONG pitch = 0;
|
||||
void* surfacePtr = nullptr;
|
||||
std::atomic<void*> surfacePtr = nullptr;
|
||||
IReleaseNotifier releaseNotifier(onRelease);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <atomic>
|
||||
#include <ddraw.h>
|
||||
|
||||
class IReleaseNotifier;
|
||||
@ -25,6 +26,6 @@ namespace CompatPrimarySurface
|
||||
extern LONG height;
|
||||
extern DDPIXELFORMAT pixelFormat;
|
||||
extern LONG pitch;
|
||||
extern void* surfacePtr;
|
||||
extern std::atomic<void*> surfacePtr;
|
||||
extern IReleaseNotifier releaseNotifier;
|
||||
}
|
||||
|
@ -150,6 +150,7 @@
|
||||
<ClInclude Include="DDrawProcs.h" />
|
||||
<ClInclude Include="CompatDirectDraw.h" />
|
||||
<ClInclude Include="CompatPrimarySurface.h" />
|
||||
<ClInclude Include="DDrawScopedThreadLock.h" />
|
||||
<ClInclude Include="DDrawTypes.h" />
|
||||
<ClInclude Include="CompatDirectDrawSurface.h" />
|
||||
<ClInclude Include="DDrawVtableVisitor.h" />
|
||||
|
@ -63,6 +63,9 @@
|
||||
<ClInclude Include="Config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DDrawScopedThreadLock.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DllMain.cpp">
|
||||
|
20
DDrawCompat/DDrawScopedThreadLock.h
Normal file
20
DDrawCompat/DDrawScopedThreadLock.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "DDrawProcs.h"
|
||||
|
||||
namespace Compat
|
||||
{
|
||||
class DDrawScopedThreadLock
|
||||
{
|
||||
public:
|
||||
DDrawScopedThreadLock()
|
||||
{
|
||||
origProcs.AcquireDDThreadLock();
|
||||
}
|
||||
|
||||
~DDrawScopedThreadLock()
|
||||
{
|
||||
origProcs.ReleaseDDThreadLock();
|
||||
}
|
||||
};
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#include <atomic>
|
||||
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdiSurface.h"
|
||||
@ -24,6 +26,8 @@ namespace
|
||||
LARGE_INTEGER g_lastUpdateTime = {};
|
||||
LARGE_INTEGER g_qpcFrequency = {};
|
||||
|
||||
std::atomic<bool> g_isFullScreen(false);
|
||||
|
||||
bool compatBlt(IDirectDrawSurface7* dest)
|
||||
{
|
||||
Compat::LogEnter("RealPrimarySurface::compatBlt", dest);
|
||||
@ -111,6 +115,7 @@ namespace
|
||||
|
||||
g_frontBuffer = nullptr;
|
||||
g_backBuffer = nullptr;
|
||||
g_isFullScreen = false;
|
||||
if (g_paletteConverterSurface)
|
||||
{
|
||||
g_paletteConverterSurface->lpVtbl->Release(g_paletteConverterSurface);
|
||||
@ -246,6 +251,8 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
|
||||
g_frontBuffer->lpVtbl->SetPrivateData(g_frontBuffer,
|
||||
IID_IReleaseNotifier, &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||
|
||||
g_isFullScreen = isFlippable;
|
||||
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
@ -290,7 +297,7 @@ IDirectDrawSurface7* RealPrimarySurface::getSurface()
|
||||
|
||||
bool RealPrimarySurface::isFullScreen()
|
||||
{
|
||||
return nullptr != g_backBuffer;
|
||||
return g_isFullScreen;
|
||||
}
|
||||
|
||||
bool RealPrimarySurface::isLost()
|
||||
|
Loading…
x
Reference in New Issue
Block a user