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

Restore primary surface globals if create fails

Fixes error creating "second" primary in Prince of Persia 3D when
starting a new game.  First primary is not completely released because
IDirectDrawGammaControl is not released. Native ddraw still allows
creation of a second fullscreen primary in this case.

This fix replaces the previous fix for Conquest: Frontier Wars also.
This commit is contained in:
narzoul 2022-08-11 23:33:11 +02:00
parent d4f5020e6f
commit ebba0ec6a4
2 changed files with 20 additions and 20 deletions

View File

@ -170,9 +170,9 @@ namespace
CALL_ORIG_PROC(DirectDrawEnumerateExA)(createDefaultPrimaryEnum, &dm.deviceName, DDENUM_ATTACHEDSECONDARYDEVICES); CALL_ORIG_PROC(DirectDrawEnumerateExA)(createDefaultPrimaryEnum, &dm.deviceName, DDENUM_ATTACHEDSECONDARYDEVICES);
} }
CompatPtr<IDirectDrawSurface7> createWindowedBackBuffer(DWORD width, DWORD height) CompatPtr<IDirectDrawSurface7> createWindowedBackBuffer(DDraw::TagSurface& tagSurface, DWORD width, DWORD height)
{ {
auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*g_tagSurface->getDDS()); auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*tagSurface.getDDS());
if (!resource) if (!resource)
{ {
LOG_INFO << "ERROR: createWindowedBackBuffer: driver resource handle not found"; LOG_INFO << "ERROR: createWindowedBackBuffer: driver resource handle not found";
@ -428,6 +428,7 @@ namespace DDraw
{ {
LOG_FUNC("RealPrimarySurface::create", &dd); LOG_FUNC("RealPrimarySurface::create", &dd);
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;
auto prevMonitorRect = g_monitorRect;
g_monitorRect = Win32::DisplayMode::getMonitorInfo( g_monitorRect = Win32::DisplayMode::getMonitorInfo(
D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName).rcMonitor; D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName).rcMonitor;
@ -437,6 +438,7 @@ namespace DDraw
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
desc.dwBackBufferCount = 2; desc.dwBackBufferCount = 2;
auto prevIsFullscreen = g_isFullscreen;
g_isFullscreen = true; g_isFullscreen = true;
CompatPtr<IDirectDrawSurface> surface; CompatPtr<IDirectDrawSurface> surface;
HRESULT result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr); HRESULT result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr);
@ -453,31 +455,34 @@ namespace DDraw
if (FAILED(result)) if (FAILED(result))
{ {
LOG_INFO << "ERROR: Failed to create the real primary surface: " << Compat::hex(result); LOG_INFO << "ERROR: Failed to create the real primary surface: " << Compat::hex(result);
g_monitorRect = {}; g_monitorRect = prevMonitorRect;
g_isFullscreen = prevIsFullscreen;
return result; return result;
} }
auto ddLcl = DDraw::DirectDraw::getInt(dd.get()).lpLcl; auto ddLcl = DDraw::DirectDraw::getInt(dd.get()).lpLcl;
g_tagSurface = DDraw::TagSurface::get(ddLcl); auto tagSurface = DDraw::TagSurface::get(ddLcl);
if (!g_tagSurface) if (!tagSurface)
{ {
LOG_INFO << "ERROR: TagSurface not found"; LOG_INFO << "ERROR: TagSurface not found";
g_monitorRect = {}; g_monitorRect = prevMonitorRect;
g_isFullscreen = prevIsFullscreen;
return DDERR_GENERIC; return DDERR_GENERIC;
} }
if (0 == desc.dwBackBufferCount) if (0 == desc.dwBackBufferCount)
{ {
g_windowedBackBuffer = createWindowedBackBuffer( g_windowedBackBuffer = createWindowedBackBuffer(*tagSurface,
g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top).detach(); g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top).detach();
if (!g_windowedBackBuffer) if (!g_windowedBackBuffer)
{ {
g_monitorRect = {}; g_monitorRect = prevMonitorRect;
g_tagSurface = nullptr; g_isFullscreen = prevIsFullscreen;
return DDERR_GENERIC; return DDERR_GENERIC;
} }
} }
g_tagSurface = tagSurface;
g_frontBuffer = CompatPtr<IDirectDrawSurface7>::from(surface.get()).detach(); g_frontBuffer = CompatPtr<IDirectDrawSurface7>::from(surface.get()).detach();
g_frontBuffer->SetPrivateData(g_frontBuffer, IID_IReleaseNotifier, g_frontBuffer->SetPrivateData(g_frontBuffer, IID_IReleaseNotifier,
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER); &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);

View File

@ -90,23 +90,18 @@ namespace DDraw
{ {
LOG_FUNC("PrimarySurface::create", &dd, desc, surface); LOG_FUNC("PrimarySurface::create", &dd, desc, surface);
DDraw::RealPrimarySurface::destroyDefaultPrimary(); DDraw::RealPrimarySurface::destroyDefaultPrimary();
if (g_primarySurface)
{
LOG_ONCE("Warning: suppressed an attempt to create multiple primary surfaces");
return LOG_RESULT(DDERR_UNSUPPORTED);
}
const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd)); const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd));
g_deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName; auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName;
g_monitorRect = Win32::DisplayMode::getMonitorInfo(g_deviceName).rcMonitor; auto prevMonitorRect = g_monitorRect;
g_monitorRect = Win32::DisplayMode::getMonitorInfo(deviceName).rcMonitor;
g_monitorRect.right = g_monitorRect.left + dm.dwWidth; g_monitorRect.right = g_monitorRect.left + dm.dwWidth;
g_monitorRect.bottom = g_monitorRect.top + dm.dwHeight; g_monitorRect.bottom = g_monitorRect.top + dm.dwHeight;
HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd)); HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd));
if (FAILED(result)) if (FAILED(result))
{ {
g_deviceName.clear(); g_monitorRect = prevMonitorRect;
g_monitorRect = {};
return LOG_RESULT(result); return LOG_RESULT(result);
} }
@ -126,12 +121,12 @@ namespace DDraw
if (FAILED(result)) if (FAILED(result))
{ {
LOG_INFO << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result); LOG_INFO << "ERROR: Failed to create the compat primary surface: " << Compat::hex(result);
g_deviceName.clear(); g_monitorRect = prevMonitorRect;
g_monitorRect = {};
RealPrimarySurface::release(); RealPrimarySurface::release();
return LOG_RESULT(result); return LOG_RESULT(result);
} }
g_deviceName = deviceName;
g_origCaps = origCaps; g_origCaps = origCaps;
g_deviceWindow = *DDraw::DirectDraw::getDeviceWindowPtr(dd.get()); g_deviceWindow = *DDraw::DirectDraw::getDeviceWindowPtr(dd.get());
g_gdiPrimarySurface = createGdiPrimarySurface(*CompatPtr<IDirectDraw>::from(&dd)).detach(); g_gdiPrimarySurface = createGdiPrimarySurface(*CompatPtr<IDirectDraw>::from(&dd)).detach();