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.
 
 
 
 
 
 

1992 lines
80 KiB

/******************************Module*Header*******************************\
*
* Module Name: Brush.c
* Author: Noel VanHook
* Purpose: Handle calls to DrvRealizeBrush
*
* Copyright (c) 1995 Cirrus Logic, Inc.
*
* $Log: X:/log/laguna/nt35/displays/cl546x/BRUSH.C $
*
* Rev 1.29 Mar 04 1998 15:11:18 frido
* Added new shadow macros.
*
* Rev 1.28 Feb 24 1998 13:19:16 frido
* Removed a few warning messages for NT 5.0.
*
* Rev 1.27 Nov 03 1997 12:51:52 frido
* Added REQUIRE macros.
*
* Rev 1.26 25 Aug 1997 16:01:22 FRIDO
* Removed resetting of brush unique ID counters in vInvalidateBrushCache.
*
* Rev 1.25 08 Aug 1997 15:33:16 FRIDO
* Changed brush cache width to bytes for new memory manager.
*
* Rev 1.24 06 Aug 1997 17:29:56 noelv
* Don't RIP on brush cache alloc failure. This failure is normal for modes
* without enough offscreen memory for a cache.
*
* Rev 1.23 09 Apr 1997 10:48:52 SueS
* Changed sw_test_flag to pointer_switch.
*
* Rev 1.22 08 Apr 1997 12:12:32 einkauf
*
* add SYNC_W_3D to coordinate MCD/2D HW access
*
* Rev 1.21 19 Feb 1997 13:06:20 noelv
* Added vInvalidateBrushCache()
*
* Rev 1.20 17 Dec 1996 16:51:00 SueS
* Added test for writing to log file based on cursor at (0,0).
*
* Rev 1.19 26 Nov 1996 10:18:22 SueS
* Changed WriteLogFile parameters for buffering. Added test for null
* pointer in logging function.
*
* Rev 1.18 13 Nov 1996 15:57:54 SueS
* Changed WriteFile calls to WriteLogFile.
*
* Rev 1.17 22 Aug 1996 18:14:18 noelv
* Frido bug fix release 8-22.
*
* Rev 1.6 22 Aug 1996 19:12:44 frido
* #1308 - Added extra checks for empty cache slots.
*
* Rev 1.5 18 Aug 1996 15:19:58 frido
* #nbr - Added brush translation.
*
* Rev 1.4 17 Aug 1996 14:03:10 frido
* Removed extraneous #include directives.
*
* Rev 1.3 17 Aug 1996 13:12:12 frido
* New release from Bellevue.
* #1244 - Fixed brush rotation for off-screen bitmaps.
*
* Rev 1.2 15 Aug 1996 12:26:40 frido
* Moved BRUSH_DBG_LEVEL down.
*
* Rev 1.1 15 Aug 1996 11:45:14 frido
* Added precompiled header.
*
* Rev 1.0 14 Aug 1996 17:16:16 frido
* Initial revision.
*
* Rev 1.14 25 Jul 1996 15:55:24 bennyn
*
* Modified to support DirectDraw
*
* Rev 1.13 04 Jun 1996 15:57:34 noelv
*
* Added debug code
*
* Rev 1.12 28 May 1996 15:11:14 noelv
* Updated data logging.
*
* Rev 1.11 16 May 1996 14:54:20 noelv
* Added logging code.
*
* Rev 1.10 11 Apr 1996 09:25:16 noelv
* Fided debug messages.
*
* Rev 1.9 10 Apr 1996 14:14:04 NOELV
*
* Frido release 27
*
* Rev 1.19 08 Apr 1996 16:45:56 frido
* Added SolidBrush cache.
* Added new check for 32-bpp brushes.
*
* Rev 1.18 01 Apr 1996 14:00:08 frido
* Added check for valid brush cache.
* Changed layout of brush cache.
*
* Rev 1.17 30 Mar 1996 22:16:02 frido
* Refined checking for invalid translation flags.
*
* Rev 1.16 27 Mar 1996 13:07:38 frido
* Added check for undocumented translation flags.
*
* Rev 1.15 25 Mar 1996 12:03:06 frido
* Changed #ifdef LOG_CALLS into #if LOG_CALLS.
*
* Rev 1.14 25 Mar 1996 11:50:16 frido
* Bellevue 102B03.
*
* Rev 1.5 20 Mar 1996 16:20:06 noelv
* 32 bpp color brushes are broken in the chip
*
* Rev 1.4 20 Mar 1996 16:09:32 noelv
*
* Updated data logging
*
* Rev 1.3 05 Mar 1996 11:57:38 noelv
* Frido version 19
*
* Rev 1.13 05 Mar 1996 00:56:30 frido
* Some changes here and there.
*
* Rev 1.12 04 Mar 1996 23:48:50 frido
* Removed bug in realization of dithered brush.
*
* Rev 1.11 04 Mar 1996 20:22:30 frido
* Removed bug in BLTDEF register with colored brushes.
*
* Rev 1.10 28 Feb 1996 22:37:42 frido
* Added Optimize.h.
*
* Rev 1.9 17 Feb 1996 21:45:28 frido
* Revamped brushing algorithmn.
*
* Rev 1.8 13 Feb 1996 16:51:18 frido
* Changed the layout of the PDEV structure.
* Changed the layout of all brush caches.
* Changed the number of brush caches.
*
* Rev 1.7 10 Feb 1996 21:44:32 frido
* Split monochrome and colored translation cache.
*
* Rev 1.6 08 Feb 1996 00:19:24 frido
* Optimized the entire brushing for non-intel CPU's.
* Removed DrvRealizeBrush for i386 since it is now in assembly.
*
* Rev 1.5 05 Feb 1996 17:35:32 frido
* Added translation cache.
*
* Rev 1.4 05 Feb 1996 11:34:02 frido
* Added support for 4-bpp brushes.
*
* Rev 1.3 03 Feb 1996 14:20:04 frido
* Use the compile switch "-Dfrido=0" to disable my extensions.
*
* Rev 1.2 20 Jan 1996 22:13:14 frido
* Added dither cache.
* Optimized loading of brush cache bits.
*
\**************************************************************************/
/*
We have two versions of DrvRealizeBrush, a 'C' version and an 'ASM' version.
These must be both be kept up to date. The ASM version is used for production
drivers. The C version is used for debugging, prototyping, data gathering and
anything else that requires rapid, non-performance-critical changes to the
driver.
Brushes:
=========
Here is a general feel for how brush information flows between NT and the
driver components.
NT calls DrvBitBlt() with a drawing request.
DrvBitBlt() determines it needs a brush and calls SetBrush().
SetBrush() determins the brush has not been realized yet and calls NT
(BRUSHOBJ_pvGetRbrush()).
NT calls DrvRealizeBrush().
DrvRealizeBrush() creates a BrushObject and returns it to NT.
NT returns brush object to SetBrush().
SetBrush calls CacheBrush() if the brush is not cached.
SetBrush() sets up pattern on chip.
SetBrush() returns DRAWDEF value to BitBlt.
There are 5 seperate brush caches maintained: A mono cache, a color cache, a
dither cache, a 4bpp cache, and a solid cache. We do not handle brushes with
masks. Some of the code for this is in place, but work was stopped on it.
Realizing Brushes:
==================
When we realize a brush we keep a bit of information about it.
ajPattern[0] = The bitmap that makes up the pattern.
nPatSize = The size of the bitmap.
iBitmapFormat = BMF_1BPP, BMF_4BPP, etc.
ulForeColor = For mono brushes.
ulBackColor = For mono brushes.
iType = Type of brush.
iUniq = Unique value for brush.
cache_slot = Where we cached it last time we used it. It may still be
there, or it may have been ejected from the cache since we
used it last.
cache_xy = The off-screen location of the brush bits.
cjMask = Offset to mask bits in ajPattern[].
The memory for the brush data structure is managed by the operating system.
When we realize a brush, we tell NT how much memory we need to hold our brush
data, and NT gives us a pointer. When NT discards the brush, it frees the
memory it gave us *without* notifing us first! This means we can't keep lists
of pointers to realized brushes and access them at our leisure, because they
may not exist anymore. This is a pain when caching brushes. It would be nice
if we could track cached/not-cached states in the brush itself, but we have no
way of notifing a brush that it has been uncached, because NT way have already
unrealized the brush.
The solution to this is to keep brush ID information in the cache. The realized
brush tracks where it is in the cache. The cache tracks which realized brush is
in each slot.
Caching brushes:
================
We allocate 3 128-byte wide rectangles, side by side. The
layout of this brush cache region is:
+----------------+----------------+----------------+
| | | MONOCHROME |
| COLOR | 4BPP +----------------+
| BRUSHES | BRUSHES | DITHER |
| | | BRUSHES |
| | +----------------+
| | | SOLID BRUSHES |
+----------------+----------------+----------------+
Mono brushes use 1 bit per pixel (1 byte per scan line, 8 bytes per brush) and
are stored 16 to a line. Replacement policy is round robin. We work out way
through the cache table entries, and when the cache is full, we go back to 0 and
start again.
The pdev holds a counter that increments every time we cache a brush. We MOD
this counter with the number of table entries to find the next place to put a
brush. When we store the brush, we store a unswizzled copy in the cache table
itself, and a swizzled copy in the cache. After storing the brush, we give it a
'serial number' which is stored in both the cache, and the realized brush. We
then copy the brushes X,Y address into the realized brush for easy access. So,
for index I in the cache, things look like this:
Realized Brush
--------------
cache_slot = I - tells us which cache table entry to use;
cache_xy - x,y address of brush in offscreen memory. Copied from cache
table.
iUniq - matches iUniq in CacheTable[I]
Cache Table [I]
---------------
xy - x,y address of brush in offscreen memory. Computed at init time.
ajPattern - brush bits.
iUniq - matches iUniq in RealizedBrush
Now, in the future, if we are given this brush again, we first check cache_slot
in the realized brush to see where we cached it last time we used it. Then we
compare iUniq values to see if our brush is *still* cached there.
Dither brushes use 1 byte per pixel (8 bytes per scan line, 64 bytes per brush)
and are stored 2 to a line.
4bpp brushes use 1 DWORD per pixel (32 bytes per scan line, 256 bytes per brush)
and use two lines per brush.
Solid brushes use 1 DWORD per pixel (32 bytes scan line, 256 bytes per brush)
and use two lines per brush.
Color brushes:
8 bpp - 1 byte per pixel, two brushes per scan line.
16 bpp - 2 bytes per pixel, 1 brush per scan line.
24,32 bpp - 4 bytes per pixel, two scan lines per brush.
Brushes are put in the cache using direct frame buffer access. To make using
cached brushes fast, we maintain a seperate cache table for each cache. Each
entry in the cache table tracks the (x,y) address of the brush in a format
directly usable by the chip, and the linear address of the brush for storing the
brush quickly.
Initialization:
-----------------
Brush cache initialization is done during surface initialization.
DrvEnableSurface() => binitSurf() => vInitBrushCache().
*/
#include "precomp.h"
#include "SWAT.h"
#define BRUSH_DBG_LEVEL 1
void vRealizeBrushBits(
PPDEV ppdev,
SURFOBJ *psoPattern,
PBYTE pbDest,
PULONG pulXlate,
PRBRUSH pRbrush);
BOOL CacheMono(PPDEV ppdev, PRBRUSH pRbrush);
BOOL Cache4BPP(PPDEV ppdev, PRBRUSH pRbrush);
BOOL CacheDither(PPDEV ppdev, PRBRUSH pRbrush);
BOOL CacheBrush(PPDEV ppdev, PRBRUSH pRbrush);
//
// These are test/debugging/information-gathering functions that
// get compiled out under a free build.
//
#if LOG_CALLS
void LogRealizeBrush(
ULONG acc,
PPDEV ppdev,
SURFOBJ *psoPattern,
SURFOBJ *psoMask,
XLATEOBJ *pxlo
);
#else
#define LogRealizeBrush(acc, ppdev, psoPattern, psoMask, pxlo)
#endif
//
// These aren't part of the driver. They are debugging support functions
// that can be inserted where needed.
//
// This dumps useful information about brushes that NT gives us.
void PrintBrush(SURFOBJ *psoPattern);
// This dumps useful information about brushes we have realized.
void PrintRealizedBrush(PRBRUSH pRbrush);
//
// Mono brushes must be swizzled before they are stored away.
// We do this with this look up table.
//
BYTE Swiz[] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
/**************************************************************************\
* *
* DrvRealizeBrush *
* *
\**************************************************************************/
//#nbr (begin)
#if USE_ASM && defined(i386)
BOOL i386RealizeBrush(
#else
BOOL DrvRealizeBrush(
#endif
//#nbr (end)
BRUSHOBJ *pbo,
SURFOBJ *psoTarget,
SURFOBJ *psoPattern,
SURFOBJ *psoMask,
XLATEOBJ *pxlo,
ULONG iHatch)
{
PPDEV ppdev;
INT cjPattern, // size of the brush pattern (in bytes).
cjMask; // size of the brush mask (in bytes).
PRBRUSH pRbrush; // Our brush structure.
PULONG pulXlate; // Color translation table.
FLONG flXlate; // Translation flags.
#if 1 //#nbr
LONG lDelta;
#endif
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: Entry.\n"));
//
// Reality check.
//
ASSERTMSG(psoTarget != 0, "DrvRealizeBrush: No target.\n");
//
// Is the screen the target?
//
ppdev = (PPDEV) (psoTarget ? psoTarget->dhpdev : 0);
if (!ppdev)
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: punted (no pdev).\n"));
LogRealizeBrush(1, ppdev, psoPattern, psoMask, pxlo);
return FALSE;
}
SYNC_W_3D(ppdev);
//
// If we don't have a brush cache (maybe we're low on offscreen memory?)
// then we can't do brushes.
//
if (ppdev->Bcache == NULL)
{
LogRealizeBrush(6, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
if (iHatch & RB_DITHERCOLOR)
{
ULONG rgb = iHatch & 0x00FFFFFF;
int i;
// Allocate the memory.
pRbrush = (PRBRUSH) BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH));
if (pRbrush == NULL)
{
LogRealizeBrush(6, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
// Init the brush structure.
pRbrush->nPatSize = 0;
pRbrush->iBitmapFormat = BMF_8BPP;
pRbrush->cjMask = 0;
pRbrush->iType = BRUSH_DITHER;
pRbrush->iUniq = rgb;
// Lookup the dither in the dither cache.
for (i = 0; i < NUM_DITHER_BRUSHES; i++)
{
if (ppdev->Dtable[i].ulColor == rgb)
{
pRbrush->cache_slot = i * sizeof(ppdev->Dtable[i]);
pRbrush->cache_xy = ppdev->Dtable[i].xy;
LogRealizeBrush(0, ppdev, psoPattern, psoMask, pxlo);
return(TRUE);
}
}
// Create the dither and cache it.
LogRealizeBrush(99, ppdev, psoPattern, psoMask, pxlo);
return(CacheDither(ppdev, pRbrush));
}
ASSERTMSG(psoPattern != 0, "DrvRealizeBrush: No pattern.\n");
// Is it an 8x8 brush?
if ((psoPattern->sizlBitmap.cx != 8) || (psoPattern->sizlBitmap.cy != 8))
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: punted (not 8x8).\n"));
LogRealizeBrush(3, ppdev, psoPattern, psoMask, pxlo);
return FALSE;
}
// Does it have a mask?
// Some of the mask code is in place, but not all of it.
if ((psoMask != NULL) && (psoMask->pvScan0 != psoPattern->pvScan0))
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: punted (has a mask).\n"));
LogRealizeBrush(4, ppdev, psoPattern, psoMask, pxlo);
return FALSE;
}
// Is it a standard format brush?
if (psoPattern->iType != STYPE_BITMAP)
{
DISPDBG((BRUSH_DBG_LEVEL,
"DrvRealizeBrush: punted (not standard bitmap).\n"));
LogRealizeBrush(2, ppdev, psoPattern, psoMask, pxlo);
return FALSE;
}
//
// Get the color translation.
//
flXlate = pxlo ? pxlo->flXlate : XO_TRIVIAL;
if (flXlate & XO_TRIVIAL)
{
pulXlate = NULL;
}
else if (flXlate & XO_TABLE)
{
pulXlate = pxlo->pulXlate;
}
else if (pxlo->iSrcType == PAL_INDEXED)
{
pulXlate = XLATEOBJ_piVector(pxlo);
}
else
{
// Some kind of translation we don't handle.
return FALSE;
}
// The hardware does not support colored bitmaps in 32-bpp.
if ( (psoPattern->iBitmapFormat > BMF_1BPP) &&
(ppdev->iBitmapFormat == BMF_32BPP) )
{
LogRealizeBrush(5, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
if (psoPattern->iBitmapFormat == BMF_4BPP)
{
int i;
// Check if we support this bitmap.
if ( (psoPattern->cjBits != XLATE_PATSIZE) ||
(pxlo->cEntries != XLATE_COLORS) )
{
// We don't support other bitmaps than 8x8 and 16 translation
// entries.
LogRealizeBrush(10, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
// Allocate the brush.
pRbrush = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) + XLATE_PATSIZE +
XLATE_COLORS * sizeof(ULONG));
if (pRbrush == NULL)
{
LogRealizeBrush(6, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
//
// Init the brush structure.
//
pRbrush->nPatSize = XLATE_PATSIZE + XLATE_COLORS * sizeof(ULONG);
pRbrush->iBitmapFormat = BMF_4BPP;
pRbrush->cjMask = 0;
pRbrush->iType = BRUSH_4BPP;
// Copy the 4-bpp pattern and translation palette to the brush.
if (psoPattern->lDelta == 4)
{
memcpy(pRbrush->ajPattern, psoPattern->pvBits, XLATE_PATSIZE);
}
else
{
BYTE *pSrc = psoPattern->pvScan0;
for (i = 0; i < 8; i++)
{
((DWORD *) pRbrush->ajPattern)[i] = *(DWORD *) pSrc;
pSrc += psoPattern->lDelta;
}
}
memcpy(pRbrush->ajPattern + XLATE_PATSIZE, pulXlate,
XLATE_COLORS * sizeof(ULONG));
// Lookup the pattern and palette in the translation cache.
for (i = 0; i < NUM_4BPP_BRUSHES; i++)
{
if ((memcmp(ppdev->Xtable[i].ajPattern, pRbrush->ajPattern,
XLATE_PATSIZE + XLATE_COLORS * sizeof(ULONG)) == 0)
#if 1 //#1308
&& (ppdev->Xtable[i].iUniq != 0)
#endif
)
{
// We have a match!
pRbrush->iUniq = ppdev->Xtable[i].iUniq;
pRbrush->cache_slot = i * sizeof(ppdev->Xtable[i]);
pRbrush->cache_xy = ppdev->Xtable[i].xy;
LogRealizeBrush(0, ppdev, psoPattern, psoMask, pxlo);
return(TRUE);
}
}
// Cache the brush now.
LogRealizeBrush(6, ppdev, psoPattern, psoMask, pxlo);
return(Cache4BPP(ppdev, pRbrush));
}
if (psoPattern->iBitmapFormat == BMF_1BPP)
{
int i;
PBYTE pSrc;
// Check if we support this bitmap.
if (pulXlate == 0)
{
LogRealizeBrush(11, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
// Allocate the brush.
pRbrush = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) + 8);
if (pRbrush == NULL)
{
LogRealizeBrush(6, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
//
// Init the brush structure.
//
pRbrush->nPatSize = 8;
pRbrush->iBitmapFormat = BMF_1BPP;
pRbrush->cjMask = 0;
pRbrush->iType = BRUSH_MONO;
// Copy the 4-bpp pattern and translation palette to the brush.
pRbrush->ulBackColor = ExpandColor(pulXlate[0], ppdev->ulBitCount);
pRbrush->ulForeColor = ExpandColor(pulXlate[1], ppdev->ulBitCount);
pSrc = (PBYTE) psoPattern->pvScan0;
for (i = 0; i < 8; i++)
{
pRbrush->ajPattern[i] = *pSrc;
pSrc += psoPattern->lDelta;
}
// Lookup the pattern and palette in the translation cache.
for (i = 0; i < NUM_MONO_BRUSHES; i++)
{
if ((*(DWORD *) &ppdev->Mtable[i].ajPattern[0] ==
*(DWORD *) &pRbrush->ajPattern[0]) &&
#if 1 //#1308
(ppdev->Mtable[i].iUniq != 0) &&
#endif
(*(DWORD *) &ppdev->Mtable[i].ajPattern[4] ==
*(DWORD *) &pRbrush->ajPattern[4]) )
{
// We have a match!
pRbrush->iUniq = ppdev->Mtable[i].iUniq;
pRbrush->cache_slot = i * sizeof(ppdev->Mtable[i]);
pRbrush->cache_xy = ppdev->Mtable[i].xy;
LogRealizeBrush(0, ppdev, psoPattern, psoMask, pxlo);
return(TRUE);
}
}
// Cache the brush now.
LogRealizeBrush(0, ppdev, psoPattern, psoMask, pxlo);
return(CacheMono(ppdev, pRbrush));
}
#if 1 //#nbr
// How much memory do we need for the pattern?
lDelta = (ppdev->iBytesPerPixel * 8);
if (ppdev->iBytesPerPixel == 3)
{
lDelta += 8;
}
cjPattern = lDelta * 8;
// Allocate the memory.
pRbrush = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) + cjPattern);
if (pRbrush == NULL)
{
DISPDBG((BRUSH_DBG_LEVEL,
"DrvRealizeBrush: punted (Mem alloc failed).\n"));
LogRealizeBrush(6, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
// Initialize the brush fields.
pRbrush->nPatSize = cjPattern;
pRbrush->iBitmapFormat = ppdev->iBitmapFormat;
pRbrush->cjMask = 0;
pRbrush->iType = BRUSH_COLOR;
// Can we realize the bits directly?
if ((psoPattern->iBitmapFormat == ppdev->iBitmapFormat) &&
(flXlate & XO_TRIVIAL))
{
// Realize the brush bits.
vRealizeBrushBits(ppdev, psoPattern, &pRbrush->ajPattern[0], pulXlate,
pRbrush);
}
else
{
HBITMAP hBrush;
SURFOBJ* psoBrush;
RECTL rclDst = { 0, 0, 8, 8 };
BOOL bRealized = FALSE;
DISPDBG((BRUSH_DBG_LEVEL, "DrvRealizeBrush: Translating brush.\n"));
// Create a bitmap wrapper for the brush bits.
hBrush = EngCreateBitmap(psoPattern->sizlBitmap, lDelta,
ppdev->iBitmapFormat, BMF_TOPDOWN,
pRbrush->ajPattern);
if (hBrush != 0)
{
// Associate the bitmap wrapper with the device.
if (EngAssociateSurface((HSURF) hBrush, ppdev->hdevEng, 0))
{
// Lock the bitmap wrapper.
psoBrush = EngLockSurface((HSURF) hBrush);
if (psoBrush != NULL)
{
// Copy the pattern bits to the bitmap wrapper.
if (EngCopyBits(psoBrush, psoPattern, NULL, pxlo, &rclDst,
(POINTL*) &rclDst))
{
// In 24-bpp, the brush bits have a different layout.
if (ppdev->iBytesPerPixel == 3)
{
INT y;
ULONG* pulDst = (ULONG*) pRbrush->ajPattern;
// Walk through every line.
for (y = 0; y < 8; y++)
{
// Copy bytes 0-7 to bytes 25-31.
pulDst[6] = pulDst[0];
pulDst[7] = pulDst[1];
// Next line.
pulDst += 8;
}
}
// Mark the brush as realized.
bRealized = TRUE;
}
else
{
DISPDBG((BRUSH_DBG_LEVEL, " EngCopyBits failed.\n"));
}
// Unlock the bitmap wrapper.
EngUnlockSurface(psoBrush);
}
else
{
DISPDBG((BRUSH_DBG_LEVEL, " EngLockSurface failed.\n"));
}
}
else
{
DISPDBG((BRUSH_DBG_LEVEL, " EngAssociateSurface failed.\n"));
}
// Delete the bitmap wrapper.
EngDeleteSurface((HSURF) hBrush);
}
else
{
DISPDBG((BRUSH_DBG_LEVEL, "(EngCreateBitmap failed)\n"));
}
if (!bRealized)
{
// The brush was not realized.
return(FALSE);
}
}
#else
if (flXlate & 0x10)
{
// Punt to GDI.
LogRealizeBrush(9, ppdev, psoPattern, psoMask, pxlo);
return(FALSE);
}
// Is it a supported color depth?
if (psoPattern->iBitmapFormat != ppdev->iBitmapFormat)
{
DISPDBG((BRUSH_DBG_LEVEL,
"DrvRealizeBrush: punted (unsupported color depth).\n"));
LogRealizeBrush(5, ppdev, psoPattern, psoMask, pxlo);
return FALSE;
}
//
// We don't handle color xlates yet.
// If there is an xlate table, punt it.
//
if ( pulXlate )
{
DISPDBG((BRUSH_DBG_LEVEL,
"DrvRealizeBrush: punted (Xlate required).\n"));
LogRealizeBrush(9, ppdev, psoPattern, psoMask, pxlo);
return FALSE;
}
//
// Alloc memory from GDI for brush storage.
//
// How much memory to we need for the pattern?
cjPattern = psoPattern->cjBits;
if (psoPattern->iBitmapFormat == BMF_24BPP)
cjPattern += 64;
// We need memory for the mask too.
// Check for mask bits equal to pattern bits.
// If psoMask is NULL, the mask is never used, so no memory is needed.
if ((psoMask != NULL) && (psoMask->pvScan0 != psoPattern->pvScan0))
cjMask = psoMask->cjBits;
else
cjMask = 0;
// Allocate the memory.
pRbrush =
(PRBRUSH) BRUSHOBJ_pvAllocRbrush(pbo,sizeof(RBRUSH)+cjPattern+cjMask);
if (!pRbrush)
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: punted (Mem alloc failed).\n"));
LogRealizeBrush(6, ppdev, psoPattern, psoMask, pxlo);
return (FALSE);
}
//
// Init the brush structure.
//
pRbrush->nPatSize = cjPattern;
pRbrush->iBitmapFormat = psoPattern->iBitmapFormat;
pRbrush->cjMask = (cjMask ? cjPattern : 0);
pRbrush->iType = BRUSH_COLOR;
//
// Realize the brush and mask. Actually we punted masks a while ago.
//
vRealizeBrushBits(ppdev, psoPattern, &pRbrush->ajPattern[0], pulXlate,
pRbrush);
#endif
//
// Cache the brush now.
//
CacheBrush(ppdev, pRbrush);
//
// Dump brush data to the profiling file.
// Gets compiled out under a free build.
//
LogRealizeBrush(0, ppdev, psoPattern, psoMask, pxlo);
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: Done.\n"));
return (TRUE);
}
/***********************************************************************\
* *
* vRealizeBrushBits() *
* *
* Copies the brush pattern from GDI to our realized brush. *
* Called by DrvRealizeBrush() *
* *
\***********************************************************************/
void vRealizeBrushBits(
PPDEV ppdev,
SURFOBJ *psoPattern,
PBYTE pbDest,
PULONG pulXlate,
PRBRUSH pRbrush
)
{
PBYTE pbSrc;
INT i,j;
LONG lDelta;
//
// Find the top scan line in the brush, and it's scan line delta
// This works for both top down and bottom up brushes.
//
pbSrc = psoPattern->pvScan0;
lDelta = (psoPattern->lDelta);
//
// At this point all brushs are 8x8.
// Currently we only support mono brushes, and brushes with the same
// color depth as the screen. Color translations aren't supported.
//
// Mono brushes must be swizzled as we copy them. We do this using
// a 256 byte lookup table.
//
// We store the brushes in host memory as a linear string of bytes.
// Before we use the brush we will cache it off screen memory in a
// format that the BLT engine can use.
//
switch (psoPattern->iBitmapFormat)
{
case BMF_8BPP:
//
// Store the pattern as 64 consecutive bytes.
//
if (lDelta == 8)
{
memcpy(pbDest, pbSrc, 8 * 8);
}
else
{
// For each row in the pattern.
for (j = 0; j < 8; j++)
{
// Copy the row.
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[0];
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[4];
// Move to next row.
pbSrc += lDelta;
}
}
return;
case BMF_16BPP:
//
// Store the pattern as 128 consecutive bytes.
//
if (lDelta == 16)
{
memcpy(pbDest, pbSrc, 16 * 8);
}
else
{
// For each row in the pattern.
for (j = 0; j < 8; j++)
{
// Copy the row.
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[0];
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[4];
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[8];
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[12];
// Move to next row.
pbSrc += lDelta;
}
}
return;
case BMF_24BPP:
//
// Store the pattern as 256 consecutive bytes.
//
//
// Each row in the pattern needs 24 bytes. The pattern is stored
// with 32 bytes per row though, with the last 8 bytes being a
// copy of the first 8 bytes, like so:
//
// RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RG
// 1 2 3 4 5 6 7 8 1 2 3
// \___________________________/ \________/
// | |
// pattern scan line copy of first 8
// bytes of scan line
//
// For each row in the pattern.
for (j = 0; j < 8; j++)
{
//
// Copy the row.
//
for (i = 0; i < 24; i += sizeof(ULONG))
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[i];
//
// Pad the last 8 bytes with a copy of the first 8 bytes.
//
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[0];
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[4];
// Move to next row.
pbSrc += lDelta;
}
return;
case BMF_32BPP:
//
// Store the pattern as 256 consecutive bytes.
//
if (lDelta == 32)
{
memcpy(pbDest, pbSrc, 32 * 8);
}
else
{
// For each row in the pattern.
for (j = 0; j < 8; j++)
{
// Copy the row.
for (i = 0; i < 32; i += sizeof(ULONG))
*((ULONG *) pbDest)++ = *(ULONG *) &pbSrc[i];
// Move to next row.
pbSrc += lDelta;
}
}
return;
}
}
// ===========================================================================+
// ||
// ExpandColor() ||
// Expands a color value to 32 bits by replication. ||
// Called by vRealizeBrushBits() ||
// ||
// ===========================================================================+
ULONG ExpandColor(ULONG iSolidColor, ULONG ulBitCount)
{
ULONG color;
//
// If the color is an 8 or 16 bit color, it needs to be
// extended (by replication) to fill a 32 bit register.
//
switch (ulBitCount)
{
case 8: // For 8 bpp duplicate byte 0 into bytes 1,2,3.
color = iSolidColor & 0x00000000FF; // Clear upper 24 bits.
return ((color << 24) | (color << 16) | (color << 8) | color);
case 16: // For 16 bpp, duplicate the low word into the high word.
color = (iSolidColor) & 0x0000FFFF; // Clear upper 16 bits.
return ((color << 16) | color);
case 24: // For 24 bpp clear the upper 8 bits.
return (iSolidColor & 0x00FFFFFF);
default: // For 32 bpp just use the color supplied by NT.
return (iSolidColor); // Color of fill
}
}
/**************************************************************************\
* *
* CacheMono() *
* Cache a realized monochrome brush. *
* *
\**************************************************************************/
BOOL CacheMono(PPDEV ppdev, PRBRUSH pRbrush)
{
int i;
ULONG tbl_idx = ppdev->MNext % NUM_MONO_BRUSHES;
PBYTE pdest;
// Copy the monochrome pattern to the cache and off-screen.
pdest = ppdev->Mtable[tbl_idx].pjLinear;
for (i = 0; i < 8; i++)
{
ppdev->Mtable[tbl_idx].ajPattern[i] = pRbrush->ajPattern[i];
pdest[i] = Swiz[pRbrush->ajPattern[i]];
}
// Store the new uniq ID in the cache slot.
pRbrush->iUniq = ppdev->Mtable[tbl_idx].iUniq = ++ppdev->MNext;
pRbrush->cache_slot = tbl_idx * sizeof(ppdev->Mtable[tbl_idx]);
pRbrush->cache_xy = ppdev->Mtable[tbl_idx].xy;
return(TRUE);
}
/**************************************************************************\
* *
* Cache4BPP() *
* Cache a realized 4-bpp brush. *
* *
\**************************************************************************/
BOOL Cache4BPP(PPDEV ppdev, PRBRUSH pRbrush)
{
ULONG tbl_idx = ppdev->XNext % NUM_4BPP_BRUSHES;
int i, j;
PBYTE psrc, pdest;
ULONG *pulPalette;
// Copy the 4-bpp pattern to the cache.
#pragma prefast(suppress: 203, "Ugly but works - we're copying pattern and palette (PREfast bug 611168)")
memcpy(ppdev->Xtable[tbl_idx].ajPattern, pRbrush->ajPattern,
XLATE_PATSIZE + XLATE_COLORS * sizeof(ULONG));
psrc = ppdev->Xtable[tbl_idx].ajPattern;
pulPalette = ppdev->Xtable[tbl_idx].ajPalette;
pdest = ppdev->Xtable[tbl_idx].pjLinear;
switch (ppdev->ulBitCount)
{
case 8:
for (i = 0; i < 8; i++)
{
for (j = 0; j < 4; j++)
{
*pdest++ = (BYTE) pulPalette[psrc[j] >> 4];
*pdest++ = (BYTE) pulPalette[psrc[j] & 0x0F];
}
psrc += 4;
}
break;
case 16:
for (i = 0; i < 8; i++)
{
for (j = 0; j < 4; j++)
{
*((WORD *)pdest)++ = (WORD) pulPalette[psrc[j] >> 4];
*((WORD *)pdest)++ = (WORD) pulPalette[psrc[j] & 0x0F];
}
psrc += 4;
}
break;
case 24:
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j += 2)
{
ULONG p1, p2, p3, p4;
p1 = pulPalette[psrc[j] >> 4];
p2 = pulPalette[psrc[j] & 0x0F];
p3 = pulPalette[psrc[j + 1] >> 4];
p4 = pulPalette[psrc[j + 1] & 0x0F];
*((DWORD *)pdest)++ = p1 | (p2 << 24);
*((DWORD *)pdest)++ = (p2 >> 8) | (p3 << 16);
*((DWORD *)pdest)++ = (p3 >> 16) | (p4 << 8);
}
psrc += 4;
*((DWORD *)pdest)++ = *(DWORD *) &pdest[-24];
*((DWORD *)pdest)++ = *(DWORD *) &pdest[-24];
}
pdest += ppdev->lDeltaScreen - 4 * 8 * 4;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j += 2)
{
ULONG p1, p2, p3, p4;
p1 = pulPalette[psrc[j] >> 4];
p2 = pulPalette[psrc[j] & 0x0F];
p3 = pulPalette[psrc[j + 1] >> 4];
p4 = pulPalette[psrc[j + 1] & 0x0F];
*((DWORD *)pdest)++ = p1 | (p2 << 24);
*((DWORD *)pdest)++ = (p2 >> 8) | (p3 << 16);
*((DWORD *)pdest)++ = (p3 >> 16) | (p4 << 8);
}
psrc += 4;
*((DWORD *)pdest)++ = *(DWORD *) &pdest[-24];
*((DWORD *)pdest)++ = *(DWORD *) &pdest[-24];
}
break;
case 32:
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
*((DWORD *)pdest)++ = pulPalette[psrc[j] >> 4];
*((DWORD *)pdest)++ = pulPalette[psrc[j] & 0x0F];
}
psrc += 4;
}
pdest += ppdev->lDeltaScreen - 4 * 8 * 4;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
*((DWORD *)pdest)++ = pulPalette[psrc[j] >> 4];
*((DWORD *)pdest)++ = pulPalette[psrc[j] & 0x0F];
}
psrc += 4;
}
break;
}
// Store the new uniq ID in the cache slot.
pRbrush->iUniq = ppdev->Xtable[tbl_idx].iUniq = ++ppdev->XNext;
pRbrush->cache_slot = tbl_idx * sizeof(ppdev->Xtable[tbl_idx]);
pRbrush->cache_xy = ppdev->Xtable[tbl_idx].xy;
return(TRUE);
}
/**************************************************************************\
* *
* CacheDither() *
* Cache a realized dither brush. *
* *
\**************************************************************************/
BOOL CacheDither(PPDEV ppdev, PRBRUSH pRbrush)
{
ULONG tbl_idx = ppdev->DNext++ % NUM_DITHER_BRUSHES;
// Create the dither directly in off-screen memory.
vDitherColor(pRbrush->iUniq, (ULONG *) ppdev->Dtable[tbl_idx].pjLinear);
// Store the color in the cache slot.
ppdev->Dtable[tbl_idx].ulColor = pRbrush->iUniq;
pRbrush->cache_slot = tbl_idx * sizeof(ppdev->Dtable[tbl_idx]);
pRbrush->cache_xy = ppdev->Dtable[tbl_idx].xy;
return(TRUE);
}
/**************************************************************************\
* *
* CacheBrush() *
* Cache a realized color brush. *
* *
\**************************************************************************/
BOOL CacheBrush(PPDEV ppdev, PRBRUSH pRbrush)
{
PBYTE psrc, pdest;
ULONG tbl_idx = ppdev->CNext;
if (++ppdev->CNext == ppdev->CLast)
{
ppdev->CNext = 0;
}
// Copy the brush bits to off-screen.
psrc = pRbrush->ajPattern;
pdest = ppdev->Ctable[tbl_idx].pjLinear;
if (pRbrush->iBitmapFormat < BMF_24BPP)
{
memcpy(pdest, pRbrush->ajPattern, pRbrush->nPatSize);
}
else
{
memcpy(pdest, psrc, 32 * 4);
memcpy(pdest + ppdev->lDeltaScreen, psrc + 32 * 4, 32 * 4);
}
ppdev->Ctable[tbl_idx].brushID = pRbrush;
pRbrush->cache_slot = tbl_idx * sizeof(ppdev->Ctable[tbl_idx]);
pRbrush->cache_xy = ppdev->Ctable[tbl_idx].xy;
return(TRUE);
}
//--------------------------------------------------------------------------//
// //
// SetBrush() //
// Used by op2BLT(), HostToScreenBLT() and ScreenToScreenBLT() in BITBLT.C //
// to setup the chip to use the current brush. //
// //
//--------------------------------------------------------------------------//
BOOL SetBrush(
PPDEV ppdev,
ULONG *bltdef, // local copy of the BLTDEF register.
BRUSHOBJ *pbo,
POINTL *pptlBrush)
{
ULONG color;
PRBRUSH pRbrush = 0;
USHORT patoff_x, patoff_y;
if (ppdev->bDirectDrawInUse)
return(FALSE);
//
// See if the brush is really a solid color.
//
if (pbo->iSolidColor != 0xFFFFFFFF) // It's a solid brush.
{
// Expand the color to a full 32 bit DWORD.
switch (ppdev->ulBitCount)
{
case 8:
color = pbo->iSolidColor & 0x000000FF;
color |= color << 8;
color |= color << 16;
break;
case 16:
color = pbo->iSolidColor & 0x0000FFFF;
color |= color << 16;
break;
case 24:
color = pbo->iSolidColor & 0x00FFFFFF;
break;
case 32:
color = pbo->iSolidColor;
break;
}
#if SOLID_CACHE
ppdev->Stable[ppdev->SNext].ulColor = color;
#endif
// Load the fg and bg color registers.
REQUIRE(2);
LL_BGCOLOR(color, 2);
// Set the operation
*bltdef |= 0x0007; // OP2=FILL.
return TRUE; // That's it!
}
//
// It's not a solid color, it's a pattern.
//
// Get the pointer to our drivers realization of the brush.
if (pbo->pvRbrush != NULL)
{
pRbrush = pbo->pvRbrush;
}
else // we haven't realized it yet, so do so now.
{
pRbrush = BRUSHOBJ_pvGetRbrush(pbo);
if (pRbrush == NULL)
{
return(FALSE); // Fail if we do not handle the brush.
}
}
//
// Set pattern offset.
// NT specifies patttern offset as which pixel on the screen to align
// with pattern(0,0). Laguna specifies pattern offset as which pixel
// of the pattern to align with screen(0,0). Only the lowest three
// bits are significant, so we can ignore any overflow when converting.
// Also, even though PATOFF is a reg_16, we can't do byte wide writes
// to it. We have to write both PATOFF.pt.X and PATOFF.pt.Y in a single
// 16 bit write.
//
#if 1 //#1244
patoff_x = (USHORT)(-(pptlBrush->x + ppdev->ptlOffset.x) & 7);
patoff_y = (USHORT)(-(pptlBrush->y + ppdev->ptlOffset.y) & 7);
#else
patoff_x = ((pptlBrush->x - 1) ^ 0x07) & 0x07;
patoff_y = ((pptlBrush->y - 1) ^ 0x07) & 0x07;
#endif
REQUIRE(1);
LL16(grPATOFF.w, (patoff_y << 8) | patoff_x);
//
// What kind of brush is it?
//
if (pRbrush->iType == BRUSH_MONO) // Monochrome brush.
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: Using MONO Brush.\n"));
#define mb ((MC_ENTRY*)(((BYTE*)ppdev->Mtable) + pRbrush->cache_slot))
if (mb->iUniq != pRbrush->iUniq)
{
CacheMono(ppdev, pRbrush);
}
// Load the fg and bg color registers.
REQUIRE(6);
LL_FGCOLOR(pRbrush->ulForeColor, 0);
LL_BGCOLOR(pRbrush->ulBackColor, 0);
LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
*bltdef |= 0x000D;
return(TRUE);
}
else if (pRbrush->iType == BRUSH_4BPP) // 4-bpp brush.
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: Using 4bpp Brush.\n"));
#define xb ((XC_ENTRY*)(((BYTE*)ppdev->Xtable) + pRbrush->cache_slot))
if (xb->iUniq != pRbrush->iUniq)
{
Cache4BPP(ppdev, pRbrush);
}
REQUIRE(2);
LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
*bltdef |= 0x0009;
return(TRUE);
}
else if (pRbrush->iType == BRUSH_DITHER) // Dither brush.
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: Using dither Brush.\n"));
#define db ((DC_ENTRY*)(((BYTE*)ppdev->Dtable) + pRbrush->cache_slot))
if (db->ulColor != pRbrush->iUniq)
{
CacheDither(ppdev, pRbrush);
}
REQUIRE(2);
LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
*bltdef |= 0x0009;
return(TRUE);
}
else // Color brush.
{
DISPDBG((BRUSH_DBG_LEVEL,"DrvRealizeBrush: Using color Brush.\n"));
#define cb ((BC_ENTRY*)(((BYTE*)ppdev->Ctable) + pRbrush->cache_slot))
if (cb->brushID != pRbrush)
{
CacheBrush(ppdev, pRbrush);
}
REQUIRE(2);
LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
*bltdef |= 0x0009;
return(TRUE);
}
}
// ==========================================================================+
// ||
// vInitBrushCache() ||
// Called by bInitSURF in SCREEN.C ||
// Allocate some off screen memory to cache brushes in. ||
// Initialize the brush caching tables. ||
// ||
// ==========================================================================+
void vInitBrushCache(
PPDEV ppdev
)
{
SIZEL sizel;
int i;
ULONG x, y;
//
// NOTE: The size and location of the brush cache itself
// is in pixel coordinates. The offsets of the
// individual brushes within the cache are BYTE offsets.
//
//
// We need to allocate a 128 BYTE wide rectangle.
// The offscreen memory manager wants the size of the requested
// rectangle in PIXELS. So firure out how many pixels are in 128 bytes.
//
/*
We are going to allocate 3 128-byte wide rectangles, side by side. The
layout of this brush cache region is:
+----------------+----------------+----------------+
| | | MONOCHROME |
| COLOR | 4BPP +----------------+
| BRUSHES | BRUSHES | DITHER |
| | | BRUSHES |
+----------------+----------------+----------------+
*/
sizel.cy = max(max(NUM_COLOR_BRUSHES / 2,
NUM_4BPP_BRUSHES * 2),
NUM_MONO_BRUSHES / 16 + NUM_DITHER_BRUSHES / 2 + 2);
#if MEMMGR
sizel.cx = 128 * 3;
#else
sizel.cx = (128 * 3) / ppdev->iBytesPerPixel;
#endif
//
// Allocate the offscreen memory
//
DISPDBG((BRUSH_DBG_LEVEL,"Allocating the brush cache.\n"));
ppdev->Bcache = AllocOffScnMem(ppdev, &sizel, 0, 0);
// Did the allocate succeed?
if (! ppdev->Bcache)
{
//
// We failed to allocate a brush cache.
// Return while the entire cache is still marked as as unusable,
// This will cause anything needing a brush to punt.
//
return;
}
//
// Init the cache table.
// The X offests of all the brushes in the cache are BYTE
// offsets.
//
// Init the monochrome cache table. The x offsets are bit offsets.
// Brushes are stored 16 to a row.
for (i = 0; i < NUM_MONO_BRUSHES; i++)
{
x = ppdev->Bcache->x + (128 * 2) + (i % 16) * 8; // byte offset
y = ppdev->Bcache->y + (i / 16);
ppdev->Mtable[i].xy = (y << 16) | (x << 3); // convert to bit offset
ppdev->Mtable[i].pjLinear = ppdev->pjScreen
+ x + (y * ppdev->lDeltaScreen);
ppdev->Mtable[i].iUniq = 0;
}
ppdev->MNext = 0;
// Init the 4-bpp cache table. The x offsets are byte offsets.
// Each brush takes 2 rows.
for (i = 0; i < NUM_4BPP_BRUSHES; i++)
{
x = ppdev->Bcache->x + (128 * 1);
y = ppdev->Bcache->y + (i * 2);
ppdev->Xtable[i].xy = (y << 16) | x;
ppdev->Xtable[i].pjLinear = ppdev->pjScreen
+ x + (y * ppdev->lDeltaScreen);
ppdev->Xtable[i].iUniq = 0;
}
ppdev->XNext = 0;
// Init the dither cache table. The x offsets are byte offsets.
// Two brushes per row.
for (i = 0; i < NUM_DITHER_BRUSHES; i++)
{
x = ppdev->Bcache->x + (128 * 2) + (i % 2) * 64;
y = ppdev->Bcache->y + (i / 2) + (NUM_MONO_BRUSHES / 16);
ppdev->Dtable[i].xy = (y << 16) | x;
ppdev->Dtable[i].pjLinear = ppdev->pjScreen
+ x + (y * ppdev->lDeltaScreen);
ppdev->Dtable[i].ulColor = (ULONG) -1;
}
ppdev->DNext = 0;
#if SOLID_CACHE
// Solid brush cache is for using a mono brush with a mono source.
// The mono brush is converted to a solid color brush.
// Each brush takes two rows.
for (i = 0; i < NUM_SOLID_BRUSHES; i++)
{
x = ppdev->Bcache->x + (128 * 2);
y = ppdev->Bcache->y + (i * 2) + (NUM_MONO_BRUSHES / 16)
+ (NUM_DITHER_BRUSHES / 2);
ppdev->Stable[i].xy = (y << 16) | x;
ppdev->Stable[i].pjLinear = ppdev->pjScreen
+ x + (y * ppdev->lDeltaScreen);
}
ppdev->SNext = 0;
#endif
// Init the color cache table. The x offsets are byte offsets.
switch (ppdev->ulBitCount)
{
case 8: // 8-bpp
ppdev->CLast = NUM_8BPP_BRUSHES;
for (i = 0; i < NUM_8BPP_BRUSHES; i++)
{
x = ppdev->Bcache->x + (i % 2) * 64;
y = ppdev->Bcache->y + (i / 2);
ppdev->Ctable[i].xy = (y << 16) | x;
ppdev->Ctable[i].pjLinear = ppdev->pjScreen
+ x + (y * ppdev->lDeltaScreen);
ppdev->Ctable[i].brushID = 0;
}
break;
case 16: // 16-bpp
ppdev->CLast = NUM_16BPP_BRUSHES;
for (i = 0; i < NUM_16BPP_BRUSHES; i++)
{
x = ppdev->Bcache->x;
y = ppdev->Bcache->y + i;
ppdev->Ctable[i].xy = (y << 16) | x;
ppdev->Ctable[i].pjLinear = ppdev->pjScreen
+ x + (y * ppdev->lDeltaScreen);
ppdev->Ctable[i].brushID = 0;
}
break;
default: // 24-bpp or 32-bpp
ppdev->CLast = NUM_TC_BRUSHES;
for (i = 0; i < NUM_TC_BRUSHES; i++)
{
x = ppdev->Bcache->x;
y = ppdev->Bcache->y + (i * 2);
ppdev->Ctable[i].xy = (y << 16) | x;
ppdev->Ctable[i].pjLinear = ppdev->pjScreen
+ x + (y * ppdev->lDeltaScreen);
ppdev->Ctable[i].brushID = 0;
}
break;
}
ppdev->CNext = 0;
}
// ==========================================================================+
// ||
// vInvalidateBrushCache() ||
// ||
// Invalidate the brush caching tables. ||
// ||
// ==========================================================================+
void vInvalidateBrushCache(PPDEV ppdev)
{
ULONG i;
// 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;
}
#if LOG_CALLS
/* --------------------------------------------------------------------*\
| |
| Dump information on what brushes are requested from GDI to the |
| profiling file. Allows us to track what gets accellerated and |
| what gets punted. This function gets compiled out under a free |
| build. |
| |
\*---------------------------------------------------------------------*/
extern long lg_i;
extern char lg_buf[256];
void LogRealizeBrush(
ULONG acc,
PPDEV ppdev,
SURFOBJ *psoPattern,
SURFOBJ *psoMask,
XLATEOBJ *pxlo
)
{
#if ENABLE_LOG_SWITCH
if (pointer_switch == 0) return;
#endif
lg_i = sprintf(lg_buf,"DrvRealizeBrush: ");
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
// Did we realize it? If not, why?
switch (acc)
{
case 0: lg_i = sprintf(lg_buf,"(Realized) "); break;
case 1: lg_i = sprintf(lg_buf,"(Punted - No PDEV) "); break;
case 2: lg_i = sprintf(lg_buf,"(Punted - Not STYPE_BITMAP) "); break;
case 3: lg_i = sprintf(lg_buf,"(Punted - Not 8x8) "); break;
case 4: lg_i = sprintf(lg_buf,"(Punted - Has mask) "); break;
case 5: lg_i = sprintf(lg_buf,"(Punted - Bad color depth) "); break;
case 6: lg_i = sprintf(lg_buf,"(Punted - ALLOC failed) "); break;
case 7: lg_i = sprintf(lg_buf,"(Punted - Color Bottom-Up) "); break;
case 8: lg_i = sprintf(lg_buf,"(Punted - No 1BPP Xlate) "); break;
case 9: lg_i = sprintf(lg_buf,"(Punted - Has Color Xlate) "); break;
case 10: lg_i = sprintf(lg_buf,"(Punted - 4bpp format) "); break;
case 11: lg_i = sprintf(lg_buf,"(Punted - 1bpp XLATE) "); break;
case 99: lg_i = sprintf(lg_buf,"(Dithered) "); break;
default: lg_i = sprintf(lg_buf,"(STATUS UNKNOWN) "); break;
}
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
if (psoPattern == NULL)
{
lg_i = sprintf(lg_buf,"FMT=NULL");
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
else
{
switch (psoPattern->iBitmapFormat)
{
case BMF_1BPP : lg_i = sprintf(lg_buf,"FMT=1_bpp "); break;
case BMF_4BPP : lg_i = sprintf(lg_buf,"FMT=4_bpp "); break;
case BMF_8BPP : lg_i = sprintf(lg_buf,"FMT=8_bpp "); break;
case BMF_16BPP: lg_i = sprintf(lg_buf,"FMT=16bpp "); break;
case BMF_24BPP: lg_i = sprintf(lg_buf,"FMT=24bpp "); break;
case BMF_32BPP: lg_i = sprintf(lg_buf,"FMT=32bpp "); break;
case BMF_4RLE : lg_i = sprintf(lg_buf,"FMT=4_rle "); break;
case BMF_8RLE : lg_i = sprintf(lg_buf,"FMT=8_rle "); break;
default: lg_i = sprintf(lg_buf,"FMT=OTHER "); break;
}
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
lg_i = sprintf(lg_buf,"CX=%d CY=%d ", psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy);
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
lg_i = sprintf(lg_buf,"MASK=%s ",
((psoMask == NULL) ? "NONE":
((psoMask->pvScan0 == psoPattern->pvScan0) ? "SAME" : "DIFF")));
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
if (pxlo == NULL)
{
lg_i = sprintf(lg_buf,"XLAT=NONE ");
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
else
{
if (pxlo->flXlate & XO_TRIVIAL)
{
lg_i = sprintf(lg_buf,"XLAT=TRIVIAL ");
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
if (pxlo->flXlate & XO_TABLE)
{
lg_i = sprintf(lg_buf,"XLAT=TABLE ");
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
if (pxlo->flXlate & XO_TO_MONO)
{
lg_i = sprintf(lg_buf,"XLAT=TO_MONO ");
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
switch (pxlo->iSrcType)
{
case PAL_INDEXED: lg_i = sprintf(lg_buf,"SRCPAL=INDEXED "); break;
case PAL_BITFIELDS: lg_i = sprintf(lg_buf,"SRCPAL=BITFIELD "); break;
case PAL_RGB: lg_i = sprintf(lg_buf,"SRCPAL=R_G_B "); break;
case PAL_BGR: lg_i = sprintf(lg_buf,"SRCPAL=B_G_R "); break;
default: lg_i = sprintf(lg_buf,"SRCPAL=NONE "); break;
}
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
switch (pxlo->iDstType)
{
case PAL_INDEXED: lg_i = sprintf(lg_buf,"DSTPAL=INDEXED "); break;
case PAL_BITFIELDS:lg_i = sprintf(lg_buf,"DSTPAL=BITFIELD "); break;
case PAL_RGB: lg_i = sprintf(lg_buf,"DSTPAL=R_G_B "); break;
case PAL_BGR: lg_i = sprintf(lg_buf,"DSTPAL=B_G_R "); break;
default: lg_i = sprintf(lg_buf,"DSTPAL=NONE "); break;
}
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
lg_i = sprintf(lg_buf,"\r\n");
WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
}
#endif
#if SOLID_CACHE
/******************************************************************************
* *
* Name: CacheSolid *
* *
* Function: Convert a solid color into a colored brush for use when a *
* monochrome source blt requires a solid brush. This will speed *
* up WinBench 96 tests 5 and 9. *
* *
******************************************************************************/
void CacheSolid(PPDEV ppdev)
{
PBYTE pjBrush = ppdev->Stable[ppdev->SNext].pjLinear;
ULONG color = ppdev->Stable[ppdev->SNext].ulColor;
int i, j;
switch (ppdev->iBitmapFormat)
{
case BMF_8BPP:
for (i = 0; i < 64; i += 4)
{
// Remember, the color is already expanded!
*(ULONG *) &pjBrush[i] = color;
}
break;
case BMF_16BPP:
for (i = 0; i < 128; i += 4)
{
// Remember, the color is already expanded!
*(ULONG *) &pjBrush[i] = color;
}
break;
case BMF_24BPP:
for (j = 0; j < 4; j++)
{
for (i = 0; i < 24; i += 3)
{
*(ULONG *) &pjBrush[i] = color;
}
*(ULONG *) &pjBrush[i + 0] = *(ULONG *) &pjBrush[0];
*(ULONG *) &pjBrush[i + 4] = *(ULONG *) &pjBrush[4];
pjBrush += 32;
}
pjBrush += ppdev->lDeltaScreen - 128;
for (j = 0; j < 4; j++)
{
for (i = 0; i < 24; i += 3)
{
*(ULONG *) &pjBrush[i] = color;
}
*(ULONG *) &pjBrush[i + 0] = *(ULONG *) &pjBrush[0];
*(ULONG *) &pjBrush[i + 4] = *(ULONG *) &pjBrush[4];
pjBrush += 32;
}
break;
case BMF_32BPP:
for (i = 0; i < 128; i += 4)
{
*(ULONG *) &pjBrush[i] = color;
}
pjBrush += ppdev->lDeltaScreen;
for (i = 0; i < 128; i += 4)
{
*(ULONG *) &pjBrush[i] = color;
}
break;
}
REQUIRE(2);
LL32(grOP2_opMRDRAM, ppdev->Stable[ppdev->SNext].xy);
ppdev->SNext = (ppdev->SNext + 1) % NUM_SOLID_BRUSHES;
}
#endif
#if DBG
//
// The rest of this file is debugging functions.
//
/* --------------------------------------------------------------------*\
| |
| PrintBrush() |
| Dump a 1 bpp brush as 'X's and ' 's to the debuger so we can see what |
| it looks like. |
| |
| We don't currently use this, but it can be useful to have for |
| debugging purposes. |
| |
\*---------------------------------------------------------------------*/
void PrintBrush(
SURFOBJ *psoPattern
)
{
int i,j;
char c;
// Only do this for 1bpp brushes.
if (psoPattern->iBitmapFormat != BMF_1BPP)
return;
DISPDBG((BRUSH_DBG_LEVEL,"Brush information:\n"));
DISPDBG((BRUSH_DBG_LEVEL,"Brush delta is %d bytes.\n",psoPattern->lDelta));
DISPDBG((BRUSH_DBG_LEVEL,"Brush uses %d bytes.\n",psoPattern->cjBits));
DISPDBG((BRUSH_DBG_LEVEL,"Brush bits are at 0x%08X.\n",psoPattern->pvBits));
DISPDBG((BRUSH_DBG_LEVEL,"Scan 0 is at 0x%08X.\n",psoPattern->pvScan0));
if (psoPattern->fjBitmap & BMF_TOPDOWN)
DISPDBG((BRUSH_DBG_LEVEL,"Brush is top down.\n",psoPattern->pvScan0));
else
DISPDBG((BRUSH_DBG_LEVEL,"Brush is bottom up.\n",psoPattern->pvScan0));
DISPDBG((BRUSH_DBG_LEVEL,"PATTERN:\n"));
for (i=0; i<8; ++i)
{
c = (unsigned char)((long*)psoPattern->pvBits)[i];
DISPDBG((BRUSH_DBG_LEVEL,"'"));
for (j=7; (7>=j && j>=0) ; --j)
{
if (c&1)
DISPDBG((BRUSH_DBG_LEVEL,"X"));
else
DISPDBG((BRUSH_DBG_LEVEL," "));
c = c >> 1;
}
DISPDBG((BRUSH_DBG_LEVEL,"'\n"));
}
}
//
// ===========================================================================
// Dumps all kind of cool stuff about realized brushes to the debugger.
//
// Here's the realized brush structure:
/*
typedef struct {
ULONG nPatSize;
ULONG iBitmapFormat;
ULONG ulForeColor;
ULONG ulBackColor;
ULONG isCached; // 1 if this brush is cached, 0 if not.
ULONG cache_slot; // Slot number of cache table entry.
ULONG cache_x; // These are the (x,y) location of
ULONG cache_y; // the cached brush from screen(0,0)
ULONG cjMask; // offset to mask bits in ajPattern[]
BYTE ajPattern[1]; // pattern bits followed by mask bits
} RBRUSH, *PRBRUSH;
*/
// ============================================================================
//
void PrintRealizedBrush(
PRBRUSH pRbrush)
{
int i,j;
char c;
// Only do this for 1bpp brushes.
if (pRbrush->iBitmapFormat != BMF_1BPP)
return;
DISPDBG((BRUSH_DBG_LEVEL,"\nRealized brush information:\n"));
DISPDBG((BRUSH_DBG_LEVEL,"Brush colors: FG = 0x%08X BG = 0x%08X \n",
pRbrush->ulForeColor, pRbrush->ulForeColor));
DISPDBG((BRUSH_DBG_LEVEL,"Brush pattern size is %d bytes.\n",
pRbrush->nPatSize));
DISPDBG((BRUSH_DBG_LEVEL,"PATTERN:\n"));
for (i=0; i<8; ++i)
{
c = pRbrush->ajPattern[i];
DISPDBG((BRUSH_DBG_LEVEL,"'"));
for (j=7; (7>=j && j>=0) ; --j)
{
if (c&1)
DISPDBG((BRUSH_DBG_LEVEL,"X"));
else
DISPDBG((BRUSH_DBG_LEVEL," "));
c = c >> 1;
}
DISPDBG((BRUSH_DBG_LEVEL,"'\n"));
}
DISPDBG((BRUSH_DBG_LEVEL,"\n"));
}
#endif