|
|
/****************************************************************************
***************************************************************************** * * ****************************************** * * 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 */
|