From e8f987eb05b57b601d23e8e08cf769f5068e568f Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 24 Sep 2016 23:02:48 +0200 Subject: [PATCH] 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. --- DDrawCompat/DDraw/DirectDrawSurface.cpp | 7 ++ DDrawCompat/DDraw/DirectDrawSurface.h | 3 + DDrawCompat/DDraw/Repository.cpp | 93 ++++++++++++++++------ DDrawCompat/DDraw/Repository.h | 5 +- DDrawCompat/DDraw/Surfaces/Surface.cpp | 13 ++- DDrawCompat/DDraw/Surfaces/Surface.h | 2 +- DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp | 17 ++-- DDrawCompat/DDraw/Surfaces/TagSurface.cpp | 4 +- 8 files changed, 98 insertions(+), 46 deletions(-) diff --git a/DDrawCompat/DDraw/DirectDrawSurface.cpp b/DDrawCompat/DDraw/DirectDrawSurface.cpp index 4e94a57..9e3a28b 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.cpp +++ b/DDrawCompat/DDraw/DirectDrawSurface.cpp @@ -26,6 +26,13 @@ namespace namespace DDraw { + CompatPtr getDirectDraw(CompatRef surface) + { + CompatPtr dd; + surface.get().lpVtbl->GetDDInterface(&surface, reinterpret_cast(&dd.getRef())); + return dd; + } + template void DirectDrawSurface::setCompatVtable(Vtable& vtable) { diff --git a/DDrawCompat/DDraw/DirectDrawSurface.h b/DDrawCompat/DDraw/DirectDrawSurface.h index 9b72a40..935cfd2 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.h +++ b/DDrawCompat/DDraw/DirectDrawSurface.h @@ -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 getDirectDraw(CompatRef surface); + template class DirectDrawSurface : public CompatVtable> { diff --git a/DDrawCompat/DDraw/Repository.cpp b/DDrawCompat/DDraw/Repository.cpp index bd5d5a9..74e177a 100644 --- a/DDrawCompat/DDraw/Repository.cpp +++ b/DDrawCompat/DDraw/Repository.cpp @@ -1,8 +1,10 @@ #include +#include #include #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 g_sysMemSurfaces; - static std::vector g_vidMemSurfaces; + struct Repository + { + CompatWeakPtr dd; + std::vector surfaces; + }; + + Repository g_sysMemRepo; + std::map g_vidMemRepos; CompatPtr createDirectDraw(); - Surface createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps); + Surface createSurface(CompatRef dd, + DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps); std::vector::iterator findSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, std::vector& cachedSurfaces); void destroySmallerSurfaces(DWORD width, DWORD height, const DDPIXELFORMAT& pf, std::vector& cachedSurfaces); - Surface getSurface(const DDSURFACEDESC2& desc); + Surface getSurface(CompatRef dd, const DDSURFACEDESC2& desc); void normalizePixelFormat(DDPIXELFORMAT& pf); void returnSurface(const Surface& surface); @@ -30,21 +39,22 @@ namespace reinterpret_cast(&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 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 dd, DWORD caps) { - std::vector& 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 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 dd, const DDSURFACEDESC2& desc) + : Surface(getSurface(dd, desc)) { } @@ -177,5 +211,18 @@ namespace DDraw static auto dd = new CompatPtr(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); + } + } } } diff --git a/DDrawCompat/DDraw/Repository.h b/DDrawCompat/DDraw/Repository.h index 2b5bccb..40198b0 100644 --- a/DDrawCompat/DDraw/Repository.h +++ b/DDrawCompat/DDraw/Repository.h @@ -4,6 +4,7 @@ #include +#include "Common/CompatRef.h" #include "Common/CompatWeakPtr.h" namespace DDraw @@ -12,6 +13,7 @@ namespace DDraw { struct Surface { + void* ddObject; DDSURFACEDESC2 desc; CompatWeakPtr surface; }; @@ -19,10 +21,11 @@ namespace DDraw class ScopedSurface : public Surface { public: - ScopedSurface(const DDSURFACEDESC2& desc); + ScopedSurface(CompatRef dd, const DDSURFACEDESC2& desc); ~ScopedSurface(); }; CompatWeakPtr getDirectDraw(); + void onRelease(void* ddObject); } } diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp index 357b24d..ee688f8 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.cpp +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -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 dd; - CompatVtable::s_origVtable.GetDDInterface( - &dds, reinterpret_cast(&dd.getRef())); + dds->GetDDInterface(&dds, reinterpret_cast(&dd.getRef())); privateData->createImpl(); privateData->m_impl->m_data = privateData.get(); @@ -187,10 +187,7 @@ namespace DDraw CompatPtr Surface::getDirectDraw() const { - auto dds(getDirectDrawSurface()); - CompatPtr dd; - m_impl7->GetDDInterface(dds, reinterpret_cast(&dd.getRef())); - return CompatPtr(dd); + return DDraw::getDirectDraw(*getDirectDrawSurface()); } CompatPtr Surface::getDirectDrawSurface() const diff --git a/DDrawCompat/DDraw/Surfaces/Surface.h b/DDrawCompat/DDraw/Surfaces/Surface.h index 8a201e6..f77ddd7 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.h +++ b/DDrawCompat/DDraw/Surfaces/Surface.h @@ -40,6 +40,7 @@ namespace DDraw static void attach(CompatRef dds, std::unique_ptr& privateData); + void* m_ddObject; std::unique_ptr> m_impl; std::unique_ptr> m_impl2; std::unique_ptr> m_impl3; @@ -56,7 +57,6 @@ namespace DDraw IDirectDrawSurface* m_dds; IID m_ddId; - void* m_ddObject; DWORD m_refCount; }; } diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index 0f1844a..977c058 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -1,6 +1,7 @@ #include #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(desc.dwWidth), static_cast(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) || diff --git a/DDrawCompat/DDraw/Surfaces/TagSurface.cpp b/DDrawCompat/DDraw/Surfaces/TagSurface.cpp index 743af80..77bf177 100644 --- a/DDrawCompat/DDraw/Surfaces/TagSurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/TagSurface.cpp @@ -2,6 +2,7 @@ #include #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; })); }