From 947bb41bf3196a51c86bdd63cdb890b16e2f7ed8 Mon Sep 17 00:00:00 2001 From: narzoul Date: Tue, 25 Jul 2017 21:27:40 +0200 Subject: [PATCH] Emulate flip when the primary surface is requested in system memory When the primary surface chain is requested to be created in system memory, flip should be emulated (copy from back buffer to front buffer) to be consistent with legacy DirectDraw behavior. Fixes flashing graphical artifacts in Carmageddon (Win95 version) menus when exiting from a race, mentioned in issue #3. --- DDrawCompat/DDraw/DirectDraw.cpp | 12 ++----- DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp | 8 +++++ DDrawCompat/DDraw/Surfaces/PrimarySurface.h | 1 + .../DDraw/Surfaces/PrimarySurfaceImpl.cpp | 31 +++++++++++++++---- DDrawCompat/DDraw/Surfaces/SurfaceImpl.h | 4 +-- 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index 3675112..1936661 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -122,20 +122,14 @@ namespace DDraw return s_origVtable.CreateSurface(This, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); } - HRESULT result = DD_OK; - - const bool isPrimary = 0 != (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE); - - if (isPrimary) + if (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { - result = PrimarySurface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); + return PrimarySurface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); } else { - result = Surface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); + return Surface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); } - - return result; } template diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index e438c29..8c62e2a 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -10,6 +10,7 @@ namespace DDSURFACEDESC2 g_primarySurfaceDesc = {}; CompatWeakPtr g_gdiSurface = nullptr; CompatWeakPtr g_primarySurface = nullptr; + bool g_isFlipEmulated = false; } namespace DDraw @@ -25,6 +26,7 @@ namespace DDraw g_gdiSurface = nullptr; g_primarySurface = nullptr; + g_isFlipEmulated = false; s_palette = nullptr; s_surfaceBuffers.clear(); ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries)); @@ -67,6 +69,7 @@ namespace DDraw CompatPtr surface1(Compat::queryInterface(surface)); g_gdiSurface = surface1; g_primarySurface = surface1; + g_isFlipEmulated = 0 != (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY); ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc)); g_primarySurfaceDesc.dwSize = sizeof(g_primarySurfaceDesc); @@ -127,6 +130,11 @@ namespace DDraw Compat::queryInterface(g_primarySurface.get())); } + bool PrimarySurface::isFlipEmulated() + { + return g_isFlipEmulated; + } + void PrimarySurface::resizeBuffers(CompatRef surface) { DDSCAPS2 flipCaps = {}; diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h index 9ae577f..37478f0 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h @@ -20,6 +20,7 @@ namespace DDraw static const DDSURFACEDESC2& getDesc(); static CompatPtr getGdiSurface(); static CompatPtr getPrimary(); + static bool isFlipEmulated(); void updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride); diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index c0b7542..59b1673 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -80,19 +80,38 @@ namespace DDraw } HRESULT result = m_impl.Flip(This, lpDDSurfaceTargetOverride, dwFlags); - if (SUCCEEDED(result)) + if (FAILED(result)) { - result = RealPrimarySurface::flip(dwFlags); - if (SUCCEEDED(result)) + return result; + } + + result = RealPrimarySurface::flip(dwFlags); + if (SUCCEEDED(result) && !PrimarySurface::isFlipEmulated()) + { + static_cast(m_data)->updateGdiSurfacePtr( + CompatPtr::from(lpDDSurfaceTargetOverride)); + return DD_OK; + } + + undoFlip(This, lpDDSurfaceTargetOverride); + + if (SUCCEEDED(result) && PrimarySurface::isFlipEmulated()) + { + if (lpDDSurfaceTargetOverride) { - static_cast(m_data)->updateGdiSurfacePtr( - CompatPtr::from(lpDDSurfaceTargetOverride)); + s_origVtable.BltFast(This, 0, 0, lpDDSurfaceTargetOverride, nullptr, DDBLTFAST_WAIT); } else { - undoFlip(This, lpDDSurfaceTargetOverride); + TDdsCaps caps = {}; + caps.dwCaps = DDSCAPS_BACKBUFFER; + CompatPtr backBuffer; + s_origVtable.GetAttachedSurface(This, &caps, &backBuffer.getRef()); + + s_origVtable.BltFast(This, 0, 0, backBuffer, nullptr, DDBLTFAST_WAIT); } } + return result; } diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h index fa35f19..9e4d56f 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h @@ -56,6 +56,8 @@ namespace DDraw protected: void undoFlip(TSurface* This, TSurface* targetOverride); + static const Vtable& s_origVtable; + private: bool bltRetry(TSurface*& dstSurface, RECT*& dstRect, TSurface*& srcSurface, RECT*& srcRect, bool isTransparentBlt, @@ -63,7 +65,5 @@ namespace DDraw bool prepareBltRetrySurface(TSurface*& surface, RECT*& rect, const TSurfaceDesc& desc, bool isTransparentBlt, bool isCopyNeeded); void replaceWithVidMemSurface(TSurface*& surface, RECT*& rect, const TSurfaceDesc& desc); - - static const Vtable& s_origVtable; }; }