diff --git a/DDrawCompat/Common/CompatPtr.h b/DDrawCompat/Common/CompatPtr.h index 0175648..3e57e24 100644 --- a/DDrawCompat/Common/CompatPtr.h +++ b/DDrawCompat/Common/CompatPtr.h @@ -9,6 +9,12 @@ template class CompatPtr : public CompatWeakPtr { public: + template + static CompatPtr from(OtherIntf* other) + { + return CompatPtr(Compat::queryInterface(other)); + } + CompatPtr(std::nullptr_t = nullptr) { } diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index aa602c2..4760e81 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -40,7 +40,9 @@ namespace DDraw void DirectDraw::setCompatVtable(Vtable& 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 + HRESULT STDMETHODCALLTYPE DirectDraw::FlipToGDISurface(TDirectDraw* /*This*/) + { + return PrimarySurface::flipToGdiSurface(); + } + template HRESULT STDMETHODCALLTYPE DirectDraw::GetDisplayMode( TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc) @@ -92,6 +100,25 @@ namespace DDraw return DD_OK; } + template + HRESULT STDMETHODCALLTYPE DirectDraw::GetGDISurface( + TDirectDraw* /*This*/, TSurface** lplpGDIDDSSurface) + { + if (!lplpGDIDDSSurface) + { + return DDERR_INVALIDPARAMS; + } + + auto gdiSurface(PrimarySurface::getGdiSurface()); + if (!gdiSurface) + { + return DDERR_NOTFOUND; + } + + *lplpGDIDDSSurface = CompatPtr::from(gdiSurface.get()).detach(); + return DD_OK; + } + template HRESULT STDMETHODCALLTYPE DirectDraw::RestoreDisplayMode(TDirectDraw* This) { diff --git a/DDrawCompat/DDraw/DirectDraw.h b/DDrawCompat/DDraw/DirectDraw.h index 7953912..e9300e4 100644 --- a/DDrawCompat/DDraw/DirectDraw.h +++ b/DDrawCompat/DDraw/DirectDraw.h @@ -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); diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index f81282d..87974e9 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -7,6 +7,7 @@ namespace { DDSURFACEDESC2 g_primarySurfaceDesc = {}; + CompatWeakPtr g_gdiSurface = nullptr; CompatWeakPtr 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 surface1(Compat::queryInterface(surface)); + g_gdiSurface = surface1; g_primarySurface = surface1; ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc)); @@ -89,11 +92,25 @@ namespace DDraw m_impl7.reset(new PrimarySurfaceImpl(*m_surface->getImpl())); } + 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 PrimarySurface::getGdiSurface() + { + return CompatPtr::from(g_gdiSurface.get()); + } + CompatPtr PrimarySurface::getPrimary() { if (!g_primarySurface) @@ -104,6 +121,36 @@ namespace DDraw Compat::queryInterface(g_primarySurface.get())); } + void PrimarySurface::updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride) + { + auto primary(CompatPtr::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 current(primary); + CompatPtr 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 PrimarySurface::s_palette; PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {}; } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h index 8e4a677..b64775b 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h @@ -13,9 +13,13 @@ namespace DDraw template static HRESULT create(CompatRef dd, TSurfaceDesc desc, TSurface*& surface); + static HRESULT flipToGdiSurface(); static const DDSURFACEDESC2& getDesc(); + static CompatPtr getGdiSurface(); static CompatPtr getPrimary(); + void updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride); + static CompatWeakPtr s_palette; static PALETTEENTRY s_paletteEntries[256]; diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index b90b3ff..f03857c 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -85,6 +85,15 @@ namespace DDraw if (SUCCEEDED(result)) { result = RealPrimarySurface::flip(dwFlags); + if (SUCCEEDED(result)) + { + static_cast(m_data)->updateGdiSurfacePtr( + CompatPtr::from(lpDDSurfaceTargetOverride)); + } + else + { + undoFlip(This, lpDDSurfaceTargetOverride); + } } return result; } diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index c0a1ac3..8f51548 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -70,6 +70,26 @@ namespace DDraw ::fixSurfacePtrs(*surface7); } + template + void SurfaceImpl::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 HRESULT SurfaceImpl::Blt( TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h index 6ad0dc3..19aea56 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h @@ -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& s_origVtable; }; diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index 15c24a4..3546dd5 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -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);