Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2925 lines
79 KiB

/****************************************************************************
*****************************************************************************
*
* ******************************************
* * Copyright (c) 1995, Cirrus Logic, Inc. *
* * All Rights Reserved *
* ******************************************
*
* PROJECT: Laguna I (CL-GD5462) -
*
* FILE: memmgr.c
*
* AUTHOR: Benny Ng
*
* DESCRIPTION:
* This program provides the off screen memory management
* using (X,Y) coordinate as memory reference instead of
* linear memory.
*
* MODULES:
* SaveOffscnToHost()
* RestoreHostToOffscn()
* DDOffScnMemAlloc()
* DDOffScnMemRestore()
* InitOffScnMem()
* AllocOffScnMem()
* FreeOffScnMem()
* CloseOffScnMem()
* ConvertToVideoBufferAddr()
* OFS_AllocHdl()
* OFS_InitMem()
* OFS_PackMem()
* OFS_InsertInFreeQ()
* OFS_RemoveFrmFreeQ()
* OFS_InsertInUsedQ()
* OFS_RemoveFrmUsedQ()
*
* REVISION HISTORY:
* 6/12/95 Benny Ng Initial version
*
* $Log: X:/log/laguna/nt35/displays/cl546x/MEMMGR.C $
*
* Rev 1.48 Mar 04 1998 15:28:50 frido
* Added new shadow macros.
*
* Rev 1.47 Jan 22 1998 16:21:16 frido
* PDR#11132. The CopyBitmaps function is using byte aligned striping
* but was using the normal BLTEXT register instead of MBLTEXT.
*
* Rev 1.46 Dec 10 1997 13:32:16 frido
* Merged from 1.62 branch.
*
* Rev 1.45.1.2 Dec 04 1997 13:40:22 frido
* PDR#11039: Removed memory mover in 24-bpp as well.
*
* Rev 1.45.1.1 Dec 03 1997 18:11:10 frido
* PDR#11039. Disabled the memory mover in 32-bpp. It seems to cause
* corruption. This needs to be investigated after WHQL!
*
* Rev 1.45.1.0 Nov 13 1997 16:40:52 frido
* Added striping code inside the CopyBitmap routine which is used by the
* memory manager mmMove routine. This fixes the drop in speed in the
* High-End Graphics.
*
* Rev 1.45 Nov 03 1997 15:48:10 frido
* Added REQUIRE macros.
*
* Rev 1.44 Oct 28 1997 09:44:00 frido
* Fixed a compile problem with the updated mmCore.c
*
* Rev 1.43 02 Oct 1997 17:13:36 frido
* I have removed the extra rectangle in 1280x1024x8.
*
* Rev 1.42 24 Sep 1997 13:46:14 frido
* PDR#10526: Immortal Klowns needs its surfaces to be DWORD aligned in size.
*
* Rev 1.41 16 Sep 1997 15:07:28 bennyn
*
* Added eight bytes alignment option
*
* Rev 1.40 29 Aug 1997 14:05:12 noelv
* Added MINSZY define.
*
* Rev 1.39 29 Aug 1997 08:54:58 FRIDO
* The old AllocOffScnMem routine had various bugs in there causing
* overlapping rectangles. The entire algoritm has been changed.
*
* Rev 1.38 25 Aug 1997 16:05:46 FRIDO
*
* Added invalidation of brush cache in DDOffScnMemRestore.
*
* Rev 1.37 18 Aug 1997 09:21:22 FRIDO
*
* Added initialization of bitmap filter.
*
* Rev 1.36 13 Aug 1997 12:16:24 bennyn
* Changed the PREALLOC_Y to 17 & Fixed the free rectange initialization bug
*
* Rev 1.35 08 Aug 1997 17:24:16 FRIDO
* Added support for new memory manager.
*
* Rev 1.34 07 Aug 1997 12:31:30 bennyn
* Undo Shuhua's fix and eliminated the extra rectangle for 1600x1200x16 and x
*
* Rev 1.33 06 Aug 1997 12:47:52 noelv
* Shuhua's fix for DXView no-memory bug. # 10227
*
* Rev 1.32 01 Jul 1997 09:53:30 einkauf
* init pdsurf to NULL in OFS_InsertInFreeQ (fix PDR 9385)
* change x tile size to 64 instead of 32 for 3D draw buffers
*
* Rev 1.31 29 Apr 1997 16:28:46 noelv
*
* Merged in new SWAT code.
* SWAT:
* SWAT: Rev 1.6 24 Apr 1997 11:56:40 frido
* SWAT: NT140b09 merge.
* SWAT:
* SWAT: Rev 1.5 24 Apr 1997 11:49:56 frido
* SWAT: Removed all memory manager changes.
* SWAT:
* SWAT: Rev 1.4 19 Apr 1997 16:41:56 frido
* SWAT: Fixed minor bugs.
* SWAT: Added SWAT.h include file.
* SWAT:
* SWAT: Rev 1.3 15 Apr 1997 19:12:56 frido
* SWAT: Added more SWAT5 code (still disabled).
* SWAT:
* SWAT: Rev 1.2 10 Apr 1997 17:36:56 frido
* SWAT: Started work on SWAT5 optmizations.
* SWAT:
* SWAT: Rev 1.1 09 Apr 1997 17:33:16 frido
* SWAT: Called vAssertModeText to enable/disable font cache for DirectDraw.
*
* Rev 1.30 17 Apr 1997 15:31:28 noelv
* Dont' use the extra rectangle on an 8 meg board.
*
* Rev 1.29 17 Apr 1997 12:03:44 bennyn
* Fixed init offscn mem allocation problem for 1280x1024x24.
*
* Rev 1.28 26 Feb 1997 09:23:40 noelv
*
* Added MCD support from ADC
*
* Rev 1.27 23 Jan 1997 10:57:32 noelv
* Added debugging option to erase memory blocks when freed.
*
* Rev 1.26 27 Nov 1996 11:32:42 noelv
* Disabled Magic Bitmap. Yeah!!!
*
* Rev 1.25 26 Nov 1996 09:58:52 noelv
*
* Added DBG prints.
*
* Rev 1.24 12 Nov 1996 15:21:58 bennyn
*
* Fixed ALT-ENTER problem with DD appl
*
* Rev 1.23 07 Nov 1996 16:01:38 bennyn
* Alloc offscn mem in DD createsurface
*
* Rev 1.22 23 Oct 1996 14:42:42 BENNYN
*
* CLeanup not use code for DirectDraw cursor
*
* Rev 1.21 18 Sep 1996 13:58:48 bennyn
*
* Put the cursor mask and brush cache at the bottom of offscn mem
*
* Rev 1.20 27 Aug 1996 09:41:48 bennyn
* Restore the changes from the missing version
*
* Rev 1.19 26 Aug 1996 17:33:40 bennyn
* Restore the changes for the losed version
*
* Rev 1.18 23 Aug 1996 09:10:28 noelv
* Save unders are now discardable.
*
* Rev 1.7 22 Aug 1996 18:09:30 frido
* #ss -Added removing of DrvSaveScreenBits areas when DirectDraw gets
* initialized.
*
* Rev 1.6 20 Aug 1996 11:07:56 frido
* #ddl - Fixed DirectDraw lockup problem (compiler optimization bug).
*
* Rev 1.5 17 Aug 1996 19:39:16 frido
* Fixed DirectDraw cursor problem.
*
* Rev 1.4 17 Aug 1996 14:03:42 frido
* Added pre-compiled header.
*
* Rev 1.3 17 Aug 1996 13:25:28 frido
* New release from Bellevue.
*
* Rev 1.14 16 Aug 1996 09:04:22 bennyn
*
* Modified to fix DirectDraw cursor problem
*
* Rev 1.13 07 Aug 1996 13:52:32 noelv
*
* Cleaned up my hack job init code.
*
* Rev 1.12 25 Jul 1996 15:59:14 bennyn
*
* Free more offscreen mem for DirectDraw
*
* Rev 1.11 11 Jul 1996 15:54:18 bennyn
*
* Added DirectDraw support
*
* Rev 1.10 05 Jun 1996 09:03:10 noelv
*
* Added the "extra rectangle".
*
* Rev 1.9 27 May 1996 14:53:12 BENNYN
* Use 2 free queues search instead of one
*
* Rev 1.8 21 May 1996 14:43:24 BENNYN
* Cleanup and code optimize.
*
* Rev 1.7 01 May 1996 11:00:06 bennyn
*
* Modified for NT4.0
*
* Rev 1.6 25 Apr 1996 22:40:34 noelv
* Cleaned up frame buffer initialization some. All of main rectangle is mana
*
* Rev 1.5 10 Apr 1996 14:14:34 NOELV
*
* Hacked to ignore the 'extra' rectangle.
*
* Rev 1.4 04 Apr 1996 13:20:18 noelv
* Frido release 26
*
* Rev 1.2 28 Mar 1996 20:03:16 frido
* Added comments around changes.
*
* Rev 1.1 25 Mar 1996 11:56:26 frido
* Removed warning message.
*
* Rev 1.0 17 Jan 1996 12:53:26 frido
* Checked in from initial workfile by PVCS Version Manager Project Assistant.
*
* Rev 1.0 25 Jul 1995 11:23:18 NOELV
* Initial revision.
*
* Rev 1.4 20 Jun 1995 16:09:46 BENNYN
*
*
* Rev 1.3 09 Jun 1995 16:03:38 BENNYN
*
* Rev 1.2 09 Jun 1995 09:48:54 BENNYN
* Modified the linear address offset calculation
*
* Rev 1.1 08 Jun 1995 15:20:08 BENNYN
*
* Rev 1.0 08 Jun 1995 14:54:16 BENNYN
* Initial revision.
*
****************************************************************************
****************************************************************************/
/*----------------------------- INCLUDES ----------------------------------*/
#include "precomp.h"
#include "SWAT.h" // SWAT optimizations.
#define DISPLVL 1
#if !MEMMGR
/******************************************************************************\
* *
* O L D M E M O R Y M A N A G E R *
* *
\******************************************************************************/
/*----------------------------- DEFINES -----------------------------------*/
// Definition of FLAG in OFMHDL structure
#define IN_USE 1
#define FREE 2
#define UNKNOWN 3
#define MEMSZY 64
#define MINSZX 16
#define MINSZY 1
//#define DBGBRK
#define PREALLOC_Y 17
//
// This is a debugging option.
// We will erase (paint white) offscreen memory when it is freed.
//
#define CLEAR_WHEN_FREE 0
/*--------------------- STATIC FUNCTION PROTOTYPES ------------------------*/
/*--------------------------- ENUMERATIONS --------------------------------*/
/*----------------------------- TYPEDEFS ----------------------------------*/
typedef union _HOST_DATA {
BYTE bData[8];
DWORD dwData[2];
} HOST_DATA;
/*-------------------------- STATIC VARIABLES -----------------------------*/
/*-------------------------- GLOBAL FUNCTIONS -----------------------------*/
// Function prototypes
POFMHDL OFS_AllocHdl();
BOOL OFS_InitMem (PPDEV ppdev, PRECTL surf);
POFMHDL OFS_FindBestFitFreeBlock(PPDEV ppdev, OFMHDL *pFreeQ,
PLONG reqszx, PLONG reqszy,
ULONG alignflag);
void OFS_PackMem (PPDEV ppdev, OFMHDL *hdl);
void OFS_InsertInFreeQ (PPDEV ppdev, OFMHDL *hdl);
void OFS_RemoveFrmFreeQ (PPDEV ppdev, OFMHDL *hdl);
void OFS_InsertInUsedQ (PPDEV ppdev, OFMHDL *hdl);
void OFS_RemoveFrmUsedQ (PPDEV ppdev, OFMHDL *hdl);
BOOL OFS_DiscardMem(PPDEV ppdev, LONG reqszx, LONG reqszy);
#ifndef WINNT_VER35
#if 0 // Save the code as sample screen to host and host to screen BLT
// ppdev->pPtrMaskHost = SaveOffscnToHost(ppdev, ppdev->PtrMaskHandle);
// RestoreHostToOffscn(ppdev, ppdev->PtrMaskHandle, ppdev->pPtrMaskHost);
/****************************************************************************
* FUNCTION NAME: SaveOffscnToHost
*
* DESCRIPTION: Save the off-screen memory to host.
*
* Output: Pointer to host address
* NULL = failed.
****************************************************************************/
PBYTE SaveOffscnToHost(PPDEV ppdev, POFMHDL pdh)
{
BYTE *pvHost = NULL;
BYTE *pvHostScan0;
HOST_DATA rddata;
ULONG ultmp;
LONG i, j, k;
LONG xsize, ysize, tsize;
if (pdh == NULL)
return NULL;
// Calculate the host size
tsize = pdh->sizex * pdh->sizey;
pvHostScan0 = (BYTE *) MEM_ALLOC (FL_ZERO_MEMORY, tsize, ALLOC_TAG);
if (pvHostScan0 == NULL)
return NULL;
DISPDBG((DISPLVL, "SaveOffscnToHost\n"));
// Do a Screen to Host BLT
// Wait for BLT engine not busy
while (((ultmp = LLDR_SZ (grSTATUS)) & 0x7) != 0)
;
// Save the host address in PDEV
pvHost = pvHostScan0;
// Setup the laguna registers for byte to byte BLT extents
REQUIRE(9);
LL_DRAWBLTDEF(0x201000CC, 0);
// LL16 (grOP1_opRDRAM.pt.X, 0);
LL_OP1_MONO (pdh->x, pdh->y);
LL32 (grOP0_opMRDRAM.dw, 0);
// LL16 (grMBLTEXT_EX.pt.X, (WORD)lSrcDelta);
// LL16 (grMBLTEXT_EX.pt.Y, cy);
xsize = pdh->sizex;
ysize = pdh->sizey;
LL_MBLTEXT (xsize, ysize);
// Copy the offscreen memory data to host space
for (i=0; i < ysize; i++)
{
// Copy one screen line data from source to destination
k = 8;
for (j=0; j < xsize; j++)
{
if (k > 7)
{
k = 0;
// Read the offscreen data
rddata.dwData[0] = LLDR_SZ(grHOSTDATA[0]);
rddata.dwData[1] = LLDR_SZ(grHOSTDATA[1]);
};
*pvHostScan0 = rddata.bData[k++];
pvHostScan0++;
}; // end for j
}; // end for i
return (pvHost);
}
/****************************************************************************
* FUNCTION NAME: RestoreHostToOffscn
*
* DESCRIPTION: Restore host data to the off-screen memory.
*
* Output: TRUE = success,
* FALSE = failed.
****************************************************************************/
BOOL RestoreHostToOffscn(PPDEV ppdev, POFMHDL pdh, PBYTE pHostAddr)
{
BYTE *pvScan0;
ULONG ultmp;
LONG cx, cy;
LONG i, j, k;
ULONG XYcord;
PDWORD pPattern;
HOST_DATA datapattern;
LONG xsize, ysize;
if ((pdh == NULL) || (pHostAddr == NULL))
return FALSE;
DISPDBG((DISPLVL, "RestoreHostToOffscn\n"));
// Do the host to screen blt
// Wait for BLT engine not busy
while (((ultmp = LLDR_SZ (grSTATUS)) & 0x7) != 0)
;
pPattern = &datapattern.dwData[0];
pvScan0 = pHostAddr;
// Get dimensions of the bitmap
cx = pdh->sizex;
cy = pdh->sizey;
// Setup the laguna registers for byte to byte BLT extents
REQUIRE(9);
LL_DRAWBLTDEF(0x102000CC, 0);
// LL16 (grOP1_opRDRAM.pt.X, 0);
LL_OP1 (0,0);
XYcord = (pdh->y << 16) | (pdh->x);
LL32 (grOP0_opMRDRAM.dw, XYcord);
// LL16 (grMBLTEXT_EX.pt.X, (WORD)lSrcDelta);
// LL16 (grMBLTEXT_EX.pt.Y, cy);
LL_MBLTEXT (cx, cy);
// Copy the host bitmap data into the space in offscreen memory
k = 0;
for (i=0; i < cy; i++)
{
datapattern.dwData[0] = 0;
// Copy one screen line data from source to destination
for (j=0; j < cx; j++)
{
datapattern.bData[k++] = *pvScan0;
pvScan0++;
if (k > 3)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *pPattern);
k = 0;
}; // endif (k > 3)
}; // endfor j
}; // end for i
return TRUE;
}
#endif
#if 0 // SWAT3 - the "inifinite" loop has gone
#if 1 //#ddl
#pragma optimize("", off)
#endif
#endif
/****************************************************************************
* FUNCTION NAME: DDOffScnMemAlloc()
*
* DESCRIPTION: Free up as much off-screen memory as possible, and
* reserve the biggest chunk for use by DirectDraw.
*
* Output: Pointer to the OFMHDL structure or.
* NULL means not enough memory for allocation.
****************************************************************************/
POFMHDL DDOffScnMemAlloc(PPDEV ppdev)
{
LONG lg_szx, lg_szy;
OFMHDL *pds, *pallochdl;
POFMHDL pofm, pofmNext;
ULONG ultmp;
DISPDBG((DISPLVL, "DDOffScnMemAlloc\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
#if WINBENCH96
// Free the pre-allocate magic block
if (ppdev->pofmMagic != NULL)
{
FreeOffScnMem(ppdev, ppdev->pofmMagic);
ppdev->pofmMagic = NULL;
ppdev->bMagicUsed = 0;
};
#endif
#if 0 // Not free the brush cache
// Free the brush cache
if (ppdev->Bcache != NULL)
{
FreeOffScnMem(ppdev, ppdev->Bcache);
ppdev->Bcache = NULL;
};
#endif // Not free the brush cache
// We have to move all off-screen device bitmaps to memory.
for (pofm = ppdev->OFM_UsedQ; pofm; pofm = pofmNext)
{
pofmNext = pofm->nexthdl;
if ( (pofm->pdsurf) && (pofm->pdsurf->pofm) )
{
if (!bCreateDibFromScreen(ppdev, pofm->pdsurf))
{
DISPDBG((DISPLVL, "DD: Error moving off-screen bitmap to DIB"));
break;
}
}
#if 1 //#ss
else if (pofm->alignflag & SAVESCREEN_FLAG)
{
// Free the DrvSaveScreenBits rectangle.
FreeOffScnMem(ppdev, pofm);
}
#endif
}
// Free the Font cache.
#if 1 // SWAT3 - Font cache release has moved to vAssertModeText.
vAssertModeText(ppdev, FALSE);
#else
while (ppdev->pfcChain != NULL)
{
DrvDestroyFont(ppdev->pfcChain->pfo);
}
#endif
// Find the biggest chunk of free memory for use by DirectDraw.
#ifndef ALLOC_IN_CREATESURFACE
if ((pds = ppdev->OFM_SubFreeQ2) == NULL)
pds = ppdev->OFM_SubFreeQ1;
#endif
pallochdl = NULL;
#ifndef ALLOC_IN_CREATESURFACE
lg_szx = 0;
lg_szy = 0;
while (pds != NULL)
{
if (pds->flag == FREE)
{
if ((pds->sizex > lg_szx) || (pds->sizey > lg_szy))
{
lg_szx = pds->sizex;
lg_szy = pds->sizey;
pallochdl = pds;
}; // if ((pds->sizex > lg_szx) || (pds->sizex > lg_szy))
}; // if (pds->flag == FREE)
// Next free block
pds = pds->subnxthdl;
} /* end while */
// Remove the free block from Free Queue and insert into the Used Queue
if (pallochdl != NULL)
{
OFS_RemoveFrmFreeQ(ppdev, pallochdl);
OFS_InsertInUsedQ(ppdev, pallochdl);
};
#endif
return(pallochdl);
} // DDOffScnMemAlloc()
#if 0 // SWAT3
#if 1 //#ddl
#pragma optimize("", on)
#endif
#endif
/****************************************************************************
* FUNCTION NAME: DDOffScnMemRestore()
*
* DESCRIPTION: Restore the offscreen memory allocation after DirectDraw
* use.
****************************************************************************/
void DDOffScnMemRestore(PPDEV ppdev)
{
SIZEL sizl;
int i;
ULONG curloc;
ULONG ultmp;
DDOFM *pds;
DDOFM *nxtpds;
DISPDBG((DISPLVL, "DDOffScnMemRestore\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
// Free all the DD allocate offsreen memory
pds = ppdev->DDOffScnMemQ;
while (pds != NULL)
{
nxtpds = pds->nexthdl;
FreeOffScnMem(ppdev, pds->phdl);
MEMORY_FREE(pds);
pds = nxtpds;
};
ppdev->DDOffScnMemQ = NULL;
// Free the allocated DirectDraw off-screen memory
if (ppdev->DirectDrawHandle != NULL)
{
FreeOffScnMem(ppdev, ppdev->DirectDrawHandle);
ppdev->DirectDrawHandle = NULL;
};
#if 0 // Not free the brush cache
// Allocate brush cache
vInvalidateBrushCache(ppdev);
// Invalidate the entire monochrome brush cache.
for (i = 0; i < NUM_MONO_BRUSHES; i++)
{
ppdev->Mtable[i].iUniq = 0;
memset(ppdev->Mtable[i].ajPattern, 0, sizeof(ppdev->Mtable[i].ajPattern));
}
ppdev->MNext = 0;
// Invalidate the entire 4-bpp brush cache.
for (i = 0; i < NUM_4BPP_BRUSHES; i++)
{
ppdev->Xtable[i].iUniq = 0;
memset(ppdev->Xtable[i].ajPattern, 0, sizeof(ppdev->Xtable[i].ajPattern));
}
ppdev->XNext = 0;
// Invalidate the entire dither brush cache.
for (i = 0; i < NUM_DITHER_BRUSHES; i++)
{
ppdev->Dtable[i].ulColor = (ULONG) -1;
}
ppdev->DNext = 0;
// Invalidate the entire color brush cache.
for (i = 0; i < (int) ppdev->CLast; i++)
{
ppdev->Ctable[i].brushID = 0;
}
ppdev->CNext = 0;
#else
// Invalidate the entire brush cache now.
vInvalidateBrushCache(ppdev);
#endif // Not free the brush cache
#if WINBENCH96
// Allocate the magic block
sizl.cx = MAGIC_SIZEX;
sizl.cy = MAGIC_SIZEY;
ppdev->pofmMagic = AllocOffScnMem(ppdev, &sizl, PIXEL_AlIGN, NULL);
ppdev->bMagicUsed = 0;
#endif
// Invalidate all cached fonts.
#if SWAT3
vAssertModeText(ppdev, TRUE);
#endif
ppdev->ulFontCount++;
} // DDOffScnMemRestore()
#endif // ! ver3.51
/****************************************************************************
* FUNCTION NAME: InitOffScnMem()
*
* DESCRIPTION: Initialize the offscreen memory. This module uses
* the screen size, screen pitch and bits per pixel to
* calculate the amount of off screen available and performs
* the off screen memory management initialization.
*
* When this routine is called, the following member in
* the PDEV structure is assumed being setup for the current
* mode.
* lOffset_2D,
* lTotalMem,
* lTileSize,
* lDeltaScreen,
* ulBitCount
* cxScreen,
* cyScreen.
*
* This routine needs to be called whenever there is a
* mode change.
*
* Output: TRUE = Ok,
* FALSE = failed.
****************************************************************************/
BOOL InitOffScnMem(PPDEV ppdev)
{
BOOL bAllocCursorMaskBuf;
RECTL surf;
SIZEL rctsize;
ULONG AvailMem;
ULONG ulTemp;
ULONG alignflag;
LONG ScnPitch;
ULONG BytesInExtraRect, BytesInMainRect, Interleave, WidthInTiles,
TileHeight, ExtraHeight, ExtraWidth, NumScanLines;
ULONG ulLastLinearScan = ppdev->lTotalMem / ppdev->lDeltaScreen;
BYTE TileCntl;
DISPDBG((DISPLVL, "InitOffScnMem\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
// If invalid argument or offscreen manager already initialized,
// return FALSE
if ((ppdev == NULL) || (ppdev->OFM_init == TRUE))
return (FALSE);
// Create Mutex
#ifdef WINNT_VER40
if ((ppdev->MMhsem = EngCreateSemaphore()) == NULL)
#else
if ((ppdev->MutexHdl = CreateMutex(NULL, FALSE, NULL)) == NULL)
#endif
return (FALSE);
// Wait for Mutex is released
#ifdef WINNT_VER40
EngAcquireSemaphore(ppdev->MMhsem);
#else
WaitForSingleObject(ppdev->MutexHdl, INFINITE);
#endif
ppdev->bDirectDrawInUse = FALSE;
ppdev->OFM_init = TRUE;
ppdev->OFM_SubFreeQ1 = NULL;
ppdev->OFM_SubFreeQ2 = NULL;
ppdev->OFM_UsedQ = NULL;
ppdev->OFM_FreeQ = NULL;
ppdev->DDOffScnMemQ = NULL;
#ifdef WINNT_VER40
ppdev->DirectDrawHandle = NULL;
#endif
// Release the Mutex
#ifdef WINNT_VER40
EngReleaseSemaphore(ppdev->MMhsem);
#else
ReleaseMutex(ppdev->MutexHdl);
#endif
//
// Get the whole frame buffer as off screen memory.
// The frame buffer is composed of 2 rectangles. A main rectangle
// whose width is the same as the memory pitch, and an "extra" rectangle
// which is narrower and hangs off the lower left corner of the main
// rectangle.
//
// The tiling interleave factor.
TileCntl = LLDR_SZ(grTILE_CTRL);
DISPDBG((DISPLVL, "InitOffScnMem - TileCntl = %d\n", TileCntl));
TileCntl = (TileCntl >> 6) & 0x3;
Interleave = 1 << TileCntl;
DISPDBG((DISPLVL, "InitOffScnMem - Interleave = %d\n", Interleave));
// Width of the frame buffer in tiles. Each tile may be 128x16 bytes
// or 256x8 bytes.
WidthInTiles = ppdev->lDeltaScreen / ppdev->lTileSize;
DISPDBG((DISPLVL, "InitOffScnMem - WidthInTiles = %d\n", WidthInTiles));
// Get the size in bytes of the Extra rectangle.
BytesInExtraRect = ppdev->lTotalMem % (WidthInTiles * 2048 * Interleave);
DISPDBG((DISPLVL, "InitOffScnMem - BytesInExtraRect = %d\n",
BytesInExtraRect));
// Get the size in bytes of the Main rectangle
BytesInMainRect = ppdev->lTotalMem - BytesInExtraRect;
DISPDBG((DISPLVL, "InitOffScnMem - BytesInMain = %d\n", BytesInMainRect));
// Get the number of scan lines in the main rectangle.
NumScanLines = BytesInMainRect / ppdev->lDeltaScreen;
DISPDBG((DISPLVL, "InitOffScnMem - NumScanLines = %d\n", NumScanLines));
// v-normmi
ppdev->cyMemoryReal = NumScanLines; // without extra rectangle which will be
// added below
// Manage main rectangle
if (NumScanLines > (ppdev->cyScreen + PREALLOC_Y))
{
surf.left = 0;
surf.top = 0;
surf.right = ppdev->lDeltaScreen;
surf.bottom = NumScanLines - PREALLOC_Y;
}
else if (NumScanLines > ppdev->cyScreen)
{
surf.left = 0;
surf.top = 0;
surf.right = ppdev->lDeltaScreen;
surf.bottom = ppdev->cyScreen;
}
// v-normmi
// else if ((ULONG) ppdev->lDeltaScreen != ppdev->cxScreen)
else if ((ULONG) ppdev->lDeltaScreen != (ppdev->cxScreen * ppdev->iBytesPerPixel))
{
surf.left = ppdev->cxScreen * ppdev->iBytesPerPixel;
surf.top = 0;
surf.right = ppdev->lDeltaScreen;
surf.bottom = NumScanLines - PREALLOC_Y;
if (!OFS_InitMem(ppdev, &surf))
{
DISPDBG((DISPLVL, "InitOffScnMem - InitMem1-1 failed\n"));
return(FALSE);
}
surf.left = 0;
surf.top = 0;
surf.right = ppdev->cxScreen * ppdev->iBytesPerPixel;
surf.bottom = NumScanLines;
}
else
{
surf.left = 0;
surf.top = 0;
surf.right = ppdev->lDeltaScreen;
surf.bottom = NumScanLines;
};
DISPDBG((DISPLVL, "Initializing surface (x=%d,y=%d) to (x=%d,y=%d)....\n",
surf.left, surf.top, surf.right, surf.bottom));
if (!OFS_InitMem(ppdev, &surf))
{
DISPDBG((DISPLVL, "InitOffScnMem - InitMem1 failed\n"));
return(FALSE);
}
// Mark a (PREALLOC_Y x Screen pitch) free block at the buttom
// of the offscreen memory.
// The purpose for that is to force the cursor mask and brush cache
// to be allocated at that area.
bAllocCursorMaskBuf = FALSE;
if (NumScanLines > (ppdev->cyScreen + PREALLOC_Y))
{
bAllocCursorMaskBuf = TRUE;
surf.left = 0;
surf.top = NumScanLines - PREALLOC_Y;
surf.right = ppdev->lDeltaScreen;
surf.bottom = NumScanLines;
}
else if (NumScanLines > ppdev->cyScreen)
{
bAllocCursorMaskBuf = TRUE;
surf.left = 0;
surf.top = ppdev->cyScreen;
surf.right = ppdev->lDeltaScreen;
surf.bottom = NumScanLines;
}
// v-normmi
// else if ((ULONG) ppdev->lDeltaScreen != ppdev->cxScreen)
else if ((ULONG) ppdev->lDeltaScreen != (ppdev->cxScreen * ppdev->iBytesPerPixel))
{
bAllocCursorMaskBuf = TRUE;
surf.left = ppdev->cxScreen * ppdev->iBytesPerPixel;
surf.top = NumScanLines - PREALLOC_Y;
surf.right = ppdev->lDeltaScreen;
surf.bottom = NumScanLines;
};
if (bAllocCursorMaskBuf)
{
if (!OFS_InitMem(ppdev, &surf))
{
DISPDBG((DISPLVL, "InitOffScnMem - InitMem2 failed\n"));
return(FALSE);
}
};
//
// BTN - For some reason, this extra rectange cause the WHQL PC97
// Rand Create/Release 100x test fails on 1600x1200x16 and 1600x1200x8
//
if ((ppdev->cxScreen == 1600) &&
(ppdev->cyScreen == 1200) &&
((ppdev->iBytesPerPixel == 2) || (ppdev->iBytesPerPixel == 1)))
BytesInExtraRect = 0;
//
// Manage the extra rectangle.
// NVH - Skip for 8 meg boards.
//
if (ppdev->lTotalMem < 8*1024*1024)
if (BytesInExtraRect)
{
// get Tile Height
TileHeight = 2048 / ppdev->lTileSize;
DISPDBG((DISPLVL, "InitOffScnMem - TileHeight = %d\n", TileHeight));
// Get height of extra rectangle
ExtraHeight = Interleave * TileHeight;
DISPDBG((DISPLVL, "InitOffScnMem - ExtraHeight = %d\n", ExtraHeight));
// v-normmi
ppdev->cyMemoryReal += ExtraHeight; // account for extra rectangle
// Get the width of the extra rectangle
ExtraWidth = BytesInExtraRect / ExtraHeight;
DISPDBG((DISPLVL, "InitOffScnMem - ExtraWidth = %d\n", ExtraWidth));
ulLastLinearScan = (ExtraHeight + NumScanLines);
surf.left = 0;
surf.top = NumScanLines;
surf.right = ExtraWidth;
surf.bottom = MIN ((LONG) ulLastLinearScan,
(LONG) (ExtraHeight+NumScanLines));
DISPDBG((DISPLVL, "Initializing surface (x=%d,y=%d) to (x=%d,y=%d).\n",
surf.left, surf.top, surf.right, surf.bottom));
if (!OFS_InitMem(ppdev, &surf))
{
DISPDBG((DISPLVL, "InitOffScnMem - InitMem1 failed\n"));
return(FALSE);
}
}
else
{
DISPDBG((DISPLVL, " **** No extra rectangle.\n"));
}
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
// Allocate the active video buffer space from the off screen memory
rctsize.cx = ppdev->cxScreen;
rctsize.cy = ppdev->cyScreen;
if ((ppdev->lTileSize == (LONG) 128) || (ppdev->lTileSize == (LONG) 256))
alignflag = 0;
else
alignflag = NO_X_TILE_AlIGN | NO_Y_TILE_AlIGN;
if ((ppdev->ScrnHandle = AllocOffScnMem(ppdev, &rctsize, alignflag, NULL)) == NULL)
{
DISPDBG((DISPLVL, "InitOffScnMem - AllocOffScnMem failed\n"));
return(FALSE);
};
DISPDBG((DISPLVL, "InitOffScnMem Completed\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
return (TRUE);
} // InitOffScnMem()
/****************************************************************************
* FUNCTION NAME: AllocOffScnMem()
*
* DESCRIPTION: Allocate a rectange space from the offscreen memory.
* This routine do a search of the Free Queue to find a
* best fit free memory block. It the free block is bigger
* than the request size, it will split the unused memory
* into smaller rectange blocks and insert them back to
* the Free Queue for future use. It will also do a tile
* or pixel alignment if requested.
*
* If no more enough free memory for the current request,
* This routine will search Used Queue for any discardable
* allocated block. Releases those blocks to satisfy
* the current request.
*
* An user-supplied callback function will be call before
* the discardable block is released.
*
* Input: surf: Request of the offscreen memory size (in Pixel).
*
* alignflag: Alignment flag.
*
* pcallback: Callback function pointer.
* (Only apply if the flag is set to DISCARDABLE_FLAG).
*
* Output: Pointer to the OFMHDL structure or.
* NULL means not enough memory for allocation.
****************************************************************************/
POFMHDL AllocOffScnMem(PPDEV ppdev,
PSIZEL surf,
ULONG alignflag,
POFM_CALLBACK pcallback)
{
// Convert the pixel into bytes requirement
LONG bpp;
LONG reqszx;
LONG reqszy;
LONG orgreqszx;
OFMHDL *pds, *pallochdl;
BOOL findflg, alignblkflg;
LONG szx, szy;
LONG tmpx, tmpy;
DISPDBG((DISPLVL, "AllocOffScnMem\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
if (alignflag & MCD_Z_BUFFER_ALLOCATE)
{
// special memory region -> z buffer: always 16bit/pix
bpp = 2;
}
else if (alignflag & MCD_TEXTURE_ALLOCATE)
{
// special memory region -> texture map: depth varies and is coded in alignflag
bpp = (alignflag & MCD_TEXTURE_ALLOCATE) >> MCD_TEXTURE_ALLOC_SHIFT;
}
else
{
// normal memory region -> allocate at depth of frame buffer
bpp = ppdev->ulBitCount/8;
}
reqszx = surf->cx * bpp;
reqszy = surf->cy;
orgreqszx = reqszx;
// If no more free memory or invalid arguments, return NULL
// if ((ppdev == NULL) || (surf == NULL) || (ppdev->OFM_FreeQ == NULL) || (!ppdev->OFM_init))
if (ppdev->OFM_FreeQ == NULL)
return (NULL);
#ifndef ALLOC_IN_CREATESURFACE
if (ppdev->bDirectDrawInUse)
return (NULL);
#endif
// Wait for Mutex is released
#ifdef WINNT_VER40
EngAcquireSemaphore(ppdev->MMhsem);
#else
WaitForSingleObject(ppdev->MutexHdl, INFINITE);
#endif
// Search for the free memory block
findflg = FALSE;
pallochdl = NULL;
while (!findflg)
{
// Search for the best fit block for the request and
// Check whether any free block satisfy the requirement
if (reqszy < MEMSZY)
{
pallochdl = OFS_FindBestFitFreeBlock(ppdev,
ppdev->OFM_SubFreeQ1,
&reqszx, &reqszy,
alignflag);
};
if (pallochdl == NULL)
{
pallochdl = OFS_FindBestFitFreeBlock(ppdev,
ppdev->OFM_SubFreeQ2,
&reqszx, &reqszy,
alignflag);
};
if (pallochdl != NULL)
{
// Remove the free block from Free Queue
OFS_RemoveFrmFreeQ(ppdev, pallochdl);
alignblkflg = FALSE;
#if 0 // Frido 08/29/97: a new algorithm is in place now, see below.
// If tilt aligned, create the free block for the align adjusted
// memory
if (!(alignflag & PIXEL_AlIGN))
{
if ((tmpx = pallochdl->aligned_x - pallochdl->x) > MINSZX)
{
if ((pds = OFS_AllocHdl()) != NULL)
{
pds->x = pallochdl->x;
pds->y = pallochdl->y;
pds->sizex = tmpx;
pds->sizey = reqszy;
OFS_InsertInFreeQ(ppdev, pds);
alignblkflg = TRUE;
};
};
};
szx = pallochdl->sizex;
szy = pallochdl->sizey;
// If the block is larger than the request size, create the
// free blocks for excess size
if ((szx > reqszx) && (szy > reqszy))
{
if ((szx - reqszx) > (szy - reqszy))
{
tmpx = reqszx;
tmpy = szy;
}
else
{
tmpx = szx;
tmpy = reqszy;
};
}
else
{
tmpx = reqszx;
tmpy = reqszy;
}; // endif ((szx > reqszx) && (szy > reqszy))
if (szx > reqszx)
{
if ((pds = OFS_AllocHdl()) != NULL)
{
pds->x = pallochdl->x + reqszx;
pds->y = pallochdl->y;
pds->sizex = szx - reqszx;
pds->sizey = tmpy;
OFS_InsertInFreeQ(ppdev, pds);
};
}
else
{
reqszx = szx;
};
if (szy > reqszy)
{
if ((pds = OFS_AllocHdl()) != NULL)
{
pds->x = pallochdl->x;
pds->y = pallochdl->y + reqszy;
pds->sizex = tmpx;
pds->sizey = szy - reqszy;
OFS_InsertInFreeQ(ppdev, pds);
};
}
else
{
reqszy = szy;
};
// If this is discardable block, save the callback function pointer
if ((alignflag & DISCARDABLE_FLAG) != 0)
pallochdl->pcallback = pcallback;
else
pallochdl->pcallback = NULL;
// Insert allocate block into the Used Queue
if (alignblkflg)
{
pallochdl->x = pallochdl->aligned_x;
pallochdl->y = pallochdl->aligned_y;
pallochdl->sizex = orgreqszx;
}
else
{
pallochdl->sizex = reqszx;
};
pallochdl->sizey = reqszy;
#else
tmpx = pallochdl->aligned_x + reqszx;
tmpy = pallochdl->aligned_y + reqszy;
// Do we have extra space at the top?
szy = pallochdl->aligned_y - pallochdl->y;
if (szy >= MINSZY)
{
pds = OFS_AllocHdl();
if (pds != NULL)
{
pds->x = pallochdl->x;
pds->y = pallochdl->y;
pds->sizex = pallochdl->sizex;
pds->sizey = szy;
OFS_InsertInFreeQ(ppdev, pds);
pallochdl->y += szy;
pallochdl->sizey -= szy;
}
}
// Do we have extra space at the bottom?
szy = pallochdl->y + pallochdl->sizey - tmpy;
if (szy >= MINSZY)
{
pds = OFS_AllocHdl();
if (pds != NULL)
{
pds->x = pallochdl->x;
pds->y = tmpy;
pds->sizex = pallochdl->sizex;
pds->sizey = szy;
OFS_InsertInFreeQ(ppdev, pds);
pallochdl->sizey -= szy;
}
}
// Do we have extra space at the top?
szx = pallochdl->aligned_x - pallochdl->x;
if (szx >= MINSZX)
{
pds = OFS_AllocHdl();
if (pds != NULL)
{
pds->x = pallochdl->x;
pds->y = pallochdl->y;
pds->sizex = szx;
pds->sizey = pallochdl->sizey;
OFS_InsertInFreeQ(ppdev, pds);
pallochdl->x += szx;
pallochdl->sizex -= szx;
}
}
// Do we have extra space at the right?
szx = pallochdl->x + pallochdl->sizex - tmpx;
if (szx >= MINSZX)
{
pds = OFS_AllocHdl();
if (pds != NULL)
{
pds->x = tmpx;
pds->y = pallochdl->y;
pds->sizex = szx;
pds->sizey = pallochdl->sizey;
OFS_InsertInFreeQ(ppdev, pds);
pallochdl->sizex -= szx;
}
}
#endif
pallochdl->alignflag = alignflag;
OFS_InsertInUsedQ(ppdev, pallochdl);
// Set Find flag to indicate a free block is found
findflg = TRUE;
}
else
{
// Free block not found, try to discard any discardable memory
// to satisfy the request
if (!OFS_DiscardMem(ppdev, reqszx, reqszy))
{
DISPDBG((DISPLVL, "AllocOffScnMem failed\n"));
// Allocation fail not enough memory
break;
};
}; // endif pallochdl != NULL
}; // endwhile
// Release the Mutex
#ifdef WINNT_VER40
EngReleaseSemaphore(ppdev->MMhsem);
#else
ReleaseMutex(ppdev->MutexHdl);
#endif
DISPDBG((DISPLVL, "AllocOffScnMem Completed\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
if (pallochdl)
{
DISPDBG((DISPLVL,
"AllocOffScnMem: from (x=%d,y=%d) to (x=%d,y=%d).\n",
pallochdl->x,
pallochdl->y,
(pallochdl->x + pallochdl->sizex),
(pallochdl->y + pallochdl->sizey) ));
}
return(pallochdl);
} // AllocOffScnMem()
/****************************************************************************
* FUNCTION NAME: FreeOffScnMem()
*
* DESCRIPTION: Free the allocated offscreen memory.
*
* Input: Pointer to the OFMHDL structure.
*
* Output: TRUE = Ok,
* FALSE = failed.
****************************************************************************/
BOOL FreeOffScnMem(PPDEV ppdev,
OFMHDL *hdl)
{
OFMHDL *pds;
BOOL fndflg;
DISPDBG((DISPLVL, "FreeOffScnMem\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
// if ((!ppdev->OFM_init) || (ppdev == NULL) || (hdl == NULL))
if (ppdev == NULL)
return (FALSE);
#if CLEAR_WHEN_FREE
REQUIRE(7);
LL16(grBLTDEF, 0x1101); // solid color fill
LL16(grDRAWDEF, 0x00FF); // whiteness
LL_OP0(hdl->x, hdl->y);
LL_BLTEXT( (hdl->sizex/ppdev->iBytesPerPixel), hdl->sizey );
#endif
// Wait for Mutex is released
#ifdef WINNT_VER40
EngAcquireSemaphore(ppdev->MMhsem);
#else
WaitForSingleObject(ppdev->MutexHdl, INFINITE);
#endif
// Validate the release block
fndflg = FALSE;
pds = ppdev->OFM_UsedQ;
while (pds != 0)
{
if ((hdl == pds) && (pds->flag == IN_USE))
{
fndflg = TRUE;
break;
};
// Next free block
pds = pds->nexthdl;
}; // end while
// Return if it is an invalid handle
if (!fndflg)
return (FALSE);
DISPDBG((DISPLVL,
"FreeOffScnMem: from (x=%d,y=%d) to (x=%d,y=%d).\n",
hdl->x,
hdl->y,
(hdl->x + hdl->sizex),
(hdl->y + hdl->sizey) ));
// Remove the block from the Used queue
OFS_RemoveFrmUsedQ(ppdev, hdl);
// Unfragment the memory
OFS_PackMem(ppdev, hdl);
// Insert the block into the Free queue
OFS_InsertInFreeQ(ppdev, hdl);
// Release the Mutex
#ifdef WINNT_VER40
EngReleaseSemaphore(ppdev->MMhsem);
#else
ReleaseMutex(ppdev->MutexHdl);
#endif
DISPDBG((DISPLVL, "FreeOffScnMem Completed\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
return (TRUE);
} // FreeOffScnMem()
/****************************************************************************
* FUNCTION NAME: CloseOffScnMem()
*
* DESCRIPTION: Close the offscreen memory manager. This function
* will release all allocated offscreen memories and the
* memories used by the Offscreen manager back to Windows.
****************************************************************************/
void CloseOffScnMem(PPDEV ppdev)
{
OFMHDL *pds;
OFMHDL *nxtpds;
DISPDBG((DISPLVL, "CloseOffScnMem\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
// If invalid arguments, return NULL
if ((!ppdev->OFM_init) || (ppdev == NULL))
return;
// Wait for Mutex is released
#ifdef WINNT_VER40
EngAcquireSemaphore(ppdev->MMhsem);
#else
WaitForSingleObject(ppdev->MutexHdl, INFINITE);
#endif
pds = ppdev->OFM_UsedQ;
while (pds != NULL)
{
nxtpds = pds->nexthdl;
MEMORY_FREE(pds);
pds = nxtpds;
};
pds = ppdev->OFM_FreeQ;
while (pds != NULL)
{
nxtpds = pds->nexthdl;
MEMORY_FREE(pds);
pds = nxtpds;
};
ppdev->OFM_UsedQ = NULL;
ppdev->OFM_FreeQ = NULL;
ppdev->OFM_SubFreeQ1 = NULL;
ppdev->OFM_SubFreeQ2 = NULL;
ppdev->DDOffScnMemQ = NULL;
ppdev->OFM_init = FALSE;
// Release the Mutex
#ifdef WINNT_VER40
EngReleaseSemaphore(ppdev->MMhsem);
#else
ReleaseMutex(ppdev->MutexHdl);
#endif
// Close the Mutex
#ifdef WINNT_VER40
EngDeleteSemaphore(ppdev->MMhsem);
#else
CloseHandle(ppdev->MutexHdl);
#endif
DISPDBG((DISPLVL, "CloseOffScnMem Completed\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
} // CloseOffScnMem()
/****************************************************************************
* FUNCTION NAME: ConvertToVideoBufferAddr()
*
* DESCRIPTION: Convert the X, Y rectange cordinate into Linear address
* in video buffer.
*
* Input: Pointer to the OFMHDL structure.
*
* Output: 32-bits Linear address pointer.
****************************************************************************/
PVOID ConvertToVideoBufferAddr(PPDEV ppdev, POFMHDL psurf)
{
ULONG retaddr;
DISPDBG((DISPLVL, "ConvertToVideoBufferAddr\n"));
// If invalid arguments, return NULL
//v-normmi
//if ((!ppdev->OFM_init) || (ppdev == NULL) || (psurf == NULL))
if (( ppdev == NULL) || (!ppdev->OFM_init) || (psurf == NULL))
return (NULL);
// Wait for Mutex is released
#ifdef WINNT_VER40
EngAcquireSemaphore(ppdev->MMhsem);
#else
WaitForSingleObject(ppdev->MutexHdl, INFINITE);
#endif
// Calculate the linear address from the X & Y coordinate
retaddr = ((ULONG) (psurf->x + (ppdev->lDeltaScreen * psurf->y))) +
((ULONG) ppdev->pjScreen);
DISPDBG((DISPLVL, "ConvertToVideoBufferAddr Completed\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
// Release the Mutex
#ifdef WINNT_VER40
EngReleaseSemaphore(ppdev->MMhsem);
#else
ReleaseMutex(ppdev->MutexHdl);
#endif
return ((PVOID)retaddr);
} // ConvertToVideoBufAddr()
/****************************************************************************
* FUNCTION NAME: OFS_AllocHdl()
*
* DESCRIPTION: Alocate offscreen memoru handler from the windows heap.
*
* Input: None
*
* Output: Pointer to OFMHDL structre
****************************************************************************/
POFMHDL OFS_AllocHdl()
{
OFMHDL *pds;
#ifdef WINNT_VER40
if ((pds = (POFMHDL) MEM_ALLOC (FL_ZERO_MEMORY, sizeof(OFMHDL), ALLOC_TAG)) != NULL)
#else
if ((pds = (POFMHDL) MEM_ALLOC (LPTR, sizeof(OFMHDL))) != NULL)
#endif
{
pds->x = 0;
pds->y = 0;
pds->aligned_x = 0;
pds->aligned_y = 0;
pds->sizex = 0;
pds->sizey = 0;
pds->alignflag = 0;
pds->flag = 0;
pds->pcallback = 0;
pds->prevhdl = 0;
pds->nexthdl = 0;
pds->subprvhdl = 0;
pds->subnxthdl = 0;
pds->prvFonthdl = 0;
pds->nxtFonthdl = 0;
pds->pdsurf = 0;
};
return (pds);
} // OFS_AllocHdl()
/****************************************************************************
* FUNCTION NAME: OFS_InitMem()
*
* DESCRIPTION: Initialize the offscreen memory.
*
* Input: Coordinate and size of the offscreen memory.
*
* Output: TRUE = Ok,
* FALSE = failed.
****************************************************************************/
BOOL OFS_InitMem(PPDEV ppdev,
PRECTL surf)
{
OFMHDL *pds;
// Allocate the control block handle from local windows memory pool
#ifdef WINNT_VER40
if ((pds = (POFMHDL) MEM_ALLOC(FL_ZERO_MEMORY, sizeof(OFMHDL), ALLOC_TAG)) == NULL)
#else
if ((pds = (POFMHDL) MEM_ALLOC(LPTR, sizeof(OFMHDL))) == NULL)
#endif
return (FALSE);
// Wait for Mutex is released
#ifdef WINNT_VER40
EngAcquireSemaphore(ppdev->MMhsem);
#else
WaitForSingleObject(ppdev->MutexHdl, INFINITE);
#endif
// Insert the free memory block into the queue
pds->x = surf->left;
pds->y = surf->top;
pds->sizex = surf->right - surf->left;
pds->sizey = surf->bottom - surf->top;
OFS_InsertInFreeQ(ppdev, pds);
// Release the Mutex
#ifdef WINNT_VER40
EngReleaseSemaphore(ppdev->MMhsem);
#else
ReleaseMutex(ppdev->MutexHdl);
#endif
return (TRUE);
} // OFS_InitMem()
/****************************************************************************
* FUNCTION NAME: OFS_FindBestFitFreeBlock()
*
* DESCRIPTION: Find the best fit free block.
*
* Input: Request offscreen memory size (in bytes).
*
* Output: Pointer to the OFMHDL structure or.
* NULL means not enough memory for allocation.
****************************************************************************/
POFMHDL OFS_FindBestFitFreeBlock(PPDEV ppdev,
OFMHDL *pFreeQ,
PLONG preqszx,
PLONG preqszy,
ULONG alignflag)
{
OFMHDL *pds = pFreeQ;
LONG reqszx = *preqszx;
LONG reqszy = *preqszy;
OFMHDL *pbestfit_hdl = NULL;
LONG bestfitx = 0x7FFFFFF;
LONG bestfity = 0x7FFFFFF;
LONG bpp;
LONG tileszx = 0;
LONG tileszy = 0;
LONG maskx = 0;
LONG masky = 0;
BOOL Findit = FALSE;
ULONG bestfit_aligned_x, bestfit_aligned_y;
LONG bestfit_Reqszx, bestfit_Reqszy;
ULONG aligned_x, aligned_y;
LONG szx, szy;
LONG NewReqszx, NewReqszy;
BOOL adjxflg, adjyflg;
if (alignflag & MCD_Z_BUFFER_ALLOCATE)
{
// special memory region -> z buffer: always 16bit/pix
bpp = 2;
}
else if (alignflag & MCD_TEXTURE_ALLOCATE)
{
// special memory region -> texture map: depth varies and is coded in alignflag
bpp = (alignflag & MCD_TEXTURE_ALLOCATE) >> MCD_TEXTURE_ALLOC_SHIFT;
}
else
{
// normal memory region -> allocate at depth of frame buffer
bpp = ppdev->ulBitCount/8;
}
// Check the alignment flag and adjust the request size accordingly.
if (alignflag & EIGHT_BYTES_ALIGN)
{ // 8 bytes alignment.
tileszx = 8;
tileszy = 1;
maskx = tileszx - 0x1;
masky = 0;
}
else if (alignflag & PIXEL_AlIGN)
{
tileszx = bpp;
tileszy = 1;
maskx = tileszx - 0x1;
masky = 0;
if (bpp == 3)
{
maskx += 1;
masky += 1;
};
}
else if (alignflag & (MCD_DRAW_BUFFER_ALLOCATE|MCD_Z_BUFFER_ALLOCATE|MCD_TEXTURE_ALLOCATE))
{
// Determine tile size
if (alignflag & MCD_DRAW_BUFFER_ALLOCATE)
tileszx = 64; // rgb buffer on 64 byte boundary (z always at x=0, so tile doesn't matter)
else
tileszx = 32; // texture on 32 byte boundary
if (alignflag & MCD_TEXTURE_ALLOCATE)
tileszy = 16; // textures must be on 16 scanline boundary
else
tileszy = 32; // z,backbuf must be on 32 scanline boundary
maskx = tileszx - 1;
masky = tileszy - 1;
}
else
{
// Determine tile size
tileszx = ppdev->lTileSize;
tileszy = (LONG) 2048/ppdev->lTileSize;
maskx = tileszx - 1;
masky = tileszy - 1;
};
// Search for the best fit block for the request
while (pds != NULL)
{
if (pds->flag == FREE)
{
szx = pds->sizex;
szy = pds->sizey;
// MCD z buffer, and possibly color buffer need to start at x=0
if ((szx >= reqszx) && (szy >= reqszy) && (!(alignflag & MCD_NO_X_OFFSET) || (pds->x==0)))
{
// If yes, calculate the aligned rectange starting positions
aligned_x = pds->x;
aligned_y = pds->y;
adjxflg = FALSE;
adjyflg = FALSE;
if (alignflag & PIXEL_AlIGN)
{
if ((pds->x % bpp) != 0)
adjxflg = TRUE;
if ((pds->y % bpp) != 0)
adjyflg = TRUE;
}
else
{
if ((!(alignflag & NO_X_TILE_AlIGN)) && ((pds->x % tileszx) != 0))
adjxflg = TRUE;
if ((!(alignflag & NO_Y_TILE_AlIGN)) && ((pds->y % tileszy) != 0))
adjyflg = TRUE;
};
if (adjxflg)
aligned_x = (pds->x & (~maskx)) + tileszx;
if (adjyflg)
aligned_y = (pds->y & (~masky)) + tileszy;
// Adjust the request size again to fit the required alignment
NewReqszx = reqszx + (aligned_x - pds->x);
NewReqszy = reqszy + (aligned_y - pds->y);
// Check the allocate block is large enough to hold the adjusted
// request size
if ((szx >= NewReqszx) && (szy >= NewReqszy))
{
if ((szx == NewReqszx) && (szy == NewReqszy))
{
Findit = TRUE;
bestfit_Reqszx = NewReqszx;
bestfit_Reqszy = NewReqszy;
bestfit_aligned_x = aligned_x;
bestfit_aligned_y = aligned_y;
pbestfit_hdl = pds;
}
else if ((bestfitx > szx) || (bestfity > szy))
{
bestfit_Reqszx = NewReqszx;
bestfit_Reqszy = NewReqszy;
bestfit_aligned_x = aligned_x;
bestfit_aligned_y = aligned_y;
bestfitx = szx;
bestfity = szy;
pbestfit_hdl = pds;
}; // if ((bestfitx > szx) || (bestfity > szy))
}; // if ((szx >= NewReqszx) && (szy >= NewReqszy))
}; // if ((szx >= reqszx) && (szy >= reqszy))
}; // if (pds->flag == FREE)
// Next free block
if (Findit)
pds = NULL;
else
pds = pds->subnxthdl;
} /* end while */
if (pbestfit_hdl != NULL)
{
*preqszx = bestfit_Reqszx;
*preqszy = bestfit_Reqszy;
pbestfit_hdl->aligned_x = bestfit_aligned_x;
pbestfit_hdl->aligned_y = bestfit_aligned_y;
};
return(pbestfit_hdl);
} // OFS_FindBestFitFreeBlock()
/****************************************************************************
* FUNCTION NAME: OFS_PackMem()
*
* DESCRIPTION: Unfragment the memory.
* This routine combines current release memory block
* with the adjacent free blocks of same X or Y dimension into
* one big free block.
****************************************************************************/
void OFS_PackMem(PPDEV ppdev,
OFMHDL *hdl)
{
BOOL cmbflg;
OFMHDL *pds;
ULONG pdsxdim, pdsydim;
pds = ppdev->OFM_FreeQ;
while (pds != NULL)
{
// Check for any free block (aliasing in either X or Y direction)
// before or after the current release block.
// If yes, combine the two into one big free block
pdsxdim = pds->x + pds->sizex;
pdsydim = pds->y + pds->sizey;
cmbflg = FALSE;
// Check for X-axis
if ((hdl->x == pds->x) && ((hdl->x + hdl->sizex) == pdsxdim))
{
if ((hdl->y == pdsydim) || (hdl->y == (pds->y - hdl->sizey)))
{
cmbflg = TRUE;
hdl->sizey += pds->sizey;
if (hdl->y == pdsydim)
hdl->y = pds->y;
};
};
// Check for Y-axis
if ((hdl->y == pds->y) && ((hdl->y + hdl->sizey) == pdsydim))
{
if ((hdl->x == pdsxdim) || (hdl->x == (pds->x - hdl->sizex)))
{
cmbflg = TRUE;
hdl->sizex += pds->sizex;
if (hdl->x == pdsxdim)
hdl->x = pds->x;
};
};
if (cmbflg)
{
OFS_RemoveFrmFreeQ(ppdev, pds);
// Release control block to Windows
MEMORY_FREE(pds);
// Restart the unfragment memory processing
pds = ppdev->OFM_FreeQ;
}
else
{
// Next free block
pds = pds->nexthdl;
};
}; // end while
} // OFS_PackMem
/****************************************************************************
* FUNCTION NAME: OFS_InsertInFreeQ()
*
* DESCRIPTION: Insert the handle into the Free queue.
*
* Input: Pointer to the OFMHDL structure.
*
* Output: None
****************************************************************************/
void OFS_InsertInFreeQ(PPDEV ppdev,
OFMHDL *hdl)
{
hdl->flag = FREE;
hdl->prevhdl = NULL;
hdl->subprvhdl = NULL;
hdl->aligned_x = 0;
hdl->aligned_y = 0;
hdl->alignflag = 0;
hdl->pcallback = NULL;
// Fix for PDR9385 - added by Mark Einkauf
// if pdsurf non-zero, when this block reused later, various DIB functions can misbehave
// Exact scenario in 9385 was...
// first app exit:
// DrvDisableDirectDraw freed all OFM blocks (leaving pdsurf field non-0 in some cases)
// next app startup:
// DrvGetDirectDrawInfo, calls...
// DDOffScnMemAlloc
// - loops through all OFM_UsedQ blocks, searching for
// off screen bit maps it can convert to DIB (and then free the offscreen memory)
// - Finds UsedQ block with non-zero pdsurf, pointing to non-existent pdsurf,
// which then had non-zero pofm field, causing it to appear as a valid
// off-screen bitmap
// - does memcpy with garbage x,y,sizex,sizey, wreaking havoc on system memory
// in a random sort of way
hdl->pdsurf = NULL;
// Insert into the SubFreeQs
if (hdl->sizey < MEMSZY)
{
if (ppdev->OFM_SubFreeQ1 == NULL)
{
hdl->subnxthdl = NULL;
ppdev->OFM_SubFreeQ1 = hdl;
}
else
{
ppdev->OFM_SubFreeQ1->subprvhdl = hdl;
hdl->subnxthdl = ppdev->OFM_SubFreeQ1;
ppdev->OFM_SubFreeQ1 = hdl;
};
}
else
{
if (ppdev->OFM_SubFreeQ2 == NULL)
{
hdl->subnxthdl = NULL;
ppdev->OFM_SubFreeQ2 = hdl;
}
else
{
ppdev->OFM_SubFreeQ2->subprvhdl = hdl;
hdl->subnxthdl = ppdev->OFM_SubFreeQ2;
ppdev->OFM_SubFreeQ2 = hdl;
};
};
// Insert into the Main FreeQ
if (ppdev->OFM_FreeQ == NULL)
{
hdl->nexthdl = NULL;
ppdev->OFM_FreeQ = hdl;
}
else
{
ppdev->OFM_FreeQ->prevhdl = hdl;
hdl->nexthdl = ppdev->OFM_FreeQ;
ppdev->OFM_FreeQ = hdl;
};
} // OFS_InsertInFreeQ()
/****************************************************************************
* FUNCTION NAME: OFS_RemoveFrmFreeQ()
*
* DESCRIPTION: Remove the handle from the Free queue.
****************************************************************************/
void OFS_RemoveFrmFreeQ(PPDEV ppdev,
OFMHDL *hdl)
{
OFMHDL *prvpds, *nxtpds;
OFMHDL *subprvpds, *subnxtpds;
hdl->flag = UNKNOWN;
prvpds = hdl->prevhdl;
nxtpds = hdl->nexthdl;
subprvpds = hdl->subprvhdl;
subnxtpds = hdl->subnxthdl;
// Remove from the SubFreeQs
if (hdl->sizey < MEMSZY)
{
if (hdl == ppdev->OFM_SubFreeQ1)
{
ppdev->OFM_SubFreeQ1 = subnxtpds;
if (subnxtpds != 0)
subnxtpds->subprvhdl = NULL;
}
else
{
if (subnxtpds != NULL)
subnxtpds->subprvhdl = subprvpds;
if (subprvpds != NULL)
subprvpds->subnxthdl = subnxtpds;
};
}
else
{
if (hdl == ppdev->OFM_SubFreeQ2)
{
ppdev->OFM_SubFreeQ2 = subnxtpds;
if (subnxtpds != 0)
subnxtpds->subprvhdl = NULL;
}
else
{
if (subnxtpds != NULL)
subnxtpds->subprvhdl = subprvpds;
if (subprvpds != NULL)
subprvpds->subnxthdl = subnxtpds;
};
};
// Remove from the Main FreeQ
if (hdl == ppdev->OFM_FreeQ)
{
ppdev->OFM_FreeQ = nxtpds;
if (nxtpds != 0)
nxtpds->prevhdl = NULL;
}
else
{
if (nxtpds != NULL)
nxtpds->prevhdl = prvpds;
if (prvpds != NULL)
prvpds->nexthdl = nxtpds;
};
} // OFS_RemoveFrmFreeQ
/****************************************************************************
* FUNCTION NAME: OFS_InsertInUsedQ()
*
* DESCRIPTION: Insert the handle into the Used queue.
****************************************************************************/
void OFS_InsertInUsedQ(PPDEV ppdev,
OFMHDL *hdl)
{
hdl->flag = IN_USE;
hdl->prevhdl = NULL;
if (ppdev->OFM_UsedQ == NULL)
{
hdl->nexthdl = NULL;
ppdev->OFM_UsedQ = hdl;
}
else
{
ppdev->OFM_UsedQ->prevhdl = hdl;
hdl->nexthdl = ppdev->OFM_UsedQ;
ppdev->OFM_UsedQ = hdl;
};
} // OFS_InsertInUsedQ()
/****************************************************************************
* FUNCTION NAME: OFS_RemoveFrmUsedQ()
*
* DESCRIPTION: Remove the handle from the Used queue.
****************************************************************************/
void OFS_RemoveFrmUsedQ(PPDEV ppdev,
OFMHDL *hdl)
{
OFMHDL *prvpds, *nxtpds;
hdl->flag = UNKNOWN;
prvpds = hdl->prevhdl;
nxtpds = hdl->nexthdl;
if (hdl == ppdev->OFM_UsedQ)
{
ppdev->OFM_UsedQ = nxtpds;
if (nxtpds != 0)
nxtpds->prevhdl = NULL;
}
else
{
if (nxtpds != NULL)
nxtpds->prevhdl = prvpds;
if (prvpds != NULL)
prvpds->nexthdl = nxtpds;
};
} // OFS_RemoveFrmUsedQ()
/****************************************************************************
* FUNCTION NAME: OFS_DiscardMem()
*
* DESCRIPTION: This routine search Used Queue to find any discardable
* allocated block. Releases those blocks to satisfy
* the current request.
*
* Input: Request offscreen memory size (in bytes).
*
* Output: TRUE: Find a free block.
* FALSE: No free block available.
****************************************************************************/
BOOL OFS_DiscardMem(PPDEV ppdev,
LONG reqszx,
LONG reqszy)
{
OFMHDL *hdl, *pds;
hdl = ppdev->OFM_UsedQ;
while (hdl != NULL)
{
if ((hdl->alignflag & DISCARDABLE_FLAG) != 0)
{
// Save the handle
pds = hdl;
// Get next free block handle
hdl = hdl->nexthdl;
// Call the callback function
if (pds->pcallback != NULL)
pds->pcallback();
// Remove this discardable block from the Used queue
OFS_RemoveFrmUsedQ(ppdev, pds);
// Unfragment the memory
OFS_PackMem(ppdev, pds);
// Insert the block into the Free queue
OFS_InsertInFreeQ(ppdev, pds);
// Return TRUE, if the combined block is satisfy the request.
// Otherwise continues search for next discardable block.
if ((pds->sizex >= reqszx) && (pds->sizey >= reqszy))
return TRUE;
}
else
{
// Next free block
hdl = hdl->nexthdl;
}; // endif ((hdl->alignflag & DISCARDABLE_FLAG) != 0)
}; // endwhile (hdl != NULL)
// Return FALSE, no more discardable block to release and still
// no free block large enough for the request.
return FALSE;
} // OFS_DiscardMem
#else /* MEMMGR */
/******************************************************************************\
* *
* N E W M E M O R Y M A N A G E R *
* *
\******************************************************************************/
#ifdef WINNT_VER40
#define CREATE_MUTEX(ppdev) ppdev->MMhsem = EngCreateSemaphore()
#define DELETE_MUTEX(ppdev) EngDeleteSemaphore(ppdev->MMhsem)
#define BEGIN_MUTEX(ppdev) EngAcquireSemaphore(ppdev->MMhsem);
#define END_MUTEX(ppdev) EngReleaseSemaphore(ppdev->MMhsem)
#else
#define CREATE_MUTEX(ppdev) ppdev->MutexHdl = CreateMutex(NULL, FALSE, NULL)
#define DELETE_MUTEX(ppdev) CloseHandle(ppdev->MutexHdl)
#define BEGIN_MUTEX(ppdev) WaitForSingleObject(ppdev->MutexHdl, INFINITE);
#define END_MUTEX(ppdev) ReleaseMutex(ppdev->MutexHdl)
#endif
/******************************************************************************\
* Function: HostifyBitmap
*
* Purpose: Move a device bitmap from off-screen memory to host memory.
*
* On entry: pdm Pointer to node to hostify.
*
* Returns: TRUE if successful, FALSE if there is an error.
\******************************************************************************/
BOOL HostifyBitmap(PDEVMEM pdm)
{
if (pdm->ofm.pdsurf != NULL)
{
// Hostify the bitmap.
if (!bCreateDibFromScreen(pdm->ofm.pdsurf->ppdev, pdm->ofm.pdsurf))
{
// There was an error.
return FALSE;
}
}
return TRUE;
}
/******************************************************************************\
* Function: HostifyAllBitmaps
*
* Purpose: Move all device bitmaps from off-screen memory to host memory.
*
* On entry: ppdev Pointer to physical device.
*
* Returns: Nothing.
\******************************************************************************/
void HostifyAllBitmaps(PPDEV ppdev)
{
PDEVMEM pdm, pdmNext;
// Walk through all used nodes.
for (pdm = ppdev->mmMemMgr.pdmUsed; pdm != NULL; pdm = pdmNext)
{
// Save pointer to next node.
pdmNext = pdm->next;
// If this is a device bitmap, hostify it.
if (pdm->ofm.pdsurf != NULL)
{
if (bCreateDibFromScreen(ppdev, pdm->ofm.pdsurf))
{
// After successful hostification, free the node.
mmFree(&ppdev->mmMemMgr, pdm);
}
}
// If this is a SaveScreen bitmap, just remove it.
else if (pdm->ofm.alignflag & SAVESCREEN_FLAG)
{
mmFree(&ppdev->mmMemMgr, pdm);
}
}
}
/******************************************************************************\
* Function: CopyBitmap
*
* Purpose: Move a device bitmap in off-screen memory.
*
* On entry: pdmNew Pointer to new node for device bitmap.
* pdmOld Pointer to old node of device bitmap.
*
* Returns: Nothing.
\******************************************************************************/
void CopyBitmap(PDEVMEM pdmNew, PDEVMEM pdmOld)
{
PPDEV ppdev;
PDSURF pdsurf;
ULONG xSrc, xDest, xExt, cx;
BOOL fFirst = TRUE;
// Set the pointers to the device bitmap and physical device.
pdsurf = pdmOld->ofm.pdsurf;
ppdev = pdsurf->ppdev;
// Setup the values in the old NT structure.
pdmNew->ofm.x = pdmNew->ofm.aligned_x = pdmNew->cbAddr.pt.x;
pdmNew->ofm.y = pdmNew->ofm.aligned_y = pdmNew->cbAddr.pt.y;
pdmNew->ofm.sizex = pdmNew->cbSize.pt.x;
pdmNew->ofm.sizey = pdmNew->cbSize.pt.y;
// Copy the information from the old node.
pdmNew->ofm.alignflag = pdmOld->ofm.alignflag;
pdmNew->ofm.pcallback = pdmOld->ofm.pcallback;
pdmNew->ofm.pdsurf = pdsurf;
// Update the device bitmap structure.
pdsurf->pofm = (POFMHDL) pdmNew;
pdsurf->ptl.x = pdmNew->cbAddr.pt.x / ppdev->iBytesPerPixel;
pdsurf->ptl.y = pdmNew->cbAddr.pt.y;
pdsurf->packedXY = (pdsurf->ptl.y << 16) | pdsurf->ptl.x;
// Copy the device bitmap to a new location.
xSrc = pdmOld->cbAddr.pt.x;
xDest = pdmNew->cbAddr.pt.x;
xExt = pdmNew->cbSize.pt.x;
// We do striping.
while (xExt > 0)
{
cx = min( xExt, ppdev->lTileSize - (xSrc % ppdev->lTileSize) );
cx = min( cx, ppdev->lTileSize - (xDest % ppdev->lTileSize) );
if (fFirst)
{
fFirst = FALSE;
REQUIRE(9);
LL_DRAWBLTDEF(0x101000CC, 0);
LL_OP1_MONO(xSrc, pdmOld->cbAddr.pt.y);
LL_OP0_MONO(xDest, pdmNew->cbAddr.pt.y);
LL_MBLTEXT(cx, pdmNew->cbSize.pt.y);
}
else
{
REQUIRE(4);
LL16(grOP1_opMRDRAM.PT.X, xSrc);
LL16(grOP0_opMRDRAM.PT.X, xDest);
LL16(grMBLTEXT_XEX.PT.X, cx);
}
xSrc += cx;
xDest += cx;
xExt -= cx;
}
}
/******************************************************************************\
* Function: InitOffScnMem
*
* Purpose: Initialize the off-screen memory manager.
*
* On entry: ppdev Pointer to physical device.
*
* Returns: TRUE if successful, FALSE if there is an error.
\******************************************************************************/
BOOL InitOffScnMem(PPDEV ppdev)
{
UINT Interleave, WidthInTiles, ExtraWidth, ExtraHeight;
ULONG BytesInMainRect, BytesInExtraRect;
GXRECT rect;
SIZEL size;
GXPOINT align;
PDEVMEM pdm;
DISPDBG((DISPLVL, "InitOffScnMem\n"));
// Already initialized?
if (ppdev == NULL || ppdev->OFM_init == TRUE)
{
DISPDBG((DISPLVL, "InitOffScnMem: already initialized\n"));
return FALSE;
}
// Create the semaphore.
if ((CREATE_MUTEX(ppdev)) == NULL)
{
DISPDBG((DISPLVL, "InitOffScnMem: CREATE_MUTEX failed\n"));
return FALSE;
}
// Setup the maximum width for a device bitmap for which we will move and
// hostify other devcie bitmaps.
if ( (ppdev->iBytesPerPixel == 3) || (ppdev->iBytesPerPixel == 4) )
{
ppdev->must_have_width = 0;
}
else
{
ppdev->must_have_width = ppdev->cxScreen * 98 / 100;
}
// Calculate memory stuff.
Interleave = 1 << ((LLDR_SZ(grTILE_CTRL) & 0xC0) >> 6);
WidthInTiles = ppdev->lDeltaScreen / ppdev->lTileSize;
BytesInExtraRect = ppdev->lTotalMem % (WidthInTiles * 2048 * Interleave);
BytesInMainRect = ppdev->lTotalMem - BytesInExtraRect;
//
// BTN - For some reason, this extra rectange cause the WHQL PC97
// Rand Create/Release 100x test fails on 1600x1200x16 and 1600x1200x8
//
if ((ppdev->cxScreen == 1600) &&
(ppdev->cyScreen == 1200) &&
((ppdev->iBytesPerPixel == 2) || (ppdev->iBytesPerPixel == 1)))
BytesInExtraRect = 0;
//
// I have removed the extra rectangle at 1280x1024x8. Somehow it messes up
// FoxBear.
//
if ( (ppdev->cxScreen == 1280)
&& (ppdev->cyScreen == 1024)
&& (ppdev->iBytesPerPixel == 1)
)
{
BytesInExtraRect = 0;
}
// Setup the main rectangle.
rect.left = 0;
rect.top = 0;
rect.right = ppdev->lDeltaScreen;
rect.bottom = BytesInMainRect / ppdev->lDeltaScreen;
// Setup the extra rectangle.
if (BytesInExtraRect && ppdev->lTotalMem < 8 * 1024 * 1024)
{
ExtraHeight = Interleave * 2048 / ppdev->lTileSize;
ExtraWidth = BytesInExtraRect / ExtraHeight;
}
else
{
ExtraWidth = ExtraHeight = 0;
}
// v-normmi effective height of direct frame buffer access region
// not all of it is populated with memory
ppdev->cyMemoryReal = rect.bottom + ExtraHeight;
BEGIN_MUTEX(ppdev)
{
// Initialize the mmemory manager core.
ppdev->mmMemMgr.mmTileWidth = ppdev->lTileSize;
ppdev->mmMemMgr.mmHeapWidth = rect.right;
ppdev->mmMemMgr.mmHeapHeight = rect.bottom + ExtraHeight;
mmInit(&ppdev->mmMemMgr);
// Initialize flags and queues.
ppdev->OFM_init = TRUE;
ppdev->bDirectDrawInUse = FALSE;
ppdev->DDOffScnMemQ = FALSE;
ppdev->DirectDrawHandle = NULL;
}
END_MUTEX(ppdev);
// Add the main rectangle to the heap.
if (!mmAddRectToList(&ppdev->mmMemMgr, &ppdev->mmMemMgr.pdmHeap, &rect,
FALSE))
{
DISPDBG((DISPLVL, "InitOffScnMem: mmAddRectToList failed\n"));
return FALSE;
}
DISPDBG((DISPLVL, "InitOffScnMem: main rectangle from (%d,%d) to (%d,%d)\n",
rect.left, rect.top, rect.right, rect.bottom));
// Add the extra rectangle to the heap.
if (ExtraWidth > 0 && ExtraHeight > 0)
{
rect.left = 0;
rect.top = rect.bottom;
rect.right = ExtraWidth;
rect.bottom += ExtraHeight;
if (mmAddRectToList(&ppdev->mmMemMgr, &ppdev->mmMemMgr.pdmHeap, &rect,
FALSE))
{
DISPDBG((DISPLVL, "InitOffScnMem: "
"extra rectangle from (%d,%d) to (%d,%d)\n", rect.left,
rect.top, rect.right, rect.bottom));
}
}
// Allocate a node for the screen.
size.cx = ppdev->cxScreen;
size.cy = ppdev->cyScreen;
ppdev->ScrnHandle = AllocOffScnMem(ppdev, &size, SCREEN_ALLOCATE, NULL);
if (ppdev->ScrnHandle == NULL)
{
DISPDBG((DISPLVL, "InitOffScnMem: AllocOffScnMem failed\n"));
return FALSE;
}
// Determine if bitmap filter should be turned on.
align.pt.x = align.pt.y = 1;
pdm = mmAllocLargest(&ppdev->mmMemMgr, align);
if (pdm == NULL)
{
DISPDBG((DISPLVL, "InitOffScnMem: mmAllocLargest faled\n"));
return FALSE;
}
size.cx = pdm->cbSize.pt.x / ppdev->iBytesPerPixel;
size.cy = pdm->cbSize.pt.y;
mmFree(&ppdev->mmMemMgr, pdm);
if ((ULONG) size.cx < ppdev->cxScreen || (ULONG) size.cy < ppdev->cyScreen)
{
ppdev->fBitmapFilter = TRUE;
ppdev->szlBitmapMin.cx = 64;
ppdev->szlBitmapMin.cy = 64;
ppdev->szlBitmapMax.cx = size.cx;
ppdev->szlBitmapMax.cy = size.cy;
}
else
{
ppdev->fBitmapFilter = FALSE;
}
// Return success.
DISPDBG((DISPLVL, "InitOffScnMem: completed\n"));
return TRUE;
}
/******************************************************************************\
* Function: CloseOffScnMem
*
* Purpose: Free all memory allocated for the off-screen memory manager.
*
* On entry: ppdev Pointer to physical device.
*
* Returns: Nothing.
\******************************************************************************/
void CloseOffScnMem(PPDEV ppdev)
{
PHANDLES ph, phNext;
DISPDBG((DISPLVL, "CloseOffScnMem\n"));
// Already closed?
if (ppdev == NULL || !ppdev->OFM_init)
{
DISPDBG((DISPLVL, "CloseOffScnMem: already closed\n"));
return;
}
BEGIN_MUTEX(ppdev)
{
// Delete all allocated arrays.
for (ph = ppdev->mmMemMgr.phArray; ph != NULL; ph = phNext)
{
phNext = ph->pNext;
MEMORY_FREE(ph);
}
ppdev->mmMemMgr.phArray = NULL;
ppdev->mmMemMgr.pdmUsed = NULL;
ppdev->mmMemMgr.pdmFree = NULL;
ppdev->mmMemMgr.pdmHeap = NULL;
ppdev->mmMemMgr.pdmHandles = NULL;
ppdev->OFM_init = FALSE;
}
END_MUTEX(ppdev);
// Delete the semaphore.
DELETE_MUTEX(ppdev);
DISPDBG((DISPLVL, "CloseOffScnMem: completed\n"));
}
/******************************************************************************\
* Function: AllocOffScnMem
*
* Purpose: Allocate a node in off-screen memory.
*
* On entry: ppdev Pointer to physical device.
* psize Pointer to the size of the requested node. The size
* is specified in pixels or bytes, depending on the
* alignment flags.
* alignflag Alignment flags.
* pcallback Pointer to callback routine if DISCARDABLE_FLAG is
* set.
*
* Returns: Pointer to the node if successful, or NULL if there is not
* enough memory to allocate the node.
\******************************************************************************/
POFMHDL AllocOffScnMem(PPDEV ppdev, PSIZEL psize, ULONG alignflag,
POFM_CALLBACK pcallback)
{
GXPOINT size, align;
UINT bpp;
PDEVMEM pdm;
DISPDBG((DISPLVL, "AllocOffScnMem\n"));
// If the memory manager active?
if (ppdev == NULL || !ppdev->OFM_init || psize == NULL)
{
DISPDBG((DISPLVL, "AllocOffScnMem: not initialized\n"));
return NULL;
}
#ifndef ALLOC_IN_CREATESURFACE
// Return in case DirectDraw is active.
if (pdpev->bDirectDrawInUse)
{
DISPDBG((DISPLVL, "AllocOffScnMem: DirectDraw is active\n"));
return NULL;
}
#endif
// Z-buffer alignment.
if (alignflag & MCD_Z_BUFFER_ALLOCATE)
{
bpp = 2;
align.pt.x = 32;
align.pt.y = 32;
}
// Texture alignment.
else if (alignflag & MCD_TEXTURE_ALLOCATE)
{
bpp = (alignflag & MCD_TEXTURE_ALLOCATE) >> MCD_TEXTURE_ALLOC_SHIFT;
align.pt.x = 32;
align.pt.y = 16;
}
// DirectDraw buffer alignment.
else if (alignflag & MCD_DRAW_BUFFER_ALLOCATE)
{
bpp = ppdev->iBytesPerPixel;
align.pt.x = 64;
align.pt.y = 32;
}
// 8 bytes alignment.
else if (alignflag & EIGHT_BYTES_ALIGN)
{
bpp = ppdev->iBytesPerPixel;
align.pt.x = 8;
align.pt.y = 1;
}
// Pixel alignment.
else if (alignflag & PIXEL_AlIGN)
{
bpp = ppdev->iBytesPerPixel;
align.pt.x = ppdev->iBytesPerPixel;
align.pt.y = 1;
}
// Screen alignment.
else if (alignflag & SCREEN_ALLOCATE)
{
bpp = ppdev->iBytesPerPixel;
align.pt.x = ppdev->lDeltaScreen;
align.pt.y = ppdev->cyMemory;
}
// Tile alignment.
else
{
bpp = 1;
align.pt.x = ppdev->lTileSize;
align.pt.y = 2048 / ppdev->lTileSize;
if (alignflag & NO_X_TILE_AlIGN)
{
align.pt.x = 1;
}
if (alignflag & NO_Y_TILE_AlIGN)
{
align.pt.y = 1;
}
}
// The Z-buffer needs to be allocated at x=0.
if (alignflag & MCD_NO_X_OFFSET)
{
align.pt.x = ppdev->lDeltaScreen;
}
#if TILE_ALIGNMENT
// If this is a call from DrvCreateDeviceBitmap, set tile alignment.
if (alignflag & MUST_HAVE)
{
align.pt.x |= 0x8000;
}
#endif
// Set the size of the node.
size.pt.x = psize->cx * bpp;
size.pt.y = psize->cy;
#if 1 // PDR#10526
// Immortal Klowns copies a few bytes too much to the screen if the size of
// a DirectDraw surface is not DWORD aligned. So for DirectDraw and pixel
// aligned allocations we align the size to DWORDs.
if (ppdev->bDirectDrawInUse && (alignflag & PIXEL_AlIGN))
{
size.pt.x = (size.pt.x + 3) & ~3;
}
#endif
BEGIN_MUTEX(ppdev)
{
// 1st pass, allocate the node.
pdm = mmAlloc(&ppdev->mmMemMgr, size, align);
if (pdm == NULL && (alignflag & MUST_HAVE))
{
// 2nd pass, move stuff away and allocate the node.
pdm = mmMove(&ppdev->mmMemMgr, size, align, CopyBitmap);
}
}
END_MUTEX(ppdev);
if (pdm == NULL)
{
// Oops, no room for the node.
DISPDBG((DISPLVL, "AllocOffScnMem: failed for (%dx%d)\n", size.pt.x,
size.pt.y));
return NULL;
}
// Setup the values in the old NT structure.
pdm->ofm.x = pdm->ofm.aligned_x = pdm->cbAddr.pt.x;
pdm->ofm.y = pdm->ofm.aligned_y = pdm->cbAddr.pt.y;
pdm->ofm.sizex = pdm->cbSize.pt.x;
pdm->ofm.sizey = pdm->cbSize.pt.y;
pdm->ofm.alignflag = alignflag;
pdm->ofm.pdsurf = NULL;
// Set the address of the callback function.
if (alignflag & DISCARDABLE_FLAG)
{
pdm->ofm.pcallback = pcallback;
}
else if (alignflag & MUST_HAVE)
{
// This is a device bitmap.
pdm->ofm.pcallback = (POFM_CALLBACK) HostifyBitmap;
}
else
{
// No callback function.
pdm->ofm.pcallback = NULL;
}
// Return node.
DISPDBG((DISPLVL, "AllocOffScnMem: completed from (%d,%d) to (%d,%d)\n",
pdm->cbAddr.pt.x, pdm->cbAddr.pt.y, pdm->cbAddr.pt.x +
pdm->cbSize.pt.x, pdm->cbAddr.pt.y + pdm->cbSize.pt.y));
return (POFMHDL) pdm;
}
/******************************************************************************\
* Function: FreeOffScnMem
*
* Purpose: Free a node allocated from off-screen memory.
*
* On entry: ppdev Pointer to physical device.
* hdl Handle of node to free.
*
* Returns: TRUE if successful, FALSE if there is an error.
\******************************************************************************/
BOOL FreeOffScnMem(PPDEV ppdev, POFMHDL hdl)
{
DISPDBG((DISPLVL, "FreeOffScnMem\n"));
// If the memory manager enabled?
if (ppdev == NULL || !ppdev->OFM_init || hdl == NULL)
{
DISPDBG((DISPLVL, "FreeOffScnMem: not initialized\n"));
return FALSE;
}
// Free the node.
DISPDBG((DISPLVL, "FreeOffScnMem: from (%d,%d) to (%d,%d)\n", hdl->x,
hdl->y, hdl->x + hdl->sizex, hdl->y + hdl->sizey));
mmFree(&ppdev->mmMemMgr, (PDEVMEM) hdl);
// Return success.
DISPDBG((DISPLVL, "FreeOffScnMem: completed\n"));
return TRUE;
}
/******************************************************************************\
* Function: ConvertToVideoBufferAddr
*
* Purpose: Convert the location of a node in off-screen memory to a linear
* address.
*
* On entry: ppdev Pointer to physical device.
* hdl Handle of node.
*
* Returns: Linear address of node.
\******************************************************************************/
PVOID ConvertToVideoBufferAddr(PPDEV ppdev, POFMHDL hdl)
{
PBYTE retaddr;
BEGIN_MUTEX(ppdev)
{
// Calculate the address.
retaddr = ppdev->pjScreen + hdl->x + hdl->y * ppdev->lDeltaScreen;
}
END_MUTEX(ppdev);
return (PVOID) retaddr;
}
/******************************************************************************\
* Function: DDOffScnMemAlloc
*
* Purpose: Free all non-essential memory to make room for DirectDraw.
*
* On entry: ppdev Pointer to physical device.
*
* Returns: Pointer to biggest node for DirectDraw or NULL if the memory
* manager handles DirectDraw surfaces.
\******************************************************************************/
POFMHDL DDOffScnMemAlloc(PPDEV ppdev)
{
PDEVMEM pdm;
GXPOINT align;
DISPDBG((DISPLVL, "DDOffScnMemAlloc\n"));
// Hostify all device bitmaps.
HostifyAllBitmaps(ppdev);
// SWAT3: Font cache release has moved to vAssertModeText.
vAssertModeText(ppdev, FALSE);
#ifdef ALLOC_IN_CREATESURFACE
// We handle DirectDraw surfaces ourselfs.
pdm = NULL;
#else
// Allocate the biggest chunk of memory for DirectDraw.
align.pt.x = align.pt.y = 1;
pdm = mmAllocLargest(&ppdev->mmMemMgr, align);
#endif
DISPDBG((DISPLVL, "DDOffScnMemAlloc: completed\n"));
return (POFMHDL) pdm;
}
/******************************************************************************\
* Function: DDOffScnMemRestore
*
* Purpose: Release the memory allocated by DirectDraw.
*
* On entry: ppdev Pointer to physical device.
*
* Returns: Nothing.
\******************************************************************************/
void DDOffScnMemRestore(PPDEV ppdev)
{
PDDOFM pdd, pddNext;
DISPDBG((DISPLVL, "DDOffScnMemRestore\n"));
// Release all DirectDraw nodes.
for (pdd = ppdev->DDOffScnMemQ; pdd != NULL; pdd = pddNext)
{
pddNext = pdd->nexthdl;
mmFree(&ppdev->mmMemMgr, (PDEVMEM) pdd->phdl);
MEMORY_FREE(pdd);
}
ppdev->DDOffScnMemQ = NULL;
// Release DirectDraw memory.
if (ppdev->DirectDrawHandle != NULL)
{
mmFree(&ppdev->mmMemMgr, (PDEVMEM) ppdev->DirectDrawHandle);
ppdev->DirectDrawHandle = NULL;
}
// Invalidate the entire brush cache now.
vInvalidateBrushCache(ppdev);
// Invalidate all cached fonts.
#if SWAT3
vAssertModeText(ppdev, TRUE);
#endif
ppdev->ulFontCount++;
DISPDBG((DISPLVL, "DDOffScnMemRestore: completed\n"));
}
/******************************************************************************\
* Function: FindHandle
*
* Purpose: Find a specific node int the used list.
*
* On entry: ppdev Pointer to physical device.
* hdl Handle of node to find.
*
* Returns: A pointer to the specified handle if it is found in the used
* list, otherwise NULL will be returned.
\******************************************************************************/
POFMHDL FindHandle(PPDEV ppdev, POFMHDL hdl)
{
PDEVMEM pdm;
// Walk through the used list.
for (pdm = ppdev->mmMemMgr.pdmUsed; pdm != NULL; pdm = pdm->next)
{
if ((POFMHDL) pdm == hdl)
{
// We have a match!
return hdl;
}
}
return NULL;
}
#endif /* MEMMGR */