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

Mitigate performance issues caused by slow surface interface release

Releasing the last reference to a surface interface has a significant
performance impact. Mitigating the issue by eliminating some frequent
but unnecessary QueryInterface calls.

Fixes most of the performance drop reported in issue #24.
This commit is contained in:
narzoul 2017-11-18 22:28:04 +01:00
parent 3f1fa0fae1
commit 60c3c4f153
8 changed files with 45 additions and 76 deletions

View File

@ -26,13 +26,6 @@ namespace
namespace DDraw namespace DDraw
{ {
CompatPtr<IDirectDraw7> getDirectDraw(CompatRef<IDirectDrawSurface7> surface)
{
CompatPtr<IUnknown> dd;
surface.get().lpVtbl->GetDDInterface(&surface, reinterpret_cast<void**>(&dd.getRef()));
return dd;
}
template <typename TSurface> template <typename TSurface>
void DirectDrawSurface<TSurface>::setCompatVtable(Vtable<TSurface>& vtable) void DirectDrawSurface<TSurface>::setCompatVtable(Vtable<TSurface>& vtable)
{ {

View File

@ -8,8 +8,6 @@
namespace DDraw namespace DDraw
{ {
CompatPtr<IDirectDraw7> getDirectDraw(CompatRef<IDirectDrawSurface7> surface);
template <typename TSurface> template <typename TSurface>
class DirectDrawSurface : public CompatVtable<Vtable<TSurface>> class DirectDrawSurface : public CompatVtable<Vtable<TSurface>>
{ {

View File

@ -8,9 +8,14 @@
namespace namespace
{ {
DDSURFACEDESC2 g_primarySurfaceDesc = {}; DDSURFACEDESC2 g_primarySurfaceDesc = {};
CompatWeakPtr<IDirectDrawSurface> g_gdiSurface = nullptr; CompatWeakPtr<IDirectDrawSurface7> g_primarySurface = nullptr;
CompatWeakPtr<IDirectDrawSurface> g_primarySurface = nullptr; HANDLE g_gdiResourceHandle = nullptr;
DWORD g_origCaps = 0; DWORD g_origCaps = 0;
HANDLE getResourceHandle(IDirectDrawSurface7& surface)
{
return reinterpret_cast<HANDLE**>(&surface)[1][2];
}
} }
namespace DDraw namespace DDraw
@ -24,7 +29,7 @@ namespace DDraw
{ {
Compat::LogEnter("PrimarySurface::~PrimarySurface"); Compat::LogEnter("PrimarySurface::~PrimarySurface");
g_gdiSurface = nullptr; g_gdiResourceHandle = nullptr;
g_primarySurface = nullptr; g_primarySurface = nullptr;
g_origCaps = 0; g_origCaps = 0;
s_palette = nullptr; s_palette = nullptr;
@ -68,9 +73,8 @@ namespace DDraw
std::unique_ptr<Surface> privateData(new PrimarySurface(Surface::getSurface(*surface))); std::unique_ptr<Surface> privateData(new PrimarySurface(Surface::getSurface(*surface)));
attach(*surface7, privateData); attach(*surface7, privateData);
CompatPtr<IDirectDrawSurface> surface1(Compat::queryInterface<IDirectDrawSurface>(surface)); g_gdiResourceHandle = getResourceHandle(*surface7);
g_gdiSurface = surface1; g_primarySurface = surface7;
g_primarySurface = surface1;
g_origCaps = origCaps; g_origCaps = origCaps;
ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc)); ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc));
@ -105,11 +109,12 @@ namespace DDraw
HRESULT PrimarySurface::flipToGdiSurface() HRESULT PrimarySurface::flipToGdiSurface()
{ {
if (!g_primarySurface) CompatPtr<IDirectDrawSurface7> gdiSurface;
if (!g_primarySurface || !(gdiSurface = getGdiSurface()))
{ {
return DDERR_NOTFOUND; return DDERR_NOTFOUND;
} }
return g_primarySurface.get()->lpVtbl->Flip(g_primarySurface, g_gdiSurface, DDFLIP_WAIT); return g_primarySurface.get()->lpVtbl->Flip(g_primarySurface, gdiSurface, DDFLIP_WAIT);
} }
const DDSURFACEDESC2& PrimarySurface::getDesc() const DDSURFACEDESC2& PrimarySurface::getDesc()
@ -118,18 +123,36 @@ namespace DDraw
} }
CompatPtr<IDirectDrawSurface7> PrimarySurface::getGdiSurface() CompatPtr<IDirectDrawSurface7> PrimarySurface::getGdiSurface()
{
return CompatPtr<IDirectDrawSurface7>::from(g_gdiSurface.get());
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
{ {
if (!g_primarySurface) if (!g_primarySurface)
{ {
return nullptr; return nullptr;
} }
return CompatPtr<IDirectDrawSurface7>(
Compat::queryInterface<IDirectDrawSurface7>(g_primarySurface.get())); DDSCAPS2 caps = {};
caps.dwCaps = DDSCAPS_FLIP;
CompatWeakPtr<IDirectDrawSurface7> surface(g_primarySurface);
do
{
if (getResourceHandle(*surface) == g_gdiResourceHandle)
{
return CompatPtr<IDirectDrawSurface7>::from(surface.get());
}
if (FAILED(surface->GetAttachedSurface(surface, &caps, &surface.getRef())))
{
return nullptr;
}
surface->Release(surface);
} while (surface != g_primarySurface);
return nullptr;
}
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
{
return g_primarySurface;
} }
DWORD PrimarySurface::getOrigCaps() DWORD PrimarySurface::getOrigCaps()
@ -162,37 +185,6 @@ namespace DDraw
} while (surfacePtr && surfacePtr != &surface); } while (surfacePtr && surfacePtr != &surface);
} }
void PrimarySurface::updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride)
{
auto primary(CompatPtr<IDirectDrawSurface>::from(m_surface->getDirectDrawSurface().get()));
if (flipTargetOverride)
{
if (g_gdiSurface.get() == flipTargetOverride)
{
g_gdiSurface = primary;
}
else if (g_gdiSurface.get() == primary)
{
g_gdiSurface = flipTargetOverride;
}
return;
}
DDSCAPS caps = {};
caps.dwCaps = DDSCAPS_FLIP;
CompatPtr<IDirectDrawSurface> current(primary);
CompatPtr<IDirectDrawSurface> next;
HRESULT result = current->GetAttachedSurface(current, &caps, &next.getRef());
while (SUCCEEDED(result) && next.get() != g_gdiSurface.get() && next.get() != primary)
{
current = next;
next.reset();
result = current->GetAttachedSurface(current, &caps, &next.getRef());
}
g_gdiSurface = current;
}
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette; CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;
PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {}; PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {};
std::vector<std::vector<unsigned char>> PrimarySurface::s_surfaceBuffers; std::vector<std::vector<unsigned char>> PrimarySurface::s_surfaceBuffers;

