diff --git a/DDrawCompat/Config/Config.cpp b/DDrawCompat/Config/Config.cpp index 668c20b..984bc90 100644 --- a/DDrawCompat/Config/Config.cpp +++ b/DDrawCompat/Config/Config.cpp @@ -2,6 +2,7 @@ namespace Config { + Settings::AlignSysMemSurfaces alignSysMemSurfaces; Settings::AlternatePixelCenter alternatePixelCenter; Settings::AltTabFix altTabFix; Settings::Antialiasing antialiasing; diff --git a/DDrawCompat/Config/Config.h b/DDrawCompat/Config/Config.h index fce5de8..f985a08 100644 --- a/DDrawCompat/Config/Config.h +++ b/DDrawCompat/Config/Config.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -27,6 +28,7 @@ namespace Config { + extern Settings::AlignSysMemSurfaces alignSysMemSurfaces; extern Settings::AlternatePixelCenter alternatePixelCenter; extern Settings::AltTabFix altTabFix; extern Settings::Antialiasing antialiasing; diff --git a/DDrawCompat/Config/Settings/AlignSysMemSurfaces.h b/DDrawCompat/Config/Settings/AlignSysMemSurfaces.h new file mode 100644 index 0000000..7c06461 --- /dev/null +++ b/DDrawCompat/Config/Settings/AlignSysMemSurfaces.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace Config +{ + namespace Settings + { + class AlignSysMemSurfaces : public MappedSetting + { + public: + AlignSysMemSurfaces() + : MappedSetting("AlignSysMemSurfaces", "on", { {"off", 8}, {"on", 0} }) + { + } + }; + } +} diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 1381c98..9d1e62d 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -566,6 +566,7 @@ namespace D3dDdi return; } + const auto ALIGNMENT = DDraw::Surface::ALIGNMENT; std::vector surfaceInfo(m_fixedData.SurfCount); for (UINT i = 0; i < m_fixedData.SurfCount; ++i) { @@ -575,21 +576,16 @@ namespace D3dDdi if (i != 0) { std::uintptr_t offset = reinterpret_cast(surfaceInfo[i - 1].pSysMem) + - ((surfaceInfo[i - 1].SysMemPitch * surfaceInfo[i - 1].Height + 15) & ~15); + ((surfaceInfo[i - 1].SysMemPitch * surfaceInfo[i - 1].Height + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT); surfaceInfo[i].pSysMem = reinterpret_cast(offset); } } std::uintptr_t bufferSize = reinterpret_cast(surfaceInfo.back().pSysMem) + - surfaceInfo.back().SysMemPitch * surfaceInfo.back().Height + 8; + surfaceInfo.back().SysMemPitch * surfaceInfo.back().Height + ALIGNMENT; m_lockBuffer.reset(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufferSize)); - BYTE* bufferStart = static_cast(m_lockBuffer.get()); - if (0 == reinterpret_cast(bufferStart) % 16) - { - bufferStart += 8; - } - + BYTE* bufferStart = static_cast(DDraw::Surface::alignBuffer(m_lockBuffer.get())); for (UINT i = 0; i < m_fixedData.SurfCount; ++i) { surfaceInfo[i].pSysMem = bufferStart + reinterpret_cast(surfaceInfo[i].pSysMem); diff --git a/DDrawCompat/DDraw/DirectDrawSurface.cpp b/DDrawCompat/DDraw/DirectDrawSurface.cpp index 0710e26..ed286e8 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.cpp +++ b/DDrawCompat/DDraw/DirectDrawSurface.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -69,6 +71,11 @@ namespace SET_COMPAT_METHOD(SetClipper); SET_COMPAT_METHOD(SetPalette); SET_COMPAT_METHOD(Unlock); + + if constexpr (!std::is_same_v && !std::is_same_v) + { + SET_COMPAT_METHOD(SetSurfaceDesc); + } } } diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp index 7f12b44..59b5095 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.cpp +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -11,6 +12,14 @@ DEFINE_GUID(IID_CompatSurfacePrivateData, 0xc62d8849, 0xdfac, 0x4454, 0xa1, 0xe8, 0xda, 0x67, 0x44, 0x64, 0x26, 0xba); +namespace +{ + void heapFree(void* p) + { + HeapFree(GetProcessHeap(), 0, p); + } +} + namespace DDraw { HRESULT STDMETHODCALLTYPE Surface::QueryInterface(REFIID, LPVOID*) @@ -37,6 +46,7 @@ namespace DDraw : m_origCaps(origCaps) , m_refCount(0) , m_sizeOverride{} + , m_sysMemBuffer(nullptr, &heapFree) { } @@ -45,6 +55,19 @@ namespace DDraw DirectDrawClipper::setClipper(*this, nullptr); } + void* Surface::alignBuffer(void* buffer) + { + auto p = static_cast(buffer); + const DWORD alignmentOffset = Config::alignSysMemSurfaces.get(); + const DWORD mod = reinterpret_cast(p) % ALIGNMENT; + p = p - mod + alignmentOffset; + if (mod > alignmentOffset) + { + p += ALIGNMENT; + } + return p; + } + void Surface::attach(CompatRef dds, std::unique_ptr privateData) { if (SUCCEEDED(dds->SetPrivateData(&dds, IID_CompatSurfacePrivateData, @@ -82,6 +105,10 @@ namespace DDraw attach(*attachedSurfaces[i], std::make_unique(privateData->m_origCaps)); } } + else if ((desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && !(desc.dwFlags & DDSD_LPSURFACE)) + { + privateData->fixAlignment(*surface7); + } attach(*surface7, std::move(privateData)); @@ -106,6 +133,39 @@ namespace DDraw m_impl7.reset(new SurfaceImpl(this)); } + void Surface::fixAlignment(CompatRef surface) + { + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + if (FAILED(surface->Lock(&surface, nullptr, &desc, DDLOCK_WAIT, nullptr))) + { + return; + } + surface->Unlock(&surface, nullptr); + + const DWORD alignmentOffset = Config::alignSysMemSurfaces.get(); + const DWORD size = desc.lPitch * desc.dwHeight; + if (0 == size || alignmentOffset == reinterpret_cast(desc.lpSurface) % ALIGNMENT) + { + return; + } + + m_sysMemBuffer.reset(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + ALIGNMENT)); + if (!m_sysMemBuffer) + { + return; + } + + desc = {}; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_LPSURFACE; + desc.lpSurface = alignBuffer(m_sysMemBuffer.get()); + if (FAILED(surface->SetSurfaceDesc(&surface, &desc, 0))) + { + m_sysMemBuffer.reset(); + } + } + template <> SurfaceImpl* Surface::getImpl() const { return m_impl.get(); } template <> diff --git a/DDrawCompat/DDraw/Surfaces/Surface.h b/DDrawCompat/DDraw/Surfaces/Surface.h index 34f57ae..4a24526 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.h +++ b/DDrawCompat/DDraw/Surfaces/Surface.h @@ -16,6 +16,8 @@ namespace DDraw class Surface { public: + static const DWORD ALIGNMENT = 32; + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*); virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); @@ -23,6 +25,8 @@ namespace DDraw Surface(DWORD origCaps); virtual ~Surface(); + static void* alignBuffer(void* buffer); + template static HRESULT create( CompatRef dd, TSurfaceDesc desc, TSurface*& surface, std::unique_ptr privateData); @@ -44,6 +48,8 @@ namespace DDraw virtual void createImpl(); + void fixAlignment(CompatRef surface); + std::unique_ptr> m_impl; std::unique_ptr> m_impl2; std::unique_ptr> m_impl3; @@ -59,5 +65,6 @@ namespace DDraw DWORD m_origCaps; DWORD m_refCount; SIZE m_sizeOverride; + std::unique_ptr m_sysMemBuffer; }; } diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index b9b3280..dd5f8bf 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -255,6 +256,24 @@ namespace DDraw return getOrigVtable(This).SetPalette(This, lpDDPalette); } + template + HRESULT SurfaceImpl::SetSurfaceDesc(TSurface* This, TSurfaceDesc* lpddsd, DWORD dwFlags) + { + if constexpr (!std::is_same_v && !std::is_same_v) + { + HRESULT result = getOrigVtable(This).SetSurfaceDesc(This, lpddsd, dwFlags); + if (SUCCEEDED(result) && (lpddsd->dwFlags & DDSD_LPSURFACE)) + { + m_data->m_sysMemBuffer.reset(); + } + return result; + } + else + { + return DD_OK; + } + } + template HRESULT SurfaceImpl::Unlock(TSurface* This, TUnlockParam lpRect) { diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h index bf579b0..99ea70a 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h @@ -40,6 +40,7 @@ namespace DDraw virtual HRESULT Restore(TSurface* This); virtual HRESULT SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper); virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette); + virtual HRESULT SetSurfaceDesc(TSurface* This, TSurfaceDesc* lpddsd, DWORD dwFlags); virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect); protected: diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index d37c2af..b3e2854 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -158,6 +158,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index a987fa1..c3578b5 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -570,6 +570,9 @@ Header Files\Overlay + + Header Files\Config\Settings + diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 714b8e0..0916005 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -90,7 +90,7 @@ namespace } void* bits = nullptr; - return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, section, 8); + return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, section, Config::alignSysMemSurfaces.get()); } } @@ -206,7 +206,7 @@ namespace Gdi desc.ddpfPixelFormat = DDraw::DirectDraw::getRgbPixelFormat(g_bpp); desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; desc.lPitch = g_pitch; - desc.lpSurface = static_cast(g_surfaceView) + 8 + + desc.lpSurface = static_cast(g_surfaceView) + Config::alignSysMemSurfaces.get() + (rect.top - g_bounds.top) * g_pitch + (rect.left - g_bounds.left) * g_bpp / 8; return desc;