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

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

View File

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

View File

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

View File

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