From 19cce6b9d696e4b8053b92b1f62a71e90bec982d Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 10 Sep 2016 22:09:23 +0200 Subject: [PATCH] Preparation for splitting the DirectDrawSurface wrapper into layers --- DDrawCompat/DDraw/ActivateAppHandler.cpp | 4 +- DDrawCompat/DDraw/DirectDraw.cpp | 44 +- DDrawCompat/DDraw/DirectDrawSurface.cpp | 560 ++------------------- DDrawCompat/DDraw/DirectDrawSurface.h | 51 -- DDrawCompat/DDraw/Surfaces/Surface.cpp | 159 ++++++ DDrawCompat/DDraw/Surfaces/Surface.h | 48 ++ DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp | 520 +++++++++++++++++++ DDrawCompat/DDraw/Surfaces/SurfaceImpl.h | 50 ++ DDrawCompat/DDrawCompat.vcxproj | 4 + DDrawCompat/DDrawCompat.vcxproj.filters | 18 + 10 files changed, 839 insertions(+), 619 deletions(-) create mode 100644 DDrawCompat/DDraw/Surfaces/Surface.cpp create mode 100644 DDrawCompat/DDraw/Surfaces/Surface.h create mode 100644 DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp create mode 100644 DDrawCompat/DDraw/Surfaces/SurfaceImpl.h diff --git a/DDrawCompat/DDraw/ActivateAppHandler.cpp b/DDrawCompat/DDraw/ActivateAppHandler.cpp index 64b7ce2..4b059de 100644 --- a/DDrawCompat/DDraw/ActivateAppHandler.cpp +++ b/DDrawCompat/DDraw/ActivateAppHandler.cpp @@ -4,8 +4,8 @@ #include "DDraw/ActivateAppHandler.h" #include "DDraw/CompatPrimarySurface.h" #include "DDraw/DirectDraw.h" -#include "DDraw/DirectDrawSurface.h" #include "DDraw/DisplayMode.h" +#include "DDraw/Surfaces/SurfaceImpl.h" #include "Gdi/Gdi.h" #include "Win32/FontSmoothing.h" @@ -41,7 +41,7 @@ namespace auto primary(DDraw::CompatPrimarySurface::getPrimary()); if (primary && SUCCEEDED(primary->Restore(primary))) { - DDraw::DirectDrawSurface::fixSurfacePtrs(*primary); + DDraw::SurfaceImpl::fixSurfacePtrs(*primary); Gdi::invalidate(nullptr); } diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index d56ef4c..6a46e16 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -5,6 +5,8 @@ #include "DDraw/DirectDrawSurface.h" #include "DDraw/DisplayMode.h" #include "DDraw/IReleaseNotifier.h" +#include "DDraw/Surfaces/Surface.h" +#include "DDraw/Surfaces/SurfaceImpl.h" namespace { @@ -106,49 +108,23 @@ namespace DDraw TSurface** lplpDDSurface, IUnknown* pUnkOuter) { + if (!This || !lpDDSurfaceDesc || !lplpDDSurface) + { + return s_origVtable.CreateSurface(This, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); + } + HRESULT result = DD_OK; - const bool isPrimary = lpDDSurfaceDesc && - (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE); + const bool isPrimary = 0 != (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE); if (isPrimary) { - result = DirectDrawSurface::createCompatPrimarySurface( + result = SurfaceImpl::createCompatPrimarySurface( *This, *lpDDSurfaceDesc, *lplpDDSurface); } else { - if (lpDDSurfaceDesc && - (lpDDSurfaceDesc->dwFlags & DDSD_WIDTH) && - (lpDDSurfaceDesc->dwFlags & DDSD_HEIGHT) && - !(lpDDSurfaceDesc->ddsCaps.dwCaps & (DDSCAPS_ALPHA | DDSCAPS_ZBUFFER))) - { - CompatPtr dd(Compat::queryInterface(This)); - auto dm = DisplayMode::getDisplayMode(*dd); - - TSurfaceDesc desc = *lpDDSurfaceDesc; - if (!(desc.dwFlags & DDSD_PIXELFORMAT)) - { - desc.dwFlags |= DDSD_PIXELFORMAT; - desc.ddpfPixelFormat = dm.ddpfPixelFormat; - } - if (!(desc.ddsCaps.dwCaps & (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_OVERLAY | DDSCAPS_TEXTURE | - DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))) - { - desc.dwFlags |= DDSD_CAPS; - desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; - } - result = s_origVtable.CreateSurface(This, &desc, lplpDDSurface, pUnkOuter); - } - else - { - result = s_origVtable.CreateSurface(This, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); - } - } - - if (SUCCEEDED(result)) - { - DirectDrawSurface::fixSurfacePtrs(**lplpDDSurface); + result = Surface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); } return result; diff --git a/DDrawCompat/DDraw/DirectDrawSurface.cpp b/DDrawCompat/DDraw/DirectDrawSurface.cpp index 3cfef18..35bbb03 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.cpp +++ b/DDrawCompat/DDraw/DirectDrawSurface.cpp @@ -1,535 +1,48 @@ #include -#include "Common/CompatPtr.h" -#include "DDraw/CompatPrimarySurface.h" -#include "DDraw/DirectDraw.h" -#include "DDraw/DirectDrawPalette.h" #include "DDraw/DirectDrawSurface.h" -#include "DDraw/DisplayMode.h" -#include "DDraw/IReleaseNotifier.h" -#include "DDraw/RealPrimarySurface.h" -#include "DDraw/Repository.h" -#include "Gdi/Gdi.h" +#include "DDraw/Surfaces/Surface.h" +#include "DDraw/Surfaces/SurfaceImpl.h" namespace { - bool mirrorBlt(CompatRef dst, CompatRef src, - RECT srcRect, DWORD mirrorFx); - - bool g_lockingPrimary = false; - - void fixSurfacePtr(CompatRef surface, const DDSURFACEDESC2& desc) + template + HRESULT STDMETHODCALLTYPE callImpl(TSurface* This, Params... params) { - if ((desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) || 0 == desc.dwWidth || 0 == desc.dwHeight) + DDraw::SurfaceImpl* surfaceImpl = + This ? DDraw::Surface::getImpl(*This) : nullptr; + if (!surfaceImpl) { - return; + return (CompatVtableBase::s_origVtable.*origMethod)(This, params...); } - - DDSURFACEDESC2 tempSurfaceDesc = desc; - tempSurfaceDesc.dwWidth = 1; - tempSurfaceDesc.dwHeight = 1; - DDraw::Repository::ScopedSurface tempSurface(desc); - if (!tempSurface.surface) - { - return; - } - - RECT r = { 0, 0, 1, 1 }; - surface->Blt(&surface, &r, tempSurface.surface, &r, DDBLT_WAIT, nullptr); - } - - HRESULT WINAPI fixSurfacePtrEnumCallback( - LPDIRECTDRAWSURFACE7 lpDDSurface, - LPDDSURFACEDESC2 lpDDSurfaceDesc, - LPVOID lpContext) - { - auto& visitedSurfaces = *static_cast*>(lpContext); - - CompatPtr surface(lpDDSurface); - if (visitedSurfaces.find(surface) == visitedSurfaces.end()) - { - visitedSurfaces.insert(surface); - fixSurfacePtr(*surface, *lpDDSurfaceDesc); - surface->EnumAttachedSurfaces(surface, lpContext, &fixSurfacePtrEnumCallback); - } - - return DDENUMRET_OK; - } - - void fixSurfacePtrs(CompatRef surface) - { - DDSURFACEDESC2 desc = {}; - desc.dwSize = sizeof(desc); - surface->GetSurfaceDesc(&surface, &desc); - - fixSurfacePtr(surface, desc); - std::set visitedSurfaces{ &surface }; - surface->EnumAttachedSurfaces(&surface, &visitedSurfaces, &fixSurfacePtrEnumCallback); - } - - CompatWeakPtr getMirroredSurface( - CompatRef surface, RECT* srcRect, DWORD mirrorFx) - { - DDSURFACEDESC2 desc = {}; - desc.dwSize = sizeof(desc); - HRESULT result = surface->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; - } - - DDraw::Repository::ScopedSurface mirroredSurface(desc); - if (!mirroredSurface.surface) - { - return nullptr; - } - - RECT rect = { 0, 0, static_cast(desc.dwWidth), static_cast(desc.dwHeight) }; - if ((mirrorFx & DDBLTFX_MIRRORLEFTRIGHT) && (mirrorFx & DDBLTFX_MIRRORUPDOWN)) - { - DDraw::Repository::Surface tempMirroredSurface = DDraw::Repository::ScopedSurface(desc); - if (!tempMirroredSurface.surface || - !mirrorBlt(*tempMirroredSurface.surface, surface, srcRect ? *srcRect : rect, - DDBLTFX_MIRRORLEFTRIGHT) || - !mirrorBlt(*mirroredSurface.surface, *tempMirroredSurface.surface, rect, - DDBLTFX_MIRRORUPDOWN)) - { - return nullptr; - } - } - else if (!mirrorBlt(*mirroredSurface.surface, surface, srcRect ? *srcRect : rect, mirrorFx)) - { - return nullptr; - } - - return mirroredSurface.surface; - } - - bool mirrorBlt(CompatRef dst, CompatRef 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 = dst->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 = dst->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; + return (surfaceImpl->*compatMethod)(This, params...); } } +#define SET_COMPAT_METHOD(method) \ + vtable.method = &callImpl::method), &SurfaceImpl::method, \ + decltype(&Vtable::method), &Vtable::method> + namespace DDraw { template void DirectDrawSurface::setCompatVtable(Vtable& 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 - template - HRESULT DirectDrawSurface::createCompatPrimarySurface( - CompatRef dd, - TSurfaceDesc compatDesc, - TSurface*& compatSurface) - { - HRESULT result = RealPrimarySurface::create(dd); - if (FAILED(result)) - { - return result; - } - - CompatPtr dd7(Compat::queryInterface(&dd)); - const auto& dm = DisplayMode::getDisplayMode(*dd7); - compatDesc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - compatDesc.dwWidth = dm.dwWidth; - compatDesc.dwHeight = dm.dwHeight; - compatDesc.ddsCaps.dwCaps &= ~DDSCAPS_PRIMARYSURFACE; - compatDesc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; - compatDesc.ddpfPixelFormat = dm.ddpfPixelFormat; - - result = dd->CreateSurface(&dd, &compatDesc, &compatSurface, nullptr); - if (FAILED(result)) - { - Compat::Log() << "Failed to create the compat primary surface!"; - RealPrimarySurface::release(); - return result; - } - - CompatPtr primary(Compat::queryInterface(compatSurface)); - CompatPrimarySurface::setPrimary(*primary); - - return DD_OK; - } - - template - void DirectDrawSurface::fixSurfacePtrs(CompatRef surface) - { - CompatPtr surface7(Compat::queryInterface(&surface)); - ::fixSurfacePtrs(*surface7); - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::Blt( - TSurface* This, - LPRECT lpDestRect, - TSurface* lpDDSrcSurface, - LPRECT lpSrcRect, - DWORD dwFlags, - LPDDBLTFX lpDDBltFx) - { - const bool isPrimaryDest = CompatPrimarySurface::isPrimary(This); - if ((isPrimaryDest || CompatPrimarySurface::isPrimary(lpDDSrcSurface)) && - RealPrimarySurface::isLost()) - { - return DDERR_SURFACELOST; - } - - HRESULT result = DD_OK; - CompatPtr mirroredSrcSurface; - - if (lpDDSrcSurface && (dwFlags & DDBLT_DDFX) && lpDDBltFx && - (lpDDBltFx->dwDDFX & (DDBLTFX_MIRRORLEFTRIGHT | DDBLTFX_MIRRORUPDOWN))) - { - CompatPtr srcSurface( - Compat::queryInterface(lpDDSrcSurface)); - mirroredSrcSurface.reset(Compat::queryInterface( - getMirroredSurface(*srcSurface, lpSrcRect, lpDDBltFx->dwDDFX).get())); - if (!mirroredSrcSurface) - { - LOG_ONCE("Failed to emulate a mirrored Blt"); - } - } - - 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); - } - } - else - { - result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); - } - - if (isPrimaryDest && SUCCEEDED(result)) - { - RealPrimarySurface::invalidate(lpDestRect); - RealPrimarySurface::update(); - } - - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::BltFast( - TSurface* This, - DWORD dwX, - DWORD dwY, - TSurface* lpDDSrcSurface, - LPRECT lpSrcRect, - DWORD dwTrans) - { - const bool isPrimaryDest = CompatPrimarySurface::isPrimary(This); - if ((isPrimaryDest || CompatPrimarySurface::isPrimary(lpDDSrcSurface)) && - RealPrimarySurface::isLost()) - { - return DDERR_SURFACELOST; - } - - HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans); - if (isPrimaryDest && SUCCEEDED(result)) - { - const LONG x = dwX; - const LONG y = dwY; - RECT destRect = { x, y, x, y }; - if (lpSrcRect) - { - destRect.right += lpSrcRect->right - lpSrcRect->left; - destRect.bottom += lpSrcRect->bottom - lpSrcRect->top; - } - else - { - TSurfaceDesc desc = {}; - desc.dwSize = sizeof(desc); - s_origVtable.GetSurfaceDesc(lpDDSrcSurface, &desc); - destRect.right += desc.dwWidth; - destRect.bottom += desc.dwHeight; - } - RealPrimarySurface::invalidate(&destRect); - RealPrimarySurface::update(); - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::Flip( - TSurface* This, - TSurface* lpDDSurfaceTargetOverride, - DWORD dwFlags) - { - HRESULT result = s_origVtable.Flip(This, lpDDSurfaceTargetOverride, dwFlags); - if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) - { - result = RealPrimarySurface::flip(dwFlags); - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::GetCaps( - TSurface* This, - TDdsCaps* lpDDSCaps) - { - HRESULT result = s_origVtable.GetCaps(This, lpDDSCaps); - if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) - { - restorePrimaryCaps(*lpDDSCaps); - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::GetSurfaceDesc( - TSurface* This, - TSurfaceDesc* lpDDSurfaceDesc) - { - HRESULT result = s_origVtable.GetSurfaceDesc(This, lpDDSurfaceDesc); - if (SUCCEEDED(result) && !g_lockingPrimary && CompatPrimarySurface::isPrimary(This)) - { - restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps); - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::IsLost(TSurface* This) - { - HRESULT result = s_origVtable.IsLost(This); - if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) - { - result = RealPrimarySurface::isLost() ? DDERR_SURFACELOST : DD_OK; - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::Lock( - TSurface* This, - LPRECT lpDestRect, - TSurfaceDesc* lpDDSurfaceDesc, - DWORD dwFlags, - HANDLE hEvent) - { - if (CompatPrimarySurface::isPrimary(This)) - { - if (RealPrimarySurface::isLost()) - { - return DDERR_SURFACELOST; - } - g_lockingPrimary = true; - } - - HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent); - if (SUCCEEDED(result) && g_lockingPrimary && lpDDSurfaceDesc) - { - RealPrimarySurface::invalidate(lpDestRect); - restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps); - } - else if (DDERR_SURFACELOST == result) - { - TSurfaceDesc desc = {}; - desc.dwSize = sizeof(desc); - if (SUCCEEDED(s_origVtable.GetSurfaceDesc(This, &desc)) && !(desc.dwFlags & DDSD_HEIGHT)) - { - // Fixes missing handling for lost vertex buffers in Messiah - s_origVtable.Restore(This); - // Still, pass back DDERR_SURFACELOST to the application in case it handles it - } - } - - g_lockingPrimary = false; - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::QueryInterface( - TSurface* This, - REFIID riid, - LPVOID* obp) - { - if (riid == IID_IDirectDrawGammaControl && CompatPrimarySurface::isPrimary(This)) - { - auto realPrimary(RealPrimarySurface::getSurface()); - return realPrimary->QueryInterface(realPrimary, riid, obp); - } - return s_origVtable.QueryInterface(This, riid, obp); - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::ReleaseDC(TSurface* This, HDC hDC) - { - const bool isPrimary = CompatPrimarySurface::isPrimary(This); - if (isPrimary && RealPrimarySurface::isLost()) - { - return DDERR_SURFACELOST; - } - - HRESULT result = s_origVtable.ReleaseDC(This, hDC); - if (isPrimary && SUCCEEDED(result)) - { - RealPrimarySurface::invalidate(nullptr); - RealPrimarySurface::update(); - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::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 (CompatPrimarySurface::isPrimary(This)) - { - result = RealPrimarySurface::restore(); - if (wasLost) - { - Gdi::invalidate(nullptr); - } - } - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::SetClipper( - TSurface* This, - LPDIRECTDRAWCLIPPER lpDDClipper) - { - HRESULT result = s_origVtable.SetClipper(This, lpDDClipper); - if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) - { - RealPrimarySurface::setClipper(lpDDClipper); - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::SetPalette( - TSurface* This, - LPDIRECTDRAWPALETTE lpDDPalette) - { - const bool isPrimary = CompatPrimarySurface::isPrimary(This); - if (isPrimary) - { - if (lpDDPalette) - { - DirectDrawPalette::waitForNextUpdate(); - } - if (lpDDPalette == CompatPrimarySurface::g_palette) - { - return DD_OK; - } - } - - HRESULT result = s_origVtable.SetPalette(This, lpDDPalette); - if (isPrimary && SUCCEEDED(result)) - { - CompatPrimarySurface::g_palette = lpDDPalette; - RealPrimarySurface::setPalette(); - } - return result; - } - - template - HRESULT STDMETHODCALLTYPE DirectDrawSurface::Unlock(TSurface* This, TUnlockParam lpRect) - { - HRESULT result = s_origVtable.Unlock(This, lpRect); - if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) - { - RealPrimarySurface::update(); - } - return result; - } - - template - void DirectDrawSurface::restorePrimaryCaps(TDdsCaps& caps) - { - caps.dwCaps &= ~(DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY); - caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + SET_COMPAT_METHOD(Blt); + SET_COMPAT_METHOD(BltFast); + SET_COMPAT_METHOD(Flip); + SET_COMPAT_METHOD(GetCaps); + SET_COMPAT_METHOD(GetSurfaceDesc); + SET_COMPAT_METHOD(IsLost); + SET_COMPAT_METHOD(Lock); + SET_COMPAT_METHOD(QueryInterface); + SET_COMPAT_METHOD(ReleaseDC); + SET_COMPAT_METHOD(Restore); + SET_COMPAT_METHOD(SetClipper); + SET_COMPAT_METHOD(SetPalette); + SET_COMPAT_METHOD(Unlock); } template DirectDrawSurface; @@ -537,21 +50,4 @@ namespace DDraw template DirectDrawSurface; template DirectDrawSurface; template DirectDrawSurface; - - template HRESULT DirectDrawSurface::createCompatPrimarySurface( - CompatRef dd, - TSurfaceDesc compatDesc, - IDirectDrawSurface*& compatSurface); - template HRESULT DirectDrawSurface::createCompatPrimarySurface( - CompatRef dd, - TSurfaceDesc compatDesc, - IDirectDrawSurface*& compatSurface); - template HRESULT DirectDrawSurface::createCompatPrimarySurface( - CompatRef dd, - TSurfaceDesc compatDesc, - IDirectDrawSurface4*& compatSurface); - template HRESULT DirectDrawSurface::createCompatPrimarySurface( - CompatRef dd, - TSurfaceDesc compatDesc, - IDirectDrawSurface7*& compatSurface); } diff --git a/DDrawCompat/DDraw/DirectDrawSurface.h b/DDrawCompat/DDraw/DirectDrawSurface.h index 9c6aa1a..3fa05f3 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.h +++ b/DDrawCompat/DDraw/DirectDrawSurface.h @@ -12,59 +12,8 @@ namespace DDraw { public: typedef typename Types::TSurfaceDesc TSurfaceDesc; - typedef typename Types::TDdsCaps TDdsCaps; - typedef typename Types::TUnlockParam TUnlockParam; static void setCompatVtable(Vtable& vtable); - template - static HRESULT createCompatPrimarySurface( - CompatRef dd, - TSurfaceDesc compatDesc, - TSurface*& compatSurface); - - static void fixSurfacePtrs(CompatRef surface); - - 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); - - private: - static void restorePrimaryCaps(TDdsCaps& caps); }; } diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp new file mode 100644 index 0000000..d1bb721 --- /dev/null +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -0,0 +1,159 @@ +#include + +#include "Common/CompatPtr.h" +#include "DDraw/DisplayMode.h" +#include "DDraw/Surfaces/Surface.h" +#include "DDraw/Surfaces/SurfaceImpl.h" + +// {C62D8849-DFAC-4454-A1E8-DA67446426BA} +DEFINE_GUID(IID_CompatSurfacePrivateData, + 0xc62d8849, 0xdfac, 0x4454, 0xa1, 0xe8, 0xda, 0x67, 0x44, 0x64, 0x26, 0xba); + +namespace +{ + void fixSurfaceDesc(CompatRef dd, DWORD& flags, DWORD& caps, DDPIXELFORMAT& pf) + { + if ((flags & DDSD_WIDTH) && + (flags & DDSD_HEIGHT) && + !(caps & (DDSCAPS_ALPHA | DDSCAPS_ZBUFFER))) + { + if (!(flags & DDSD_PIXELFORMAT)) + { + auto dm = DDraw::DisplayMode::getDisplayMode(dd); + flags |= DDSD_PIXELFORMAT; + pf = dm.ddpfPixelFormat; + } + + if (!(caps & (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_OVERLAY | DDSCAPS_TEXTURE | + DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))) + { + flags |= DDSD_CAPS; + caps |= DDSCAPS_OFFSCREENPLAIN; + } + } + } +} + +namespace DDraw +{ + HRESULT STDMETHODCALLTYPE Surface::QueryInterface(REFIID, LPVOID*) + { + return E_NOINTERFACE; + } + + ULONG STDMETHODCALLTYPE Surface::AddRef() + { + return 0; + } + + ULONG STDMETHODCALLTYPE Surface::Release() + { + delete this; + return 0; + } + + Surface::~Surface() + { + } + + void Surface::attach(CompatRef dds, std::unique_ptr& privateData) + { + if (SUCCEEDED(dds->SetPrivateData(&dds, IID_CompatSurfacePrivateData, + privateData.get(), sizeof(privateData.get()), DDSPD_IUNKNOWNPOINTER))) + { + privateData.release(); + } + } + + HRESULT WINAPI Surface::attachToLinkedSurfaces( + IDirectDrawSurface7* surface, DDSURFACEDESC2* /*desc*/, void* rootSurface) + { + CompatPtr surfaceReleaser(surface); + if (surface == rootSurface) + { + return DDENUMRET_CANCEL; + } + + std::unique_ptr privateData(new Surface()); + attach(*surface, privateData); + CompatVtableBase::s_origVtable.EnumAttachedSurfaces( + surface, rootSurface, &attachToLinkedSurfaces); + return DDENUMRET_OK; + } + + template + HRESULT Surface::create(CompatRef dd, TSurfaceDesc desc, TSurface*& surface) + { + CompatPtr dd7(Compat::queryInterface(&dd)); + fixSurfaceDesc(*dd7, desc.dwFlags, desc.ddsCaps.dwCaps, desc.ddpfPixelFormat); + + HRESULT result = dd->CreateSurface(&dd, &desc, &surface, nullptr); + if (SUCCEEDED(result)) + { + SurfaceImpl::fixSurfacePtrs(*surface); + + CompatPtr surface7( + Compat::queryInterface(surface)); + std::unique_ptr privateData(new Surface()); + attach(*surface7, privateData); + if (desc.ddsCaps.dwCaps & DDSCAPS_COMPLEX) + { + CompatVtableBase::s_origVtable.EnumAttachedSurfaces( + surface7, surface7, &attachToLinkedSurfaces); + } + } + + return result; + } + + template HRESULT Surface::create( + CompatRef dd, DDSURFACEDESC desc, IDirectDrawSurface*& surface); + template HRESULT Surface::create( + CompatRef dd, DDSURFACEDESC desc, IDirectDrawSurface*& surface); + template HRESULT Surface::create( + CompatRef dd, DDSURFACEDESC2 desc, IDirectDrawSurface4*& surface); + template HRESULT Surface::create( + CompatRef dd, DDSURFACEDESC2 desc, IDirectDrawSurface7*& surface); + + void Surface::createImpl() + { + m_impl.reset(new SurfaceImpl()); + m_impl2.reset(new SurfaceImpl()); + m_impl3.reset(new SurfaceImpl()); + m_impl4.reset(new SurfaceImpl()); + m_impl7.reset(new SurfaceImpl()); + } + + template + SurfaceImpl* Surface::getImpl(CompatRef dds) + { + Surface* surface = nullptr; + DWORD surfacePtrSize = sizeof(surface); + CompatVtableBase::s_origVtable.GetPrivateData( + reinterpret_cast(&dds), + IID_CompatSurfacePrivateData, &surface, &surfacePtrSize); + if (!surface) + { + return nullptr; + } + + return surface->getImpl(); + } + + template SurfaceImpl* Surface::getImpl(CompatRef dds); + template SurfaceImpl* Surface::getImpl(CompatRef dds); + template SurfaceImpl* Surface::getImpl(CompatRef dds); + template SurfaceImpl* Surface::getImpl(CompatRef dds); + template SurfaceImpl* Surface::getImpl(CompatRef dds); + + template <> + SurfaceImpl* Surface::getImpl() const { return m_impl.get(); } + template <> + SurfaceImpl* Surface::getImpl() const { return m_impl2.get(); } + template <> + SurfaceImpl* Surface::getImpl() const { return m_impl3.get(); } + template <> + SurfaceImpl* Surface::getImpl() const { return m_impl4.get(); } + template <> + SurfaceImpl* Surface::getImpl() const { return m_impl7.get(); } +} diff --git a/DDrawCompat/DDraw/Surfaces/Surface.h b/DDrawCompat/DDraw/Surfaces/Surface.h new file mode 100644 index 0000000..15ab0a4 --- /dev/null +++ b/DDrawCompat/DDraw/Surfaces/Surface.h @@ -0,0 +1,48 @@ +#pragma once + +#define CINTERFACE + +#include + +#include + +#include "Common/CompatRef.h" + +namespace DDraw +{ + template + class SurfaceImpl; + + class Surface + { + public: + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*); + virtual ULONG STDMETHODCALLTYPE AddRef(); + virtual ULONG STDMETHODCALLTYPE Release(); + + virtual ~Surface(); + + template + static HRESULT create(CompatRef dd, TSurfaceDesc desc, TSurface*& surface); + + template + static SurfaceImpl* getImpl(CompatRef dds); + + template + SurfaceImpl* getImpl() const; + + protected: + static void attach(CompatRef dds, std::unique_ptr& privateData); + + std::unique_ptr> m_impl; + std::unique_ptr> m_impl2; + std::unique_ptr> m_impl3; + std::unique_ptr> m_impl4; + std::unique_ptr> m_impl7; + + private: + static HRESULT WINAPI attachToLinkedSurfaces( + IDirectDrawSurface7* surface, DDSURFACEDESC2* desc, void* rootSurface); + virtual void createImpl(); + }; +} diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp new file mode 100644 index 0000000..2acaad2 --- /dev/null +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -0,0 +1,520 @@ +#include + +#include "Common/CompatPtr.h" +#include "DDraw/CompatPrimarySurface.h" +#include "DDraw/DirectDrawPalette.h" +#include "DDraw/DisplayMode.h" +#include "DDraw/RealPrimarySurface.h" +#include "DDraw/Repository.h" +#include "DDraw/Surfaces/Surface.h" +#include "DDraw/Surfaces/SurfaceImpl.h" +#include "Gdi/Gdi.h" + +namespace +{ + bool mirrorBlt(CompatRef dst, CompatRef src, + RECT srcRect, DWORD mirrorFx); + + bool g_lockingPrimary = false; + + void fixSurfacePtr(CompatRef surface, const DDSURFACEDESC2& desc) + { + if ((desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) || 0 == desc.dwWidth || 0 == desc.dwHeight) + { + return; + } + + DDSURFACEDESC2 tempSurfaceDesc = desc; + tempSurfaceDesc.dwWidth = 1; + tempSurfaceDesc.dwHeight = 1; + DDraw::Repository::ScopedSurface tempSurface(desc); + if (!tempSurface.surface) + { + return; + } + + RECT r = { 0, 0, 1, 1 }; + surface->Blt(&surface, &r, tempSurface.surface, &r, DDBLT_WAIT, nullptr); + } + + HRESULT WINAPI fixSurfacePtrEnumCallback( + LPDIRECTDRAWSURFACE7 lpDDSurface, + LPDDSURFACEDESC2 lpDDSurfaceDesc, + LPVOID lpContext) + { + auto& visitedSurfaces = *static_cast*>(lpContext); + + CompatPtr surface(lpDDSurface); + if (visitedSurfaces.find(surface) == visitedSurfaces.end()) + { + visitedSurfaces.insert(surface); + fixSurfacePtr(*surface, *lpDDSurfaceDesc); + surface->EnumAttachedSurfaces(surface, lpContext, &fixSurfacePtrEnumCallback); + } + + return DDENUMRET_OK; + } + + void fixSurfacePtrs(CompatRef surface) + { + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + surface->GetSurfaceDesc(&surface, &desc); + + fixSurfacePtr(surface, desc); + std::set visitedSurfaces{ &surface }; + surface->EnumAttachedSurfaces(&surface, &visitedSurfaces, &fixSurfacePtrEnumCallback); + } + + CompatWeakPtr getMirroredSurface( + CompatRef surface, RECT* srcRect, DWORD mirrorFx) + { + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + HRESULT result = surface->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; + } + + DDraw::Repository::ScopedSurface mirroredSurface(desc); + if (!mirroredSurface.surface) + { + return nullptr; + } + + RECT rect = { 0, 0, static_cast(desc.dwWidth), static_cast(desc.dwHeight) }; + if ((mirrorFx & DDBLTFX_MIRRORLEFTRIGHT) && (mirrorFx & DDBLTFX_MIRRORUPDOWN)) + { + DDraw::Repository::Surface tempMirroredSurface = DDraw::Repository::ScopedSurface(desc); + if (!tempMirroredSurface.surface || + !mirrorBlt(*tempMirroredSurface.surface, surface, srcRect ? *srcRect : rect, + DDBLTFX_MIRRORLEFTRIGHT) || + !mirrorBlt(*mirroredSurface.surface, *tempMirroredSurface.surface, rect, + DDBLTFX_MIRRORUPDOWN)) + { + return nullptr; + } + } + else if (!mirrorBlt(*mirroredSurface.surface, surface, srcRect ? *srcRect : rect, mirrorFx)) + { + return nullptr; + } + + return mirroredSurface.surface; + } + + bool mirrorBlt(CompatRef dst, CompatRef 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 = dst->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 = dst->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; + } +} + +namespace DDraw +{ + template + template + HRESULT SurfaceImpl::createCompatPrimarySurface( + CompatRef dd, + TSurfaceDesc compatDesc, + TSurface*& compatSurface) + { + HRESULT result = RealPrimarySurface::create(dd); + if (FAILED(result)) + { + return result; + } + + CompatPtr dd7(Compat::queryInterface(&dd)); + const auto& dm = DisplayMode::getDisplayMode(*dd7); + compatDesc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + compatDesc.dwWidth = dm.dwWidth; + compatDesc.dwHeight = dm.dwHeight; + compatDesc.ddsCaps.dwCaps &= ~DDSCAPS_PRIMARYSURFACE; + compatDesc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; + compatDesc.ddpfPixelFormat = dm.ddpfPixelFormat; + + result = Surface::create(dd, compatDesc, compatSurface); + if (FAILED(result)) + { + Compat::Log() << "Failed to create the compat primary surface!"; + RealPrimarySurface::release(); + return result; + } + + CompatPtr primary(Compat::queryInterface(compatSurface)); + CompatPrimarySurface::setPrimary(*primary); + + return DD_OK; + } + + template + SurfaceImpl::~SurfaceImpl() + { + } + + template + void SurfaceImpl::fixSurfacePtrs(CompatRef surface) + { + CompatPtr surface7(Compat::queryInterface(&surface)); + ::fixSurfacePtrs(*surface7); + } + + template + HRESULT SurfaceImpl::Blt( + TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, + DWORD dwFlags, LPDDBLTFX lpDDBltFx) + { + const bool isPrimaryDest = CompatPrimarySurface::isPrimary(This); + if ((isPrimaryDest || CompatPrimarySurface::isPrimary(lpDDSrcSurface)) && + RealPrimarySurface::isLost()) + { + return DDERR_SURFACELOST; + } + + HRESULT result = DD_OK; + CompatPtr mirroredSrcSurface; + + if (lpDDSrcSurface && (dwFlags & DDBLT_DDFX) && lpDDBltFx && + (lpDDBltFx->dwDDFX & (DDBLTFX_MIRRORLEFTRIGHT | DDBLTFX_MIRRORUPDOWN))) + { + CompatPtr srcSurface( + Compat::queryInterface(lpDDSrcSurface)); + mirroredSrcSurface.reset(Compat::queryInterface( + getMirroredSurface(*srcSurface, lpSrcRect, lpDDBltFx->dwDDFX).get())); + if (!mirroredSrcSurface) + { + LOG_ONCE("Failed to emulate a mirrored Blt"); + } + } + + 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); + } + } + else + { + result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); + } + + if (isPrimaryDest && SUCCEEDED(result)) + { + RealPrimarySurface::invalidate(lpDestRect); + RealPrimarySurface::update(); + } + + return result; + } + + template + HRESULT SurfaceImpl::BltFast( + TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans) + { + const bool isPrimaryDest = CompatPrimarySurface::isPrimary(This); + if ((isPrimaryDest || CompatPrimarySurface::isPrimary(lpDDSrcSurface)) && + RealPrimarySurface::isLost()) + { + return DDERR_SURFACELOST; + } + + HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans); + if (isPrimaryDest && SUCCEEDED(result)) + { + const LONG x = dwX; + const LONG y = dwY; + RECT destRect = { x, y, x, y }; + if (lpSrcRect) + { + destRect.right += lpSrcRect->right - lpSrcRect->left; + destRect.bottom += lpSrcRect->bottom - lpSrcRect->top; + } + else + { + TSurfaceDesc desc = {}; + desc.dwSize = sizeof(desc); + s_origVtable.GetSurfaceDesc(lpDDSrcSurface, &desc); + destRect.right += desc.dwWidth; + destRect.bottom += desc.dwHeight; + } + RealPrimarySurface::invalidate(&destRect); + RealPrimarySurface::update(); + } + return result; + } + + template + HRESULT SurfaceImpl::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags) + { + HRESULT result = s_origVtable.Flip(This, lpDDSurfaceTargetOverride, dwFlags); + if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) + { + result = RealPrimarySurface::flip(dwFlags); + } + return result; + } + + template + HRESULT SurfaceImpl::GetCaps(TSurface* This, TDdsCaps* lpDDSCaps) + { + HRESULT result = s_origVtable.GetCaps(This, lpDDSCaps); + if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) + { + restorePrimaryCaps(*lpDDSCaps); + } + return result; + } + + template + HRESULT SurfaceImpl::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc) + { + HRESULT result = s_origVtable.GetSurfaceDesc(This, lpDDSurfaceDesc); + if (SUCCEEDED(result) && !g_lockingPrimary && CompatPrimarySurface::isPrimary(This)) + { + restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps); + } + return result; + } + + template + HRESULT SurfaceImpl::IsLost(TSurface* This) + { + HRESULT result = s_origVtable.IsLost(This); + if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) + { + result = RealPrimarySurface::isLost() ? DDERR_SURFACELOST : DD_OK; + } + return result; + } + + template + HRESULT SurfaceImpl::Lock( + TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc, + DWORD dwFlags, HANDLE hEvent) + { + if (CompatPrimarySurface::isPrimary(This)) + { + if (RealPrimarySurface::isLost()) + { + return DDERR_SURFACELOST; + } + g_lockingPrimary = true; + } + + HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent); + if (SUCCEEDED(result) && g_lockingPrimary && lpDDSurfaceDesc) + { + RealPrimarySurface::invalidate(lpDestRect); + restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps); + } + else if (DDERR_SURFACELOST == result) + { + TSurfaceDesc desc = {}; + desc.dwSize = sizeof(desc); + if (SUCCEEDED(s_origVtable.GetSurfaceDesc(This, &desc)) && !(desc.dwFlags & DDSD_HEIGHT)) + { + // Fixes missing handling for lost vertex buffers in Messiah + s_origVtable.Restore(This); + // Still, pass back DDERR_SURFACELOST to the application in case it handles it + } + } + + g_lockingPrimary = false; + return result; + } + + template + HRESULT SurfaceImpl::QueryInterface(TSurface* This, REFIID riid, LPVOID* obp) + { + if (riid == IID_IDirectDrawGammaControl && CompatPrimarySurface::isPrimary(This)) + { + auto realPrimary(RealPrimarySurface::getSurface()); + return realPrimary->QueryInterface(realPrimary, riid, obp); + } + return s_origVtable.QueryInterface(This, riid, obp); + } + + template + HRESULT SurfaceImpl::ReleaseDC(TSurface* This, HDC hDC) + { + const bool isPrimary = CompatPrimarySurface::isPrimary(This); + if (isPrimary && RealPrimarySurface::isLost()) + { + return DDERR_SURFACELOST; + } + + HRESULT result = s_origVtable.ReleaseDC(This, hDC); + if (isPrimary && SUCCEEDED(result)) + { + RealPrimarySurface::invalidate(nullptr); + RealPrimarySurface::update(); + } + return result; + } + + template + HRESULT SurfaceImpl::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 (CompatPrimarySurface::isPrimary(This)) + { + result = RealPrimarySurface::restore(); + if (wasLost) + { + Gdi::invalidate(nullptr); + } + } + } + return result; + } + + template + HRESULT SurfaceImpl::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper) + { + HRESULT result = s_origVtable.SetClipper(This, lpDDClipper); + if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) + { + RealPrimarySurface::setClipper(lpDDClipper); + } + return result; + } + + template + HRESULT SurfaceImpl::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) + { + const bool isPrimary = CompatPrimarySurface::isPrimary(This); + if (isPrimary) + { + if (lpDDPalette) + { + DirectDrawPalette::waitForNextUpdate(); + } + if (lpDDPalette == CompatPrimarySurface::g_palette) + { + return DD_OK; + } + } + + HRESULT result = s_origVtable.SetPalette(This, lpDDPalette); + if (isPrimary && SUCCEEDED(result)) + { + CompatPrimarySurface::g_palette = lpDDPalette; + RealPrimarySurface::setPalette(); + } + return result; + } + + template + HRESULT SurfaceImpl::Unlock(TSurface* This, TUnlockParam lpRect) + { + HRESULT result = s_origVtable.Unlock(This, lpRect); + if (SUCCEEDED(result) && CompatPrimarySurface::isPrimary(This)) + { + RealPrimarySurface::update(); + } + return result; + } + + template + void SurfaceImpl::restorePrimaryCaps(TDdsCaps& caps) + { + caps.dwCaps &= ~(DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY); + caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + } + + template + const Vtable& SurfaceImpl::s_origVtable = CompatVtableBase::s_origVtable; + + template SurfaceImpl; + template SurfaceImpl; + template SurfaceImpl; + template SurfaceImpl; + template SurfaceImpl; + + template HRESULT SurfaceImpl::createCompatPrimarySurface( + CompatRef dd, + TSurfaceDesc compatDesc, + IDirectDrawSurface*& compatSurface); + template HRESULT SurfaceImpl::createCompatPrimarySurface( + CompatRef dd, + TSurfaceDesc compatDesc, + IDirectDrawSurface*& compatSurface); + template HRESULT SurfaceImpl::createCompatPrimarySurface( + CompatRef dd, + TSurfaceDesc compatDesc, + IDirectDrawSurface4*& compatSurface); + template HRESULT SurfaceImpl::createCompatPrimarySurface( + CompatRef dd, + TSurfaceDesc compatDesc, + IDirectDrawSurface7*& compatSurface); +} diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h new file mode 100644 index 0000000..5d680b9 --- /dev/null +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h @@ -0,0 +1,50 @@ +#pragma once + +#define CINTERFACE + +#include + +#include "Common/CompatRef.h" +#include "Common/CompatVtable.h" +#include "DDraw/Types.h" + +namespace DDraw +{ + template + class SurfaceImpl + { + public: + typedef typename Types::TSurfaceDesc TSurfaceDesc; + typedef typename Types::TDdsCaps TDdsCaps; + typedef typename Types::TUnlockParam TUnlockParam; + + virtual ~SurfaceImpl(); + + template + static HRESULT createCompatPrimarySurface( + CompatRef dd, TSurfaceDesc compatDesc, TSurface*& compatSurface); + static void fixSurfacePtrs(CompatRef surface); + + virtual HRESULT Blt(TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, + DWORD dwFlags, LPDDBLTFX lpDDBltFx); + virtual HRESULT BltFast(TSurface* This, DWORD dwX, DWORD dwY, + TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans); + virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags); + virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps); + virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc); + virtual HRESULT IsLost(TSurface* This); + virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc, + DWORD dwFlags, HANDLE hEvent); + virtual HRESULT QueryInterface(TSurface* This, REFIID riid, LPVOID* obp); + virtual HRESULT ReleaseDC(TSurface* This, HDC hDC); + virtual HRESULT Restore(TSurface* This); + virtual HRESULT SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper); + virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette); + virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect); + + private: + static void restorePrimaryCaps(TDdsCaps& caps); + + static const Vtable& s_origVtable; + }; +} diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 9c43182..e416deb 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -179,6 +179,8 @@ + + @@ -227,6 +229,8 @@ + + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 5bfd611..d10eaa5 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -67,6 +67,12 @@ {41544d1c-712a-4bef-8913-a40155a33ba0} + + {0550f0bd-b66f-4c6a-9072-e83bdfc52e4d} + + + {c60f8247-4d67-4dcf-9f97-f1c5b1acc469} + @@ -240,6 +246,12 @@ Header Files\Dll + + Header Files\DDraw\Surfaces + + + Header Files\DDraw\Surfaces + @@ -359,6 +371,12 @@ Source Files\Dll + + Source Files\DDraw\Surfaces + + + Source Files\DDraw\Surfaces +