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

Implemented GetGDISurface and FlipToGDISurface

This commit is contained in:
narzoul 2016-11-01 17:13:07 +01:00
parent fbe34c0341
commit 1d14b606c2
9 changed files with 129 additions and 10 deletions

View File

@ -9,6 +9,12 @@ template <typename Intf>
class CompatPtr : public CompatWeakPtr<Intf>
{
public:
template <typename OtherIntf>
static CompatPtr from(OtherIntf* other)
{
return CompatPtr(Compat::queryInterface<Intf>(other));
}
CompatPtr(std::nullptr_t = nullptr)
{
}

View File

@ -40,7 +40,9 @@ namespace DDraw
void DirectDraw<TDirectDraw>::setCompatVtable(Vtable<TDirectDraw>& vtable)
{
vtable.CreateSurface = &CreateSurface;
vtable.FlipToGDISurface = &FlipToGDISurface;
vtable.GetDisplayMode = &GetDisplayMode;
vtable.GetGDISurface = &GetGDISurface;
vtable.RestoreDisplayMode = &RestoreDisplayMode;
vtable.SetCooperativeLevel = &SetCooperativeLevel;
vtable.SetDisplayMode = &SetDisplayMode;
@ -74,6 +76,12 @@ namespace DDraw
return result;
}
template <typename TDirectDraw>
HRESULT STDMETHODCALLTYPE DirectDraw<TDirectDraw>::FlipToGDISurface(TDirectDraw* /*This*/)
{
return PrimarySurface::flipToGdiSurface();
}
template <typename TDirectDraw>
HRESULT STDMETHODCALLTYPE DirectDraw<TDirectDraw>::GetDisplayMode(
TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc)
@ -92,6 +100,25 @@ namespace DDraw
return DD_OK;
}
template <typename TDirectDraw>
HRESULT STDMETHODCALLTYPE DirectDraw<TDirectDraw>::GetGDISurface(
TDirectDraw* /*This*/, TSurface** lplpGDIDDSSurface)
{
if (!lplpGDIDDSSurface)
{
return DDERR_INVALIDPARAMS;
}
auto gdiSurface(PrimarySurface::getGdiSurface());
if (!gdiSurface)
{
return DDERR_NOTFOUND;
}
*lplpGDIDDSSurface = CompatPtr<TSurface>::from(gdiSurface.get()).detach();
return DD_OK;
}
template <typename TDirectDraw>
HRESULT STDMETHODCALLTYPE DirectDraw<TDirectDraw>::RestoreDisplayMode(TDirectDraw* This)
{

View File

@ -30,7 +30,9 @@ namespace DDraw
TSurface** lplpDDSurface,
IUnknown* pUnkOuter);
static HRESULT STDMETHODCALLTYPE FlipToGDISurface(TDirectDraw* This);
static HRESULT STDMETHODCALLTYPE GetDisplayMode(TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc);
static HRESULT STDMETHODCALLTYPE GetGDISurface(TDirectDraw* This, TSurface** lplpGDIDDSSurface);
static HRESULT STDMETHODCALLTYPE RestoreDisplayMode(TDirectDraw* This);
static HRESULT STDMETHODCALLTYPE SetCooperativeLevel(TDirectDraw* This, HWND hWnd, DWORD dwFlags);

View File

@ -7,6 +7,7 @@
namespace
{
DDSURFACEDESC2 g_primarySurfaceDesc = {};
CompatWeakPtr<IDirectDrawSurface> g_gdiSurface = nullptr;
CompatWeakPtr<IDirectDrawSurface> g_primarySurface = nullptr;
}
@ -21,6 +22,7 @@ namespace DDraw
{
Compat::LogEnter("PrimarySurface::~PrimarySurface");
g_gdiSurface = nullptr;
g_primarySurface = nullptr;
s_palette = nullptr;
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
@ -62,6 +64,7 @@ namespace DDraw
attach(*surface7, privateData);
CompatPtr<IDirectDrawSurface> surface1(Compat::queryInterface<IDirectDrawSurface>(surface));
g_gdiSurface = surface1;
g_primarySurface = surface1;
ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc));
@ -89,11 +92,25 @@ namespace DDraw
m_impl7.reset(new PrimarySurfaceImpl<IDirectDrawSurface7>(*m_surface->getImpl<IDirectDrawSurface7>()));
}
HRESULT PrimarySurface::flipToGdiSurface()
{
if (!g_primarySurface)
{
return DDERR_NOTFOUND;
}
return g_primarySurface.get()->lpVtbl->Flip(g_primarySurface, g_gdiSurface, DDFLIP_WAIT);
}
const DDSURFACEDESC2& PrimarySurface::getDesc()
{
return g_primarySurfaceDesc;
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getGdiSurface()
{
return CompatPtr<IDirectDrawSurface7>::from(g_gdiSurface.get());
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
{
if (!g_primarySurface)
@ -104,6 +121,36 @@ namespace DDraw
Compat::queryInterface<IDirectDrawSurface7>(g_primarySurface.get()));
}
void PrimarySurface::updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride)
{
auto primary(CompatPtr<IDirectDrawSurface>::from(m_surface->getDirectDrawSurface().get()));
if (flipTargetOverride)
{
if (g_gdiSurface.get() == flipTargetOverride)
{
g_gdiSurface = primary;
}
else if (g_gdiSurface.get() == primary)
{
g_gdiSurface = flipTargetOverride;
}
return;
}
DDSCAPS caps = {};
caps.dwCaps = DDSCAPS_FLIP;
CompatPtr<IDirectDrawSurface> current(primary);
CompatPtr<IDirectDrawSurface> next;
HRESULT result = current->GetAttachedSurface(current, &caps, &next.getRef());
while (SUCCEEDED(result) && next.get() != g_gdiSurface.get() && next.get() != primary)
{
current = next;
result = current->GetAttachedSurface(current, &caps, &next.getRef());
}
g_gdiSurface = current;
}
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;
PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {};
}

