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

Create repository surfaces on the appropriate device

This change assigns a different DirectDraw repository object for each original
DirectDraw object that requires temporary surfaces, ensuring that video memory
surfaces are created on the appropriate device on a multi-GPU system.
This commit is contained in:
narzoul 2016-09-24 23:02:48 +02:00
parent 7220b80999
commit e8f987eb05
8 changed files with 98 additions and 46 deletions

View File

@ -26,6 +26,13 @@ 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

@ -1,5 +1,6 @@
#pragma once
#include "Common/CompatPtr.h"
#include "Common/CompatRef.h"
#include "Common/CompatVtable.h"
#include "DDraw/Visitors/DirectDrawSurfaceVtblVisitor.h"
@ -7,6 +8,8 @@
namespace DDraw
{
CompatPtr<IDirectDraw7> getDirectDraw(CompatRef<IDirectDrawSurface7> surface);
template <typename TSurface>
class DirectDrawSurface : public CompatVtable<Vtable<TSurface>>
{

View File

@ -1,8 +1,10 @@
#include <algorithm>
#include <map>
#include <vector>
#include "Common/CompatPtr.h"
#include "Common/Log.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/Repository.h"
#include "Dll/Procs.h"
@ -10,16 +12,23 @@ namespace
{
using DDraw::Repository::Surface;
static std::vector<Surface> g_sysMemSurfaces;
static std::vector<Surface> g_vidMemSurfaces;
struct Repository
{
CompatWeakPtr<IDirectDraw7> dd;
std::vector<Surface> surfaces;
};
Repository g_sysMemRepo;
std::map<void*, Repository> g_vidMemRepos;
CompatPtr<IDirectDraw7> createDirectDraw();
Surface createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
Surface createSurface(CompatRef<IDirectDraw7> dd,
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);
Surface getSurface(CompatRef<IDirectDraw7> dd, const DDSURFACEDESC2& desc);
void normalizePixelFormat(DDPIXELFORMAT& pf);
void returnSurface(const Surface& surface);
@ -30,21 +39,22 @@ namespace
reinterpret_cast<void**>(&dd.getRef()), IID_IDirectDraw7, nullptr);
if (FAILED(result))
{
Compat::Log() << "Failed to create a DirectDraw object in the repository: " << result;
LOG_ONCE("Failed to create a DirectDraw object in the repository: " << result);
return nullptr;
}
result = dd->SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL);
result = dd.get()->lpVtbl->SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL);
if (FAILED(result))
{
Compat::Log() << "Failed to set the cooperative level in the repository: " << result;
LOG_ONCE("Failed to set the cooperative level in the repository: " << result);
return nullptr;
}
return dd;
}
Surface createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps)
Surface createSurface(CompatRef<IDirectDraw7> dd,
DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps)
{
Surface surface = {};
@ -55,8 +65,7 @@ namespace
surface.desc.ddpfPixelFormat = pf;
surface.desc.ddsCaps.dwCaps = caps;
auto dd(DDraw::Repository::getDirectDraw());
dd->CreateSurface(dd, &surface.desc, &surface.surface.getRef(), nullptr);
dd.get().lpVtbl->CreateSurface(&dd, &surface.desc, &surface.surface.getRef(), nullptr);
return surface;
}
@ -103,27 +112,52 @@ namespace
return cachedSurfaces.end();
}
Surface getSurface(const DDSURFACEDESC2& desc)
Repository& getRepository(CompatRef<IDirectDraw7> dd, DWORD caps)
{
std::vector<Surface>& cachedSurfaces =
(desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ? g_sysMemSurfaces : g_vidMemSurfaces;
if (caps & DDSCAPS_SYSTEMMEMORY)
{
g_sysMemRepo.dd = DDraw::Repository::getDirectDraw();
return g_sysMemRepo;
}
void* ddObject = DDraw::getDdObject(dd.get());
auto it = g_vidMemRepos.find(ddObject);
if (it == g_vidMemRepos.end())
{
Repository repo = {};
repo.dd = createDirectDraw().detach();
return g_vidMemRepos[ddObject] = repo;
}
return it->second;
}
Surface getSurface(CompatRef<IDirectDraw7> dd, const DDSURFACEDESC2& desc)
{
Repository& repo = getRepository(dd, desc.ddsCaps.dwCaps);
if (!repo.dd)
{
return Surface();
}
DDPIXELFORMAT pf = desc.ddpfPixelFormat;
normalizePixelFormat(pf);
auto it = findSurface(desc.dwWidth, desc.dwHeight, pf, cachedSurfaces);
if (it != cachedSurfaces.end())
auto it = findSurface(desc.dwWidth, desc.dwHeight, pf, repo.surfaces);
if (it != repo.surfaces.end())
{
Surface cachedSurface = *it;
cachedSurfaces.erase(it);
repo.surfaces.erase(it);
return cachedSurface;
}
Surface newSurface = createSurface(desc.dwWidth, desc.dwHeight, pf,
DDSCAPS_OFFSCREENPLAIN | (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY));
const DWORD memFlag = (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
? DDSCAPS_SYSTEMMEMORY : DDSCAPS_VIDEOMEMORY;
Surface newSurface = createSurface(*repo.dd, desc.dwWidth, desc.dwHeight, pf,
DDSCAPS_OFFSCREENPLAIN | memFlag);
if (newSurface.surface)
{
destroySmallerSurfaces(desc.dwWidth, desc.dwHeight, pf, cachedSurfaces);
newSurface.ddObject = DDraw::getDdObject(dd.get());
destroySmallerSurfaces(desc.dwWidth, desc.dwHeight, pf, repo.surfaces);
}
return newSurface;
}
@ -149,11 +183,11 @@ namespace
if (surface.desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
{
g_sysMemSurfaces.push_back(surface);
g_sysMemRepo.surfaces.push_back(surface);
}
else
{
g_vidMemSurfaces.push_back(surface);
g_vidMemRepos[surface.ddObject].surfaces.push_back(surface);
}
}
}
@ -162,8 +196,8 @@ namespace DDraw
{
namespace Repository
{
ScopedSurface::ScopedSurface(const DDSURFACEDESC2& desc)
: Surface(getSurface(desc))
ScopedSurface::ScopedSurface(CompatRef<IDirectDraw7> dd, const DDSURFACEDESC2& desc)
: Surface(getSurface(dd, desc))
{
}
@ -177,5 +211,18 @@ namespace DDraw
static auto dd = new CompatPtr<IDirectDraw7>(createDirectDraw());
return *dd;
}
void onRelease(void* ddObject)
{
auto it = g_vidMemRepos.find(ddObject);
if (it != g_vidMemRepos.end())
{
for (auto& surface : it->second.surfaces)
{
surface.surface->Release(surface.surface);
}
g_vidMemRepos.erase(it);
}
}
}
}

