mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Added a DC cache for GDI interworking
A certain number of DCs are now created upfront and cached to reduce the likelihood of deadlocks. This avoids having to enter the DD critical section to create new DCs in most cases. This change seems to resolve deadlock issues when Alt-Tabbing in Deadlock 2.
This commit is contained in:
parent
2e8d7e47ab
commit
2dc8d4f13b
@ -603,6 +603,7 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Restore(TSurface* T
|
|||||||
result = RealPrimarySurface::restore();
|
result = RealPrimarySurface::restore();
|
||||||
if (wasLost)
|
if (wasLost)
|
||||||
{
|
{
|
||||||
|
CompatGdiSurface::release();
|
||||||
updateSurfaceParams();
|
updateSurfaceParams();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -690,8 +691,7 @@ void CompatDirectDrawSurface<TSurface>::updateSurfaceParams()
|
|||||||
if (SUCCEEDED(s_origVtable.Lock(s_compatPrimarySurface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
|
if (SUCCEEDED(s_origVtable.Lock(s_compatPrimarySurface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
|
||||||
{
|
{
|
||||||
s_origVtable.Unlock(s_compatPrimarySurface, nullptr);
|
s_origVtable.Unlock(s_compatPrimarySurface, nullptr);
|
||||||
CompatPrimarySurface::pitch = desc.lPitch;
|
CompatGdiSurface::setSurfaceMemory(desc.lpSurface, desc.lPitch);
|
||||||
CompatPrimarySurface::surfacePtr = desc.lpSurface;
|
|
||||||
}
|
}
|
||||||
g_lockingPrimary = false;
|
g_lockingPrimary = false;
|
||||||
}
|
}
|
||||||
|
254
DDrawCompat/CompatGdiDcCache.cpp
Normal file
254
DDrawCompat/CompatGdiDcCache.cpp
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
|
#include "CompatGdiDcCache.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include "DDrawLog.h"
|
||||||
|
#include "DDrawProcs.h"
|
||||||
|
#include "DDrawScopedThreadLock.h"
|
||||||
|
|
||||||
|
namespace CompatGdiDcCache
|
||||||
|
{
|
||||||
|
bool operator<(const SurfaceMemoryDesc& desc1, const SurfaceMemoryDesc& desc2)
|
||||||
|
{
|
||||||
|
return desc1.surfaceMemory < desc2.surfaceMemory ||
|
||||||
|
(desc1.surfaceMemory == desc2.surfaceMemory && desc1.pitch < desc2.pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using CompatGdiDcCache::SurfaceMemoryDesc;
|
||||||
|
using CompatGdiDcCache::CompatDc;
|
||||||
|
|
||||||
|
std::map<SurfaceMemoryDesc, std::vector<CompatDc>> g_compatDcCaches;
|
||||||
|
std::vector<CompatDc>* g_currentCompatDcCache = nullptr;
|
||||||
|
|
||||||
|
DWORD g_cacheId = 0;
|
||||||
|
IDirectDraw7* g_directDraw = nullptr;
|
||||||
|
void* g_surfaceMemory = nullptr;
|
||||||
|
LONG g_pitch = 0;
|
||||||
|
|
||||||
|
IDirectDrawSurface7* createGdiSurface();
|
||||||
|
void releaseCompatDc(CompatDc compatDc);
|
||||||
|
void releaseCompatDcCache(std::vector<CompatDc>& compatDcCache);
|
||||||
|
|
||||||
|
void clearAllCaches()
|
||||||
|
{
|
||||||
|
for (auto& compatDcCache : g_compatDcCaches)
|
||||||
|
{
|
||||||
|
releaseCompatDcCache(compatDcCache.second);
|
||||||
|
}
|
||||||
|
g_compatDcCaches.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirectDraw7* createDirectDraw()
|
||||||
|
{
|
||||||
|
IDirectDraw7* dd = nullptr;
|
||||||
|
CALL_ORIG_DDRAW(DirectDrawCreateEx, nullptr, reinterpret_cast<LPVOID*>(&dd), IID_IDirectDraw7, nullptr);
|
||||||
|
if (!dd)
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to create a DirectDraw interface for GDI";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(CompatDirectDraw<IDirectDraw7>::s_origVtable.SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL)))
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to set the cooperative level on the DirectDraw interface for GDI";
|
||||||
|
dd->lpVtbl->Release(dd);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompatDc createCompatDc()
|
||||||
|
{
|
||||||
|
CompatDc compatDc = {};
|
||||||
|
|
||||||
|
IDirectDrawSurface7* surface = createGdiSurface();
|
||||||
|
if (!surface)
|
||||||
|
{
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC dc = nullptr;
|
||||||
|
HRESULT result = surface->lpVtbl->GetDC(surface, &dc);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to create a GDI DC: " << result);
|
||||||
|
surface->lpVtbl->Release(surface);
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
|
||||||
|
compatDc.cacheId = g_cacheId;
|
||||||
|
compatDc.surfaceMemoryDesc.surfaceMemory = g_surfaceMemory;
|
||||||
|
compatDc.surfaceMemoryDesc.pitch = g_pitch;
|
||||||
|
compatDc.dc = dc;
|
||||||
|
compatDc.surface = surface;
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
desc.dwWidth = CompatPrimarySurface::width;
|
||||||
|
desc.dwHeight = CompatPrimarySurface::height;
|
||||||
|
desc.ddpfPixelFormat = CompatPrimarySurface::pixelFormat;
|
||||||
|
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||||
|
desc.lPitch = g_pitch;
|
||||||
|
desc.lpSurface = g_surfaceMemory;
|
||||||
|
|
||||||
|
IDirectDrawSurface7* surface = nullptr;
|
||||||
|
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
||||||
|
g_directDraw, &desc, &surface, nullptr);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to create a GDI surface: " << result);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CompatPrimarySurface::palette)
|
||||||
|
{
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
|
||||||
|
surface, CompatPrimarySurface::palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillCurrentCache()
|
||||||
|
{
|
||||||
|
for (DWORD i = 0; i < Config::gdiDcCacheSize; ++i)
|
||||||
|
{
|
||||||
|
CompatDc compatDc = createCompatDc();
|
||||||
|
if (!compatDc.dc)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_currentCompatDcCache->push_back(compatDc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseCompatDc(CompatDc compatDc)
|
||||||
|
{
|
||||||
|
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
|
||||||
|
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC(
|
||||||
|
compatDc.surface, compatDc.dc)))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to release a cached DC");
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(compatDc.surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseCompatDcCache(std::vector<CompatDc>& compatDcCache)
|
||||||
|
{
|
||||||
|
for (auto& compatDc : compatDcCache)
|
||||||
|
{
|
||||||
|
releaseCompatDc(compatDc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CompatGdiDcCache
|
||||||
|
{
|
||||||
|
CompatDc getDc()
|
||||||
|
{
|
||||||
|
CompatDc compatDc = {};
|
||||||
|
if (!g_currentCompatDcCache)
|
||||||
|
{
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_currentCompatDcCache->empty())
|
||||||
|
{
|
||||||
|
LOG_ONCE("Warning: GDI DC cache size is insufficient");
|
||||||
|
compatDc = createCompatDc();
|
||||||
|
if (!compatDc.dc)
|
||||||
|
{
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compatDc = g_currentCompatDcCache->back();
|
||||||
|
g_currentCompatDcCache->pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
compatDc.dcState = SaveDC(compatDc.dc);
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init()
|
||||||
|
{
|
||||||
|
g_directDraw = createDirectDraw();
|
||||||
|
return nullptr != g_directDraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isReleased()
|
||||||
|
{
|
||||||
|
return g_compatDcCaches.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
if (g_currentCompatDcCache)
|
||||||
|
{
|
||||||
|
g_currentCompatDcCache = nullptr;
|
||||||
|
clearAllCaches();
|
||||||
|
++g_cacheId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void returnDc(const CompatDc& compatDc)
|
||||||
|
{
|
||||||
|
RestoreDC(compatDc.dc, compatDc.dcState);
|
||||||
|
|
||||||
|
if (compatDc.cacheId != g_cacheId)
|
||||||
|
{
|
||||||
|
releaseCompatDc(compatDc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_compatDcCaches[compatDc.surfaceMemoryDesc].push_back(compatDc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSurfaceMemory(void* surfaceMemory, LONG pitch)
|
||||||
|
{
|
||||||
|
g_surfaceMemory = surfaceMemory;
|
||||||
|
g_pitch = pitch;
|
||||||
|
|
||||||
|
if (!surfaceMemory)
|
||||||
|
{
|
||||||
|
g_currentCompatDcCache = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceMemoryDesc surfaceMemoryDesc = { surfaceMemory, pitch };
|
||||||
|
auto it = g_compatDcCaches.find(surfaceMemoryDesc);
|
||||||
|
if (it == g_compatDcCaches.end())
|
||||||
|
{
|
||||||
|
g_currentCompatDcCache = &g_compatDcCaches[surfaceMemoryDesc];
|
||||||
|
fillCurrentCache();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_currentCompatDcCache = &it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
DDrawCompat/CompatGdiDcCache.h
Normal file
33
DDrawCompat/CompatGdiDcCache.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CINTERFACE
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <ddraw.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
namespace CompatGdiDcCache
|
||||||
|
{
|
||||||
|
struct SurfaceMemoryDesc
|
||||||
|
{
|
||||||
|
void* surfaceMemory;
|
||||||
|
LONG pitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompatDc
|
||||||
|
{
|
||||||
|
DWORD cacheId;
|
||||||
|
SurfaceMemoryDesc surfaceMemoryDesc;
|
||||||
|
IDirectDrawSurface7* surface;
|
||||||
|
HDC origDc;
|
||||||
|
HDC dc;
|
||||||
|
int dcState;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompatDc getDc();
|
||||||
|
bool init();
|
||||||
|
bool isReleased();
|
||||||
|
void release();
|
||||||
|
void returnDc(const CompatDc& compatDc);
|
||||||
|
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "CompatDirectDraw.h"
|
#include "CompatDirectDraw.h"
|
||||||
#include "CompatDirectDrawSurface.h"
|
#include "CompatDirectDrawSurface.h"
|
||||||
|
#include "CompatGdiDcCache.h"
|
||||||
#include "CompatGdiSurface.h"
|
#include "CompatGdiSurface.h"
|
||||||
#include "CompatPrimarySurface.h"
|
#include "CompatPrimarySurface.h"
|
||||||
#include "DDrawLog.h"
|
#include "DDrawLog.h"
|
||||||
@ -18,6 +19,8 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
using CompatGdiDcCache::CompatDc;
|
||||||
|
|
||||||
struct CaretData
|
struct CaretData
|
||||||
{
|
{
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
@ -28,12 +31,6 @@ namespace
|
|||||||
bool isDrawn;
|
bool isDrawn;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GdiSurface
|
|
||||||
{
|
|
||||||
IDirectDrawSurface7* surface;
|
|
||||||
HDC origDc;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ExcludeClipRectsData
|
struct ExcludeClipRectsData
|
||||||
{
|
{
|
||||||
HDC compatDc;
|
HDC compatDc;
|
||||||
@ -68,8 +65,7 @@ namespace
|
|||||||
auto g_origShowCaret = &ShowCaret;
|
auto g_origShowCaret = &ShowCaret;
|
||||||
auto g_origHideCaret = &HideCaret;
|
auto g_origHideCaret = &HideCaret;
|
||||||
|
|
||||||
IDirectDraw7* g_directDraw = nullptr;
|
std::unordered_map<HDC, CompatDc> g_dcToCompatDc;
|
||||||
std::unordered_map<HDC, GdiSurface> g_dcToSurface;
|
|
||||||
|
|
||||||
CaretData g_caret = {};
|
CaretData g_caret = {};
|
||||||
|
|
||||||
@ -106,7 +102,7 @@ namespace
|
|||||||
{
|
{
|
||||||
HDC origDc = reinterpret_cast<HDC>(ret->wParam);
|
HDC origDc = reinterpret_cast<HDC>(ret->wParam);
|
||||||
GdiScopedThreadLock gdiLock;
|
GdiScopedThreadLock gdiLock;
|
||||||
if (g_dcToSurface.find(origDc) == g_dcToSurface.end())
|
if (g_dcToCompatDc.find(origDc) == g_dcToCompatDc.end())
|
||||||
{
|
{
|
||||||
HWND hwnd = WindowFromDC(origDc);
|
HWND hwnd = WindowFromDC(origDc);
|
||||||
POINT origin = {};
|
POINT origin = {};
|
||||||
@ -125,58 +121,6 @@ namespace
|
|||||||
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
IDirectDraw7* createDirectDraw()
|
|
||||||
{
|
|
||||||
IDirectDraw7* dd = nullptr;
|
|
||||||
CALL_ORIG_DDRAW(DirectDrawCreateEx, nullptr, reinterpret_cast<LPVOID*>(&dd), IID_IDirectDraw7, nullptr);
|
|
||||||
if (!dd)
|
|
||||||
{
|
|
||||||
Compat::Log() << "Failed to create a DirectDraw interface for GDI";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(CompatDirectDraw<IDirectDraw7>::s_origVtable.SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL)))
|
|
||||||
{
|
|
||||||
Compat::Log() << "Failed to set the cooperative level on the DirectDraw interface for GDI";
|
|
||||||
dd->lpVtbl->Release(dd);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dd;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
desc.dwWidth = CompatPrimarySurface::width;
|
|
||||||
desc.dwHeight = CompatPrimarySurface::height;
|
|
||||||
desc.ddpfPixelFormat = CompatPrimarySurface::pixelFormat;
|
|
||||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
|
||||||
desc.lPitch = CompatPrimarySurface::pitch;
|
|
||||||
desc.lpSurface = CompatPrimarySurface::surfacePtr;
|
|
||||||
|
|
||||||
IDirectDrawSurface7* surface = nullptr;
|
|
||||||
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
|
||||||
g_directDraw, &desc, &surface, nullptr);
|
|
||||||
if (FAILED(result))
|
|
||||||
{
|
|
||||||
LOG_ONCE("Failed to create a GDI surface: " << result);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CompatPrimarySurface::palette)
|
|
||||||
{
|
|
||||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
|
|
||||||
surface, CompatPrimarySurface::palette);
|
|
||||||
}
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
|
BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
||||||
@ -205,51 +149,37 @@ namespace
|
|||||||
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin)
|
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin)
|
||||||
{
|
{
|
||||||
GdiScopedThreadLock gdiLock;
|
GdiScopedThreadLock gdiLock;
|
||||||
if (!CompatPrimarySurface::surfacePtr || !origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
if (!origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
||||||
{
|
{
|
||||||
return origDc;
|
return origDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
HookRecursionGuard recursionGuard;
|
HookRecursionGuard recursionGuard;
|
||||||
|
CompatDc compatDc = CompatGdiDcCache::getDc();
|
||||||
IDirectDrawSurface7* surface = createGdiSurface();
|
if (!compatDc.dc)
|
||||||
if (!surface)
|
|
||||||
{
|
{
|
||||||
return origDc;
|
return origDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
HDC compatDc = nullptr;
|
|
||||||
HRESULT result = surface->lpVtbl->GetDC(surface, &compatDc);
|
|
||||||
if (FAILED(result))
|
|
||||||
{
|
|
||||||
LOG_ONCE("Failed to create a GDI DC: " << result);
|
|
||||||
surface->lpVtbl->Release(surface);
|
|
||||||
return origDc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hwnd)
|
if (hwnd)
|
||||||
{
|
{
|
||||||
SetWindowOrgEx(compatDc, -origin.x, -origin.y, nullptr);
|
SetWindowOrgEx(compatDc.dc, -origin.x, -origin.y, nullptr);
|
||||||
|
|
||||||
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
|
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
|
||||||
GetRandomRgn(origDc, clipRgn, SYSRGN);
|
GetRandomRgn(origDc, clipRgn, SYSRGN);
|
||||||
SelectClipRgn(compatDc, clipRgn);
|
SelectClipRgn(compatDc.dc, clipRgn);
|
||||||
RECT r = {};
|
RECT r = {};
|
||||||
GetRgnBox(clipRgn, &r);
|
GetRgnBox(clipRgn, &r);
|
||||||
DeleteObject(clipRgn);
|
DeleteObject(clipRgn);
|
||||||
|
|
||||||
ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) };
|
ExcludeClipRectsData excludeClipRectsData = { compatDc.dc, origin, GetAncestor(hwnd, GA_ROOT) };
|
||||||
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
|
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
|
||||||
reinterpret_cast<LPARAM>(&excludeClipRectsData));
|
reinterpret_cast<LPARAM>(&excludeClipRectsData));
|
||||||
}
|
}
|
||||||
|
|
||||||
GdiSurface gdiSurface = { surface, origDc };
|
compatDc.origDc = origDc;
|
||||||
g_dcToSurface[compatDc] = gdiSurface;
|
g_dcToCompatDc[compatDc.dc] = compatDc;
|
||||||
|
return compatDc.dc;
|
||||||
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
|
|
||||||
return compatDc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FARPROC getProcAddress(HMODULE module, const char* procName)
|
FARPROC getProcAddress(HMODULE module, const char* procName)
|
||||||
@ -320,22 +250,13 @@ namespace
|
|||||||
|
|
||||||
HookRecursionGuard recursionGuard;
|
HookRecursionGuard recursionGuard;
|
||||||
|
|
||||||
auto it = g_dcToSurface.find(hdc);
|
auto it = g_dcToCompatDc.find(hdc);
|
||||||
|
|
||||||
if (it != g_dcToSurface.end())
|
if (it != g_dcToCompatDc.end())
|
||||||
{
|
{
|
||||||
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
|
||||||
|
|
||||||
if (FAILED(it->second.surface->lpVtbl->ReleaseDC(it->second.surface, hdc)))
|
|
||||||
{
|
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
it->second.surface->lpVtbl->Release(it->second.surface);
|
|
||||||
|
|
||||||
HDC origDc = it->second.origDc;
|
HDC origDc = it->second.origDc;
|
||||||
g_dcToSurface.erase(it);
|
CompatGdiDcCache::returnDc(it->second);
|
||||||
|
g_dcToCompatDc.erase(it);
|
||||||
|
|
||||||
RealPrimarySurface::update();
|
RealPrimarySurface::update();
|
||||||
return origDc;
|
return origDc;
|
||||||
@ -518,8 +439,7 @@ void CompatGdiSurface::hookGdi()
|
|||||||
}
|
}
|
||||||
|
|
||||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||||
g_directDraw = createDirectDraw();
|
if (CompatGdiDcCache::init())
|
||||||
if (g_directDraw)
|
|
||||||
{
|
{
|
||||||
DetourTransactionBegin();
|
DetourTransactionBegin();
|
||||||
hookGdiFunction("GetDC", g_origGetDc, &getDc);
|
hookGdiFunction("GetDC", g_origGetDc, &getDc);
|
||||||
@ -540,3 +460,20 @@ void CompatGdiSurface::hookGdi()
|
|||||||
}
|
}
|
||||||
alreadyHooked = true;
|
alreadyHooked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompatGdiSurface::release()
|
||||||
|
{
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
|
CompatGdiDcCache::release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatGdiSurface::setSurfaceMemory(void* surfaceMemory, LONG pitch)
|
||||||
|
{
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
|
const bool wasReleased = CompatGdiDcCache::isReleased();
|
||||||
|
CompatGdiDcCache::setSurfaceMemory(surfaceMemory, pitch);
|
||||||
|
if (wasReleased)
|
||||||
|
{
|
||||||
|
InvalidateRect(nullptr, nullptr, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,4 +4,6 @@ class CompatGdiSurface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void hookGdi();
|
static void hookGdi();
|
||||||
|
static void release();
|
||||||
|
static void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
||||||
};
|
};
|
||||||
|
@ -15,8 +15,6 @@ namespace
|
|||||||
CompatPrimarySurface::width = 0;
|
CompatPrimarySurface::width = 0;
|
||||||
CompatPrimarySurface::height = 0;
|
CompatPrimarySurface::height = 0;
|
||||||
ZeroMemory(&CompatPrimarySurface::pixelFormat, sizeof(CompatPrimarySurface::pixelFormat));
|
ZeroMemory(&CompatPrimarySurface::pixelFormat, sizeof(CompatPrimarySurface::pixelFormat));
|
||||||
CompatPrimarySurface::pitch = 0;
|
|
||||||
CompatPrimarySurface::surfacePtr = nullptr;
|
|
||||||
|
|
||||||
CompatDirectDrawSurface<IDirectDrawSurface>::resetPrimarySurfacePtr();
|
CompatDirectDrawSurface<IDirectDrawSurface>::resetPrimarySurfacePtr();
|
||||||
CompatDirectDrawSurface<IDirectDrawSurface2>::resetPrimarySurfacePtr();
|
CompatDirectDrawSurface<IDirectDrawSurface2>::resetPrimarySurfacePtr();
|
||||||
@ -56,7 +54,5 @@ namespace CompatPrimarySurface
|
|||||||
LONG width = 0;
|
LONG width = 0;
|
||||||
LONG height = 0;
|
LONG height = 0;
|
||||||
DDPIXELFORMAT pixelFormat = {};
|
DDPIXELFORMAT pixelFormat = {};
|
||||||
LONG pitch = 0;
|
|
||||||
std::atomic<void*> surfacePtr = nullptr;
|
|
||||||
IReleaseNotifier releaseNotifier(onRelease);
|
IReleaseNotifier releaseNotifier(onRelease);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#define CINTERFACE
|
#define CINTERFACE
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <ddraw.h>
|
#include <ddraw.h>
|
||||||
|
|
||||||
class IReleaseNotifier;
|
class IReleaseNotifier;
|
||||||
@ -25,7 +24,5 @@ namespace CompatPrimarySurface
|
|||||||
extern LONG width;
|
extern LONG width;
|
||||||
extern LONG height;
|
extern LONG height;
|
||||||
extern DDPIXELFORMAT pixelFormat;
|
extern DDPIXELFORMAT pixelFormat;
|
||||||
extern LONG pitch;
|
|
||||||
extern std::atomic<void*> surfacePtr;
|
|
||||||
extern IReleaseNotifier releaseNotifier;
|
extern IReleaseNotifier releaseNotifier;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ typedef unsigned long DWORD;
|
|||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
|
const DWORD gdiDcCacheSize = 10;
|
||||||
const DWORD minRefreshInterval = 1000 / 60;
|
const DWORD minRefreshInterval = 1000 / 60;
|
||||||
const DWORD minRefreshIntervalAfterFlip = 1000 / 10;
|
const DWORD minRefreshIntervalAfterFlip = 1000 / 10;
|
||||||
const DWORD minPaletteUpdateInterval = 1000 / 60;
|
const DWORD minPaletteUpdateInterval = 1000 / 60;
|
||||||
|
@ -145,6 +145,7 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="CompatDirectDrawPalette.h" />
|
<ClInclude Include="CompatDirectDrawPalette.h" />
|
||||||
|
<ClInclude Include="CompatGdiDcCache.h" />
|
||||||
<ClInclude Include="CompatGdiSurface.h" />
|
<ClInclude Include="CompatGdiSurface.h" />
|
||||||
<ClInclude Include="Config.h" />
|
<ClInclude Include="Config.h" />
|
||||||
<ClInclude Include="DDrawProcs.h" />
|
<ClInclude Include="DDrawProcs.h" />
|
||||||
@ -166,6 +167,7 @@
|
|||||||
<ClCompile Include="CompatDirectDraw.cpp" />
|
<ClCompile Include="CompatDirectDraw.cpp" />
|
||||||
<ClCompile Include="CompatDirectDrawPalette.cpp" />
|
<ClCompile Include="CompatDirectDrawPalette.cpp" />
|
||||||
<ClCompile Include="CompatDirectDrawSurface.cpp" />
|
<ClCompile Include="CompatDirectDrawSurface.cpp" />
|
||||||
|
<ClCompile Include="CompatGdiDcCache.cpp" />
|
||||||
<ClCompile Include="CompatGdiSurface.cpp" />
|
<ClCompile Include="CompatGdiSurface.cpp" />
|
||||||
<ClCompile Include="CompatVtable.cpp" />
|
<ClCompile Include="CompatVtable.cpp" />
|
||||||
<ClCompile Include="DDrawLog.cpp" />
|
<ClCompile Include="DDrawLog.cpp" />
|
||||||
|
@ -66,6 +66,9 @@
|
|||||||
<ClInclude Include="DDrawScopedThreadLock.h">
|
<ClInclude Include="DDrawScopedThreadLock.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatGdiDcCache.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="DllMain.cpp">
|
<ClCompile Include="DllMain.cpp">
|
||||||
@ -104,6 +107,9 @@
|
|||||||
<ClCompile Include="CompatDirectDrawPalette.cpp">
|
<ClCompile Include="CompatDirectDrawPalette.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatGdiDcCache.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="DDrawCompat.def">
|
<None Include="DDrawCompat.def">
|
||||||
|
@ -302,8 +302,13 @@ bool RealPrimarySurface::isFullScreen()
|
|||||||
|
|
||||||
bool RealPrimarySurface::isLost()
|
bool RealPrimarySurface::isLost()
|
||||||
{
|
{
|
||||||
return g_frontBuffer &&
|
const bool isLost = g_frontBuffer &&
|
||||||
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
|
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
|
||||||
|
if (isLost)
|
||||||
|
{
|
||||||
|
CompatGdiSurface::release();
|
||||||
|
}
|
||||||
|
return isLost;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::release()
|
void RealPrimarySurface::release()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user