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

Replaced IDirectDrawSurface raw pointers with smart pointers

This commit is contained in:
narzoul 2016-05-16 18:16:13 +02:00
parent 70a29c2f12
commit 068cdb8028
13 changed files with 187 additions and 217 deletions

View File

@ -2,6 +2,7 @@
#include "CompatDirectDraw.h"
#include "CompatDirectDrawSurface.h"
#include "CompatPrimarySurface.h"
#include "CompatPtr.h"
#include "IReleaseNotifier.h"
namespace
@ -17,13 +18,13 @@ namespace
};
DirectDrawInterface* g_fullScreenDirectDraw = nullptr;
IDirectDrawSurface* g_fullScreenTagSurface = nullptr;
CompatWeakPtr<IDirectDrawSurface> g_fullScreenTagSurface;
void onReleaseFullScreenTagSurface();
IReleaseNotifier g_fullScreenTagSurfaceReleaseNotifier(&onReleaseFullScreenTagSurface);
IDirectDrawSurface* createFullScreenTagSurface(IDirectDraw& dd)
CompatPtr<IDirectDrawSurface> createFullScreenTagSurface(IDirectDraw& dd)
{
DDSURFACEDESC desc = {};
desc.dwSize = sizeof(desc);
@ -32,17 +33,14 @@ namespace
desc.dwHeight = 1;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
IDirectDrawSurface* tagSurface = nullptr;
CompatDirectDraw<IDirectDraw>::s_origVtable.CreateSurface(&dd, &desc, &tagSurface, nullptr);
CompatPtr<IDirectDrawSurface> tagSurface;
CompatDirectDraw<IDirectDraw>::s_origVtable.CreateSurface(&dd, &desc, &tagSurface.getRef(), nullptr);
if (tagSurface)
{
IDirectDrawSurface7* tagSurface7 = nullptr;
CompatDirectDrawSurface<IDirectDrawSurface>::s_origVtable.QueryInterface(
tagSurface, IID_IDirectDrawSurface7, reinterpret_cast<void**>(&tagSurface7));
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPrivateData(
CompatPtr<IDirectDrawSurface7> tagSurface7(tagSurface);
tagSurface7->SetPrivateData(
tagSurface7, IID_IReleaseNotifier, &g_fullScreenTagSurfaceReleaseNotifier,
sizeof(&g_fullScreenTagSurfaceReleaseNotifier), DDSPD_IUNKNOWNPOINTER);
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(tagSurface7);
}
return tagSurface;
@ -140,12 +138,8 @@ namespace
void setFullScreenDirectDraw(IDirectDraw& dd)
{
if (g_fullScreenTagSurface)
{
CompatDirectDrawSurface<IDirectDrawSurface>::s_origVtable.Release(g_fullScreenTagSurface);
g_fullScreenTagSurface = nullptr;
}
g_fullScreenTagSurface = createFullScreenTagSurface(dd);
g_fullScreenTagSurface.release();
g_fullScreenTagSurface = createFullScreenTagSurface(dd).detach();
/*
IDirectDraw interfaces don't conform to the COM rule about object identity:
@ -259,7 +253,7 @@ HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::SetCooperativeLevel(
}
else if (isFullScreenDirectDraw(This) && g_fullScreenTagSurface)
{
CompatDirectDrawSurface<IDirectDrawSurface>::s_origVtable.Release(g_fullScreenTagSurface);
g_fullScreenTagSurface.release();
}
}
return result;

View File

@ -5,6 +5,7 @@
#include "CompatDirectDrawSurface.h"
#include "CompatGdi.h"
#include "CompatPrimarySurface.h"
#include "CompatPtr.h"
#include "DDrawProcs.h"
#include "DDrawRepository.h"
#include "IReleaseNotifier.h"
@ -12,11 +13,12 @@
namespace
{
bool mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx);
bool mirrorBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
RECT srcRect, DWORD mirrorFx);
bool g_lockingPrimary = false;
void fixSurfacePtr(IDirectDrawSurface7& surface, const DDSURFACEDESC2& desc)
void fixSurfacePtr(CompatRef<IDirectDrawSurface7> surface, const DDSURFACEDESC2& desc)
{
if ((desc.dwFlags & DDSD_CAPS) && (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ||
0 == desc.dwWidth || 0 == desc.dwHeight)
@ -34,48 +36,44 @@ namespace
}
RECT r = { 0, 0, 1, 1 };
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Blt(
&surface, &r, tempSurface.surface, &r, DDBLT_WAIT, nullptr);
surface->Blt(&surface, &r, tempSurface.surface, &r, DDBLT_WAIT, nullptr);
}
HRESULT WINAPI enumSurfacesCallback(
HRESULT WINAPI fixSurfacePtrEnumCallback(
LPDIRECTDRAWSURFACE7 lpDDSurface,
LPDDSURFACEDESC2 lpDDSurfaceDesc,
LPVOID lpContext)
{
auto& visitedSurfaces = *static_cast<std::set<IDirectDrawSurface7*>*>(lpContext);
if (visitedSurfaces.find(lpDDSurface) == visitedSurfaces.end())
CompatPtr<IDirectDrawSurface7> surface(lpDDSurface);
if (visitedSurfaces.find(surface) == visitedSurfaces.end())
{
visitedSurfaces.insert(lpDDSurface);
fixSurfacePtr(*lpDDSurface, *lpDDSurfaceDesc);
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.EnumAttachedSurfaces(
lpDDSurface, lpContext, &enumSurfacesCallback);
visitedSurfaces.insert(surface);
fixSurfacePtr(*surface, *lpDDSurfaceDesc);
surface->EnumAttachedSurfaces(surface, lpContext, &fixSurfacePtrEnumCallback);
}
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(lpDDSurface);
return DDENUMRET_OK;
}
void fixSurfacePtrs(IDirectDrawSurface7& surface)
void fixSurfacePtrs(CompatRef<IDirectDrawSurface7> surface)
{
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.GetSurfaceDesc(&surface, &desc);
surface->GetSurfaceDesc(&surface, &desc);
fixSurfacePtr(surface, desc);
std::set<IDirectDrawSurface7*> visitedSurfaces{ &surface };
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.EnumAttachedSurfaces(
&surface, &visitedSurfaces, &enumSurfacesCallback);
surface->EnumAttachedSurfaces(&surface, &visitedSurfaces, &fixSurfacePtrEnumCallback);
}
IDirectDrawSurface7* getMirroredSurface(IDirectDrawSurface7& surface, RECT* srcRect, DWORD mirrorFx)
CompatWeakPtr<IDirectDrawSurface7> getMirroredSurface(
CompatRef<IDirectDrawSurface7> surface, RECT* srcRect, DWORD mirrorFx)
{
auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
HRESULT result = origVtable.GetSurfaceDesc(&surface, &desc);
HRESULT result = surface->GetSurfaceDesc(&surface, &desc);
if (FAILED(result))
{
LOG_ONCE("Failed to get surface description for mirroring: " << result);
@ -112,34 +110,11 @@ namespace
return nullptr;
}
origVtable.AddRef(mirroredSurface.surface);
return mirroredSurface.surface;
}
template <typename TSurface>
TSurface* getMirroredSurface(TSurface& surface, RECT* rect, DWORD mirrorFx)
{
auto& origVtable = CompatDirectDrawSurface<TSurface>::s_origVtable;
IDirectDrawSurface7* surface7 = nullptr;
origVtable.QueryInterface(&surface, IID_IDirectDrawSurface7, reinterpret_cast<void**>(&surface7));
IDirectDrawSurface7* mirroredSurface7 = getMirroredSurface(*surface7, rect, mirrorFx);
surface7->lpVtbl->Release(surface7);
if (!mirroredSurface7)
{
return nullptr;
}
auto& origVtable7 = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
TSurface* mirroredSurface = nullptr;
origVtable7.QueryInterface(mirroredSurface7,
CompatDirectDrawSurface<TSurface>::s_iid, reinterpret_cast<void**>(&mirroredSurface));
origVtable7.Release(mirroredSurface7);
return mirroredSurface;
}
bool mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx)
bool mirrorBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
RECT srcRect, DWORD mirrorFx)
{
if (DDBLTFX_MIRRORLEFTRIGHT == mirrorFx)
{
@ -147,8 +122,7 @@ namespace
srcRect.left = srcRect.right - 1;
for (LONG x = 0; x < width; ++x)
{
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.BltFast(
&dst, x, 0, &src, &srcRect, DDBLTFAST_WAIT);
HRESULT result = dst->BltFast(&dst, x, 0, &src, &srcRect, DDBLTFAST_WAIT);
if (FAILED(result))
{
LOG_ONCE("Failed BltFast for mirroring: " << result);
@ -164,8 +138,7 @@ namespace
srcRect.top = srcRect.bottom - 1;
for (LONG y = 0; y < height; ++y)
{
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.BltFast(
&dst, 0, y, &src, &srcRect, DDBLTFAST_WAIT);
HRESULT result = dst->BltFast(&dst, 0, y, &src, &srcRect, DDBLTFAST_WAIT);
if (FAILED(result))
{
LOG_ONCE("Failed BltFast for mirroring: " << result);
@ -243,12 +216,10 @@ HRESULT CompatDirectDrawSurface<TSurface>::createCompatPrimarySurface(
}
template <typename TSurface>
void CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(TSurface& surface)
void CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(CompatRef<TSurface> surface)
{
IDirectDrawSurface7* surface7 = nullptr;
surface.lpVtbl->QueryInterface(&surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&surface7));
CompatPtr<IDirectDrawSurface7> surface7(Compat::queryInterface<IDirectDrawSurface7>(&surface));
::fixSurfacePtrs(*surface7);
surface7->lpVtbl->Release(surface7);
}
template <typename TSurface>
@ -268,12 +239,15 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Blt(
}
HRESULT result = DD_OK;
TSurface* mirroredSrcSurface = nullptr;
CompatPtr<TSurface> mirroredSrcSurface;
if (lpDDSrcSurface && (dwFlags & DDBLT_DDFX) && lpDDBltFx &&
(lpDDBltFx->dwDDFX & (DDBLTFX_MIRRORLEFTRIGHT | DDBLTFX_MIRRORUPDOWN)))
{
mirroredSrcSurface = getMirroredSurface(*lpDDSrcSurface, lpSrcRect, lpDDBltFx->dwDDFX);
CompatPtr<IDirectDrawSurface7> srcSurface(
Compat::queryInterface<IDirectDrawSurface7>(lpDDSrcSurface));
mirroredSrcSurface.reset(Compat::queryInterface<TSurface>(
getMirroredSurface(*srcSurface, lpSrcRect, lpDDBltFx->dwDDFX).get()));
if (!mirroredSrcSurface)
{
LOG_ONCE("Failed to emulate a mirrored Blt");
@ -305,8 +279,6 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Blt(
{
result = s_origVtable.Blt(This, lpDestRect, mirroredSrcSurface, nullptr, flags, &fx);
}
s_origVtable.Release(mirroredSrcSurface);
}
else
{
@ -461,8 +433,8 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::QueryInterface(
{
if (riid == IID_IDirectDrawGammaControl && CompatPrimarySurface::isPrimary(This))
{
return RealPrimarySurface::getSurface()->lpVtbl->QueryInterface(
RealPrimarySurface::getSurface(), riid, obp);
auto realPrimary(RealPrimarySurface::getSurface());
return realPrimary->QueryInterface(realPrimary, riid, obp);
}
return s_origVtable.QueryInterface(This, riid, obp);
}

View File

@ -2,6 +2,7 @@
#include <type_traits>
#include "CompatRef.h"
#include "CompatVtable.h"
#include "DDrawTypes.h"
#include "DirectDrawSurfaceVtblVisitor.h"
@ -22,7 +23,7 @@ public:
TSurfaceDesc compatDesc,
TSurface*& compatSurface);
static void fixSurfacePtrs(TSurface& surface);
static void fixSurfacePtrs(CompatRef<TSurface> surface);
static HRESULT STDMETHODCALLTYPE Blt(
TSurface* This,

View File

@ -1,7 +1,6 @@
#include <atomic>
#include "CompatDirectDrawPalette.h"
#include "CompatDirectDrawSurface.h"
#include "CompatGdi.h"
#include "CompatGdiCaret.h"
#include "CompatGdiDcCache.h"

View File

@ -3,9 +3,9 @@
#include "CompatDirectDraw.h"
#include "CompatDirectDrawPalette.h"
#include "CompatDirectDrawSurface.h"
#include "CompatGdiDcCache.h"
#include "CompatPrimarySurface.h"
#include "CompatPtr.h"
#include "Config.h"
#include "DDrawLog.h"
#include "DDrawProcs.h"
@ -27,37 +27,36 @@ namespace
void* g_surfaceMemory = nullptr;
LONG g_pitch = 0;
IDirectDrawSurface7* createGdiSurface();
CompatPtr<IDirectDrawSurface7> createGdiSurface();
CachedDc createCachedDc()
{
CachedDc cachedDc = {};
IDirectDrawSurface7* surface = createGdiSurface();
CompatPtr<IDirectDrawSurface7> surface(createGdiSurface());
if (!surface)
{
return cachedDc;
}
HDC dc = nullptr;
HRESULT result = surface->lpVtbl->GetDC(surface, &dc);
HRESULT result = surface->GetDC(surface, &dc);
if (FAILED(result))
{
LOG_ONCE("Failed to create a GDI DC: " << result);
surface->lpVtbl->Release(surface);
return cachedDc;
}
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
Compat::origProcs.ReleaseDDThreadLock();
cachedDc.surface = surface;
cachedDc.surface = surface.detach();
cachedDc.dc = dc;
cachedDc.cacheId = g_cacheId;
return cachedDc;
}
IDirectDrawSurface7* createGdiSurface()
CompatPtr<IDirectDrawSurface7> createGdiSurface()
{
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
@ -69,9 +68,9 @@ namespace
desc.lPitch = g_pitch;
desc.lpSurface = g_surfaceMemory;
IDirectDrawSurface7* surface = nullptr;
CompatPtr<IDirectDrawSurface7> surface;
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
g_directDraw, &desc, &surface, nullptr);
g_directDraw, &desc, &surface.getRef(), nullptr);
if (FAILED(result))
{
LOG_ONCE("Failed to create a GDI surface: " << result);
@ -80,7 +79,7 @@ namespace
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
{
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(surface, g_palette);
surface->SetPalette(surface, g_palette);
}
return surface;
@ -115,14 +114,13 @@ namespace
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
Compat::origProcs.AcquireDDThreadLock();
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC(
cachedDc.surface, cachedDc.dc);
HRESULT result = cachedDc.surface->ReleaseDC(cachedDc.surface, cachedDc.dc);
if (FAILED(result))
{
LOG_ONCE("Failed to release a cached DC: " << result);
}
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(cachedDc.surface);
cachedDc.surface.release();
}
}

View File

@ -6,11 +6,13 @@
#include <ddraw.h>
#include <Windows.h>
#include "CompatWeakPtr.h"
namespace CompatGdiDcCache
{
struct CachedDc
{
IDirectDrawSurface7* surface;
CompatWeakPtr<IDirectDrawSurface7> surface;
HDC dc;
DWORD cacheId;
};

View File

@ -3,9 +3,9 @@
#include "CompatDirectDraw.h"
#include "CompatDirectDrawPalette.h"
#include "CompatDirectDrawSurface.h"
#include "CompatPaletteConverter.h"
#include "CompatPrimarySurface.h"
#include "CompatPtr.h"
#include "DDrawRepository.h"
#include "DDrawTypes.h"
#include "Hook.h"
@ -16,7 +16,7 @@ namespace
{
HDC g_dc = nullptr;
HGDIOBJ g_oldBitmap = nullptr;
IDirectDrawSurface7* g_surface = nullptr;
CompatWeakPtr<IDirectDrawSurface7> g_surface;
void convertPaletteEntriesToRgbQuad(RGBQUAD* entries, DWORD count)
{
@ -27,7 +27,7 @@ namespace
}
}
HBITMAP createDibSection(void*& bits)
HBITMAP createDibSection(const DDSURFACEDESC2& primaryDesc, void*& bits)
{
struct PalettizedBitmapInfo
{
@ -37,8 +37,8 @@ namespace
PalettizedBitmapInfo bmi = {};
bmi.header.biSize = sizeof(bmi.header);
bmi.header.biWidth = RealPrimarySurface::s_surfaceDesc.dwWidth;
bmi.header.biHeight = -static_cast<LONG>(RealPrimarySurface::s_surfaceDesc.dwHeight);
bmi.header.biWidth = primaryDesc.dwWidth;
bmi.header.biHeight = -static_cast<LONG>(primaryDesc.dwHeight);
bmi.header.biPlanes = 1;
bmi.header.biBitCount = 8;
bmi.header.biCompression = BI_RGB;
@ -48,7 +48,7 @@ namespace
DIB_RGB_COLORS, &bits, nullptr, 0);
}
IDirectDrawSurface7* createSurface(void* bits)
CompatPtr<IDirectDrawSurface7> createSurface(const DDSURFACEDESC2& primaryDesc, void* bits)
{
IDirectDraw7* dd = DDrawRepository::getDirectDraw();
if (!dd)
@ -60,38 +60,38 @@ namespace
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS |
DDSD_PITCH | DDSD_LPSURFACE;
desc.dwWidth = RealPrimarySurface::s_surfaceDesc.dwWidth;
desc.dwHeight = RealPrimarySurface::s_surfaceDesc.dwHeight;
desc.dwWidth = primaryDesc.dwWidth;
desc.dwHeight = primaryDesc.dwHeight;
desc.ddpfPixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
desc.lPitch = (RealPrimarySurface::s_surfaceDesc.dwWidth + 3) & ~3;
desc.lPitch = (primaryDesc.dwWidth + 3) & ~3;
desc.lpSurface = bits;
IDirectDrawSurface7* surface = nullptr;
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(dd, &desc, &surface, nullptr);
CompatPtr<IDirectDrawSurface7> surface;
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(dd, &desc, &surface.getRef(), nullptr);
return surface;
}
}
namespace CompatPaletteConverter
{
bool create()
bool create(const DDSURFACEDESC2& primaryDesc)
{
if (CompatPrimarySurface::displayMode.pixelFormat.dwRGBBitCount > 8 &&
RealPrimarySurface::s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount > 8)
primaryDesc.ddpfPixelFormat.dwRGBBitCount > 8)
{
return true;
}
void* bits = nullptr;
HBITMAP dib = createDibSection(bits);
HBITMAP dib = createDibSection(primaryDesc, bits);
if (!dib)
{
Compat::Log() << "Failed to create the palette converter DIB section";
return false;
}
IDirectDrawSurface7* surface = createSurface(bits);
CompatPtr<IDirectDrawSurface7> surface(createSurface(primaryDesc, bits));
if (!surface)
{
Compat::Log() << "Failed to create the palette converter surface";
@ -103,14 +103,13 @@ namespace CompatPaletteConverter
if (!dc)
{
Compat::Log() << "Failed to create the palette converter DC";
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(surface);
DeleteObject(dib);
return false;
}
g_oldBitmap = SelectObject(dc, dib);
g_dc = dc;
g_surface = surface;
g_surface = surface.detach();
return true;
}
@ -119,7 +118,7 @@ namespace CompatPaletteConverter
return g_dc;
}
IDirectDrawSurface7* getSurface()
CompatWeakPtr<IDirectDrawSurface7> getSurface()
{
return g_surface;
}
@ -131,8 +130,7 @@ namespace CompatPaletteConverter
return;
}
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(g_surface);
g_surface = nullptr;
g_surface.release();
DeleteObject(SelectObject(g_dc, g_oldBitmap));
DeleteDC(g_dc);
@ -143,8 +141,7 @@ namespace CompatPaletteConverter
{
if (g_surface)
{
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
g_surface, clipper);
HRESULT result = g_surface->SetClipper(g_surface, clipper);
if (FAILED(result))
{
LOG_ONCE("Failed to set a clipper on the palette converter surface: " << result);

View File

@ -4,11 +4,13 @@
#include <ddraw.h>
#include "CompatWeakPtr.h"
namespace CompatPaletteConverter
{
bool create();
bool create(const DDSURFACEDESC2& primaryDesc);
HDC getDc();
IDirectDrawSurface7* getSurface();
CompatWeakPtr<IDirectDrawSurface7> getSurface();
void release();
void setClipper(IDirectDrawClipper* clipper);
void updatePalette(DWORD startingEntry, DWORD count);

View File

@ -2,7 +2,7 @@
#include <vector>
#include "CompatDirectDraw.h"
#include "CompatDirectDrawSurface.h"
#include "CompatPtr.h"
#include "DDrawLog.h"
#include "DDrawProcs.h"
#include "DDrawRepository.h"
@ -63,7 +63,7 @@ namespace
surface.desc.ddsCaps.dwCaps = caps;
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
dd, &surface.desc, &surface.surface, nullptr);
dd, &surface.desc, &surface.surface.getRef(), nullptr);
return surface;
}
@ -76,7 +76,7 @@ namespace
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->surface.release();
it = cachedSurfaces.erase(it);
}
else
@ -89,17 +89,16 @@ namespace
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)))
if (FAILED(it->surface->IsLost(it->surface)) &&
FAILED(it->surface->Restore(it->surface)))
{
origVtable.Release(it->surface);
it->surface.release();
it = cachedSurfaces.erase(it);
continue;
}

View File

@ -4,12 +4,14 @@
#include <ddraw.h>
#include "CompatWeakPtr.h"
namespace DDrawRepository
{
struct Surface
{
DDSURFACEDESC2 desc;
IDirectDrawSurface7* surface;
CompatWeakPtr<IDirectDrawSurface7> surface;
};
class ScopedSurface : public Surface

View File

@ -11,6 +11,7 @@
#include "CompatDirectDrawPalette.h"
#include "CompatGdi.h"
#include "CompatRegistry.h"
#include "CompatPtr.h"
#include "CompatVtable.h"
#include "DDrawProcs.h"
#include "DDrawRepository.h"
@ -35,6 +36,12 @@ namespace
}
}
template <typename CompatInterface>
void hookVtable(const CompatPtr<typename CompatInterface::Interface>& intf)
{
CompatInterface::hookVtable(*intf);
}
void hookDirectDraw(IDirectDraw7& dd)
{
IUnknown& ddUnk = reinterpret_cast<IUnknown&>(dd);
@ -53,17 +60,17 @@ namespace
desc.dwHeight = 1;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
IDirectDrawSurface7* surface = nullptr;
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(&dd, &desc, &surface, nullptr);
CompatPtr<IDirectDrawSurface7> surface;
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
&dd, &desc, &surface.getRef(), nullptr);
if (SUCCEEDED(result))
{
IUnknown& surfaceUnk = reinterpret_cast<IUnknown&>(*surface);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface>>(IID_IDirectDrawSurface, surfaceUnk);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface2>>(IID_IDirectDrawSurface2, surfaceUnk);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface3>>(IID_IDirectDrawSurface3, surfaceUnk);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface4>>(IID_IDirectDrawSurface4, surfaceUnk);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface7>>(IID_IDirectDrawSurface7, surfaceUnk);
surface->lpVtbl->Release(surface);
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable = *surface.get()->lpVtbl;
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface>>(surface);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface2>>(surface);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface3>>(surface);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface4>>(surface);
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface7>>(surface);
}
else
{

View File

@ -6,6 +6,8 @@
#include "CompatGdi.h"
#include "CompatPaletteConverter.h"
#include "CompatPrimarySurface.h"
#include "CompatPtr.h"
#include "CompatRef.h"
#include "Config.h"
#include "DDrawScopedThreadLock.h"
#include "DDrawProcs.h"
@ -19,9 +21,11 @@ namespace
{
void onRelease();
void updateNow(long long qpcNow);
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
IDirectDrawSurface7* g_frontBuffer = nullptr;
IDirectDrawSurface7* g_backBuffer = nullptr;
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_backBuffer;
DDSURFACEDESC2 g_surfaceDesc = {};
IReleaseNotifier g_releaseNotifier(onRelease);
bool g_stopUpdateThread = false;
@ -34,7 +38,7 @@ namespace
std::atomic<bool> g_isFullScreen(false);
bool compatBlt(IDirectDrawSurface7* dest)
bool compatBlt(CompatRef<IDirectDrawSurface7> dest)
{
Compat::LogEnter("RealPrimarySurface::compatBlt", dest);
@ -44,12 +48,11 @@ namespace
}
bool result = false;
const auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
if (!RealPrimarySurface::isFullScreen())
{
IDirectDrawClipper* clipper = nullptr;
if (FAILED(origVtable.GetClipper(g_frontBuffer, &clipper)))
if (FAILED(g_frontBuffer->GetClipper(g_frontBuffer, &clipper)))
{
return false;
}
@ -59,27 +62,27 @@ namespace
auto primary(CompatPrimarySurface::getPrimary());
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
{
origVtable.Blt(CompatPaletteConverter::getSurface(), &g_updateRect,
auto paletteConverter(CompatPaletteConverter::getSurface());
paletteConverter->Blt(paletteConverter, &g_updateRect,
primary, &g_updateRect, DDBLT_WAIT, nullptr);
HDC destDc = nullptr;
origVtable.GetDC(dest, &destDc);
dest->GetDC(&dest, &destDc);
result = TRUE == CALL_ORIG_FUNC(BitBlt)(destDc, g_updateRect.left, g_updateRect.top,
g_updateRect.right - g_updateRect.left, g_updateRect.bottom - g_updateRect.top,
CompatPaletteConverter::getDc(), g_updateRect.left, g_updateRect.top, SRCCOPY);
origVtable.ReleaseDC(dest, destDc);
dest->ReleaseDC(&dest, destDc);
if (dest == g_frontBuffer)
if (&dest == g_frontBuffer)
{
// Force the screen to be updated. It won't refresh from BitBlt alone.
RECT r = { 0, 0, 1, 1 };
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.BltFast(
g_frontBuffer, 0, 0, g_frontBuffer, &r, DDBLTFAST_WAIT);
g_frontBuffer->BltFast(g_frontBuffer, 0, 0, g_frontBuffer, &r, DDBLTFAST_WAIT);
}
}
else
{
result = SUCCEEDED(origVtable.Blt(dest, &g_updateRect,
result = SUCCEEDED(dest->Blt(&dest, &g_updateRect,
primary, &g_updateRect, DDBLT_WAIT, nullptr));
}
@ -99,6 +102,53 @@ namespace
return qpcNextUpdate + g_qpcMinUpdateInterval * (missedIntervals + 1);
}
HRESULT init(CompatPtr<IDirectDrawSurface7> surface)
{
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
surface->GetSurfaceDesc(surface, &desc);
if (!CompatPaletteConverter::create(desc))
{
return DDERR_GENERIC;
}
CompatPtr<IDirectDrawSurface7> backBuffer;
const bool isFlippable = 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP);
if (isFlippable)
{
DDSCAPS2 backBufferCaps = {};
backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER;
surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef());
}
g_qpcMinUpdateInterval = Time::g_qpcFrequency / Config::maxPrimaryUpdateRate;
g_qpcNextUpdate = Time::queryPerformanceCounter();
if (!g_updateEvent)
{
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
}
if (!g_updateThread)
{
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
SetThreadPriority(g_updateThread, THREAD_PRIORITY_ABOVE_NORMAL);
}
surface->SetPrivateData(surface, IID_IReleaseNotifier,
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
timeBeginPeriod(1);
g_frontBuffer = surface.detach();
g_backBuffer = backBuffer.detach();
g_surfaceDesc = desc;
g_isFullScreen = isFlippable;
return DD_OK;
}
bool isNextUpdateSignaledAndReady(long long qpcNow)
{
return Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0 &&
@ -112,15 +162,11 @@ namespace
ResetEvent(g_updateEvent);
timeEndPeriod(1);
g_frontBuffer = nullptr;
if (g_backBuffer)
{
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(g_backBuffer);
g_backBuffer = nullptr;
}
g_backBuffer.release();
g_isFullScreen = false;
CompatPaletteConverter::release();
ZeroMemory(&RealPrimarySurface::s_surfaceDesc, sizeof(RealPrimarySurface::s_surfaceDesc));
ZeroMemory(&g_surfaceDesc, sizeof(g_surfaceDesc));
Compat::LogLeave("RealPrimarySurface::onRelease");
}
@ -129,7 +175,7 @@ namespace
{
ResetEvent(g_updateEvent);
if (compatBlt(g_frontBuffer))
if (compatBlt(*g_frontBuffer))
{
long long qpcNextUpdate = getNextUpdateQpc(qpcNow);
if (Time::qpcToMs(qpcNow - qpcNextUpdate) >= 0)
@ -170,8 +216,6 @@ namespace
}
}
DDSURFACEDESC2 RealPrimarySurface::s_surfaceDesc = {};
template <typename DirectDraw>
HRESULT RealPrimarySurface::create(DirectDraw& dd)
{
@ -181,9 +225,9 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
desc.dwBackBufferCount = 1;
typename Types<DirectDraw>::TCreatedSurface* surface = nullptr;
CompatPtr<typename Types<DirectDraw>::TCreatedSurface> surface;
HRESULT result = CompatDirectDraw<DirectDraw>::s_origVtable.CreateSurface(
&dd, &desc, &surface, nullptr);
&dd, &desc, &surface.getRef(), nullptr);
bool isFlippable = true;
if (DDERR_NOEXCLUSIVEMODE == result)
@ -193,7 +237,7 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
desc.dwBackBufferCount = 0;
isFlippable = false;
result = CompatDirectDraw<DirectDraw>::s_origVtable.CreateSurface(
&dd, &desc, &surface, nullptr);
&dd, &desc, &surface.getRef(), nullptr);
}
if (FAILED(result))
@ -202,48 +246,7 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
return result;
}
surface->lpVtbl->QueryInterface(
surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&g_frontBuffer));
surface->lpVtbl->Release(surface);
s_surfaceDesc.dwSize = sizeof(s_surfaceDesc);
g_frontBuffer->lpVtbl->GetSurfaceDesc(g_frontBuffer, &s_surfaceDesc);
if (!CompatPaletteConverter::create())
{
g_frontBuffer->lpVtbl->Release(g_frontBuffer);
g_frontBuffer = nullptr;
return DDERR_GENERIC;
}
if (isFlippable)
{
DDSCAPS2 backBufferCaps = {};
backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER;
g_frontBuffer->lpVtbl->GetAttachedSurface(g_frontBuffer, &backBufferCaps, &g_backBuffer);
}
g_qpcMinUpdateInterval = Time::g_qpcFrequency / Config::maxPrimaryUpdateRate;
g_qpcNextUpdate = Time::queryPerformanceCounter();
if (!g_updateEvent)
{
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
}
if (!g_updateThread)
{
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
SetThreadPriority(g_updateThread, THREAD_PRIORITY_ABOVE_NORMAL);
}
g_frontBuffer->lpVtbl->SetPrivateData(g_frontBuffer,
IID_IReleaseNotifier, &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
g_isFullScreen = isFlippable;
timeBeginPeriod(1);
return DD_OK;
return init(surface);
}
template HRESULT RealPrimarySurface::create(IDirectDraw&);
@ -267,7 +270,7 @@ void RealPrimarySurface::enableUpdates()
HRESULT RealPrimarySurface::flip(DWORD flags)
{
if (!g_backBuffer)
if (!g_isFullScreen)
{
return DDERR_NOTFLIPPABLE;
}
@ -275,13 +278,13 @@ HRESULT RealPrimarySurface::flip(DWORD flags)
ResetEvent(g_updateEvent);
invalidate(nullptr);
compatBlt(g_backBuffer);
compatBlt(*g_backBuffer);
if (flags & DDFLIP_DONOTWAIT)
{
flags ^= DDFLIP_DONOTWAIT;
}
HRESULT result = g_frontBuffer->lpVtbl->Flip(g_frontBuffer, nullptr, flags | DDFLIP_WAIT);
HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags | DDFLIP_WAIT);
if (SUCCEEDED(result))
{
g_qpcNextUpdate = getNextUpdateQpc(
@ -291,7 +294,7 @@ HRESULT RealPrimarySurface::flip(DWORD flags)
return result;
}
IDirectDrawSurface7* RealPrimarySurface::getSurface()
CompatWeakPtr<IDirectDrawSurface7> RealPrimarySurface::getSurface()
{
return g_frontBuffer;
}
@ -316,16 +319,12 @@ bool RealPrimarySurface::isFullScreen()
bool RealPrimarySurface::isLost()
{
return g_frontBuffer &&
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
return g_frontBuffer && DDERR_SURFACELOST == g_frontBuffer->IsLost(g_frontBuffer);
}
void RealPrimarySurface::release()
{
if (g_frontBuffer)
{
g_frontBuffer->lpVtbl->Release(g_frontBuffer);
}
g_frontBuffer.release();
}
void RealPrimarySurface::removeUpdateThread()
@ -349,15 +348,14 @@ void RealPrimarySurface::removeUpdateThread()
HRESULT RealPrimarySurface::restore()
{
return g_frontBuffer->lpVtbl->Restore(g_frontBuffer);
return g_frontBuffer->Restore(g_frontBuffer);
}
void RealPrimarySurface::setClipper(LPDIRECTDRAWCLIPPER clipper)
{
CompatPaletteConverter::setClipper(clipper);
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
g_frontBuffer, clipper);
HRESULT result = g_frontBuffer->SetClipper(g_frontBuffer, clipper);
if (FAILED(result))
{
LOG_ONCE("Failed to set clipper on the real primary surface: " << result);
@ -366,10 +364,9 @@ void RealPrimarySurface::setClipper(LPDIRECTDRAWCLIPPER clipper)
void RealPrimarySurface::setPalette()
{
if (s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8)
if (g_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8)
{
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
g_frontBuffer, CompatPrimarySurface::palette);
g_frontBuffer->SetPalette(g_frontBuffer, CompatPrimarySurface::palette);
}
updatePalette(0, 256);

View File

@ -4,6 +4,8 @@
#include <ddraw.h>
#include "CompatWeakPtr.h"
class RealPrimarySurface
{
public:
@ -13,7 +15,7 @@ public:
static void disableUpdates();
static void enableUpdates();
static HRESULT flip(DWORD flags);
static IDirectDrawSurface7* getSurface();
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
static void invalidate(const RECT* rect);
static bool isFullScreen();
static bool isLost();
@ -24,6 +26,4 @@ public:
static void setPalette();
static void update();
static void updatePalette(DWORD startingEntry, DWORD count);
static DDSURFACEDESC2 s_surfaceDesc;
};