View File

@ -4,6 +4,7 @@
#include <ddraw.h>
#include "Common/CompatRef.h"
#include "Common/CompatWeakPtr.h"
namespace DDraw
@ -12,6 +13,7 @@ namespace DDraw
{
struct Surface
{
void* ddObject;
DDSURFACEDESC2 desc;
CompatWeakPtr<IDirectDrawSurface7> surface;
};
@ -19,10 +21,11 @@ namespace DDraw
class ScopedSurface : public Surface
{
public:
ScopedSurface(const DDSURFACEDESC2& desc);
ScopedSurface(CompatRef<IDirectDraw7> dd, const DDSURFACEDESC2& desc);
~ScopedSurface();
};
CompatWeakPtr<IDirectDraw7> getDirectDraw();
void onRelease(void* ddObject);
}
}

View File

@ -2,6 +2,7 @@
#include "Common/CompatPtr.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/DirectDrawSurface.h"
#include "DDraw/DisplayMode.h"
#include "DDraw/Surfaces/Surface.h"
#include "DDraw/Surfaces/SurfaceImpl.h"
@ -79,9 +80,9 @@ namespace DDraw
}
Surface::Surface()
: m_dds(nullptr)
: m_ddObject(nullptr)
, m_dds(nullptr)
, m_ddId()
, m_ddObject(nullptr)
, m_refCount(0)
{
}
@ -96,8 +97,7 @@ namespace DDraw
privateData.get(), sizeof(privateData.get()), DDSPD_IUNKNOWNPOINTER)))
{
CompatPtr<IUnknown> dd;
CompatVtable<IDirectDrawSurface7Vtbl>::s_origVtable.GetDDInterface(
&dds, reinterpret_cast<void**>(&dd.getRef()));
dds->GetDDInterface(&dds, reinterpret_cast<void**>(&dd.getRef()));
privateData->createImpl();
privateData->m_impl->m_data = privateData.get();
@ -187,10 +187,7 @@ namespace DDraw
CompatPtr<IDirectDraw7> Surface::getDirectDraw() const
{
auto dds(getDirectDrawSurface());
CompatPtr<IUnknown> dd;
m_impl7->GetDDInterface(dds, reinterpret_cast<void**>(&dd.getRef()));
return CompatPtr<IDirectDraw7>(dd);
return DDraw::getDirectDraw(*getDirectDrawSurface());
}
CompatPtr<IDirectDrawSurface7> Surface::getDirectDrawSurface() const

View File

@ -40,6 +40,7 @@ namespace DDraw
static void attach(CompatRef<IDirectDrawSurface7> dds, std::unique_ptr<Surface>& privateData);
void* m_ddObject;
std::unique_ptr<SurfaceImpl<IDirectDrawSurface>> m_impl;
std::unique_ptr<SurfaceImpl<IDirectDrawSurface2>> m_impl2;
std::unique_ptr<SurfaceImpl<IDirectDrawSurface3>> m_impl3;
@ -56,7 +57,6 @@ namespace DDraw
IDirectDrawSurface* m_dds;
IID m_ddId;
void* m_ddObject;
DWORD m_refCount;
};
}

