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

Revamping GDI interworking - Part 2

Extended GDI redirection to most of the GDI rendering methods.
Readded handling of window messages and extended it to support scrolling.
Readded manual drawing of the caret.
Simplified the DC cache.
This commit is contained in:
narzoul 2016-01-10 00:23:32 +01:00
parent 5a30b072ba
commit 1999d1c56e
16 changed files with 625 additions and 320 deletions

View File

@ -66,10 +66,6 @@ HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::CreateSurface(
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(**lplpDDSurface); CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(**lplpDDSurface);
if (isPrimary)
{
CompatDirectDrawSurface<TSurface>::updateSurfaceParams();
}
} }
return result; return result;

View File

@ -477,7 +477,6 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Flip(
if (This == s_compatPrimarySurface && SUCCEEDED(result)) if (This == s_compatPrimarySurface && SUCCEEDED(result))
{ {
result = RealPrimarySurface::flip(dwFlags); result = RealPrimarySurface::flip(dwFlags);
updateSurfaceParams();
} }
return result; return result;
} }
@ -603,8 +602,7 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Restore(TSurface* T
result = RealPrimarySurface::restore(); result = RealPrimarySurface::restore();
if (wasLost) if (wasLost)
{ {
CompatGdi::releaseSurfaceMemory(); CompatGdi::invalidate();
updateSurfaceParams();
} }
} }
} }
@ -682,20 +680,6 @@ void CompatDirectDrawSurface<TSurface>::restorePrimaryCaps(TDdsCaps& caps)
caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE; caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
} }
template <typename TSurface>
void CompatDirectDrawSurface<TSurface>::updateSurfaceParams()
{
TSurfaceDesc desc = {};
desc.dwSize = sizeof(desc);
g_lockingPrimary = true;
if (SUCCEEDED(s_origVtable.Lock(s_compatPrimarySurface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
{
s_origVtable.Unlock(s_compatPrimarySurface, nullptr);
CompatGdi::setSurfaceMemory(desc.lpSurface, desc.lPitch);
}
g_lockingPrimary = false;
}
template <typename TSurface> template <typename TSurface>
TSurface* CompatDirectDrawSurface<TSurface>::s_compatPrimarySurface = nullptr; TSurface* CompatDirectDrawSurface<TSurface>::s_compatPrimarySurface = nullptr;

View File

@ -23,7 +23,6 @@ public:
static void fixSurfacePtrs(TSurface& surface); static void fixSurfacePtrs(TSurface& surface);
static void initPrimarySurfacePtr(const GUID& guid, IUnknown& surface); static void initPrimarySurfacePtr(const GUID& guid, IUnknown& surface);
static void resetPrimarySurfacePtr(); static void resetPrimarySurfacePtr();
static void updateSurfaceParams();
static HRESULT STDMETHODCALLTYPE Blt( static HRESULT STDMETHODCALLTYPE Blt(
TSurface* This, TSurface* This,

View File

@ -1,14 +1,72 @@
#include "CompatDirectDrawSurface.h"
#include "CompatGdi.h" #include "CompatGdi.h"
#include "CompatGdiCaret.h"
#include "CompatGdiDcCache.h" #include "CompatGdiDcCache.h"
#include "CompatGdiFunctions.h" #include "CompatGdiFunctions.h"
#include "CompatGdiWinProc.h"
#include "CompatPrimarySurface.h"
#include "DDrawProcs.h"
#include "RealPrimarySurface.h"
namespace namespace
{ {
CRITICAL_SECTION g_gdiCriticalSection; DWORD g_renderingDepth = 0;
FARPROC getProcAddress(HMODULE module, const char* procName)
{
if (!module || !procName)
{
return nullptr;
}
PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(module);
if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic) {
return nullptr;
}
char* moduleBase = reinterpret_cast<char*>(module);
PIMAGE_NT_HEADERS ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<char*>(dosHeader) + dosHeader->e_lfanew);
if (IMAGE_NT_SIGNATURE != ntHeader->Signature)
{
return nullptr;
}
PIMAGE_EXPORT_DIRECTORY exportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
moduleBase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* rvaOfNames = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfNames);
for (DWORD i = 0; i < exportDir->NumberOfNames; ++i)
{
if (0 == strcmp(procName, moduleBase + rvaOfNames[i]))
{
WORD* nameOrds = reinterpret_cast<WORD*>(moduleBase + exportDir->AddressOfNameOrdinals);
DWORD* rvaOfFunctions = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfFunctions);
return reinterpret_cast<FARPROC>(moduleBase + rvaOfFunctions[nameOrds[i]]);
}
}
return nullptr;
}
BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM /*lParam*/)
{
DWORD processId = 0;
GetWindowThreadProcessId(hwnd, &processId);
if (processId == GetCurrentProcessId())
{
RedrawWindow(hwnd, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
return TRUE;
}
} }
namespace CompatGdi namespace CompatGdi
{ {
CRITICAL_SECTION g_gdiCriticalSection;
std::unordered_map<void*, const char*> g_funcNames;
GdiScopedThreadLock::GdiScopedThreadLock() GdiScopedThreadLock::GdiScopedThreadLock()
{ {
EnterCriticalSection(&g_gdiCriticalSection); EnterCriticalSection(&g_gdiCriticalSection);
@ -19,29 +77,89 @@ namespace CompatGdi
LeaveCriticalSection(&g_gdiCriticalSection); LeaveCriticalSection(&g_gdiCriticalSection);
} }
bool beginGdiRendering()
{
if (!RealPrimarySurface::isFullScreen())
{
return false;
}
Compat::origProcs.AcquireDDThreadLock();
EnterCriticalSection(&g_gdiCriticalSection);
if (0 == g_renderingDepth)
{
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Lock(
CompatPrimarySurface::surface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
{
LeaveCriticalSection(&g_gdiCriticalSection);
Compat::origProcs.ReleaseDDThreadLock();
return false;
}
CompatGdiDcCache::setSurfaceMemory(desc.lpSurface, desc.lPitch);
}
++g_renderingDepth;
return true;
}
void endGdiRendering()
{
--g_renderingDepth;
if (0 == g_renderingDepth)
{
GdiFlush();
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Unlock(
CompatPrimarySurface::surface, nullptr);
RealPrimarySurface::update();
}
LeaveCriticalSection(&g_gdiCriticalSection);
Compat::origProcs.ReleaseDDThreadLock();
}
void hookGdiFunction(const char* moduleName, const char* funcName, void*& origFuncPtr, void* newFuncPtr)
{
#ifdef _DEBUG
g_funcNames[origFuncPtr] = funcName;
#endif
FARPROC procAddr = getProcAddress(GetModuleHandle(moduleName), funcName);
if (!procAddr)
{
Compat::Log() << "Failed to load the address of a GDI function: " << funcName;
return;
}
origFuncPtr = procAddr;
if (NO_ERROR != DetourAttach(&origFuncPtr, newFuncPtr))
{
Compat::Log() << "Failed to hook a GDI function: " << funcName;
return;
}
}
void installHooks() void installHooks()
{ {
InitializeCriticalSection(&g_gdiCriticalSection); InitializeCriticalSection(&g_gdiCriticalSection);
if (CompatGdiDcCache::init()) if (CompatGdiDcCache::init())
{ {
CompatGdiFunctions::hookGdiFunctions(); CompatGdiFunctions::installHooks();
CompatGdiWinProc::installHooks();
CompatGdiCaret::installHooks();
} }
} }
void releaseSurfaceMemory() void invalidate()
{ {
GdiScopedThreadLock gdiLock; EnumWindows(&invalidateWindow, 0);
CompatGdiDcCache::release();
} }
void setSurfaceMemory(void* surfaceMemory, int pitch) void updatePalette()
{ {
GdiScopedThreadLock gdiLock; GdiScopedThreadLock gdiLock;
const bool wasReleased = CompatGdiDcCache::isReleased(); CompatGdiDcCache::clear();
CompatGdiDcCache::setSurfaceMemory(surfaceMemory, pitch);
if (wasReleased)
{
InvalidateRect(nullptr, nullptr, TRUE);
}
} }
} }

View File

@ -1,5 +1,15 @@
#pragma once #pragma once
#define WIN32_LEAN_AND_MEAN
#include <unordered_map>
#include <Windows.h>
#include "DDrawLog.h"
#define CALL_ORIG_GDI(func) CompatGdi::getOrigFuncPtr<decltype(&func), &func>()
namespace CompatGdi namespace CompatGdi
{ {
class GdiScopedThreadLock class GdiScopedThreadLock
@ -9,7 +19,29 @@ namespace CompatGdi
~GdiScopedThreadLock(); ~GdiScopedThreadLock();
}; };
extern CRITICAL_SECTION g_gdiCriticalSection;
extern std::unordered_map<void*, const char*> g_funcNames;
bool beginGdiRendering();
void endGdiRendering();
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
OrigFuncPtr& getOrigFuncPtr()
{
static OrigFuncPtr origFuncPtr = origFunc;
return origFuncPtr;
}
void hookGdiFunction(const char* moduleName, const char* funcName, void*& origFuncPtr, void* newFuncPtr);
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
void hookGdiFunction(const char* moduleName, const char* funcName, OrigFuncPtr newFuncPtr)
{
hookGdiFunction(moduleName, funcName,
reinterpret_cast<void*&>(getOrigFuncPtr<OrigFuncPtr, origFunc>()), newFuncPtr);
}
void installHooks(); void installHooks();
void releaseSurfaceMemory(); void invalidate();
void setSurfaceMemory(void* surfaceMemory, int pitch); void updatePalette();
}; };

View File

@ -0,0 +1,160 @@
#define CINTERFACE
#define WIN32_LEAN_AND_MEAN
#include <oleacc.h>
#include <Windows.h>
#include <detours.h>
#include "CompatGdi.h"
#include "CompatGdiCaret.h"
#include "CompatGdiDc.h"
namespace
{
struct CaretData
{
HWND hwnd;
long left;
long top;
long width;
long height;
bool isDrawn;
};
CaretData g_caret = {};
void drawCaret()
{
if (CompatGdi::beginGdiRendering())
{
HDC dc = GetDC(g_caret.hwnd);
HDC compatDc = CompatGdiDc::getDc(dc);
PatBlt(compatDc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT);
CompatGdiDc::releaseDc(dc);
ReleaseDC(g_caret.hwnd, dc);
CompatGdi::endGdiRendering();
}
}
LONG getCaretState(IAccessible* accessible)
{
VARIANT varChild = {};
varChild.vt = VT_I4;
varChild.lVal = CHILDID_SELF;
VARIANT varState = {};
accessible->lpVtbl->get_accState(accessible, varChild, &varState);
return varState.lVal;
}
void CALLBACK caretDestroyEvent(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD /*event*/,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD /*dwEventThread*/,
DWORD /*dwmsEventTime*/)
{
CompatGdi::GdiScopedThreadLock gdiLock;
if (OBJID_CARET != idObject || !g_caret.isDrawn || g_caret.hwnd != hwnd)
{
return;
}
IAccessible* accessible = nullptr;
VARIANT varChild = {};
AccessibleObjectFromEvent(hwnd, idObject, idChild, &accessible, &varChild);
if (accessible)
{
if (STATE_SYSTEM_INVISIBLE == getCaretState(accessible))
{
drawCaret();
g_caret.isDrawn = false;
}
accessible->lpVtbl->Release(accessible);
}
}
BOOL WINAPI createCaret(HWND hWnd, HBITMAP hBitmap, int nWidth, int nHeight)
{
BOOL result = CALL_ORIG_GDI(CreateCaret)(hWnd, hBitmap, nWidth, nHeight);
if (result)
{
CompatGdi::GdiScopedThreadLock gdiLock;
if (g_caret.isDrawn)
{
drawCaret();
g_caret.isDrawn = false;
}
g_caret.width = nWidth ? nWidth : GetSystemMetrics(SM_CXBORDER);
g_caret.height = nHeight ? nHeight : GetSystemMetrics(SM_CYBORDER);
}
return result;
}
BOOL WINAPI showCaret(HWND hWnd)
{
if (!CALL_ORIG_GDI(ShowCaret)(hWnd))
{
return FALSE;
}
CompatGdi::GdiScopedThreadLock gdiLock;
if (!g_caret.isDrawn)
{
IAccessible* accessible = nullptr;
AccessibleObjectFromWindow(hWnd, static_cast<DWORD>(OBJID_CARET), IID_IAccessible,
reinterpret_cast<void**>(&accessible));
if (accessible)
{
if (0 == getCaretState(accessible))
{
POINT caretPos = {};
GetCaretPos(&caretPos);
g_caret.left = caretPos.x;
g_caret.top = caretPos.y;
g_caret.hwnd = hWnd;
drawCaret();
g_caret.isDrawn = true;
}
accessible->lpVtbl->Release(accessible);
}
}
return TRUE;
}
BOOL WINAPI hideCaret(HWND hWnd)
{
BOOL result = CALL_ORIG_GDI(HideCaret)(hWnd);
if (result)
{
CompatGdi::GdiScopedThreadLock gdiLock;
if (g_caret.isDrawn)
{
drawCaret();
g_caret.isDrawn = false;
}
}
return result;
}
}
#define HOOK_GDI_FUNCTION(module, func, newFunc) \
CompatGdi::hookGdiFunction<decltype(&func), &func>(#module, #func, &newFunc);
namespace CompatGdiCaret
{
void installHooks()
{
DetourTransactionBegin();
HOOK_GDI_FUNCTION(user32, CreateCaret, createCaret);
HOOK_GDI_FUNCTION(user32, ShowCaret, showCaret);
HOOK_GDI_FUNCTION(user32, HideCaret, hideCaret);
DetourTransactionCommit();
const DWORD threadId = GetCurrentThreadId();
SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY,
nullptr, &caretDestroyEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
}
}

View File

@ -1,9 +1,27 @@
#include <algorithm>
#include <unordered_map>
#include "CompatGdiDc.h" #include "CompatGdiDc.h"
#include "CompatGdiDcCache.h" #include "CompatGdiDcCache.h"
#include "RealPrimarySurface.h" #include "DDrawLog.h"
namespace namespace
{ {
using CompatGdiDcCache::CachedDc;
struct CompatDc : CachedDc
{
CompatDc(const CachedDc& cachedDc = {}) : CachedDc(cachedDc) {}
DWORD refCount;
HDC origDc;
HGDIOBJ origFont;
HGDIOBJ origBrush;
HGDIOBJ origPen;
};
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
CompatDcMap g_origDcToCompatDc;
struct ExcludeClipRectsData struct ExcludeClipRectsData
{ {
HDC compatDc; HDC compatDc;
@ -11,6 +29,35 @@ namespace
HWND rootWnd; HWND rootWnd;
}; };
void copyDcAttributes(CompatDc& compatDc, HDC origDc, POINT& origin)
{
compatDc.origFont = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT));
compatDc.origBrush = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
compatDc.origPen = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_PEN));
SetArcDirection(compatDc.dc, GetArcDirection(origDc));
SetBkColor(compatDc.dc, GetBkColor(origDc));
SetBkMode(compatDc.dc, GetBkMode(origDc));
SetDCBrushColor(compatDc.dc, GetDCBrushColor(origDc));
SetDCPenColor(compatDc.dc, GetDCPenColor(origDc));
SetPolyFillMode(compatDc.dc, GetPolyFillMode(origDc));
SetROP2(compatDc.dc, GetROP2(origDc));
SetStretchBltMode(compatDc.dc, GetStretchBltMode(origDc));
SetTextAlign(compatDc.dc, GetTextAlign(origDc));
SetTextCharacterExtra(compatDc.dc, GetTextCharacterExtra(origDc));
SetTextColor(compatDc.dc, GetTextColor(origDc));
SetWindowOrgEx(compatDc.dc, -origin.x, -origin.y, nullptr);
POINT brushOrg = {};
GetBrushOrgEx(origDc, &brushOrg);
SetBrushOrgEx(compatDc.dc, brushOrg.x, brushOrg.y, nullptr);
POINT currentPos = {};
MoveToEx(origDc, 0, 0, &currentPos);
MoveToEx(origDc, currentPos.x, currentPos.y, nullptr);
MoveToEx(compatDc.dc, currentPos.x, currentPos.y, nullptr);
}
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);
@ -19,56 +66,102 @@ namespace
return FALSE; return FALSE;
} }
if (!IsWindowVisible(hwnd))
{
return TRUE;
}
RECT rect = {}; RECT rect = {};
GetWindowRect(hwnd, &rect); GetWindowRect(hwnd, &rect);
OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y); OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y);
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom); ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom);
return TRUE; return TRUE;
} }
void setClippingRegion(HDC compatDc, HDC origDc, POINT& origin)
{
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
const bool isEmptyClipRgn = 1 != GetRandomRgn(origDc, clipRgn, SYSRGN);
SelectClipRgn(compatDc, isEmptyClipRgn ? nullptr : clipRgn);
DeleteObject(clipRgn);
HRGN origClipRgn = CreateRectRgn(0, 0, 0, 0);
if (1 == GetClipRgn(origDc, origClipRgn))
{
OffsetRgn(origClipRgn, origin.x, origin.y);
ExtSelectClipRgn(compatDc, origClipRgn, RGN_AND);
}
DeleteObject(origClipRgn);
if (!isEmptyClipRgn)
{
HWND hwnd = WindowFromDC(origDc);
if (hwnd)
{
ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) };
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
reinterpret_cast<LPARAM>(&excludeClipRectsData));
RECT windowRect = {};
GetWindowRect(hwnd, &windowRect);
}
}
}
} }
namespace CompatGdiDc namespace CompatGdiDc
{ {
CachedDc getDc(HDC origDc) HDC getDc(HDC origDc)
{ {
CachedDc cachedDc = {}; if (!origDc || OBJ_DC != GetObjectType(origDc) || DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY) ||
if (!origDc || !RealPrimarySurface::isFullScreen() || g_origDcToCompatDc.end() != std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
OBJ_DC != GetObjectType(origDc) || [=](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == origDc; }))
DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY))
{ {
return cachedDc; return nullptr;
} }
cachedDc = CompatGdiDcCache::getDc(); auto it = g_origDcToCompatDc.find(origDc);
if (!cachedDc.dc) if (it != g_origDcToCompatDc.end())
{ {
return cachedDc; ++it->second.refCount;
return it->second.dc;
} }
HWND hwnd = WindowFromDC(origDc); CompatDc compatDc(CompatGdiDcCache::getDc());
if (hwnd) if (!compatDc.dc)
{ {
POINT origin = {}; return nullptr;
GetDCOrgEx(origDc, &origin);
SetWindowOrgEx(cachedDc.dc, -origin.x, -origin.y, nullptr);
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
GetRandomRgn(origDc, clipRgn, SYSRGN);
SelectClipRgn(cachedDc.dc, clipRgn);
RECT r = {};
GetRgnBox(clipRgn, &r);
DeleteObject(clipRgn);
ExcludeClipRectsData excludeClipRectsData = { cachedDc.dc, origin, GetAncestor(hwnd, GA_ROOT) };
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
reinterpret_cast<LPARAM>(&excludeClipRectsData));
} }
return cachedDc; POINT origin = {};
GetDCOrgEx(origDc, &origin);
copyDcAttributes(compatDc, origDc, origin);
setClippingRegion(compatDc.dc, origDc, origin);
compatDc.refCount = 1;
compatDc.origDc = origDc;
g_origDcToCompatDc.insert(CompatDcMap::value_type(origDc, compatDc));
return compatDc.dc;
} }
void releaseDc(const CachedDc& cachedDc) void releaseDc(HDC origDc)
{ {
CompatGdiDcCache::releaseDc(cachedDc); auto it = g_origDcToCompatDc.find(origDc);
if (it == g_origDcToCompatDc.end())
{
return;
}
CompatDc& compatDc = it->second;
--compatDc.refCount;
if (0 == compatDc.refCount)
{
SelectObject(compatDc.dc, compatDc.origFont);
SelectObject(compatDc.dc, compatDc.origBrush);
SelectObject(compatDc.dc, compatDc.origPen);
CompatGdiDcCache::releaseDc(compatDc);
g_origDcToCompatDc.erase(origDc);
}
} }
} }

