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

Fixed deadlock when hooking NVIDIA user-mode display drivers

See issue #28
This commit is contained in:
narzoul 2019-01-02 18:52:06 +01:00
parent 14104894b2
commit 8e8eeb083a
5 changed files with 45 additions and 40 deletions

View File

@ -4,6 +4,7 @@
#include "Common/Hook.h"
#include "Common/Log.h"
#include "Common/ScopedCriticalSection.h"
#include "DDraw/ScopedThreadLock.h"
#include "Gdi/Dc.h"
#include "Gdi/DcCache.h"
@ -29,6 +30,7 @@ namespace
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
Compat::CriticalSection g_cs;
CompatDcMap g_origDcToCompatDc;
void restoreDc(const CompatDc& compatDc);
@ -147,7 +149,7 @@ namespace Gdi
{
void dllProcessDetach()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
for (auto& origDcToCompatDc : g_origDcToCompatDc)
{
restoreDc(origDcToCompatDc.second);
@ -158,7 +160,7 @@ namespace Gdi
void dllThreadDetach()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
const DWORD threadId = GetCurrentThreadId();
auto it = g_origDcToCompatDc.begin();
while (it != g_origDcToCompatDc.end())
@ -183,7 +185,8 @@ namespace Gdi
return nullptr;
}
DDraw::ScopedThreadLock lock;
DDraw::ScopedThreadLock ddLock;
Compat::ScopedCriticalSection lock(g_cs);
auto it = g_origDcToCompatDc.find(origDc);
if (it != g_origDcToCompatDc.end())
{
@ -228,7 +231,7 @@ namespace Gdi
HDC getOrigDc(HDC dc)
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
[dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; });
return it != g_origDcToCompatDc.end() ? it->first : dc;
@ -236,7 +239,7 @@ namespace Gdi
void releaseDc(HDC origDc)
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
auto it = g_origDcToCompatDc.find(origDc);
if (it == g_origDcToCompatDc.end())
{

View File

@ -3,12 +3,13 @@
#include <memory>
#include <vector>
#include "DDraw/ScopedThreadLock.h"
#include "Common/ScopedCriticalSection.h"
#include "Gdi/DcCache.h"
#include "Gdi/VirtualScreen.h"
namespace
{
Compat::CriticalSection g_cs;
std::map<DWORD, std::vector<HDC>> g_threadIdToDcCache;
}
@ -18,7 +19,7 @@ namespace Gdi
{
void deleteDc(HDC cachedDc)
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
for (auto& threadIdToDcCache : g_threadIdToDcCache)
{
auto& dcCache = threadIdToDcCache.second;
@ -34,7 +35,7 @@ namespace Gdi
void dllProcessDetach()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
for (auto& threadIdToDcCache : g_threadIdToDcCache)
{
for (HDC dc : threadIdToDcCache.second)
@ -47,7 +48,7 @@ namespace Gdi
void dllThreadDetach()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
auto it = g_threadIdToDcCache.find(GetCurrentThreadId());
if (it == g_threadIdToDcCache.end())
{
@ -64,7 +65,7 @@ namespace Gdi
HDC getDc()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
std::vector<HDC>& dcCache = g_threadIdToDcCache[GetCurrentThreadId()];
if (dcCache.empty())
@ -79,7 +80,7 @@ namespace Gdi
void releaseDc(HDC cachedDc)
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
g_threadIdToDcCache[GetCurrentThreadId()].push_back(cachedDc);
}
}

View File

@ -6,7 +6,7 @@
#include "Common/Hook.h"
#include "Common/Log.h"
#include "DDraw/ScopedThreadLock.h"
#include "Common/ScopedCriticalSection.h"
#include "Gdi/Gdi.h"
#include "Gdi/Palette.h"
#include "VirtualScreen.h"
@ -14,6 +14,7 @@
namespace
{
Compat::CriticalSection g_cs;
PALETTEENTRY g_systemPalette[256] = {};
UINT g_systemPaletteUse = SYSPAL_STATIC;
UINT g_systemPaletteFirstUnusedIndex = 10;
@ -75,7 +76,7 @@ namespace
++g_systemPaletteFirstUnusedIndex;
}
Gdi::VirtualScreen::updatePalette();
Gdi::VirtualScreen::updatePalette(g_systemPalette);
return count;
}
@ -102,7 +103,7 @@ namespace
nEntries = 256 - iStartIndex;
}
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
std::memcpy(lppe, &g_systemPalette[iStartIndex], nEntries * sizeof(PALETTEENTRY));
return LOG_RESULT(nEntries);
@ -115,7 +116,7 @@ namespace
{
return LOG_RESULT(SYSPAL_ERROR);
}
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
return g_systemPaletteUse;
}
@ -124,7 +125,7 @@ namespace
LOG_FUNC("RealizePalette", hdc);
if (Gdi::isDisplayDc(hdc))
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
if (g_foregroundPaletteDcs.find(hdc) != g_foregroundPaletteDcs.end())
{
g_systemPaletteFirstUnusedIndex = g_systemPaletteFirstNonReservedIndex;
@ -137,7 +138,7 @@ namespace
int WINAPI releaseDc(HWND hWnd, HDC hDC)
{
LOG_FUNC("ReleaseDC", hWnd, hDC);
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
g_foregroundPaletteDcs.erase(hDC);
return LOG_RESULT(CALL_ORIG_FUNC(ReleaseDC)(hWnd, hDC));
}
@ -151,7 +152,7 @@ namespace
HWND wnd = CALL_ORIG_FUNC(WindowFromDC)(hdc);
if (wnd && GetDesktopWindow() != wnd)
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
if (bForceBackground || GetStockObject(DEFAULT_PALETTE) == hpal)
{
g_foregroundPaletteDcs.erase(hdc);
@ -173,7 +174,7 @@ namespace
return LOG_RESULT(SYSPAL_ERROR);
}
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
const UINT prevUsage = g_systemPaletteUse;
switch (uUsage)
{
@ -210,7 +211,7 @@ namespace Gdi
HPALETTE defaultPalette = reinterpret_cast<HPALETTE>(GetStockObject(DEFAULT_PALETTE));
GetPaletteEntries(defaultPalette, 0, 10, g_systemPalette);
GetPaletteEntries(defaultPalette, 10, 10, &g_systemPalette[246]);
Gdi::VirtualScreen::updatePalette();
Gdi::VirtualScreen::updatePalette(g_systemPalette);
HOOK_FUNCTION(gdi32, GetSystemPaletteEntries, getSystemPaletteEntries);
HOOK_FUNCTION(gdi32, GetSystemPaletteUse, getSystemPaletteUse);

View File

@ -1,5 +1,6 @@
#include <set>
#include "Common/ScopedCriticalSection.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/ScopedThreadLock.h"
#include "DDraw/Surfaces/PrimarySurface.h"
@ -10,6 +11,7 @@
namespace
{
Compat::CriticalSection g_cs;
Gdi::Region g_region;
RECT g_bounds = {};
DWORD g_bpp = 0;
@ -70,7 +72,7 @@ namespace Gdi
{
HDC createDc()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
std::unique_ptr<void, decltype(&DeleteObject)> dib(createDib(), DeleteObject);
if (!dib)
{
@ -91,7 +93,6 @@ namespace Gdi
dib.release();
g_stockBitmap = stockBitmap;
g_dcs.insert(dc.get());
return dc.release();
@ -99,7 +100,7 @@ namespace Gdi
HBITMAP createDib()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
if (!g_surfaceFileMapping)
{
return nullptr;
@ -109,19 +110,21 @@ namespace Gdi
HBITMAP createOffScreenDib(DWORD width, DWORD height)
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
return createDibSection(width, height, nullptr);
}
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect)
{
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)
{
return nullptr;
}
DDraw::ScopedThreadLock lock;
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
@ -151,7 +154,7 @@ namespace Gdi
return;
}
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
DeleteObject(SelectObject(dc, g_stockBitmap));
DeleteDC(dc);
g_dcs.erase(dc);
@ -159,13 +162,13 @@ namespace Gdi
RECT getBounds()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
return g_bounds;
}
const Region& getRegion()
Region getRegion()
{
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
return g_region;
}
@ -177,7 +180,7 @@ namespace Gdi
bool update()
{
LOG_FUNC("VirtualScreen::update");
DDraw::ScopedThreadLock lock;
Compat::ScopedCriticalSection lock(g_cs);
static auto prevDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
@ -220,19 +223,16 @@ namespace Gdi
return LOG_RESULT(true);
}
void updatePalette()
void updatePalette(PALETTEENTRY(&palette)[256])
{
DDraw::ScopedThreadLock lock;
PALETTEENTRY pal[256] = {};
GetSystemPaletteEntries(Gdi::getScreenDc(), 0, 256, pal);
Compat::ScopedCriticalSection lock(g_cs);
RGBQUAD systemPalette[256] = {};
for (int i = 0; i < 256; ++i)
{
systemPalette[i].rgbRed = pal[i].peRed;
systemPalette[i].rgbGreen = pal[i].peGreen;
systemPalette[i].rgbBlue = pal[i].peBlue;
systemPalette[i].rgbRed = palette[i].peRed;
systemPalette[i].rgbGreen = palette[i].peGreen;
systemPalette[i].rgbBlue = palette[i].peBlue;
}
if (0 != memcmp(g_systemPalette, systemPalette, sizeof(systemPalette)))

View File

@ -19,10 +19,10 @@ namespace Gdi
void deleteDc(HDC dc);
RECT getBounds();
const Region& getRegion();
Region getRegion();
void init();
bool update();
void updatePalette();
void updatePalette(PALETTEENTRY(&palette)[256]);
}
}