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
{
CompatPtr<IDirectDraw7> getDirectDraw(CompatRef<IDirectDrawSurface7> surface)
{
CompatPtr<IUnknown> dd;
surface.get().lpVtbl->GetDDInterface(&surface, reinterpret_cast<void**>(&dd.getRef()));
return dd;
}
template <typename TSurface>
void DirectDrawSurface<TSurface>::setCompatVtable(Vtable<TSurface>& vtable)
{

View File

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

View File

@ -8,9 +8,14 @@
namespace
{
DDSURFACEDESC2 g_primarySurfaceDesc = {};
CompatWeakPtr<IDirectDrawSurface> g_gdiSurface = nullptr;
CompatWeakPtr<IDirectDrawSurface> g_primarySurface = nullptr;
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface = nullptr;
HANDLE g_gdiResourceHandle = nullptr;
DWORD g_origCaps = 0;
HANDLE getResourceHandle(IDirectDrawSurface7& surface)
{
return reinterpret_cast<HANDLE**>(&surface)[1][2];
}
}
namespace DDraw
@ -24,7 +29,7 @@ namespace DDraw
{
Compat::LogEnter("PrimarySurface::~PrimarySurface");
g_gdiSurface = nullptr;
g_gdiResourceHandle = nullptr;
g_primarySurface = nullptr;
g_origCaps = 0;
s_palette = nullptr;
@ -68,9 +73,8 @@ namespace DDraw
std::unique_ptr<Surface> privateData(new PrimarySurface(Surface::getSurface(*surface)));
attach(*surface7, privateData);
CompatPtr<IDirectDrawSurface> surface1(Compat::queryInterface<IDirectDrawSurface>(surface));
g_gdiSurface = surface1;
g_primarySurface = surface1;
g_gdiResourceHandle = getResourceHandle(*surface7);
g_primarySurface = surface7;
g_origCaps = origCaps;
ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc));
@ -105,11 +109,12 @@ namespace DDraw
HRESULT PrimarySurface::flipToGdiSurface()
{
if (!g_primarySurface)
CompatPtr<IDirectDrawSurface7> gdiSurface;
if (!g_primarySurface || !(gdiSurface = getGdiSurface()))
{
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()
@ -118,18 +123,36 @@ namespace DDraw
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getGdiSurface()
{
return CompatPtr<IDirectDrawSurface7>::from(g_gdiSurface.get());
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
{
if (!g_primarySurface)
{
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()
@ -162,37 +185,6 @@ namespace DDraw
} 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;
PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {};
std::vector<std::vector<unsigned char>> PrimarySurface::s_surfaceBuffers;

View File

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

View File

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

View File

@ -108,7 +108,6 @@ namespace DDraw
Surface::Surface()
: m_ddObject(nullptr)
, m_dds(nullptr)
, m_ddId()
, m_refCount(0)
{
@ -133,8 +132,6 @@ namespace DDraw
privateData->m_impl4->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_ddObject = DDraw::getDdObject(*CompatPtr<IDirectDraw>(dd));
@ -207,16 +204,6 @@ namespace DDraw
template <>
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>
Surface* Surface::getSurface(TSurface& dds)
{

View File

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

View File

@ -121,7 +121,12 @@ namespace DDraw
replDesc.ddpfPixelFormat = desc.ddpfPixelFormat;
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)
{
surface = CompatPtr<TSurface>::from(replacementSurface.surface.get());