mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Separate GDI and DirectDraw surfaces
This commit is contained in:
parent
6183aed7da
commit
785663700d
@ -1,11 +1,12 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <detours.h>
|
||||
@ -19,7 +20,7 @@ namespace
|
||||
struct HookedFunctionInfo
|
||||
{
|
||||
HMODULE module;
|
||||
void* trampoline;
|
||||
void*& origFunction;
|
||||
void* newFunction;
|
||||
};
|
||||
|
||||
@ -28,7 +29,7 @@ namespace
|
||||
std::map<void*, HookedFunctionInfo>::iterator findOrigFunc(void* origFunc)
|
||||
{
|
||||
return std::find_if(g_hookedFunctions.begin(), g_hookedFunctions.end(),
|
||||
[=](const auto& i) { return origFunc == i.first || origFunc == i.second.trampoline; });
|
||||
[=](const auto& i) { return origFunc == i.first || origFunc == i.second.origFunction; });
|
||||
}
|
||||
|
||||
std::vector<HMODULE> getProcessModules(HANDLE process)
|
||||
@ -111,7 +112,7 @@ namespace
|
||||
const auto it = findOrigFunc(origFuncPtr);
|
||||
if (it != g_hookedFunctions.end())
|
||||
{
|
||||
origFuncPtr = it->second.trampoline;
|
||||
origFuncPtr = it->second.origFunction;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -136,13 +137,14 @@ namespace
|
||||
HMODULE module = nullptr;
|
||||
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
reinterpret_cast<char*>(hookedFuncPtr), &module);
|
||||
g_hookedFunctions[hookedFuncPtr] = { module, origFuncPtr, newFuncPtr };
|
||||
g_hookedFunctions.emplace(
|
||||
std::make_pair(hookedFuncPtr, HookedFunctionInfo{ module, origFuncPtr, newFuncPtr }));
|
||||
}
|
||||
|
||||
void unhookFunction(const std::map<void*, HookedFunctionInfo>::iterator& hookedFunc)
|
||||
{
|
||||
DetourTransactionBegin();
|
||||
DetourDetach(&hookedFunc->second.trampoline, hookedFunc->second.newFunction);
|
||||
DetourDetach(&hookedFunc->second.origFunction, hookedFunc->second.newFunction);
|
||||
DetourTransactionCommit();
|
||||
|
||||
if (hookedFunc->second.module)
|
||||
@ -173,7 +175,9 @@ namespace Compat
|
||||
if (0 != _stricmp(moduleBaseName.c_str(), moduleName))
|
||||
{
|
||||
Compat::Log() << "Disabling external hook to " << funcName << " in " << moduleBaseName;
|
||||
hookFunction(hookFunc, newFunc);
|
||||
static std::list<void*> origFuncs;
|
||||
origFuncs.push_back(hookFunc);
|
||||
hookFunction(origFuncs.back(), newFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,5 @@ namespace Config
|
||||
{
|
||||
const int maxPaletteUpdatesPerMs = 5;
|
||||
const int minExpectedFlipsPerSec = 5;
|
||||
const DWORD preallocatedGdiDcCount = 4;
|
||||
const DWORD primarySurfaceExtraRows = 2;
|
||||
}
|
||||
|
@ -2,12 +2,36 @@
|
||||
#include "D3dDdi/Device.h"
|
||||
#include "D3dDdi/DeviceFuncs.h"
|
||||
#include "D3dDdi/KernelModeThunks.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
|
||||
|
||||
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
|
||||
HANDLE g_gdiResourceHandle = nullptr;
|
||||
bool g_isReadOnlyGdiLockEnabled = false;
|
||||
|
||||
class RenderGuard : public Gdi::DDrawAccessGuard
|
||||
{
|
||||
public:
|
||||
RenderGuard(D3dDdi::Device& device, Gdi::Access access)
|
||||
: Gdi::DDrawAccessGuard(access)
|
||||
, m_device(device)
|
||||
{
|
||||
device.prepareForRendering();
|
||||
}
|
||||
|
||||
RenderGuard(D3dDdi::Device& device, Gdi::Access access, HANDLE resource, UINT subResourceIndex = UINT_MAX)
|
||||
: Gdi::DDrawAccessGuard(access, g_gdiResourceHandle == resource)
|
||||
, m_device(device)
|
||||
{
|
||||
device.prepareForRendering(resource, subResourceIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
D3dDdi::Device & m_device;
|
||||
};
|
||||
|
||||
D3DDDI_RESOURCEFLAGS getResourceTypeFlags()
|
||||
{
|
||||
@ -81,8 +105,8 @@ namespace D3dDdi
|
||||
|
||||
HRESULT Device::blt(const D3DDDIARG_BLT& data)
|
||||
{
|
||||
prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex);
|
||||
prepareForRendering(data.hDstResource, data.DstSubResourceIndex);
|
||||
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex);
|
||||
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource, data.DstSubResourceIndex);
|
||||
|
||||
auto it = m_oversizedResources.find(data.hSrcResource);
|
||||
if (it != m_oversizedResources.end())
|
||||
@ -101,13 +125,13 @@ namespace D3dDdi
|
||||
|
||||
HRESULT Device::clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect)
|
||||
{
|
||||
prepareForRendering();
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||
return m_origVtable->pfnClear(m_device, &data, numRect, rect);
|
||||
}
|
||||
|
||||
HRESULT Device::colorFill(const D3DDDIARG_COLORFILL& data)
|
||||
{
|
||||
prepareForRendering(data.hResource, data.SubResourceIndex);
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE, data.hResource, data.SubResourceIndex);
|
||||
return m_origVtable->pfnColorFill(m_device, &data);
|
||||
}
|
||||
|
||||
@ -198,6 +222,10 @@ namespace D3dDdi
|
||||
{
|
||||
m_sharedPrimary = nullptr;
|
||||
}
|
||||
if (resource == g_gdiResourceHandle)
|
||||
{
|
||||
g_gdiResourceHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -205,45 +233,49 @@ namespace D3dDdi
|
||||
|
||||
HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data)
|
||||
{
|
||||
prepareForRendering();
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||
return m_origVtable->pfnDrawIndexedPrimitive(m_device, &data);
|
||||
}
|
||||
|
||||
HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data,
|
||||
UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer)
|
||||
{
|
||||
prepareForRendering();
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||
return m_origVtable->pfnDrawIndexedPrimitive2(m_device, &data, indicesSize, indexBuffer, flagBuffer);
|
||||
}
|
||||
|
||||
HRESULT Device::drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer)
|
||||
{
|
||||
prepareForRendering();
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||
return m_origVtable->pfnDrawPrimitive(m_device, &data, flagBuffer);
|
||||
}
|
||||
|
||||
HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data)
|
||||
{
|
||||
prepareForRendering();
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||
return m_origVtable->pfnDrawPrimitive2(m_device, &data);
|
||||
}
|
||||
|
||||
HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info,
|
||||
const FLOAT* patch)
|
||||
{
|
||||
prepareForRendering();
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||
return m_origVtable->pfnDrawRectPatch(m_device, &data, info, patch);
|
||||
}
|
||||
|
||||
HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info,
|
||||
const FLOAT* patch)
|
||||
{
|
||||
prepareForRendering();
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||
return m_origVtable->pfnDrawTriPatch(m_device, &data, info, patch);
|
||||
}
|
||||
|
||||
HRESULT Device::lock(D3DDDIARG_LOCK& data)
|
||||
{
|
||||
Gdi::DDrawAccessGuard accessGuard(
|
||||
(data.Flags.ReadOnly || g_isReadOnlyGdiLockEnabled) ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE,
|
||||
data.hResource == g_gdiResourceHandle);
|
||||
|
||||
auto it = m_renderTargetResources.find(data.hResource);
|
||||
if (it != m_renderTargetResources.end())
|
||||
{
|
||||
@ -269,35 +301,45 @@ namespace D3dDdi
|
||||
|
||||
HRESULT Device::present(const D3DDDIARG_PRESENT& data)
|
||||
{
|
||||
prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex);
|
||||
RenderGuard renderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex);
|
||||
return m_origVtable->pfnPresent(m_device, &data);
|
||||
}
|
||||
|
||||
HRESULT Device::present1(D3DDDIARG_PRESENT1& data)
|
||||
{
|
||||
bool isGdiResourceInvolved = false;
|
||||
for (UINT i = 0; i < data.SrcResources && !isGdiResourceInvolved; ++i)
|
||||
{
|
||||
isGdiResourceInvolved = data.phSrcResources[i].hResource == g_gdiResourceHandle;
|
||||
}
|
||||
|
||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, isGdiResourceInvolved);
|
||||
|
||||
for (UINT i = 0; i < data.SrcResources; ++i)
|
||||
{
|
||||
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex);
|
||||
}
|
||||
|
||||
return m_origVtable->pfnPresent1(m_device, &data);
|
||||
}
|
||||
|
||||
HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data)
|
||||
{
|
||||
prepareForRendering(data.hDstResource);
|
||||
prepareForRendering(data.hSrcResource);
|
||||
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource);
|
||||
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource);
|
||||
return m_origVtable->pfnTexBlt(m_device, &data);
|
||||
}
|
||||
|
||||
HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data)
|
||||
{
|
||||
prepareForRendering(data.hDstResource);
|
||||
prepareForRendering(data.hSrcResource);
|
||||
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource);
|
||||
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource);
|
||||
return m_origVtable->pfnTexBlt1(m_device, &data);
|
||||
}
|
||||
|
||||
HRESULT Device::unlock(const D3DDDIARG_UNLOCK& data)
|
||||
{
|
||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, data.hResource == g_gdiResourceHandle);
|
||||
auto it = m_renderTargetResources.find(data.hResource);
|
||||
if (it != m_renderTargetResources.end())
|
||||
{
|
||||
@ -344,4 +386,14 @@ namespace D3dDdi
|
||||
prepareForRendering((it++)->second);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::setGdiResourceHandle(HANDLE resource)
|
||||
{
|
||||
g_gdiResourceHandle = resource;
|
||||
}
|
||||
|
||||
void Device::setReadOnlyGdiLock(bool enable)
|
||||
{
|
||||
g_isReadOnlyGdiLockEnabled = enable;
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,9 @@ namespace D3dDdi
|
||||
void prepareForRendering(HANDLE resource, UINT subResourceIndex = UINT_MAX);
|
||||
void prepareForRendering();
|
||||
|
||||
static void setGdiResourceHandle(HANDLE resource);
|
||||
static void setReadOnlyGdiLock(bool enable);
|
||||
|
||||
private:
|
||||
template <typename CreateResourceArg, typename CreateResourceFunc>
|
||||
HRESULT createOversizedResource(
|
||||
|
@ -31,6 +31,7 @@ namespace
|
||||
|
||||
std::map<D3DKMT_HANDLE, ContextInfo> g_contexts;
|
||||
std::map<D3DKMT_HANDLE, DeviceInfo> g_devices;
|
||||
HMONITOR g_lastOpenAdapterMonitor = nullptr;
|
||||
|
||||
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
||||
decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr;
|
||||
@ -123,6 +124,20 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS APIENTRY openAdapterFromHdc(D3DKMT_OPENADAPTERFROMHDC* pData)
|
||||
{
|
||||
Compat::LogEnter("D3DKMTOpenAdapterFromHdc", pData);
|
||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTOpenAdapterFromHdc)(pData);
|
||||
if (pData)
|
||||
{
|
||||
POINT p = {};
|
||||
GetDCOrgEx(pData->hDc, &p);
|
||||
g_lastOpenAdapterMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
Compat::LogLeave("D3DKMTOpenAdapterFromHdc", pData) << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool isPresentReady(D3DKMT_HANDLE device, D3DDDI_VIDEO_PRESENT_SOURCE_ID vidPnSourceId)
|
||||
{
|
||||
D3DKMT_GETDEVICESTATE deviceState = {};
|
||||
@ -253,6 +268,11 @@ namespace D3dDdi
|
||||
{
|
||||
namespace KernelModeThunks
|
||||
{
|
||||
HMONITOR getLastOpenAdapterMonitor()
|
||||
{
|
||||
return g_lastOpenAdapterMonitor;
|
||||
}
|
||||
|
||||
bool isPresentReady()
|
||||
{
|
||||
for (auto it : g_devices)
|
||||
@ -272,6 +292,7 @@ namespace D3dDdi
|
||||
HOOK_FUNCTION(gdi32, D3DKMTCreateDCFromMemory, createDcFromMemory);
|
||||
HOOK_FUNCTION(gdi32, D3DKMTDestroyContext, destroyContext);
|
||||
HOOK_FUNCTION(gdi32, D3DKMTDestroyDevice, destroyDevice);
|
||||
HOOK_FUNCTION(gdi32, D3DKMTOpenAdapterFromHdc, openAdapterFromHdc);
|
||||
HOOK_FUNCTION(gdi32, D3DKMTQueryAdapterInfo, queryAdapterInfo);
|
||||
HOOK_FUNCTION(gdi32, D3DKMTPresent, present);
|
||||
HOOK_FUNCTION(gdi32, D3DKMTSetQueuedLimit, setQueuedLimit);
|
||||
|
@ -1,5 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <d3d.h>
|
||||
#include <d3dumddi.h>
|
||||
#include <../km/d3dkmthk.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include "D3dDdi/Log/KernelModeThunksLog.h"
|
||||
|
||||
static const auto D3DDDI_FLIPINTERVAL_NOOVERRIDE = static_cast<D3DDDI_FLIPINTERVAL_TYPE>(5);
|
||||
@ -8,6 +16,7 @@ namespace D3dDdi
|
||||
{
|
||||
namespace KernelModeThunks
|
||||
{
|
||||
HMONITOR getLastOpenAdapterMonitor();
|
||||
void installHooks();
|
||||
bool isPresentReady();
|
||||
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval);
|
||||
|
@ -1,6 +1,13 @@
|
||||
#include "Common/Log.h"
|
||||
#include "D3dDdi/Log/KernelModeThunksLog.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const LUID& luid)
|
||||
{
|
||||
return Compat::LogStruct(os)
|
||||
<< Compat::hex(luid.LowPart)
|
||||
<< Compat::hex(luid.HighPart);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATECONTEXT& data)
|
||||
{
|
||||
return Compat::LogStruct(os)
|
||||
@ -73,6 +80,15 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_DESTROYDEVICE& data)
|
||||
<< Compat::hex(data.hDevice);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_OPENADAPTERFROMHDC& data)
|
||||
{
|
||||
return Compat::LogStruct(os)
|
||||
<< data.hDc
|
||||
<< Compat::hex(data.hAdapter)
|
||||
<< data.AdapterLuid
|
||||
<< data.VidPnSourceId;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_PRESENT& data)
|
||||
{
|
||||
return Compat::LogStruct(os)
|
||||
|
@ -8,12 +8,14 @@
|
||||
#include <d3dumddi.h>
|
||||
#include <../km/d3dkmthk.h>
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const LUID& luid);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATECONTEXT& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATECONTEXTVIRTUAL& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATEDCFROMMEMORY& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATEDEVICE& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_DESTROYCONTEXT& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_DESTROYDEVICE& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_OPENADAPTERFROMHDC& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_PRESENT& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETQUEUEDLIMIT& data);
|
||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER& data);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "Common/Hook.h"
|
||||
#include "DDraw/ActivateAppHandler.h"
|
||||
#include "DDraw/RealPrimarySurface.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Win32/DisplayMode.h"
|
||||
#include "Win32/FontSmoothing.h"
|
||||
@ -32,6 +33,7 @@ namespace
|
||||
{
|
||||
case WM_ACTIVATEAPP:
|
||||
{
|
||||
DDraw::RealPrimarySurface::disableUpdates();
|
||||
isDisplayChangeNotificationEnabled = false;
|
||||
if (TRUE == wParam)
|
||||
{
|
||||
@ -43,6 +45,7 @@ namespace
|
||||
}
|
||||
LRESULT result = g_origDdWndProc(hwnd, uMsg, wParam, lParam);
|
||||
isDisplayChangeNotificationEnabled = true;
|
||||
DDraw::RealPrimarySurface::enableUpdates();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -8,43 +8,6 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp)
|
||||
{
|
||||
DDPIXELFORMAT pf = {};
|
||||
pf.dwSize = sizeof(pf);
|
||||
pf.dwFlags = DDPF_RGB;
|
||||
pf.dwRGBBitCount = bpp;
|
||||
|
||||
switch (bpp)
|
||||
{
|
||||
case 1:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED1;
|
||||
break;
|
||||
case 2:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED2;
|
||||
break;
|
||||
case 4:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED4;
|
||||
break;
|
||||
case 8:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED8;
|
||||
break;
|
||||
case 16:
|
||||
pf.dwRBitMask = 0xF800;
|
||||
pf.dwGBitMask = 0x07E0;
|
||||
pf.dwBBitMask = 0x001F;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
pf.dwRBitMask = 0xFF0000;
|
||||
pf.dwGBitMask = 0x00FF00;
|
||||
pf.dwBBitMask = 0x0000FF;
|
||||
break;
|
||||
}
|
||||
|
||||
return pf;
|
||||
}
|
||||
|
||||
template <typename TDirectDraw>
|
||||
HRESULT setDisplayMode(TDirectDraw* This, DWORD width, DWORD height, DWORD bpp)
|
||||
{
|
||||
@ -100,6 +63,43 @@ namespace DDraw
|
||||
return dm;
|
||||
}
|
||||
|
||||
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp)
|
||||
{
|
||||
DDPIXELFORMAT pf = {};
|
||||
pf.dwSize = sizeof(pf);
|
||||
pf.dwFlags = DDPF_RGB;
|
||||
pf.dwRGBBitCount = bpp;
|
||||
|
||||
switch (bpp)
|
||||
{
|
||||
case 1:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED1;
|
||||
break;
|
||||
case 2:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED2;
|
||||
break;
|
||||
case 4:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED4;
|
||||
break;
|
||||
case 8:
|
||||
pf.dwFlags |= DDPF_PALETTEINDEXED8;
|
||||
break;
|
||||
case 16:
|
||||
pf.dwRBitMask = 0xF800;
|
||||
pf.dwGBitMask = 0x07E0;
|
||||
pf.dwBBitMask = 0x001F;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
pf.dwRBitMask = 0xFF0000;
|
||||
pf.dwGBitMask = 0x00FF00;
|
||||
pf.dwBBitMask = 0x0000FF;
|
||||
break;
|
||||
}
|
||||
|
||||
return pf;
|
||||
}
|
||||
|
||||
void suppressEmulatedDirectDraw(GUID*& guid)
|
||||
{
|
||||
if (reinterpret_cast<GUID*>(DDCREATE_EMULATIONONLY) == guid)
|
||||
|
@ -18,6 +18,7 @@ namespace DDraw
|
||||
void* getDdObject(TDirectDraw& dd);
|
||||
|
||||
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd);
|
||||
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
|
||||
void suppressEmulatedDirectDraw(GUID*& guid);
|
||||
|
||||
template <typename TDirectDraw>
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "DDraw/DirectDrawPalette.h"
|
||||
#include "DDraw/RealPrimarySurface.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
|
||||
namespace DDraw
|
||||
{
|
||||
@ -37,7 +38,7 @@ namespace DDraw
|
||||
{
|
||||
std::memcpy(&PrimarySurface::s_paletteEntries[dwStartingEntry], lpEntries,
|
||||
dwCount * sizeof(PALETTEENTRY));
|
||||
RealPrimarySurface::updatePalette(dwStartingEntry, dwCount);
|
||||
RealPrimarySurface::updatePalette();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ namespace DDraw
|
||||
SET_COMPAT_METHOD(BltFast);
|
||||
SET_COMPAT_METHOD(Flip);
|
||||
SET_COMPAT_METHOD(GetCaps);
|
||||
SET_COMPAT_METHOD(GetDC);
|
||||
SET_COMPAT_METHOD(GetSurfaceDesc);
|
||||
SET_COMPAT_METHOD(IsLost);
|
||||
SET_COMPAT_METHOD(Lock);
|
||||
|
@ -104,6 +104,8 @@ namespace DDraw
|
||||
{
|
||||
void installHooks()
|
||||
{
|
||||
RealPrimarySurface::init();
|
||||
|
||||
Win32::Registry::unsetValue(
|
||||
HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\DirectDraw", "EmulationOnly");
|
||||
Win32::Registry::unsetValue(
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CompatPtr.h"
|
||||
#include "Common/Hook.h"
|
||||
#include "Common/Time.h"
|
||||
#include "Config/Config.h"
|
||||
#include "D3dDdi/Device.h"
|
||||
#include "D3dDdi/KernelModeThunks.h"
|
||||
#include "DDraw/DirectDraw.h"
|
||||
#include "DDraw/DirectDrawSurface.h"
|
||||
@ -13,11 +15,26 @@
|
||||
#include "DDraw/ScopedThreadLock.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
#include "DDraw/Types.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
#include "Gdi/Window.h"
|
||||
#include "Win32/DisplayMode.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct BltToWindowViaGdiArgs
|
||||
{
|
||||
std::unique_ptr<HDC__, void(*)(HDC)> virtualScreenDc;
|
||||
Gdi::Region* primaryRegion;
|
||||
|
||||
BltToWindowViaGdiArgs()
|
||||
: virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc)
|
||||
, primaryRegion(nullptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void onRelease();
|
||||
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
||||
|
||||
@ -42,7 +59,8 @@ namespace
|
||||
|
||||
BOOL CALLBACK addVisibleLayeredWindowToVector(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
if (IsWindowVisible(hwnd) && (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
||||
if (IsWindowVisible(hwnd) && (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
|
||||
!Gdi::Window::isPresentationWindow(hwnd))
|
||||
{
|
||||
auto& visibleLayeredWindows = *reinterpret_cast<std::vector<HWND>*>(lParam);
|
||||
visibleLayeredWindows.push_back(hwnd);
|
||||
@ -52,7 +70,7 @@ namespace
|
||||
|
||||
BOOL CALLBACK bltToWindow(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
if (!IsWindowVisible(hwnd) || (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
||||
if (!IsWindowVisible(hwnd) || !Gdi::Window::isPresentationWindow(hwnd))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@ -63,6 +81,54 @@ namespace
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK bltToWindowViaGdi(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
if (!IsWindowVisible(hwnd) || !Gdi::Window::isPresentationWindow(hwnd))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
auto window = Gdi::Window::get(GetParent(hwnd));
|
||||
if (!window)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Gdi::Region visibleRegion = window->getVisibleRegion();
|
||||
if (visibleRegion.isEmpty())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
auto& args = *reinterpret_cast<BltToWindowViaGdiArgs*>(lParam);
|
||||
if (args.primaryRegion)
|
||||
{
|
||||
visibleRegion -= *args.primaryRegion;
|
||||
if (visibleRegion.isEmpty())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.virtualScreenDc)
|
||||
{
|
||||
args.virtualScreenDc.reset(Gdi::VirtualScreen::createDc());
|
||||
if (!args.virtualScreenDc)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_READ);
|
||||
HDC presentationWindowDc = GetWindowDC(hwnd);
|
||||
RECT rect = window->getWindowRect();
|
||||
CALL_ORIG_FUNC(BitBlt)(presentationWindowDc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
|
||||
args.virtualScreenDc.get(), rect.left, rect.top, SRCCOPY);
|
||||
ReleaseDC(hwnd, presentationWindowDc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void bltVisibleLayeredWindowsToBackBuffer()
|
||||
{
|
||||
std::vector<HWND> visibleLayeredWindows;
|
||||
@ -94,7 +160,6 @@ namespace
|
||||
}
|
||||
|
||||
g_backBuffer->ReleaseDC(g_backBuffer, backBufferDc);
|
||||
DDraw::RealPrimarySurface::update();
|
||||
}
|
||||
|
||||
HRESULT bltToPrimaryChain(CompatRef<IDirectDrawSurface7> src)
|
||||
@ -112,15 +177,31 @@ namespace
|
||||
{
|
||||
Compat::LogEnter("RealPrimarySurface::compatBlt");
|
||||
|
||||
bool result = false;
|
||||
BltToWindowViaGdiArgs bltToWindowViaGdiArgs;
|
||||
if (!g_frontBuffer || (!g_isFullScreen && DDraw::RealPrimarySurface::isLost()))
|
||||
{
|
||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
||||
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
||||
Compat::LogLeave("RealPrimarySurface::compatBlt") << false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Gdi::Region primaryRegion(DDraw::PrimarySurface::getMonitorRect());
|
||||
bltToWindowViaGdiArgs.primaryRegion = &primaryRegion;
|
||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
||||
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
||||
|
||||
bool result = false;
|
||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(primary.get()));
|
||||
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
HDC paletteConverterDc = nullptr;
|
||||
g_paletteConverter->GetDC(g_paletteConverter, &paletteConverterDc);
|
||||
HDC primaryDc = nullptr;
|
||||
D3dDdi::Device::setReadOnlyGdiLock(true);
|
||||
primary->GetDC(primary, &primaryDc);
|
||||
D3dDdi::Device::setReadOnlyGdiLock(false);
|
||||
|
||||
if (paletteConverterDc && primaryDc)
|
||||
{
|
||||
@ -203,7 +284,6 @@ namespace
|
||||
surface->SetClipper(surface, g_clipper);
|
||||
}
|
||||
|
||||
g_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec;
|
||||
g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout;
|
||||
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
||||
|
||||
@ -216,17 +296,6 @@ namespace
|
||||
}
|
||||
g_qpcUpdateInterval = Time::g_qpcFrequency / dm.dwRefreshRate;
|
||||
|
||||
if (!g_updateEvent)
|
||||
{
|
||||
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
}
|
||||
|
||||
if (!g_updateThread)
|
||||
{
|
||||
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
|
||||
SetThreadPriority(g_updateThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
|
||||
surface->SetPrivateData(surface, IID_IReleaseNotifier,
|
||||
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||
|
||||
@ -265,6 +334,7 @@ namespace
|
||||
g_clipper.release();
|
||||
g_isFullScreen = false;
|
||||
g_paletteConverter.release();
|
||||
g_qpcUpdateInterval = Time::g_qpcFrequency / 60;
|
||||
|
||||
ZeroMemory(&g_surfaceDesc, sizeof(g_surfaceDesc));
|
||||
|
||||
@ -275,6 +345,7 @@ namespace
|
||||
{
|
||||
ResetEvent(g_updateEvent);
|
||||
|
||||
Gdi::VirtualScreen::update();
|
||||
if (compatBlt() && g_isFullScreen)
|
||||
{
|
||||
D3dDdi::KernelModeThunks::overrideFlipInterval(
|
||||
@ -349,7 +420,7 @@ namespace DDraw
|
||||
return result;
|
||||
}
|
||||
|
||||
return init(dd, surface);
|
||||
return ::init(dd, surface);
|
||||
}
|
||||
|
||||
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
|
||||
@ -408,6 +479,17 @@ namespace DDraw
|
||||
return g_frontBuffer;
|
||||
}
|
||||
|
||||
void RealPrimarySurface::init()
|
||||
{
|
||||
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
||||
g_qpcUpdateInterval = Time::g_qpcFrequency / 60;
|
||||
g_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec;
|
||||
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
|
||||
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
|
||||
SetThreadPriority(g_updateThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
|
||||
bool RealPrimarySurface::isFullScreen()
|
||||
{
|
||||
return g_isFullScreen;
|
||||
@ -465,7 +547,7 @@ namespace DDraw
|
||||
g_frontBuffer->SetPalette(g_frontBuffer, PrimarySurface::s_palette);
|
||||
}
|
||||
|
||||
updatePalette(0, 256);
|
||||
updatePalette();
|
||||
}
|
||||
|
||||
void RealPrimarySurface::update()
|
||||
@ -500,9 +582,8 @@ namespace DDraw
|
||||
}
|
||||
}
|
||||
|
||||
void RealPrimarySurface::updatePalette(DWORD startingEntry, DWORD count)
|
||||
void RealPrimarySurface::updatePalette()
|
||||
{
|
||||
Gdi::updatePalette(startingEntry, count);
|
||||
if (PrimarySurface::s_palette)
|
||||
{
|
||||
update();
|
||||
|
@ -20,6 +20,7 @@ namespace DDraw
|
||||
static HRESULT flip(DWORD flags);
|
||||
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
||||
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
||||
static void init();
|
||||
static bool isFullScreen();
|
||||
static bool isLost();
|
||||
static void release();
|
||||
@ -28,6 +29,6 @@ namespace DDraw
|
||||
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
|
||||
static void setPalette();
|
||||
static void update();
|
||||
static void updatePalette(DWORD startingEntry, DWORD count);
|
||||
static void updatePalette();
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,13 @@
|
||||
#define CINTERFACE
|
||||
#define _NO_DDRAWINT_NO_COM
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
#include "Common/CompatPtr.h"
|
||||
#include "Common/CompatRef.h"
|
||||
#include "Config/Config.h"
|
||||
#include "D3dDdi/Device.h"
|
||||
#include "D3dDdi/KernelModeThunks.h"
|
||||
#include "DDraw/DirectDraw.h"
|
||||
#include "DDraw/RealPrimarySurface.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
@ -8,11 +16,30 @@
|
||||
namespace
|
||||
{
|
||||
DDSURFACEDESC2 g_primarySurfaceDesc = {};
|
||||
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface = nullptr;
|
||||
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
|
||||
HANDLE g_gdiResourceHandle = nullptr;
|
||||
DWORD g_origCaps = 0;
|
||||
RECT g_monitorRect = {};
|
||||
|
||||
HANDLE getResourceHandle(IDirectDrawSurface7& surface)
|
||||
RECT getDdMonitorRect(CompatRef<IDirectDraw7> dd)
|
||||
{
|
||||
DDDEVICEIDENTIFIER2 di = {};
|
||||
dd->GetDeviceIdentifier(&dd, &di, 0); // Calls D3DKMTOpenAdapterFromHdc, which updates last monitor below
|
||||
|
||||
HMONITOR monitor = D3dDdi::KernelModeThunks::getLastOpenAdapterMonitor();
|
||||
if (!monitor)
|
||||
{
|
||||
monitor = MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(monitor, &mi);
|
||||
return mi.rcMonitor;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HANDLE getResourceHandle(TSurface& surface)
|
||||
{
|
||||
return reinterpret_cast<HANDLE**>(&surface)[1][2];
|
||||
}
|
||||
@ -32,6 +59,7 @@ namespace DDraw
|
||||
g_gdiResourceHandle = nullptr;
|
||||
g_primarySurface = nullptr;
|
||||
g_origCaps = 0;
|
||||
g_monitorRect = {};
|
||||
s_palette = nullptr;
|
||||
s_surfaceBuffers.clear();
|
||||
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
|
||||
@ -75,6 +103,7 @@ namespace DDraw
|
||||
|
||||
g_primarySurface = surface7;
|
||||
g_origCaps = origCaps;
|
||||
g_monitorRect = getDdMonitorRect(*CompatPtr<IDirectDraw7>::from(&dd));
|
||||
|
||||
ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc));
|
||||
g_primarySurfaceDesc.dwSize = sizeof(g_primarySurfaceDesc);
|
||||
@ -86,6 +115,8 @@ namespace DDraw
|
||||
}
|
||||
|
||||
g_gdiResourceHandle = getResourceHandle(*surface7);
|
||||
D3dDdi::Device::setGdiResourceHandle(*reinterpret_cast<HANDLE*>(g_gdiResourceHandle));
|
||||
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
@ -135,7 +166,7 @@ namespace DDraw
|
||||
|
||||
do
|
||||
{
|
||||
if (getResourceHandle(*surface) == g_gdiResourceHandle)
|
||||
if (isGdiSurface(surface.get()))
|
||||
{
|
||||
return CompatPtr<IDirectDrawSurface7>::from(surface.get());
|
||||
}
|
||||
@ -150,6 +181,11 @@ namespace DDraw
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RECT PrimarySurface::getMonitorRect()
|
||||
{
|
||||
return g_monitorRect;
|
||||
}
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
|
||||
{
|
||||
return g_primarySurface;
|
||||
@ -160,6 +196,27 @@ namespace DDraw
|
||||
return g_origCaps;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
static bool PrimarySurface::isGdiSurface(TSurface* surface)
|
||||
{
|
||||
return surface && getResourceHandle(*surface) == g_gdiResourceHandle;
|
||||
}
|
||||
|
||||
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface*);
|
||||
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface2*);
|
||||
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface3*);
|
||||
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*);
|
||||
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface7*);
|
||||
|
||||
void PrimarySurface::onRestore()
|
||||
{
|
||||
CompatPtr<IUnknown> ddUnk;
|
||||
g_primarySurface.get()->lpVtbl->GetDDInterface(
|
||||
g_primarySurface, reinterpret_cast<void**>(&ddUnk.getRef()));
|
||||
CompatPtr<IDirectDraw7> dd7(ddUnk);
|
||||
g_monitorRect = getDdMonitorRect(*dd7);
|
||||
}
|
||||
|
||||
void PrimarySurface::resizeBuffers(CompatRef<IDirectDrawSurface7> surface)
|
||||
{
|
||||
DDSCAPS2 flipCaps = {};
|
||||
|
@ -19,10 +19,13 @@ namespace DDraw
|
||||
static HRESULT flipToGdiSurface();
|
||||
static const DDSURFACEDESC2& getDesc();
|
||||
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
|
||||
static RECT getMonitorRect();
|
||||
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
|
||||
static DWORD getOrigCaps();
|
||||
static void onRestore();
|
||||
|
||||
void updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride);
|
||||
template <typename TSurface>
|
||||
static bool isGdiSurface(TSurface* surface);
|
||||
|
||||
static CompatWeakPtr<IDirectDrawPalette> s_palette;
|
||||
static PALETTEENTRY s_paletteEntries[256];
|
||||
|
@ -57,22 +57,6 @@ namespace DDraw
|
||||
HRESULT result = m_impl.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
const LONG x = dwX;
|
||||
const LONG y = dwY;
|
||||
RECT destRect = { x, y, x, y };
|
||||
if (lpSrcRect)
|
||||
{
|
||||
destRect.right += lpSrcRect->right - lpSrcRect->left;
|
||||
destRect.bottom += lpSrcRect->bottom - lpSrcRect->top;
|
||||
}
|
||||
else
|
||||
{
|
||||
TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
CompatVtable<Vtable<TSurface>>::s_origVtable.GetSurfaceDesc(lpDDSrcSurface, &desc);
|
||||
destRect.right += desc.dwWidth;
|
||||
destRect.bottom += desc.dwHeight;
|
||||
}
|
||||
RealPrimarySurface::update();
|
||||
}
|
||||
return result;
|
||||
@ -195,6 +179,7 @@ namespace DDraw
|
||||
result = m_impl.Restore(This);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
PrimarySurface::onRestore();
|
||||
Gdi::redraw(nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
#include "Common/CompatRef.h"
|
||||
#include "DDraw/Repository.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
#include "DDraw/Surfaces/Surface.h"
|
||||
#include "DDraw/Surfaces/SurfaceImpl.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -159,6 +161,8 @@ namespace DDraw
|
||||
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
|
||||
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
|
||||
{
|
||||
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
|
||||
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
|
||||
HRESULT result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||
if (DDERR_UNSUPPORTED == result || DDERR_GENERIC == result)
|
||||
{
|
||||
@ -178,6 +182,8 @@ namespace DDraw
|
||||
HRESULT SurfaceImpl<TSurface>::BltFast(
|
||||
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
|
||||
{
|
||||
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
|
||||
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
|
||||
HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||
if (DDERR_UNSUPPORTED == result || DDERR_GENERIC == result)
|
||||
{
|
||||
@ -221,6 +227,13 @@ namespace DDraw
|
||||
return s_origVtable.GetCaps(This, lpDDSCaps);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
|
||||
{
|
||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
return s_origVtable.GetDC(This, lphDC);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT SurfaceImpl2<TSurface>::GetDDInterface(TSurface* /*This*/, LPVOID* lplpDD)
|
||||
{
|
||||
@ -250,6 +263,8 @@ namespace DDraw
|
||||
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||
DWORD dwFlags, HANDLE hEvent)
|
||||
{
|
||||
Gdi::DDrawAccessGuard accessGuard((dwFlags & DDLOCK_READONLY) ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE,
|
||||
PrimarySurface::isGdiSurface(This));
|
||||
HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||
if (DDERR_SURFACELOST == result)
|
||||
{
|
||||
@ -269,6 +284,7 @@ namespace DDraw
|
||||
template <typename TSurface>
|
||||
HRESULT SurfaceImpl<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
|
||||
{
|
||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
|
||||
return s_origVtable.ReleaseDC(This, hDC);
|
||||
}
|
||||
|
||||
@ -287,6 +303,7 @@ namespace DDraw
|
||||
template <typename TSurface>
|
||||
HRESULT SurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
|
||||
{
|
||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
|
||||
return s_origVtable.Unlock(This, lpRect);
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ namespace DDraw
|
||||
TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans);
|
||||
virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags);
|
||||
virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps);
|
||||
virtual HRESULT GetDC(TSurface* This, HDC* lphDC);
|
||||
virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc);
|
||||
virtual HRESULT IsLost(TSurface* This);
|
||||
virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||
|
@ -215,6 +215,7 @@
|
||||
<ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h" />
|
||||
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" />
|
||||
<ClInclude Include="Dll\Procs.h" />
|
||||
<ClInclude Include="Gdi\AccessGuard.h" />
|
||||
<ClInclude Include="Gdi\Gdi.h" />
|
||||
<ClInclude Include="Gdi\Caret.h" />
|
||||
<ClInclude Include="Gdi\Dc.h" />
|
||||
@ -225,6 +226,7 @@
|
||||
<ClInclude Include="Gdi\ScrollBar.h" />
|
||||
<ClInclude Include="Gdi\ScrollFunctions.h" />
|
||||
<ClInclude Include="Gdi\TitleBar.h" />
|
||||
<ClInclude Include="Gdi\VirtualScreen.h" />
|
||||
<ClInclude Include="Gdi\Window.h" />
|
||||
<ClInclude Include="Gdi\WinProc.h" />
|
||||
<ClInclude Include="Win32\DisplayMode.h" />
|
||||
@ -274,6 +276,7 @@
|
||||
<ClCompile Include="Dll\Procs.cpp" />
|
||||
<ClCompile Include="Dll\DllMain.cpp" />
|
||||
<ClCompile Include="Dll\UnmodifiedProcs.cpp" />
|
||||
<ClCompile Include="Gdi\AccessGuard.cpp" />
|
||||
<ClCompile Include="Gdi\Gdi.cpp" />
|
||||
<ClCompile Include="Gdi\Caret.cpp" />
|
||||
<ClCompile Include="Gdi\Dc.cpp" />
|
||||
@ -284,6 +287,7 @@
|
||||
<ClCompile Include="Gdi\ScrollBar.cpp" />
|
||||
<ClCompile Include="Gdi\ScrollFunctions.cpp" />
|
||||
<ClCompile Include="Gdi\TitleBar.cpp" />
|
||||
<ClCompile Include="Gdi\VirtualScreen.cpp" />
|
||||
<ClCompile Include="Gdi\Window.cpp" />
|
||||
<ClCompile Include="Gdi\WinProc.cpp" />
|
||||
<ClCompile Include="Win32\DisplayMode.cpp" />
|
||||
|
@ -321,6 +321,12 @@
|
||||
<ClInclude Include="Gdi\Region.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gdi\VirtualScreen.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gdi\AccessGuard.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -494,6 +500,12 @@
|
||||
<ClCompile Include="Gdi\Region.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Gdi\VirtualScreen.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Gdi\AccessGuard.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Dll\DDrawCompat.def">
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "Direct3d/Hooks.h"
|
||||
#include "Dll/Procs.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
#include "Win32/DisplayMode.h"
|
||||
#include "Win32/FontSmoothing.h"
|
||||
#include "Win32/MsgHooks.h"
|
||||
@ -39,14 +40,15 @@ namespace
|
||||
Win32::Registry::installHooks();
|
||||
Compat::Log() << "Installing Direct3D driver hooks";
|
||||
D3dDdi::installHooks();
|
||||
Compat::Log() << "Installing display mode hooks";
|
||||
Win32::DisplayMode::installHooks(g_origDDrawModule);
|
||||
Gdi::VirtualScreen::init();
|
||||
Compat::Log() << "Installing DirectDraw hooks";
|
||||
DDraw::installHooks();
|
||||
Compat::Log() << "Installing Direct3D hooks";
|
||||
Direct3d::installHooks();
|
||||
Compat::Log() << "Installing GDI hooks";
|
||||
Gdi::installHooks();
|
||||
Compat::Log() << "Installing display mode hooks";
|
||||
Win32::DisplayMode::installHooks(g_origDDrawModule);
|
||||
Compat::Log() << "Finished installing hooks";
|
||||
isAlreadyInstalled = true;
|
||||
}
|
||||
|
152
DDrawCompat/Gdi/AccessGuard.cpp
Normal file
152
DDrawCompat/Gdi/AccessGuard.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "DDraw/RealPrimarySurface.h"
|
||||
#include "DDraw/ScopedThreadLock.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Accessor
|
||||
{
|
||||
DWORD readAccessDepth;
|
||||
DWORD writeAccessDepth;
|
||||
bool isSynced;
|
||||
|
||||
Accessor(bool isSynced) : readAccessDepth(0), writeAccessDepth(0), isSynced(isSynced) {}
|
||||
};
|
||||
|
||||
Accessor g_ddrawAccessor(false);
|
||||
Accessor g_gdiAccessor(true);
|
||||
bool g_isSyncing = false;
|
||||
|
||||
bool synchronize(Gdi::User user);
|
||||
|
||||
void beginAccess(Gdi::User user, Gdi::Access access)
|
||||
{
|
||||
Compat::LogEnter("beginAccess", user, access);
|
||||
|
||||
Accessor& accessor = Gdi::USER_DDRAW == user ? g_ddrawAccessor : g_gdiAccessor;
|
||||
DWORD& accessDepth = Gdi::ACCESS_READ == access ? accessor.readAccessDepth : accessor.writeAccessDepth;
|
||||
++accessDepth;
|
||||
|
||||
accessor.isSynced = accessor.isSynced || synchronize(user);
|
||||
if (accessor.isSynced && Gdi::ACCESS_WRITE == access)
|
||||
{
|
||||
Accessor& otherAccessor = Gdi::USER_DDRAW == user ? g_gdiAccessor : g_ddrawAccessor;
|
||||
otherAccessor.isSynced = false;
|
||||
}
|
||||
|
||||
Compat::LogLeave("beginAccess", user, access) << accessor.isSynced;
|
||||
}
|
||||
|
||||
void endAccess(Gdi::User user, Gdi::Access access)
|
||||
{
|
||||
Compat::LogEnter("endAccess", user, access);
|
||||
|
||||
Accessor& accessor = Gdi::USER_DDRAW == user ? g_ddrawAccessor : g_gdiAccessor;
|
||||
DWORD& accessDepth = Gdi::ACCESS_READ == access ? accessor.readAccessDepth : accessor.writeAccessDepth;
|
||||
--accessDepth;
|
||||
|
||||
if (Gdi::USER_DDRAW == user &&
|
||||
0 == g_ddrawAccessor.readAccessDepth && 0 == g_ddrawAccessor.writeAccessDepth &&
|
||||
(0 != g_gdiAccessor.readAccessDepth || 0 != g_gdiAccessor.writeAccessDepth))
|
||||
{
|
||||
g_gdiAccessor.isSynced = g_gdiAccessor.isSynced || synchronize(Gdi::USER_GDI);
|
||||
if (g_gdiAccessor.isSynced && 0 != g_gdiAccessor.writeAccessDepth)
|
||||
{
|
||||
g_ddrawAccessor.isSynced = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == accessDepth && Gdi::ACCESS_WRITE == access && Gdi::USER_GDI == user &&
|
||||
0 == g_ddrawAccessor.writeAccessDepth)
|
||||
{
|
||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||
if (!primary || DDraw::PrimarySurface::isGdiSurface(primary.get()))
|
||||
{
|
||||
DDraw::RealPrimarySurface::update();
|
||||
}
|
||||
}
|
||||
|
||||
Compat::LogLeave("endAccess", user, access);
|
||||
}
|
||||
|
||||
bool synchronize(Gdi::User user)
|
||||
{
|
||||
auto ddrawSurface(DDraw::PrimarySurface::getGdiSurface());
|
||||
if (!ddrawSurface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto gdiSurface(Gdi::VirtualScreen::createSurface(DDraw::PrimarySurface::getMonitorRect()));
|
||||
if (!gdiSurface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
g_isSyncing = true;
|
||||
if (Gdi::USER_DDRAW == user)
|
||||
{
|
||||
CompatPtr<IDirectDrawClipper> clipper;
|
||||
ddrawSurface->GetClipper(ddrawSurface, &clipper.getRef());
|
||||
ddrawSurface->SetClipper(ddrawSurface, nullptr);
|
||||
result = SUCCEEDED(ddrawSurface->BltFast(
|
||||
ddrawSurface, 0, 0, gdiSurface, nullptr, DDBLTFAST_WAIT));
|
||||
ddrawSurface->SetClipper(ddrawSurface, clipper);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SUCCEEDED(gdiSurface->BltFast(
|
||||
gdiSurface, 0, 0, ddrawSurface, nullptr, DDBLTFAST_WAIT));
|
||||
}
|
||||
g_isSyncing = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
AccessGuard::AccessGuard(User user, Access access, bool condition)
|
||||
: m_user(user)
|
||||
, m_access(access)
|
||||
, m_condition(condition)
|
||||
{
|
||||
if (m_condition)
|
||||
{
|
||||
DDraw::ScopedThreadLock lock;
|
||||
if (g_isSyncing)
|
||||
{
|
||||
m_condition = false;
|
||||
return;
|
||||
}
|
||||
|
||||
beginAccess(user, access);
|
||||
}
|
||||
}
|
||||
|
||||
AccessGuard::~AccessGuard()
|
||||
{
|
||||
if (m_condition)
|
||||
{
|
||||
DDraw::ScopedThreadLock lock;
|
||||
endAccess(m_user, m_access);
|
||||
}
|
||||
}
|
||||
|
||||
DDrawAccessGuard::DDrawAccessGuard(Access access, bool condition)
|
||||
: AccessGuard(USER_DDRAW, access, condition)
|
||||
{
|
||||
}
|
||||
|
||||
GdiAccessGuard::GdiAccessGuard(Access access, bool condition)
|
||||
: AccessGuard(USER_GDI, access, condition)
|
||||
{
|
||||
}
|
||||
}
|
40
DDrawCompat/Gdi/AccessGuard.h
Normal file
40
DDrawCompat/Gdi/AccessGuard.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
enum Access
|
||||
{
|
||||
ACCESS_READ,
|
||||
ACCESS_WRITE
|
||||
};
|
||||
|
||||
enum User
|
||||
{
|
||||
USER_DDRAW,
|
||||
USER_GDI
|
||||
};
|
||||
|
||||
class AccessGuard
|
||||
{
|
||||
protected:
|
||||
AccessGuard(User user, Access access, bool condition = true);
|
||||
~AccessGuard();
|
||||
|
||||
private:
|
||||
User m_user;
|
||||
Access m_access;
|
||||
bool m_condition;
|
||||
};
|
||||
|
||||
class DDrawAccessGuard : public AccessGuard
|
||||
{
|
||||
public:
|
||||
DDrawAccessGuard(Access access, bool condition = true);
|
||||
};
|
||||
|
||||
class GdiAccessGuard : public AccessGuard
|
||||
{
|
||||
public:
|
||||
GdiAccessGuard(Access access, bool condition = true);
|
||||
};
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "Common/Hook.h"
|
||||
#include "Common/ScopedCriticalSection.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
#include "Gdi/Caret.h"
|
||||
#include "Gdi/Dc.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
@ -103,11 +104,11 @@ namespace
|
||||
return;
|
||||
}
|
||||
|
||||
if ((g_caret.isVisible || newCaret.isVisible) && Gdi::beginGdiRendering())
|
||||
if ((g_caret.isVisible || newCaret.isVisible))
|
||||
{
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
drawCaret(g_caret);
|
||||
drawCaret(newCaret);
|
||||
Gdi::endGdiRendering();
|
||||
}
|
||||
|
||||
g_caret = newCaret;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Hook.h"
|
||||
#include "Common/Log.h"
|
||||
@ -7,24 +8,27 @@
|
||||
#include "Gdi/Dc.h"
|
||||
#include "Gdi/DcCache.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
#include "Gdi/Window.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using Gdi::DcCache::CachedDc;
|
||||
|
||||
struct CompatDc : CachedDc
|
||||
struct CompatDc
|
||||
{
|
||||
CompatDc(const CachedDc& cachedDc = {}) : CachedDc(cachedDc) {}
|
||||
HDC dc;
|
||||
DWORD refCount;
|
||||
HDC origDc;
|
||||
int savedState;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<HDC__, void(*)(HDC)> OrigDc;
|
||||
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
|
||||
CompatDcMap g_origDcToCompatDc;
|
||||
|
||||
void copyDcAttributes(CompatDc& compatDc, HDC origDc, POINT& origin)
|
||||
CRITICAL_SECTION g_cs;
|
||||
CompatDcMap g_origDcToCompatDc;
|
||||
thread_local std::vector<OrigDc> g_threadDcs;
|
||||
|
||||
void copyDcAttributes(const CompatDc& compatDc, HDC origDc, const POINT& origin)
|
||||
{
|
||||
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT));
|
||||
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
|
||||
@ -76,6 +80,15 @@ namespace
|
||||
MoveToEx(compatDc.dc, currentPos.x, currentPos.y, nullptr);
|
||||
}
|
||||
|
||||
void deleteDc(HDC origDc)
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
auto it = g_origDcToCompatDc.find(origDc);
|
||||
RestoreDC(it->second.dc, it->second.savedState);
|
||||
Gdi::DcCache::deleteDc(it->second.dc);
|
||||
g_origDcToCompatDc.erase(origDc);
|
||||
}
|
||||
|
||||
void setClippingRegion(HDC compatDc, HDC origDc, HWND hwnd, const POINT& origin)
|
||||
{
|
||||
if (hwnd)
|
||||
@ -100,12 +113,16 @@ namespace
|
||||
|
||||
void updateWindow(HWND wnd)
|
||||
{
|
||||
auto window = Gdi::Window::get(wnd);
|
||||
if (!window)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RECT windowRect = {};
|
||||
GetWindowRect(wnd, &windowRect);
|
||||
|
||||
auto& window = Gdi::Window::get(wnd);
|
||||
RECT cachedWindowRect = window.getWindowRect();
|
||||
|
||||
RECT cachedWindowRect = window->getWindowRect();
|
||||
if (!EqualRect(&windowRect, &cachedWindowRect))
|
||||
{
|
||||
Gdi::Window::updateAll();
|
||||
@ -124,8 +141,7 @@ namespace Gdi
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Compat::ScopedCriticalSection gdiLock(Gdi::g_gdiCriticalSection);
|
||||
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
auto it = g_origDcToCompatDc.find(origDc);
|
||||
if (it != g_origDcToCompatDc.end())
|
||||
{
|
||||
@ -140,7 +156,8 @@ namespace Gdi
|
||||
updateWindow(rootWnd);
|
||||
}
|
||||
|
||||
CompatDc compatDc(Gdi::DcCache::getDc());
|
||||
CompatDc compatDc;
|
||||
compatDc.dc = Gdi::DcCache::getDc();
|
||||
if (!compatDc.dc)
|
||||
{
|
||||
return nullptr;
|
||||
@ -148,6 +165,9 @@ namespace Gdi
|
||||
|
||||
POINT origin = {};
|
||||
GetDCOrgEx(origDc, &origin);
|
||||
RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds();
|
||||
origin.x -= virtualScreenBounds.left;
|
||||
origin.y -= virtualScreenBounds.top;
|
||||
|
||||
compatDc.savedState = SaveDC(compatDc.dc);
|
||||
copyDcAttributes(compatDc, origDc, origin);
|
||||
@ -156,21 +176,27 @@ namespace Gdi
|
||||
compatDc.refCount = 1;
|
||||
compatDc.origDc = origDc;
|
||||
g_origDcToCompatDc.insert(CompatDcMap::value_type(origDc, compatDc));
|
||||
g_threadDcs.emplace_back(origDc, &deleteDc);
|
||||
|
||||
return compatDc.dc;
|
||||
}
|
||||
|
||||
HDC getOrigDc(HDC dc)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
InitializeCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
void releaseDc(HDC origDc)
|
||||
{
|
||||
Compat::ScopedCriticalSection gdiLock(Gdi::g_gdiCriticalSection);
|
||||
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
auto it = g_origDcToCompatDc.find(origDc);
|
||||
if (it == g_origDcToCompatDc.end())
|
||||
{
|
||||
@ -181,8 +207,13 @@ namespace Gdi
|
||||
--compatDc.refCount;
|
||||
if (0 == compatDc.refCount)
|
||||
{
|
||||
auto threadDcIter = std::find_if(g_threadDcs.begin(), g_threadDcs.end(),
|
||||
[origDc](const OrigDc& dc) { return dc.get() == origDc; });
|
||||
threadDcIter->release();
|
||||
g_threadDcs.erase(threadDcIter);
|
||||
|
||||
RestoreDC(compatDc.dc, compatDc.savedState);
|
||||
Gdi::DcCache::releaseDc(compatDc);
|
||||
Gdi::DcCache::releaseDc(compatDc.dc);
|
||||
g_origDcToCompatDc.erase(origDc);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ namespace Gdi
|
||||
{
|
||||
HDC getDc(HDC origDc);
|
||||
HDC getOrigDc(HDC dc);
|
||||
void init();
|
||||
void releaseDc(HDC origDc);
|
||||
}
|
||||
}
|
||||
|
@ -1,227 +1,45 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CompatPtr.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Config/Config.h"
|
||||
#include "DDraw/Repository.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
#include "Dll/Procs.h"
|
||||
#include "Gdi/DcCache.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using Gdi::DcCache::CachedDc;
|
||||
|
||||
std::vector<CachedDc> g_cache;
|
||||
DWORD g_cacheSize = 0;
|
||||
DWORD g_cacheId = 0;
|
||||
DWORD g_maxUsedCacheSize = 0;
|
||||
DWORD g_ddLockThreadId = 0;
|
||||
typedef std::unique_ptr<HDC__, void(*)(HDC)> CachedDc;
|
||||
|
||||
CompatWeakPtr<IDirectDrawPalette> g_palette;
|
||||
PALETTEENTRY g_paletteEntries[256] = {};
|
||||
void* g_surfaceMemory = nullptr;
|
||||
LONG g_pitch = 0;
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> createGdiSurface();
|
||||
|
||||
CachedDc createCachedDc()
|
||||
{
|
||||
CachedDc cachedDc = {};
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> surface(createGdiSurface());
|
||||
if (!surface)
|
||||
{
|
||||
return cachedDc;
|
||||
}
|
||||
|
||||
HDC dc = nullptr;
|
||||
HRESULT result = surface->GetDC(surface, &dc);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to create a GDI DC: " << result);
|
||||
return cachedDc;
|
||||
}
|
||||
|
||||
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
||||
Dll::g_origProcs.ReleaseDDThreadLock();
|
||||
|
||||
cachedDc.surface = surface.detach();
|
||||
cachedDc.dc = dc;
|
||||
cachedDc.cacheId = g_cacheId;
|
||||
return cachedDc;
|
||||
}
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> createGdiSurface()
|
||||
{
|
||||
DDSURFACEDESC2 desc = DDraw::PrimarySurface::getDesc();
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||
desc.lPitch = g_pitch;
|
||||
desc.lpSurface = g_surfaceMemory;
|
||||
|
||||
auto dd(DDraw::Repository::getDirectDraw());
|
||||
CompatPtr<IDirectDrawSurface7> surface;
|
||||
HRESULT result = dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to create a GDI surface: " << result);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (desc.ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
surface->SetPalette(surface, g_palette);
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
void extendCache()
|
||||
{
|
||||
if (g_cacheSize >= Config::preallocatedGdiDcCount)
|
||||
{
|
||||
LOG_ONCE("Warning: Preallocated GDI DC count is insufficient. This may lead to graphical issues.");
|
||||
}
|
||||
|
||||
if (GetCurrentThreadId() != g_ddLockThreadId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < Config::preallocatedGdiDcCount; ++i)
|
||||
{
|
||||
CachedDc cachedDc = createCachedDc();
|
||||
if (!cachedDc.dc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_cache.push_back(cachedDc);
|
||||
++g_cacheSize;
|
||||
}
|
||||
}
|
||||
|
||||
void releaseCachedDc(CachedDc cachedDc)
|
||||
{
|
||||
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
||||
Dll::g_origProcs.AcquireDDThreadLock();
|
||||
|
||||
HRESULT result = cachedDc.surface->ReleaseDC(cachedDc.surface, cachedDc.dc);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to release a cached DC: " << result);
|
||||
}
|
||||
|
||||
cachedDc.surface.release();
|
||||
}
|
||||
thread_local std::vector<CachedDc> g_cache;
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
namespace DcCache
|
||||
{
|
||||
void clear()
|
||||
void deleteDc(HDC cachedDc)
|
||||
{
|
||||
for (auto& cachedDc : g_cache)
|
||||
{
|
||||
releaseCachedDc(cachedDc);
|
||||
}
|
||||
g_cache.clear();
|
||||
g_cacheSize = 0;
|
||||
++g_cacheId;
|
||||
Gdi::VirtualScreen::deleteDc(cachedDc);
|
||||
}
|
||||
|
||||
CachedDc getDc()
|
||||
HDC getDc()
|
||||
{
|
||||
CachedDc cachedDc = {};
|
||||
if (!g_surfaceMemory)
|
||||
{
|
||||
return cachedDc;
|
||||
}
|
||||
HDC cachedDc = nullptr;
|
||||
|
||||
if (g_cache.empty())
|
||||
{
|
||||
extendCache();
|
||||
cachedDc = Gdi::VirtualScreen::createDc();
|
||||
}
|
||||
|
||||
if (!g_cache.empty())
|
||||
else
|
||||
{
|
||||
cachedDc = g_cache.back();
|
||||
cachedDc = g_cache.back().release();
|
||||
g_cache.pop_back();
|
||||
|
||||
const DWORD usedCacheSize = g_cacheSize - g_cache.size();
|
||||
if (usedCacheSize > g_maxUsedCacheSize)
|
||||
{
|
||||
g_maxUsedCacheSize = usedCacheSize;
|
||||
Compat::Log() << "GDI used DC cache size: " << g_maxUsedCacheSize;
|
||||
}
|
||||
}
|
||||
|
||||
return cachedDc;
|
||||
}
|
||||
|
||||
bool init()
|
||||
void releaseDc(HDC cachedDc)
|
||||
{
|
||||
auto dd(DDraw::Repository::getDirectDraw());
|
||||
dd->CreatePalette(dd,
|
||||
DDPCAPS_8BIT | DDPCAPS_ALLOW256, g_paletteEntries, &g_palette.getRef(), nullptr);
|
||||
return nullptr != g_palette;
|
||||
}
|
||||
|
||||
void releaseDc(const CachedDc& cachedDc)
|
||||
{
|
||||
if (cachedDc.cacheId == g_cacheId)
|
||||
{
|
||||
g_cache.push_back(cachedDc);
|
||||
}
|
||||
else
|
||||
{
|
||||
releaseCachedDc(cachedDc);
|
||||
}
|
||||
}
|
||||
|
||||
void setDdLockThreadId(DWORD ddLockThreadId)
|
||||
{
|
||||
g_ddLockThreadId = ddLockThreadId;
|
||||
}
|
||||
|
||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch)
|
||||
{
|
||||
if (g_surfaceMemory == surfaceMemory && g_pitch == pitch)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_surfaceMemory = surfaceMemory;
|
||||
g_pitch = pitch;
|
||||
clear();
|
||||
}
|
||||
|
||||
void updatePalette(DWORD startingEntry, DWORD count)
|
||||
{
|
||||
PALETTEENTRY entries[256] = {};
|
||||
std::memcpy(&entries[startingEntry],
|
||||
&DDraw::PrimarySurface::s_paletteEntries[startingEntry],
|
||||
count * sizeof(PALETTEENTRY));
|
||||
|
||||
for (DWORD i = startingEntry; i < startingEntry + count; ++i)
|
||||
{
|
||||
if (entries[i].peFlags & PC_RESERVED)
|
||||
{
|
||||
entries[i] = DDraw::PrimarySurface::s_paletteEntries[0];
|
||||
entries[i].peFlags = DDraw::PrimarySurface::s_paletteEntries[i].peFlags;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != std::memcmp(&g_paletteEntries[startingEntry], &entries[startingEntry],
|
||||
count * sizeof(PALETTEENTRY)))
|
||||
{
|
||||
std::memcpy(&g_paletteEntries[startingEntry], &entries[startingEntry],
|
||||
count * sizeof(PALETTEENTRY));
|
||||
g_palette->SetEntries(g_palette, 0, startingEntry, count, g_paletteEntries);
|
||||
clear();
|
||||
}
|
||||
g_cache.emplace_back(CachedDc(cachedDc, &deleteDc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <ddraw.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include "Common/CompatWeakPtr.h"
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
namespace DcCache
|
||||
{
|
||||
struct CachedDc
|
||||
{
|
||||
CompatWeakPtr<IDirectDrawSurface7> surface;
|
||||
HDC dc;
|
||||
DWORD cacheId;
|
||||
};
|
||||
|
||||
void clear();
|
||||
CachedDc getDc();
|
||||
bool init();
|
||||
void releaseDc(const CachedDc& cachedDc);
|
||||
void setDdLockThreadId(DWORD ddLockThreadId);
|
||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
||||
void updatePalette(DWORD startingEntry, DWORD count);
|
||||
void deleteDc(HDC cachedDc);
|
||||
HDC getDc();
|
||||
void releaseDc(HDC cachedDc);
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
#include "Common/Hook.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
#include "Gdi/Dc.h"
|
||||
#include "Gdi/DcFunctions.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
#include "Win32/DisplayMode.h"
|
||||
|
||||
namespace
|
||||
@ -80,21 +82,18 @@ namespace
|
||||
Compat::LogEnter(g_funcNames[origFunc], params...);
|
||||
#endif
|
||||
|
||||
if (!hasDisplayDcArg(params...) ||
|
||||
!Gdi::beginGdiRendering(getDdLockFlags<OrigFuncPtr, origFunc>(params...)))
|
||||
Result result = 0;
|
||||
if (hasDisplayDcArg(params...))
|
||||
{
|
||||
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
||||
|
||||
#ifdef _DEBUG
|
||||
Compat::LogLeave(g_funcNames[origFunc], params...) << result;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
const bool isReadOnlyAccess = getDdLockFlags<OrigFuncPtr, origFunc>(params...) & DDLOCK_READONLY;
|
||||
Gdi::GdiAccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
|
||||
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
||||
releaseDc(params...);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
||||
}
|
||||
|
||||
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
||||
releaseDc(params...);
|
||||
Gdi::endGdiRendering();
|
||||
|
||||
#ifdef _DEBUG
|
||||
Compat::LogLeave(g_funcNames[origFunc], params...) << result;
|
||||
@ -254,6 +253,13 @@ namespace
|
||||
return 1;
|
||||
}
|
||||
|
||||
UINT WINAPI realizePalette(HDC hdc)
|
||||
{
|
||||
UINT result = CALL_ORIG_FUNC(RealizePalette)(hdc);
|
||||
Gdi::VirtualScreen::updatePalette();
|
||||
return result;
|
||||
}
|
||||
|
||||
HWND WINAPI windowFromDc(HDC dc)
|
||||
{
|
||||
return CALL_ORIG_FUNC(WindowFromDC)(Gdi::Dc::getOrigDc(dc));
|
||||
@ -311,6 +317,9 @@ namespace Gdi
|
||||
// Clipping functions
|
||||
HOOK_FUNCTION(gdi32, GetRandomRgn, getRandomRgn);
|
||||
|
||||
// Color functions
|
||||
HOOK_SHIM_FUNCTION(RealizePalette, realizePalette);
|
||||
|
||||
// Device context functions
|
||||
HOOK_GDI_DC_FUNCTION(gdi32, DrawEscape);
|
||||
HOOK_FUNCTION(user32, WindowFromDC, windowFromDc);
|
||||
|
@ -1,152 +1,37 @@
|
||||
#include "Common/ScopedCriticalSection.h"
|
||||
#include "DDraw/RealPrimarySurface.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
#include "Dll/Procs.h"
|
||||
#include "Gdi/Caret.h"
|
||||
#include "Gdi/DcCache.h"
|
||||
#include "Gdi/Dc.h"
|
||||
#include "Gdi/DcFunctions.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/PaintHandlers.h"
|
||||
#include "Gdi/ScrollFunctions.h"
|
||||
#include "Gdi/Window.h"
|
||||
#include "Gdi/WinProc.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
DWORD g_gdiThreadId = 0;
|
||||
DWORD g_renderingRefCount = 0;
|
||||
DWORD g_ddLockFlags = 0;
|
||||
DWORD g_ddLockThreadRenderingRefCount = 0;
|
||||
DWORD g_ddLockThreadId = 0;
|
||||
HANDLE g_ddUnlockBeginEvent = nullptr;
|
||||
HANDLE g_ddUnlockEndEvent = nullptr;
|
||||
bool g_isDelayedUnlockPending = false;
|
||||
|
||||
bool lockGdiSurface(DWORD lockFlags)
|
||||
{
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
auto gdiSurface(DDraw::PrimarySurface::getGdiSurface());
|
||||
if (!gdiSurface || FAILED(gdiSurface.get()->lpVtbl->Lock(
|
||||
gdiSurface, nullptr, &desc, lockFlags | DDLOCK_WAIT, nullptr)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
g_ddLockFlags = lockFlags;
|
||||
if (0 != lockFlags)
|
||||
{
|
||||
EnterCriticalSection(&Gdi::g_gdiCriticalSection);
|
||||
}
|
||||
|
||||
g_ddLockThreadId = GetCurrentThreadId();
|
||||
Gdi::DcCache::setDdLockThreadId(g_ddLockThreadId);
|
||||
Gdi::DcCache::setSurfaceMemory(desc.lpSurface, desc.lPitch);
|
||||
return true;
|
||||
}
|
||||
HDC g_screenDc = nullptr;
|
||||
|
||||
BOOL CALLBACK redrawWindowCallback(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
Gdi::redrawWindow(hwnd, reinterpret_cast<HRGN>(lParam));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void unlockGdiSurface()
|
||||
{
|
||||
GdiFlush();
|
||||
auto gdiSurface(DDraw::PrimarySurface::getGdiSurface());
|
||||
if (gdiSurface)
|
||||
{
|
||||
gdiSurface.get()->lpVtbl->Unlock(gdiSurface, nullptr);
|
||||
if (DDLOCK_READONLY != g_ddLockFlags)
|
||||
{
|
||||
DDraw::RealPrimarySurface::update();
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != g_ddLockFlags)
|
||||
{
|
||||
LeaveCriticalSection(&Gdi::g_gdiCriticalSection);
|
||||
}
|
||||
g_ddLockFlags = 0;
|
||||
|
||||
Dll::g_origProcs.ReleaseDDThreadLock();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
CRITICAL_SECTION g_gdiCriticalSection;
|
||||
|
||||
bool beginGdiRendering(DWORD lockFlags)
|
||||
{
|
||||
Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection);
|
||||
|
||||
if (0 == g_renderingRefCount)
|
||||
{
|
||||
LeaveCriticalSection(&g_gdiCriticalSection);
|
||||
Dll::g_origProcs.AcquireDDThreadLock();
|
||||
EnterCriticalSection(&g_gdiCriticalSection);
|
||||
if (!lockGdiSurface(lockFlags))
|
||||
{
|
||||
Dll::g_origProcs.ReleaseDDThreadLock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetCurrentThreadId() == g_ddLockThreadId)
|
||||
{
|
||||
++g_ddLockThreadRenderingRefCount;
|
||||
}
|
||||
|
||||
++g_renderingRefCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
void endGdiRendering()
|
||||
{
|
||||
Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection);
|
||||
|
||||
if (GetCurrentThreadId() == g_ddLockThreadId)
|
||||
{
|
||||
if (1 == g_renderingRefCount)
|
||||
{
|
||||
unlockGdiSurface();
|
||||
g_ddLockThreadRenderingRefCount = 0;
|
||||
g_renderingRefCount = 0;
|
||||
}
|
||||
else if (1 == g_ddLockThreadRenderingRefCount)
|
||||
{
|
||||
g_isDelayedUnlockPending = true;
|
||||
gdiLock.unlock();
|
||||
WaitForSingleObject(g_ddUnlockBeginEvent, INFINITE);
|
||||
unlockGdiSurface();
|
||||
g_ddLockThreadRenderingRefCount = 0;
|
||||
g_renderingRefCount = 0;
|
||||
SetEvent(g_ddUnlockEndEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
--g_ddLockThreadRenderingRefCount;
|
||||
--g_renderingRefCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
--g_renderingRefCount;
|
||||
if (1 == g_renderingRefCount && g_isDelayedUnlockPending)
|
||||
{
|
||||
SetEvent(g_ddUnlockBeginEvent);
|
||||
WaitForSingleObject(g_ddUnlockEndEvent, INFINITE);
|
||||
g_isDelayedUnlockPending = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DWORD getGdiThreadId()
|
||||
{
|
||||
return g_gdiThreadId;
|
||||
}
|
||||
|
||||
HDC getScreenDc()
|
||||
{
|
||||
return g_screenDc;
|
||||
}
|
||||
|
||||
HRGN getVisibleWindowRgn(HWND hwnd)
|
||||
{
|
||||
return DcFunctions::getVisibleWindowRgn(hwnd);
|
||||
@ -163,39 +48,24 @@ namespace Gdi
|
||||
void installHooks()
|
||||
{
|
||||
g_gdiThreadId = GetCurrentThreadId();
|
||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||
if (Gdi::DcCache::init())
|
||||
{
|
||||
g_ddUnlockBeginEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
g_ddUnlockEndEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
if (!g_ddUnlockBeginEvent || !g_ddUnlockEndEvent)
|
||||
{
|
||||
Compat::Log() << "Failed to create the unlock events for GDI";
|
||||
return;
|
||||
}
|
||||
g_screenDc = GetDC(nullptr);
|
||||
|
||||
Gdi::DcFunctions::installHooks();
|
||||
Gdi::PaintHandlers::installHooks();
|
||||
Gdi::ScrollFunctions::installHooks();
|
||||
Gdi::WinProc::installHooks();
|
||||
Gdi::Caret::installHooks();
|
||||
}
|
||||
}
|
||||
|
||||
bool isTopLevelWindow(HWND hwnd)
|
||||
{
|
||||
return !(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) ||
|
||||
GetParent(hwnd) == GetDesktopWindow();
|
||||
Gdi::Dc::init();
|
||||
Gdi::DcFunctions::installHooks();
|
||||
Gdi::PaintHandlers::installHooks();
|
||||
Gdi::ScrollFunctions::installHooks();
|
||||
Gdi::WinProc::installHooks();
|
||||
Gdi::Caret::installHooks();
|
||||
}
|
||||
|
||||
void redraw(HRGN rgn)
|
||||
{
|
||||
EnumThreadWindows(GetCurrentThreadId(), &redrawWindowCallback, reinterpret_cast<LPARAM>(rgn));
|
||||
EnumThreadWindows(g_gdiThreadId, &redrawWindowCallback, reinterpret_cast<LPARAM>(rgn));
|
||||
}
|
||||
|
||||
void redrawWindow(HWND hwnd, HRGN rgn)
|
||||
{
|
||||
if (!IsWindowVisible(hwnd) || IsIconic(hwnd))
|
||||
if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || Window::isPresentationWindow(hwnd))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -228,14 +98,7 @@ namespace Gdi
|
||||
Gdi::Caret::uninstallHooks();
|
||||
Gdi::WinProc::uninstallHooks();
|
||||
Gdi::PaintHandlers::uninstallHooks();
|
||||
}
|
||||
|
||||
void updatePalette(DWORD startingEntry, DWORD count)
|
||||
{
|
||||
if (DDraw::PrimarySurface::s_palette)
|
||||
{
|
||||
Gdi::DcCache::updatePalette(startingEntry, count);
|
||||
}
|
||||
ReleaseDC(nullptr, g_screenDc);
|
||||
}
|
||||
|
||||
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
|
||||
|
@ -8,20 +8,14 @@ namespace Gdi
|
||||
{
|
||||
typedef void(*WindowPosChangeNotifyFunc)();
|
||||
|
||||
bool beginGdiRendering(DWORD lockFlags = 0);
|
||||
void endGdiRendering();
|
||||
|
||||
DWORD getGdiThreadId();
|
||||
HDC getScreenDc();
|
||||
HRGN getVisibleWindowRgn(HWND hwnd);
|
||||
void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc);
|
||||
void installHooks();
|
||||
bool isTopLevelWindow(HWND hwnd);
|
||||
void redraw(HRGN rgn);
|
||||
void redrawWindow(HWND hwnd, HRGN rgn);
|
||||
void unhookWndProc(LPCSTR className, WNDPROC oldWndProc);
|
||||
void uninstallHooks();
|
||||
void updatePalette(DWORD startingEntry, DWORD count);
|
||||
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc);
|
||||
|
||||
extern CRITICAL_SECTION g_gdiCriticalSection;
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "Common/Hook.h"
|
||||
#include "Common/Log.h"
|
||||
#include "DDraw/RealPrimarySurface.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
#include "Gdi/Dc.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/PaintHandlers.h"
|
||||
@ -185,19 +186,15 @@ namespace
|
||||
|
||||
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
|
||||
{
|
||||
if (hwnd && Gdi::beginGdiRendering())
|
||||
if (hwnd)
|
||||
{
|
||||
LRESULT result = 0;
|
||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||
if (compatDc)
|
||||
{
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
result = CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
|
||||
Gdi::Dc::releaseDc(dc);
|
||||
}
|
||||
|
||||
Gdi::endGdiRendering();
|
||||
if (compatDc)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -207,7 +204,7 @@ namespace
|
||||
|
||||
LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc)
|
||||
{
|
||||
if (!hwnd || !Gdi::beginGdiRendering())
|
||||
if (!hwnd)
|
||||
{
|
||||
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
||||
}
|
||||
@ -216,6 +213,7 @@ namespace
|
||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||
if (compatDc)
|
||||
{
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
|
||||
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
||||
ValidateRect(hwnd, nullptr);
|
||||
@ -227,13 +225,12 @@ namespace
|
||||
}
|
||||
|
||||
ReleaseDC(hwnd, dc);
|
||||
Gdi::endGdiRendering();
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc)
|
||||
{
|
||||
if (!hwnd || !Gdi::beginGdiRendering())
|
||||
if (!hwnd)
|
||||
{
|
||||
return CallWindowProc(origWndProc, hwnd, WM_NCPAINT, wParam, 0);
|
||||
}
|
||||
@ -243,6 +240,7 @@ namespace
|
||||
|
||||
if (compatDc)
|
||||
{
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
Gdi::TitleBar titleBar(hwnd, compatDc);
|
||||
titleBar.drawAll();
|
||||
titleBar.excludeFromClipRegion();
|
||||
@ -257,13 +255,12 @@ namespace
|
||||
}
|
||||
|
||||
ReleaseDC(hwnd, windowDc);
|
||||
Gdi::endGdiRendering();
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc)
|
||||
{
|
||||
if (!hwnd || !Gdi::beginGdiRendering())
|
||||
if (!hwnd)
|
||||
{
|
||||
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
||||
}
|
||||
@ -274,6 +271,7 @@ namespace
|
||||
|
||||
if (compatDc)
|
||||
{
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
|
||||
reinterpret_cast<WPARAM>(compatDc), PRF_CLIENT);
|
||||
Gdi::Dc::releaseDc(dc);
|
||||
@ -285,21 +283,16 @@ namespace
|
||||
|
||||
EndPaint(hwnd, &paint);
|
||||
|
||||
Gdi::endGdiRendering();
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc)
|
||||
{
|
||||
if (!Gdi::beginGdiRendering())
|
||||
{
|
||||
return CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), flags);
|
||||
}
|
||||
|
||||
LRESULT result = 0;
|
||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||
if (compatDc)
|
||||
{
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(compatDc), flags);
|
||||
Gdi::Dc::releaseDc(dc);
|
||||
}
|
||||
@ -307,8 +300,6 @@ namespace
|
||||
{
|
||||
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), flags);
|
||||
}
|
||||
|
||||
Gdi::endGdiRendering();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,9 @@
|
||||
#include <utility>
|
||||
|
||||
#include "Gdi/Region.h"
|
||||
#include "Win32/DisplayMode.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
BOOL CALLBACK addMonitorRectToRegion(
|
||||
HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
Gdi::Region& virtualScreenRegion = *reinterpret_cast<Gdi::Region*>(dwData);
|
||||
Gdi::Region monitorRegion(*lprcMonitor);
|
||||
virtualScreenRegion |= monitorRegion;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Gdi::Region calculateVirtualScreenRegion()
|
||||
{
|
||||
Gdi::Region region;
|
||||
EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(®ion));
|
||||
return region;
|
||||
}
|
||||
|
||||
Gdi::Region combineRegions(const Gdi::Region& rgn1, const Gdi::Region& rgn2, int mode)
|
||||
{
|
||||
Gdi::Region region;
|
||||
@ -132,17 +115,4 @@ namespace Gdi
|
||||
CombineRgn(m_region, m_region, other, mode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Region& getVirtualScreenRegion()
|
||||
{
|
||||
static Region virtualScreenRegion;
|
||||
static ULONG displaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
|
||||
const ULONG currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
|
||||
if (currentDisplaySettingsUniqueness != displaySettingsUniqueness)
|
||||
{
|
||||
virtualScreenRegion = calculateVirtualScreenRegion();
|
||||
displaySettingsUniqueness = currentDisplaySettingsUniqueness;
|
||||
}
|
||||
return virtualScreenRegion;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,4 @@ namespace Gdi
|
||||
|
||||
HRGN m_region;
|
||||
};
|
||||
|
||||
const Region& getVirtualScreenRegion();
|
||||
}
|
||||
|
244
DDrawCompat/Gdi/VirtualScreen.cpp
Normal file
244
DDrawCompat/Gdi/VirtualScreen.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
#include <set>
|
||||
|
||||
#include "Common/ScopedCriticalSection.h"
|
||||
#include "DDraw/DirectDraw.h"
|
||||
#include "DDraw/Repository.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/Region.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
#include "Win32/DisplayMode.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
CRITICAL_SECTION g_cs = {};
|
||||
Gdi::Region g_region;
|
||||
RECT g_bounds = {};
|
||||
DWORD g_bpp = 0;
|
||||
LONG g_width = 0;
|
||||
LONG g_height = 0;
|
||||
DWORD g_pitch = 0;
|
||||
HANDLE g_surfaceFileMapping = nullptr;
|
||||
void* g_surfaceView = nullptr;
|
||||
|
||||
HGDIOBJ g_stockBitmap = nullptr;
|
||||
RGBQUAD g_systemPalette[256] = {};
|
||||
std::set<HDC> g_dcs;
|
||||
|
||||
BOOL CALLBACK addMonitorRectToRegion(
|
||||
HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
Gdi::Region& virtualScreenRegion = *reinterpret_cast<Gdi::Region*>(dwData);
|
||||
Gdi::Region monitorRegion(*lprcMonitor);
|
||||
virtualScreenRegion |= monitorRegion;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
namespace VirtualScreen
|
||||
{
|
||||
HDC createDc()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
std::unique_ptr<void, decltype(&DeleteObject)> dib(createDib(), DeleteObject);
|
||||
if (!dib)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<HDC__, decltype(&DeleteDC)> dc(CreateCompatibleDC(nullptr), DeleteDC);
|
||||
if (!dc)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HGDIOBJ stockBitmap = SelectObject(dc.get(), dib.get());
|
||||
if (!stockBitmap)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dib.release();
|
||||
|
||||
|
||||
g_stockBitmap = stockBitmap;
|
||||
g_dcs.insert(dc.get());
|
||||
return dc.release();
|
||||
}
|
||||
|
||||
HBITMAP createDib()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (!g_surfaceFileMapping)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct BITMAPINFO256 : public BITMAPINFO
|
||||
{
|
||||
RGBQUAD bmiRemainingColors[255];
|
||||
};
|
||||
|
||||
BITMAPINFO256 bmi = {};
|
||||
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||
bmi.bmiHeader.biWidth = g_width;
|
||||
bmi.bmiHeader.biHeight = -g_height;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = static_cast<WORD>(g_bpp);
|
||||
bmi.bmiHeader.biCompression = 8 == g_bpp ? BI_RGB : BI_BITFIELDS;
|
||||
|
||||
if (8 == g_bpp)
|
||||
{
|
||||
memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette));
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto pf = DDraw::getRgbPixelFormat(g_bpp);
|
||||
reinterpret_cast<DWORD&>(bmi.bmiColors[0]) = pf.dwRBitMask;
|
||||
reinterpret_cast<DWORD&>(bmi.bmiColors[1]) = pf.dwGBitMask;
|
||||
reinterpret_cast<DWORD&>(bmi.bmiColors[2]) = pf.dwBBitMask;
|
||||
}
|
||||
|
||||
void* bits = nullptr;
|
||||
return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, g_surfaceFileMapping, 0);
|
||||
}
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect)
|
||||
{
|
||||
if (rect.left < g_bounds.left || rect.top < g_bounds.top ||
|
||||
rect.right > g_bounds.right || rect.bottom > g_bounds.bottom)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
||||
desc.dwWidth = rect.right - rect.left;
|
||||
desc.dwHeight = rect.bottom - rect.top;
|
||||
desc.ddpfPixelFormat = DDraw::getRgbPixelFormat(g_bpp);
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||
desc.lPitch = g_pitch;
|
||||
desc.lpSurface = static_cast<unsigned char*>(g_surfaceView) +
|
||||
(rect.top - g_bounds.top) * g_pitch +
|
||||
(rect.left - g_bounds.left) * g_bpp / 8;
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> surface;
|
||||
auto dd(DDraw::Repository::getDirectDraw());
|
||||
dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
|
||||
return surface;
|
||||
}
|
||||
|
||||
void deleteDc(HDC dc)
|
||||
{
|
||||
if (!dc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
DeleteObject(SelectObject(dc, g_stockBitmap));
|
||||
DeleteDC(dc);
|
||||
g_dcs.erase(dc);
|
||||
}
|
||||
|
||||
RECT getBounds()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
return g_bounds;
|
||||
}
|
||||
|
||||
const Region& getRegion()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
return g_region;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
InitializeCriticalSection(&g_cs);
|
||||
update();
|
||||
updatePalette();
|
||||
}
|
||||
|
||||
bool update()
|
||||
{
|
||||
Compat::LogEnter("VirtualScreen::update");
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
|
||||
static auto prevDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
|
||||
const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
|
||||
if (currentDisplaySettingsUniqueness == prevDisplaySettingsUniqueness)
|
||||
{
|
||||
Compat::LogLeave("VirtualScreen::update") << false;
|
||||
return false;
|
||||
}
|
||||
|
||||
prevDisplaySettingsUniqueness = currentDisplaySettingsUniqueness;
|
||||
|
||||
g_region = Region();
|
||||
EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(&g_region));
|
||||
GetRgnBox(g_region, &g_bounds);
|
||||
|
||||
g_bpp = Win32::DisplayMode::getBpp();
|
||||
g_width = g_bounds.right - g_bounds.left;
|
||||
g_height = g_bounds.bottom - g_bounds.top;
|
||||
g_pitch = (g_width * g_bpp / 8 + 3) & ~3;
|
||||
|
||||
if (g_surfaceFileMapping)
|
||||
{
|
||||
for (HDC dc : g_dcs)
|
||||
{
|
||||
DeleteObject(SelectObject(dc, g_stockBitmap));
|
||||
}
|
||||
UnmapViewOfFile(g_surfaceView);
|
||||
CloseHandle(g_surfaceFileMapping);
|
||||
}
|
||||
|
||||
g_surfaceFileMapping = CreateFileMapping(
|
||||
INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, g_pitch * g_height, nullptr);
|
||||
g_surfaceView = MapViewOfFile(g_surfaceFileMapping, FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
for (HDC dc : g_dcs)
|
||||
{
|
||||
SelectObject(dc, createDib());
|
||||
}
|
||||
|
||||
Gdi::redraw(nullptr);
|
||||
|
||||
Compat::LogLeave("VirtualScreen::update") << true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void updatePalette()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (8 != g_bpp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PALETTEENTRY pal[256] = {};
|
||||
GetSystemPaletteEntries(nullptr, 0, 256, pal);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (0 != memcmp(g_systemPalette, systemPalette, sizeof(systemPalette)))
|
||||
{
|
||||
memcpy(g_systemPalette, systemPalette, sizeof(systemPalette));
|
||||
for (HDC dc : g_dcs)
|
||||
{
|
||||
SetDIBColorTable(dc, 0, 256, systemPalette);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
DDrawCompat/Gdi/VirtualScreen.h
Normal file
27
DDrawCompat/Gdi/VirtualScreen.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "Common/CompatPtr.h"
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
class Region;
|
||||
|
||||
namespace VirtualScreen
|
||||
{
|
||||
HDC createDc();
|
||||
HBITMAP createDib();
|
||||
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect);
|
||||
void deleteDc(HDC dc);
|
||||
|
||||
RECT getBounds();
|
||||
const Region& getRegion();
|
||||
|
||||
void init();
|
||||
bool update();
|
||||
void updatePalette();
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/ScopedCriticalSection.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
#include "Gdi/Dc.h"
|
||||
#include "Gdi/ScrollBar.h"
|
||||
#include "Gdi/ScrollFunctions.h"
|
||||
@ -94,6 +95,12 @@ namespace
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool isTopLevelNonLayeredWindow(HWND hwnd)
|
||||
{
|
||||
return !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
|
||||
(!(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) || GetParent(hwnd) == GetDesktopWindow());
|
||||
}
|
||||
|
||||
void CALLBACK objectStateChangeEvent(
|
||||
HWINEVENTHOOK /*hWinEventHook*/,
|
||||
DWORD /*event*/,
|
||||
@ -105,7 +112,7 @@ namespace
|
||||
{
|
||||
if (OBJID_TITLEBAR == idObject || OBJID_HSCROLL == idObject || OBJID_VSCROLL == idObject)
|
||||
{
|
||||
if (!hwnd || !Gdi::beginGdiRendering())
|
||||
if (!hwnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -114,6 +121,7 @@ namespace
|
||||
HDC compatDc = Gdi::Dc::getDc(windowDc);
|
||||
if (compatDc)
|
||||
{
|
||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
if (OBJID_TITLEBAR == idObject)
|
||||
{
|
||||
Gdi::TitleBar(hwnd, compatDc).drawButtons();
|
||||
@ -128,9 +136,7 @@ namespace
|
||||
}
|
||||
Gdi::Dc::releaseDc(windowDc);
|
||||
}
|
||||
|
||||
ReleaseDC(hwnd, windowDc);
|
||||
Gdi::endGdiRendering();
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,22 +160,17 @@ namespace
|
||||
|
||||
void onCreateWindow(HWND hwnd)
|
||||
{
|
||||
if (Gdi::isTopLevelWindow(hwnd))
|
||||
if (isTopLevelNonLayeredWindow(hwnd))
|
||||
{
|
||||
disableDwmAttributes(hwnd);
|
||||
removeDropShadow(hwnd);
|
||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
||||
Gdi::Window::add(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
void onDestroyWindow(HWND hwnd)
|
||||
{
|
||||
if (Gdi::isTopLevelWindow(hwnd))
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
||||
Gdi::Window::remove(hwnd);
|
||||
}
|
||||
Gdi::Window::remove(hwnd);
|
||||
}
|
||||
|
||||
void onMenuSelect()
|
||||
@ -190,19 +191,15 @@ namespace
|
||||
SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
||||
}
|
||||
|
||||
if (!Gdi::isTopLevelWindow(hwnd))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
||||
|
||||
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
||||
{
|
||||
notifyFunc();
|
||||
}
|
||||
|
||||
Gdi::Window::updateAll();
|
||||
if (isTopLevelNonLayeredWindow(hwnd))
|
||||
{
|
||||
Gdi::Window::updateAll();
|
||||
}
|
||||
}
|
||||
|
||||
void removeDropShadow(HWND hwnd)
|
||||
|
@ -1,6 +1,34 @@
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/VirtualScreen.h"
|
||||
#include "Gdi/Window.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
namespace
|
||||
{
|
||||
ATOM registerPresentationWindowClass();
|
||||
|
||||
ATOM getPresentationWindowClassAtom()
|
||||
{
|
||||
static ATOM atom = registerPresentationWindowClass();
|
||||
return atom;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK presentationWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
ATOM registerPresentationWindowClass()
|
||||
{
|
||||
WNDCLASS wc = {};
|
||||
wc.lpfnWndProc = &presentationWindowProc;
|
||||
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
wc.lpszClassName = "DDrawCompatPresentationWindow";
|
||||
return RegisterClass(&wc);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
Window::Window(HWND hwnd)
|
||||
@ -8,18 +36,34 @@ namespace Gdi
|
||||
, m_windowRect{ 0, 0, 0, 0 }
|
||||
, m_isUpdating(false)
|
||||
{
|
||||
m_presentationWindow = CreateWindowEx(
|
||||
WS_EX_LAYERED | WS_EX_TRANSPARENT,
|
||||
reinterpret_cast<const char*>(getPresentationWindowClassAtom()),
|
||||
nullptr,
|
||||
WS_DISABLED | WS_POPUP,
|
||||
0, 0, 1, 1,
|
||||
m_hwnd,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
SetLayeredWindowAttributes(m_presentationWindow, 0, 255, LWA_ALPHA);
|
||||
update();
|
||||
}
|
||||
|
||||
Window& Window::add(HWND hwnd)
|
||||
Window* Window::add(HWND hwnd)
|
||||
{
|
||||
auto it = s_windows.find(hwnd);
|
||||
if (it != s_windows.end())
|
||||
{
|
||||
return it->second;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
return s_windows.emplace(hwnd, hwnd).first->second;
|
||||
if (isPresentationWindow(hwnd))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &s_windows.emplace(hwnd, hwnd).first->second;
|
||||
}
|
||||
|
||||
void Window::calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion)
|
||||
@ -41,21 +85,22 @@ namespace Gdi
|
||||
|
||||
if (!preservedRegion.isEmpty())
|
||||
{
|
||||
HDC screenDc = GetDC(nullptr);
|
||||
HDC screenDc = Gdi::getScreenDc();
|
||||
SelectClipRgn(screenDc, preservedRegion);
|
||||
BitBlt(screenDc, m_windowRect.left, m_windowRect.top,
|
||||
oldWindowRect.right - oldWindowRect.left, oldWindowRect.bottom - oldWindowRect.top,
|
||||
screenDc, oldWindowRect.left, oldWindowRect.top, SRCCOPY);
|
||||
ReleaseDC(nullptr, screenDc);
|
||||
SelectClipRgn(screenDc, nullptr);
|
||||
|
||||
m_invalidatedRegion -= preservedRegion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window& Window::get(HWND hwnd)
|
||||
Window* Window::get(HWND hwnd)
|
||||
{
|
||||
return add(hwnd);
|
||||
auto it = s_windows.find(hwnd);
|
||||
return it != s_windows.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
Region Window::getVisibleRegion() const
|
||||
@ -68,6 +113,11 @@ namespace Gdi
|
||||
return m_windowRect;
|
||||
}
|
||||
|
||||
bool Window::isPresentationWindow(HWND hwnd)
|
||||
{
|
||||
return GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom();
|
||||
}
|
||||
|
||||
void Window::remove(HWND hwnd)
|
||||
{
|
||||
s_windows.erase(hwnd);
|
||||
@ -92,8 +142,12 @@ namespace Gdi
|
||||
HDC windowDc = GetWindowDC(m_hwnd);
|
||||
GetRandomRgn(windowDc, newVisibleRegion, SYSRGN);
|
||||
ReleaseDC(m_hwnd, windowDc);
|
||||
newVisibleRegion &= getVirtualScreenRegion();
|
||||
newVisibleRegion &= VirtualScreen::getRegion();
|
||||
}
|
||||
|
||||
SetWindowPos(m_presentationWindow, nullptr, newWindowRect.left, newWindowRect.top,
|
||||
newWindowRect.right - newWindowRect.left, newWindowRect.bottom - newWindowRect.top,
|
||||
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW);
|
||||
}
|
||||
|
||||
std::swap(m_windowRect, newWindowRect);
|
||||
|
@ -20,9 +20,11 @@ namespace Gdi
|
||||
Region getVisibleRegion() const;
|
||||
RECT getWindowRect() const;
|
||||
|
||||
static Window& add(HWND hwnd);
|
||||
static Window& get(HWND hwnd);
|
||||
static Window* add(HWND hwnd);
|
||||
static Window* get(HWND hwnd);
|
||||
static void remove(HWND hwnd);
|
||||
|
||||
static bool isPresentationWindow(HWND hwnd);
|
||||
static void updateAll();
|
||||
|
||||
private:
|
||||
@ -30,6 +32,7 @@ namespace Gdi
|
||||
void update();
|
||||
|
||||
HWND m_hwnd;
|
||||
HWND m_presentationWindow;
|
||||
RECT m_windowRect;
|
||||
Region m_visibleRegion;
|
||||
Region m_invalidatedRegion;
|
||||
|
@ -372,6 +372,11 @@ namespace Win32
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD getBpp()
|
||||
{
|
||||
return g_currentBpp;
|
||||
}
|
||||
|
||||
ULONG queryDisplaySettingsUniqueness()
|
||||
{
|
||||
static auto ddQueryDisplaySettingsUniqueness = reinterpret_cast<ULONG(APIENTRY*)()>(
|
||||
|
@ -13,6 +13,7 @@ namespace Win32
|
||||
const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage);
|
||||
HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight);
|
||||
|
||||
DWORD getBpp();
|
||||
ULONG queryDisplaySettingsUniqueness();
|
||||
void setDDrawBpp(DWORD bpp);
|
||||
|
||||
|
@ -52,8 +52,7 @@ namespace Win32
|
||||
reinterpret_cast<void*>(settings.orientation), 0);
|
||||
|
||||
const char* regKey = "FontSmoothing";
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETFONTSMOOTHING,
|
||||
reinterpret_cast<LPARAM>(regKey), SMTO_BLOCK, 100, nullptr);
|
||||
PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETFONTSMOOTHING, reinterpret_cast<LPARAM>(regKey));
|
||||
RedrawWindow(nullptr, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user