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

Create palettized surfaces in system memory

This commit is contained in:
narzoul 2016-12-19 19:25:15 +01:00
parent e6bb6b1e35
commit 26995d6108
7 changed files with 71 additions and 220 deletions

View File

@ -1,164 +0,0 @@
#include <algorithm>
#include <cstring>
#include "Common/CompatPtr.h"
#include "Common/Hook.h"
#include "Common/ScopedCriticalSection.h"
#include "DDraw/DisplayMode.h"
#include "DDraw/PaletteConverter.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Repository.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Types.h"
namespace
{
HDC g_dc = nullptr;
HGDIOBJ g_oldBitmap = nullptr;
CompatWeakPtr<IDirectDrawSurface7> g_surface;
void convertPaletteEntriesToRgbQuad(RGBQUAD* entries, DWORD count)
{
for (DWORD i = 0; i < count; ++i)
{
entries[i].rgbReserved = 0;
std::swap(entries[i].rgbRed, entries[i].rgbBlue);
}
}
HBITMAP createDibSection(const DDSURFACEDESC2& dm, void*& bits)
{
struct PalettizedBitmapInfo
{
BITMAPINFOHEADER header;
PALETTEENTRY colors[256];
};
PalettizedBitmapInfo bmi = {};
bmi.header.biSize = sizeof(bmi.header);
bmi.header.biWidth = dm.dwWidth;
bmi.header.biHeight = -static_cast<LONG>(dm.dwHeight);
bmi.header.biPlanes = 1;
bmi.header.biBitCount = static_cast<WORD>(dm.ddpfPixelFormat.dwRGBBitCount);
bmi.header.biCompression = BI_RGB;
return CreateDIBSection(nullptr, reinterpret_cast<BITMAPINFO*>(&bmi),
DIB_RGB_COLORS, &bits, nullptr, 0);
}
CompatPtr<IDirectDrawSurface7> createSurface(const DDSURFACEDESC2& dm, void* bits)
{
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS |
DDSD_PITCH | DDSD_LPSURFACE;
desc.dwWidth = dm.dwWidth;
desc.dwHeight = dm.dwHeight;
desc.ddpfPixelFormat = dm.ddpfPixelFormat;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
desc.lPitch = (dm.dwWidth * dm.ddpfPixelFormat.dwRGBBitCount / 8 + 3) & ~3;
desc.lpSurface = bits;
auto dd(DDraw::Repository::getDirectDraw());
CompatPtr<IDirectDrawSurface7> surface;
dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
return surface;
}
}
namespace DDraw
{
namespace PaletteConverter
{
bool create()
{
auto dd(Repository::getDirectDraw());
auto dm(DisplayMode::getDisplayMode(*dd));
DDSURFACEDESC2 realDm = {};
realDm.dwSize = sizeof(realDm);
dd->GetDisplayMode(dd, &realDm);
if (dm.ddpfPixelFormat.dwRGBBitCount > 8 &&
realDm.ddpfPixelFormat.dwRGBBitCount > 8)
{
return true;
}
void* bits = nullptr;
HBITMAP dib = createDibSection(dm, bits);
if (!dib)
{
Compat::Log() << "Failed to create the palette converter DIB section";
return false;
}
CompatPtr<IDirectDrawSurface7> surface(createSurface(dm, bits));
if (!surface)
{
Compat::Log() << "Failed to create the palette converter surface";
DeleteObject(dib);
return false;
}
HDC dc = CALL_ORIG_FUNC(CreateCompatibleDC)(nullptr);
if (!dc)
{
Compat::Log() << "Failed to create the palette converter DC";
DeleteObject(dib);
return false;
}
g_oldBitmap = SelectObject(dc, dib);
g_dc = dc;
g_surface = surface.detach();
return true;
}
HDC getDc()
{
return g_dc;
}
CompatWeakPtr<IDirectDrawSurface7> getSurface()
{
return g_surface;
}
void release()
{
if (!g_surface)
{
return;
}
g_surface.release();
DeleteObject(SelectObject(g_dc, g_oldBitmap));
DeleteDC(g_dc);
g_dc = nullptr;
}
void setClipper(CompatWeakPtr<IDirectDrawClipper> clipper)
{
if (g_surface)
{
HRESULT result = g_surface->SetClipper(g_surface, clipper);
if (FAILED(result))
{
LOG_ONCE("Failed to set a clipper on the palette converter surface: " << result);
}
}
}
void updatePalette(DWORD startingEntry, DWORD count)
{
if (g_dc && PrimarySurface::s_palette)
{
RGBQUAD entries[256] = {};
std::memcpy(entries, &PrimarySurface::s_paletteEntries[startingEntry],
count * sizeof(PALETTEENTRY));
convertPaletteEntriesToRgbQuad(entries, count);
SetDIBColorTable(g_dc, startingEntry, count, entries);
}
}
};
}

