1075 lines
34 KiB
C
1075 lines
34 KiB
C
/******************************************************************************\
|
||
*
|
||
* $Workfile: brush.c $
|
||
*
|
||
* Handles all brush/pattern initialization and realization.
|
||
*
|
||
* Copyright (c) 1992-1995 Microsoft Corporation
|
||
* Copyright (c) 1996 Cirrus Logic, Inc.
|
||
*
|
||
* $Log: S:/projects/drivers/ntsrc/display/brush.c_v $
|
||
*
|
||
* Rev 1.3 Nov 26 1996 14:28:48 unknown
|
||
* Use second aperture for blt.
|
||
*
|
||
* Rev 1.2 Nov 07 1996 16:44:50 unknown
|
||
* Clean up CAPS flags
|
||
*
|
||
* Rev 1.1 Oct 10 1996 15:36:16 unknown
|
||
*
|
||
*
|
||
* Rev 1.5 13 Aug 1996 11:55:34 frido
|
||
* Fixed misalignment in brush cache.
|
||
*
|
||
* Rev 1.4 12 Aug 1996 17:08:08 frido
|
||
* Commented brush cache.
|
||
* Removed unaccessed local variables.
|
||
*
|
||
* Rev 1.3 05 Aug 1996 11:17:50 frido
|
||
* Added more check for XLATEOBJ.
|
||
*
|
||
* Rev 1.2 31 Jul 1996 15:43:28 frido
|
||
* Added new brush caches.
|
||
*
|
||
* jl01 10-08-96 Do Transparent BLT w/o Solid Fill. Refer to PDRs#5511/6817.
|
||
*
|
||
* sge01 11/26/96 Use second aperture when doing 24bpp cache blt.
|
||
*
|
||
*
|
||
\******************************************************************************/
|
||
|
||
#include "precomp.h"
|
||
|
||
//bc#1 Handy macros.
|
||
#define BUSY_BLT(ppdev, pjBase) (CP_MM_ACL_STAT(ppdev, pjBase) & 0x10)
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vRealizeDitherPattern
|
||
*
|
||
* Generates an 8x8 dither pattern, in our internal realization format, for
|
||
* the color ulRGBToDither. Note that the high byte of ulRGBToDither does
|
||
* not need to be set to zero, because vComputeSubspaces ignores it.
|
||
\**************************************************************************/
|
||
|
||
VOID vRealizeDitherPattern(
|
||
RBRUSH* prb,
|
||
ULONG ulRGBToDither)
|
||
{
|
||
ULONG ulNumVertices;
|
||
VERTEX_DATA vVertexData[4];
|
||
VERTEX_DATA* pvVertexData;
|
||
|
||
// Calculate what color subspaces are involved in the dither:
|
||
|
||
pvVertexData = vComputeSubspaces(ulRGBToDither, vVertexData);
|
||
|
||
// Now that we have found the bounding vertices and the number of
|
||
// pixels to dither for each vertex, we can create the dither pattern
|
||
|
||
ulNumVertices = (ULONG)(pvVertexData - vVertexData);
|
||
// # of vertices with more than zero pixels in the dither
|
||
|
||
// Do the actual dithering:
|
||
|
||
vDitherColor(&prb->aulPattern[0], vVertexData, pvVertexData, ulNumVertices);
|
||
|
||
// Initialize the fields we need:
|
||
|
||
prb->ptlBrushOrg.x = LONG_MIN;
|
||
prb->fl = 0;
|
||
prb->pbe = NULL;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL DrvRealizeBrush
|
||
*
|
||
* This function allows us to convert GDI brushes into an internal form
|
||
* we can use. It may be called directly by GDI at SelectObject time, or
|
||
* it may be called by GDI as a result of us calling BRUSHOBJ_pvGetRbrush
|
||
* to create a realized brush in a function like DrvBitBlt.
|
||
*
|
||
* Note that we have no way of determining what the current Rop or brush
|
||
* alignment are at this point.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL DrvRealizeBrush(
|
||
BRUSHOBJ* pbo,
|
||
SURFOBJ* psoDst,
|
||
SURFOBJ* psoPattern,
|
||
SURFOBJ* psoMask,
|
||
XLATEOBJ* pxlo,
|
||
ULONG iHatch)
|
||
{
|
||
ULONG iPatternFormat;
|
||
BYTE* pjSrc;
|
||
BYTE* pjDst;
|
||
LONG lSrcDelta;
|
||
LONG cj;
|
||
LONG i;
|
||
LONG j;
|
||
RBRUSH* prb;
|
||
ULONG* pulXlate;
|
||
SURFOBJ* psoPunt;
|
||
RECTL rclDst;
|
||
FLONG flXlate; //bc#1
|
||
|
||
PDEV* ppdev = (PPDEV)psoDst->dhpdev;
|
||
|
||
#if 1 //bc#1 Dither cache.
|
||
// Dithers...
|
||
if (iHatch & RB_DITHERCOLOR)
|
||
{
|
||
if (ppdev->flStatus & STAT_DITHER_CACHE)
|
||
{
|
||
DITHERCACHE* pdc;
|
||
ULONG ulColor;
|
||
|
||
// Save the color.
|
||
ulColor = iHatch & 0xFFFFFF;
|
||
|
||
// Allocate the brush.
|
||
prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH));
|
||
if (prb == NULL)
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Set the dithered brush flags.
|
||
prb->fl = RBRUSH_DITHER;
|
||
prb->ulUniq = ulColor;
|
||
|
||
// Look for a match with the cached dithers.
|
||
pdc = &ppdev->aDithers[0];
|
||
for (i = 0; i < NUM_DITHERS; i++)
|
||
{
|
||
if (pdc->ulColor == ulColor)
|
||
{
|
||
// We have a match, just set the brush pointers.
|
||
DISPDBG((20, "DrvRealizeBrush: DitherCache match (0x%06X)",
|
||
ulColor));
|
||
prb->ulSlot = (ULONG)((ULONG_PTR)pdc - (ULONG_PTR)ppdev);
|
||
prb->ulBrush = pdc->ulBrush;
|
||
return(TRUE);
|
||
}
|
||
pdc++;
|
||
}
|
||
|
||
// Create the dither and cache it.
|
||
return(bCacheDither(ppdev, prb));
|
||
}
|
||
|
||
if (!(ppdev->flStatus & (STAT_BRUSH_CACHE | STAT_PATTERN_CACHE)))
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: No brush cache to create dither"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Allocate the brush.
|
||
prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) +
|
||
PELS_TO_BYTES(TOTAL_BRUSH_SIZE));
|
||
if (prb == NULL)
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Realize the dither.
|
||
vRealizeDitherPattern(prb, iHatch);
|
||
if (ppdev->flStatus & STAT_PATTERN_CACHE)
|
||
{
|
||
prb->cjBytes = PELS_TO_BYTES(8) * 8;
|
||
prb->ulSlot = 0;
|
||
return(bCachePattern(ppdev, prb));
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
#endif
|
||
|
||
// We only accelerate 8x8 patterns.
|
||
if ((psoPattern->sizlBitmap.cx != 8) || (psoPattern->sizlBitmap.cy != 8))
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: psoPattern too big (%d x %d)",
|
||
psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
|
||
return(FALSE);
|
||
}
|
||
|
||
// We don't support masks just yet.
|
||
if ((psoMask != NULL) && (psoMask->pvScan0 != psoPattern->pvScan0))
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: psoMask not supported"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Get the brush type.
|
||
iPatternFormat = psoPattern->iBitmapFormat;
|
||
if (psoPattern->iType != STYPE_BITMAP)
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: psoPattern->iType (=%d) not supported",
|
||
psoPattern->iType));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Get the color translation table.
|
||
flXlate = (pxlo == NULL) ? XO_TRIVIAL : pxlo->flXlate;
|
||
if (flXlate & XO_TRIVIAL)
|
||
{
|
||
pulXlate = NULL;
|
||
}
|
||
else if (flXlate & XO_TABLE)
|
||
{
|
||
pulXlate = pxlo->pulXlate;
|
||
}
|
||
else
|
||
{
|
||
pulXlate = XLATEOBJ_piVector(pxlo);
|
||
}
|
||
|
||
#if 1 //bc#1 Monochrome cache.
|
||
if ((iPatternFormat == BMF_1BPP) &&
|
||
(ppdev->flStatus & STAT_MONOCHROME_CACHE))
|
||
{
|
||
MONOCACHE* pmc;
|
||
|
||
// We need a translation table.
|
||
if (pulXlate == NULL)
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: psoPattern(monochrome) pxlo=NULL"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Allocate the brush.
|
||
prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) + 8);
|
||
if (prb == NULL)
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Initialize the realized brush.
|
||
prb->fl = RBRUSH_MONOCHROME;
|
||
prb->ulBackColor = pulXlate[0];
|
||
prb->ulForeColor = pulXlate[1];
|
||
|
||
pjSrc = psoPattern->pvScan0;
|
||
lSrcDelta = psoPattern->lDelta;
|
||
|
||
// Copy the pattern to the realized brush.
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
((BYTE*) prb->aulPattern)[i] = *pjSrc;
|
||
|
||
pjSrc += lSrcDelta;
|
||
}
|
||
|
||
// Lookup the pattern in te monochrome cache.
|
||
pmc = &ppdev->aMonochromes[0];
|
||
if (ppdev->cBpp == 3)
|
||
{
|
||
for (i = 0; i < NUM_MONOCHROMES; i++)
|
||
{
|
||
if ((pmc->aulPattern[0] == prb->aulPattern[0]) &&
|
||
(pmc->aulPattern[1] == prb->aulPattern[1]) &&
|
||
(pmc->ulBackColor == prb->ulBackColor) &&
|
||
(pmc->ulForeColor == prb->ulForeColor))
|
||
{
|
||
// We have a match! Just copy the brush pointers.
|
||
DISPDBG((20, "DrvRealizeBrush: Monochrome hit"));
|
||
prb->ulUniq = pmc->ulUniq;
|
||
prb->ulSlot = (ULONG)((ULONG_PTR)pmc - (ULONG_PTR)ppdev);
|
||
prb->ulBrush = pmc->ulBrush;
|
||
return(TRUE);
|
||
}
|
||
pmc++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (i = 0; i < NUM_MONOCHROMES; i++)
|
||
{
|
||
if ((pmc->aulPattern[0] == prb->aulPattern[0]) &&
|
||
(pmc->aulPattern[1] == prb->aulPattern[1]))
|
||
{
|
||
// We have a match! Just copy the brush pointers.
|
||
DISPDBG((20, "DrvRealizeBrush: Monochrome hit"));
|
||
prb->ulUniq = pmc->ulUniq;
|
||
prb->ulSlot = (ULONG)((ULONG_PTR)pmc - (ULONG_PTR)ppdev);
|
||
prb->ulBrush = pmc->ulBrush;
|
||
return(TRUE);
|
||
}
|
||
pmc++;
|
||
}
|
||
}
|
||
|
||
return(bCacheMonochrome(ppdev, prb));
|
||
}
|
||
#endif
|
||
|
||
// We must have either an old-style brush cache or a new-style pattern
|
||
// cache to continue.
|
||
if (!(ppdev->flStatus & (STAT_BRUSH_CACHE | STAT_PATTERN_CACHE)))
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: No brush cache"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Allocate the brush.
|
||
prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) +
|
||
PELS_TO_BYTES(TOTAL_BRUSH_SIZE));
|
||
if (prb == NULL)
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
|
||
return(FALSE);
|
||
}
|
||
|
||
// Initialize the realized brush.
|
||
prb->ptlBrushOrg.x = LONG_MIN;
|
||
prb->fl = RBRUSH_PATTERN;
|
||
prb->pbe = NULL;
|
||
|
||
lSrcDelta = psoPattern->lDelta;
|
||
pjSrc = (BYTE*) psoPattern->pvScan0;
|
||
pjDst = (BYTE*) &prb->aulPattern[0];
|
||
|
||
//bc#1
|
||
if ((ppdev->iBitmapFormat == iPatternFormat) && (flXlate & XO_TRIVIAL))
|
||
{
|
||
// The pattern is the same color depth as the screen, and there's no
|
||
// translation to be done.
|
||
cj = PELS_TO_BYTES(8);
|
||
|
||
// Copy the pattern to the realized brush.
|
||
for (i = 8; i != 0; i--)
|
||
{
|
||
RtlCopyMemory(pjDst, pjSrc, cj);
|
||
|
||
pjSrc += lSrcDelta;
|
||
pjDst += cj;
|
||
}
|
||
}
|
||
else if ((iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
|
||
{
|
||
// Translate the 16-color brush.
|
||
for (i = 8; i != 0; i--)
|
||
{
|
||
// Inner loop is repeated only 4 times because each loop handles 2
|
||
// pixels.
|
||
for (j = 4; j != 0; j--)
|
||
{
|
||
*pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
|
||
*pjDst++ = (BYTE) pulXlate[*pjSrc & 0x0F];
|
||
pjSrc++;
|
||
}
|
||
|
||
pjSrc += lSrcDelta - 4;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// We've got a brush whose format we haven't special cased. No problem,
|
||
// we can have GDI convert it to our device's format. We simply use a
|
||
// temporary surface object that was created with the same format as
|
||
// the display, and point it to our brush realization.
|
||
psoPunt = ppdev->psoBank;
|
||
psoPunt->pvScan0 = pjDst;
|
||
psoPunt->lDelta = PELS_TO_BYTES(8);
|
||
|
||
rclDst.left = 0;
|
||
rclDst.top = 0;
|
||
rclDst.right = 8;
|
||
rclDst.bottom = 8;
|
||
|
||
if (!EngCopyBits(psoPunt, psoPattern, NULL, pxlo, &rclDst,
|
||
(POINTL*) &rclDst))
|
||
{
|
||
DISPDBG((2, "DrvRealizeBrush: Unable to create funky brush"));
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
#if 1 //bc#1
|
||
// If we have a pattern cache, cache the brush now.
|
||
if (ppdev->flStatus & STAT_PATTERN_CACHE)
|
||
{
|
||
prb->cjBytes = PELS_TO_BYTES(8) * 8;
|
||
return(bCachePattern(ppdev, prb));
|
||
}
|
||
#endif
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL bEnableBrushCache
|
||
*
|
||
* Allocates off-screen memory for storing the brush cache.
|
||
\**************************************************************************/
|
||
|
||
BOOL bEnableBrushCache(
|
||
PDEV* ppdev)
|
||
{
|
||
OH* poh; // Points to off-screen chunk of memory
|
||
BRUSHENTRY* pbe; // Pointer to the brush-cache entry
|
||
LONG i;
|
||
LONG cBrushAlign; // 0 = no alignment,
|
||
// n = align to n pixels
|
||
LONG x;
|
||
LONG y;
|
||
|
||
#if 1 //bc#1 Dither cache.
|
||
if ((ppdev->cBpp == 1) &&
|
||
(ppdev->flCaps & CAPS_AUTOSTART) &&
|
||
(ppdev->bLinearMode))
|
||
{
|
||
LONG lDelta;
|
||
|
||
// Allocate the dither cache horizontally.
|
||
poh = pohAllocatePermanent(ppdev, 64 * NUM_DITHERS + 63, 1);
|
||
lDelta = 64;
|
||
if (poh == NULL)
|
||
{
|
||
// Allocate the dither cache vertically.
|
||
poh = pohAllocatePermanent(ppdev, 64 + 63, NUM_DITHERS);
|
||
lDelta = ppdev->lDelta;
|
||
}
|
||
|
||
if (poh != NULL)
|
||
{
|
||
// Align the cache to a 64-byte boundary.
|
||
ULONG ulBase = (poh->xy + 63) & ~63;
|
||
|
||
// Initialize the dither cache.
|
||
DISPDBG((4, "DitherCache allocated at %d,%d (%d x %d)",
|
||
poh->x, poh->y, poh->cx, poh->cy));
|
||
for (i = 0; i < NUM_DITHERS; i++)
|
||
{
|
||
ppdev->aDithers[i].ulColor = (ULONG) -1;
|
||
ppdev->aDithers[i].ulBrush = ulBase;
|
||
|
||
ulBase += lDelta;
|
||
}
|
||
|
||
// The dither cache has been initialized.
|
||
ppdev->iDitherCache = 0;
|
||
ppdev->flStatus |= STAT_DITHER_CACHE;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if 1 //bc#1 Pattern cache.
|
||
if ((ppdev->flCaps & CAPS_AUTOSTART) &&
|
||
(ppdev->bLinearMode))
|
||
{
|
||
LONG lDelta;
|
||
LONG cBrushSize;
|
||
ULONG ulAlignment;
|
||
|
||
// Calculate the width of brush in pixels.
|
||
if (ppdev->cBpp == 3)
|
||
{
|
||
cBrushSize = (256 + 2) / 3;
|
||
ulAlignment = 256;
|
||
}
|
||
else
|
||
{
|
||
cBrushSize = 64;
|
||
ulAlignment = PELS_TO_BYTES(64);
|
||
}
|
||
|
||
// Allocate the pattern cache horizontally.
|
||
poh = pohAllocatePermanent(ppdev, cBrushSize * NUM_PATTERNS +
|
||
(cBrushSize - 1), 1);
|
||
lDelta = ulAlignment;
|
||
if (poh == NULL)
|
||
{
|
||
// Allocate the pattern cache vertically.
|
||
poh = pohAllocatePermanent(ppdev, cBrushSize + (cBrushSize - 1),
|
||
NUM_PATTERNS);
|
||
lDelta = ppdev->lDelta;
|
||
}
|
||
|
||
if (poh != NULL)
|
||
{
|
||
// Align the cache to a 64-pixel boundary.
|
||
ULONG ulBase = (poh->xy + (ulAlignment - 1)) & ~(ulAlignment - 1);
|
||
|
||
// Initialize the pattern cache.
|
||
DISPDBG((4, "PatternCache allocated at %d,%d (%d x %d)",
|
||
poh->x, poh->y, poh->cx, poh->cy));
|
||
for (i = 0; i < NUM_PATTERNS; i++)
|
||
{
|
||
ppdev->aPatterns[i].ulBrush = ulBase;
|
||
ppdev->aPatterns[i].prbUniq = NULL;
|
||
|
||
ulBase += lDelta;
|
||
}
|
||
|
||
// The pattern cache has been initialized.
|
||
ppdev->iPatternCache = 0;
|
||
ppdev->flStatus |= STAT_PATTERN_CACHE;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if 1 //bc#1 Monochrome cache.
|
||
if ((ppdev->flCaps & CAPS_AUTOSTART) &&
|
||
(ppdev->bLinearMode))
|
||
{
|
||
LONG lDelta;
|
||
LONG cBrushSize;
|
||
ULONG ulAlignment;
|
||
|
||
// Calculate the width of brush in pixels.
|
||
if (ppdev->cBpp == 3)
|
||
{
|
||
cBrushSize = (256 + 2) / 3;
|
||
ulAlignment = 256;
|
||
}
|
||
else
|
||
{
|
||
cBrushSize = BYTES_TO_PELS(8);
|
||
ulAlignment = 8;
|
||
}
|
||
|
||
// Allocate the pattern cache horizontally.
|
||
poh = pohAllocatePermanent(ppdev, cBrushSize * NUM_MONOCHROMES +
|
||
(cBrushSize - 1), 1);
|
||
lDelta = ulAlignment;
|
||
if (poh == NULL)
|
||
{
|
||
// Allocate the pattern cache vertically.
|
||
poh = pohAllocatePermanent(ppdev, cBrushSize + (cBrushSize - 1),
|
||
NUM_MONOCHROMES);
|
||
lDelta = ppdev->lDelta;
|
||
}
|
||
|
||
if (poh != NULL)
|
||
{
|
||
// Align the cache to an 8-byte boundary.
|
||
ULONG ulBase = (poh->xy + (ulAlignment - 1)) & ~(ulAlignment - 1);
|
||
|
||
// Initialize the monochrome cache.
|
||
DISPDBG((4, "MonochromeCache allocated at %d,%d (%d x %d)",
|
||
poh->x, poh->y, poh->cx, poh->cy));
|
||
for (i = 0; i < NUM_MONOCHROMES; i++)
|
||
{
|
||
ppdev->aMonochromes[i].ulBrush = ulBase;
|
||
ppdev->aMonochromes[i].aulPattern[0] = 0;
|
||
ppdev->aMonochromes[i].aulPattern[1] = 0;
|
||
|
||
ulBase += lDelta;
|
||
}
|
||
|
||
// The monochrome cache has been initialized.
|
||
ppdev->iMonochromeCache = 0;
|
||
ppdev->flStatus |= STAT_MONOCHROME_CACHE;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
cBrushAlign = 64; // Align all brushes to 64 pixels
|
||
|
||
DISPDBG((2, "cBrushAlign = %d", cBrushAlign));
|
||
|
||
pbe = &ppdev->abe[0]; // Points to where we'll put the first
|
||
// brush cache entry
|
||
|
||
{
|
||
|
||
// Reserve the offscreen space that is required for the CP to do
|
||
// solid fills. If this fails, our solid fill code will not work.
|
||
// We need two DWORD storage locations if we're going to do any
|
||
// monochrome expansion stuff (font painting...).
|
||
|
||
// Note: these must be 8 byte aligned for the cirrus chips
|
||
|
||
// Not having a solid color work area is a
|
||
// fatal error for this driver.
|
||
|
||
DISPDBG((2,"Allocating solid brush work area"));
|
||
poh = pohAllocatePermanent(ppdev, 16, 1);
|
||
|
||
ASSERTDD((poh != NULL),
|
||
"We couldn't allocate offscreen space for the solid colors");
|
||
|
||
ppdev->ulSolidColorOffset = ((((poh->y * ppdev->lDelta) +
|
||
PELS_TO_BYTES(poh->x)) + 7) & ~7);
|
||
|
||
DISPDBG((2,"ppdev->ulSolidColorOffset = %xh", ppdev->ulSolidColorOffset));
|
||
|
||
|
||
#if 1 //bc#1 Only one pattern cache.
|
||
if (ppdev->flStatus & STAT_PATTERN_CACHE)
|
||
{
|
||
goto ReturnTrue;
|
||
}
|
||
#endif
|
||
|
||
///////////////////////////////////////////////////////////////////////
|
||
// Special cases where we want no brush cache...
|
||
//
|
||
// There are a couple of instances where we have no xfer buffer to
|
||
// the HW blt engine. In that case, we are unable to realize
|
||
// patterns, so don't enable the cache.
|
||
//
|
||
// (1) NEC Mips nachines lock up on xfers, so they're diabled.
|
||
// (2) At 1280x1024 on a 2MB card, we currently have no room for
|
||
// the buffer because of stretched scans. This will be fixed.
|
||
|
||
{
|
||
if (ppdev->pulXfer == NULL)
|
||
goto ReturnTrue;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate single brush location for intermediate alignment purposes
|
||
//
|
||
#if 1 //bc#1
|
||
if (ppdev->cBpp == 3)
|
||
{
|
||
poh = pohAllocatePermanent(ppdev,
|
||
(8 * 8 * 4) / 3 + (cBrushAlign - 1), 1);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
poh = pohAllocatePermanent(ppdev, (8 * 8) + (cBrushAlign - 1), 1);
|
||
}
|
||
|
||
if (poh == NULL)
|
||
{
|
||
DISPDBG((2,"Failed to allocate aligned brush area"));
|
||
goto ReturnTrue; // See note about why we can return TRUE...
|
||
}
|
||
ppdev->ulAlignedPatternOffset = ((poh->xy) +
|
||
(PELS_TO_BYTES(cBrushAlign) - 1)) &
|
||
~(PELS_TO_BYTES(cBrushAlign) - 1);
|
||
DISPDBG((2,"ppdev->ulAlignedPatternOffset = %xh", ppdev->ulAlignedPatternOffset));
|
||
|
||
//
|
||
// Allocate brush cache
|
||
//
|
||
|
||
#if 1 //bc#1
|
||
if (ppdev->cBpp == 3)
|
||
{
|
||
poh = pohAllocatePermanent(ppdev,
|
||
(BRUSH_TILE_FACTOR * 8 * 8 * 4) / 3 + cBrushAlign - 1,
|
||
FAST_BRUSH_COUNT);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
poh = pohAllocatePermanent(ppdev,
|
||
// remember this is pixels, not bytes
|
||
(BRUSH_TILE_FACTOR * 8 * 8) + (cBrushAlign - 1),
|
||
FAST_BRUSH_COUNT);
|
||
}
|
||
|
||
if (poh == NULL)
|
||
{
|
||
DISPDBG((2,"Failed to allocate brush cache"));
|
||
goto ReturnTrue; // See note about why we can return TRUE...
|
||
}
|
||
|
||
ppdev->cBrushCache = FAST_BRUSH_COUNT;
|
||
|
||
// Hardware brushes require that the bits start on a 64 (height*width)
|
||
// pixel boundary. The heap manager doesn't guarantee us any such
|
||
// alignment, so we allocate a bit of extra room so that we can
|
||
// do the alignment ourselves:
|
||
|
||
x = poh->x;
|
||
y = poh->y;
|
||
|
||
for (i = FAST_BRUSH_COUNT; i != 0; i--)
|
||
{
|
||
ULONG ulOffset;
|
||
ULONG ulCeil;
|
||
ULONG ulDiff;
|
||
|
||
// Note: I learned the HARD way that you can't just align x
|
||
// to your pattern size, because the lDelta of your screen
|
||
// is not guaranteed to be a multiple of your pattern size.
|
||
// Since y is changing in this loop, the recalc must
|
||
// be done inside this loop. I really need to set these
|
||
// up with a hardcoded linear buffer or else make the
|
||
// heap linear.
|
||
|
||
ulOffset = (y * ppdev->lDelta) + PELS_TO_BYTES(x);
|
||
ulCeil = (ulOffset + (PELS_TO_BYTES(cBrushAlign)-1)) & ~(PELS_TO_BYTES(cBrushAlign)-1);
|
||
ulDiff = (ulCeil - ulOffset)/ppdev->cBpp;
|
||
|
||
// If we hadn't allocated 'ppdev' with FL_ZERO_MEMORY,
|
||
// we would have to initialize pbe->prbVerify too...
|
||
|
||
pbe->x = x + ulDiff;
|
||
pbe->y = y;
|
||
pbe->xy = (pbe->y * ppdev->lDelta) + PELS_TO_BYTES(pbe->x);
|
||
|
||
DISPDBG((2, "BrushCache[%d] pos(%d,%d) offset(%d)", i, pbe->x,
|
||
pbe->y, pbe->xy ));
|
||
|
||
y++;
|
||
pbe++;
|
||
}
|
||
}
|
||
|
||
// Note that we don't have to remember 'poh' for when we have
|
||
// to disable brushes -- the off-screen heap frees any
|
||
// off-screen heap allocations automatically.
|
||
|
||
// We successfully allocated the brush cache, so let's turn
|
||
// on the switch showing that we can use it:
|
||
|
||
ppdev->flStatus |= STAT_BRUSH_CACHE;
|
||
|
||
ReturnTrue:
|
||
|
||
// If we couldn't allocate a brush cache, it's not a catastrophic
|
||
// failure; patterns will still work, although they'll be a bit
|
||
// slower since they'll go through GDI. As a result we don't
|
||
// actually have to fail this call:
|
||
|
||
vAssertModeBrushCache(ppdev, TRUE);
|
||
|
||
DISPDBG((5, "Passed bEnableBrushCache"));
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vDisableBrushCache
|
||
*
|
||
* Cleans up anything done in bEnableBrushCache.
|
||
\**************************************************************************/
|
||
|
||
VOID vDisableBrushCache(PDEV* ppdev)
|
||
{
|
||
// We ain't gotta do nothin'
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vAssertModeBrushCache
|
||
*
|
||
* Resets the brush cache when we exit out of full-screen.
|
||
\**************************************************************************/
|
||
|
||
VOID vAssertModeBrushCache(
|
||
PDEV* ppdev,
|
||
BOOL bEnable)
|
||
{
|
||
BRUSHENTRY* pbe;
|
||
LONG i;
|
||
|
||
if (bEnable)
|
||
{
|
||
//bc#1 Invalidate the dither cache.
|
||
if (ppdev->flStatus & STAT_DITHER_CACHE)
|
||
{
|
||
for (i = 0; i < NUM_DITHERS; i++)
|
||
{
|
||
ppdev->aDithers[i].ulColor = (ULONG) -1;
|
||
}
|
||
}
|
||
|
||
//bc#1 Invalidate the pattern cache.
|
||
if (ppdev->flStatus & STAT_PATTERN_CACHE)
|
||
{
|
||
for (i = 0; i < NUM_PATTERNS; i++)
|
||
{
|
||
ppdev->aPatterns[i].prbUniq = NULL;
|
||
}
|
||
}
|
||
|
||
//bc#1 Invalidate the monochrome cache.
|
||
if (ppdev->flStatus & STAT_MONOCHROME_CACHE)
|
||
{
|
||
for (i = 0; i < NUM_MONOCHROMES; i++)
|
||
{
|
||
ppdev->aMonochromes[i].ulUniq = 0;
|
||
ppdev->aMonochromes[i].aulPattern[0] = 0;
|
||
ppdev->aMonochromes[i].aulPattern[1] = 0;
|
||
}
|
||
}
|
||
|
||
// Invalidate the brush cache.
|
||
if (ppdev->flStatus & STAT_BRUSH_CACHE)
|
||
{
|
||
pbe = &ppdev->abe[0];
|
||
|
||
for (i = ppdev->cBrushCache; i != 0; i--)
|
||
{
|
||
pbe->prbVerify = NULL;
|
||
pbe++;
|
||
}
|
||
}
|
||
|
||
// Create a solid 8 x 8 monochrome bitmap in offscreen memory which
|
||
// will be used for solid fills.
|
||
if (ppdev->flCaps & CAPS_MM_IO)
|
||
{
|
||
BYTE* pjBase = ppdev->pjBase;
|
||
|
||
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
|
||
CP_MM_XCNT(ppdev, pjBase, 7);
|
||
CP_MM_YCNT(ppdev, pjBase, 0);
|
||
CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0);
|
||
CP_MM_BLT_MODE(ppdev, pjBase, 0);
|
||
CP_MM_ROP(ppdev, pjBase, CL_WHITENESS);
|
||
CP_MM_DST_ADDR_ABS(ppdev, pjBase, ppdev->ulSolidColorOffset);
|
||
CP_MM_START_BLT(ppdev, pjBase);
|
||
}
|
||
else
|
||
{
|
||
BYTE* pjPorts = ppdev->pjPorts;
|
||
|
||
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);
|
||
CP_IO_XCNT(ppdev, pjPorts, 7);
|
||
CP_IO_YCNT(ppdev, pjPorts, 0);
|
||
CP_IO_BLT_MODE(ppdev, pjPorts, 0);
|
||
CP_IO_ROP(ppdev, pjPorts, CL_WHITENESS);
|
||
CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ppdev->ulSolidColorOffset);
|
||
CP_IO_START_BLT(ppdev, pjPorts);
|
||
}
|
||
}
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// B R U S H C A C H E S T U F F //
|
||
// //
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/*
|
||
Dither Cache:
|
||
============
|
||
The dither cache is very important (at least with a slow CPU). Since the
|
||
dithering process (in 8-bpp) takes quite a long time we must somehow cache
|
||
the dithering process so it doesn't have to be executed over and over again.
|
||
We do this by comparing the requested logical color with the cached dithers.
|
||
If we have a match we simply copy the cached parameters and return. If we
|
||
don't have a match we create a new cache slot and create the dither in
|
||
off-screen memory.
|
||
|
||
Pattern Cache:
|
||
=============
|
||
The pattern cache holds the colored brushes. Whenever we are requested to
|
||
realize the same brush again, we can simply return. We don't check for the
|
||
brush bits since that will take up too much time.
|
||
|
||
Monochrome Cache:
|
||
================
|
||
The monochrome cache holds the monochrome brushes. Whenever a monochrome
|
||
brush needs to be realized we check to see if it is already cached
|
||
off-screen. If it is we simply copy the cached parameters and return.
|
||
Otherwise we have to create a new cache slot and realize the monochrome
|
||
brush directly in off-screen memory. This has a slight performance hit since
|
||
the bitblt engine is interrupted (on CL5436) or must be idle (in 24-bpp).
|
||
|
||
Translation Cache:
|
||
=================
|
||
Is not yet implemented.
|
||
*/
|
||
|
||
/******************************************************************************\
|
||
*
|
||
* Function: bCacheDither
|
||
*
|
||
* Cache a dithered color.
|
||
*
|
||
* Parameters: ppdev Pointer to physicsl device.
|
||
* prb Pointer to physical brush.
|
||
*
|
||
* Returns: TRUE.
|
||
*
|
||
\******************************************************************************/
|
||
BOOL bCacheDither(
|
||
PDEV* ppdev,
|
||
RBRUSH* prb)
|
||
{
|
||
ULONG ulNumVertices;
|
||
VERTEX_DATA vVertexData[4];
|
||
VERTEX_DATA* pvVertexData;
|
||
DITHERCACHE* pdc;
|
||
ULONG ulIndex;
|
||
|
||
// New dither cache entry.
|
||
ulIndex = ppdev->iDitherCache++ % NUM_DITHERS;
|
||
pdc = &ppdev->aDithers[ulIndex];
|
||
|
||
// Store the color in the cache slot.
|
||
pdc->ulColor = prb->ulUniq;
|
||
|
||
// Update the brush cache variables.
|
||
prb->ulSlot = (ULONG)((ULONG_PTR)pdc - (ULONG_PTR)ppdev);
|
||
prb->ulBrush = pdc->ulBrush;
|
||
|
||
// Create the dither.
|
||
pvVertexData = vComputeSubspaces(prb->ulUniq, vVertexData);
|
||
ulNumVertices = (ULONG)(pvVertexData - vVertexData);
|
||
vDitherColorToVideoMemory((ULONG*) (ppdev->pjScreen + pdc->ulBrush), vVertexData,
|
||
pvVertexData, ulNumVertices);
|
||
|
||
DISPDBG((20, "Caching dithered brush ulIndex=%d ulColor=%06X",
|
||
ulIndex, pdc->ulColor));
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************************************************************\
|
||
*
|
||
* Function: bCacheColor
|
||
*
|
||
* Cache a patterned brush.
|
||
*
|
||
* Parameters: ppdev Pointer to physicsl device.
|
||
* prb Pointer to physical brush.
|
||
*
|
||
* Returns: TRUE.
|
||
*
|
||
\******************************************************************************/
|
||
BOOL bCachePattern(
|
||
PDEV* ppdev,
|
||
RBRUSH* prb
|
||
)
|
||
{
|
||
PATTERNCACHE* ppc;
|
||
LONG lDstDelta;
|
||
SIZEL sizlDst;
|
||
ULONG* pulSrc;
|
||
LONG i;
|
||
ULONG* pulDst;
|
||
ULONG ulIndex;
|
||
|
||
BYTE* pjBase = ppdev->pjBase;
|
||
|
||
// New pattern cache entry.
|
||
ulIndex = ppdev->iPatternCache++ % NUM_PATTERNS;
|
||
ppc = &ppdev->aPatterns[ulIndex];
|
||
|
||
// Update the brush cache variables.
|
||
ppc->prbUniq = prb;
|
||
prb->ulSlot = (ULONG)((ULONG_PTR)ppc - (ULONG_PTR)ppdev);
|
||
prb->ulBrush = ppc->ulBrush;
|
||
|
||
// Calculate the sizes for the pattern.
|
||
pulSrc = prb->aulPattern;
|
||
pulDst = (ULONG*) ppdev->pulXfer;
|
||
lDstDelta = (ppdev->cBpp == 3) ? (8 * 4) : PELS_TO_BYTES(8);
|
||
sizlDst.cx = PELS_TO_BYTES(8) - 1;
|
||
sizlDst.cy = 8 - 1;
|
||
|
||
// Wait for the bitblt engine.
|
||
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
|
||
|
||
// Setup the blit registers.
|
||
CP_MM_XCNT(ppdev, pjBase, sizlDst.cx);
|
||
CP_MM_YCNT(ppdev, pjBase, sizlDst.cy);
|
||
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDstDelta);
|
||
CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0);
|
||
CP_MM_BLT_MODE(ppdev, pjBase, SRC_CPU_DATA);
|
||
CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY);
|
||
CP_MM_DST_ADDR_ABS(ppdev, pjBase, ppc->ulBrush);
|
||
|
||
// Copy the brush to off-screen cache memory.
|
||
for (i = prb->cjBytes; i > 0; i -= sizeof(ULONG))
|
||
{
|
||
WRITE_REGISTER_ULONG(pulDst, *pulSrc++);
|
||
}
|
||
|
||
DISPDBG((20, "Caching patterned brush at slot %d", ulIndex));
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************************************************************\
|
||
*
|
||
* Function: bCacheMonochrome
|
||
*
|
||
* Cache a monochrome brush.
|
||
*
|
||
* Parameters: ppdev Pointer to physicsl device.
|
||
* prb Pointer to physical brush.
|
||
*
|
||
* Returns: TRUE.
|
||
*
|
||
\******************************************************************************/
|
||
BOOL bCacheMonochrome(
|
||
PDEV* ppdev,
|
||
RBRUSH* prb
|
||
)
|
||
{
|
||
MONOCACHE* pmc;
|
||
ULONG ulIndex;
|
||
BYTE* pjDst;
|
||
ULONG* pulDst;
|
||
|
||
// New monochrome cache entry.
|
||
ulIndex = ppdev->iMonochromeCache++ % NUM_MONOCHROMES;
|
||
pmc = &ppdev->aMonochromes[ulIndex];
|
||
|
||
// Update the brush cache variables.
|
||
pmc->aulPattern[0] = prb->aulPattern[0];
|
||
pmc->aulPattern[1] = prb->aulPattern[1];
|
||
|
||
pmc->ulUniq = ppdev->iMonochromeCache;
|
||
prb->ulUniq = ppdev->iMonochromeCache;
|
||
prb->ulSlot = (ULONG)((ULONG_PTR)pmc - (ULONG_PTR)ppdev);
|
||
prb->ulBrush = pmc->ulBrush;
|
||
|
||
// Copy the brush to off-screen cache memory.
|
||
if (ppdev->cBpp == 3)
|
||
{
|
||
BYTE* pjBase = ppdev->pjBase;
|
||
|
||
// Copy colors to brush cache.
|
||
pmc->ulBackColor = prb->ulBackColor;
|
||
pmc->ulForeColor = prb->ulForeColor;
|
||
|
||
pulDst = (ULONG*)ppdev->pulXfer;
|
||
|
||
// Wait for bitblt engine.
|
||
while (BUSY_BLT(ppdev, pjBase));
|
||
|
||
// Fill the background.
|
||
CP_MM_FG_COLOR(ppdev, pjBase, pmc->ulBackColor);
|
||
CP_MM_XCNT(ppdev, pjBase, (8 * 3) - 1);
|
||
CP_MM_YCNT(ppdev, pjBase, (8) - 1);
|
||
CP_MM_DST_Y_OFFSET(ppdev, pjBase, 8 * 4);
|
||
CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0);
|
||
CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_COLOR_EXPAND |
|
||
ENABLE_8x8_PATTERN_COPY |
|
||
SET_24BPP_COLOR);
|
||
CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY);
|
||
CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_SOLID_FILL);
|
||
CP_MM_DST_ADDR_ABS(ppdev, pjBase, pmc->ulBrush);
|
||
|
||
// Wait for bitblt engine.
|
||
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
|
||
|
||
// Expand the pattern.
|
||
CP_MM_FG_COLOR(ppdev, pjBase, pmc->ulForeColor);
|
||
CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_COLOR_EXPAND |
|
||
SET_24BPP_COLOR |
|
||
ENABLE_TRANSPARENCY_COMPARE |
|
||
SRC_CPU_DATA);
|
||
CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0) // jl01
|
||
CP_MM_DST_ADDR_ABS(ppdev, pjBase, pmc->ulBrush);
|
||
|
||
WRITE_REGISTER_ULONG(pulDst, pmc->aulPattern[0]);
|
||
WRITE_REGISTER_ULONG(pulDst, pmc->aulPattern[1]);
|
||
}
|
||
|
||
else
|
||
{
|
||
pulDst = (ULONG *)(ppdev->pjScreen + prb->ulBrush);
|
||
|
||
WRITE_REGISTER_ULONG(pulDst++, prb->aulPattern[0]);
|
||
WRITE_REGISTER_ULONG(pulDst, prb->aulPattern[1]);
|
||
}
|
||
|
||
DISPDBG((20, "Caching monochrome brush ulIndex=%d pattern=%08X%08X",
|
||
ulIndex, prb->aulPattern[0], prb->aulPattern[1]));
|
||
return(TRUE);
|
||
}
|