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.
 
 
 
 
 
 

491 lines
17 KiB

/******************************Module*Header*******************************\
*
* *******************
* * GDI SAMPLE CODE *
* *******************
*
* Module Name: brush.c
*
* Content: Handles all brush/pattern initialization and realization.
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
\**************************************************************************/
#include "precomp.h"
#include "heap.h"
//-----------------------------------------------------------------------------
//
// VOID vRealizeDitherPattern
//
// Generates an 8x8 dither pattern, in our internal realization format, for
// the colour ulRGBToDither.
//
//-----------------------------------------------------------------------------
VOID
vRealizeDitherPattern(HDEV hdev,
RBrush* prb,
ULONG ulRGBToDither)
{
//
// Do the actual dithering
// Note: This function is NT5 only. If you want to write a NT4 driver,
// you have to implement dither function in the driver
//
EngDitherColor(hdev, DM_DEFAULT, ulRGBToDither, &prb->aulPattern[0]);
//
// Initialize the fields we need
//
prb->ptlBrushOrg.x = LONG_MIN;
prb->fl = 0;
prb->pbe = NULL;
}// vRealizeDitherPattern()
//---------------------------Public*Routine------------------------------------
//
// BOOL DrvRealizeBrush
//
// This function allows us to convert GDI brushes into an internal form
// we can use. It is called by GDI when we've called BRUSHOBJ_pvGetRbrush
// in some other function like DrvBitBlt, and GDI doesn't happen have a cached
// realization lying around.
//
// Parameters:
// pbo----------Points to the BRUSHOBJ that is to be realized. All other
// parameters, except for psoTarget, can be queried from this
// object. Parameter specifications are provided as an
// optimization. This parameter is best used only as a parameter
// for BRUSHOBJ_pvAllocRBrush, which allocates the memory for the
// realized brush.
// psoTarget----Points to the surface for which the brush is to be realized.
// This surface can be the physical surface for the device, a
// device format bitmap, or a standard format bitmap.
// psoPattern---Points to the surface that describes the pattern for the brush.
// For a raster device, this is a bitmap. For a vector device,
// this is one of the pattern surfaces provided by DrvEnablePDEV.
// psoMask------Points to a transparency mask for the brush. This is a 1 bit
// per pixel bitmap that has the same extent as the pattern. A
// mask of zero means the pixel is considered a background pixel
// for the brush. (In transparent background mode, the background
// pixels are unaffected in a fill.) Plotters can ignore this
// parameter because they never draw background information.
// pxlo---------Points to a XLATEOBJ that defines the interpretration of colors
// in the pattern. A XLATEOBJXxx service routine can be called to
// translate the colors to device color indices. Vector devices
// should translate color zero through the XLATEOBJ to get the
// foreground color for the brush.
// ulHatch------Specifies whether psoPattern is one of the hatch brushes
// returned by DrvEnablePDEV. This is true if the value of this
// parameter is less than HS_API_MAX.
//
// Return Value
// The return value is TRUE if the brush was successfully realized. Otherwise,
// it is FALSE, and an error code is logged.
//
// Comments
// To realize a brush, the driver converts a GDI brush into a form that can be
// used internally. A realized brush contains information and accelerators the
// driver needs to fill an area with a pattern; information that is defined by
// the driver and used only by the driver.
//
// The driver's realization of a brush is written into the buffer allocated by
// a call to BRUSHOBJ_pvAllocRbrush.
//
// DrvRealizeBrush is required for a driver that does any drawing to any
// surface.
//
// ppdev->bRealizeTransparent -- Hint for whether or not the brush should be
// realized for transparency. If this hint is
// wrong, there will be no error, but the brush
// will have to be unnecessarily re-realized.
//
// Note: You should always set 'ppdev->bRealizeTransparent' before calling
// BRUSHOBJ_pvGetRbrush!
//
//-----------------------------------------------------------------------------
BOOL
DrvRealizeBrush(BRUSHOBJ* pbo,
SURFOBJ* psoDst,
SURFOBJ* psoPattern,
SURFOBJ* psoMask,
XLATEOBJ* pxlo,
ULONG ulHatch)
{
PDev* ppdev = (PDev*)psoDst->dhpdev;
BYTE* pbDst;
BYTE* pbSrc;
LONG i;
LONG j;
LONG lNumPixelToBeCopied;
LONG lSrcDelta;
RBrush* prb;
ULONG* pulXlate;
ULONG ulPatternFormat;
PERMEDIA_DECL;
DBG_GDI((6, "DrvRealizeBrush called for pbo 0x%x", pbo));
//
// We have a fast path for dithers when we set GCAPS_DITHERONREALIZE:
//
if ( ulHatch & RB_DITHERCOLOR )
{
//
// Move this test in here since we always support monochrome brushes
// as they live in the on-chip area stipple. These dithered brushes
// will always be colored requiring available off-screen memory.
//
if ( !(ppdev->flStatus & STAT_BRUSH_CACHE) )
{
//
// We only handle brushes if we have an off-screen brush cache
// available. If there isn't one, we can simply fail the
// realization, and eventually GDI will do the drawing for us
// (although a lot slower than we could have done it)
//
DBG_GDI((6, "brush cache not enabled"));
goto ReturnFalse;
}
DBG_GDI((7, "DITHERONREALIZE"));
//
// We have a fast path for dithers when we set GCAPS_DITHERONREALIZE
// First, we need to allocate memory for the realization of a brush
// Note: actually we ask for allocation of a RBRUSH + the brush
// stamp size
//
prb = (RBrush*)BRUSHOBJ_pvAllocRbrush(pbo,
sizeof(RBrush) + (TOTAL_BRUSH_SIZE << ppdev->cPelSize));
if ( prb == NULL )
{
DBG_GDI((1, "BRUSHOBJ_pvAllocRbrush() in dither return NULL\n"));
goto ReturnFalse;
}
//
// Dither and realize the brsuh pattern
//
vRealizeDitherPattern(psoDst->hdev, prb, ulHatch);
goto ReturnTrue;
}// if ( ulHatch & RB_DITHERCOLOR )
//
// We only handle brushes if we have an off-screen brush cache available
// If there isn't one, we can simply fail the realization, and eventually
// GDI will do the drawing for us (although a lot slower than we could have
// done it). We always succeed for 1bpp patterns since we use the area
// stipple unit to do these rather than off-screen memory.
//
ulPatternFormat = psoPattern->iBitmapFormat;
if ( !(ppdev->flStatus & STAT_BRUSH_CACHE)
&&(ulPatternFormat != BMF_1BPP) )
{
DBG_GDI((1, "brush cache not enabled, or Bitmap is not 1 BPP"));
goto ReturnFalse;
}
//
// We only accelerate 8x8 patterns since most of the video card can only
// accelerate 8x8 brush
//
if ( (psoPattern->sizlBitmap.cx != 8)
||(psoPattern->sizlBitmap.cy != 8) )
{
DBG_GDI((1, "Brush Bitmap size is not 8x8"));
goto ReturnFalse;
}
//
// We need to allocate memory for the realization of a brush
// Note: actually we ask for allocation of a RBRUSH + the brush stamp size
//
prb = (RBrush*)BRUSHOBJ_pvAllocRbrush(pbo,
sizeof(RBrush) + (TOTAL_BRUSH_SIZE << ppdev->cPelSize));
if ( prb == NULL )
{
DBG_GDI((0, "BRUSHOBJ_pvAllocRbrush() failed"));
goto ReturnFalse;
}
//
// Initialize the fields we need
//
prb->ptlBrushOrg.x = LONG_MIN;
prb->fl = 0;
prb->pbe = NULL;
lSrcDelta = psoPattern->lDelta;
pbSrc = (BYTE*)psoPattern->pvScan0;
pbDst = (BYTE*)&prb->aulPattern[0];
//
// At 8bpp, we handle patterns at 1bpp, 4bpp and 8bpp with/without an xlate
// At 16bpp, we handle patterns at 16 bpp without an xlate.
// At 32bpp, we handle patterns at 32bpp without an xlate.
// We handle all the patterns at 1 bpp with/without an Xlate
//
// Check if the brush pattern has the same color depth as our current
// display color depth
//
if ( ulPatternFormat == BMF_1BPP )
{
DWORD Data;
DBG_GDI((7, "Realizing 1bpp brush"));
//
// We dword align the monochrome bitmap so that every row starts
// on a new long (so that we can do long writes later to transfer
// the bitmap to the area stipple unit).
//
for ( i = 8; i != 0; i-- )
{
//
// Replicate the brush to 32 bits wide, as the TX cannot
// span fill 8 bit wide brushes
//
Data = (*pbSrc) & 0xff;
Data |= Data << 8;
Data |= Data << 16;
*(DWORD*)pbDst = Data;
//
// Area stipple is loaded with DWORDS
//
pbDst += sizeof(DWORD);
pbSrc += lSrcDelta;
}
pulXlate = pxlo->pulXlate;
prb->fl |= RBRUSH_2COLOR;
prb->ulForeColor = pulXlate[1];
prb->ulBackColor = pulXlate[0];
}// Pattern at 1 BPP
else if ( (ulPatternFormat == BMF_4BPP)&&(ppdev->iBitmapFormat == BMF_8BPP))
{
DBG_GDI((7, "Realizing 4bpp brush"));
//
// The screen is 8bpp and the pattern is 4bpp:
//
pulXlate = pxlo->pulXlate;
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-- )
{
*pbDst++ = (BYTE)pulXlate[*pbSrc >> 4];
*pbDst++ = (BYTE)pulXlate[*pbSrc & 15];
pbSrc++;
}
pbSrc += lSrcDelta - 4;
}
}// Pattern 4BPP and Screen 8 BPP
else if ( ( ppdev->iBitmapFormat == ulPatternFormat )
&&( (pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL) ) )
{
DBG_GDI((7, "Realizing un-translated brush"));
//
// The pattern is the same colour depth as the screen, and
// there's no translation to be done.
// Here we first need to calculate how many pixel need to be
// copied
//
lNumPixelToBeCopied = (8 << ppdev->cPelSize);
for ( i = 8; i != 0; i-- )
{
RtlCopyMemory(pbDst, pbSrc, lNumPixelToBeCopied);
pbSrc += lSrcDelta;
pbDst += lNumPixelToBeCopied;
}
}// Pattern and Screen has same color depth, No Xlate
else if ( (ppdev->iBitmapFormat == BMF_8BPP)
&&(ulPatternFormat == BMF_8BPP) )
{
DBG_GDI((7, "Realizing 8bpp translated brush"));
//
// The screen is 8bpp, and there's translation to be done
// So we have to do copy + Xlate one by one
//
pulXlate = pxlo->pulXlate;
for ( i = 8; i != 0; i-- )
{
for ( j = 8; j != 0; j-- )
{
*pbDst++ = (BYTE)pulXlate[*pbSrc++];
}
pbSrc += lSrcDelta - 8;
}
}// Screen mode and pattern mode all at 8 BPP
else
{
//
// We've got a brush whose format we haven't special cased.
//
goto ReturnFalse;
}
ReturnTrue:
DBG_GDI((6, "DrvRealizeBrush returning true"));
return(TRUE);
ReturnFalse:
if ( psoPattern != NULL )
{
DBG_GDI((1, "Failed realization -- Type: %li Format: %li cx: %li cy: %li",
psoPattern->iType, psoPattern->iBitmapFormat,
psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
}
DBG_GDI((6, "DrvRealizeBrush returning false"));
return(FALSE);
}// DrvRealizeBrush()
//-----------------------------------------------------------------------------
//
// BOOL bEnableBrushCache
//
// Allocates off-screen memory for storing the brush cache.
//
//-----------------------------------------------------------------------------
BOOL
bEnableBrushCache(PDev* ppdev)
{
BrushEntry* pbe; // Pointer to the brush-cache entry
LONG i;
LONG lDelta;
ULONG ulPixOffset;
DBG_GDI((6, "bEnableBrushCache"));
ASSERTDD(!(ppdev->flStatus & STAT_BRUSH_CACHE),
"bEnableBrushCache: unexpected already enabled brush cache");
//
// ENABLE_BRUSH_CACHE by default is on. It would be turned off in
// bInitializeHw() if 3D buffers runs out of memory
//
if ( !(ppdev->flStatus & ENABLE_BRUSH_CACHE) )
{
DBG_GDI((1, "Brush cache not valid for creation"));
goto ReturnTrue;
}
ppdev->ulBrushVidMem = ulVidMemAllocate(ppdev,
CACHED_BRUSH_WIDTH,
CACHED_BRUSH_HEIGHT
*NUM_CACHED_BRUSHES,
ppdev->cPelSize,
&lDelta,
&ppdev->pvmBrushHeap,
&ppdev->ulBrushPackedPP,
FALSE);
if (ppdev->ulBrushVidMem == 0 )
{
DBG_GDI((0, "bEnableBrushCache: failed to allocate video memory"));
goto ReturnTrue; // See note about why we can return TRUE...
}
ASSERTDD(lDelta == (CACHED_BRUSH_WIDTH << ppdev->cPelSize),
"bEnableBrushCache: unexpected stride does not match width");
ppdev->cBrushCache = NUM_CACHED_BRUSHES;
ulPixOffset = (ULONG) ppdev->ulBrushVidMem >> ppdev->cPelSize;
pbe = &ppdev->abe[0];
for (i = 0; i < NUM_CACHED_BRUSHES; i++, pbe++)
{
pbe->prbVerify = NULL;
pbe->ulPixelOffset = ulPixOffset;
ulPixOffset += CACHED_BRUSH_SIZE;
memset((pbe->ulPixelOffset << ppdev->cPelSize) + ppdev->pjScreen,
0x0, (CACHED_BRUSH_SIZE << ppdev->cPelSize));
}
//
// We successfully allocated the brush cache, so let's turn
// on the switch showing that we can use it:
//
DBG_GDI((6, "bEnableBrushCache: successfully allocated brush cache"));
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:
//
DBG_GDI((6, "Passed bEnableBrushCache"));
return(TRUE);
}// bEnableBrushCache()
//-----------------------------------------------------------------------------
//
// VOID vDisableBrushCache
//
// Cleans up anything done in bEnableBrushCache.
//
//-----------------------------------------------------------------------------
VOID
vDisableBrushCache(PDev* ppdev)
{
DBG_GDI((6,"vDisableBrushCache"));
if(ppdev->flStatus & STAT_BRUSH_CACHE)
{
DBG_GDI((6,"vDisableBrushCache: freeing brush cache"));
VidMemFree(ppdev->pvmBrushHeap->lpHeap,
(FLATPTR)(ppdev->ulBrushVidMem));
ppdev->cBrushCache = 0;
ppdev->flStatus &= ~STAT_BRUSH_CACHE;
DBG_GDI((6,"vDisableBrushCache: freeing brush cache done"));
}
}// vDisableBrushCache()
//-----------------------------------------------------------------------------
//
// VOID vAssertModeBrushCache
//
// Resets the brush cache when we exit out of full-screen.
//
//-----------------------------------------------------------------------------
VOID
vAssertModeBrushCache(PDev* ppdev,
BOOL bEnable)
{
if ( bEnable )
{
bEnableBrushCache(ppdev);
}
else
{
vDisableBrushCache(ppdev);
}
}// vAssertModeBrushCache()