View File

@ -1,20 +0,0 @@
#pragma once
#define CINTERFACE
#include <ddraw.h>
#include "Common/CompatWeakPtr.h"
namespace DDraw
{
namespace PaletteConverter
{
bool create();
HDC getDc();
CompatWeakPtr<IDirectDrawSurface7> getSurface();
void release();
void setClipper(CompatWeakPtr<IDirectDrawClipper> clipper);
void updatePalette(DWORD startingEntry, DWORD count);
}
}

View File

@ -5,8 +5,8 @@
#include "Common/Time.h"
#include "Config/Config.h"
#include "DDraw/DirectDrawSurface.h"
#include "DDraw/DisplayMode.h"
#include "DDraw/IReleaseNotifier.h"
#include "DDraw/PaletteConverter.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/ScopedThreadLock.h"
#include "DDraw/Surfaces/PrimarySurface.h"
@ -21,6 +21,7 @@ namespace
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_backBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter;
CompatWeakPtr<IDirectDrawClipper> g_clipper;
DDSURFACEDESC2 g_surfaceDesc = {};
DDraw::IReleaseNotifier g_releaseNotifier(onRelease);
@ -49,22 +50,26 @@ namespace
auto primary(DDraw::PrimarySurface::getPrimary());
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
{
auto paletteConverter(DDraw::PaletteConverter::getSurface());
paletteConverter->Blt(paletteConverter, &g_updateRect,
primary, &g_updateRect, DDBLT_WAIT, nullptr);
HDC paletteConverterDc = nullptr;
g_paletteConverter->GetDC(g_paletteConverter, &paletteConverterDc);
HDC primaryDc = nullptr;
primary->GetDC(primary, &primaryDc);
HDC destDc = nullptr;
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,
DDraw::PaletteConverter::getDc(), g_updateRect.left, g_updateRect.top, SRCCOPY);
dest->ReleaseDC(&dest, destDc);
if (&dest == g_frontBuffer)
if (paletteConverterDc && primaryDc)
{
// Force the screen to be updated. It won't refresh from BitBlt alone.
RECT r = { 0, 0, 1, 1 };
g_frontBuffer->BltFast(g_frontBuffer, 0, 0, g_frontBuffer, &r, DDBLTFAST_WAIT);
result = TRUE == CALL_ORIG_FUNC(BitBlt)(paletteConverterDc,
g_updateRect.left, g_updateRect.top,
g_updateRect.right - g_updateRect.left, g_updateRect.bottom - g_updateRect.top,
primaryDc, g_updateRect.left, g_updateRect.top, SRCCOPY);
}
primary->ReleaseDC(primary, primaryDc);
g_paletteConverter->ReleaseDC(g_paletteConverter, paletteConverterDc);
if (result)
{
result = SUCCEEDED(dest->Blt(&dest, &g_updateRect,
g_paletteConverter, &g_updateRect, DDBLT_WAIT, nullptr));
}
}
else
@ -78,7 +83,40 @@ namespace
SetRectEmpty(&g_updateRect);
}
Compat::LogLeave("RealPrimarySurface::compatBlt", dest);
Compat::LogLeave("RealPrimarySurface::compatBlt", dest) << result;
return result;
}
template <typename TDirectDraw>
HRESULT createPaletteConverter(CompatRef<TDirectDraw> dd)
{
auto dd7(CompatPtr<IDirectDraw7>::from(&dd));
auto dm = DDraw::DisplayMode::getDisplayMode(*dd7);
if (dm.ddpfPixelFormat.dwRGBBitCount > 8)
{
return DD_OK;
}
typename DDraw::Types<TDirectDraw>::TSurfaceDesc desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
desc.dwWidth = dm.dwWidth;
desc.dwHeight = dm.dwHeight;
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
desc.ddpfPixelFormat.dwRGBBitCount = 32;
desc.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
desc.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
desc.ddpfPixelFormat.dwBBitMask = 0x000000FF;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
CompatPtr<DDraw::Types<TDirectDraw>::TCreatedSurface> paletteConverter;
HRESULT result = dd->CreateSurface(&dd, &desc, &paletteConverter.getRef(), nullptr);
if (SUCCEEDED(result))
{
g_paletteConverter = Compat::queryInterface<IDirectDrawSurface7>(paletteConverter.get());
}
return result;
}
@ -91,11 +129,6 @@ namespace
HRESULT init(CompatPtr<IDirectDrawSurface7> surface)
{
if (!DDraw::PaletteConverter::create())
{
return DDERR_GENERIC;
}
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
surface->GetSurfaceDesc(surface, &desc);
@ -152,7 +185,7 @@ namespace
g_backBuffer = nullptr;
g_clipper = nullptr;
g_isFullScreen = false;
DDraw::PaletteConverter::release();
g_paletteConverter.release();
ZeroMemory(&g_surfaceDesc, sizeof(g_surfaceDesc));
@ -209,6 +242,13 @@ namespace DDraw
template <typename DirectDraw>
HRESULT RealPrimarySurface::create(CompatRef<DirectDraw> dd)
{
HRESULT result = createPaletteConverter(dd);
if (FAILED(result))
{
Compat::Log() << "Failed to create the palette converter surface: " << Compat::hex(result);
return result;
}
typename Types<DirectDraw>::TSurfaceDesc desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
@ -216,7 +256,7 @@ namespace DDraw
desc.dwBackBufferCount = 1;
CompatPtr<typename Types<DirectDraw>::TCreatedSurface> surface;
HRESULT result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr);
result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr);
bool isFlippable = true;
if (DDERR_NOEXCLUSIVEMODE == result)
@ -230,7 +270,8 @@ namespace DDraw
if (FAILED(result))
{
Compat::Log() << "Failed to create the real primary surface";
Compat::Log() << "Failed to create the real primary surface: " << Compat::hex(result);
g_paletteConverter.release();
return result;
}
@ -343,7 +384,6 @@ namespace DDraw
LOG_ONCE("Failed to set clipper on the real primary surface: " << result);
return;
}
PaletteConverter::setClipper(clipper);
g_clipper = clipper;
}
@ -375,7 +415,6 @@ namespace DDraw
void RealPrimarySurface::updatePalette(DWORD startingEntry, DWORD count)
{
PaletteConverter::updatePalette(startingEntry, count);
Gdi::updatePalette(startingEntry, count);
if (PrimarySurface::s_palette)
{

View File

@ -26,10 +26,15 @@ namespace
pf = dm.ddpfPixelFormat;
}
if ((pf.dwFlags & DDPF_RGB) && pf.dwRGBBitCount <= 8)
{
caps &= ~(DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
caps |= DDSCAPS_SYSTEMMEMORY;
}
if (!(caps & (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_OVERLAY | DDSCAPS_TEXTURE |
DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER)))
{
flags |= DDSD_CAPS;
caps |= DDSCAPS_OFFSCREENPLAIN;
}
}

View File

@ -184,7 +184,6 @@
<ClInclude Include="DDraw\DirectDrawPalette.h" />
<ClInclude Include="DDraw\DirectDrawSurface.h" />
<ClInclude Include="DDraw\DisplayMode.h" />
<ClInclude Include="DDraw\PaletteConverter.h" />
<ClInclude Include="DDraw\Hooks.h" />
<ClInclude Include="DDraw\Repository.h" />
<ClInclude Include="DDraw\ScopedThreadLock.h" />
@ -247,7 +246,6 @@
<ClCompile Include="DDraw\DirectDrawPalette.cpp" />
<ClCompile Include="DDraw\DirectDrawSurface.cpp" />
<ClCompile Include="DDraw\DisplayMode.cpp" />
<ClCompile Include="DDraw\PaletteConverter.cpp" />
<ClCompile Include="DDraw\Hooks.cpp" />
<ClCompile Include="DDraw\Repository.cpp" />
<ClCompile Include="DDraw\IReleaseNotifier.cpp" />

View File

@ -123,9 +123,6 @@
<ClInclude Include="DDraw\DisplayMode.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
<ClInclude Include="DDraw\PaletteConverter.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
<ClInclude Include="DDraw\Hooks.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
@ -344,9 +341,6 @@
<ClCompile Include="DDraw\DisplayMode.cpp">
<Filter>Source Files\DDraw</Filter>
</ClCompile>
<ClCompile Include="DDraw\PaletteConverter.cpp">
<Filter>Source Files\DDraw</Filter>
</ClCompile>
<ClCompile Include="DDraw\Hooks.cpp">
<Filter>Source Files\DDraw</Filter>
</ClCompile>

View File

@ -1,7 +1,6 @@
#include <atomic>
#include "Common/ScopedCriticalSection.h"
#include "DDraw/PaletteConverter.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "Dll/Procs.h"