1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00
DDrawCompat/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp
narzoul bbb850faf1 Create 8-bit render target primary surface in system memory
Fixes issue with entering space battles in Star Wars Rebellion
full-screen mode (issue #22).
2020-04-13 13:22:54 +02:00

243 lines
6.7 KiB
C++

#include "Common/CompatPtr.h"
#include "Common/CompatRef.h"
#include "Config/Config.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/KernelModeThunks.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/DirectDrawSurface.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurfaceImpl.h"
#include "Gdi/Palette.h"
#include "Gdi/VirtualScreen.h"
namespace
{
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
HANDLE g_gdiResourceHandle = nullptr;
HANDLE g_frontResource = nullptr;
DWORD g_origCaps = 0;
}
namespace DDraw
{
PrimarySurface::~PrimarySurface()
{
LOG_FUNC("PrimarySurface::~PrimarySurface");
g_gdiResourceHandle = nullptr;
g_frontResource = nullptr;
g_primarySurface = nullptr;
g_origCaps = 0;
s_palette = nullptr;
DDraw::RealPrimarySurface::release();
}
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
HRESULT PrimarySurface::create(CompatRef<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface)
{
HRESULT result = RealPrimarySurface::create(dd);
if (FAILED(result))
{
return result;
}
const DWORD origCaps = desc.ddsCaps.dwCaps;
const auto& dm = DDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd));
desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
desc.dwWidth = dm.dwWidth;
desc.dwHeight = dm.dwHeight;
desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN;
desc.ddpfPixelFormat = dm.ddpfPixelFormat;
if (desc.ddpfPixelFormat.dwRGBBitCount <= 8 && (desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
{
desc.ddsCaps.dwCaps &= ~DDSCAPS_3DDEVICE;
desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
}
auto privateData(std::make_unique<PrimarySurface>());
auto data = privateData.get();
result = Surface::create(dd, desc, surface, std::move(privateData));
if (FAILED(result))
{
Compat::Log() << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result);
RealPrimarySurface::release();
return result;
}
g_origCaps = origCaps;
data->restore();
return DD_OK;
}
template HRESULT PrimarySurface::create(
CompatRef<IDirectDraw> dd, DDSURFACEDESC desc, IDirectDrawSurface*& surface);
template HRESULT PrimarySurface::create(
CompatRef<IDirectDraw2> dd, DDSURFACEDESC desc, IDirectDrawSurface*& surface);
template HRESULT PrimarySurface::create(
CompatRef<IDirectDraw4> dd, DDSURFACEDESC2 desc, IDirectDrawSurface4*& surface);
template HRESULT PrimarySurface::create(
CompatRef<IDirectDraw7> dd, DDSURFACEDESC2 desc, IDirectDrawSurface7*& surface);
void PrimarySurface::createImpl()
{
m_impl.reset(new PrimarySurfaceImpl<IDirectDrawSurface>(this));
m_impl2.reset(new PrimarySurfaceImpl<IDirectDrawSurface2>(this));
m_impl3.reset(new PrimarySurfaceImpl<IDirectDrawSurface3>(this));
m_impl4.reset(new PrimarySurfaceImpl<IDirectDrawSurface4>(this));
m_impl7.reset(new PrimarySurfaceImpl<IDirectDrawSurface7>(this));
}
HRESULT PrimarySurface::flipToGdiSurface()
{
CompatPtr<IDirectDrawSurface7> gdiSurface;
if (!g_primarySurface || !(gdiSurface = getGdiSurface()))
{
return DDERR_NOTFOUND;
}
return g_primarySurface.get()->lpVtbl->Flip(g_primarySurface, gdiSurface, DDFLIP_WAIT);
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getGdiSurface()
{
if (!g_primarySurface)
{
return nullptr;
}
DDSCAPS2 caps = {};
caps.dwCaps = DDSCAPS_FLIP;
CompatWeakPtr<IDirectDrawSurface7> surface(g_primarySurface);
do
{
if (isGdiSurface(surface.get()))
{
return CompatPtr<IDirectDrawSurface7>::from(surface.get());
}
if (FAILED(surface->GetAttachedSurface(surface, &caps, &surface.getRef())))
{
return nullptr;
}
surface->Release(surface);
} while (surface != g_primarySurface);
return nullptr;
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getBackBuffer()
{
DDSCAPS2 caps = {};
caps.dwCaps = DDSCAPS_BACKBUFFER;
CompatPtr<IDirectDrawSurface7> backBuffer;
g_primarySurface->GetAttachedSurface(g_primarySurface, &caps, &backBuffer.getRef());
return backBuffer;
}
CompatPtr<IDirectDrawSurface7> PrimarySurface::getLastSurface()
{
DDSCAPS2 caps = {};
caps.dwCaps = DDSCAPS_FLIP;
auto surface(CompatPtr<IDirectDrawSurface7>::from(g_primarySurface.get()));
CompatPtr<IDirectDrawSurface7> nextSurface;
while (SUCCEEDED(surface->GetAttachedSurface(surface, &caps, &nextSurface.getRef())) &&
nextSurface != g_primarySurface)
{
surface = nextSurface;
}
return surface;
}
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
{
return g_primarySurface;
}
HANDLE PrimarySurface::getFrontResource()
{
return g_frontResource;
}
DWORD PrimarySurface::getOrigCaps()
{
return g_origCaps;
}
template <typename TSurface>
static bool PrimarySurface::isGdiSurface(TSurface* surface)
{
return surface && getRuntimeResourceHandle(*surface) == g_gdiResourceHandle;
}
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface*);
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface2*);
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface3*);
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface4*);
template bool PrimarySurface::isGdiSurface(IDirectDrawSurface7*);
void PrimarySurface::restore()
{
LOG_FUNC("PrimarySurface::restore");
Gdi::VirtualScreen::update();
g_primarySurface = m_surface;
g_gdiResourceHandle = getRuntimeResourceHandle(*g_primarySurface);
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
m_surface->GetSurfaceDesc(m_surface, &desc);
if (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
{
DDSURFACEDESC2 gdiDesc = Gdi::VirtualScreen::getSurfaceDesc(D3dDdi::KernelModeThunks::getMonitorRect());
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE;
desc.lPitch = gdiDesc.lPitch;
desc.lpSurface = gdiDesc.lpSurface;
m_surface->SetSurfaceDesc(m_surface, &desc, 0);
}
updateFrontResource();
D3dDdi::Device::setGdiResourceHandle(g_frontResource);
Surface::restore();
}
void PrimarySurface::updateFrontResource()
{
g_frontResource = getDriverResourceHandle(*g_primarySurface);
}
void PrimarySurface::updatePalette()
{
PALETTEENTRY entries[256] = {};
if (s_palette)
{
PrimarySurface::s_palette->GetEntries(s_palette, 0, 0, 256, entries);
}
if (RealPrimarySurface::isFullScreen())
{
if (!s_palette)
{
auto sysPalEntries(Gdi::Palette::getSystemPalette());
std::memcpy(entries, sysPalEntries.data(), sizeof(entries));
}
Gdi::Palette::setHardwarePalette(entries);
}
else if (s_palette)
{
Gdi::Palette::setSystemPalette(entries, 256, false);
}
RealPrimarySurface::update();
}
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;
}