You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
563 lines
17 KiB
563 lines
17 KiB
//=============================================================================
|
|
//
|
|
// Copyright (C) 1997 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: ddrestor.c
|
|
// Content: DirectDraw persistent-content surfaces for Windows 9x
|
|
//
|
|
// Date By Reason
|
|
// ---------- -------- -----------------------------------------------------
|
|
// 09/30/1997 jeffno Created
|
|
// 10/02/1997 johnstep Initial implementation
|
|
//
|
|
//=============================================================================
|
|
|
|
#include "ddrawpr.h"
|
|
#include "dx8priv.h"
|
|
|
|
//
|
|
// MEM_SHARED is an undocumented flag for VirtualAlloc, taken from the Windows
|
|
// 9x source code.
|
|
//
|
|
|
|
#define MEM_SHARED 0x08000000 // make memory globally visible
|
|
|
|
//
|
|
// QWORD_MULTIPLE is used to compute the pitch of a dummy surface,
|
|
// based on its width, given that the pitch must be a QWORD multiple.
|
|
//
|
|
|
|
#define QWORD_MULTIPLE(x) (((x) + 7) & 0xFFFFFFF8)
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: allocSurfaceContentsMemory
|
|
//
|
|
//=============================================================================
|
|
|
|
static HRESULT allocSurfaceContentsMemory(LPDDRAWI_DDRAWSURFACE_LCL this_lcl)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_GBL this_gbl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL_MORE this_gbl_more;
|
|
DWORD size;
|
|
LPVOID pvContents;
|
|
LPDDPIXELFORMAT lpddpf;
|
|
|
|
this_gbl = this_lcl->lpGbl;
|
|
this_gbl_more = GET_LPDDRAWSURFACE_GBL_MORE(this_gbl);
|
|
|
|
this_gbl_more->pvContents = NULL;
|
|
this_gbl_more->dwBackupStamp = 0;
|
|
|
|
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
return DD_OK;
|
|
}
|
|
|
|
if (this_gbl->wHeight)
|
|
{
|
|
GET_PIXEL_FORMAT(this_lcl, this_gbl, lpddpf);
|
|
size = QWORD_MULTIPLE((this_gbl->wWidth * lpddpf->dwRGBBitCount) >> 3) * this_gbl->wHeight;
|
|
}
|
|
else
|
|
{
|
|
size = this_gbl->dwLinearSize;
|
|
}
|
|
|
|
//
|
|
// Use VirtualAlloc with the undocumented MEM_SHARED flag so the memory
|
|
// is allcocated from the Windows 9x shared arena. We could change this to
|
|
// use MemAlloc() and instead of VirtualFree, MemFree().
|
|
//
|
|
|
|
pvContents = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_SHARED, PAGE_READWRITE);
|
|
|
|
if (!pvContents)
|
|
{
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
this_gbl_more->pvContents = pvContents;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: allocSurfaceAttachContents
|
|
//
|
|
//=============================================================================
|
|
|
|
static HRESULT allocSurfaceAttachContents(LPDDRAWI_DDRAWSURFACE_LCL this_lcl)
|
|
{
|
|
LPATTACHLIST pattachList;
|
|
LPDDRAWI_DDRAWSURFACE_INT curr_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL curr_lcl;
|
|
HRESULT ddrval;
|
|
|
|
for (pattachList = this_lcl->lpAttachList; pattachList; pattachList = pattachList->lpLink)
|
|
{
|
|
curr_int = pattachList->lpIAttached;
|
|
curr_lcl = curr_int->lpLcl;
|
|
|
|
if (curr_lcl->dwFlags & DDRAWISURF_IMPLICITCREATE)
|
|
{
|
|
ddrval = AllocSurfaceContents(curr_lcl);
|
|
if (FAILED(ddrval))
|
|
{
|
|
return ddrval;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: AllocSurfaceContents
|
|
//
|
|
//=============================================================================
|
|
|
|
HRESULT AllocSurfaceContents(LPDDRAWI_DDRAWSURFACE_LCL this_lcl)
|
|
{
|
|
HRESULT ddrval;
|
|
|
|
ddrval = allocSurfaceContentsMemory(this_lcl);
|
|
if (FAILED(ddrval))
|
|
{
|
|
return ddrval;
|
|
}
|
|
|
|
ddrval = allocSurfaceAttachContents(this_lcl);
|
|
if (FAILED(ddrval))
|
|
{
|
|
return ddrval;
|
|
}
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: FreeSurfaceContents
|
|
//
|
|
//=============================================================================
|
|
|
|
void FreeSurfaceContents(LPDDRAWI_DDRAWSURFACE_LCL this_lcl)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_GBL_MORE this_gbl_more;
|
|
|
|
this_gbl_more = GET_LPDDRAWSURFACE_GBL_MORE(this_lcl->lpGbl);
|
|
|
|
VirtualFree(this_gbl_more->pvContents, 0, MEM_RELEASE);
|
|
|
|
this_gbl_more->pvContents = NULL;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: createDummySurface
|
|
//
|
|
//=============================================================================
|
|
|
|
static LPDDRAWI_DDRAWSURFACE_INT createDummySurface(LPDDRAWI_DDRAWSURFACE_LCL this_lcl)
|
|
{
|
|
LPDDRAWI_DIRECTDRAW_INT pdrv_int;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
|
|
DDSURFACEDESC2 ddsd;
|
|
LPDIRECTDRAWSURFACE lpdds;
|
|
HRESULT ddrval;
|
|
|
|
pdrv_int = this_lcl->lpSurfMore->lpDD_int;
|
|
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
|
|
|
|
ZeroMemory(&ddsd, sizeof ddsd);
|
|
ddsd.dwSize = sizeof ddsd;
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
|
ddsd.dwWidth = 1;
|
|
ddsd.dwHeight = 1;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
|
|
|
|
ddrval = InternalCreateSurface(pdrv_lcl, &ddsd, &lpdds, pdrv_int, NULL, 0);
|
|
if (FAILED(ddrval))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return (LPDDRAWI_DDRAWSURFACE_INT) lpdds;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: BackupSurfaceContents
|
|
//
|
|
// This function assumes that the surface passed in is a video memory
|
|
// surface.
|
|
//
|
|
//=============================================================================
|
|
|
|
HRESULT BackupSurfaceContents(LPDDRAWI_DDRAWSURFACE_LCL this_lcl)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_GBL this_gbl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL_MORE this_gbl_more;
|
|
HRESULT ddrval;
|
|
LPVOID pbits;
|
|
LPDDRAWI_DDRAWSURFACE_INT psurf_int;
|
|
LPDDRAWI_DDRAWSURFACE_INT pnew_int;
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv;
|
|
DDSURFACEDESC2 ddsd;
|
|
DWORD bytes;
|
|
LPBYTE psrc;
|
|
LPBYTE pdst;
|
|
DWORD y;
|
|
LONG pitch;
|
|
LPDDPIXELFORMAT lpddpf;
|
|
|
|
this_gbl = this_lcl->lpGbl;
|
|
this_gbl_more = GET_LPDDRAWSURFACE_GBL_MORE(this_gbl);
|
|
|
|
if (!this_gbl_more->dwBackupStamp &&
|
|
(this_gbl_more->dwBackupStamp == this_gbl_more->dwContentsStamp))
|
|
{
|
|
DPF(3, "Contents unchanged, so not backing up again");
|
|
return DD_OK;
|
|
}
|
|
|
|
if (!this_gbl_more->pvContents)
|
|
{
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
pdrv = this_gbl->lpDD;
|
|
|
|
GET_PIXEL_FORMAT(this_lcl, this_gbl, lpddpf);
|
|
pitch = QWORD_MULTIPLE((this_gbl->wWidth * lpddpf->dwRGBBitCount) >> 3);
|
|
|
|
psurf_int = createDummySurface(this_lcl);
|
|
|
|
//
|
|
// First try to blt, if that fails, we'll lock and copy memory
|
|
//
|
|
|
|
if (psurf_int)
|
|
{
|
|
ZeroMemory(&ddsd, sizeof ddsd);
|
|
ddsd.dwSize = sizeof ddsd;
|
|
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
|
|
ddsd.ddpfPixelFormat.dwSize = sizeof ddsd.ddpfPixelFormat;
|
|
DD_Surface_GetPixelFormat((LPDIRECTDRAWSURFACE) psurf_int, &ddsd.ddpfPixelFormat);
|
|
ddsd.dwWidth = this_gbl->wWidth;
|
|
ddsd.dwHeight = this_gbl->wHeight;
|
|
ddsd.lPitch = pitch;
|
|
ddsd.lpSurface = this_gbl_more->pvContents;
|
|
|
|
ddrval = DD_Surface_SetSurfaceDesc4((LPDIRECTDRAWSURFACE3) psurf_int, &ddsd, 0);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
pnew_int = MemAlloc(sizeof (DDRAWI_DDRAWSURFACE_INT));
|
|
if (pnew_int)
|
|
{
|
|
pnew_int->lpVtbl = &ddSurface4Callbacks;
|
|
pnew_int->lpLcl = this_lcl;
|
|
pnew_int->lpLink = pdrv->dsList;
|
|
pdrv->dsList = pnew_int;
|
|
pnew_int->dwIntRefCnt = 0;
|
|
|
|
ddrval = ((LPDIRECTDRAWSURFACE) psurf_int)->lpVtbl->Blt(
|
|
(LPDIRECTDRAWSURFACE) psurf_int,
|
|
NULL,
|
|
(LPDIRECTDRAWSURFACE) pnew_int,
|
|
NULL,
|
|
DDBLT_WAIT,
|
|
NULL);
|
|
|
|
pdrv->dsList = pnew_int->lpLink;
|
|
MemFree(pnew_int);
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
InternalSurfaceRelease(psurf_int, FALSE, FALSE);
|
|
|
|
this_gbl_more->dwBackupStamp = this_gbl_more->dwContentsStamp;
|
|
|
|
DPF(4, "BackupSurfaceContents Blt succeeded");
|
|
|
|
return DD_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
InternalSurfaceRelease(psurf_int, FALSE, FALSE);
|
|
}
|
|
|
|
//
|
|
// Blt failed, so now we'll just lock and copy memory
|
|
//
|
|
|
|
ddrval = InternalLock(this_lcl, &pbits, NULL , DDLOCK_WAIT | DDLOCK_TAKE_WIN16);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
psrc = pbits;
|
|
pdst = this_gbl_more->pvContents;
|
|
bytes = this_gbl->wWidth;
|
|
bytes *= lpddpf->dwRGBBitCount;
|
|
bytes >>= 3;
|
|
|
|
for (y = 0; y < this_gbl->wHeight; ++y)
|
|
{
|
|
CopyMemory(pdst, psrc, bytes);
|
|
psrc += this_gbl->lPitch;
|
|
pdst += pitch;
|
|
}
|
|
|
|
InternalUnlock(this_lcl, NULL, NULL, DDLOCK_TAKE_WIN16);
|
|
DPF(5, "BackupSurfaceContents CopyMemory succeeded");
|
|
}
|
|
else
|
|
{
|
|
FreeSurfaceContents(this_lcl);
|
|
return ddrval;
|
|
}
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: RestoreSurfaceContents
|
|
//
|
|
//=============================================================================
|
|
|
|
HRESULT RestoreSurfaceContents(LPDDRAWI_DDRAWSURFACE_LCL this_lcl)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_GBL this_gbl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL_MORE this_gbl_more;
|
|
HRESULT ddrval;
|
|
LPVOID pbits;
|
|
LPDDRAWI_DDRAWSURFACE_INT psurf_int;
|
|
LPDDRAWI_DDRAWSURFACE_INT pnew_int;
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv;
|
|
DDSURFACEDESC2 ddsd;
|
|
DWORD bytes;
|
|
LPBYTE psrc;
|
|
LPBYTE pdst;
|
|
DWORD y;
|
|
LONG pitch;
|
|
LPDDPIXELFORMAT lpddpf;
|
|
|
|
this_gbl = this_lcl->lpGbl;
|
|
this_gbl_more = GET_LPDDRAWSURFACE_GBL_MORE(this_gbl);
|
|
|
|
if (!this_gbl_more->pvContents)
|
|
{
|
|
return DDERR_GENERIC; // backup probably failed
|
|
}
|
|
|
|
pdrv = this_gbl->lpDD;
|
|
|
|
GET_PIXEL_FORMAT(this_lcl, this_gbl, lpddpf);
|
|
pitch = QWORD_MULTIPLE((this_gbl->wWidth * lpddpf->dwRGBBitCount) >> 3);
|
|
|
|
psurf_int = createDummySurface(this_lcl);
|
|
|
|
//
|
|
// First try to blt, if that fails, we'll lock and copy memory
|
|
//
|
|
|
|
if (psurf_int)
|
|
{
|
|
ZeroMemory(&ddsd, sizeof ddsd);
|
|
ddsd.dwSize = sizeof ddsd;
|
|
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
|
|
ddsd.ddpfPixelFormat.dwSize = sizeof ddsd.ddpfPixelFormat;
|
|
DD_Surface_GetPixelFormat((LPDIRECTDRAWSURFACE) psurf_int, &ddsd.ddpfPixelFormat);
|
|
ddsd.dwWidth = this_gbl->wWidth;
|
|
ddsd.dwHeight = this_gbl->wHeight;
|
|
ddsd.lPitch = pitch;
|
|
ddsd.lpSurface = this_gbl_more->pvContents;
|
|
|
|
ddrval = DD_Surface_SetSurfaceDesc4((LPDIRECTDRAWSURFACE3) psurf_int, &ddsd, 0);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
pnew_int = MemAlloc(sizeof (DDRAWI_DDRAWSURFACE_INT));
|
|
if (pnew_int)
|
|
{
|
|
pnew_int->lpVtbl = &ddSurface4Callbacks;
|
|
pnew_int->lpLcl = this_lcl;
|
|
pnew_int->lpLink = pdrv->dsList;
|
|
pdrv->dsList = pnew_int;
|
|
pnew_int->dwIntRefCnt = 0;
|
|
|
|
ddrval = ((LPDIRECTDRAWSURFACE) psurf_int)->lpVtbl->Blt(
|
|
(LPDIRECTDRAWSURFACE) pnew_int,
|
|
NULL,
|
|
(LPDIRECTDRAWSURFACE) psurf_int,
|
|
NULL,
|
|
DDBLT_WAIT,
|
|
NULL);
|
|
|
|
this_gbl_more->dwBackupStamp = this_gbl_more->dwContentsStamp;
|
|
|
|
pdrv->dsList = pnew_int->lpLink;
|
|
MemFree(pnew_int);
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
InternalSurfaceRelease(psurf_int, FALSE, FALSE);
|
|
DPF(5, "RestoreSurfaceContents Blt succeeded");
|
|
|
|
return DD_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
InternalSurfaceRelease(psurf_int, FALSE, FALSE);
|
|
}
|
|
|
|
//
|
|
// Blt failed, so now we'll just lock and copy memory
|
|
//
|
|
|
|
ddrval = InternalLock(this_lcl, &pbits, NULL , DDLOCK_WAIT | DDLOCK_TAKE_WIN16);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
psrc = this_gbl_more->pvContents;
|
|
pdst = pbits;
|
|
bytes = this_gbl->wWidth;
|
|
bytes *= lpddpf->dwRGBBitCount;
|
|
bytes >>= 3;
|
|
|
|
for (y = 0; y < this_gbl->wHeight; ++y)
|
|
{
|
|
CopyMemory(pdst, psrc, bytes);
|
|
psrc += pitch;
|
|
pdst += this_gbl->lPitch;
|
|
}
|
|
|
|
InternalUnlock(this_lcl, NULL, NULL, DDLOCK_TAKE_WIN16);
|
|
DPF(5, "RestoreSurfaceContents CopyMemory succeeded");
|
|
|
|
this_gbl_more->dwBackupStamp = this_gbl_more->dwContentsStamp;
|
|
}
|
|
else
|
|
{
|
|
return ddrval;
|
|
}
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: restoreSurfaces
|
|
//
|
|
//=============================================================================
|
|
|
|
static HRESULT restoreSurfaces(LPDDRAWI_DDRAWSURFACE_INT this_int, LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl)
|
|
{
|
|
HRESULT ddrval;
|
|
|
|
if (this_int)
|
|
{
|
|
while (this_int &&
|
|
((this_int->lpLcl->lpSurfMore->lpDD_lcl != pdrv_lcl) ||
|
|
(this_int->lpLcl->dwFlags & DDRAWISURF_IMPLICITCREATE)))
|
|
{
|
|
this_int = this_int->lpLink;
|
|
}
|
|
if (this_int)
|
|
{
|
|
ddrval = restoreSurfaces(this_int->lpLink, pdrv_lcl);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = DD_Surface_Restore((LPDIRECTDRAWSURFACE) this_int);
|
|
if (FAILED(ddrval))
|
|
{
|
|
return ddrval;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return ddrval;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: DD_RestoreAllSurfaces
|
|
//
|
|
// Restore all surfaces owned by the DirectDraw object.
|
|
//
|
|
//=============================================================================
|
|
|
|
HRESULT EXTERN_DDAPI DD_RestoreAllSurfaces(LPDIRECTDRAW lpDD)
|
|
{
|
|
LPDDRAWI_DIRECTDRAW_INT this_int;
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
|
|
HRESULT ddrval;
|
|
|
|
|
|
ENTER_DDRAW()
|
|
|
|
DPF(2,A,"ENTERAPI: DD_RestoreALlSurfaces");
|
|
/*DPF(2, "RestoreAllSurfaces");*/
|
|
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
|
|
if (!VALID_DIRECTDRAW_PTR(this_int))
|
|
{
|
|
LEAVE_DDRAW()
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
this_lcl = this_int->lpLcl;
|
|
}
|
|
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF_ERR("Exception encountered validating parameters");
|
|
LEAVE_DDRAW()
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
ddrval = restoreSurfaces(this_lcl->lpGbl->dsList, this_lcl);
|
|
DPF(5, "RestoreAllSurfaces returns: %08x (%u)", ddrval, HRESULT_CODE(ddrval));
|
|
LEAVE_DDRAW()
|
|
|
|
return ddrval;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Function: BackupAllSurfaces
|
|
//
|
|
// Backup all surfaces owned by the DirectDraw object.
|
|
//
|
|
//=============================================================================
|
|
|
|
void BackupAllSurfaces(LPDDRAWI_DIRECTDRAW_GBL this_gbl)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT psurf_int;
|
|
|
|
DPF(5, "BackupAllSurfaces: %08x", this_gbl);
|
|
|
|
psurf_int = this_gbl->dsList;
|
|
|
|
while (psurf_int)
|
|
{
|
|
if (!SURFACE_LOST(psurf_int->lpLcl) &&
|
|
(psurf_int->lpLcl->lpSurfMore->lpDD_lcl->lpGbl == this_gbl) &&
|
|
(psurf_int->lpLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
|
|
(psurf_int->lpLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_PERSISTENTCONTENTS))
|
|
{
|
|
DPF(5, "BackupSurfaceContents: %08x", psurf_int->lpLcl);
|
|
BackupSurfaceContents(psurf_int->lpLcl);
|
|
}
|
|
|
|
psurf_int = psurf_int->lpLink;
|
|
}
|
|
}
|