mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Initial commit
This commit is contained in:
commit
2a5e699c6e
140
DDrawCompat/CompatDirectDraw.cpp
Normal file
140
DDrawCompat/CompatDirectDraw.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename TSurfaceDesc>
|
||||
HRESULT PASCAL enumDisplayModesCallback(
|
||||
TSurfaceDesc* lpDDSurfaceDesc,
|
||||
LPVOID lpContext)
|
||||
{
|
||||
if (lpDDSurfaceDesc)
|
||||
{
|
||||
*static_cast<DDPIXELFORMAT*>(lpContext) = lpDDSurfaceDesc->ddpfPixelFormat;
|
||||
}
|
||||
return DDENUMRET_CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TDirectDraw>
|
||||
void CompatDirectDraw<TDirectDraw>::setCompatVtable(Vtable<TDirectDraw>& vtable)
|
||||
{
|
||||
vtable.CreateSurface = &CreateSurface;
|
||||
vtable.RestoreDisplayMode = &RestoreDisplayMode;
|
||||
vtable.SetDisplayMode = &SetDisplayMode;
|
||||
}
|
||||
|
||||
template <typename TDirectDraw>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::CreateSurface(
|
||||
TDirectDraw* This,
|
||||
TSurfaceDesc* lpDDSurfaceDesc,
|
||||
TSurface** lplpDDSurface,
|
||||
IUnknown* pUnkOuter)
|
||||
{
|
||||
HRESULT result = DD_OK;
|
||||
|
||||
const bool isPrimary = lpDDSurfaceDesc &&
|
||||
(lpDDSurfaceDesc->dwFlags & DDSD_CAPS) &&
|
||||
(lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
|
||||
|
||||
if (isPrimary)
|
||||
{
|
||||
result = CompatDirectDrawSurface<TSurface>::createCompatPrimarySurface(
|
||||
*This, *lpDDSurfaceDesc, *lplpDDSurface);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CompatPrimarySurface::displayMode.pixelFormat.dwSize != 0 &&
|
||||
!(lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT))
|
||||
{
|
||||
lpDDSurfaceDesc->dwFlags |= DDSD_PIXELFORMAT;
|
||||
lpDDSurfaceDesc->ddpfPixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
|
||||
}
|
||||
result = s_origVtable.CreateSurface(This, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(**lplpDDSurface);
|
||||
if (isPrimary)
|
||||
{
|
||||
CompatDirectDrawSurface<TSurface>::updateSurfaceParams();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TDirectDraw>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::RestoreDisplayMode(TDirectDraw* This)
|
||||
{
|
||||
HRESULT result = s_origVtable.RestoreDisplayMode(This);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
CompatPrimarySurface::displayMode = CompatPrimarySurface::getDisplayMode(*This);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TDirectDraw>
|
||||
template <typename... Params>
|
||||
static HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::SetDisplayMode(
|
||||
TDirectDraw* This,
|
||||
DWORD dwWidth,
|
||||
DWORD dwHeight,
|
||||
DWORD dwBPP,
|
||||
Params... params)
|
||||
{
|
||||
TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
desc.dwWidth = dwWidth;
|
||||
desc.dwHeight = dwHeight;
|
||||
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
|
||||
desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
|
||||
desc.ddpfPixelFormat.dwRGBBitCount = dwBPP;
|
||||
|
||||
switch (dwBPP)
|
||||
{
|
||||
case 1: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED1; break;
|
||||
case 2: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED2; break;
|
||||
case 4: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED4; break;
|
||||
case 8: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; break;
|
||||
}
|
||||
|
||||
DDPIXELFORMAT pf = {};
|
||||
if (dwBPP > 8)
|
||||
{
|
||||
if (FAILED(s_origVtable.EnumDisplayModes(This, 0, &desc, &pf, &enumDisplayModesCallback)) ||
|
||||
0 == pf.dwSize)
|
||||
{
|
||||
Compat::Log() << "Failed to find the requested display mode: " <<
|
||||
dwWidth << "x" << dwHeight << "x" << dwBPP;
|
||||
return DDERR_INVALIDMODE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pf = desc.ddpfPixelFormat;
|
||||
}
|
||||
|
||||
HRESULT result = s_origVtable.SetDisplayMode(This, dwWidth, dwHeight, 32, params...);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
CompatPrimarySurface::displayMode.width = dwWidth;
|
||||
CompatPrimarySurface::displayMode.height = dwHeight;
|
||||
CompatPrimarySurface::displayMode.pixelFormat = pf;
|
||||
}
|
||||
else
|
||||
{
|
||||
Compat::Log() << "Failed to set the display mode to " << dwWidth << "x" << dwHeight << "x32";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template CompatDirectDraw<IDirectDraw>;
|
||||
template CompatDirectDraw<IDirectDraw2>;
|
||||
template CompatDirectDraw<IDirectDraw4>;
|
||||
template CompatDirectDraw<IDirectDraw7>;
|
31
DDrawCompat/CompatDirectDraw.h
Normal file
31
DDrawCompat/CompatDirectDraw.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "CompatVtable.h"
|
||||
#include "DDrawTypes.h"
|
||||
#include "DirectDrawVtblVisitor.h"
|
||||
|
||||
template <typename TDirectDraw>
|
||||
class CompatDirectDraw : public CompatVtable<CompatDirectDraw<TDirectDraw>, TDirectDraw>
|
||||
{
|
||||
public:
|
||||
typedef typename Types<TDirectDraw>::TCreatedSurface TSurface;
|
||||
typedef typename Types<TDirectDraw>::TSurfaceDesc TSurfaceDesc;
|
||||
|
||||
static void setCompatVtable(Vtable<TDirectDraw>& vtable);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CreateSurface(
|
||||
TDirectDraw* This,
|
||||
TSurfaceDesc* lpDDSurfaceDesc,
|
||||
TSurface** lplpDDSurface,
|
||||
IUnknown* pUnkOuter);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE RestoreDisplayMode(TDirectDraw* This);
|
||||
|
||||
template <typename... Params>
|
||||
static HRESULT STDMETHODCALLTYPE SetDisplayMode(
|
||||
TDirectDraw* This,
|
||||
DWORD dwWidth,
|
||||
DWORD dwHeight,
|
||||
DWORD dwBPP,
|
||||
Params... params);
|
||||
};
|
23
DDrawCompat/CompatDirectDrawPalette.cpp
Normal file
23
DDrawCompat/CompatDirectDrawPalette.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "CompatDirectDrawPalette.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
void CompatDirectDrawPalette::setCompatVtable(IDirectDrawPaletteVtbl& vtable)
|
||||
{
|
||||
vtable.SetEntries = &SetEntries;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawPalette::SetEntries(
|
||||
IDirectDrawPalette* This,
|
||||
DWORD dwFlags,
|
||||
DWORD dwStartingEntry,
|
||||
DWORD dwCount,
|
||||
LPPALETTEENTRY lpEntries)
|
||||
{
|
||||
HRESULT result = s_origVtable.SetEntries(This, dwFlags, dwStartingEntry, dwCount, lpEntries);
|
||||
if (This == CompatPrimarySurface::palette && SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::updatePalette();
|
||||
}
|
||||
return result;
|
||||
}
|
17
DDrawCompat/CompatDirectDrawPalette.h
Normal file
17
DDrawCompat/CompatDirectDrawPalette.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "CompatVtable.h"
|
||||
#include "DirectDrawPaletteVtblVisitor.h"
|
||||
|
||||
class CompatDirectDrawPalette : public CompatVtable<CompatDirectDrawPalette, IDirectDrawPalette>
|
||||
{
|
||||
public:
|
||||
static void setCompatVtable(IDirectDrawPaletteVtbl& vtable);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SetEntries(
|
||||
IDirectDrawPalette* This,
|
||||
DWORD dwFlags,
|
||||
DWORD dwStartingEntry,
|
||||
DWORD dwCount,
|
||||
LPPALETTEENTRY lpEntries);
|
||||
};
|
685
DDrawCompat/CompatDirectDrawSurface.cpp
Normal file
685
DDrawCompat/CompatDirectDrawSurface.cpp
Normal file
@ -0,0 +1,685 @@
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdiSurface.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "DDrawProcs.h"
|
||||
#include "IReleaseNotifier.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct SimilarSurface
|
||||
{
|
||||
DWORD width;
|
||||
DWORD height;
|
||||
DDPIXELFORMAT pixelFormat;
|
||||
IDirectDrawSurface7* front;
|
||||
IDirectDrawSurface7* back;
|
||||
};
|
||||
|
||||
SimilarSurface getSimilarSurface(const DDSURFACEDESC2& desc);
|
||||
bool mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx);
|
||||
|
||||
IDirectDraw7* g_mirrorDirectDraw = nullptr;
|
||||
|
||||
IDirectDraw7* createMirrorDirectDraw()
|
||||
{
|
||||
IDirectDraw7* dd = nullptr;
|
||||
CALL_ORIG_DDRAW(DirectDrawCreateEx, nullptr, reinterpret_cast<void**>(&dd), IID_IDirectDraw7, nullptr);
|
||||
if (!dd ||
|
||||
FAILED(CompatDirectDraw<IDirectDraw7>::s_origVtable.SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL)))
|
||||
{
|
||||
Compat::Log() << "Failed to create a helper DirectDraw object for mirroring";
|
||||
}
|
||||
return dd;
|
||||
}
|
||||
|
||||
void fixSurfacePtr(IDirectDrawSurface7& surface, DDSURFACEDESC2& desc)
|
||||
{
|
||||
if ((desc.dwFlags & DDSD_CAPS) && (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DDBLTFX fx = {};
|
||||
fx.dwSize = sizeof(fx);
|
||||
surface.lpVtbl->Blt(&surface, nullptr, nullptr, nullptr, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
|
||||
}
|
||||
|
||||
HRESULT WINAPI enumSurfacesCallback(
|
||||
LPDIRECTDRAWSURFACE7 lpDDSurface,
|
||||
LPDDSURFACEDESC2 lpDDSurfaceDesc,
|
||||
LPVOID lpContext)
|
||||
{
|
||||
auto visitedSurfaces = *static_cast<std::set<IDirectDrawSurface7*>*>(lpContext);
|
||||
|
||||
if (visitedSurfaces.find(lpDDSurface) == visitedSurfaces.end())
|
||||
{
|
||||
visitedSurfaces.insert(lpDDSurface);
|
||||
fixSurfacePtr(*lpDDSurface, *lpDDSurfaceDesc);
|
||||
lpDDSurface->lpVtbl->EnumAttachedSurfaces(lpDDSurface, &visitedSurfaces, &enumSurfacesCallback);
|
||||
}
|
||||
|
||||
lpDDSurface->lpVtbl->Release(lpDDSurface);
|
||||
return DDENUMRET_OK;
|
||||
}
|
||||
|
||||
void fixSurfacePtrs(IDirectDrawSurface7& surface)
|
||||
{
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
surface.lpVtbl->GetSurfaceDesc(&surface, &desc);
|
||||
|
||||
fixSurfacePtr(surface, desc);
|
||||
std::set<IDirectDrawSurface7*> visitedSurfaces{ &surface };
|
||||
surface.lpVtbl->EnumAttachedSurfaces(&surface, &visitedSurfaces, &enumSurfacesCallback);
|
||||
}
|
||||
|
||||
IDirectDrawSurface7* getMirroredSurface(IDirectDrawSurface7& surface, RECT* srcRect, DWORD mirrorFx)
|
||||
{
|
||||
auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
HRESULT result = origVtable.GetSurfaceDesc(&surface, &desc);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to get surface description for mirroring: " << result);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (srcRect)
|
||||
{
|
||||
desc.dwWidth = srcRect->right - srcRect->left;
|
||||
desc.dwHeight = srcRect->bottom - srcRect->top;
|
||||
}
|
||||
|
||||
SimilarSurface similarSurface = getSimilarSurface(desc);
|
||||
if (!similarSurface.front)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RECT rect = { 0, 0, static_cast<LONG>(desc.dwWidth), static_cast<LONG>(desc.dwHeight) };
|
||||
if ((mirrorFx & DDBLTFX_MIRRORLEFTRIGHT) && (mirrorFx & DDBLTFX_MIRRORUPDOWN))
|
||||
{
|
||||
if (!mirrorBlt(*similarSurface.back, surface, srcRect ? *srcRect : rect, DDBLTFX_MIRRORLEFTRIGHT) ||
|
||||
!mirrorBlt(*similarSurface.front, *similarSurface.back, rect, DDBLTFX_MIRRORUPDOWN))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if (!mirrorBlt(*similarSurface.front, surface, srcRect ? *srcRect : rect, mirrorFx))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
origVtable.AddRef(similarSurface.front);
|
||||
return similarSurface.front;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
TSurface* getMirroredSurface(TSurface& surface, RECT* rect, DWORD mirrorFx)
|
||||
{
|
||||
auto& origVtable = CompatDirectDrawSurface<TSurface>::s_origVtable;
|
||||
|
||||
IDirectDrawSurface7* surface7 = nullptr;
|
||||
origVtable.QueryInterface(&surface, IID_IDirectDrawSurface7, reinterpret_cast<void**>(&surface7));
|
||||
IDirectDrawSurface7* mirroredSurface7 = getMirroredSurface(*surface7, rect, mirrorFx);
|
||||
surface7->lpVtbl->Release(surface7);
|
||||
|
||||
if (!mirroredSurface7)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto& origVtable7 = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||
TSurface* mirroredSurface = nullptr;
|
||||
origVtable7.QueryInterface(mirroredSurface7,
|
||||
CompatDirectDrawSurface<TSurface>::s_iid, reinterpret_cast<void**>(&mirroredSurface));
|
||||
origVtable7.Release(mirroredSurface7);
|
||||
return mirroredSurface;
|
||||
}
|
||||
|
||||
SimilarSurface getSimilarSurface(const DDSURFACEDESC2& desc)
|
||||
{
|
||||
static std::vector<SimilarSurface> similarSurfacesVidMem;
|
||||
static std::vector<SimilarSurface> similarSurfacesSysMem;
|
||||
|
||||
std::vector<SimilarSurface>& similarSurfaces =
|
||||
(desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ? similarSurfacesSysMem : similarSurfacesVidMem;
|
||||
|
||||
DDPIXELFORMAT pf = desc.ddpfPixelFormat;
|
||||
if (!(pf.dwFlags & DDPF_FOURCC))
|
||||
{
|
||||
pf.dwFourCC = 0;
|
||||
}
|
||||
if (!(pf.dwFlags & (DDPF_ALPHAPIXELS | DDPF_ZPIXELS)))
|
||||
{
|
||||
pf.dwRGBAlphaBitMask = 0;
|
||||
}
|
||||
auto it = std::find_if(similarSurfaces.begin(), similarSurfaces.end(),
|
||||
[&](SimilarSurface& s) { return 0 == memcmp(&s.pixelFormat, &pf, sizeof(pf)); });
|
||||
|
||||
auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||
SimilarSurface similarSurface = {};
|
||||
if (it != similarSurfaces.end())
|
||||
{
|
||||
if (DDERR_SURFACELOST == origVtable.IsLost(it->front) ||
|
||||
DDERR_SURFACELOST == origVtable.IsLost(it->back))
|
||||
{
|
||||
origVtable.Release(it->front);
|
||||
origVtable.Release(it->back);
|
||||
similarSurfaces.erase(it);
|
||||
it = similarSurfaces.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
similarSurface = *it;
|
||||
}
|
||||
}
|
||||
|
||||
if (similarSurface.width >= desc.dwWidth && similarSurface.height >= desc.dwHeight)
|
||||
{
|
||||
return similarSurface;
|
||||
}
|
||||
|
||||
DDSURFACEDESC2 similarDesc = {};
|
||||
similarDesc.dwSize = sizeof(similarDesc);
|
||||
similarDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
|
||||
similarDesc.dwWidth = max(similarSurface.width, desc.dwWidth);
|
||||
similarDesc.dwHeight = max(similarSurface.height, desc.dwHeight);
|
||||
similarDesc.ddpfPixelFormat = pf;
|
||||
similarDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||
if (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
||||
{
|
||||
similarDesc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
||||
}
|
||||
|
||||
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
||||
g_mirrorDirectDraw, &similarDesc, &similarSurface.front, nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to create a front surface for mirroring");
|
||||
similarSurface.front = nullptr;
|
||||
return similarSurface;
|
||||
}
|
||||
|
||||
result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
||||
g_mirrorDirectDraw, &similarDesc, &similarSurface.back, nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to create a back surface for mirroring");
|
||||
origVtable.Release(similarSurface.front);
|
||||
similarSurface.front = nullptr;
|
||||
return similarSurface;
|
||||
}
|
||||
|
||||
similarSurface.width = similarDesc.dwWidth;
|
||||
similarSurface.height = similarDesc.dwHeight;
|
||||
similarSurface.pixelFormat = pf;
|
||||
|
||||
if (it != similarSurfaces.end())
|
||||
{
|
||||
origVtable.Release(it->front);
|
||||
origVtable.Release(it->back);
|
||||
*it = similarSurface;
|
||||
}
|
||||
else
|
||||
{
|
||||
similarSurfaces.push_back(similarSurface);
|
||||
}
|
||||
|
||||
return similarSurface;
|
||||
}
|
||||
|
||||
bool mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx)
|
||||
{
|
||||
if (DDBLTFX_MIRRORLEFTRIGHT == mirrorFx)
|
||||
{
|
||||
LONG width = srcRect.right - srcRect.left;
|
||||
srcRect.left = srcRect.right - 1;
|
||||
for (LONG x = 0; x < width; ++x)
|
||||
{
|
||||
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.BltFast(
|
||||
&dst, x, 0, &src, &srcRect, DDBLTFAST_WAIT);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed BltFast for mirroring: " << result);
|
||||
return false;
|
||||
}
|
||||
--srcRect.left;
|
||||
--srcRect.right;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LONG height = srcRect.bottom - srcRect.top;
|
||||
srcRect.top = srcRect.bottom - 1;
|
||||
for (LONG y = 0; y < height; ++y)
|
||||
{
|
||||
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.BltFast(
|
||||
&dst, 0, y, &src, &srcRect, DDBLTFAST_WAIT);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed BltFast for mirroring: " << result);
|
||||
return false;
|
||||
}
|
||||
--srcRect.top;
|
||||
--srcRect.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
void CompatDirectDrawSurface<TSurface>::setCompatVtable(Vtable<TSurface>& vtable)
|
||||
{
|
||||
vtable.Blt = &Blt;
|
||||
vtable.BltFast = &BltFast;
|
||||
vtable.Flip = &Flip;
|
||||
vtable.GetCaps = &GetCaps;
|
||||
vtable.GetSurfaceDesc = &GetSurfaceDesc;
|
||||
vtable.IsLost = &IsLost;
|
||||
vtable.Lock = &Lock;
|
||||
vtable.QueryInterface = &QueryInterface;
|
||||
vtable.ReleaseDC = &ReleaseDC;
|
||||
vtable.Restore = &Restore;
|
||||
vtable.SetClipper = &SetClipper;
|
||||
vtable.SetPalette = &SetPalette;
|
||||
vtable.Unlock = &Unlock;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
template <typename TDirectDraw>
|
||||
HRESULT CompatDirectDrawSurface<TSurface>::createCompatPrimarySurface(
|
||||
TDirectDraw& dd,
|
||||
TSurfaceDesc compatDesc,
|
||||
TSurface*& compatSurface)
|
||||
{
|
||||
if (0 == CompatPrimarySurface::displayMode.pixelFormat.dwSize)
|
||||
{
|
||||
CompatPrimarySurface::displayMode = CompatPrimarySurface::getDisplayMode(dd);
|
||||
}
|
||||
|
||||
HRESULT result = RealPrimarySurface::create(dd);
|
||||
if (FAILED(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
CompatPrimarySurface::width = CompatPrimarySurface::displayMode.width;
|
||||
CompatPrimarySurface::height = CompatPrimarySurface::displayMode.height;
|
||||
CompatPrimarySurface::pixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
|
||||
|
||||
compatDesc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
compatDesc.dwWidth = CompatPrimarySurface::width;
|
||||
compatDesc.dwHeight = CompatPrimarySurface::height;
|
||||
compatDesc.ddsCaps.dwCaps ^= DDSCAPS_PRIMARYSURFACE;
|
||||
compatDesc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN;
|
||||
compatDesc.ddpfPixelFormat = CompatPrimarySurface::pixelFormat;
|
||||
|
||||
result = CompatDirectDraw<TDirectDraw>::s_origVtable.CreateSurface(
|
||||
&dd, &compatDesc, &compatSurface, nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
Compat::Log() << "Failed to create the compat primary surface!";
|
||||
RealPrimarySurface::release();
|
||||
return result;
|
||||
}
|
||||
|
||||
g_mirrorDirectDraw = createMirrorDirectDraw();
|
||||
|
||||
s_compatPrimarySurface = compatSurface;
|
||||
initCompatPrimarySurface();
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
void CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(TSurface& surface)
|
||||
{
|
||||
IDirectDrawSurface7* surface7 = nullptr;
|
||||
surface.lpVtbl->QueryInterface(&surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&surface7));
|
||||
::fixSurfacePtrs(*surface7);
|
||||
surface7->lpVtbl->Release(surface7);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
void CompatDirectDrawSurface<TSurface>::initPrimarySurfacePtr(const GUID& guid, IUnknown& surface)
|
||||
{
|
||||
if (SUCCEEDED(surface.lpVtbl->QueryInterface(
|
||||
&surface, guid, reinterpret_cast<LPVOID*>(&s_compatPrimarySurface))))
|
||||
{
|
||||
s_compatPrimarySurface->lpVtbl->Release(s_compatPrimarySurface);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Blt(
|
||||
TSurface* This,
|
||||
LPRECT lpDestRect,
|
||||
TSurface* lpDDSrcSurface,
|
||||
LPRECT lpSrcRect,
|
||||
DWORD dwFlags,
|
||||
LPDDBLTFX lpDDBltFx)
|
||||
{
|
||||
if ((This == s_compatPrimarySurface || lpDDSrcSurface == s_compatPrimarySurface) &&
|
||||
RealPrimarySurface::isLost())
|
||||
{
|
||||
return DDERR_SURFACELOST;
|
||||
}
|
||||
|
||||
HRESULT result = DD_OK;
|
||||
TSurface* mirroredSrcSurface = nullptr;
|
||||
|
||||
if (lpDDSrcSurface && (dwFlags & DDBLT_DDFX) && lpDDBltFx &&
|
||||
(lpDDBltFx->dwDDFX & (DDBLTFX_MIRRORLEFTRIGHT | DDBLTFX_MIRRORUPDOWN)))
|
||||
{
|
||||
mirroredSrcSurface = getMirroredSurface(*lpDDSrcSurface, lpSrcRect, lpDDBltFx->dwDDFX);
|
||||
}
|
||||
|
||||
if (mirroredSrcSurface)
|
||||
{
|
||||
DWORD flags = dwFlags;
|
||||
DDBLTFX fx = *lpDDBltFx;
|
||||
fx.dwDDFX &= ~(DDBLTFX_MIRRORLEFTRIGHT | DDBLTFX_MIRRORUPDOWN);
|
||||
if (0 == fx.dwDDFX)
|
||||
{
|
||||
flags ^= DDBLT_DDFX;
|
||||
}
|
||||
if (flags & DDBLT_KEYSRC)
|
||||
{
|
||||
DDCOLORKEY srcColorKey = {};
|
||||
s_origVtable.GetColorKey(lpDDSrcSurface, DDCKEY_SRCBLT, &srcColorKey);
|
||||
s_origVtable.SetColorKey(mirroredSrcSurface, DDCKEY_SRCBLT, &srcColorKey);
|
||||
}
|
||||
|
||||
if (lpSrcRect)
|
||||
{
|
||||
RECT srcRect = { 0, 0, lpSrcRect->right - lpSrcRect->left, lpSrcRect->bottom - lpSrcRect->top };
|
||||
result = s_origVtable.Blt(This, lpDestRect, mirroredSrcSurface, &srcRect, flags, &fx);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = s_origVtable.Blt(This, lpDestRect, mirroredSrcSurface, nullptr, flags, &fx);
|
||||
}
|
||||
|
||||
s_origVtable.Release(mirroredSrcSurface);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||
}
|
||||
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::BltFast(
|
||||
TSurface* This,
|
||||
DWORD dwX,
|
||||
DWORD dwY,
|
||||
TSurface* lpDDSrcSurface,
|
||||
LPRECT lpSrcRect,
|
||||
DWORD dwTrans)
|
||||
{
|
||||
if ((This == s_compatPrimarySurface || lpDDSrcSurface == s_compatPrimarySurface) &&
|
||||
RealPrimarySurface::isLost())
|
||||
{
|
||||
return DDERR_SURFACELOST;
|
||||
}
|
||||
|
||||
HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Flip(
|
||||
TSurface* This,
|
||||
TSurface* lpDDSurfaceTargetOverride,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
HRESULT result = s_origVtable.Flip(This, lpDDSurfaceTargetOverride, dwFlags);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
result = RealPrimarySurface::flip(dwFlags);
|
||||
updateSurfaceParams();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::GetCaps(
|
||||
TSurface* This,
|
||||
TDdsCaps* lpDDSCaps)
|
||||
{
|
||||
HRESULT result = s_origVtable.GetCaps(This, lpDDSCaps);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
restorePrimaryCaps(*lpDDSCaps);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::GetSurfaceDesc(
|
||||
TSurface* This,
|
||||
TSurfaceDesc* lpDDSurfaceDesc)
|
||||
{
|
||||
HRESULT result = s_origVtable.GetSurfaceDesc(This, lpDDSurfaceDesc);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::IsLost(TSurface* This)
|
||||
{
|
||||
HRESULT result = s_origVtable.IsLost(This);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
result = RealPrimarySurface::isLost() ? DDERR_SURFACELOST : DD_OK;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Lock(
|
||||
TSurface* This,
|
||||
LPRECT lpDestRect,
|
||||
TSurfaceDesc* lpDDSurfaceDesc,
|
||||
DWORD dwFlags,
|
||||
HANDLE hEvent)
|
||||
{
|
||||
if (This == s_compatPrimarySurface && RealPrimarySurface::isLost())
|
||||
{
|
||||
return DDERR_SURFACELOST;
|
||||
}
|
||||
return s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::QueryInterface(
|
||||
TSurface* This,
|
||||
REFIID riid,
|
||||
LPVOID* obp)
|
||||
{
|
||||
if (This == s_compatPrimarySurface && riid == IID_IDirectDrawGammaControl)
|
||||
{
|
||||
return RealPrimarySurface::getSurface()->lpVtbl->QueryInterface(
|
||||
RealPrimarySurface::getSurface(), riid, obp);
|
||||
}
|
||||
return s_origVtable.QueryInterface(This, riid, obp);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
|
||||
{
|
||||
if (This == s_compatPrimarySurface && RealPrimarySurface::isLost())
|
||||
{
|
||||
return DDERR_SURFACELOST;
|
||||
}
|
||||
|
||||
HRESULT result = s_origVtable.ReleaseDC(This, hDC);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Restore(TSurface* This)
|
||||
{
|
||||
const bool wasLost = DDERR_SURFACELOST == s_origVtable.IsLost(This);
|
||||
HRESULT result = s_origVtable.Restore(This);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
if (wasLost)
|
||||
{
|
||||
fixSurfacePtrs(*This);
|
||||
}
|
||||
if (This == s_compatPrimarySurface)
|
||||
{
|
||||
result = RealPrimarySurface::restore();
|
||||
if (wasLost)
|
||||
{
|
||||
updateSurfaceParams();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::SetClipper(
|
||||
TSurface* This,
|
||||
LPDIRECTDRAWCLIPPER lpDDClipper)
|
||||
{
|
||||
HRESULT result = s_origVtable.SetClipper(This, lpDDClipper);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::setClipper(lpDDClipper);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::SetPalette(
|
||||
TSurface* This,
|
||||
LPDIRECTDRAWPALETTE lpDDPalette)
|
||||
{
|
||||
HRESULT result = s_origVtable.SetPalette(This, lpDDPalette);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
CompatPrimarySurface::palette = lpDDPalette;
|
||||
RealPrimarySurface::setPalette(lpDDPalette);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
|
||||
{
|
||||
HRESULT result = s_origVtable.Unlock(This, lpRect);
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
void CompatDirectDrawSurface<TSurface>::initCompatPrimarySurface()
|
||||
{
|
||||
Compat::LogEnter("CompatDirectDrawSurface::initCompatPrimarySurface");
|
||||
|
||||
IUnknown& unk = reinterpret_cast<IUnknown&>(*s_compatPrimarySurface);
|
||||
CompatDirectDrawSurface<IDirectDrawSurface>::initPrimarySurfacePtr(IID_IDirectDrawSurface, unk);
|
||||
CompatDirectDrawSurface<IDirectDrawSurface2>::initPrimarySurfacePtr(IID_IDirectDrawSurface2, unk);
|
||||
CompatDirectDrawSurface<IDirectDrawSurface3>::initPrimarySurfacePtr(IID_IDirectDrawSurface3, unk);
|
||||
CompatDirectDrawSurface<IDirectDrawSurface4>::initPrimarySurfacePtr(IID_IDirectDrawSurface4, unk);
|
||||
CompatDirectDrawSurface<IDirectDrawSurface7>::initPrimarySurfacePtr(IID_IDirectDrawSurface7, unk);
|
||||
|
||||
if (SUCCEEDED(s_origVtable.QueryInterface(
|
||||
s_compatPrimarySurface,
|
||||
IID_IDirectDrawSurface7,
|
||||
reinterpret_cast<LPVOID*>(&CompatPrimarySurface::surface))))
|
||||
{
|
||||
IReleaseNotifier* releaseNotifier = &CompatPrimarySurface::releaseNotifier;
|
||||
CompatPrimarySurface::surface->lpVtbl->SetPrivateData(CompatPrimarySurface::surface,
|
||||
IID_IReleaseNotifier, releaseNotifier, sizeof(releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||
CompatPrimarySurface::surface->lpVtbl->Release(CompatPrimarySurface::surface);
|
||||
}
|
||||
|
||||
Compat::LogLeave("CompatDirectDrawSurface::initCompatPrimarySurface");
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
void CompatDirectDrawSurface<TSurface>::restorePrimaryCaps(TDdsCaps& caps)
|
||||
{
|
||||
caps.dwCaps ^= DDSCAPS_OFFSCREENPLAIN;
|
||||
caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
void CompatDirectDrawSurface<TSurface>::updateSurfaceParams()
|
||||
{
|
||||
TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
if (SUCCEEDED(s_origVtable.Lock(s_compatPrimarySurface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
|
||||
{
|
||||
s_origVtable.Unlock(s_compatPrimarySurface, nullptr);
|
||||
CompatPrimarySurface::pitch = desc.lPitch;
|
||||
CompatPrimarySurface::surfacePtr = desc.lpSurface;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
TSurface* CompatDirectDrawSurface<TSurface>::s_compatPrimarySurface = nullptr;
|
||||
|
||||
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface>::s_iid = IID_IDirectDrawSurface;
|
||||
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface2>::s_iid = IID_IDirectDrawSurface2;
|
||||
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface3>::s_iid = IID_IDirectDrawSurface3;
|
||||
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface4>::s_iid = IID_IDirectDrawSurface4;
|
||||
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface7>::s_iid = IID_IDirectDrawSurface7;
|
||||
|
||||
template CompatDirectDrawSurface<IDirectDrawSurface>;
|
||||
template CompatDirectDrawSurface<IDirectDrawSurface2>;
|
||||
template CompatDirectDrawSurface<IDirectDrawSurface3>;
|
||||
template CompatDirectDrawSurface<IDirectDrawSurface4>;
|
||||
template CompatDirectDrawSurface<IDirectDrawSurface7>;
|
||||
|
||||
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface>::createCompatPrimarySurface(
|
||||
IDirectDraw& dd,
|
||||
TSurfaceDesc compatDesc,
|
||||
IDirectDrawSurface*& compatSurface);
|
||||
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface>::createCompatPrimarySurface(
|
||||
IDirectDraw2& dd,
|
||||
TSurfaceDesc compatDesc,
|
||||
IDirectDrawSurface*& compatSurface);
|
||||
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface4>::createCompatPrimarySurface(
|
||||
IDirectDraw4& dd,
|
||||
TSurfaceDesc compatDesc,
|
||||
IDirectDrawSurface4*& compatSurface);
|
||||
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface7>::createCompatPrimarySurface(
|
||||
IDirectDraw7& dd,
|
||||
TSurfaceDesc compatDesc,
|
||||
IDirectDrawSurface7*& compatSurface);
|
72
DDrawCompat/CompatDirectDrawSurface.h
Normal file
72
DDrawCompat/CompatDirectDrawSurface.h
Normal file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "CompatVtable.h"
|
||||
#include "DDrawTypes.h"
|
||||
#include "DirectDrawSurfaceVtblVisitor.h"
|
||||
|
||||
template <typename TSurface>
|
||||
class CompatDirectDrawSurface : public CompatVtable<CompatDirectDrawSurface<TSurface>, TSurface>
|
||||
{
|
||||
public:
|
||||
typedef typename Types<TSurface>::TSurfaceDesc TSurfaceDesc;
|
||||
typedef typename Types<TSurface>::TDdsCaps TDdsCaps;
|
||||
typedef typename Types<TSurface>::TUnlockParam TUnlockParam;
|
||||
|
||||
static void setCompatVtable(Vtable<TSurface>& vtable);
|
||||
|
||||
template <typename TDirectDraw>
|
||||
static HRESULT createCompatPrimarySurface(
|
||||
TDirectDraw& dd,
|
||||
TSurfaceDesc compatDesc,
|
||||
TSurface*& compatSurface);
|
||||
|
||||
static void fixSurfacePtrs(TSurface& surface);
|
||||
static void initPrimarySurfacePtr(const GUID& guid, IUnknown& surface);
|
||||
static void updateSurfaceParams();
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE Blt(
|
||||
TSurface* This,
|
||||
LPRECT lpDestRect,
|
||||
TSurface* lpDDSrcSurface,
|
||||
LPRECT lpSrcRect,
|
||||
DWORD dwFlags,
|
||||
LPDDBLTFX lpDDBltFx);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE BltFast(
|
||||
TSurface* This,
|
||||
DWORD dwX,
|
||||
DWORD dwY,
|
||||
TSurface* lpDDSrcSurface,
|
||||
LPRECT lpSrcRect,
|
||||
DWORD dwTrans);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE Flip(
|
||||
TSurface* This,
|
||||
TSurface* lpDDSurfaceTargetOverride,
|
||||
DWORD dwFlags);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE GetCaps(TSurface* This, TDdsCaps* lpDDSCaps);
|
||||
static HRESULT STDMETHODCALLTYPE GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc);
|
||||
static HRESULT STDMETHODCALLTYPE IsLost(TSurface* This);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE Lock(
|
||||
TSurface* This,
|
||||
LPRECT lpDestRect,
|
||||
TSurfaceDesc* lpDDSurfaceDesc,
|
||||
DWORD dwFlags,
|
||||
HANDLE hEvent);
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE QueryInterface(TSurface* This, REFIID riid, LPVOID* obp);
|
||||
static HRESULT STDMETHODCALLTYPE ReleaseDC(TSurface* This, HDC hDC);
|
||||
static HRESULT STDMETHODCALLTYPE Restore(TSurface* This);
|
||||
static HRESULT STDMETHODCALLTYPE SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper);
|
||||
static HRESULT STDMETHODCALLTYPE SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette);
|
||||
static HRESULT STDMETHODCALLTYPE Unlock(TSurface* This, TUnlockParam lpRect);
|
||||
|
||||
static const IID& s_iid;
|
||||
|
||||
private:
|
||||
static void initCompatPrimarySurface();
|
||||
static void restorePrimaryCaps(TDdsCaps& caps);
|
||||
static TSurface* s_compatPrimarySurface;
|
||||
};
|
537
DDrawCompat/CompatGdiSurface.cpp
Normal file
537
DDrawCompat/CompatGdiSurface.cpp
Normal file
@ -0,0 +1,537 @@
|
||||
#define CINTERFACE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <oleacc.h>
|
||||
#include <Windows.h>
|
||||
#include <detours.h>
|
||||
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdiSurface.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "DDrawLog.h"
|
||||
#include "DDrawProcs.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CaretData
|
||||
{
|
||||
HWND hwnd;
|
||||
long left;
|
||||
long top;
|
||||
long width;
|
||||
long height;
|
||||
bool isDrawn;
|
||||
};
|
||||
|
||||
struct GdiSurface
|
||||
{
|
||||
IDirectDrawSurface7* surface;
|
||||
HDC origDc;
|
||||
};
|
||||
|
||||
struct ExcludeClipRectsData
|
||||
{
|
||||
HDC compatDc;
|
||||
POINT clientOrigin;
|
||||
HWND rootWnd;
|
||||
};
|
||||
|
||||
bool g_suppressGdiHooks = false;
|
||||
|
||||
class HookRecursionGuard
|
||||
{
|
||||
public:
|
||||
HookRecursionGuard()
|
||||
{
|
||||
g_suppressGdiHooks = true;
|
||||
}
|
||||
|
||||
~HookRecursionGuard()
|
||||
{
|
||||
g_suppressGdiHooks = false;
|
||||
}
|
||||
};
|
||||
|
||||
auto g_origGetDc = &GetDC;
|
||||
auto g_origGetDcEx = &GetDCEx;
|
||||
auto g_origGetWindowDc = &GetWindowDC;
|
||||
auto g_origReleaseDc = &ReleaseDC;
|
||||
auto g_origBeginPaint = &BeginPaint;
|
||||
auto g_origEndPaint = &EndPaint;
|
||||
|
||||
auto g_origCreateCaret = &CreateCaret;
|
||||
auto g_origShowCaret = &ShowCaret;
|
||||
auto g_origHideCaret = &HideCaret;
|
||||
|
||||
IDirectDraw7* g_directDraw = nullptr;
|
||||
std::unordered_map<HDC, GdiSurface> g_dcToSurface;
|
||||
|
||||
CaretData g_caret = {};
|
||||
|
||||
POINT getClientOrigin(HWND hwnd);
|
||||
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin);
|
||||
HDC releaseCompatDc(HDC hdc);
|
||||
|
||||
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (HC_ACTION == nCode)
|
||||
{
|
||||
auto ret = reinterpret_cast<CWPRETSTRUCT*>(lParam);
|
||||
if (WM_WINDOWPOSCHANGED == ret->message)
|
||||
{
|
||||
InvalidateRect(nullptr, nullptr, TRUE);
|
||||
}
|
||||
else if (WM_ERASEBKGND == ret->message && ret->lResult)
|
||||
{
|
||||
HDC origDc = reinterpret_cast<HDC>(ret->wParam);
|
||||
if (g_dcToSurface.find(origDc) == g_dcToSurface.end())
|
||||
{
|
||||
HWND hwnd = WindowFromDC(origDc);
|
||||
POINT origin = {};
|
||||
ClientToScreen(hwnd, &origin);
|
||||
|
||||
HDC compatDc = getCompatDc(hwnd, origDc, origin);
|
||||
if (compatDc != origDc)
|
||||
{
|
||||
SendMessage(hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
|
||||
releaseCompatDc(compatDc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
IDirectDraw7* createDirectDraw()
|
||||
{
|
||||
IDirectDraw7* dd = nullptr;
|
||||
CALL_ORIG_DDRAW(DirectDrawCreateEx, nullptr, reinterpret_cast<LPVOID*>(&dd), IID_IDirectDraw7, nullptr);
|
||||
if (!dd)
|
||||
{
|
||||
Compat::Log() << "Failed to create a DirectDraw interface for GDI";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(CompatDirectDraw<IDirectDraw7>::s_origVtable.SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL)))
|
||||
{
|
||||
Compat::Log() << "Failed to set the cooperative level on the DirectDraw interface for GDI";
|
||||
dd->lpVtbl->Release(dd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return dd;
|
||||
}
|
||||
|
||||
IDirectDrawSurface7* createGdiSurface()
|
||||
{
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
||||
desc.dwWidth = CompatPrimarySurface::width;
|
||||
desc.dwHeight = CompatPrimarySurface::height;
|
||||
desc.ddpfPixelFormat = CompatPrimarySurface::pixelFormat;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||
desc.lPitch = CompatPrimarySurface::pitch;
|
||||
desc.lpSurface = CompatPrimarySurface::surfacePtr;
|
||||
|
||||
IDirectDrawSurface7* surface = nullptr;
|
||||
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
||||
g_directDraw, &desc, &surface, nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to create a GDI surface: " << result);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (CompatPrimarySurface::palette)
|
||||
{
|
||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
|
||||
surface, CompatPrimarySurface::palette);
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
||||
if (hwnd == excludeClipRectsData->rootWnd)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RECT rect = {};
|
||||
GetWindowRect(hwnd, &rect);
|
||||
OffsetRect(&rect, -excludeClipRectsData->clientOrigin.x, -excludeClipRectsData->clientOrigin.y);
|
||||
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
POINT getClientOrigin(HWND hwnd)
|
||||
{
|
||||
POINT origin = {};
|
||||
if (hwnd)
|
||||
{
|
||||
ClientToScreen(hwnd, &origin);
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
|
||||
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin)
|
||||
{
|
||||
if (!CompatPrimarySurface::surfacePtr || !origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
||||
{
|
||||
return origDc;
|
||||
}
|
||||
|
||||
HookRecursionGuard recursionGuard;
|
||||
|
||||
IDirectDrawSurface7* surface = createGdiSurface();
|
||||
if (!surface)
|
||||
{
|
||||
return origDc;
|
||||
}
|
||||
|
||||
HDC compatDc = nullptr;
|
||||
HRESULT result = surface->lpVtbl->GetDC(surface, &compatDc);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to create a GDI DC: " << result);
|
||||
surface->lpVtbl->Release(surface);
|
||||
return origDc;
|
||||
}
|
||||
|
||||
if (hwnd)
|
||||
{
|
||||
SetWindowOrgEx(compatDc, -origin.x, -origin.y, nullptr);
|
||||
|
||||
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
|
||||
GetRandomRgn(origDc, clipRgn, SYSRGN);
|
||||
SelectClipRgn(compatDc, clipRgn);
|
||||
RECT r = {};
|
||||
GetRgnBox(clipRgn, &r);
|
||||
DeleteObject(clipRgn);
|
||||
|
||||
ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) };
|
||||
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
|
||||
reinterpret_cast<LPARAM>(&excludeClipRectsData));
|
||||
}
|
||||
|
||||
GdiSurface gdiSurface = { surface, origDc };
|
||||
g_dcToSurface[compatDc] = gdiSurface;
|
||||
|
||||
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
FARPROC getProcAddress(HMODULE module, const char* procName)
|
||||
{
|
||||
if (!module || !procName)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(module);
|
||||
if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic) {
|
||||
return nullptr;
|
||||
}
|
||||
char* moduleBase = reinterpret_cast<char*>(module);
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(
|
||||
reinterpret_cast<char*>(dosHeader) + dosHeader->e_lfanew);
|
||||
if (IMAGE_NT_SIGNATURE != ntHeader->Signature)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_EXPORT_DIRECTORY exportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
|
||||
moduleBase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
|
||||
DWORD* rvaOfNames = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfNames);
|
||||
|
||||
for (DWORD i = 0; i < exportDir->NumberOfNames; ++i)
|
||||
{
|
||||
if (0 == strcmp(procName, moduleBase + rvaOfNames[i]))
|
||||
{
|
||||
WORD* nameOrds = reinterpret_cast<WORD*>(moduleBase + exportDir->AddressOfNameOrdinals);
|
||||
DWORD* rvaOfFunctions = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfFunctions);
|
||||
return reinterpret_cast<FARPROC>(moduleBase + rvaOfFunctions[nameOrds[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
POINT getWindowOrigin(HWND hwnd)
|
||||
{
|
||||
POINT origin = {};
|
||||
if (hwnd)
|
||||
{
|
||||
RECT windowRect = {};
|
||||
GetWindowRect(hwnd, &windowRect);
|
||||
origin.x = windowRect.left;
|
||||
origin.y = windowRect.top;
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
|
||||
template <typename FuncPtr>
|
||||
void hookGdiFunction(const char* funcName, FuncPtr& origFuncPtr, FuncPtr newFuncPtr)
|
||||
{
|
||||
origFuncPtr = reinterpret_cast<FuncPtr>(getProcAddress(GetModuleHandle("user32"), funcName));
|
||||
DetourAttach(reinterpret_cast<void**>(&origFuncPtr), newFuncPtr);
|
||||
}
|
||||
|
||||
HDC releaseCompatDc(HDC hdc)
|
||||
{
|
||||
if (g_suppressGdiHooks)
|
||||
{
|
||||
return hdc;
|
||||
}
|
||||
|
||||
HookRecursionGuard recursionGuard;
|
||||
|
||||
auto it = g_dcToSurface.find(hdc);
|
||||
|
||||
if (it != g_dcToSurface.end())
|
||||
{
|
||||
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
|
||||
if (FAILED(it->second.surface->lpVtbl->ReleaseDC(it->second.surface, hdc)))
|
||||
{
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
}
|
||||
|
||||
it->second.surface->lpVtbl->Release(it->second.surface);
|
||||
|
||||
HDC origDc = it->second.origDc;
|
||||
g_dcToSurface.erase(it);
|
||||
|
||||
RealPrimarySurface::update();
|
||||
return origDc;
|
||||
}
|
||||
|
||||
return hdc;
|
||||
}
|
||||
|
||||
void drawCaret()
|
||||
{
|
||||
HDC dc = GetDC(g_caret.hwnd);
|
||||
PatBlt(dc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT);
|
||||
ReleaseDC(g_caret.hwnd, dc);
|
||||
}
|
||||
|
||||
LONG getCaretState(IAccessible* accessible)
|
||||
{
|
||||
VARIANT varChild = {};
|
||||
varChild.vt = VT_I4;
|
||||
varChild.lVal = CHILDID_SELF;
|
||||
VARIANT varState = {};
|
||||
accessible->lpVtbl->get_accState(accessible, varChild, &varState);
|
||||
return varState.lVal;
|
||||
}
|
||||
|
||||
void CALLBACK caretDestroyEvent(
|
||||
HWINEVENTHOOK /*hWinEventHook*/,
|
||||
DWORD /*event*/,
|
||||
HWND hwnd,
|
||||
LONG idObject,
|
||||
LONG idChild,
|
||||
DWORD /*dwEventThread*/,
|
||||
DWORD /*dwmsEventTime*/)
|
||||
{
|
||||
if (OBJID_CARET != idObject || !g_caret.isDrawn || g_caret.hwnd != hwnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IAccessible* accessible = nullptr;
|
||||
VARIANT varChild = {};
|
||||
AccessibleObjectFromEvent(hwnd, idObject, idChild, &accessible, &varChild);
|
||||
if (accessible)
|
||||
{
|
||||
if (STATE_SYSTEM_INVISIBLE == getCaretState(accessible))
|
||||
{
|
||||
drawCaret();
|
||||
g_caret.isDrawn = false;
|
||||
}
|
||||
accessible->lpVtbl->Release(accessible);
|
||||
}
|
||||
}
|
||||
|
||||
HDC WINAPI getDc(HWND hWnd)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("GetDC", hWnd);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origGetDc(hWnd), getClientOrigin(hWnd));
|
||||
|
||||
Compat::LogLeave("GetDC", hWnd) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
HDC WINAPI getDcEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("GetDCEx", hWnd);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origGetDcEx(hWnd, hrgnClip, flags),
|
||||
flags & (DCX_WINDOW | DCX_PARENTCLIP) ? getWindowOrigin(hWnd) : getClientOrigin(hWnd));
|
||||
|
||||
Compat::LogLeave("GetDCEx", hWnd) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
HDC WINAPI getWindowDc(HWND hWnd)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("GetWindowDC", hWnd);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origGetWindowDc(hWnd), getWindowOrigin(hWnd));
|
||||
|
||||
Compat::LogLeave("GetWindowDC", hWnd) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
int WINAPI releaseDc(HWND hWnd, HDC hDC)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("ReleaseDC", hWnd, hDC);
|
||||
|
||||
int result = g_origReleaseDc(hWnd, releaseCompatDc(hDC));
|
||||
|
||||
Compat::LogLeave("ReleaseDC", hWnd, hDC) << result;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return result;
|
||||
}
|
||||
|
||||
HDC WINAPI beginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("BeginPaint", hWnd, lpPaint);
|
||||
|
||||
HDC compatDc = getCompatDc(hWnd, g_origBeginPaint(hWnd, lpPaint), getClientOrigin(hWnd));
|
||||
lpPaint->hdc = compatDc;
|
||||
|
||||
Compat::LogLeave("BeginPaint", hWnd, lpPaint) << compatDc;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return compatDc;
|
||||
}
|
||||
|
||||
BOOL WINAPI endPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter("EndPaint", hWnd, lpPaint);
|
||||
|
||||
BOOL result = FALSE;
|
||||
if (lpPaint)
|
||||
{
|
||||
PAINTSTRUCT paint = *lpPaint;
|
||||
paint.hdc = releaseCompatDc(lpPaint->hdc);
|
||||
result = g_origEndPaint(hWnd, &paint);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = g_origEndPaint(hWnd, lpPaint);
|
||||
}
|
||||
|
||||
Compat::LogLeave("EndPaint", hWnd, lpPaint) << result;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI createCaret(HWND hWnd, HBITMAP hBitmap, int nWidth, int nHeight)
|
||||
{
|
||||
BOOL result = g_origCreateCaret(hWnd, hBitmap, nWidth, nHeight);
|
||||
if (result)
|
||||
{
|
||||
if (g_caret.isDrawn)
|
||||
{
|
||||
drawCaret();
|
||||
g_caret.isDrawn = false;
|
||||
}
|
||||
g_caret.width = nWidth ? nWidth : GetSystemMetrics(SM_CXBORDER);
|
||||
g_caret.height = nHeight ? nHeight : GetSystemMetrics(SM_CYBORDER);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI showCaret(HWND hWnd)
|
||||
{
|
||||
BOOL result = g_origShowCaret(hWnd);
|
||||
if (result && !g_caret.isDrawn)
|
||||
{
|
||||
IAccessible* accessible = nullptr;
|
||||
AccessibleObjectFromWindow(hWnd, static_cast<DWORD>(OBJID_CARET), IID_IAccessible,
|
||||
reinterpret_cast<void**>(&accessible));
|
||||
if (accessible)
|
||||
{
|
||||
if (0 == getCaretState(accessible))
|
||||
{
|
||||
POINT caretPos = {};
|
||||
GetCaretPos(&caretPos);
|
||||
g_caret.left = caretPos.x;
|
||||
g_caret.top = caretPos.y;
|
||||
g_caret.hwnd = hWnd;
|
||||
drawCaret();
|
||||
g_caret.isDrawn = true;
|
||||
}
|
||||
accessible->lpVtbl->Release(accessible);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI hideCaret(HWND hWnd)
|
||||
{
|
||||
BOOL result = g_origHideCaret(hWnd);
|
||||
if (result && g_caret.isDrawn)
|
||||
{
|
||||
drawCaret();
|
||||
g_caret.isDrawn = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void CompatGdiSurface::hookGdi()
|
||||
{
|
||||
static bool alreadyHooked = false;
|
||||
if (alreadyHooked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_directDraw = createDirectDraw();
|
||||
if (g_directDraw)
|
||||
{
|
||||
DetourTransactionBegin();
|
||||
hookGdiFunction("GetDC", g_origGetDc, &getDc);
|
||||
hookGdiFunction("GetDCEx", g_origGetDcEx, &getDcEx);
|
||||
hookGdiFunction("GetWindowDC", g_origGetWindowDc, &getWindowDc);
|
||||
hookGdiFunction("ReleaseDC", g_origReleaseDc, &releaseDc);
|
||||
hookGdiFunction("BeginPaint", g_origBeginPaint, &beginPaint);
|
||||
hookGdiFunction("EndPaint", g_origEndPaint, &endPaint);
|
||||
hookGdiFunction("CreateCaret", g_origCreateCaret, &createCaret);
|
||||
hookGdiFunction("ShowCaret", g_origShowCaret, &showCaret);
|
||||
hookGdiFunction("HideCaret", g_origHideCaret, &hideCaret);
|
||||
DetourTransactionCommit();
|
||||
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId);
|
||||
SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY,
|
||||
nullptr, &caretDestroyEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
|
||||
}
|
||||
alreadyHooked = true;
|
||||
}
|
7
DDrawCompat/CompatGdiSurface.h
Normal file
7
DDrawCompat/CompatGdiSurface.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
class CompatGdiSurface
|
||||
{
|
||||
public:
|
||||
static void hookGdi();
|
||||
};
|
51
DDrawCompat/CompatPrimarySurface.cpp
Normal file
51
DDrawCompat/CompatPrimarySurface.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "IReleaseNotifier.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
void onRelease()
|
||||
{
|
||||
CompatPrimarySurface::surface = nullptr;
|
||||
CompatPrimarySurface::palette = nullptr;
|
||||
CompatPrimarySurface::width = 0;
|
||||
CompatPrimarySurface::height = 0;
|
||||
ZeroMemory(&CompatPrimarySurface::pixelFormat, sizeof(CompatPrimarySurface::pixelFormat));
|
||||
CompatPrimarySurface::pitch = 0;
|
||||
CompatPrimarySurface::surfacePtr = nullptr;
|
||||
|
||||
RealPrimarySurface::release();
|
||||
}
|
||||
}
|
||||
|
||||
namespace CompatPrimarySurface
|
||||
{
|
||||
template <typename TDirectDraw>
|
||||
DisplayMode getDisplayMode(TDirectDraw& dd)
|
||||
{
|
||||
DisplayMode dm = {};
|
||||
typename CompatDirectDraw<TDirectDraw>::TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
CompatDirectDraw<TDirectDraw>::s_origVtable.GetDisplayMode(&dd, &desc);
|
||||
dm.width = desc.dwWidth;
|
||||
dm.height = desc.dwHeight;
|
||||
dm.pixelFormat = desc.ddpfPixelFormat;
|
||||
return dm;
|
||||
}
|
||||
|
||||
template DisplayMode getDisplayMode(IDirectDraw& dd);
|
||||
template DisplayMode getDisplayMode(IDirectDraw2& dd);
|
||||
template DisplayMode getDisplayMode(IDirectDraw4& dd);
|
||||
template DisplayMode getDisplayMode(IDirectDraw7& dd);
|
||||
|
||||
DisplayMode displayMode = {};
|
||||
IDirectDrawSurface7* surface = nullptr;
|
||||
LPDIRECTDRAWPALETTE palette = nullptr;
|
||||
LONG width = 0;
|
||||
LONG height = 0;
|
||||
DDPIXELFORMAT pixelFormat = {};
|
||||
LONG pitch = 0;
|
||||
void* surfacePtr = nullptr;
|
||||
IReleaseNotifier releaseNotifier(onRelease);
|
||||
}
|
30
DDrawCompat/CompatPrimarySurface.h
Normal file
30
DDrawCompat/CompatPrimarySurface.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
class IReleaseNotifier;
|
||||
|
||||
namespace CompatPrimarySurface
|
||||
{
|
||||
struct DisplayMode
|
||||
{
|
||||
LONG width;
|
||||
LONG height;
|
||||
DDPIXELFORMAT pixelFormat;
|
||||
};
|
||||
|
||||
template <typename TDirectDraw>
|
||||
DisplayMode getDisplayMode(TDirectDraw& dd);
|
||||
|
||||
extern DisplayMode displayMode;
|
||||
extern IDirectDrawSurface7* surface;
|
||||
extern LPDIRECTDRAWPALETTE palette;
|
||||
extern LONG width;
|
||||
extern LONG height;
|
||||
extern DDPIXELFORMAT pixelFormat;
|
||||
extern LONG pitch;
|
||||
extern void* surfacePtr;
|
||||
extern IReleaseNotifier releaseNotifier;
|
||||
}
|
6
DDrawCompat/CompatVtable.cpp
Normal file
6
DDrawCompat/CompatVtable.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "CompatVtable.h"
|
||||
|
||||
namespace Compat
|
||||
{
|
||||
std::map<void*, DetouredMethodInfo> detouredMethods;
|
||||
}
|
175
DDrawCompat/CompatVtable.h
Normal file
175
DDrawCompat/CompatVtable.h
Normal file
@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <detours.h>
|
||||
|
||||
#include "DDrawLog.h"
|
||||
#include "DDrawVtableVisitor.h"
|
||||
|
||||
template <typename Interface>
|
||||
using Vtable = typename std::remove_pointer<decltype(Interface::lpVtbl)>::type;
|
||||
|
||||
namespace Compat
|
||||
{
|
||||
struct DetouredMethodInfo
|
||||
{
|
||||
DetouredMethodInfo(void*& updatedOrigMethodPtr, std::map<void*, void*>& vtablePtrToCompatVtable)
|
||||
: updatedOrigMethodPtr(updatedOrigMethodPtr), vtablePtrToCompatVtable(vtablePtrToCompatVtable)
|
||||
{
|
||||
}
|
||||
|
||||
void*& updatedOrigMethodPtr;
|
||||
std::map<void*, void*>& vtablePtrToCompatVtable;
|
||||
};
|
||||
|
||||
extern std::map<void*, DetouredMethodInfo> detouredMethods;
|
||||
}
|
||||
|
||||
template <typename CompatInterface, typename Interface>
|
||||
class CompatVtable
|
||||
{
|
||||
public:
|
||||
typedef Interface Interface;
|
||||
|
||||
static void hookVtable(Interface& intf)
|
||||
{
|
||||
static bool isInitialized = false;
|
||||
if (!isInitialized)
|
||||
{
|
||||
isInitialized = true;
|
||||
|
||||
s_vtablePtr = intf.lpVtbl;
|
||||
s_origVtable = *intf.lpVtbl;
|
||||
|
||||
DetourTransactionBegin();
|
||||
InitVisitor visitor;
|
||||
forEach<Vtable<Interface>>(visitor);
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
}
|
||||
|
||||
static Vtable<Interface> s_origVtable;
|
||||
|
||||
private:
|
||||
class InitVisitor
|
||||
{
|
||||
public:
|
||||
template <typename MemberDataPtr, MemberDataPtr ptr>
|
||||
void visit(const std::string& vtableTypeName, const std::string& funcName)
|
||||
{
|
||||
s_funcNames[getKey<MemberDataPtr, ptr>()] = vtableTypeName + "::" + funcName;
|
||||
|
||||
if (!(s_compatVtable.*ptr))
|
||||
{
|
||||
s_compatVtable.*ptr = s_origVtable.*ptr;
|
||||
s_threadSafeVtable.*ptr = s_origVtable.*ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_threadSafeVtable.*ptr = getThreadSafeFuncPtr<MemberDataPtr, ptr>(s_compatVtable.*ptr);
|
||||
hookMethod(reinterpret_cast<void*&>(s_origVtable.*ptr), s_threadSafeVtable.*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Result, typename... Params>
|
||||
using FuncPtr = Result(STDMETHODCALLTYPE *)(Params...);
|
||||
|
||||
template <typename MemberDataPtr, MemberDataPtr ptr>
|
||||
static std::vector<unsigned char> getKey()
|
||||
{
|
||||
MemberDataPtr mp = ptr;
|
||||
unsigned char* p = reinterpret_cast<unsigned char*>(&mp);
|
||||
return std::vector<unsigned char>(p, p + sizeof(mp));
|
||||
}
|
||||
|
||||
template <typename MemberDataPtr, MemberDataPtr ptr, typename Result, typename... Params>
|
||||
static FuncPtr<Result, Params...> getThreadSafeFuncPtr(FuncPtr<Result, Params...>)
|
||||
{
|
||||
return &threadSafeFunc<MemberDataPtr, ptr, Result, Params...>;
|
||||
}
|
||||
|
||||
void hookMethod(void*& origMethodPtr, void* newMethodPtr)
|
||||
{
|
||||
auto it = Compat::detouredMethods.find(origMethodPtr);
|
||||
if (it != Compat::detouredMethods.end())
|
||||
{
|
||||
origMethodPtr = it->second.updatedOrigMethodPtr;
|
||||
it->second.vtablePtrToCompatVtable[s_vtablePtr] = &s_compatVtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
DetourAttach(&origMethodPtr, newMethodPtr);
|
||||
s_vtablePtrToCompatVtable[s_vtablePtr] = &s_compatVtable;
|
||||
Compat::detouredMethods.emplace(origMethodPtr,
|
||||
Compat::DetouredMethodInfo(origMethodPtr, s_vtablePtrToCompatVtable));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MemberDataPtr, MemberDataPtr ptr, typename Result, typename IntfPtr, typename... Params>
|
||||
static Result STDMETHODCALLTYPE threadSafeFunc(IntfPtr This, Params... params)
|
||||
{
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
Compat::LogEnter(s_funcNames[getKey<MemberDataPtr, ptr>()].c_str(), This, params...);
|
||||
|
||||
Result result;
|
||||
auto it = s_vtablePtrToCompatVtable.find(This->lpVtbl);
|
||||
if (it != s_vtablePtrToCompatVtable.end())
|
||||
{
|
||||
Vtable<Interface>& compatVtable = *static_cast<Vtable<Interface>*>(it->second);
|
||||
result = (compatVtable.*ptr)(This, params...);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (s_origVtable.*ptr)(This, params...);
|
||||
}
|
||||
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
Compat::LogLeave(s_funcNames[getKey<MemberDataPtr, ptr>()].c_str(), This, params...) << result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
static Vtable<Interface> createCompatVtable()
|
||||
{
|
||||
Vtable<Interface> vtable = {};
|
||||
CompatInterface::setCompatVtable(vtable);
|
||||
return vtable;
|
||||
}
|
||||
|
||||
static Vtable<Interface>& getCompatVtable()
|
||||
{
|
||||
static Vtable<Interface> vtable(createCompatVtable());
|
||||
return vtable;
|
||||
}
|
||||
|
||||
static Vtable<Interface>* s_vtablePtr;
|
||||
static Vtable<Interface> s_compatVtable;
|
||||
static Vtable<Interface> s_threadSafeVtable;
|
||||
static std::map<void*, void*> s_vtablePtrToCompatVtable;
|
||||
static std::map<std::vector<unsigned char>, std::string> s_funcNames;
|
||||
};
|
||||
|
||||
template <typename CompatInterface, typename Interface>
|
||||
Vtable<Interface>* CompatVtable<CompatInterface, Interface>::s_vtablePtr = nullptr;
|
||||
|
||||
template <typename CompatInterface, typename Interface>
|
||||
Vtable<Interface> CompatVtable<CompatInterface, Interface>::s_origVtable = {};
|
||||
|
||||
template <typename CompatInterface, typename Interface>
|
||||
Vtable<Interface> CompatVtable<CompatInterface, Interface>::s_compatVtable(CompatInterface::getCompatVtable());
|
||||
|
||||
template <typename CompatInterface, typename Interface>
|
||||
Vtable<Interface> CompatVtable<CompatInterface, Interface>::s_threadSafeVtable = {};
|
||||
|
||||
template <typename CompatInterface, typename Interface>
|
||||
std::map<void*, void*> CompatVtable<CompatInterface, Interface>::s_vtablePtrToCompatVtable;
|
||||
|
||||
template <typename CompatInterface, typename Interface>
|
||||
std::map<std::vector<unsigned char>, std::string> CompatVtable<CompatInterface, Interface>::s_funcNames;
|
10
DDrawCompat/Config.h
Normal file
10
DDrawCompat/Config.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
namespace Config
|
||||
{
|
||||
const DWORD minRefreshInterval = 1000 / 60;
|
||||
const DWORD minRefreshIntervalAfterFlip = 1000 / 10;
|
||||
const DWORD minPaletteUpdateInterval = 1000 / 60;
|
||||
}
|
26
DDrawCompat/DDrawCompat.def
Normal file
26
DDrawCompat/DDrawCompat.def
Normal file
@ -0,0 +1,26 @@
|
||||
LIBRARY ddraw
|
||||
|
||||
EXPORTS
|
||||
AcquireDDThreadLock
|
||||
CompleteCreateSysmemSurface
|
||||
D3DParseUnknownCommand
|
||||
DDGetAttachedSurfaceLcl
|
||||
DDInternalLock
|
||||
DDInternalUnlock
|
||||
DSoundHelp
|
||||
DirectDrawCreate
|
||||
DirectDrawCreateClipper
|
||||
DirectDrawCreateEx
|
||||
DirectDrawEnumerateA
|
||||
DirectDrawEnumerateExA
|
||||
DirectDrawEnumerateExW
|
||||
DirectDrawEnumerateW
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
GetDDSurfaceLocal
|
||||
GetOLEThunkData
|
||||
GetSurfaceFromDC
|
||||
RegisterSpecialCase
|
||||
ReleaseDDThreadLock
|
||||
SetAppCompatData
|
||||
DirectInputCreateA
|
184
DDrawCompat/DDrawCompat.vcxproj
Normal file
184
DDrawCompat/DDrawCompat.vcxproj
Normal file
@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{1146187A-17DE-4350-B9D1-9F9EAA934908}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>DDrawCompat</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetName>ddraw</TargetName>
|
||||
<IncludePath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\lib.X86;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetName>ddraw</TargetName>
|
||||
<IncludePath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\lib.X86;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>No</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CompatDirectDrawPalette.h" />
|
||||
<ClInclude Include="CompatGdiSurface.h" />
|
||||
<ClInclude Include="Config.h" />
|
||||
<ClInclude Include="DDrawProcs.h" />
|
||||
<ClInclude Include="CompatDirectDraw.h" />
|
||||
<ClInclude Include="CompatPrimarySurface.h" />
|
||||
<ClInclude Include="DDrawTypes.h" />
|
||||
<ClInclude Include="CompatDirectDrawSurface.h" />
|
||||
<ClInclude Include="DDrawVtableVisitor.h" />
|
||||
<ClInclude Include="CompatVtable.h" />
|
||||
<ClInclude Include="DirectDrawPaletteVtblVisitor.h" />
|
||||
<ClInclude Include="DirectDrawSurfaceVtblVisitor.h" />
|
||||
<ClInclude Include="DirectDrawVtblVisitor.h" />
|
||||
<ClInclude Include="DDrawLog.h" />
|
||||
<ClInclude Include="IReleaseNotifier.h" />
|
||||
<ClInclude Include="RealPrimarySurface.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CompatDirectDraw.cpp" />
|
||||
<ClCompile Include="CompatDirectDrawPalette.cpp" />
|
||||
<ClCompile Include="CompatDirectDrawSurface.cpp" />
|
||||
<ClCompile Include="CompatGdiSurface.cpp" />
|
||||
<ClCompile Include="CompatVtable.cpp" />
|
||||
<ClCompile Include="DDrawLog.cpp" />
|
||||
<ClCompile Include="DllMain.cpp" />
|
||||
<ClCompile Include="CompatPrimarySurface.cpp" />
|
||||
<ClCompile Include="DDrawProcs.cpp" />
|
||||
<ClCompile Include="IReleaseNotifier.cpp" />
|
||||
<ClCompile Include="RealPrimarySurface.cpp" />
|
||||
<ClCompile Include="UnmodifiedDDrawProcs.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="DDrawCompat.def" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
110
DDrawCompat/DDrawCompat.vcxproj.filters
Normal file
110
DDrawCompat/DDrawCompat.vcxproj.filters
Normal file
@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DDrawProcs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatDirectDraw.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DDrawTypes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatDirectDrawSurface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DDrawVtableVisitor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatVtable.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DDrawLog.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DirectDrawSurfaceVtblVisitor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DirectDrawVtblVisitor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DirectDrawPaletteVtblVisitor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatDirectDrawPalette.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatGdiSurface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RealPrimarySurface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatPrimarySurface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IReleaseNotifier.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DllMain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UnmodifiedDDrawProcs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DDrawProcs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DDrawLog.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RealPrimarySurface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatPrimarySurface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatGdiSurface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IReleaseNotifier.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatVtable.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatDirectDraw.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatDirectDrawSurface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatDirectDrawPalette.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="DDrawCompat.def">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
39
DDrawCompat/DDrawLog.cpp
Normal file
39
DDrawCompat/DDrawLog.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "DDrawLog.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, LPRECT rect)
|
||||
{
|
||||
if (rect)
|
||||
{
|
||||
os << "RECT(" << rect->left << ',' << rect->top << ',' << rect->right << ',' << rect->bottom << ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "NullRect";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace Compat
|
||||
{
|
||||
Log::Log()
|
||||
{
|
||||
SYSTEMTIME st = {};
|
||||
GetLocalTime(&st);
|
||||
|
||||
char time[100];
|
||||
sprintf_s(time, "%02hu:%02hu:%02hu.%03hu ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||
|
||||
s_logFile << GetCurrentThreadId() << " " << time;
|
||||
}
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
s_logFile << std::endl;
|
||||
}
|
||||
|
||||
std::ofstream Log::s_logFile("ddraw.log");
|
||||
}
|
104
DDrawCompat/DDrawLog.h
Normal file
104
DDrawCompat/DDrawLog.h
Normal file
@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <fstream>
|
||||
|
||||
struct _GUID;
|
||||
struct tagRECT;
|
||||
|
||||
#define LOG_ONCE(msg) \
|
||||
static bool isAlreadyLogged##__LINE__ = false; \
|
||||
if (!isAlreadyLogged##__LINE__) \
|
||||
{ \
|
||||
Compat::Log() << msg; \
|
||||
isAlreadyLogged##__LINE__ = true; \
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const _GUID& guid)
|
||||
{
|
||||
return os << &guid;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, tagRECT* rect);
|
||||
|
||||
namespace Compat
|
||||
{
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
Log();
|
||||
~Log();
|
||||
|
||||
template <typename T>
|
||||
Log& operator<<(const T& t)
|
||||
{
|
||||
s_logFile << t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename... Params>
|
||||
Log(const char* prefix, const char* funcName, Params... params) : Log()
|
||||
{
|
||||
s_logFile << prefix << ' ' << funcName << '(';
|
||||
toList(params...);
|
||||
s_logFile << ')';
|
||||
}
|
||||
|
||||
private:
|
||||
void toList()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Param>
|
||||
void toList(Param param)
|
||||
{
|
||||
s_logFile << param;
|
||||
}
|
||||
|
||||
template <typename Param, typename... Params>
|
||||
void toList(Param firstParam, Params... remainingParams)
|
||||
{
|
||||
s_logFile << firstParam << ", ";
|
||||
toList(remainingParams...);
|
||||
}
|
||||
|
||||
static std::ofstream s_logFile;
|
||||
};
|
||||
|
||||
#ifdef _DEBUG
|
||||
class LogEnter : private Log
|
||||
{
|
||||
public:
|
||||
template <typename... Params>
|
||||
LogEnter(const char* funcName, Params... params) : Log("-->", funcName, params...)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class LogLeave : private Log
|
||||
{
|
||||
public:
|
||||
template <typename... Params>
|
||||
LogLeave(const char* funcName, Params... params) : Log("<--", funcName, params...)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
void operator<<(const Result& result)
|
||||
{
|
||||
static_cast<Log&>(*this) << " = " << result;
|
||||
}
|
||||
};
|
||||
#else
|
||||
class LogEnter
|
||||
{
|
||||
public:
|
||||
template <typename... Params> LogEnter(const char*, Params...) {}
|
||||
template <typename Result> void operator<<(const Result&) {}
|
||||
};
|
||||
|
||||
typedef LogEnter LogLeave;
|
||||
#endif
|
||||
}
|
6
DDrawCompat/DDrawProcs.cpp
Normal file
6
DDrawCompat/DDrawProcs.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "DDrawProcs.h"
|
||||
|
||||
namespace Compat
|
||||
{
|
||||
DDrawProcs origProcs = {};
|
||||
}
|
55
DDrawCompat/DDrawProcs.h
Normal file
55
DDrawCompat/DDrawProcs.h
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#define VISIT_UNMODIFIED_DDRAW_PROCS(visit) \
|
||||
visit(AcquireDDThreadLock) \
|
||||
visit(CompleteCreateSysmemSurface) \
|
||||
visit(D3DParseUnknownCommand) \
|
||||
visit(DDGetAttachedSurfaceLcl) \
|
||||
visit(DDInternalLock) \
|
||||
visit(DDInternalUnlock) \
|
||||
visit(DSoundHelp) \
|
||||
visit(DirectDrawCreateClipper) \
|
||||
visit(DirectDrawEnumerateA) \
|
||||
visit(DirectDrawEnumerateExA) \
|
||||
visit(DirectDrawEnumerateExW) \
|
||||
visit(DirectDrawEnumerateW) \
|
||||
visit(DllCanUnloadNow) \
|
||||
visit(DllGetClassObject) \
|
||||
visit(GetDDSurfaceLocal) \
|
||||
visit(GetOLEThunkData) \
|
||||
visit(GetSurfaceFromDC) \
|
||||
visit(RegisterSpecialCase) \
|
||||
visit(ReleaseDDThreadLock) \
|
||||
visit(SetAppCompatData)
|
||||
|
||||
#define VISIT_MODIFIED_DDRAW_PROCS(visit) \
|
||||
visit(DirectDrawCreate) \
|
||||
visit(DirectDrawCreateEx)
|
||||
|
||||
#define VISIT_ALL_DDRAW_PROCS(visit) \
|
||||
VISIT_UNMODIFIED_DDRAW_PROCS(visit) \
|
||||
VISIT_MODIFIED_DDRAW_PROCS(visit)
|
||||
|
||||
#define ADD_FARPROC_MEMBER(memberName) FARPROC memberName;
|
||||
|
||||
namespace Compat
|
||||
{
|
||||
struct DDrawProcs
|
||||
{
|
||||
VISIT_ALL_DDRAW_PROCS(ADD_FARPROC_MEMBER);
|
||||
FARPROC DirectInputCreateA;
|
||||
};
|
||||
|
||||
extern DDrawProcs origProcs;
|
||||
}
|
||||
|
||||
#undef ADD_FARPROC_MEMBER
|
||||
|
||||
#define CALL_ORIG_DDRAW(procName, ...) \
|
||||
(Compat::origProcs.procName ? \
|
||||
reinterpret_cast<decltype(procName)*>(Compat::origProcs.procName)(__VA_ARGS__) : \
|
||||
E_FAIL)
|
79
DDrawCompat/DDrawTypes.h
Normal file
79
DDrawCompat/DDrawTypes.h
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
struct DDrawTypes
|
||||
{
|
||||
typedef IDirectDrawSurface TSurface;
|
||||
typedef IDirectDrawSurface TCreatedSurface;
|
||||
typedef DDSURFACEDESC TSurfaceDesc;
|
||||
typedef DDSCAPS TDdsCaps;
|
||||
typedef LPDDENUMSURFACESCALLBACK TEnumSurfacesCallbackPtr;
|
||||
typedef LPVOID TUnlockParam;
|
||||
};
|
||||
|
||||
struct DDrawTypes2
|
||||
{
|
||||
typedef IDirectDrawSurface2 TSurface;
|
||||
typedef IDirectDrawSurface TCreatedSurface;
|
||||
typedef DDSURFACEDESC TSurfaceDesc;
|
||||
typedef DDSCAPS TDdsCaps;
|
||||
typedef LPDDENUMSURFACESCALLBACK TEnumSurfacesCallbackPtr;
|
||||
typedef LPVOID TUnlockParam;
|
||||
};
|
||||
|
||||
struct DDrawTypes3
|
||||
{
|
||||
typedef IDirectDrawSurface3 TSurface;
|
||||
typedef IDirectDrawSurface3 TCreatedSurface;
|
||||
typedef DDSURFACEDESC TSurfaceDesc;
|
||||
typedef DDSCAPS TDdsCaps;
|
||||
typedef LPDDENUMSURFACESCALLBACK TEnumSurfacesCallbackPtr;
|
||||
typedef LPVOID TUnlockParam;
|
||||
};
|
||||
|
||||
struct DDrawTypes4
|
||||
{
|
||||
typedef IDirectDrawSurface4 TSurface;
|
||||
typedef IDirectDrawSurface4 TCreatedSurface;
|
||||
typedef DDSURFACEDESC2 TSurfaceDesc;
|
||||
typedef DDSCAPS2 TDdsCaps;
|
||||
typedef LPDDENUMSURFACESCALLBACK2 TEnumSurfacesCallbackPtr;
|
||||
typedef LPRECT TUnlockParam;
|
||||
};
|
||||
|
||||
struct DDrawTypes7
|
||||
{
|
||||
typedef IDirectDrawSurface7 TSurface;
|
||||
typedef IDirectDrawSurface7 TCreatedSurface;
|
||||
typedef DDSURFACEDESC2 TSurfaceDesc;
|
||||
typedef DDSCAPS2 TDdsCaps;
|
||||
typedef LPDDENUMSURFACESCALLBACK7 TEnumSurfacesCallbackPtr;
|
||||
typedef LPRECT TUnlockParam;
|
||||
};
|
||||
|
||||
template <typename Interface>
|
||||
struct Types;
|
||||
|
||||
#define DD_CONCAT(x, y, ...) x##y
|
||||
|
||||
#define DD_TYPES(Interface, ...) \
|
||||
template <> \
|
||||
struct Types<DD_CONCAT(Interface, __VA_ARGS__)> : DD_CONCAT(DDrawTypes, __VA_ARGS__) \
|
||||
{}
|
||||
|
||||
DD_TYPES(IDirectDraw);
|
||||
DD_TYPES(IDirectDraw, 2);
|
||||
DD_TYPES(IDirectDraw, 4);
|
||||
DD_TYPES(IDirectDraw, 7);
|
||||
|
||||
DD_TYPES(IDirectDrawSurface);
|
||||
DD_TYPES(IDirectDrawSurface, 2);
|
||||
DD_TYPES(IDirectDrawSurface, 3);
|
||||
DD_TYPES(IDirectDrawSurface, 4);
|
||||
DD_TYPES(IDirectDrawSurface, 7);
|
||||
|
||||
#undef DD_TYPES
|
||||
#undef DD_CONCAT
|
41
DDrawCompat/DDrawVtableVisitor.h
Normal file
41
DDrawCompat/DDrawVtableVisitor.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <ddraw.h>
|
||||
#include <typeinfo>
|
||||
|
||||
template <typename Vtable>
|
||||
struct DDrawVtableForEach;
|
||||
|
||||
template <typename Vtable, typename Visitor>
|
||||
void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<Vtable>::forEach<Vtable>(visitor);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string getTypeName()
|
||||
{
|
||||
std::string typeName(typeid(T).name());
|
||||
if (0 == typeName.find("struct "))
|
||||
{
|
||||
typeName = typeName.substr(typeName.find(" ") + 1);
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
|
||||
#define DD_VISIT(member) \
|
||||
visitor.visit<decltype(&Vtable::member), &Vtable::member>(getTypeName<Vtable>(), #member)
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IUnknownVtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DD_VISIT(QueryInterface);
|
||||
DD_VISIT(AddRef);
|
||||
DD_VISIT(Release);
|
||||
}
|
||||
};
|
18
DDrawCompat/DirectDrawPaletteVtblVisitor.h
Normal file
18
DDrawCompat/DirectDrawPaletteVtblVisitor.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "DDrawVtableVisitor.h"
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDrawPaletteVtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IUnknownVtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(GetCaps);
|
||||
DD_VISIT(GetEntries);
|
||||
DD_VISIT(Initialize);
|
||||
DD_VISIT(SetEntries);
|
||||
}
|
||||
};
|
104
DDrawCompat/DirectDrawSurfaceVtblVisitor.h
Normal file
104
DDrawCompat/DirectDrawSurfaceVtblVisitor.h
Normal file
@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include "DDrawVtableVisitor.h"
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDrawSurfaceVtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IUnknownVtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(AddAttachedSurface);
|
||||
DD_VISIT(AddOverlayDirtyRect);
|
||||
DD_VISIT(Blt);
|
||||
DD_VISIT(BltBatch);
|
||||
DD_VISIT(BltFast);
|
||||
DD_VISIT(DeleteAttachedSurface);
|
||||
DD_VISIT(EnumAttachedSurfaces);
|
||||
DD_VISIT(EnumOverlayZOrders);
|
||||
DD_VISIT(Flip);
|
||||
DD_VISIT(GetAttachedSurface);
|
||||
DD_VISIT(GetBltStatus);
|
||||
DD_VISIT(GetCaps);
|
||||
DD_VISIT(GetClipper);
|
||||
DD_VISIT(GetColorKey);
|
||||
DD_VISIT(GetDC);
|
||||
DD_VISIT(GetFlipStatus);
|
||||
DD_VISIT(GetOverlayPosition);
|
||||
DD_VISIT(GetPalette);
|
||||
DD_VISIT(GetPixelFormat);
|
||||
DD_VISIT(GetSurfaceDesc);
|
||||
DD_VISIT(Initialize);
|
||||
DD_VISIT(IsLost);
|
||||
DD_VISIT(Lock);
|
||||
DD_VISIT(ReleaseDC);
|
||||
DD_VISIT(Restore);
|
||||
DD_VISIT(SetClipper);
|
||||
DD_VISIT(SetColorKey);
|
||||
DD_VISIT(SetOverlayPosition);
|
||||
DD_VISIT(SetPalette);
|
||||
DD_VISIT(Unlock);
|
||||
DD_VISIT(UpdateOverlay);
|
||||
DD_VISIT(UpdateOverlayDisplay);
|
||||
DD_VISIT(UpdateOverlayZOrder);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDrawSurface2Vtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IDirectDrawSurfaceVtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(GetDDInterface);
|
||||
DD_VISIT(PageLock);
|
||||
DD_VISIT(PageUnlock);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDrawSurface3Vtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IDirectDrawSurface2Vtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(SetSurfaceDesc);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDrawSurface4Vtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IDirectDrawSurface3Vtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(SetPrivateData);
|
||||
DD_VISIT(GetPrivateData);
|
||||
DD_VISIT(FreePrivateData);
|
||||
DD_VISIT(GetUniquenessValue);
|
||||
DD_VISIT(ChangeUniquenessValue);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDrawSurface7Vtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IDirectDrawSurface4Vtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(SetPriority);
|
||||
DD_VISIT(GetPriority);
|
||||
DD_VISIT(SetLOD);
|
||||
DD_VISIT(GetLOD);
|
||||
}
|
||||
};
|
74
DDrawCompat/DirectDrawVtblVisitor.h
Normal file
74
DDrawCompat/DirectDrawVtblVisitor.h
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "DDrawVtableVisitor.h"
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDrawVtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IUnknownVtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(Compact);
|
||||
DD_VISIT(CreateClipper);
|
||||
DD_VISIT(CreatePalette);
|
||||
DD_VISIT(CreateSurface);
|
||||
DD_VISIT(DuplicateSurface);
|
||||
DD_VISIT(EnumDisplayModes);
|
||||
DD_VISIT(EnumSurfaces);
|
||||
DD_VISIT(FlipToGDISurface);
|
||||
DD_VISIT(GetCaps);
|
||||
DD_VISIT(GetDisplayMode);
|
||||
DD_VISIT(GetFourCCCodes);
|
||||
DD_VISIT(GetGDISurface);
|
||||
DD_VISIT(GetMonitorFrequency);
|
||||
DD_VISIT(GetScanLine);
|
||||
DD_VISIT(GetVerticalBlankStatus);
|
||||
DD_VISIT(Initialize);
|
||||
DD_VISIT(RestoreDisplayMode);
|
||||
DD_VISIT(SetCooperativeLevel);
|
||||
DD_VISIT(SetDisplayMode);
|
||||
DD_VISIT(WaitForVerticalBlank);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDraw2Vtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IDirectDrawVtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(GetAvailableVidMem);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDraw4Vtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IDirectDraw2Vtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(GetSurfaceFromDC);
|
||||
DD_VISIT(RestoreAllSurfaces);
|
||||
DD_VISIT(TestCooperativeLevel);
|
||||
DD_VISIT(GetDeviceIdentifier);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DDrawVtableForEach<IDirectDraw7Vtbl>
|
||||
{
|
||||
template <typename Vtable, typename Visitor>
|
||||
static void forEach(Visitor& visitor)
|
||||
{
|
||||
DDrawVtableForEach<IDirectDraw4Vtbl>::forEach<Vtable>(visitor);
|
||||
|
||||
DD_VISIT(StartModeTest);
|
||||
DD_VISIT(EvaluateMode);
|
||||
}
|
||||
};
|
207
DDrawCompat/DllMain.cpp
Normal file
207
DDrawCompat/DllMain.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
#include <string>
|
||||
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatDirectDrawPalette.h"
|
||||
#include "CompatGdiSurface.h"
|
||||
#include "CompatVtable.h"
|
||||
#include "DDrawProcs.h"
|
||||
|
||||
struct IDirectInput;
|
||||
|
||||
namespace
|
||||
{
|
||||
HMODULE g_origDDrawModule = nullptr;
|
||||
HMODULE g_origDInputModule = nullptr;
|
||||
|
||||
template <typename CompatInterface>
|
||||
void hookVtable(const GUID& guid, IUnknown& unk)
|
||||
{
|
||||
typename CompatInterface::Interface* intf = nullptr;
|
||||
if (SUCCEEDED(unk.lpVtbl->QueryInterface(&unk, guid, reinterpret_cast<LPVOID*>(&intf))))
|
||||
{
|
||||
CompatInterface::hookVtable(*intf);
|
||||
intf->lpVtbl->Release(intf);
|
||||
}
|
||||
}
|
||||
|
||||
void hookDirectDraw(IDirectDraw& dd)
|
||||
{
|
||||
IUnknown& ddUnk = reinterpret_cast<IUnknown&>(dd);
|
||||
hookVtable<CompatDirectDraw<IDirectDraw>>(IID_IDirectDraw, ddUnk);
|
||||
hookVtable<CompatDirectDraw<IDirectDraw2>>(IID_IDirectDraw2, ddUnk);
|
||||
hookVtable<CompatDirectDraw<IDirectDraw4>>(IID_IDirectDraw4, ddUnk);
|
||||
hookVtable<CompatDirectDraw<IDirectDraw7>>(IID_IDirectDraw7, ddUnk);
|
||||
}
|
||||
|
||||
void hookDirectDrawSurface(IDirectDraw& dd)
|
||||
{
|
||||
DDSURFACEDESC desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
||||
desc.dwWidth = 1;
|
||||
desc.dwHeight = 1;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||
|
||||
IDirectDrawSurface* surface = nullptr;
|
||||
if (SUCCEEDED(dd.lpVtbl->CreateSurface(&dd, &desc, &surface, nullptr)))
|
||||
{
|
||||
IUnknown& surfaceUnk = reinterpret_cast<IUnknown&>(*surface);
|
||||
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface>>(IID_IDirectDrawSurface, surfaceUnk);
|
||||
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface2>>(IID_IDirectDrawSurface2, surfaceUnk);
|
||||
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface3>>(IID_IDirectDrawSurface3, surfaceUnk);
|
||||
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface4>>(IID_IDirectDrawSurface4, surfaceUnk);
|
||||
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface7>>(IID_IDirectDrawSurface7, surfaceUnk);
|
||||
surface->lpVtbl->Release(surface);
|
||||
}
|
||||
}
|
||||
|
||||
void hookDirectDrawPalette(IDirectDraw& dd)
|
||||
{
|
||||
PALETTEENTRY paletteEntries[2] = {};
|
||||
IDirectDrawPalette* palette = nullptr;
|
||||
if (SUCCEEDED(dd.lpVtbl->CreatePalette(&dd, DDPCAPS_1BIT, paletteEntries, &palette, nullptr)))
|
||||
{
|
||||
CompatDirectDrawPalette::hookVtable(*palette);
|
||||
palette->lpVtbl->Release(palette);
|
||||
}
|
||||
}
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
static bool isAlreadyInstalled = false;
|
||||
if (!isAlreadyInstalled)
|
||||
{
|
||||
Compat::Log() << "Installing DirectDraw hooks";
|
||||
IDirectDraw* dd = nullptr;
|
||||
if (SUCCEEDED(CALL_ORIG_DDRAW(DirectDrawCreate, nullptr, &dd, nullptr)))
|
||||
{
|
||||
dd->lpVtbl->SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL);
|
||||
|
||||
hookDirectDraw(*dd);
|
||||
hookDirectDrawSurface(*dd);
|
||||
hookDirectDrawPalette(*dd);
|
||||
|
||||
Compat::Log() << "Installing GDI hooks";
|
||||
CompatGdiSurface::hookGdi();
|
||||
|
||||
dd->lpVtbl->Release(dd);
|
||||
}
|
||||
Compat::Log() << "Finished installing hooks";
|
||||
isAlreadyInstalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool loadLibrary(const std::string& systemDirectory, const std::string& dllName, HMODULE& module)
|
||||
{
|
||||
const std::string systemDllPath = systemDirectory + '\\' + dllName;
|
||||
|
||||
module = LoadLibrary(systemDllPath.c_str());
|
||||
if (!module)
|
||||
{
|
||||
Compat::Log() << "Failed to load system " << dllName << " from " << systemDllPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void suppressEmulatedDirectDraw(GUID*& guid)
|
||||
{
|
||||
if (reinterpret_cast<GUID*>(DDCREATE_EMULATIONONLY) == guid)
|
||||
{
|
||||
LOG_ONCE("Warning: suppressed a request to create an emulated DirectDraw object");
|
||||
guid = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define LOAD_ORIGINAL_DDRAW_PROC(procName) \
|
||||
Compat::origProcs.procName = GetProcAddress(g_origDDrawModule, #procName);
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
char currentDllPath[MAX_PATH] = {};
|
||||
GetModuleFileName(hinstDLL, currentDllPath, MAX_PATH);
|
||||
Compat::Log() << "Loading DDrawCompat from " << currentDllPath;
|
||||
|
||||
char systemDirectory[MAX_PATH] = {};
|
||||
GetSystemDirectory(systemDirectory, MAX_PATH);
|
||||
|
||||
std::string systemDDrawDllPath = std::string(systemDirectory) + "\\ddraw.dll";
|
||||
if (0 == _stricmp(currentDllPath, systemDDrawDllPath.c_str()))
|
||||
{
|
||||
Compat::Log() << "DDrawCompat cannot be installed as the system ddraw.dll";
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!loadLibrary(systemDirectory, "ddraw.dll", g_origDDrawModule) ||
|
||||
!loadLibrary(systemDirectory, "dinput.dll", g_origDInputModule))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VISIT_ALL_DDRAW_PROCS(LOAD_ORIGINAL_DDRAW_PROC);
|
||||
Compat::origProcs.DirectInputCreateA = GetProcAddress(g_origDInputModule, "DirectInputCreateA");
|
||||
|
||||
SetProcessAffinityMask(GetCurrentProcess(), 1);
|
||||
|
||||
if (Compat::origProcs.SetAppCompatData)
|
||||
{
|
||||
typedef HRESULT WINAPI SetAppCompatDataFunc(DWORD, DWORD);
|
||||
auto setAppCompatData = reinterpret_cast<SetAppCompatDataFunc*>(Compat::origProcs.SetAppCompatData);
|
||||
const DWORD disableMaxWindowedMode = 12;
|
||||
setAppCompatData(disableMaxWindowedMode, 0);
|
||||
}
|
||||
|
||||
Compat::Log() << "DDrawCompat loaded successfully";
|
||||
}
|
||||
else if (fdwReason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
FreeLibrary(g_origDInputModule);
|
||||
FreeLibrary(g_origDDrawModule);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C" HRESULT WINAPI DirectDrawCreate(
|
||||
GUID* lpGUID,
|
||||
LPDIRECTDRAW* lplpDD,
|
||||
IUnknown* pUnkOuter)
|
||||
{
|
||||
Compat::LogEnter(__func__, lpGUID, lplpDD, pUnkOuter);
|
||||
installHooks();
|
||||
suppressEmulatedDirectDraw(lpGUID);
|
||||
HRESULT result = CALL_ORIG_DDRAW(DirectDrawCreate, lpGUID, lplpDD, pUnkOuter);
|
||||
Compat::LogLeave(__func__, lpGUID, lplpDD, pUnkOuter) << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" HRESULT WINAPI DirectDrawCreateEx(
|
||||
GUID* lpGUID,
|
||||
LPVOID* lplpDD,
|
||||
REFIID iid,
|
||||
IUnknown* pUnkOuter)
|
||||
{
|
||||
Compat::LogEnter(__func__, lpGUID, lplpDD, iid, pUnkOuter);
|
||||
installHooks();
|
||||
suppressEmulatedDirectDraw(lpGUID);
|
||||
HRESULT result = CALL_ORIG_DDRAW(DirectDrawCreateEx, lpGUID, lplpDD, iid, pUnkOuter);
|
||||
Compat::LogLeave(__func__, lpGUID, lplpDD, iid, pUnkOuter) << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" HRESULT WINAPI DirectInputCreateA(
|
||||
HINSTANCE hinst,
|
||||
DWORD dwVersion,
|
||||
IDirectInput** lplpDirectInput,
|
||||
LPUNKNOWN punkOuter)
|
||||
{
|
||||
Compat::LogEnter(__func__, hinst, dwVersion, lplpDirectInput, punkOuter);
|
||||
HRESULT result = CALL_ORIG_DDRAW(DirectInputCreateA, hinst, dwVersion, lplpDirectInput, punkOuter);
|
||||
Compat::LogLeave(__func__, hinst, dwVersion, lplpDirectInput, punkOuter) << result;
|
||||
return result;
|
||||
}
|
7
DDrawCompat/IReleaseNotifier.cpp
Normal file
7
DDrawCompat/IReleaseNotifier.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "IReleaseNotifier.h"
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
// {7810158A-CB51-448A-8706-443A7DF6D4ED}
|
||||
DEFINE_GUID(IID_IReleaseNotifier,
|
||||
0x7810158a, 0xcb51, 0x448a, 0x87, 0x6, 0x44, 0x3a, 0x7d, 0xf6, 0xd4, 0xed);
|
37
DDrawCompat/IReleaseNotifier.h
Normal file
37
DDrawCompat/IReleaseNotifier.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <Unknwnbase.h>
|
||||
|
||||
// {7810158A-CB51-448A-8706-443A7DF6D4ED}
|
||||
DEFINE_GUID(IID_IReleaseNotifier,
|
||||
0x7810158a, 0xcb51, 0x448a, 0x87, 0x6, 0x44, 0x3a, 0x7d, 0xf6, 0xd4, 0xed);
|
||||
|
||||
class IReleaseNotifier
|
||||
{
|
||||
public:
|
||||
IReleaseNotifier(const std::function<void()>& notifyHandler)
|
||||
: m_notifyHandler(notifyHandler)
|
||||
{
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*)
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
virtual ULONG STDMETHODCALLTYPE Release()
|
||||
{
|
||||
m_notifyHandler();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> m_notifyHandler;
|
||||
};
|
376
DDrawCompat/RealPrimarySurface.cpp
Normal file
376
DDrawCompat/RealPrimarySurface.cpp
Normal file
@ -0,0 +1,376 @@
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdiSurface.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "Config.h"
|
||||
#include "DDrawProcs.h"
|
||||
#include "DDrawTypes.h"
|
||||
#include "IReleaseNotifier.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
void onRelease();
|
||||
void updateNow();
|
||||
|
||||
IDirectDrawSurface7* g_frontBuffer = nullptr;
|
||||
IDirectDrawSurface7* g_backBuffer = nullptr;
|
||||
IDirectDrawSurface7* g_paletteConverterSurface = nullptr;
|
||||
IReleaseNotifier g_releaseNotifier(onRelease);
|
||||
|
||||
HANDLE g_updateThread = nullptr;
|
||||
HANDLE g_updateEvent = nullptr;
|
||||
bool g_isFlipEvent = false;
|
||||
LARGE_INTEGER g_lastUpdateTime = {};
|
||||
LARGE_INTEGER g_qpcFrequency = {};
|
||||
|
||||
bool compatBlt(IDirectDrawSurface7* dest)
|
||||
{
|
||||
Compat::LogEnter("RealPrimarySurface::compatBlt", dest);
|
||||
|
||||
bool result = false;
|
||||
const auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||
|
||||
if (!RealPrimarySurface::isFullScreen())
|
||||
{
|
||||
IDirectDrawClipper* clipper = nullptr;
|
||||
if (FAILED(origVtable.GetClipper(g_frontBuffer, &clipper)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
clipper->lpVtbl->Release(clipper);
|
||||
}
|
||||
|
||||
if (g_paletteConverterSurface)
|
||||
{
|
||||
origVtable.Blt(g_paletteConverterSurface, nullptr, CompatPrimarySurface::surface, nullptr,
|
||||
DDBLT_WAIT, nullptr);
|
||||
|
||||
HDC destDc = nullptr;
|
||||
origVtable.GetDC(dest, &destDc);
|
||||
HDC converterDc = nullptr;
|
||||
origVtable.GetDC(g_paletteConverterSurface, &converterDc);
|
||||
|
||||
result = TRUE == BitBlt(destDc, 0, 0,
|
||||
RealPrimarySurface::s_surfaceDesc.dwWidth, RealPrimarySurface::s_surfaceDesc.dwHeight,
|
||||
converterDc, 0, 0, SRCCOPY);
|
||||
|
||||
origVtable.ReleaseDC(g_paletteConverterSurface, converterDc);
|
||||
origVtable.ReleaseDC(dest, destDc);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SUCCEEDED(origVtable.Blt(
|
||||
dest, nullptr, CompatPrimarySurface::surface, nullptr, DDBLT_WAIT, nullptr));
|
||||
}
|
||||
|
||||
Compat::LogLeave("RealPrimarySurface::compatBlt", dest);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename DirectDraw>
|
||||
HRESULT createPaletteConverterSurface(DirectDraw& dd)
|
||||
{
|
||||
if (CompatPrimarySurface::displayMode.pixelFormat.dwRGBBitCount > 8 &&
|
||||
RealPrimarySurface::s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount > 8)
|
||||
{
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
typename Types<DirectDraw>::TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
|
||||
desc.dwWidth = RealPrimarySurface::s_surfaceDesc.dwWidth;
|
||||
desc.dwHeight = RealPrimarySurface::s_surfaceDesc.dwHeight;
|
||||
desc.ddpfPixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||
|
||||
typename Types<DirectDraw>::TCreatedSurface* surface = nullptr;
|
||||
HRESULT result = dd.lpVtbl->CreateSurface(&dd, &desc, &surface, nullptr);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
surface->lpVtbl->QueryInterface(
|
||||
surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&g_paletteConverterSurface));
|
||||
surface->lpVtbl->Release(surface);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD getTimeElapsedInMs(const LARGE_INTEGER& time)
|
||||
{
|
||||
LARGE_INTEGER currentTime = {};
|
||||
QueryPerformanceCounter(¤tTime);
|
||||
return static_cast<DWORD>((currentTime.QuadPart - time.QuadPart) * 1000 / g_qpcFrequency.QuadPart);
|
||||
}
|
||||
|
||||
void onRelease()
|
||||
{
|
||||
g_frontBuffer = nullptr;
|
||||
g_backBuffer = nullptr;
|
||||
g_paletteConverterSurface->lpVtbl->Release(g_paletteConverterSurface);
|
||||
g_paletteConverterSurface = nullptr;
|
||||
|
||||
SetEvent(g_updateEvent);
|
||||
if (WAIT_TIMEOUT == WaitForSingleObject(g_updateThread, 500))
|
||||
{
|
||||
TerminateThread(g_updateThread, 0);
|
||||
}
|
||||
g_updateThread = nullptr;
|
||||
|
||||
CloseHandle(g_updateEvent);
|
||||
g_updateEvent = nullptr;
|
||||
|
||||
ZeroMemory(&RealPrimarySurface::s_surfaceDesc, sizeof(RealPrimarySurface::s_surfaceDesc));
|
||||
}
|
||||
|
||||
void updateNow()
|
||||
{
|
||||
QueryPerformanceCounter(&g_lastUpdateTime);
|
||||
|
||||
if (g_backBuffer)
|
||||
{
|
||||
if (compatBlt(g_backBuffer))
|
||||
{
|
||||
g_frontBuffer->lpVtbl->Flip(g_frontBuffer, nullptr, DDFLIP_NOVSYNC | DDFLIP_WAIT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compatBlt(g_frontBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
WaitForSingleObject(g_updateEvent, INFINITE);
|
||||
if (!g_frontBuffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
ResetEvent(g_updateEvent);
|
||||
|
||||
if (!g_isFlipEvent)
|
||||
{
|
||||
updateNow();
|
||||
}
|
||||
|
||||
DWORD timeSinceLastUpdate = getTimeElapsedInMs(g_lastUpdateTime);
|
||||
DWORD minRefreshInterval = g_isFlipEvent ?
|
||||
Config::minRefreshIntervalAfterFlip : Config::minRefreshInterval;
|
||||
DWORD minRefreshIntervalTimeout = timeSinceLastUpdate < minRefreshInterval ?
|
||||
minRefreshInterval - timeSinceLastUpdate : 0;
|
||||
|
||||
g_isFlipEvent = false;
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
|
||||
if (minRefreshIntervalTimeout)
|
||||
{
|
||||
Sleep(minRefreshIntervalTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DDSURFACEDESC2 RealPrimarySurface::s_surfaceDesc = {};
|
||||
|
||||
template <typename DirectDraw>
|
||||
HRESULT RealPrimarySurface::create(DirectDraw& dd)
|
||||
{
|
||||
typename Types<DirectDraw>::TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
|
||||
desc.dwBackBufferCount = 1;
|
||||
|
||||
typename Types<DirectDraw>::TCreatedSurface* surface = nullptr;
|
||||
HRESULT result = CompatDirectDraw<DirectDraw>::s_origVtable.CreateSurface(
|
||||
&dd, &desc, &surface, nullptr);
|
||||
|
||||
bool isFlippable = true;
|
||||
if (DDERR_NOEXCLUSIVEMODE == result)
|
||||
{
|
||||
desc.dwFlags = DDSD_CAPS;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
desc.dwBackBufferCount = 0;
|
||||
isFlippable = false;
|
||||
result = CompatDirectDraw<DirectDraw>::s_origVtable.CreateSurface(
|
||||
&dd, &desc, &surface, nullptr);
|
||||
}
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
Compat::Log() << "Failed to create the real primary surface";
|
||||
return result;
|
||||
}
|
||||
|
||||
surface->lpVtbl->QueryInterface(
|
||||
surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&g_frontBuffer));
|
||||
surface->lpVtbl->Release(surface);
|
||||
|
||||
s_surfaceDesc.dwSize = sizeof(s_surfaceDesc);
|
||||
g_frontBuffer->lpVtbl->GetSurfaceDesc(g_frontBuffer, &s_surfaceDesc);
|
||||
|
||||
result = createPaletteConverterSurface(dd);
|
||||
if (FAILED(result))
|
||||
{
|
||||
Compat::Log() << "Failed to create palette converter surface";
|
||||
g_frontBuffer->lpVtbl->Release(g_frontBuffer);
|
||||
g_frontBuffer = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isFlippable)
|
||||
{
|
||||
DDSCAPS2 backBufferCaps = {};
|
||||
backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||
g_frontBuffer->lpVtbl->GetAttachedSurface(g_frontBuffer, &backBufferCaps, &g_backBuffer);
|
||||
}
|
||||
|
||||
QueryPerformanceFrequency(&g_qpcFrequency);
|
||||
|
||||
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
|
||||
SetThreadPriority(g_updateThread, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
|
||||
g_frontBuffer->lpVtbl->SetPrivateData(g_frontBuffer,
|
||||
IID_IReleaseNotifier, &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
template HRESULT RealPrimarySurface::create(IDirectDraw&);
|
||||
template HRESULT RealPrimarySurface::create(IDirectDraw2&);
|
||||
template HRESULT RealPrimarySurface::create(IDirectDraw4&);
|
||||
template HRESULT RealPrimarySurface::create(IDirectDraw7&);
|
||||
|
||||
HRESULT RealPrimarySurface::flip(DWORD flags)
|
||||
{
|
||||
if (!g_backBuffer)
|
||||
{
|
||||
return DDERR_NOTFLIPPABLE;
|
||||
}
|
||||
|
||||
if (flags & DDFLIP_NOVSYNC)
|
||||
{
|
||||
update();
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
compatBlt(g_backBuffer);
|
||||
if (flags & DDFLIP_DONOTWAIT)
|
||||
{
|
||||
flags ^= DDFLIP_DONOTWAIT;
|
||||
}
|
||||
|
||||
HRESULT result = g_frontBuffer->lpVtbl->Flip(g_frontBuffer, nullptr, flags | DDFLIP_WAIT);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
QueryPerformanceCounter(&g_lastUpdateTime);
|
||||
g_isFlipEvent = true;
|
||||
SetEvent(g_updateEvent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
IDirectDrawSurface7* RealPrimarySurface::getSurface()
|
||||
{
|
||||
return g_frontBuffer;
|
||||
}
|
||||
|
||||
bool RealPrimarySurface::isFullScreen()
|
||||
{
|
||||
return nullptr != g_backBuffer;
|
||||
}
|
||||
|
||||
bool RealPrimarySurface::isLost()
|
||||
{
|
||||
return g_frontBuffer &&
|
||||
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
|
||||
}
|
||||
|
||||
void RealPrimarySurface::release()
|
||||
{
|
||||
if (g_frontBuffer)
|
||||
{
|
||||
g_frontBuffer->lpVtbl->Release(g_frontBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT RealPrimarySurface::restore()
|
||||
{
|
||||
return g_frontBuffer->lpVtbl->Restore(g_frontBuffer);
|
||||
}
|
||||
|
||||
void RealPrimarySurface::setClipper(LPDIRECTDRAWCLIPPER clipper)
|
||||
{
|
||||
if (g_paletteConverterSurface)
|
||||
{
|
||||
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
|
||||
g_paletteConverterSurface, clipper);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to set the clipper on the converter surface: " << result);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
|
||||
g_frontBuffer, clipper);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to set clipper on the real primary surface: " << result);
|
||||
}
|
||||
}
|
||||
|
||||
void RealPrimarySurface::setPalette(LPDIRECTDRAWPALETTE palette)
|
||||
{
|
||||
if (g_paletteConverterSurface && CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
HRESULT result = g_paletteConverterSurface->lpVtbl->SetPalette(g_paletteConverterSurface, palette);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to set the palette on the converter surface: " << result);
|
||||
}
|
||||
}
|
||||
|
||||
if (s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
HRESULT result = g_frontBuffer->lpVtbl->SetPalette(g_frontBuffer, palette);
|
||||
if (FAILED(result) && DDERR_NOPALETTEATTACHED != result)
|
||||
{
|
||||
LOG_ONCE("Failed to set the palette on the real primary surface: " << result);
|
||||
}
|
||||
}
|
||||
|
||||
updatePalette();
|
||||
}
|
||||
|
||||
void RealPrimarySurface::update()
|
||||
{
|
||||
g_isFlipEvent = false;
|
||||
SetEvent(g_updateEvent);
|
||||
}
|
||||
|
||||
void RealPrimarySurface::updatePalette()
|
||||
{
|
||||
if (isFullScreen())
|
||||
{
|
||||
flip(DDFLIP_WAIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
static LARGE_INTEGER lastUpdateTime = {};
|
||||
DWORD timeSinceLastUpdate = getTimeElapsedInMs(lastUpdateTime);
|
||||
if (timeSinceLastUpdate < Config::minPaletteUpdateInterval)
|
||||
{
|
||||
Sleep(Config::minPaletteUpdateInterval - timeSinceLastUpdate);
|
||||
}
|
||||
QueryPerformanceCounter(&lastUpdateTime);
|
||||
}
|
25
DDrawCompat/RealPrimarySurface.h
Normal file
25
DDrawCompat/RealPrimarySurface.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
class RealPrimarySurface
|
||||
{
|
||||
public:
|
||||
template <typename DirectDraw>
|
||||
static HRESULT create(DirectDraw& dd);
|
||||
|
||||
static HRESULT flip(DWORD flags);
|
||||
static IDirectDrawSurface7* getSurface();
|
||||
static bool isFullScreen();
|
||||
static bool isLost();
|
||||
static void release();
|
||||
static HRESULT restore();
|
||||
static void setClipper(LPDIRECTDRAWCLIPPER clipper);
|
||||
static void setPalette(LPDIRECTDRAWPALETTE palette);
|
||||
static void update();
|
||||
static void updatePalette();
|
||||
|
||||
static DDSURFACEDESC2 s_surfaceDesc;
|
||||
};
|
9
DDrawCompat/UnmodifiedDDrawProcs.cpp
Normal file
9
DDrawCompat/UnmodifiedDDrawProcs.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "DDrawProcs.h"
|
||||
|
||||
#define CREATE_DDRAW_PROC_STUB(procName) \
|
||||
extern "C" __declspec(naked) void __stdcall procName() \
|
||||
{ \
|
||||
__asm jmp Compat::origProcs.procName \
|
||||
}
|
||||
|
||||
VISIT_UNMODIFIED_DDRAW_PROCS(CREATE_DDRAW_PROC_STUB)
|
Loading…
x
Reference in New Issue
Block a user