From 6a2255160f78f79bac93bccc01bbc127096340fb Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 15 Jul 2017 12:41:21 +0200 Subject: [PATCH] Add extra rows to system memory primary surface buffers Fixes a memory corruption issue in Diablo 1, reported in issue #3. --- DDrawCompat/Config/Config.h | 1 + DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp | 33 +++++++++++++++++++ DDrawCompat/DDraw/Surfaces/PrimarySurface.h | 7 ++++ 3 files changed, 41 insertions(+) diff --git a/DDrawCompat/Config/Config.h b/DDrawCompat/Config/Config.h index 6df3d79..6b1bb08 100644 --- a/DDrawCompat/Config/Config.h +++ b/DDrawCompat/Config/Config.h @@ -7,4 +7,5 @@ namespace Config const int maxPaletteUpdatesPerMs = 5; const int minExpectedFlipsPerSec = 5; const DWORD preallocatedGdiDcCount = 4; + const DWORD primarySurfaceExtraRows = 2; } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index 1ad1db6..e438c29 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -1,4 +1,5 @@ #include "Common/CompatPtr.h" +#include "Config/Config.h" #include "DDraw/DirectDraw.h" #include "DDraw/RealPrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h" @@ -25,6 +26,7 @@ namespace DDraw g_gdiSurface = nullptr; g_primarySurface = nullptr; s_palette = nullptr; + s_surfaceBuffers.clear(); ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries)); ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc)); @@ -70,6 +72,11 @@ namespace DDraw g_primarySurfaceDesc.dwSize = sizeof(g_primarySurfaceDesc); CompatVtable::s_origVtable.GetSurfaceDesc(surface7, &g_primarySurfaceDesc); + if (g_primarySurfaceDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) + { + resizeBuffers(*surface7); + } + return DD_OK; } @@ -120,6 +127,31 @@ namespace DDraw Compat::queryInterface(g_primarySurface.get())); } + void PrimarySurface::resizeBuffers(CompatRef surface) + { + DDSCAPS2 flipCaps = {}; + flipCaps.dwCaps = DDSCAPS_FLIP; + + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_LPSURFACE; + + const DWORD newBufferSize = g_primarySurfaceDesc.lPitch * + (g_primarySurfaceDesc.dwHeight + Config::primarySurfaceExtraRows); + + auto surfacePtr(CompatPtr::from(&surface)); + do + { + s_surfaceBuffers.push_back(std::vector(newBufferSize)); + desc.lpSurface = s_surfaceBuffers.back().data(); + surfacePtr->SetSurfaceDesc(surfacePtr, &desc, 0); + + CompatPtr nextSurface; + surfacePtr->GetAttachedSurface(surfacePtr, &flipCaps, &nextSurface.getRef()); + surfacePtr.swap(nextSurface); + } while (surfacePtr && surfacePtr != &surface); + } + void PrimarySurface::updateGdiSurfacePtr(IDirectDrawSurface* flipTargetOverride) { auto primary(CompatPtr::from(m_surface->getDirectDrawSurface().get())); @@ -153,4 +185,5 @@ namespace DDraw CompatWeakPtr PrimarySurface::s_palette; PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {}; + std::vector> PrimarySurface::s_surfaceBuffers; } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h index b64775b..9ae577f 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h @@ -1,6 +1,9 @@ #pragma once +#include + #include "Common/CompatPtr.h" +#include "Common/CompatRef.h" #include "DDraw/Surfaces/Surface.h" namespace DDraw @@ -28,6 +31,10 @@ namespace DDraw virtual void createImpl() override; + static void resizeBuffers(CompatRef surface); + std::unique_ptr m_surface; + + static std::vector> s_surfaceBuffers; }; }