|
|
//=============================================================================
//
// 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; } }
|