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:
parent
9ddeab4149
commit
495325c984
@ -1,6 +1,4 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "CompatDirectDraw.h"
|
#include "CompatDirectDraw.h"
|
||||||
#include "CompatDirectDrawPalette.h"
|
#include "CompatDirectDrawPalette.h"
|
||||||
@ -14,23 +12,14 @@
|
|||||||
|
|
||||||
namespace
|
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 mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx);
|
||||||
|
|
||||||
bool g_lockingPrimary = false;
|
bool g_lockingPrimary = false;
|
||||||
|
|
||||||
void fixSurfacePtr(IDirectDrawSurface7& surface, const DDSURFACEDESC2& desc)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@ -38,16 +27,15 @@ namespace
|
|||||||
DDSURFACEDESC2 tempSurfaceDesc = desc;
|
DDSURFACEDESC2 tempSurfaceDesc = desc;
|
||||||
tempSurfaceDesc.dwWidth = 1;
|
tempSurfaceDesc.dwWidth = 1;
|
||||||
tempSurfaceDesc.dwHeight = 1;
|
tempSurfaceDesc.dwHeight = 1;
|
||||||
SimilarSurface tempSurface = getSimilarSurface(desc);
|
DDrawRepository::ScopedSurface tempSurface(desc);
|
||||||
if (!tempSurface.front)
|
if (!tempSurface.surface)
|
||||||
{
|
{
|
||||||
LOG_ONCE("Failed to fix a surface memory pointer");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT r = { 0, 0, 1, 1 };
|
RECT r = { 0, 0, 1, 1 };
|
||||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Blt(
|
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Blt(
|
||||||
&surface, &r, tempSurface.front, &r, DDBLT_WAIT, nullptr);
|
&surface, &r, tempSurface.surface, &r, DDBLT_WAIT, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT WINAPI enumSurfacesCallback(
|
HRESULT WINAPI enumSurfacesCallback(
|
||||||
@ -100,8 +88,8 @@ namespace
|
|||||||
desc.dwHeight = srcRect->bottom - srcRect->top;
|
desc.dwHeight = srcRect->bottom - srcRect->top;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimilarSurface similarSurface = getSimilarSurface(desc);
|
DDrawRepository::ScopedSurface mirroredSurface(desc);
|
||||||
if (!similarSurface.front)
|
if (!mirroredSurface.surface)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -109,19 +97,23 @@ namespace
|
|||||||
RECT rect = { 0, 0, static_cast<LONG>(desc.dwWidth), static_cast<LONG>(desc.dwHeight) };
|
RECT rect = { 0, 0, static_cast<LONG>(desc.dwWidth), static_cast<LONG>(desc.dwHeight) };
|
||||||
if ((mirrorFx & DDBLTFX_MIRRORLEFTRIGHT) && (mirrorFx & DDBLTFX_MIRRORUPDOWN))
|
if ((mirrorFx & DDBLTFX_MIRRORLEFTRIGHT) && (mirrorFx & DDBLTFX_MIRRORUPDOWN))
|
||||||
{
|
{
|
||||||
if (!mirrorBlt(*similarSurface.back, surface, srcRect ? *srcRect : rect, DDBLTFX_MIRRORLEFTRIGHT) ||
|
DDrawRepository::Surface tempMirroredSurface = DDrawRepository::ScopedSurface(desc);
|
||||||
!mirrorBlt(*similarSurface.front, *similarSurface.back, rect, DDBLTFX_MIRRORUPDOWN))
|
if (!tempMirroredSurface.surface ||
|
||||||
|
!mirrorBlt(*tempMirroredSurface.surface, surface, srcRect ? *srcRect : rect,
|
||||||
|
DDBLTFX_MIRRORLEFTRIGHT) ||
|
||||||
|
!mirrorBlt(*mirroredSurface.surface, *tempMirroredSurface.surface, rect,
|
||||||
|
DDBLTFX_MIRRORUPDOWN))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!mirrorBlt(*similarSurface.front, surface, srcRect ? *srcRect : rect, mirrorFx))
|
else if (!mirrorBlt(*mirroredSurface.surface, surface, srcRect ? *srcRect : rect, mirrorFx))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
origVtable.AddRef(similarSurface.front);
|
origVtable.AddRef(mirroredSurface.surface);
|
||||||
return similarSurface.front;
|
return mirroredSurface.surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
@ -147,105 +139,6 @@ namespace
|
|||||||
return mirroredSurface;
|
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)
|
bool mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx)
|
||||||
{
|
{
|
||||||
if (DDBLTFX_MIRRORLEFTRIGHT == mirrorFx)
|
if (DDBLTFX_MIRRORLEFTRIGHT == mirrorFx)
|
||||||
|
@ -1,10 +1,29 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "CompatDirectDraw.h"
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
#include "DDrawLog.h"
|
#include "DDrawLog.h"
|
||||||
#include "DDrawProcs.h"
|
#include "DDrawProcs.h"
|
||||||
#include "DDrawRepository.h"
|
#include "DDrawRepository.h"
|
||||||
|
|
||||||
namespace
|
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* createDirectDraw()
|
||||||
{
|
{
|
||||||
IDirectDraw7* dd = nullptr;
|
IDirectDraw7* dd = nullptr;
|
||||||
@ -26,10 +45,143 @@ namespace
|
|||||||
|
|
||||||
return dd;
|
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
|
namespace DDrawRepository
|
||||||
{
|
{
|
||||||
|
ScopedSurface::ScopedSurface(const DDSURFACEDESC2& desc)
|
||||||
|
: Surface(getSurface(desc))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedSurface::~ScopedSurface()
|
||||||
|
{
|
||||||
|
returnSurface(*this);
|
||||||
|
}
|
||||||
|
|
||||||
IDirectDraw7* getDirectDraw()
|
IDirectDraw7* getDirectDraw()
|
||||||
{
|
{
|
||||||
static IDirectDraw7* dd = createDirectDraw();
|
static IDirectDraw7* dd = createDirectDraw();
|
||||||
|
@ -6,5 +6,18 @@
|
|||||||
|
|
||||||
namespace DDrawRepository
|
namespace DDrawRepository
|
||||||
{
|
{
|
||||||
|
struct Surface
|
||||||
|
{
|
||||||
|
DDSURFACEDESC2 desc;
|
||||||
|
IDirectDrawSurface7* surface;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedSurface : public Surface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScopedSurface(const DDSURFACEDESC2& desc);
|
||||||
|
~ScopedSurface();
|
||||||
|
};
|
||||||
|
|
||||||
IDirectDraw7* getDirectDraw();
|
IDirectDraw7* getDirectDraw();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user