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
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <detours.h>
|
#include <detours.h>
|
||||||
@ -19,7 +20,7 @@ namespace
|
|||||||
struct HookedFunctionInfo
|
struct HookedFunctionInfo
|
||||||
{
|
{
|
||||||
HMODULE module;
|
HMODULE module;
|
||||||
void* trampoline;
|
void*& origFunction;
|
||||||
void* newFunction;
|
void* newFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ namespace
|
|||||||
std::map<void*, HookedFunctionInfo>::iterator findOrigFunc(void* origFunc)
|
std::map<void*, HookedFunctionInfo>::iterator findOrigFunc(void* origFunc)
|
||||||
{
|
{
|
||||||
return std::find_if(g_hookedFunctions.begin(), g_hookedFunctions.end(),
|
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)
|
std::vector<HMODULE> getProcessModules(HANDLE process)
|
||||||
@ -111,7 +112,7 @@ namespace
|
|||||||
const auto it = findOrigFunc(origFuncPtr);
|
const auto it = findOrigFunc(origFuncPtr);
|
||||||
if (it != g_hookedFunctions.end())
|
if (it != g_hookedFunctions.end())
|
||||||
{
|
{
|
||||||
origFuncPtr = it->second.trampoline;
|
origFuncPtr = it->second.origFunction;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,13 +137,14 @@ namespace
|
|||||||
HMODULE module = nullptr;
|
HMODULE module = nullptr;
|
||||||
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||||
reinterpret_cast<char*>(hookedFuncPtr), &module);
|
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)
|
void unhookFunction(const std::map<void*, HookedFunctionInfo>::iterator& hookedFunc)
|
||||||
{
|
{
|
||||||
DetourTransactionBegin();
|
DetourTransactionBegin();
|
||||||
DetourDetach(&hookedFunc->second.trampoline, hookedFunc->second.newFunction);
|
DetourDetach(&hookedFunc->second.origFunction, hookedFunc->second.newFunction);
|
||||||
DetourTransactionCommit();
|
DetourTransactionCommit();
|
||||||
|
|
||||||
if (hookedFunc->second.module)
|
if (hookedFunc->second.module)
|
||||||
@ -173,7 +175,9 @@ namespace Compat
|
|||||||
if (0 != _stricmp(moduleBaseName.c_str(), moduleName))
|
if (0 != _stricmp(moduleBaseName.c_str(), moduleName))
|
||||||
{
|
{
|
||||||
Compat::Log() << "Disabling external hook to " << funcName << " in " << moduleBaseName;
|
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 maxPaletteUpdatesPerMs = 5;
|
||||||
const int minExpectedFlipsPerSec = 5;
|
const int minExpectedFlipsPerSec = 5;
|
||||||
const DWORD preallocatedGdiDcCount = 4;
|
|
||||||
const DWORD primarySurfaceExtraRows = 2;
|
const DWORD primarySurfaceExtraRows = 2;
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,36 @@
|
|||||||
#include "D3dDdi/Device.h"
|
#include "D3dDdi/Device.h"
|
||||||
#include "D3dDdi/DeviceFuncs.h"
|
#include "D3dDdi/DeviceFuncs.h"
|
||||||
#include "D3dDdi/KernelModeThunks.h"
|
#include "D3dDdi/KernelModeThunks.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
|
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
|
||||||
|
|
||||||
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
|
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()
|
D3DDDI_RESOURCEFLAGS getResourceTypeFlags()
|
||||||
{
|
{
|
||||||
@ -81,8 +105,8 @@ namespace D3dDdi
|
|||||||
|
|
||||||
HRESULT Device::blt(const D3DDDIARG_BLT& data)
|
HRESULT Device::blt(const D3DDDIARG_BLT& data)
|
||||||
{
|
{
|
||||||
prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex);
|
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex);
|
||||||
prepareForRendering(data.hDstResource, data.DstSubResourceIndex);
|
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource, data.DstSubResourceIndex);
|
||||||
|
|
||||||
auto it = m_oversizedResources.find(data.hSrcResource);
|
auto it = m_oversizedResources.find(data.hSrcResource);
|
||||||
if (it != m_oversizedResources.end())
|
if (it != m_oversizedResources.end())
|
||||||
@ -101,13 +125,13 @@ namespace D3dDdi
|
|||||||
|
|
||||||
HRESULT Device::clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect)
|
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);
|
return m_origVtable->pfnClear(m_device, &data, numRect, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::colorFill(const D3DDDIARG_COLORFILL& data)
|
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);
|
return m_origVtable->pfnColorFill(m_device, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +222,10 @@ namespace D3dDdi
|
|||||||
{
|
{
|
||||||
m_sharedPrimary = nullptr;
|
m_sharedPrimary = nullptr;
|
||||||
}
|
}
|
||||||
|
if (resource == g_gdiResourceHandle)
|
||||||
|
{
|
||||||
|
g_gdiResourceHandle = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -205,45 +233,49 @@ namespace D3dDdi
|
|||||||
|
|
||||||
HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data)
|
HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data)
|
||||||
{
|
{
|
||||||
prepareForRendering();
|
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||||
return m_origVtable->pfnDrawIndexedPrimitive(m_device, &data);
|
return m_origVtable->pfnDrawIndexedPrimitive(m_device, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data,
|
HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data,
|
||||||
UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer)
|
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);
|
return m_origVtable->pfnDrawIndexedPrimitive2(m_device, &data, indicesSize, indexBuffer, flagBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* 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);
|
return m_origVtable->pfnDrawPrimitive(m_device, &data, flagBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data)
|
HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data)
|
||||||
{
|
{
|
||||||
prepareForRendering();
|
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||||
return m_origVtable->pfnDrawPrimitive2(m_device, &data);
|
return m_origVtable->pfnDrawPrimitive2(m_device, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info,
|
HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info,
|
||||||
const FLOAT* patch)
|
const FLOAT* patch)
|
||||||
{
|
{
|
||||||
prepareForRendering();
|
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||||
return m_origVtable->pfnDrawRectPatch(m_device, &data, info, patch);
|
return m_origVtable->pfnDrawRectPatch(m_device, &data, info, patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info,
|
HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info,
|
||||||
const FLOAT* patch)
|
const FLOAT* patch)
|
||||||
{
|
{
|
||||||
prepareForRendering();
|
RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE);
|
||||||
return m_origVtable->pfnDrawTriPatch(m_device, &data, info, patch);
|
return m_origVtable->pfnDrawTriPatch(m_device, &data, info, patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::lock(D3DDDIARG_LOCK& data)
|
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);
|
auto it = m_renderTargetResources.find(data.hResource);
|
||||||
if (it != m_renderTargetResources.end())
|
if (it != m_renderTargetResources.end())
|
||||||
{
|
{
|
||||||
@ -269,35 +301,45 @@ namespace D3dDdi
|
|||||||
|
|
||||||
HRESULT Device::present(const D3DDDIARG_PRESENT& data)
|
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);
|
return m_origVtable->pfnPresent(m_device, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::present1(D3DDDIARG_PRESENT1& 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)
|
for (UINT i = 0; i < data.SrcResources; ++i)
|
||||||
{
|
{
|
||||||
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex);
|
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_origVtable->pfnPresent1(m_device, &data);
|
return m_origVtable->pfnPresent1(m_device, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data)
|
HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data)
|
||||||
{
|
{
|
||||||
prepareForRendering(data.hDstResource);
|
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource);
|
||||||
prepareForRendering(data.hSrcResource);
|
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource);
|
||||||
return m_origVtable->pfnTexBlt(m_device, &data);
|
return m_origVtable->pfnTexBlt(m_device, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data)
|
HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data)
|
||||||
{
|
{
|
||||||
prepareForRendering(data.hDstResource);
|
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource);
|
||||||
prepareForRendering(data.hSrcResource);
|
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource);
|
||||||
return m_origVtable->pfnTexBlt1(m_device, &data);
|
return m_origVtable->pfnTexBlt1(m_device, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Device::unlock(const D3DDDIARG_UNLOCK& 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);
|
auto it = m_renderTargetResources.find(data.hResource);
|
||||||
if (it != m_renderTargetResources.end())
|
if (it != m_renderTargetResources.end())
|
||||||
{
|
{
|
||||||
@ -344,4 +386,14 @@ namespace D3dDdi
|
|||||||
prepareForRendering((it++)->second);
|
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(HANDLE resource, UINT subResourceIndex = UINT_MAX);
|
||||||
void prepareForRendering();
|
void prepareForRendering();
|
||||||
|
|
||||||
|
static void setGdiResourceHandle(HANDLE resource);
|
||||||
|
static void setReadOnlyGdiLock(bool enable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename CreateResourceArg, typename CreateResourceFunc>
|
template <typename CreateResourceArg, typename CreateResourceFunc>
|
||||||
HRESULT createOversizedResource(
|
HRESULT createOversizedResource(
|
||||||
|
@ -31,6 +31,7 @@ namespace
|
|||||||
|
|
||||||
std::map<D3DKMT_HANDLE, ContextInfo> g_contexts;
|
std::map<D3DKMT_HANDLE, ContextInfo> g_contexts;
|
||||||
std::map<D3DKMT_HANDLE, DeviceInfo> g_devices;
|
std::map<D3DKMT_HANDLE, DeviceInfo> g_devices;
|
||||||
|
HMONITOR g_lastOpenAdapterMonitor = nullptr;
|
||||||
|
|
||||||
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
||||||
decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr;
|
decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr;
|
||||||
@ -123,6 +124,20 @@ namespace
|
|||||||
return result;
|
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)
|
bool isPresentReady(D3DKMT_HANDLE device, D3DDDI_VIDEO_PRESENT_SOURCE_ID vidPnSourceId)
|
||||||
{
|
{
|
||||||
D3DKMT_GETDEVICESTATE deviceState = {};
|
D3DKMT_GETDEVICESTATE deviceState = {};
|
||||||
@ -253,6 +268,11 @@ namespace D3dDdi
|
|||||||
{
|
{
|
||||||
namespace KernelModeThunks
|
namespace KernelModeThunks
|
||||||
{
|
{
|
||||||
|
HMONITOR getLastOpenAdapterMonitor()
|
||||||
|
{
|
||||||
|
return g_lastOpenAdapterMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
bool isPresentReady()
|
bool isPresentReady()
|
||||||
{
|
{
|
||||||
for (auto it : g_devices)
|
for (auto it : g_devices)
|
||||||
@ -272,6 +292,7 @@ namespace D3dDdi
|
|||||||
HOOK_FUNCTION(gdi32, D3DKMTCreateDCFromMemory, createDcFromMemory);
|
HOOK_FUNCTION(gdi32, D3DKMTCreateDCFromMemory, createDcFromMemory);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTDestroyContext, destroyContext);
|
HOOK_FUNCTION(gdi32, D3DKMTDestroyContext, destroyContext);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTDestroyDevice, destroyDevice);
|
HOOK_FUNCTION(gdi32, D3DKMTDestroyDevice, destroyDevice);
|
||||||
|
HOOK_FUNCTION(gdi32, D3DKMTOpenAdapterFromHdc, openAdapterFromHdc);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTQueryAdapterInfo, queryAdapterInfo);
|
HOOK_FUNCTION(gdi32, D3DKMTQueryAdapterInfo, queryAdapterInfo);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTPresent, present);
|
HOOK_FUNCTION(gdi32, D3DKMTPresent, present);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTSetQueuedLimit, setQueuedLimit);
|
HOOK_FUNCTION(gdi32, D3DKMTSetQueuedLimit, setQueuedLimit);
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
#pragma once
|
#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"
|
#include "D3dDdi/Log/KernelModeThunksLog.h"
|
||||||
|
|
||||||
static const auto D3DDDI_FLIPINTERVAL_NOOVERRIDE = static_cast<D3DDDI_FLIPINTERVAL_TYPE>(5);
|
static const auto D3DDDI_FLIPINTERVAL_NOOVERRIDE = static_cast<D3DDDI_FLIPINTERVAL_TYPE>(5);
|
||||||
@ -8,6 +16,7 @@ namespace D3dDdi
|
|||||||
{
|
{
|
||||||
namespace KernelModeThunks
|
namespace KernelModeThunks
|
||||||
{
|
{
|
||||||
|
HMONITOR getLastOpenAdapterMonitor();
|
||||||
void installHooks();
|
void installHooks();
|
||||||
bool isPresentReady();
|
bool isPresentReady();
|
||||||
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval);
|
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval);
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
#include "D3dDdi/Log/KernelModeThunksLog.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)
|
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATECONTEXT& data)
|
||||||
{
|
{
|
||||||
return Compat::LogStruct(os)
|
return Compat::LogStruct(os)
|
||||||
@ -73,6 +80,15 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_DESTROYDEVICE& data)
|
|||||||
<< Compat::hex(data.hDevice);
|
<< 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)
|
std::ostream& operator<<(std::ostream& os, const D3DKMT_PRESENT& data)
|
||||||
{
|
{
|
||||||
return Compat::LogStruct(os)
|
return Compat::LogStruct(os)
|
||||||
|
@ -8,12 +8,14 @@
|
|||||||
#include <d3dumddi.h>
|
#include <d3dumddi.h>
|
||||||
#include <../km/d3dkmthk.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_CREATECONTEXT& data);
|
||||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATECONTEXTVIRTUAL& 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_CREATEDCFROMMEMORY& data);
|
||||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATEDEVICE& 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_DESTROYCONTEXT& data);
|
||||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_DESTROYDEVICE& 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_PRESENT& data);
|
||||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETQUEUEDLIMIT& data);
|
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETQUEUEDLIMIT& data);
|
||||||
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER& data);
|
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER& data);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "DDraw/ActivateAppHandler.h"
|
#include "DDraw/ActivateAppHandler.h"
|
||||||
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
#include "Win32/DisplayMode.h"
|
#include "Win32/DisplayMode.h"
|
||||||
#include "Win32/FontSmoothing.h"
|
#include "Win32/FontSmoothing.h"
|
||||||
@ -32,6 +33,7 @@ namespace
|
|||||||
{
|
{
|
||||||
case WM_ACTIVATEAPP:
|
case WM_ACTIVATEAPP:
|
||||||
{
|
{
|
||||||
|
DDraw::RealPrimarySurface::disableUpdates();
|
||||||
isDisplayChangeNotificationEnabled = false;
|
isDisplayChangeNotificationEnabled = false;
|
||||||
if (TRUE == wParam)
|
if (TRUE == wParam)
|
||||||
{
|
{
|
||||||
@ -43,6 +45,7 @@ namespace
|
|||||||
}
|
}
|
||||||
LRESULT result = g_origDdWndProc(hwnd, uMsg, wParam, lParam);
|
LRESULT result = g_origDdWndProc(hwnd, uMsg, wParam, lParam);
|
||||||
isDisplayChangeNotificationEnabled = true;
|
isDisplayChangeNotificationEnabled = true;
|
||||||
|
DDraw::RealPrimarySurface::enableUpdates();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,43 +8,6 @@
|
|||||||
|
|
||||||
namespace
|
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>
|
template <typename TDirectDraw>
|
||||||
HRESULT setDisplayMode(TDirectDraw* This, DWORD width, DWORD height, DWORD bpp)
|
HRESULT setDisplayMode(TDirectDraw* This, DWORD width, DWORD height, DWORD bpp)
|
||||||
{
|
{
|
||||||
@ -100,6 +63,43 @@ namespace DDraw
|
|||||||
return dm;
|
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)
|
void suppressEmulatedDirectDraw(GUID*& guid)
|
||||||
{
|
{
|
||||||
if (reinterpret_cast<GUID*>(DDCREATE_EMULATIONONLY) == guid)
|
if (reinterpret_cast<GUID*>(DDCREATE_EMULATIONONLY) == guid)
|
||||||
|
@ -18,6 +18,7 @@ namespace DDraw
|
|||||||
void* getDdObject(TDirectDraw& dd);
|
void* getDdObject(TDirectDraw& dd);
|
||||||
|
|
||||||
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd);
|
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd);
|
||||||
|
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
|
||||||
void suppressEmulatedDirectDraw(GUID*& guid);
|
void suppressEmulatedDirectDraw(GUID*& guid);
|
||||||
|
|
||||||
template <typename TDirectDraw>
|
template <typename TDirectDraw>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "DDraw/DirectDrawPalette.h"
|
#include "DDraw/DirectDrawPalette.h"
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
|
|
||||||
namespace DDraw
|
namespace DDraw
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ namespace DDraw
|
|||||||
{
|
{
|
||||||
std::memcpy(&PrimarySurface::s_paletteEntries[dwStartingEntry], lpEntries,
|
std::memcpy(&PrimarySurface::s_paletteEntries[dwStartingEntry], lpEntries,
|
||||||
dwCount * sizeof(PALETTEENTRY));
|
dwCount * sizeof(PALETTEENTRY));
|
||||||
RealPrimarySurface::updatePalette(dwStartingEntry, dwCount);
|
RealPrimarySurface::updatePalette();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ namespace DDraw
|
|||||||
SET_COMPAT_METHOD(BltFast);
|
SET_COMPAT_METHOD(BltFast);
|
||||||
SET_COMPAT_METHOD(Flip);
|
SET_COMPAT_METHOD(Flip);
|
||||||
SET_COMPAT_METHOD(GetCaps);
|
SET_COMPAT_METHOD(GetCaps);
|
||||||
|
SET_COMPAT_METHOD(GetDC);
|
||||||
SET_COMPAT_METHOD(GetSurfaceDesc);
|
SET_COMPAT_METHOD(GetSurfaceDesc);
|
||||||
SET_COMPAT_METHOD(IsLost);
|
SET_COMPAT_METHOD(IsLost);
|
||||||
SET_COMPAT_METHOD(Lock);
|
SET_COMPAT_METHOD(Lock);
|
||||||
|
@ -104,6 +104,8 @@ namespace DDraw
|
|||||||
{
|
{
|
||||||
void installHooks()
|
void installHooks()
|
||||||
{
|
{
|
||||||
|
RealPrimarySurface::init();
|
||||||
|
|
||||||
Win32::Registry::unsetValue(
|
Win32::Registry::unsetValue(
|
||||||
HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\DirectDraw", "EmulationOnly");
|
HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\DirectDraw", "EmulationOnly");
|
||||||
Win32::Registry::unsetValue(
|
Win32::Registry::unsetValue(
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CompatPtr.h"
|
#include "Common/CompatPtr.h"
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Time.h"
|
#include "Common/Time.h"
|
||||||
#include "Config/Config.h"
|
#include "Config/Config.h"
|
||||||
|
#include "D3dDdi/Device.h"
|
||||||
#include "D3dDdi/KernelModeThunks.h"
|
#include "D3dDdi/KernelModeThunks.h"
|
||||||
#include "DDraw/DirectDraw.h"
|
#include "DDraw/DirectDraw.h"
|
||||||
#include "DDraw/DirectDrawSurface.h"
|
#include "DDraw/DirectDrawSurface.h"
|
||||||
@ -13,11 +15,26 @@
|
|||||||
#include "DDraw/ScopedThreadLock.h"
|
#include "DDraw/ScopedThreadLock.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
#include "DDraw/Types.h"
|
#include "DDraw/Types.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/VirtualScreen.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
#include "Win32/DisplayMode.h"
|
#include "Win32/DisplayMode.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
struct BltToWindowViaGdiArgs
|
||||||
|
{
|
||||||
|
std::unique_ptr<HDC__, void(*)(HDC)> virtualScreenDc;
|
||||||
|
Gdi::Region* primaryRegion;
|
||||||
|
|
||||||
|
BltToWindowViaGdiArgs()
|
||||||
|
: virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc)
|
||||||
|
, primaryRegion(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void onRelease();
|
void onRelease();
|
||||||
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
||||||
|
|
||||||
@ -42,7 +59,8 @@ namespace
|
|||||||
|
|
||||||
BOOL CALLBACK addVisibleLayeredWindowToVector(HWND hwnd, LPARAM lParam)
|
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);
|
auto& visibleLayeredWindows = *reinterpret_cast<std::vector<HWND>*>(lParam);
|
||||||
visibleLayeredWindows.push_back(hwnd);
|
visibleLayeredWindows.push_back(hwnd);
|
||||||
@ -52,7 +70,7 @@ namespace
|
|||||||
|
|
||||||
BOOL CALLBACK bltToWindow(HWND hwnd, LPARAM lParam)
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -63,6 +81,54 @@ namespace
|
|||||||
return TRUE;
|
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()
|
void bltVisibleLayeredWindowsToBackBuffer()
|
||||||
{
|
{
|
||||||
std::vector<HWND> visibleLayeredWindows;
|
std::vector<HWND> visibleLayeredWindows;
|
||||||
@ -94,7 +160,6 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_backBuffer->ReleaseDC(g_backBuffer, backBufferDc);
|
g_backBuffer->ReleaseDC(g_backBuffer, backBufferDc);
|
||||||
DDraw::RealPrimarySurface::update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT bltToPrimaryChain(CompatRef<IDirectDrawSurface7> src)
|
HRESULT bltToPrimaryChain(CompatRef<IDirectDrawSurface7> src)
|
||||||
@ -112,15 +177,31 @@ namespace
|
|||||||
{
|
{
|
||||||
Compat::LogEnter("RealPrimarySurface::compatBlt");
|
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());
|
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||||
|
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(primary.get()));
|
||||||
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
|
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||||
{
|
{
|
||||||
HDC paletteConverterDc = nullptr;
|
HDC paletteConverterDc = nullptr;
|
||||||
g_paletteConverter->GetDC(g_paletteConverter, &paletteConverterDc);
|
g_paletteConverter->GetDC(g_paletteConverter, &paletteConverterDc);
|
||||||
HDC primaryDc = nullptr;
|
HDC primaryDc = nullptr;
|
||||||
|
D3dDdi::Device::setReadOnlyGdiLock(true);
|
||||||
primary->GetDC(primary, &primaryDc);
|
primary->GetDC(primary, &primaryDc);
|
||||||
|
D3dDdi::Device::setReadOnlyGdiLock(false);
|
||||||
|
|
||||||
if (paletteConverterDc && primaryDc)
|
if (paletteConverterDc && primaryDc)
|
||||||
{
|
{
|
||||||
@ -203,7 +284,6 @@ namespace
|
|||||||
surface->SetClipper(surface, g_clipper);
|
surface->SetClipper(surface, g_clipper);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec;
|
|
||||||
g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout;
|
g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout;
|
||||||
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
||||||
|
|
||||||
@ -216,17 +296,6 @@ namespace
|
|||||||
}
|
}
|
||||||
g_qpcUpdateInterval = Time::g_qpcFrequency / dm.dwRefreshRate;
|
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,
|
surface->SetPrivateData(surface, IID_IReleaseNotifier,
|
||||||
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||||
|
|
||||||
@ -265,6 +334,7 @@ namespace
|
|||||||
g_clipper.release();
|
g_clipper.release();
|
||||||
g_isFullScreen = false;
|
g_isFullScreen = false;
|
||||||
g_paletteConverter.release();
|
g_paletteConverter.release();
|
||||||
|
g_qpcUpdateInterval = Time::g_qpcFrequency / 60;
|
||||||
|
|
||||||
ZeroMemory(&g_surfaceDesc, sizeof(g_surfaceDesc));
|
ZeroMemory(&g_surfaceDesc, sizeof(g_surfaceDesc));
|
||||||
|
|
||||||
@ -275,6 +345,7 @@ namespace
|
|||||||
{
|
{
|
||||||
ResetEvent(g_updateEvent);
|
ResetEvent(g_updateEvent);
|
||||||
|
|
||||||
|
Gdi::VirtualScreen::update();
|
||||||
if (compatBlt() && g_isFullScreen)
|
if (compatBlt() && g_isFullScreen)
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::overrideFlipInterval(
|
D3dDdi::KernelModeThunks::overrideFlipInterval(
|
||||||
@ -349,7 +420,7 @@ namespace DDraw
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return init(dd, surface);
|
return ::init(dd, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
|
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
|
||||||
@ -408,6 +479,17 @@ namespace DDraw
|
|||||||
return g_frontBuffer;
|
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()
|
bool RealPrimarySurface::isFullScreen()
|
||||||
{
|
{
|
||||||
return g_isFullScreen;
|
return g_isFullScreen;
|
||||||
@ -465,7 +547,7 @@ namespace DDraw
|
|||||||
g_frontBuffer->SetPalette(g_frontBuffer, PrimarySurface::s_palette);
|
g_frontBuffer->SetPalette(g_frontBuffer, PrimarySurface::s_palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePalette(0, 256);
|
updatePalette();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::update()
|
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)
|
if (PrimarySurface::s_palette)
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
|
@ -20,6 +20,7 @@ namespace DDraw
|
|||||||
static HRESULT flip(DWORD flags);
|
static HRESULT flip(DWORD flags);
|
||||||
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
||||||
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
||||||
|
static void init();
|
||||||
static bool isFullScreen();
|
static bool isFullScreen();
|
||||||
static bool isLost();
|
static bool isLost();
|
||||||
static void release();
|
static void release();
|
||||||
@ -28,6 +29,6 @@ namespace DDraw
|
|||||||
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
|
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
|
||||||
static void setPalette();
|
static void setPalette();
|
||||||
static void update();
|
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/CompatPtr.h"
|
||||||
|
#include "Common/CompatRef.h"
|
||||||
#include "Config/Config.h"
|
#include "Config/Config.h"
|
||||||
|
#include "D3dDdi/Device.h"
|
||||||
|
#include "D3dDdi/KernelModeThunks.h"
|
||||||
#include "DDraw/DirectDraw.h"
|
#include "DDraw/DirectDraw.h"
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
@ -8,11 +16,30 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
DDSURFACEDESC2 g_primarySurfaceDesc = {};
|
DDSURFACEDESC2 g_primarySurfaceDesc = {};
|
||||||
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface = nullptr;
|
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
|
||||||
HANDLE g_gdiResourceHandle = nullptr;
|
HANDLE g_gdiResourceHandle = nullptr;
|
||||||
DWORD g_origCaps = 0;
|
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];
|
return reinterpret_cast<HANDLE**>(&surface)[1][2];
|
||||||
}
|
}
|
||||||
@ -32,6 +59,7 @@ namespace DDraw
|
|||||||
g_gdiResourceHandle = nullptr;
|
g_gdiResourceHandle = nullptr;
|
||||||
g_primarySurface = nullptr;
|
g_primarySurface = nullptr;
|
||||||
g_origCaps = 0;
|
g_origCaps = 0;
|
||||||
|
g_monitorRect = {};
|
||||||
s_palette = nullptr;
|
s_palette = nullptr;
|
||||||
s_surfaceBuffers.clear();
|
s_surfaceBuffers.clear();
|
||||||
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
|
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
|
||||||
@ -75,6 +103,7 @@ namespace DDraw
|
|||||||
|
|
||||||
g_primarySurface = surface7;
|
g_primarySurface = surface7;
|
||||||
g_origCaps = origCaps;
|
g_origCaps = origCaps;
|
||||||
|
g_monitorRect = getDdMonitorRect(*CompatPtr<IDirectDraw7>::from(&dd));
|
||||||
|
|
||||||
ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc));
|
ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc));
|
||||||
g_primarySurfaceDesc.dwSize = sizeof(g_primarySurfaceDesc);
|
g_primarySurfaceDesc.dwSize = sizeof(g_primarySurfaceDesc);
|
||||||
@ -86,6 +115,8 @@ namespace DDraw
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_gdiResourceHandle = getResourceHandle(*surface7);
|
g_gdiResourceHandle = getResourceHandle(*surface7);
|
||||||
|
D3dDdi::Device::setGdiResourceHandle(*reinterpret_cast<HANDLE*>(g_gdiResourceHandle));
|
||||||
|
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +166,7 @@ namespace DDraw
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (getResourceHandle(*surface) == g_gdiResourceHandle)
|
if (isGdiSurface(surface.get()))
|
||||||
{
|
{
|
||||||
return CompatPtr<IDirectDrawSurface7>::from(surface.get());
|
return CompatPtr<IDirectDrawSurface7>::from(surface.get());
|
||||||
}
|
}
|
||||||
@ -150,6 +181,11 @@ namespace DDraw
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RECT PrimarySurface::getMonitorRect()
|
||||||
|
{
|
||||||
|
return g_monitorRect;
|
||||||
|
}
|
||||||
|
|
||||||
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
|
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
|
||||||
{
|
{
|
||||||
return g_primarySurface;
|
return g_primarySurface;
|
||||||
@ -160,6 +196,27 @@ namespace DDraw
|
|||||||
return g_origCaps;
|
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)
|
void PrimarySurface::resizeBuffers(CompatRef<IDirectDrawSurface7> surface)
|
||||||
{
|
{
|
||||||
DDSCAPS2 flipCaps = {};
|
DDSCAPS2 flipCaps = {};
|
||||||
|
@ -19,10 +19,13 @@ namespace DDraw
|
|||||||
static HRESULT flipToGdiSurface();
|
static HRESULT flipToGdiSurface();
|
||||||
static const DDSURFACEDESC2& getDesc();
|
static const DDSURFACEDESC2& getDesc();
|
||||||
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
|
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
|
||||||
|
static RECT getMonitorRect();
|
||||||
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
|
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
|
||||||
static DWORD getOrigCaps();
|
static DWORD getOrigCaps();
|
||||||
|
static void onRestore();
|
||||||
|
|
||||||
void updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride);
|
template <typename TSurface>
|
||||||
|
static bool isGdiSurface(TSurface* surface);
|
||||||
|
|
||||||
static CompatWeakPtr<IDirectDrawPalette> s_palette;
|
static CompatWeakPtr<IDirectDrawPalette> s_palette;
|
||||||
static PALETTEENTRY s_paletteEntries[256];
|
static PALETTEENTRY s_paletteEntries[256];
|
||||||
|
@ -57,22 +57,6 @@ namespace DDraw
|
|||||||
HRESULT result = m_impl.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
HRESULT result = m_impl.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||||
if (SUCCEEDED(result))
|
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();
|
RealPrimarySurface::update();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -195,6 +179,7 @@ namespace DDraw
|
|||||||
result = m_impl.Restore(This);
|
result = m_impl.Restore(This);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
|
PrimarySurface::onRestore();
|
||||||
Gdi::redraw(nullptr);
|
Gdi::redraw(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include "Common/CompatRef.h"
|
#include "Common/CompatRef.h"
|
||||||
#include "DDraw/Repository.h"
|
#include "DDraw/Repository.h"
|
||||||
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
#include "DDraw/Surfaces/Surface.h"
|
#include "DDraw/Surfaces/Surface.h"
|
||||||
#include "DDraw/Surfaces/SurfaceImpl.h"
|
#include "DDraw/Surfaces/SurfaceImpl.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -159,6 +161,8 @@ namespace DDraw
|
|||||||
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
|
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
|
||||||
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
|
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);
|
HRESULT result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||||
if (DDERR_UNSUPPORTED == result || DDERR_GENERIC == result)
|
if (DDERR_UNSUPPORTED == result || DDERR_GENERIC == result)
|
||||||
{
|
{
|
||||||
@ -178,6 +182,8 @@ namespace DDraw
|
|||||||
HRESULT SurfaceImpl<TSurface>::BltFast(
|
HRESULT SurfaceImpl<TSurface>::BltFast(
|
||||||
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
|
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);
|
HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||||
if (DDERR_UNSUPPORTED == result || DDERR_GENERIC == result)
|
if (DDERR_UNSUPPORTED == result || DDERR_GENERIC == result)
|
||||||
{
|
{
|
||||||
@ -221,6 +227,13 @@ namespace DDraw
|
|||||||
return s_origVtable.GetCaps(This, lpDDSCaps);
|
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>
|
template <typename TSurface>
|
||||||
HRESULT SurfaceImpl2<TSurface>::GetDDInterface(TSurface* /*This*/, LPVOID* lplpDD)
|
HRESULT SurfaceImpl2<TSurface>::GetDDInterface(TSurface* /*This*/, LPVOID* lplpDD)
|
||||||
{
|
{
|
||||||
@ -250,6 +263,8 @@ namespace DDraw
|
|||||||
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
DWORD dwFlags, HANDLE hEvent)
|
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);
|
HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||||
if (DDERR_SURFACELOST == result)
|
if (DDERR_SURFACELOST == result)
|
||||||
{
|
{
|
||||||
@ -269,6 +284,7 @@ namespace DDraw
|
|||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT SurfaceImpl<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
|
HRESULT SurfaceImpl<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
|
||||||
{
|
{
|
||||||
|
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
|
||||||
return s_origVtable.ReleaseDC(This, hDC);
|
return s_origVtable.ReleaseDC(This, hDC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +303,7 @@ namespace DDraw
|
|||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT SurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
|
HRESULT SurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
|
||||||
{
|
{
|
||||||
|
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(This));
|
||||||
return s_origVtable.Unlock(This, lpRect);
|
return s_origVtable.Unlock(This, lpRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ namespace DDraw
|
|||||||
TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans);
|
TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans);
|
||||||
virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags);
|
virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags);
|
||||||
virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps);
|
virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps);
|
||||||
|
virtual HRESULT GetDC(TSurface* This, HDC* lphDC);
|
||||||
virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc);
|
virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc);
|
||||||
virtual HRESULT IsLost(TSurface* This);
|
virtual HRESULT IsLost(TSurface* This);
|
||||||
virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
|
@ -215,6 +215,7 @@
|
|||||||
<ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h" />
|
<ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h" />
|
||||||
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" />
|
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" />
|
||||||
<ClInclude Include="Dll\Procs.h" />
|
<ClInclude Include="Dll\Procs.h" />
|
||||||
|
<ClInclude Include="Gdi\AccessGuard.h" />
|
||||||
<ClInclude Include="Gdi\Gdi.h" />
|
<ClInclude Include="Gdi\Gdi.h" />
|
||||||
<ClInclude Include="Gdi\Caret.h" />
|
<ClInclude Include="Gdi\Caret.h" />
|
||||||
<ClInclude Include="Gdi\Dc.h" />
|
<ClInclude Include="Gdi\Dc.h" />
|
||||||
@ -225,6 +226,7 @@
|
|||||||
<ClInclude Include="Gdi\ScrollBar.h" />
|
<ClInclude Include="Gdi\ScrollBar.h" />
|
||||||
<ClInclude Include="Gdi\ScrollFunctions.h" />
|
<ClInclude Include="Gdi\ScrollFunctions.h" />
|
||||||
<ClInclude Include="Gdi\TitleBar.h" />
|
<ClInclude Include="Gdi\TitleBar.h" />
|
||||||
|
<ClInclude Include="Gdi\VirtualScreen.h" />
|
||||||
<ClInclude Include="Gdi\Window.h" />
|
<ClInclude Include="Gdi\Window.h" />
|
||||||
<ClInclude Include="Gdi\WinProc.h" />
|
<ClInclude Include="Gdi\WinProc.h" />
|
||||||
<ClInclude Include="Win32\DisplayMode.h" />
|
<ClInclude Include="Win32\DisplayMode.h" />
|
||||||
@ -274,6 +276,7 @@
|
|||||||
<ClCompile Include="Dll\Procs.cpp" />
|
<ClCompile Include="Dll\Procs.cpp" />
|
||||||
<ClCompile Include="Dll\DllMain.cpp" />
|
<ClCompile Include="Dll\DllMain.cpp" />
|
||||||
<ClCompile Include="Dll\UnmodifiedProcs.cpp" />
|
<ClCompile Include="Dll\UnmodifiedProcs.cpp" />
|
||||||
|
<ClCompile Include="Gdi\AccessGuard.cpp" />
|
||||||
<ClCompile Include="Gdi\Gdi.cpp" />
|
<ClCompile Include="Gdi\Gdi.cpp" />
|
||||||
<ClCompile Include="Gdi\Caret.cpp" />
|
<ClCompile Include="Gdi\Caret.cpp" />
|
||||||
<ClCompile Include="Gdi\Dc.cpp" />
|
<ClCompile Include="Gdi\Dc.cpp" />
|
||||||
@ -284,6 +287,7 @@
|
|||||||
<ClCompile Include="Gdi\ScrollBar.cpp" />
|
<ClCompile Include="Gdi\ScrollBar.cpp" />
|
||||||
<ClCompile Include="Gdi\ScrollFunctions.cpp" />
|
<ClCompile Include="Gdi\ScrollFunctions.cpp" />
|
||||||
<ClCompile Include="Gdi\TitleBar.cpp" />
|
<ClCompile Include="Gdi\TitleBar.cpp" />
|
||||||
|
<ClCompile Include="Gdi\VirtualScreen.cpp" />
|
||||||
<ClCompile Include="Gdi\Window.cpp" />
|
<ClCompile Include="Gdi\Window.cpp" />
|
||||||
<ClCompile Include="Gdi\WinProc.cpp" />
|
<ClCompile Include="Gdi\WinProc.cpp" />
|
||||||
<ClCompile Include="Win32\DisplayMode.cpp" />
|
<ClCompile Include="Win32\DisplayMode.cpp" />
|
||||||
|
@ -321,6 +321,12 @@
|
|||||||
<ClInclude Include="Gdi\Region.h">
|
<ClInclude Include="Gdi\Region.h">
|
||||||
<Filter>Header Files\Gdi</Filter>
|
<Filter>Header Files\Gdi</Filter>
|
||||||
</ClInclude>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Gdi\Gdi.cpp">
|
<ClCompile Include="Gdi\Gdi.cpp">
|
||||||
@ -494,6 +500,12 @@
|
|||||||
<ClCompile Include="Gdi\Region.cpp">
|
<ClCompile Include="Gdi\Region.cpp">
|
||||||
<Filter>Source Files\Gdi</Filter>
|
<Filter>Source Files\Gdi</Filter>
|
||||||
</ClCompile>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Dll\DDrawCompat.def">
|
<None Include="Dll\DDrawCompat.def">
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "Direct3d/Hooks.h"
|
#include "Direct3d/Hooks.h"
|
||||||
#include "Dll/Procs.h"
|
#include "Dll/Procs.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/VirtualScreen.h"
|
||||||
#include "Win32/DisplayMode.h"
|
#include "Win32/DisplayMode.h"
|
||||||
#include "Win32/FontSmoothing.h"
|
#include "Win32/FontSmoothing.h"
|
||||||
#include "Win32/MsgHooks.h"
|
#include "Win32/MsgHooks.h"
|
||||||
@ -39,14 +40,15 @@ namespace
|
|||||||
Win32::Registry::installHooks();
|
Win32::Registry::installHooks();
|
||||||
Compat::Log() << "Installing Direct3D driver hooks";
|
Compat::Log() << "Installing Direct3D driver hooks";
|
||||||
D3dDdi::installHooks();
|
D3dDdi::installHooks();
|
||||||
|
Compat::Log() << "Installing display mode hooks";
|
||||||
|
Win32::DisplayMode::installHooks(g_origDDrawModule);
|
||||||
|
Gdi::VirtualScreen::init();
|
||||||
Compat::Log() << "Installing DirectDraw hooks";
|
Compat::Log() << "Installing DirectDraw hooks";
|
||||||
DDraw::installHooks();
|
DDraw::installHooks();
|
||||||
Compat::Log() << "Installing Direct3D hooks";
|
Compat::Log() << "Installing Direct3D hooks";
|
||||||
Direct3d::installHooks();
|
Direct3d::installHooks();
|
||||||
Compat::Log() << "Installing GDI hooks";
|
Compat::Log() << "Installing GDI hooks";
|
||||||
Gdi::installHooks();
|
Gdi::installHooks();
|
||||||
Compat::Log() << "Installing display mode hooks";
|
|
||||||
Win32::DisplayMode::installHooks(g_origDDrawModule);
|
|
||||||
Compat::Log() << "Finished installing hooks";
|
Compat::Log() << "Finished installing hooks";
|
||||||
isAlreadyInstalled = true;
|
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/Hook.h"
|
||||||
#include "Common/ScopedCriticalSection.h"
|
#include "Common/ScopedCriticalSection.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
#include "Gdi/Caret.h"
|
#include "Gdi/Caret.h"
|
||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
@ -103,11 +104,11 @@ namespace
|
|||||||
return;
|
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(g_caret);
|
||||||
drawCaret(newCaret);
|
drawCaret(newCaret);
|
||||||
Gdi::endGdiRendering();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_caret = newCaret;
|
g_caret = newCaret;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
@ -7,24 +8,27 @@
|
|||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/DcCache.h"
|
#include "Gdi/DcCache.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/VirtualScreen.h"
|
||||||
#include "Gdi/Window.h"
|
#include "Gdi/Window.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using Gdi::DcCache::CachedDc;
|
struct CompatDc
|
||||||
|
|
||||||
struct CompatDc : CachedDc
|
|
||||||
{
|
{
|
||||||
CompatDc(const CachedDc& cachedDc = {}) : CachedDc(cachedDc) {}
|
HDC dc;
|
||||||
DWORD refCount;
|
DWORD refCount;
|
||||||
HDC origDc;
|
HDC origDc;
|
||||||
int savedState;
|
int savedState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::unique_ptr<HDC__, void(*)(HDC)> OrigDc;
|
||||||
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
|
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_FONT));
|
||||||
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
|
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
|
||||||
@ -76,6 +80,15 @@ namespace
|
|||||||
MoveToEx(compatDc.dc, currentPos.x, currentPos.y, nullptr);
|
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)
|
void setClippingRegion(HDC compatDc, HDC origDc, HWND hwnd, const POINT& origin)
|
||||||
{
|
{
|
||||||
if (hwnd)
|
if (hwnd)
|
||||||
@ -100,12 +113,16 @@ namespace
|
|||||||
|
|
||||||
void updateWindow(HWND wnd)
|
void updateWindow(HWND wnd)
|
||||||
{
|
{
|
||||||
|
auto window = Gdi::Window::get(wnd);
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RECT windowRect = {};
|
RECT windowRect = {};
|
||||||
GetWindowRect(wnd, &windowRect);
|
GetWindowRect(wnd, &windowRect);
|
||||||
|
|
||||||
auto& window = Gdi::Window::get(wnd);
|
RECT cachedWindowRect = window->getWindowRect();
|
||||||
RECT cachedWindowRect = window.getWindowRect();
|
|
||||||
|
|
||||||
if (!EqualRect(&windowRect, &cachedWindowRect))
|
if (!EqualRect(&windowRect, &cachedWindowRect))
|
||||||
{
|
{
|
||||||
Gdi::Window::updateAll();
|
Gdi::Window::updateAll();
|
||||||
@ -124,8 +141,7 @@ namespace Gdi
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Compat::ScopedCriticalSection gdiLock(Gdi::g_gdiCriticalSection);
|
Compat::ScopedCriticalSection lock(g_cs);
|
||||||
|
|
||||||
auto it = g_origDcToCompatDc.find(origDc);
|
auto it = g_origDcToCompatDc.find(origDc);
|
||||||
if (it != g_origDcToCompatDc.end())
|
if (it != g_origDcToCompatDc.end())
|
||||||
{
|
{
|
||||||
@ -140,7 +156,8 @@ namespace Gdi
|
|||||||
updateWindow(rootWnd);
|
updateWindow(rootWnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompatDc compatDc(Gdi::DcCache::getDc());
|
CompatDc compatDc;
|
||||||
|
compatDc.dc = Gdi::DcCache::getDc();
|
||||||
if (!compatDc.dc)
|
if (!compatDc.dc)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -148,6 +165,9 @@ namespace Gdi
|
|||||||
|
|
||||||
POINT origin = {};
|
POINT origin = {};
|
||||||
GetDCOrgEx(origDc, &origin);
|
GetDCOrgEx(origDc, &origin);
|
||||||
|
RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds();
|
||||||
|
origin.x -= virtualScreenBounds.left;
|
||||||
|
origin.y -= virtualScreenBounds.top;
|
||||||
|
|
||||||
compatDc.savedState = SaveDC(compatDc.dc);
|
compatDc.savedState = SaveDC(compatDc.dc);
|
||||||
copyDcAttributes(compatDc, origDc, origin);
|
copyDcAttributes(compatDc, origDc, origin);
|
||||||
@ -156,21 +176,27 @@ namespace Gdi
|
|||||||
compatDc.refCount = 1;
|
compatDc.refCount = 1;
|
||||||
compatDc.origDc = origDc;
|
compatDc.origDc = origDc;
|
||||||
g_origDcToCompatDc.insert(CompatDcMap::value_type(origDc, compatDc));
|
g_origDcToCompatDc.insert(CompatDcMap::value_type(origDc, compatDc));
|
||||||
|
g_threadDcs.emplace_back(origDc, &deleteDc);
|
||||||
|
|
||||||
return compatDc.dc;
|
return compatDc.dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
HDC getOrigDc(HDC dc)
|
HDC getOrigDc(HDC dc)
|
||||||
{
|
{
|
||||||
|
Compat::ScopedCriticalSection lock(g_cs);
|
||||||
const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
|
const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
|
||||||
[dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; });
|
[dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; });
|
||||||
return it != g_origDcToCompatDc.end() ? it->first : dc;
|
return it != g_origDcToCompatDc.end() ? it->first : dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
InitializeCriticalSection(&g_cs);
|
||||||
|
}
|
||||||
|
|
||||||
void releaseDc(HDC origDc)
|
void releaseDc(HDC origDc)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection gdiLock(Gdi::g_gdiCriticalSection);
|
Compat::ScopedCriticalSection lock(g_cs);
|
||||||
|
|
||||||
auto it = g_origDcToCompatDc.find(origDc);
|
auto it = g_origDcToCompatDc.find(origDc);
|
||||||
if (it == g_origDcToCompatDc.end())
|
if (it == g_origDcToCompatDc.end())
|
||||||
{
|
{
|
||||||
@ -181,8 +207,13 @@ namespace Gdi
|
|||||||
--compatDc.refCount;
|
--compatDc.refCount;
|
||||||
if (0 == 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);
|
RestoreDC(compatDc.dc, compatDc.savedState);
|
||||||
Gdi::DcCache::releaseDc(compatDc);
|
Gdi::DcCache::releaseDc(compatDc.dc);
|
||||||
g_origDcToCompatDc.erase(origDc);
|
g_origDcToCompatDc.erase(origDc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
HDC getDc(HDC origDc);
|
HDC getDc(HDC origDc);
|
||||||
HDC getOrigDc(HDC dc);
|
HDC getOrigDc(HDC dc);
|
||||||
|
void init();
|
||||||
void releaseDc(HDC origDc);
|
void releaseDc(HDC origDc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,227 +1,45 @@
|
|||||||
#include <cstring>
|
#include <memory>
|
||||||
#include <vector>
|
#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/DcCache.h"
|
||||||
|
#include "Gdi/VirtualScreen.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using Gdi::DcCache::CachedDc;
|
typedef std::unique_ptr<HDC__, void(*)(HDC)> CachedDc;
|
||||||
|
|
||||||
std::vector<CachedDc> g_cache;
|
|
||||||
DWORD g_cacheSize = 0;
|
|
||||||
DWORD g_cacheId = 0;
|
|
||||||
DWORD g_maxUsedCacheSize = 0;
|
|
||||||
DWORD g_ddLockThreadId = 0;
|
|
||||||
|
|
||||||
CompatWeakPtr<IDirectDrawPalette> g_palette;
|
thread_local std::vector<CachedDc> g_cache;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
{
|
{
|
||||||
namespace DcCache
|
namespace DcCache
|
||||||
{
|
{
|
||||||
void clear()
|
void deleteDc(HDC cachedDc)
|
||||||
{
|
{
|
||||||
for (auto& cachedDc : g_cache)
|
Gdi::VirtualScreen::deleteDc(cachedDc);
|
||||||
{
|
|
||||||
releaseCachedDc(cachedDc);
|
|
||||||
}
|
|
||||||
g_cache.clear();
|
|
||||||
g_cacheSize = 0;
|
|
||||||
++g_cacheId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedDc getDc()
|
HDC getDc()
|
||||||
{
|
{
|
||||||
CachedDc cachedDc = {};
|
HDC cachedDc = nullptr;
|
||||||
if (!g_surfaceMemory)
|
|
||||||
{
|
|
||||||
return cachedDc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_cache.empty())
|
if (g_cache.empty())
|
||||||
{
|
{
|
||||||
extendCache();
|
cachedDc = Gdi::VirtualScreen::createDc();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (!g_cache.empty())
|
|
||||||
{
|
{
|
||||||
cachedDc = g_cache.back();
|
cachedDc = g_cache.back().release();
|
||||||
g_cache.pop_back();
|
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;
|
return cachedDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool init()
|
void releaseDc(HDC cachedDc)
|
||||||
{
|
{
|
||||||
auto dd(DDraw::Repository::getDirectDraw());
|
g_cache.emplace_back(CachedDc(cachedDc, &deleteDc));
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define CINTERFACE
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
#include <ddraw.h>
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#include "Common/CompatWeakPtr.h"
|
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
{
|
{
|
||||||
namespace DcCache
|
namespace DcCache
|
||||||
{
|
{
|
||||||
struct CachedDc
|
void deleteDc(HDC cachedDc);
|
||||||
{
|
HDC getDc();
|
||||||
CompatWeakPtr<IDirectDrawSurface7> surface;
|
void releaseDc(HDC cachedDc);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/DcFunctions.h"
|
#include "Gdi/DcFunctions.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/VirtualScreen.h"
|
||||||
#include "Win32/DisplayMode.h"
|
#include "Win32/DisplayMode.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -80,21 +82,18 @@ namespace
|
|||||||
Compat::LogEnter(g_funcNames[origFunc], params...);
|
Compat::LogEnter(g_funcNames[origFunc], params...);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!hasDisplayDcArg(params...) ||
|
Result result = 0;
|
||||||
!Gdi::beginGdiRendering(getDdLockFlags<OrigFuncPtr, origFunc>(params...)))
|
if (hasDisplayDcArg(params...))
|
||||||
{
|
{
|
||||||
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
const bool isReadOnlyAccess = getDdLockFlags<OrigFuncPtr, origFunc>(params...) & DDLOCK_READONLY;
|
||||||
|
Gdi::GdiAccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
|
||||||
#ifdef _DEBUG
|
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
||||||
Compat::LogLeave(g_funcNames[origFunc], params...) << result;
|
releaseDc(params...);
|
||||||
#endif
|
}
|
||||||
|
else
|
||||||
return result;
|
{
|
||||||
|
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
|
||||||
releaseDc(params...);
|
|
||||||
Gdi::endGdiRendering();
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Compat::LogLeave(g_funcNames[origFunc], params...) << result;
|
Compat::LogLeave(g_funcNames[origFunc], params...) << result;
|
||||||
@ -254,6 +253,13 @@ namespace
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT WINAPI realizePalette(HDC hdc)
|
||||||
|
{
|
||||||
|
UINT result = CALL_ORIG_FUNC(RealizePalette)(hdc);
|
||||||
|
Gdi::VirtualScreen::updatePalette();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
HWND WINAPI windowFromDc(HDC dc)
|
HWND WINAPI windowFromDc(HDC dc)
|
||||||
{
|
{
|
||||||
return CALL_ORIG_FUNC(WindowFromDC)(Gdi::Dc::getOrigDc(dc));
|
return CALL_ORIG_FUNC(WindowFromDC)(Gdi::Dc::getOrigDc(dc));
|
||||||
@ -311,6 +317,9 @@ namespace Gdi
|
|||||||
// Clipping functions
|
// Clipping functions
|
||||||
HOOK_FUNCTION(gdi32, GetRandomRgn, getRandomRgn);
|
HOOK_FUNCTION(gdi32, GetRandomRgn, getRandomRgn);
|
||||||
|
|
||||||
|
// Color functions
|
||||||
|
HOOK_SHIM_FUNCTION(RealizePalette, realizePalette);
|
||||||
|
|
||||||
// Device context functions
|
// Device context functions
|
||||||
HOOK_GDI_DC_FUNCTION(gdi32, DrawEscape);
|
HOOK_GDI_DC_FUNCTION(gdi32, DrawEscape);
|
||||||
HOOK_FUNCTION(user32, WindowFromDC, windowFromDc);
|
HOOK_FUNCTION(user32, WindowFromDC, windowFromDc);
|
||||||
|
@ -1,152 +1,37 @@
|
|||||||
#include "Common/ScopedCriticalSection.h"
|
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
#include "Dll/Procs.h"
|
|
||||||
#include "Gdi/Caret.h"
|
#include "Gdi/Caret.h"
|
||||||
#include "Gdi/DcCache.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/DcFunctions.h"
|
#include "Gdi/DcFunctions.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
#include "Gdi/PaintHandlers.h"
|
#include "Gdi/PaintHandlers.h"
|
||||||
#include "Gdi/ScrollFunctions.h"
|
#include "Gdi/ScrollFunctions.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
#include "Gdi/WinProc.h"
|
#include "Gdi/WinProc.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
DWORD g_gdiThreadId = 0;
|
DWORD g_gdiThreadId = 0;
|
||||||
DWORD g_renderingRefCount = 0;
|
HDC g_screenDc = nullptr;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL CALLBACK redrawWindowCallback(HWND hwnd, LPARAM lParam)
|
BOOL CALLBACK redrawWindowCallback(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
Gdi::redrawWindow(hwnd, reinterpret_cast<HRGN>(lParam));
|
Gdi::redrawWindow(hwnd, reinterpret_cast<HRGN>(lParam));
|
||||||
return TRUE;
|
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
|
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()
|
DWORD getGdiThreadId()
|
||||||
{
|
{
|
||||||
return g_gdiThreadId;
|
return g_gdiThreadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HDC getScreenDc()
|
||||||
|
{
|
||||||
|
return g_screenDc;
|
||||||
|
}
|
||||||
|
|
||||||
HRGN getVisibleWindowRgn(HWND hwnd)
|
HRGN getVisibleWindowRgn(HWND hwnd)
|
||||||
{
|
{
|
||||||
return DcFunctions::getVisibleWindowRgn(hwnd);
|
return DcFunctions::getVisibleWindowRgn(hwnd);
|
||||||
@ -163,39 +48,24 @@ namespace Gdi
|
|||||||
void installHooks()
|
void installHooks()
|
||||||
{
|
{
|
||||||
g_gdiThreadId = GetCurrentThreadId();
|
g_gdiThreadId = GetCurrentThreadId();
|
||||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
g_screenDc = GetDC(nullptr);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gdi::DcFunctions::installHooks();
|
Gdi::Dc::init();
|
||||||
Gdi::PaintHandlers::installHooks();
|
Gdi::DcFunctions::installHooks();
|
||||||
Gdi::ScrollFunctions::installHooks();
|
Gdi::PaintHandlers::installHooks();
|
||||||
Gdi::WinProc::installHooks();
|
Gdi::ScrollFunctions::installHooks();
|
||||||
Gdi::Caret::installHooks();
|
Gdi::WinProc::installHooks();
|
||||||
}
|
Gdi::Caret::installHooks();
|
||||||
}
|
|
||||||
|
|
||||||
bool isTopLevelWindow(HWND hwnd)
|
|
||||||
{
|
|
||||||
return !(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) ||
|
|
||||||
GetParent(hwnd) == GetDesktopWindow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void redraw(HRGN rgn)
|
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)
|
void redrawWindow(HWND hwnd, HRGN rgn)
|
||||||
{
|
{
|
||||||
if (!IsWindowVisible(hwnd) || IsIconic(hwnd))
|
if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || Window::isPresentationWindow(hwnd))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -228,14 +98,7 @@ namespace Gdi
|
|||||||
Gdi::Caret::uninstallHooks();
|
Gdi::Caret::uninstallHooks();
|
||||||
Gdi::WinProc::uninstallHooks();
|
Gdi::WinProc::uninstallHooks();
|
||||||
Gdi::PaintHandlers::uninstallHooks();
|
Gdi::PaintHandlers::uninstallHooks();
|
||||||
}
|
ReleaseDC(nullptr, g_screenDc);
|
||||||
|
|
||||||
void updatePalette(DWORD startingEntry, DWORD count)
|
|
||||||
{
|
|
||||||
if (DDraw::PrimarySurface::s_palette)
|
|
||||||
{
|
|
||||||
Gdi::DcCache::updatePalette(startingEntry, count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
|
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
|
||||||
|
@ -8,20 +8,14 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
typedef void(*WindowPosChangeNotifyFunc)();
|
typedef void(*WindowPosChangeNotifyFunc)();
|
||||||
|
|
||||||
bool beginGdiRendering(DWORD lockFlags = 0);
|
|
||||||
void endGdiRendering();
|
|
||||||
|
|
||||||
DWORD getGdiThreadId();
|
DWORD getGdiThreadId();
|
||||||
|
HDC getScreenDc();
|
||||||
HRGN getVisibleWindowRgn(HWND hwnd);
|
HRGN getVisibleWindowRgn(HWND hwnd);
|
||||||
void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc);
|
void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc);
|
||||||
void installHooks();
|
void installHooks();
|
||||||
bool isTopLevelWindow(HWND hwnd);
|
|
||||||
void redraw(HRGN rgn);
|
void redraw(HRGN rgn);
|
||||||
void redrawWindow(HWND hwnd, HRGN rgn);
|
void redrawWindow(HWND hwnd, HRGN rgn);
|
||||||
void unhookWndProc(LPCSTR className, WNDPROC oldWndProc);
|
void unhookWndProc(LPCSTR className, WNDPROC oldWndProc);
|
||||||
void uninstallHooks();
|
void uninstallHooks();
|
||||||
void updatePalette(DWORD startingEntry, DWORD count);
|
|
||||||
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc);
|
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc);
|
||||||
|
|
||||||
extern CRITICAL_SECTION g_gdiCriticalSection;
|
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
#include "Gdi/PaintHandlers.h"
|
#include "Gdi/PaintHandlers.h"
|
||||||
@ -185,19 +186,15 @@ namespace
|
|||||||
|
|
||||||
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
|
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
if (hwnd && Gdi::beginGdiRendering())
|
if (hwnd)
|
||||||
{
|
{
|
||||||
LRESULT result = 0;
|
LRESULT result = 0;
|
||||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||||
if (compatDc)
|
if (compatDc)
|
||||||
{
|
{
|
||||||
|
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
result = CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
|
result = CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
|
||||||
Gdi::Dc::releaseDc(dc);
|
Gdi::Dc::releaseDc(dc);
|
||||||
}
|
|
||||||
|
|
||||||
Gdi::endGdiRendering();
|
|
||||||
if (compatDc)
|
|
||||||
{
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +204,7 @@ namespace
|
|||||||
|
|
||||||
LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc)
|
LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
if (!hwnd || !Gdi::beginGdiRendering())
|
if (!hwnd)
|
||||||
{
|
{
|
||||||
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
||||||
}
|
}
|
||||||
@ -216,6 +213,7 @@ namespace
|
|||||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||||
if (compatDc)
|
if (compatDc)
|
||||||
{
|
{
|
||||||
|
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
|
CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
|
||||||
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
||||||
ValidateRect(hwnd, nullptr);
|
ValidateRect(hwnd, nullptr);
|
||||||
@ -227,13 +225,12 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReleaseDC(hwnd, dc);
|
ReleaseDC(hwnd, dc);
|
||||||
Gdi::endGdiRendering();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc)
|
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
if (!hwnd || !Gdi::beginGdiRendering())
|
if (!hwnd)
|
||||||
{
|
{
|
||||||
return CallWindowProc(origWndProc, hwnd, WM_NCPAINT, wParam, 0);
|
return CallWindowProc(origWndProc, hwnd, WM_NCPAINT, wParam, 0);
|
||||||
}
|
}
|
||||||
@ -243,6 +240,7 @@ namespace
|
|||||||
|
|
||||||
if (compatDc)
|
if (compatDc)
|
||||||
{
|
{
|
||||||
|
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
Gdi::TitleBar titleBar(hwnd, compatDc);
|
Gdi::TitleBar titleBar(hwnd, compatDc);
|
||||||
titleBar.drawAll();
|
titleBar.drawAll();
|
||||||
titleBar.excludeFromClipRegion();
|
titleBar.excludeFromClipRegion();
|
||||||
@ -257,13 +255,12 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReleaseDC(hwnd, windowDc);
|
ReleaseDC(hwnd, windowDc);
|
||||||
Gdi::endGdiRendering();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc)
|
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
if (!hwnd || !Gdi::beginGdiRendering())
|
if (!hwnd)
|
||||||
{
|
{
|
||||||
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
||||||
}
|
}
|
||||||
@ -274,6 +271,7 @@ namespace
|
|||||||
|
|
||||||
if (compatDc)
|
if (compatDc)
|
||||||
{
|
{
|
||||||
|
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
|
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
|
||||||
reinterpret_cast<WPARAM>(compatDc), PRF_CLIENT);
|
reinterpret_cast<WPARAM>(compatDc), PRF_CLIENT);
|
||||||
Gdi::Dc::releaseDc(dc);
|
Gdi::Dc::releaseDc(dc);
|
||||||
@ -285,21 +283,16 @@ namespace
|
|||||||
|
|
||||||
EndPaint(hwnd, &paint);
|
EndPaint(hwnd, &paint);
|
||||||
|
|
||||||
Gdi::endGdiRendering();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc)
|
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;
|
LRESULT result = 0;
|
||||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||||
if (compatDc)
|
if (compatDc)
|
||||||
{
|
{
|
||||||
|
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(compatDc), flags);
|
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(compatDc), flags);
|
||||||
Gdi::Dc::releaseDc(dc);
|
Gdi::Dc::releaseDc(dc);
|
||||||
}
|
}
|
||||||
@ -307,8 +300,6 @@ namespace
|
|||||||
{
|
{
|
||||||
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), flags);
|
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdi::endGdiRendering();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,26 +1,9 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "Gdi/Region.h"
|
#include "Gdi/Region.h"
|
||||||
#include "Win32/DisplayMode.h"
|
|
||||||
|
|
||||||
namespace
|
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 combineRegions(const Gdi::Region& rgn1, const Gdi::Region& rgn2, int mode)
|
||||||
{
|
{
|
||||||
Gdi::Region region;
|
Gdi::Region region;
|
||||||
@ -132,17 +115,4 @@ namespace Gdi
|
|||||||
CombineRgn(m_region, m_region, other, mode);
|
CombineRgn(m_region, m_region, other, mode);
|
||||||
return *this;
|
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;
|
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/Log.h"
|
||||||
#include "Common/ScopedCriticalSection.h"
|
#include "Common/ScopedCriticalSection.h"
|
||||||
|
#include "Gdi/AccessGuard.h"
|
||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/ScrollBar.h"
|
#include "Gdi/ScrollBar.h"
|
||||||
#include "Gdi/ScrollFunctions.h"
|
#include "Gdi/ScrollFunctions.h"
|
||||||
@ -94,6 +95,12 @@ namespace
|
|||||||
return TRUE;
|
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(
|
void CALLBACK objectStateChangeEvent(
|
||||||
HWINEVENTHOOK /*hWinEventHook*/,
|
HWINEVENTHOOK /*hWinEventHook*/,
|
||||||
DWORD /*event*/,
|
DWORD /*event*/,
|
||||||
@ -105,7 +112,7 @@ namespace
|
|||||||
{
|
{
|
||||||
if (OBJID_TITLEBAR == idObject || OBJID_HSCROLL == idObject || OBJID_VSCROLL == idObject)
|
if (OBJID_TITLEBAR == idObject || OBJID_HSCROLL == idObject || OBJID_VSCROLL == idObject)
|
||||||
{
|
{
|
||||||
if (!hwnd || !Gdi::beginGdiRendering())
|
if (!hwnd)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -114,6 +121,7 @@ namespace
|
|||||||
HDC compatDc = Gdi::Dc::getDc(windowDc);
|
HDC compatDc = Gdi::Dc::getDc(windowDc);
|
||||||
if (compatDc)
|
if (compatDc)
|
||||||
{
|
{
|
||||||
|
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
if (OBJID_TITLEBAR == idObject)
|
if (OBJID_TITLEBAR == idObject)
|
||||||
{
|
{
|
||||||
Gdi::TitleBar(hwnd, compatDc).drawButtons();
|
Gdi::TitleBar(hwnd, compatDc).drawButtons();
|
||||||
@ -128,9 +136,7 @@ namespace
|
|||||||
}
|
}
|
||||||
Gdi::Dc::releaseDc(windowDc);
|
Gdi::Dc::releaseDc(windowDc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseDC(hwnd, windowDc);
|
ReleaseDC(hwnd, windowDc);
|
||||||
Gdi::endGdiRendering();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,22 +160,17 @@ namespace
|
|||||||
|
|
||||||
void onCreateWindow(HWND hwnd)
|
void onCreateWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
if (Gdi::isTopLevelWindow(hwnd))
|
if (isTopLevelNonLayeredWindow(hwnd))
|
||||||
{
|
{
|
||||||
disableDwmAttributes(hwnd);
|
disableDwmAttributes(hwnd);
|
||||||
removeDropShadow(hwnd);
|
removeDropShadow(hwnd);
|
||||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
|
||||||
Gdi::Window::add(hwnd);
|
Gdi::Window::add(hwnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDestroyWindow(HWND hwnd)
|
void onDestroyWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
if (Gdi::isTopLevelWindow(hwnd))
|
Gdi::Window::remove(hwnd);
|
||||||
{
|
|
||||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
|
||||||
Gdi::Window::remove(hwnd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onMenuSelect()
|
void onMenuSelect()
|
||||||
@ -190,19 +191,15 @@ namespace
|
|||||||
SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
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)
|
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
||||||
{
|
{
|
||||||
notifyFunc();
|
notifyFunc();
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdi::Window::updateAll();
|
if (isTopLevelNonLayeredWindow(hwnd))
|
||||||
|
{
|
||||||
|
Gdi::Window::updateAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeDropShadow(HWND hwnd)
|
void removeDropShadow(HWND hwnd)
|
||||||
|
@ -1,6 +1,34 @@
|
|||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/VirtualScreen.h"
|
||||||
#include "Gdi/Window.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
|
namespace Gdi
|
||||||
{
|
{
|
||||||
Window::Window(HWND hwnd)
|
Window::Window(HWND hwnd)
|
||||||
@ -8,18 +36,34 @@ namespace Gdi
|
|||||||
, m_windowRect{ 0, 0, 0, 0 }
|
, m_windowRect{ 0, 0, 0, 0 }
|
||||||
, m_isUpdating(false)
|
, 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();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Window& Window::add(HWND hwnd)
|
Window* Window::add(HWND hwnd)
|
||||||
{
|
{
|
||||||
auto it = s_windows.find(hwnd);
|
auto it = s_windows.find(hwnd);
|
||||||
if (it != s_windows.end())
|
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)
|
void Window::calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion)
|
||||||
@ -41,21 +85,22 @@ namespace Gdi
|
|||||||
|
|
||||||
if (!preservedRegion.isEmpty())
|
if (!preservedRegion.isEmpty())
|
||||||
{
|
{
|
||||||
HDC screenDc = GetDC(nullptr);
|
HDC screenDc = Gdi::getScreenDc();
|
||||||
SelectClipRgn(screenDc, preservedRegion);
|
SelectClipRgn(screenDc, preservedRegion);
|
||||||
BitBlt(screenDc, m_windowRect.left, m_windowRect.top,
|
BitBlt(screenDc, m_windowRect.left, m_windowRect.top,
|
||||||
oldWindowRect.right - oldWindowRect.left, oldWindowRect.bottom - oldWindowRect.top,
|
oldWindowRect.right - oldWindowRect.left, oldWindowRect.bottom - oldWindowRect.top,
|
||||||
screenDc, oldWindowRect.left, oldWindowRect.top, SRCCOPY);
|
screenDc, oldWindowRect.left, oldWindowRect.top, SRCCOPY);
|
||||||
ReleaseDC(nullptr, screenDc);
|
SelectClipRgn(screenDc, nullptr);
|
||||||
|
|
||||||
m_invalidatedRegion -= preservedRegion;
|
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
|
Region Window::getVisibleRegion() const
|
||||||
@ -68,6 +113,11 @@ namespace Gdi
|
|||||||
return m_windowRect;
|
return m_windowRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Window::isPresentationWindow(HWND hwnd)
|
||||||
|
{
|
||||||
|
return GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom();
|
||||||
|
}
|
||||||
|
|
||||||
void Window::remove(HWND hwnd)
|
void Window::remove(HWND hwnd)
|
||||||
{
|
{
|
||||||
s_windows.erase(hwnd);
|
s_windows.erase(hwnd);
|
||||||
@ -92,8 +142,12 @@ namespace Gdi
|
|||||||
HDC windowDc = GetWindowDC(m_hwnd);
|
HDC windowDc = GetWindowDC(m_hwnd);
|
||||||
GetRandomRgn(windowDc, newVisibleRegion, SYSRGN);
|
GetRandomRgn(windowDc, newVisibleRegion, SYSRGN);
|
||||||
ReleaseDC(m_hwnd, windowDc);
|
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);
|
std::swap(m_windowRect, newWindowRect);
|
||||||
|
@ -20,9 +20,11 @@ namespace Gdi
|
|||||||
Region getVisibleRegion() const;
|
Region getVisibleRegion() const;
|
||||||
RECT getWindowRect() const;
|
RECT getWindowRect() const;
|
||||||
|
|
||||||
static Window& add(HWND hwnd);
|
static Window* add(HWND hwnd);
|
||||||
static Window& get(HWND hwnd);
|
static Window* get(HWND hwnd);
|
||||||
static void remove(HWND hwnd);
|
static void remove(HWND hwnd);
|
||||||
|
|
||||||
|
static bool isPresentationWindow(HWND hwnd);
|
||||||
static void updateAll();
|
static void updateAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -30,6 +32,7 @@ namespace Gdi
|
|||||||
void update();
|
void update();
|
||||||
|
|
||||||
HWND m_hwnd;
|
HWND m_hwnd;
|
||||||
|
HWND m_presentationWindow;
|
||||||
RECT m_windowRect;
|
RECT m_windowRect;
|
||||||
Region m_visibleRegion;
|
Region m_visibleRegion;
|
||||||
Region m_invalidatedRegion;
|
Region m_invalidatedRegion;
|
||||||
|
@ -372,6 +372,11 @@ namespace Win32
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD getBpp()
|
||||||
|
{
|
||||||
|
return g_currentBpp;
|
||||||
|
}
|
||||||
|
|
||||||
ULONG queryDisplaySettingsUniqueness()
|
ULONG queryDisplaySettingsUniqueness()
|
||||||
{
|
{
|
||||||
static auto ddQueryDisplaySettingsUniqueness = reinterpret_cast<ULONG(APIENTRY*)()>(
|
static auto ddQueryDisplaySettingsUniqueness = reinterpret_cast<ULONG(APIENTRY*)()>(
|
||||||
|
@ -13,6 +13,7 @@ namespace Win32
|
|||||||
const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage);
|
const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage);
|
||||||
HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight);
|
HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight);
|
||||||
|
|
||||||
|
DWORD getBpp();
|
||||||
ULONG queryDisplaySettingsUniqueness();
|
ULONG queryDisplaySettingsUniqueness();
|
||||||
void setDDrawBpp(DWORD bpp);
|
void setDDrawBpp(DWORD bpp);
|
||||||
|
|
||||||
|
@ -52,8 +52,7 @@ namespace Win32
|
|||||||
reinterpret_cast<void*>(settings.orientation), 0);
|
reinterpret_cast<void*>(settings.orientation), 0);
|
||||||
|
|
||||||
const char* regKey = "FontSmoothing";
|
const char* regKey = "FontSmoothing";
|
||||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETFONTSMOOTHING,
|
PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETFONTSMOOTHING, reinterpret_cast<LPARAM>(regKey));
|
||||||
reinterpret_cast<LPARAM>(regKey), SMTO_BLOCK, 100, nullptr);
|
|
||||||
RedrawWindow(nullptr, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
RedrawWindow(nullptr, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user