View File

@ -1,6 +1,7 @@
#include <set>
#include "Common/CompatPtr.h"
#include "DDraw/DirectDrawSurface.h"
#include "DDraw/Repository.h"
#include "DDraw/Surfaces/Surface.h"
#include "DDraw/Surfaces/SurfaceImpl.h"
@ -27,17 +28,8 @@ namespace
return;
}
DDSURFACEDESC2 tempSurfaceDesc = desc;
tempSurfaceDesc.dwWidth = 1;
tempSurfaceDesc.dwHeight = 1;
DDraw::Repository::ScopedSurface tempSurface(desc);
if (!tempSurface.surface)
{
return;
}
RECT r = { 0, 0, 1, 1 };
surface->Blt(&surface, &r, tempSurface.surface, &r, DDBLT_WAIT, nullptr);
surface->Blt(&surface, &r, &surface, &r, DDBLT_WAIT, nullptr);
}
HRESULT WINAPI fixSurfacePtrEnumCallback(
@ -87,7 +79,8 @@ namespace
desc.dwHeight = srcRect->bottom - srcRect->top;
}
DDraw::Repository::ScopedSurface mirroredSurface(desc);
auto dd(DDraw::getDirectDraw(surface));
DDraw::Repository::ScopedSurface mirroredSurface(*dd, desc);
if (!mirroredSurface.surface)
{
return nullptr;
@ -96,7 +89,7 @@ namespace
RECT rect = { 0, 0, static_cast<LONG>(desc.dwWidth), static_cast<LONG>(desc.dwHeight) };
if ((mirrorFx & DDBLTFX_MIRRORLEFTRIGHT) && (mirrorFx & DDBLTFX_MIRRORUPDOWN))
{
DDraw::Repository::Surface tempMirroredSurface = DDraw::Repository::ScopedSurface(desc);
DDraw::Repository::Surface tempMirroredSurface = DDraw::Repository::ScopedSurface(*dd, desc);
if (!tempMirroredSurface.surface ||
!mirrorBlt(*tempMirroredSurface.surface, surface, srcRect ? *srcRect : rect,
DDBLTFX_MIRRORLEFTRIGHT) ||

View File

@ -2,6 +2,7 @@
#include <map>
#include "DDraw/DirectDraw.h"
#include "DDraw/Repository.h"
#include "DDraw/Surfaces/SurfaceImpl.h"
#include "DDraw/Surfaces/TagSurface.h"
@ -16,7 +17,8 @@ namespace DDraw
{
std::find_if(g_tagSurfaces.begin(), g_tagSurfaces.end(),
[=](auto& i) { return i.second == this; })->second;
DDraw::onRelease(*this);
onRelease(*this);
Repository::onRelease(m_ddObject);
g_tagSurfaces.erase(std::find_if(g_tagSurfaces.begin(), g_tagSurfaces.end(),
[=](auto& i) { return i.second == this; }));
}