View File

@ -13,9 +13,13 @@ namespace DDraw
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
static HRESULT create(CompatRef<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface);
static HRESULT flipToGdiSurface();
static const DDSURFACEDESC2& getDesc();
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
static CompatPtr<IDirectDrawSurface7> getPrimary();
void updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride);
static CompatWeakPtr<IDirectDrawPalette> s_palette;
static PALETTEENTRY s_paletteEntries[256];

View File

@ -85,6 +85,15 @@ namespace DDraw
if (SUCCEEDED(result))
{
result = RealPrimarySurface::flip(dwFlags);
if (SUCCEEDED(result))
{
static_cast<PrimarySurface*>(m_data)->updateGdiSurfacePtr(
CompatPtr<IDirectDrawSurface>::from(lpDDSurfaceTargetOverride));
}
else
{
undoFlip(This, lpDDSurfaceTargetOverride);
}
}
return result;
}

View File

@ -70,6 +70,26 @@ namespace DDraw
::fixSurfacePtrs(*surface7);
}
template <typename TSurface>
void SurfaceImpl<TSurface>::undoFlip(TSurface* This, TSurface* targetOverride)
{
if (targetOverride)
{
SurfaceImpl::Flip(This, targetOverride, DDFLIP_WAIT);
}
else
{
TSurfaceDesc desc = {};
desc.dwSize = sizeof(desc);
s_origVtable.GetSurfaceDesc(This, &desc);
for (DWORD i = 0; i < desc.dwBackBufferCount; ++i)
{
SurfaceImpl::Flip(This, nullptr, DDFLIP_WAIT);
}
}
}
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::Blt(
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,

View File

@ -55,6 +55,9 @@ namespace DDraw
virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette);
virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect);
protected:
void undoFlip(TSurface* This, TSurface* targetOverride);
private:
static const Vtable<TSurface>& s_origVtable;
};

View File

@ -54,12 +54,13 @@ namespace
return TRUE;
}
bool lockPrimarySurface(DWORD lockFlags)
bool lockGdiSurface(DWORD lockFlags)
{
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
auto primary(DDraw::PrimarySurface::getPrimary());
if (!primary || FAILED(primary->Lock(primary, nullptr, &desc, lockFlags | DDLOCK_WAIT, nullptr)))
auto gdiSurface(DDraw::PrimarySurface::getGdiSurface());
if (!gdiSurface || FAILED(gdiSurface.get()->lpVtbl->Lock(
gdiSurface, nullptr, &desc, lockFlags | DDLOCK_WAIT, nullptr)))
{
return false;
}
@ -76,13 +77,13 @@ namespace
return true;
}
void unlockPrimarySurface()
void unlockGdiSurface()
{
GdiFlush();
auto primary(DDraw::PrimarySurface::getPrimary());
if (primary)
auto gdiSurface(DDraw::PrimarySurface::getGdiSurface());
if (gdiSurface)
{
primary->Unlock(primary, nullptr);
gdiSurface.get()->lpVtbl->Unlock(gdiSurface, nullptr);
if (DDLOCK_READONLY != g_ddLockFlags)
{
DDraw::RealPrimarySurface::invalidate(nullptr);
@ -118,7 +119,7 @@ namespace Gdi
LeaveCriticalSection(&g_gdiCriticalSection);
Dll::g_origProcs.AcquireDDThreadLock();
EnterCriticalSection(&g_gdiCriticalSection);
if (!lockPrimarySurface(lockFlags))
if (!lockGdiSurface(lockFlags))
{
Dll::g_origProcs.ReleaseDDThreadLock();
return false;
@ -142,7 +143,7 @@ namespace Gdi
{
if (1 == g_renderingRefCount)
{
unlockPrimarySurface();
unlockGdiSurface();
g_ddLockThreadRenderingRefCount = 0;
g_renderingRefCount = 0;
}
@ -151,7 +152,7 @@ namespace Gdi
g_isDelayedUnlockPending = true;
gdiLock.unlock();
WaitForSingleObject(g_ddUnlockBeginEvent, INFINITE);
unlockPrimarySurface();
unlockGdiSurface();
g_ddLockThreadRenderingRefCount = 0;
g_renderingRefCount = 0;
SetEvent(g_ddUnlockEndEvent);