From 495325c9849660df5ebfab094493e1c29c737265 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 24 Apr 2016 16:52:05 +0200 Subject: [PATCH] Moved cached surfaces to DDrawRepository --- DDrawCompat/CompatDirectDrawSurface.cpp | 139 +++------------------- DDrawCompat/DDrawRepository.cpp | 152 ++++++++++++++++++++++++ DDrawCompat/DDrawRepository.h | 13 ++ 3 files changed, 181 insertions(+), 123 deletions(-) diff --git a/DDrawCompat/CompatDirectDrawSurface.cpp b/DDrawCompat/CompatDirectDrawSurface.cpp index a2469d3..03c0e92 100644 --- a/DDrawCompat/CompatDirectDrawSurface.cpp +++ b/DDrawCompat/CompatDirectDrawSurface.cpp @@ -1,6 +1,4 @@ -#include #include -#include #include "CompatDirectDraw.h" #include "CompatDirectDrawPalette.h" @@ -14,23 +12,14 @@ 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); bool g_lockingPrimary = false; void fixSurfacePtr(IDirectDrawSurface7& surface, const DDSURFACEDESC2& desc) { - if ((desc.dwFlags & DDSD_CAPS) && (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)) + if ((desc.dwFlags & DDSD_CAPS) && (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) || + 0 == desc.dwWidth || 0 == desc.dwHeight) { return; } @@ -38,16 +27,15 @@ namespace DDSURFACEDESC2 tempSurfaceDesc = desc; tempSurfaceDesc.dwWidth = 1; tempSurfaceDesc.dwHeight = 1; - SimilarSurface tempSurface = getSimilarSurface(desc); - if (!tempSurface.front) + DDrawRepository::ScopedSurface tempSurface(desc); + if (!tempSurface.surface) { - LOG_ONCE("Failed to fix a surface memory pointer"); return; } RECT r = { 0, 0, 1, 1 }; CompatDirectDrawSurface::s_origVtable.Blt( - &surface, &r, tempSurface.front, &r, DDBLT_WAIT, nullptr); + &surface, &r, tempSurface.surface, &r, DDBLT_WAIT, nullptr); } HRESULT WINAPI enumSurfacesCallback( @@ -100,8 +88,8 @@ namespace desc.dwHeight = srcRect->bottom - srcRect->top; } - SimilarSurface similarSurface = getSimilarSurface(desc); - if (!similarSurface.front) + DDrawRepository::ScopedSurface mirroredSurface(desc); + if (!mirroredSurface.surface) { return nullptr; } @@ -109,19 +97,23 @@ namespace RECT rect = { 0, 0, static_cast(desc.dwWidth), static_cast(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)) + DDrawRepository::Surface tempMirroredSurface = DDrawRepository::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(*similarSurface.front, surface, srcRect ? *srcRect : rect, mirrorFx)) + else if (!mirrorBlt(*mirroredSurface.surface, surface, srcRect ? *srcRect : rect, mirrorFx)) { return nullptr; } - origVtable.AddRef(similarSurface.front); - return similarSurface.front; + origVtable.AddRef(mirroredSurface.surface); + return mirroredSurface.surface; } template @@ -147,105 +139,6 @@ namespace return mirroredSurface; } - SimilarSurface getSimilarSurface(const DDSURFACEDESC2& desc) - { - static std::vector similarSurfacesVidMem; - static std::vector similarSurfacesSysMem; - - std::vector& 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::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; - } - - IDirectDraw7* dd = DDrawRepository::getDirectDraw(); - if (!dd) - { - similarSurface.front = nullptr; - return similarSurface; - } - - HRESULT result = CompatDirectDraw::s_origVtable.CreateSurface( - dd, &similarDesc, &similarSurface.front, nullptr); - if (FAILED(result)) - { - LOG_ONCE("Failed to create a similar front surface"); - similarSurface.front = nullptr; - return similarSurface; - } - - result = CompatDirectDraw::s_origVtable.CreateSurface( - dd, &similarDesc, &similarSurface.back, nullptr); - if (FAILED(result)) - { - LOG_ONCE("Failed to create a similar back surface"); - 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) diff --git a/DDrawCompat/DDrawRepository.cpp b/DDrawCompat/DDrawRepository.cpp index fe58ce6..35626a1 100644 --- a/DDrawCompat/DDrawRepository.cpp +++ b/DDrawCompat/DDrawRepository.cpp @@ -1,10 +1,29 @@ +#include +#include + #include "CompatDirectDraw.h" +#include "CompatDirectDrawSurface.h" #include "DDrawLog.h" #include "DDrawProcs.h" #include "DDrawRepository.h" namespace { + using DDrawRepository::Surface; + + static std::vector g_sysMemSurfaces; + static std::vector g_vidMemSurfaces; + + IDirectDraw7* createDirectDraw(); + Surface createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps); + std::vector::iterator findSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, + std::vector& cachedSurfaces); + void destroySmallerSurfaces(DWORD width, DWORD height, const DDPIXELFORMAT& pf, + std::vector& cachedSurfaces); + Surface getSurface(const DDSURFACEDESC2& desc); + void normalizePixelFormat(DDPIXELFORMAT& pf); + void returnSurface(const Surface& surface); + IDirectDraw7* createDirectDraw() { IDirectDraw7* dd = nullptr; @@ -26,10 +45,143 @@ namespace return dd; } + + Surface createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps) + { + Surface surface = {}; + IDirectDraw7* dd = DDrawRepository::getDirectDraw(); + if (!dd) + { + return surface; + } + + surface.desc.dwSize = sizeof(surface.desc); + surface.desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + surface.desc.dwWidth = width; + surface.desc.dwHeight = height; + surface.desc.ddpfPixelFormat = pf; + surface.desc.ddsCaps.dwCaps = caps; + + HRESULT result = CompatDirectDraw::s_origVtable.CreateSurface( + dd, &surface.desc, &surface.surface, nullptr); + if (FAILED(result)) + { + LOG_ONCE("Failed to create a repository surface: " << result); + } + return surface; + } + + void destroySmallerSurfaces(DWORD width, DWORD height, const DDPIXELFORMAT& pf, + std::vector& cachedSurfaces) + { + auto it = cachedSurfaces.begin(); + while (it != cachedSurfaces.end()) + { + if (it->desc.dwWidth <= width && it->desc.dwHeight <= height && + 0 == memcmp(&it->desc.ddpfPixelFormat, &pf, sizeof(pf))) + { + CompatDirectDrawSurface::s_origVtable.Release(it->surface); + it = cachedSurfaces.erase(it); + } + else + { + ++it; + } + } + } + + std::vector::iterator findSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, + std::vector& cachedSurfaces) + { + auto& origVtable = CompatDirectDrawSurface::s_origVtable; + + auto it = cachedSurfaces.begin(); + while (it != cachedSurfaces.end()) + { + if (it->desc.dwWidth >= width && it->desc.dwHeight >= height && + 0 == memcmp(&it->desc.ddpfPixelFormat, &pf, sizeof(pf))) + { + if (FAILED(origVtable.IsLost(it->surface)) && FAILED(origVtable.Restore(it->surface))) + { + origVtable.Release(it->surface); + it = cachedSurfaces.erase(it); + continue; + } + return it; + } + ++it; + } + + return cachedSurfaces.end(); + } + + Surface getSurface(const DDSURFACEDESC2& desc) + { + std::vector& cachedSurfaces = + (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ? g_sysMemSurfaces : g_vidMemSurfaces; + + DDPIXELFORMAT pf = desc.ddpfPixelFormat; + normalizePixelFormat(pf); + + auto it = findSurface(desc.dwWidth, desc.dwHeight, pf, cachedSurfaces); + if (it != cachedSurfaces.end()) + { + Surface cachedSurface = *it; + cachedSurfaces.erase(it); + return cachedSurface; + } + + Surface newSurface = createSurface(desc.dwWidth, desc.dwHeight, pf, + DDSCAPS_OFFSCREENPLAIN | (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)); + if (newSurface.surface) + { + destroySmallerSurfaces(desc.dwWidth, desc.dwHeight, pf, cachedSurfaces); + } + return newSurface; + } + + void normalizePixelFormat(DDPIXELFORMAT& pf) + { + if (!(pf.dwFlags & DDPF_FOURCC)) + { + pf.dwFourCC = 0; + } + if (!(pf.dwFlags & (DDPF_ALPHAPIXELS | DDPF_ZPIXELS))) + { + pf.dwRGBAlphaBitMask = 0; + } + } + + void returnSurface(const Surface& surface) + { + if (!surface.surface) + { + return; + } + + if (surface.desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) + { + g_sysMemSurfaces.push_back(surface); + } + else + { + g_vidMemSurfaces.push_back(surface); + } + } } namespace DDrawRepository { + ScopedSurface::ScopedSurface(const DDSURFACEDESC2& desc) + : Surface(getSurface(desc)) + { + } + + ScopedSurface::~ScopedSurface() + { + returnSurface(*this); + } + IDirectDraw7* getDirectDraw() { static IDirectDraw7* dd = createDirectDraw(); diff --git a/DDrawCompat/DDrawRepository.h b/DDrawCompat/DDrawRepository.h index 6994c17..fb03362 100644 --- a/DDrawCompat/DDrawRepository.h +++ b/DDrawCompat/DDrawRepository.h @@ -6,5 +6,18 @@ namespace DDrawRepository { + struct Surface + { + DDSURFACEDESC2 desc; + IDirectDrawSurface7* surface; + }; + + class ScopedSurface : public Surface + { + public: + ScopedSurface(const DDSURFACEDESC2& desc); + ~ScopedSurface(); + }; + IDirectDraw7* getDirectDraw(); }