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

Moved cached surfaces to DDrawRepository

This commit is contained in:
narzoul 2016-04-24 16:52:05 +02:00
parent 9ddeab4149
commit 495325c984
3 changed files with 181 additions and 123 deletions

View File

@ -1,6 +1,4 @@
#include <algorithm>
#include <set>
#include <vector>
#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<IDirectDrawSurface7>::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<LONG>(desc.dwWidth), static_cast<LONG>(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 <typename TSurface>
@ -147,105 +139,6 @@ namespace
return mirroredSurface;
}
SimilarSurface getSimilarSurface(const DDSURFACEDESC2& desc)
{
static std::vector<SimilarSurface> similarSurfacesVidMem;
static std::vector<SimilarSurface> similarSurfacesSysMem;
std::vector<SimilarSurface>& 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<IDirectDrawSurface7>::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<IDirectDraw7>::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<IDirectDraw7>::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)

View File

@ -1,10 +1,29 @@
#include <algorithm>
#include <vector>
#include "CompatDirectDraw.h"
#include "CompatDirectDrawSurface.h"
#include "DDrawLog.h"
#include "DDrawProcs.h"
#include "DDrawRepository.h"
namespace
{
using DDrawRepository::Surface;
static std::vector<Surface> g_sysMemSurfaces;
static std::vector<Surface> g_vidMemSurfaces;
IDirectDraw7* createDirectDraw();
Surface createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
std::vector<Surface>::iterator findSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf,
std::vector<Surface>& cachedSurfaces);
void destroySmallerSurfaces(DWORD width, DWORD height, const DDPIXELFORMAT& pf,
std::vector<Surface>& 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<IDirectDraw7>::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<Surface>& 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<IDirectDrawSurface7>::s_origVtable.Release(it->surface);
it = cachedSurfaces.erase(it);
}
else
{
++it;
}
}
}
std::vector<Surface>::iterator findSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf,
std::vector<Surface>& cachedSurfaces)
{
auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::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<Surface>& 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();

View File

@ -6,5 +6,18 @@
namespace DDrawRepository
{
struct Surface
{
DDSURFACEDESC2 desc;
IDirectDrawSurface7* surface;
};
class ScopedSurface : public Surface
{
public:
ScopedSurface(const DDSURFACEDESC2& desc);
~ScopedSurface();
};
IDirectDraw7* getDirectDraw();
}