View File

@ -19,7 +19,7 @@ namespace DDraw
static HRESULT flipToGdiSurface(); static HRESULT flipToGdiSurface();
static const DDSURFACEDESC2& getDesc(); static const DDSURFACEDESC2& getDesc();
static CompatPtr<IDirectDrawSurface7> getGdiSurface(); static CompatPtr<IDirectDrawSurface7> getGdiSurface();
static CompatPtr<IDirectDrawSurface7> getPrimary(); static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
static DWORD getOrigCaps(); static DWORD getOrigCaps();
void updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride); void updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride);

View File

@ -96,8 +96,6 @@ namespace DDraw
result = RealPrimarySurface::flip(dwFlags); result = RealPrimarySurface::flip(dwFlags);
if (SUCCEEDED(result) && !isFlipEmulated) if (SUCCEEDED(result) && !isFlipEmulated)
{ {
static_cast<PrimarySurface*>(m_data)->updateGdiSurfacePtr(
CompatPtr<IDirectDrawSurface>::from(lpDDSurfaceTargetOverride));
return DD_OK; return DD_OK;
} }

View File

@ -108,7 +108,6 @@ namespace DDraw
Surface::Surface() Surface::Surface()
: m_ddObject(nullptr) : m_ddObject(nullptr)
, m_dds(nullptr)
, m_ddId() , m_ddId()
, m_refCount(0) , m_refCount(0)
{ {
@ -133,8 +132,6 @@ namespace DDraw
privateData->m_impl4->m_data = privateData.get(); privateData->m_impl4->m_data = privateData.get();
privateData->m_impl7->m_data = privateData.get(); privateData->m_impl7->m_data = privateData.get();
privateData->m_dds = CompatPtr<IDirectDrawSurface>(
Compat::queryInterface<IDirectDrawSurface>(&dds));
privateData->m_ddId = getDdIidFromVtablePtr(reinterpret_cast<void**>(dd.get())[0]); privateData->m_ddId = getDdIidFromVtablePtr(reinterpret_cast<void**>(dd.get())[0]);
privateData->m_ddObject = DDraw::getDdObject(*CompatPtr<IDirectDraw>(dd)); privateData->m_ddObject = DDraw::getDdObject(*CompatPtr<IDirectDraw>(dd));
@ -207,16 +204,6 @@ namespace DDraw
template <> template <>
SurfaceImpl<IDirectDrawSurface7>* Surface::getImpl<IDirectDrawSurface7>() const { return m_impl7.get(); } SurfaceImpl<IDirectDrawSurface7>* Surface::getImpl<IDirectDrawSurface7>() const { return m_impl7.get(); }
CompatPtr<IDirectDraw7> Surface::getDirectDraw() const
{
return DDraw::getDirectDraw(*getDirectDrawSurface());
}
CompatPtr<IDirectDrawSurface7> Surface::getDirectDrawSurface() const
{
return CompatPtr<IDirectDrawSurface7>(Compat::queryInterface<IDirectDrawSurface7>(m_dds));
}
template <typename TSurface> template <typename TSurface>
Surface* Surface::getSurface(TSurface& dds) Surface* Surface::getSurface(TSurface& dds)
{ {

View File

@ -29,9 +29,6 @@ namespace DDraw
template <typename TSurface> template <typename TSurface>
static Surface* getSurface(TSurface& dds); static Surface* getSurface(TSurface& dds);
CompatPtr<IDirectDraw7> getDirectDraw() const;
CompatPtr<IDirectDrawSurface7> getDirectDrawSurface() const;
template <typename TSurface> template <typename TSurface>
SurfaceImpl<TSurface>* getImpl() const; SurfaceImpl<TSurface>* getImpl() const;
@ -55,7 +52,6 @@ namespace DDraw
IDirectDrawSurface7* surface, DDSURFACEDESC2* desc, void* rootSurface); IDirectDrawSurface7* surface, DDSURFACEDESC2* desc, void* rootSurface);
virtual void createImpl(); virtual void createImpl();
IDirectDrawSurface* m_dds;
IID m_ddId; IID m_ddId;
DWORD m_refCount; DWORD m_refCount;
}; };

View File

@ -121,7 +121,12 @@ namespace DDraw
replDesc.ddpfPixelFormat = desc.ddpfPixelFormat; replDesc.ddpfPixelFormat = desc.ddpfPixelFormat;
replDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; replDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
DDraw::Repository::ScopedSurface replacementSurface(*m_data->getDirectDraw(), replDesc); CompatPtr<IUnknown> ddUnk;
GetDDInterface(surface, reinterpret_cast<void**>(&ddUnk.getRef()));
CompatPtr<IDirectDraw7> dd;
ddUnk->QueryInterface(ddUnk, IID_IDirectDraw7, reinterpret_cast<void**>(&dd.getRef()));
DDraw::Repository::ScopedSurface replacementSurface(*dd, replDesc);
if (replacementSurface.surface) if (replacementSurface.surface)
{ {
surface = CompatPtr<TSurface>::from(replacementSurface.surface.get()); surface = CompatPtr<TSurface>::from(replacementSurface.surface.get());