View File

@ -4,12 +4,8 @@
#include <Windows.h> #include <Windows.h>
#include "CompatGdiDcCache.h"
namespace CompatGdiDc namespace CompatGdiDc
{ {
using CompatGdiDcCache::CachedDc; HDC getDc(HDC origDc);
void releaseDc(HDC origDc);
CachedDc getDc(HDC origDc);
void releaseDc(const CachedDc& cachedDc);
} }

View File

@ -1,4 +1,3 @@
#include <map>
#include <vector> #include <vector>
#include "CompatDirectDraw.h" #include "CompatDirectDraw.h"
@ -8,41 +7,18 @@
#include "Config.h" #include "Config.h"
#include "DDrawLog.h" #include "DDrawLog.h"
#include "DDrawProcs.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 namespace
{ {
using CompatGdiDcCache::SurfaceMemoryDesc;
using CompatGdiDcCache::CachedDc; using CompatGdiDcCache::CachedDc;
std::map<SurfaceMemoryDesc, std::vector<CachedDc>> g_caches; std::vector<CachedDc> g_cache;
std::vector<CachedDc>* g_currentCache = nullptr;
IDirectDraw7* g_directDraw = nullptr; IDirectDraw7* g_directDraw = nullptr;
void* g_surfaceMemory = nullptr; void* g_surfaceMemory = nullptr;
LONG g_pitch = 0; LONG g_pitch = 0;
IDirectDrawSurface7* createGdiSurface(); IDirectDrawSurface7* createGdiSurface();
void releaseCachedDc(CachedDc cachedDc);
void releaseCache(std::vector<CachedDc>& cache);
void clearAllCaches()
{
for (auto& cache : g_caches)
{
releaseCache(cache.second);
}
g_caches.clear();
}
IDirectDraw7* createDirectDraw() IDirectDraw7* createDirectDraw()
{ {
@ -86,17 +62,13 @@ namespace
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks // Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
Compat::origProcs.ReleaseDDThreadLock(); Compat::origProcs.ReleaseDDThreadLock();
cachedDc.surfaceMemoryDesc.surfaceMemory = g_surfaceMemory;
cachedDc.surfaceMemoryDesc.pitch = g_pitch;
cachedDc.dc = dc;
cachedDc.surface = surface; cachedDc.surface = surface;
cachedDc.dc = dc;
return cachedDc; return cachedDc;
} }
IDirectDrawSurface7* createGdiSurface() IDirectDrawSurface7* createGdiSurface()
{ {
Compat::DDrawScopedThreadLock ddLock;
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;
@ -125,66 +97,49 @@ namespace
return surface; return surface;
} }
void fillCurrentCache()
{
for (DWORD i = 0; i < Config::gdiDcCacheSize; ++i)
{
CachedDc cachedDc = createCachedDc();
if (!cachedDc.dc)
{
return;
}
g_currentCache->push_back(cachedDc);
}
}
void releaseCachedDc(CachedDc cachedDc) void releaseCachedDc(CachedDc cachedDc)
{ {
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC // Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
Compat::origProcs.AcquireDDThreadLock(); Compat::origProcs.AcquireDDThreadLock();
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC( HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC(
cachedDc.surface, cachedDc.dc))) cachedDc.surface, cachedDc.dc);
if (FAILED(result))
{ {
LOG_ONCE("Failed to release a cached DC"); LOG_ONCE("Failed to release a cached DC: " << result);
Compat::origProcs.ReleaseDDThreadLock();
} }
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(cachedDc.surface); CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(cachedDc.surface);
} }
void releaseCache(std::vector<CachedDc>& cache)
{
for (auto& cachedDc : cache)
{
releaseCachedDc(cachedDc);
}
}
} }
namespace CompatGdiDcCache namespace CompatGdiDcCache
{ {
void clear()
{
for (auto& cachedDc : g_cache)
{
releaseCachedDc(cachedDc);
}
g_cache.clear();
}
CachedDc getDc() CachedDc getDc()
{ {
CachedDc cachedDc = {}; CachedDc cachedDc = {};
if (!g_currentCache) if (!g_surfaceMemory)
{ {
return cachedDc; return cachedDc;
} }
if (g_currentCache->empty()) if (g_cache.empty())
{ {
LOG_ONCE("Warning: GDI DC cache size is insufficient");
cachedDc = createCachedDc(); cachedDc = createCachedDc();
if (!cachedDc.dc)
{
return cachedDc;
}
} }
else else
{ {
cachedDc = g_currentCache->back(); cachedDc = g_cache.back();
g_currentCache->pop_back(); g_cache.pop_back();
} }
return cachedDc; return cachedDc;
@ -196,46 +151,20 @@ namespace CompatGdiDcCache
return nullptr != g_directDraw; return nullptr != g_directDraw;
} }
bool isReleased()
{
return g_caches.empty();
}
void release()
{
if (g_currentCache)
{
g_currentCache = nullptr;
clearAllCaches();
}
}
void releaseDc(const CachedDc& cachedDc) void releaseDc(const CachedDc& cachedDc)
{ {
g_caches[cachedDc.surfaceMemoryDesc].push_back(cachedDc); g_cache.push_back(cachedDc);
} }
void setSurfaceMemory(void* surfaceMemory, LONG pitch) void setSurfaceMemory(void* surfaceMemory, LONG pitch)
{ {
g_surfaceMemory = surfaceMemory; if (g_surfaceMemory == surfaceMemory && g_pitch == pitch)
g_pitch = pitch;
if (!surfaceMemory)
{ {
g_currentCache = nullptr;
return; return;
} }
SurfaceMemoryDesc surfaceMemoryDesc = { surfaceMemory, pitch }; g_surfaceMemory = surfaceMemory;
auto it = g_caches.find(surfaceMemoryDesc); g_pitch = pitch;
if (it == g_caches.end()) clear();
{
g_currentCache = &g_caches[surfaceMemoryDesc];
fillCurrentCache();
}
else
{
g_currentCache = &it->second;
}
} }
} }

View File

@ -8,23 +8,15 @@
namespace CompatGdiDcCache namespace CompatGdiDcCache
{ {
struct SurfaceMemoryDesc
{
void* surfaceMemory;
LONG pitch;
};
struct CachedDc struct CachedDc
{ {
SurfaceMemoryDesc surfaceMemoryDesc;
IDirectDrawSurface7* surface; IDirectDrawSurface7* surface;
HDC dc; HDC dc;
}; };
void clear();
CachedDc getDc(); CachedDc getDc();
bool init(); bool init();
bool isReleased();
void release();
void releaseDc(const CachedDc& cachedDc); void releaseDc(const CachedDc& cachedDc);
void setSurfaceMemory(void* surfaceMemory, LONG pitch); void setSurfaceMemory(void* surfaceMemory, LONG pitch);
} }

View File

@ -1,42 +1,30 @@
#include <algorithm>
#include <unordered_map>
#include <vector>
#include "CompatDirectDrawSurface.h"
#include "CompatGdi.h" #include "CompatGdi.h"
#include "CompatGdiDc.h" #include "CompatGdiDc.h"
#include "CompatGdiFunctions.h" #include "CompatGdiFunctions.h"
#include "CompatPrimarySurface.h"
#include "DDrawLog.h" #include "DDrawLog.h"
#include "DDrawScopedThreadLock.h"
#include "RealPrimarySurface.h"
#include <detours.h> #include <detours.h>
namespace namespace
{ {
using CompatGdiDc::CachedDc;
struct CompatDc : CachedDc
{
CompatDc(const CachedDc& cachedDc) : CachedDc(cachedDc) {}
HGDIOBJ origFont;
HGDIOBJ origBrush;
HGDIOBJ origPen;
};
std::unordered_map<void*, const char*> g_funcNames;
std::vector<CompatDc> g_usedCompatDcs;
DWORD* g_usedCompatDcCount = nullptr;
template <typename Result, typename... Params> template <typename Result, typename... Params>
using FuncPtr = Result(WINAPI *)(Params...); using FuncPtr = Result(WINAPI *)(Params...);
template <typename OrigFuncPtr, OrigFuncPtr origFunc> bool hasDisplayDcArg(HDC dc)
OrigFuncPtr& getOrigFuncPtr()
{ {
static OrigFuncPtr origFuncPtr = origFunc; return dc && OBJ_DC == GetObjectType(dc) && DT_RASDISPLAY == GetDeviceCaps(dc, TECHNOLOGY);
return origFuncPtr; }
template <typename T>
bool hasDisplayDcArg(T)
{
return false;
}
template <typename T, typename... Params>
bool hasDisplayDcArg(T t, Params... params)
{
return hasDisplayDcArg(t) || hasDisplayDcArg(params...);
} }
template <typename T> template <typename T>
@ -47,140 +35,147 @@ namespace
HDC replaceDc(HDC dc) HDC replaceDc(HDC dc)
{ {
auto it = std::find_if(g_usedCompatDcs.begin(), g_usedCompatDcs.end(), HDC compatDc = CompatGdiDc::getDc(dc);
[dc](const CompatDc& compatDc) { return compatDc.dc == dc; }); return compatDc ? compatDc : dc;
if (it != g_usedCompatDcs.end()) }
{
return it->dc;
}
CompatDc compatDc = CompatGdiDc::getDc(dc); template <typename T>
if (!compatDc.dc) void releaseDc(T) {}
{
return dc;
}
compatDc.origFont = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_FONT)); void releaseDc(HDC dc)
compatDc.origBrush = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_BRUSH)); {
compatDc.origPen = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_PEN)); CompatGdiDc::releaseDc(dc);
SetTextColor(compatDc.dc, GetTextColor(dc)); }
SetBkColor(compatDc.dc, GetBkColor(dc));
SetBkMode(compatDc.dc, GetBkMode(dc));
g_usedCompatDcs.push_back(compatDc); template <typename T, typename... Params>
++*g_usedCompatDcCount; void releaseDc(T t, Params... params)
return compatDc.dc; {
releaseDc(params...);
releaseDc(t);
} }
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params> template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
Result WINAPI compatGdiFunc(Params... params) Result WINAPI compatGdiFunc(Params... params)
{ {
CompatGdi::GdiScopedThreadLock gdiLock; if (!hasDisplayDcArg(params...) || !CompatGdi::beginGdiRendering())
Compat::DDrawScopedThreadLock ddLock;
DWORD usedCompatDcCount = 0;
g_usedCompatDcCount = &usedCompatDcCount;
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Lock(
CompatPrimarySurface::surface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
{ {
return getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...); return CompatGdi::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
} }
Result result = getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...); #ifdef _DEBUG
GdiFlush(); Compat::LogEnter(CompatGdi::g_funcNames[origFunc], params...);
#endif
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Unlock( Result result = CompatGdi::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
CompatPrimarySurface::surface, nullptr); releaseDc(params...);
CompatGdi::endGdiRendering();
if (0 != usedCompatDcCount) #ifdef _DEBUG
{ Compat::LogLeave(CompatGdi::g_funcNames[origFunc], params...) << result;
RealPrimarySurface::update(); #endif
}
for (DWORD i = 0; i < usedCompatDcCount; ++i)
{
CompatDc& compatDc = g_usedCompatDcs.back();
SelectObject(compatDc.dc, compatDc.origFont);
SelectObject(compatDc.dc, compatDc.origBrush);
SelectObject(compatDc.dc, compatDc.origPen);
CompatGdiDc::releaseDc(compatDc);
g_usedCompatDcs.pop_back();
}
return result; return result;
} }
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params> template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
OrigFuncPtr getCompatGdiFuncPtr(FuncPtr<Result, Params...>&) OrigFuncPtr getCompatGdiFuncPtr(FuncPtr<Result, Params...>)
{ {
return &compatGdiFunc<OrigFuncPtr, origFunc, Result, Params...>; return &compatGdiFunc<OrigFuncPtr, origFunc, Result, Params...>;
} }
FARPROC getProcAddress(HMODULE module, const char* procName)
{
if (!module || !procName)
{
return nullptr;
}
PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(module);
if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic) {
return nullptr;
}
char* moduleBase = reinterpret_cast<char*>(module);
PIMAGE_NT_HEADERS ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<char*>(dosHeader) + dosHeader->e_lfanew);
if (IMAGE_NT_SIGNATURE != ntHeader->Signature)
{
return nullptr;
}
PIMAGE_EXPORT_DIRECTORY exportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
moduleBase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* rvaOfNames = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfNames);
for (DWORD i = 0; i < exportDir->NumberOfNames; ++i)
{
if (0 == strcmp(procName, moduleBase + rvaOfNames[i]))
{
WORD* nameOrds = reinterpret_cast<WORD*>(moduleBase + exportDir->AddressOfNameOrdinals);
DWORD* rvaOfFunctions = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfFunctions);
return reinterpret_cast<FARPROC>(moduleBase + rvaOfFunctions[nameOrds[i]]);
}
}
return nullptr;
}
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
void hookGdiFunction(const char* moduleName, const char* funcName)
{
OrigFuncPtr& origFuncPtr = getOrigFuncPtr<OrigFuncPtr, origFunc>();
origFuncPtr = reinterpret_cast<OrigFuncPtr>(getProcAddress(GetModuleHandle(moduleName), funcName));
OrigFuncPtr newFuncPtr = getCompatGdiFuncPtr<OrigFuncPtr, origFunc>(origFuncPtr);
DetourAttach(reinterpret_cast<void**>(&origFuncPtr), newFuncPtr);
g_funcNames[origFunc] = funcName;
}
} }
void CompatGdiFunctions::hookGdiFunctions() #define HOOK_GDI_FUNCTION(module, func) \
{ CompatGdi::hookGdiFunction<decltype(&func), &func>( \
#define HOOK_GDI_FUNCTION(module, func) hookGdiFunction<decltype(&func), &func>(#module, #func); #module, #func, getCompatGdiFuncPtr<decltype(&func), &func>(&func));
#define HOOK_GDI_TEXT_FUNCTION(module, func) \ #define HOOK_GDI_TEXT_FUNCTION(module, func) \
HOOK_GDI_FUNCTION(module, func##A); \ HOOK_GDI_FUNCTION(module, func##A); \
HOOK_GDI_FUNCTION(module, func##W) HOOK_GDI_FUNCTION(module, func##W)
DetourTransactionBegin(); namespace CompatGdiFunctions
HOOK_GDI_FUNCTION(gdi32, BitBlt); {
DetourTransactionCommit(); void installHooks()
{
DetourTransactionBegin();
#undef HOOK_GDI_TEXT_FUNCTION // Bitmap functions
#undef HOOK_GDI_FUNCTION HOOK_GDI_FUNCTION(msimg32, AlphaBlend);
HOOK_GDI_FUNCTION(gdi32, BitBlt);
HOOK_GDI_FUNCTION(gdi32, CreateCompatibleBitmap);
HOOK_GDI_FUNCTION(gdi32, CreateDIBitmap);
HOOK_GDI_FUNCTION(gdi32, CreateDIBSection);
HOOK_GDI_FUNCTION(gdi32, CreateDiscardableBitmap);
HOOK_GDI_FUNCTION(gdi32, ExtFloodFill);
HOOK_GDI_FUNCTION(gdi32, GetDIBits);
HOOK_GDI_FUNCTION(gdi32, GetPixel);
HOOK_GDI_FUNCTION(msimg32, GradientFill);
HOOK_GDI_FUNCTION(gdi32, MaskBlt);
HOOK_GDI_FUNCTION(gdi32, PlgBlt);
HOOK_GDI_FUNCTION(gdi32, SetDIBits);
HOOK_GDI_FUNCTION(gdi32, SetDIBitsToDevice);
HOOK_GDI_FUNCTION(gdi32, SetPixel);
HOOK_GDI_FUNCTION(gdi32, SetPixelV);
HOOK_GDI_FUNCTION(gdi32, StretchBlt);
HOOK_GDI_FUNCTION(gdi32, StretchDIBits);
HOOK_GDI_FUNCTION(msimg32, TransparentBlt);
// Brush functions
HOOK_GDI_FUNCTION(gdi32, PatBlt);
// Device context functions
HOOK_GDI_FUNCTION(gdi32, CreateCompatibleDC);
HOOK_GDI_FUNCTION(gdi32, DrawEscape);
// Filled shape functions
HOOK_GDI_FUNCTION(gdi32, Chord);
HOOK_GDI_FUNCTION(gdi32, Ellipse);
HOOK_GDI_FUNCTION(user32, FillRect);
HOOK_GDI_FUNCTION(user32, FrameRect);
HOOK_GDI_FUNCTION(user32, InvertRect);
HOOK_GDI_FUNCTION(gdi32, Pie);
HOOK_GDI_FUNCTION(gdi32, Polygon);
HOOK_GDI_FUNCTION(gdi32, PolyPolygon);
HOOK_GDI_FUNCTION(gdi32, Rectangle);
HOOK_GDI_FUNCTION(gdi32, RoundRect);
// Font and text functions
HOOK_GDI_TEXT_FUNCTION(user32, DrawText);
HOOK_GDI_TEXT_FUNCTION(user32, DrawTextEx);
HOOK_GDI_TEXT_FUNCTION(gdi32, ExtTextOut);
HOOK_GDI_TEXT_FUNCTION(gdi32, PolyTextOut);
HOOK_GDI_TEXT_FUNCTION(user32, TabbedTextOut);
HOOK_GDI_TEXT_FUNCTION(gdi32, TextOut);
// Line and curve functions
HOOK_GDI_FUNCTION(gdi32, AngleArc);
HOOK_GDI_FUNCTION(gdi32, Arc);
HOOK_GDI_FUNCTION(gdi32, ArcTo);
HOOK_GDI_FUNCTION(gdi32, LineTo);
HOOK_GDI_FUNCTION(gdi32, PolyBezier);
HOOK_GDI_FUNCTION(gdi32, PolyBezierTo);
HOOK_GDI_FUNCTION(gdi32, PolyDraw);
HOOK_GDI_FUNCTION(gdi32, Polyline);
HOOK_GDI_FUNCTION(gdi32, PolylineTo);
HOOK_GDI_FUNCTION(gdi32, PolyPolyline);
// Painting and drawing functions
HOOK_GDI_FUNCTION(user32, DrawCaption);
HOOK_GDI_FUNCTION(user32, DrawEdge);
HOOK_GDI_FUNCTION(user32, DrawFocusRect);
HOOK_GDI_FUNCTION(user32, DrawFrameControl);
HOOK_GDI_TEXT_FUNCTION(user32, DrawState);
HOOK_GDI_TEXT_FUNCTION(user32, GrayString);
HOOK_GDI_FUNCTION(user32, PaintDesktop);
// Region functions
HOOK_GDI_FUNCTION(gdi32, FillRgn);
HOOK_GDI_FUNCTION(gdi32, FrameRgn);
HOOK_GDI_FUNCTION(gdi32, InvertRgn);
HOOK_GDI_FUNCTION(gdi32, PaintRgn);
// Scroll bar functions
HOOK_GDI_FUNCTION(user32, ScrollDC);
DetourTransactionCommit();
}
} }

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
class CompatGdiFunctions namespace CompatGdiFunctions
{ {
public: void installHooks();
static void hookGdiFunctions();
}; };

View File

@ -4,7 +4,6 @@ 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;

View File

@ -94,7 +94,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile> <ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -121,7 +121,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile> <ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>No</GenerateDebugInformation> <GenerateDebugInformation>No</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -146,9 +146,11 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="CompatDirectDrawPalette.h" /> <ClInclude Include="CompatDirectDrawPalette.h" />
<ClInclude Include="CompatGdi.h" /> <ClInclude Include="CompatGdi.h" />
<ClInclude Include="CompatGdiCaret.h" />
<ClInclude Include="CompatGdiDc.h" /> <ClInclude Include="CompatGdiDc.h" />
<ClInclude Include="CompatGdiDcCache.h" /> <ClInclude Include="CompatGdiDcCache.h" />
<ClInclude Include="CompatGdiFunctions.h" /> <ClInclude Include="CompatGdiFunctions.h" />
<ClInclude Include="CompatGdiWinProc.h" />
<ClInclude Include="Config.h" /> <ClInclude Include="Config.h" />
<ClInclude Include="DDrawProcs.h" /> <ClInclude Include="DDrawProcs.h" />
<ClInclude Include="CompatDirectDraw.h" /> <ClInclude Include="CompatDirectDraw.h" />
@ -170,8 +172,10 @@
<ClCompile Include="CompatDirectDrawPalette.cpp" /> <ClCompile Include="CompatDirectDrawPalette.cpp" />
<ClCompile Include="CompatDirectDrawSurface.cpp" /> <ClCompile Include="CompatDirectDrawSurface.cpp" />
<ClCompile Include="CompatGdi.cpp" /> <ClCompile Include="CompatGdi.cpp" />
<ClCompile Include="CompatGdiCaret.cpp" />
<ClCompile Include="CompatGdiDcCache.cpp" /> <ClCompile Include="CompatGdiDcCache.cpp" />
<ClCompile Include="CompatGdiFunctions.cpp" /> <ClCompile Include="CompatGdiFunctions.cpp" />
<ClCompile Include="CompatGdiWinProc.cpp" />
<ClCompile Include="CompatVtable.cpp" /> <ClCompile Include="CompatVtable.cpp" />
<ClCompile Include="DDrawLog.cpp" /> <ClCompile Include="DDrawLog.cpp" />
<ClCompile Include="DllMain.cpp" /> <ClCompile Include="DllMain.cpp" />

View File

@ -75,6 +75,12 @@
<ClInclude Include="CompatGdi.h"> <ClInclude Include="CompatGdi.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="CompatGdiWinProc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CompatGdiCaret.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="DllMain.cpp"> <ClCompile Include="DllMain.cpp">
@ -122,6 +128,12 @@
<ClCompile Include="CompatGdi.cpp"> <ClCompile Include="CompatGdi.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="CompatGdiWinProc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CompatGdiCaret.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="DDrawCompat.def"> <None Include="DDrawCompat.def">

View File

@ -302,13 +302,8 @@ bool RealPrimarySurface::isFullScreen()
bool RealPrimarySurface::isLost() bool RealPrimarySurface::isLost()
{ {
const bool isLost = g_frontBuffer && return g_frontBuffer &&
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer); DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
if (isLost)
{
CompatGdi::releaseSurfaceMemory();
}
return isLost;
} }
void RealPrimarySurface::release() void RealPrimarySurface::release()
@ -380,6 +375,8 @@ void RealPrimarySurface::update()
void RealPrimarySurface::updatePalette() void RealPrimarySurface::updatePalette()
{ {
CompatGdi::updatePalette();
if (isFullScreen()) if (isFullScreen())
{ {
flip(DDFLIP_WAIT); flip(DDFLIP_WAIT);