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.
 
 
 
 
 
 

856 lines
28 KiB

/******************************Module*Header**********************************\
*
* *******************
* * GDI SAMPLE CODE *
* *******************
*
* Module Name: patnfill.c
*
* Contains all the pattern fill routines
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
\*****************************************************************************/
#include "precomp.h"
#include "gdi.h"
#include "directx.h"
//-----------------------------Note--------------------------------------------
//
// A Note on brushes
//
// Out cached brushes are 64x64. Here is the reason. The minimum brush
// size that we can use as a pattern is 32.
//
// Now, we need to be able to offset the pattern when rendering in x and y
// by as much as 7 pixels in either direction. The P2
// hardware does not have a simple x/Y pattern offset mechanism. Instead
// we are forced to offset the origin by offsetting the base address of the
// pattern. This requires that we store in memory a pattern that is
// 39 pixels wide. However, the stride still needs to be acceptable to the
// texture address generation hardware. The next valid stride is 64.
//
// That's why we have 64x64 pattern brushes in our cache.
//
// Note also that we over do it when caching duplicating the brush to fill
// up the entire 64x64 even though we only use 39x39. We might change
// this in the near future.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// VOID vMonoOffset(GFNPB* ppb)
//
// Update the offset to be used in the area stipple unit. We do this for a
// mono brush which is realized in the hardware but whose alignment has simply
// changed. This avoids a full scale realization.
//
// Argumentes needed from function block (GFNPB)
//
// ppdev-------PPDev
// prbrush-----Pointer to the RBrush structure
// pptlBrush---Pointer to pointer brush structure
//
//-----------------------------------------------------------------------------
VOID
vMonoOffset(GFNPB* ppb)
{
PPDev ppdev = ppb->ppdev;
DWORD dwMode;
POINTL* pptlBrush = ppb->pptlBrush;
RBrush* prb = ppb->prbrush;
PERMEDIA_DECL;
DBG_GDI((6, "vMonoOffset started"));
//
// Construct the AreaStippleMode value. It contains the pattern size,
// the offset for the brush origin and the enable bit. Remember the
// offset so we can later check if it changes and update the hardware.
// Remember the mode so we can do a mirrored stipple easily.
//
prb->ptlBrushOrg.x = pptlBrush->x;
prb->ptlBrushOrg.y = pptlBrush->y;
dwMode = __PERMEDIA_ENABLE
| AREA_STIPPLE_XSEL(__PERMEDIA_AREA_STIPPLE_32_PIXEL_PATTERN)
| AREA_STIPPLE_YSEL(__PERMEDIA_AREA_STIPPLE_8_PIXEL_PATTERN)
| AREA_STIPPLE_MIRROR_X
| AREA_STIPPLE_XOFF(8 - (prb->ptlBrushOrg.x & 7))
| AREA_STIPPLE_YOFF(8 - (prb->ptlBrushOrg.y & 7));
prb->areaStippleMode = dwMode;
DBG_GDI((7, "setting new area stipple offset to %d, %d",
8 - (prb->ptlBrushOrg.x & 7), 8 - (prb->ptlBrushOrg.y & 7)));
ULONG* pBuffer;
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagAreaStippleMode;
pBuffer[1] = dwMode;
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
}// vMonoOffset()
//-----------------------------------------------------------------------------
//
// VOID vPatRealize(GFNPB* ppb)
//
// This routine transfers an 8x8 pattern to off-screen display memory, and
// duplicates it to make a 32x32 cached realization which is then used by
// vPatFill.
//
// Argumentes needed from function block (GFNPB)
//
// ppdev-------PPDev
// prbrush-----Pointer to the RBrush structure
//
//-----------------------------------------------------------------------------
VOID
vPatRealize(GFNPB* ppb)
{
PDev* ppdev = ppb->ppdev;
RBrush* prb = ppb->prbrush; // Points to brush realization structure
BrushEntry* pbe = prb->pbe;
BYTE* pcSrc;
LONG lNextCachedBrush;
LONG lTemp;
LONG lPelSize;
ULONG* pBuffer;
PERMEDIA_DECL;
// VALIDATE_GDI_CONTEXT;
DBG_GDI((6, "vPatRealize started"));
if ( (pbe == NULL) || (pbe->prbVerify != prb) )
{
//
// Mono brushes are realized into the area stipple unit. For this we
// have a set of special BRUSHENTRYs, one for each board.
//
if ( prb->fl & RBRUSH_2COLOR )
{
//
// 1 BPP patten
//
DBG_GDI((7, "loading mono brush into cache"));
pbe = &ppdev->abeMono;
pbe->prbVerify = prb;
prb->pbe = pbe;
}
else
{
//
// We have to allocate a new off-screen cache brush entry for
// the brush
//
lNextCachedBrush = ppdev->lNextCachedBrush; // Get the next index
pbe = &ppdev->abe[lNextCachedBrush]; // Get the brush entry
//
// Check if this index is out of the total brush stamps cached
// If yes, rotate to the 1st one
//
lNextCachedBrush++;
if ( lNextCachedBrush >= ppdev->cBrushCache )
{
lNextCachedBrush = 0;
}
//
// Reset the next brush to be allocated
//
ppdev->lNextCachedBrush = lNextCachedBrush;
//
// Update our links:
//
pbe->prbVerify = prb;
prb->pbe = pbe;
DBG_GDI((7, "new cache entry allocated for color brush"));
}// Get cached brush entry depends on its color depth
}// If the brush is not cached
//
// We're going to load mono patterns into the area stipple and set the
// start offset to the brush origin. WARNING: we assume that we are
// running little endian. I believe this is always true for NT.
//
if ( prb->fl & RBRUSH_2COLOR )
{
//
// 1 BPP patten
//
DWORD* pdwSrc = &prb->aulPattern[0];
//
// This function loads the stipple offset into the hardware. We also
// call this function on its own if the brush is realized but its
// offset changes. In that case we don't have to go through a complete
// realize again.
//
ppb->prbrush = prb;
(*ppdev->pgfnMonoOffset)(ppb);
DBG_GDI((7, "area stipple pattern:"));
InputBufferReserve(ppdev, 16, &pBuffer);
for ( lTemp = 0; lTemp < 8; ++lTemp, ++pdwSrc )
{
pBuffer[0] = __Permedia2TagAreaStipplePattern0 + lTemp;
pBuffer[1] = *pdwSrc;
pBuffer += 2;
}
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((7, "area stipple downloaded. vPatRealize done"));
return;
}// 1 BPP case
lPelSize = ppdev->cPelSize;
pcSrc = (BYTE*)&prb->aulPattern[0]; // Copy from brush buffer
InputBufferReserve(ppdev, 12 + 65, &pBuffer);
pBuffer[0] = __Permedia2TagFBWindowBase;
pBuffer[1] = pbe->ulPixelOffset;
pBuffer[2] = __Permedia2TagFBReadMode;
pBuffer[3] = PM_FBREADMODE_PARTIAL(ppdev->ulBrushPackedPP);
pBuffer[4] = __Permedia2TagLogicalOpMode;
pBuffer[5] = __PERMEDIA_DISABLE;
pBuffer[6] = __Permedia2TagRectangleOrigin;
pBuffer[7] = 0;
pBuffer[8] = __Permedia2TagRectangleSize;
pBuffer[9] = (8 << 16) | 8;
pBuffer[10] = __Permedia2TagRender;
pBuffer[11] = __RENDER_RECTANGLE_PRIMITIVE
| __RENDER_SYNC_ON_HOST_DATA
| __RENDER_INCREASE_Y
| __RENDER_INCREASE_X;
pBuffer += 12;
*pBuffer++ = (63 << 16) | __Permedia2TagColor;
switch( lPelSize )
{
case 0:
for ( lTemp = 0; lTemp < 64; ++lTemp )
{
*pBuffer++ = pcSrc[lTemp];
}
break;
case 1:
for ( lTemp = 0; lTemp < 64; ++lTemp )
{
*pBuffer++ = ((USHORT *) pcSrc)[lTemp];
}
break;
case 2:
for ( lTemp = 0; lTemp < 64; ++lTemp )
{
*pBuffer++ = ((ULONG *) pcSrc)[lTemp];
}
break;
}
InputBufferCommit(ppdev, pBuffer);
// ÚÄÂÄÂÄÄÄÂ
// ³0³1³2 ³ We now have an 8x8 colour-expanded copy of
// ÃÄÁÄÁÄÄÄÁ the pattern sitting in off-screen memory,
// ³5 ³ represented here by square '0'.
// ³ ³
// ³ ³ We're now going to expand the pattern to
// ³ ³ 64x64 by repeatedly copying larger rectangles
// ³ ³ in the indicated order, and doing a 'rolling'
// ³ ³ blt to copy vertically.
// ³ ³
// ÀÄÄÄÄÄÄÄÙ
InputBufferReserve(ppdev, 36, &pBuffer);
pBuffer[0] = __Permedia2TagFBReadMode;
pBuffer[1] = PM_FBREADMODE_PARTIAL(ppdev->ulBrushPackedPP)
| __FB_READ_SOURCE;
pBuffer[2] = __Permedia2TagStartXDom;
pBuffer[3] = INTtoFIXED(8);
pBuffer[4] = __Permedia2TagStartXSub;
pBuffer[5] = INTtoFIXED(16);
pBuffer[6] = __Permedia2TagFBSourceOffset;
pBuffer[7] = -8;
pBuffer[8] = __Permedia2TagRender;
pBuffer[9] = __RENDER_TRAPEZOID_PRIMITIVE;
pBuffer[10] = __Permedia2TagStartXDom;
pBuffer[11] = INTtoFIXED(16);
pBuffer[12] = __Permedia2TagStartXSub;
pBuffer[13] = INTtoFIXED(32);
pBuffer[14] = __Permedia2TagFBSourceOffset;
pBuffer[15] = -16;
pBuffer[16] = __Permedia2TagRender;
pBuffer[17] = __RENDER_TRAPEZOID_PRIMITIVE;
pBuffer[18] = __Permedia2TagStartXDom;
pBuffer[19] = INTtoFIXED(32);
pBuffer[20] = __Permedia2TagStartXSub;
pBuffer[21] = INTtoFIXED(64);
pBuffer[22] = __Permedia2TagFBSourceOffset;
pBuffer[23] = -32;
pBuffer[24] = __Permedia2TagRender;
pBuffer[25] = __RENDER_TRAPEZOID_PRIMITIVE;
//
// Now rolling copy downward.
//
pBuffer[26] = __Permedia2TagStartXDom;
pBuffer[27] = INTtoFIXED(0);
pBuffer[28] = __Permedia2TagStartY;
pBuffer[29] = INTtoFIXED(8);
pBuffer[30] = __Permedia2TagFBSourceOffset;
pBuffer[31] = -(CACHED_BRUSH_WIDTH << 3);
pBuffer[32] = __Permedia2TagCount;
pBuffer[33] = CACHED_BRUSH_HEIGHT - 8;
pBuffer[34] = __Permedia2TagRender;
pBuffer[35] = __RENDER_TRAPEZOID_PRIMITIVE;
pBuffer += 36;
InputBufferCommit(ppdev, pBuffer);
}// vPatRealize()
//-----------------------------------------------------------------------------
//
// VOID vMonoPatFill(GFNPB* ppb)
//
// Fill a series of rectangles with a monochrome pattern previously loaded
// into the area stipple unit. If bTransparent is false we must do each
// rectangle twice, inverting the stipple pattern in the second go.
//
// Argumentes needed from function block (GFNPB)
//
// ppdev-------PPDev
// psurfDst----Destination surface
// lNumRects---Number of rectangles to fill
// pRects------Pointer to a list of rectangles information which needed to be
// filled
// ucFgRop3----Foreground Logic OP for the fill
// ucBgRop3----Background Logic OP for the fill
// prbrush-----Pointer to the RBrush structure
// pptlBrush---Structure for brush origin
//
//-----------------------------------------------------------------------------
VOID
vMonoPatFill(GFNPB* ppb)
{
PPDev ppdev = ppb->ppdev;
Surf* psurf = ppb->psurfDst;
RBrush* prb = ppb->prbrush;
POINTL* pptlBrush = ppb->pptlBrush;
BrushEntry* pbe = prb->pbe; // Brush entry
RECTL* pRect = ppb->pRects; // List of rectangles to be
// filled in relative
// coordinates
ULONG* pBuffer;
DWORD dwColorMode;
DWORD dwColorReg;
DWORD dwLogicMode;
DWORD dwReadMode;
LONG lNumPass;
LONG lNumRects; // Can't be zero
// ULONG ulBgLogicOp = ulRop3ToLogicop(ppb->ucBgRop3);
ULONG ulBgLogicOp = ulRop3ToLogicop(ppb->ulRop4 >> 8);
// Not used (unless the brush
// has a mask, in which case it
// is the background mix mode)
// ULONG ulFgLogicOp = ulRop3ToLogicop(ppb->ucFgRop3);
ULONG ulFgLogicOp = ulRop3ToLogicop(ppb->ulRop4 & 0xFF);
// Hardware mix mode
// (foreground mix mode if
// the brush has a mask)
ULONG ulBgColor = prb->ulBackColor;
ULONG ulFgColor = prb->ulForeColor;
ULONG ulCurrentFillColor;
ULONG ulCurrentLogicOp;
PERMEDIA_DECL;
DBG_GDI((6, "vMonoPatFill called: %d rects. ulRop4 = %x",
ppb->lNumRects, ppb->ulRop4));
// DBG_GDI((6, "ulFgLogicOp = 0x%x, ulBgLogicOp = 0x%x",
// ulFgLogicOp, ulBgLogicOp));
DBG_GDI((6, "ulFgColor 0x%x, ulBgColor 0x%x", ulFgColor, ulBgColor));
//
// If anything has changed with the brush we must re-realize it. If the
// brush has been kicked out of the area stipple unit we must fully realize
// it. If only the alignment has changed we can simply update the alignment
// for the stipple.
//
if ( (pbe == NULL) || (pbe->prbVerify != prb) )
{
DBG_GDI((7, "full brush realize"));
(*ppdev->pgfnPatRealize)(ppb);
}
else if ( (prb->ptlBrushOrg.x != pptlBrush->x)
||(prb->ptlBrushOrg.y != pptlBrush->y) )
{
DBG_GDI((7, "changing brush offset"));
(*ppdev->pgfnMonoOffset)(ppb);
}
//
// We get some common operations which are really noops. we can save
// lots of time by cutting these out. As this happens a lot for masking
// operations it's worth doing.
//
if ( ((ulFgLogicOp == K_LOGICOP_AND) && (ulFgColor == ppdev->ulWhite))
||((ulFgLogicOp == K_LOGICOP_XOR) && (ulFgColor == 0)) )
{
DBG_GDI((7, "Set FgLogicOp to NOOP"));
ulFgLogicOp = K_LOGICOP_NOOP;
}
//
// Same for background
//
if ( ((ulBgLogicOp == K_LOGICOP_AND) && (ulBgColor == ppdev->ulWhite))
||((ulBgLogicOp == K_LOGICOP_XOR) && (ulBgColor == 0)) )
{
DBG_GDI((7, "Set BgLogicOp to NOOP"));
ulBgLogicOp = K_LOGICOP_NOOP;
}
//
// Try to do the background as a solid fill. lNumPass starts at 1 rather
// than 2 because we want to do all comparisons with zero. This is faster.
// We also do a trick with its value to avoid an extra WAIT_FIFO on the
// first pass.
//
if ( (ulBgLogicOp == K_LOGICOP_COPY)
&&(ulFgLogicOp == K_LOGICOP_COPY) )
{
DBG_GDI((7, "FgLogicOp and BgLogicOp are COPY"));
//
// For PatCopy case, we can use solid fill to fill the background first
// Note: we do not need to set FBWindowBase, it will be set by
// the solid fill
//
ppb->solidColor = ulBgColor;
(*ppdev->pgfnSolidFill)(ppb);
//
// We've done the background so we only want to go round the stipple
// loop once. So set the lNumPass counter up for only one loop and set
// the ulCurrentLogicOp and color to the foreground values.
//
lNumPass = 0;
ulCurrentFillColor = ulFgColor;
ulCurrentLogicOp = ulFgLogicOp;
//
// Do this here in case the solid fill changed the packing.
//
// brh not needed
// P2_DEFAULT_FB_DEPTH;
}
else
{
//
// For non-PATCOPY cases, we have to do 2 passes. Fill the background
// first and then fill the foreground
//
lNumPass = 1;
ulCurrentFillColor = ulBgColor;
ulCurrentLogicOp = ulBgLogicOp;
//
// Note: In this case, dxDom, dXSub and dY are initialised to 0, 0,
// and 1, so we don't need to re-load them here. But we need to set
// WindowBase here
//
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagFBWindowBase;
pBuffer[1] = psurf->ulPixOffset;
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
}// if-else for LOGICOP_COPY case
//
// Do 2 passes loop or single loop depends on "lNumPass"
//
while ( TRUE )
{
if ( ulCurrentLogicOp != K_LOGICOP_NOOP )
{
dwReadMode = psurf->ulPackedPP;
if ( ulCurrentLogicOp == K_LOGICOP_COPY )
{
DBG_GDI((7, "Current logicOP is COPY"));
dwColorReg = __Permedia2TagFBWriteData;
dwColorMode = __PERMEDIA_DISABLE;
dwLogicMode = __PERMEDIA_CONSTANT_FB_WRITE;
}
else
{
DBG_GDI((7, "Current logicOP is NOT-COPY"));
dwColorReg = __Permedia2TagConstantColor;
dwColorMode = __COLOR_DDA_FLAT_SHADE;
dwLogicMode = P2_ENABLED_LOGICALOP(ulCurrentLogicOp);
dwReadMode |= LogicopReadDest[ulCurrentLogicOp];
}
//
// On the bg fill pass, we have to invert the sense of the
// download bits. On the first pass, lNumPass == 1; on the second
// pass, lNumPass == 0, so we get our WAIT_FIFO sums correct!!
//
InputBufferReserve(ppdev, 10, &pBuffer);
if ( lNumPass > 0 )
{
pBuffer[0] = __Permedia2TagAreaStippleMode;
pBuffer[1] = (prb->areaStippleMode
| AREA_STIPPLE_INVERT_PAT);
pBuffer += 2;
}
pBuffer[0] = __Permedia2TagColorDDAMode;
pBuffer[1] = dwColorMode;
pBuffer[2] = __Permedia2TagFBReadMode;
pBuffer[3] = dwReadMode;
pBuffer[4] = __Permedia2TagLogicalOpMode;
pBuffer[5] = dwLogicMode;
pBuffer[6] = dwColorReg,
pBuffer[7] = ulCurrentFillColor;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
//
// Fill rects one by one
//
lNumRects = ppb->lNumRects;
while ( TRUE )
{
DBG_GDI((7, "mono pattern fill to rect (%d,%d) to (%d,%d)",
pRect->left,
pRect->top,
pRect->right,
pRect->bottom));
InputBufferReserve(ppdev, 12, &pBuffer);
//
// Render the rectangle
//
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = pRect->left << 16;
pBuffer[2] = __Permedia2TagStartXSub;
pBuffer[3] = pRect->right << 16;
pBuffer[4] = __Permedia2TagStartY;
pBuffer[5] = pRect->top << 16;
pBuffer[6] = __Permedia2TagdY;
pBuffer[7] = 1 << 16;
pBuffer[8] = __Permedia2TagCount;
pBuffer[9] = pRect->bottom - pRect->top;
pBuffer[10] = __Permedia2TagRender;
pBuffer[11] = __RENDER_TRAPEZOID_PRIMITIVE
|__RENDER_AREA_STIPPLE_ENABLE;
pBuffer += 12;
InputBufferCommit(ppdev, pBuffer);
if ( --lNumRects == 0 )
{
break;
}
pRect++;
}// loop through all the rectangles
//
// Reset our pixel values.
//
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagLogicalOpMode;
pBuffer[1] = __PERMEDIA_DISABLE;
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
//
// We must reset the area stipple mode for the foreground pass. if
// there's no foreground pass we must reset it anyway.
//
if ( lNumPass > 0 )
{
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagAreaStippleMode;
pBuffer[1] = prb->areaStippleMode;
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
}
}// if ( ulCurrentLogicOp != K_LOGICOP_NOOP )
if ( --lNumPass < 0 )
{
break;
}
//
// We need to the 2nd pass. So reset the rectangle info, color mode
// and logicop status
//
pRect = ppb->pRects;
ulCurrentFillColor = ulFgColor;
ulCurrentLogicOp = ulFgLogicOp;
}// Loop through all the passes
if ( dwColorMode != __PERMEDIA_DISABLE )
{
InputBufferReserve(ppdev, 2, &pBuffer);
//
// Restore ColorDDAMode
//
pBuffer[0] = __Permedia2TagColorDDAMode;
pBuffer[1] = __PERMEDIA_DISABLE;
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
}
DBG_GDI((6, "vMonoPatFill returning"));
}// vMonoPatFill()
//-----------------------------------------------------------------------------
//
// VOID vPatFill(GFNPB* ppb)
//
// Function to fill a set of rectangles with a given pattern. Colored patterns
// only. Monochrome patterns are handled in a different routine. This routine
// only handles patterns which were not rotated in memory and which have been
// replicated in X to cope with different alignments.
//
// Parameter block arguments
//
// ppdev-------Valid
// lNumRects---Number of rects pointed to by pRects
// pRects------Of destination rectangles to be filled
// ucFgRop3----Valid Pattern fill rop3 code (source invariant)
// pptlBrush---Origin of brush
// pdsurfDst---Destination surface
// prbrush-----ponter to RBRUSH
//
//-----------------------------------------------------------------------------
VOID
vPatFill(GFNPB* ppb)
{
PPDev ppdev = ppb->ppdev;
LONG lNumRects = ppb->lNumRects;
RECTL* prcl = ppb->pRects;
POINTL* pptlBrush = ppb->pptlBrush;
Surf* psurf = ppb->psurfDst;
RBrush* prbrush = ppb->prbrush;
BrushEntry* pbe = prbrush->pbe;
DWORD dwRenderBits;
ULONG ulBrushX;
ULONG ulBrushY;
ULONG ulBrushOffset;
// ULONG ulLogicOP = ulRop3ToLogicop(ppb->ucFgRop3);
ULONG ulLogicOP = ulRop3ToLogicop(ppb->ulRop4 & 0xFF);
ULONG* pBuffer;
PERMEDIA_DECL;
ASSERTDD(lNumRects > 0, "vPatFill: unexpected rectangle lNumRects <= 0");
if ( (pbe == NULL) || (pbe->prbVerify != ppb->prbrush) )
{
vPatRealize(ppb);
pbe = prbrush->pbe;
ASSERTDD(pbe != NULL, "vPatFill: unexpected null pattern brush entry");
}
dwRenderBits = __RENDER_TRAPEZOID_PRIMITIVE
| __RENDER_TEXTURED_PRIMITIVE;
InputBufferReserve(ppdev, 34, &pBuffer);
pBuffer[0] = __Permedia2TagFBWindowBase;
pBuffer[1] = psurf->ulPixOffset;
pBuffer[2] = __Permedia2TagLogicalOpMode;
pBuffer[3] = P2_ENABLED_LOGICALOP(ulLogicOP);
pBuffer[4] = __Permedia2TagFBReadMode;
pBuffer[5] = PM_FBREADMODE_PARTIAL(psurf->ulPackedPP)
| LogicopReadDest[ulLogicOP];
pBuffer[6] = __Permedia2TagFBWriteConfig;
pBuffer[7] = PM_FBREADMODE_PARTIAL(psurf->ulPackedPP)
| LogicopReadDest[ulLogicOP];
pBuffer[8] = __Permedia2TagFBSourceOffset;
pBuffer[9] = 0;
//
// Setup the texture unit with the pattern
//
pBuffer[10] = __Permedia2TagDitherMode;
pBuffer[11] = (COLOR_MODE << PM_DITHERMODE_COLORORDER)
| (ppdev->ulPermFormat << PM_DITHERMODE_COLORFORMAT)
| (ppdev->ulPermFormatEx << PM_DITHERMODE_COLORFORMATEXTENSION)
| (1 << PM_DITHERMODE_ENABLE);
pBuffer[12] = __Permedia2TagTextureAddressMode;
pBuffer[13] = (1 << PM_TEXADDRESSMODE_ENABLE);
pBuffer[14] = __Permedia2TagTextureColorMode;
pBuffer[15] = (1 << PM_TEXCOLORMODE_ENABLE)
| (0 << 4) // RGB
| (3 << 1); // Copy
pBuffer[16] = __Permedia2TagTextureReadMode;
pBuffer[17] = PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE)
| PM_TEXREADMODE_WIDTH(CACHED_BRUSH_WIDTH_LOG2 - 1)
| PM_TEXREADMODE_HEIGHT(CACHED_BRUSH_HEIGHT_LOG2 - 1)
| (1 << 1) // repeat S
| (1 << 3); // repeat T
pBuffer[18] = __Permedia2TagTextureDataFormat;
pBuffer[19] = (ppdev->ulPermFormat << PM_TEXDATAFORMAT_FORMAT)
| (ppdev->ulPermFormatEx << PM_TEXDATAFORMAT_FORMATEXTENSION)
| (COLOR_MODE << PM_TEXDATAFORMAT_COLORORDER);
pBuffer[20] = __Permedia2TagTextureMapFormat;
pBuffer[21] = (ppdev->ulBrushPackedPP)
| (ppdev->cPelSize << PM_TEXMAPFORMAT_TEXELSIZE);
//@@BEGIN_DDKSPLIT
// TODO: use SStart and TStart to avoid having to offset the pattern using
// ulBrushOffset. This will also allow us to save some space in the
// pattern cache (we have to make it 7 pixels wider and taller due to
// our need to set different origins).
//@@END_DDKSPLIT
pBuffer[22] = __Permedia2TagSStart;
pBuffer[23] = 0;
pBuffer[24] = __Permedia2TagTStart;
pBuffer[25] = 0;
pBuffer[26] = __Permedia2TagdSdx;
pBuffer[27] = 1 << 20;
pBuffer[28] = __Permedia2TagdSdyDom;
pBuffer[29] = 0;
pBuffer[30] = __Permedia2TagdTdx;
pBuffer[31] = 0;
pBuffer[32] = __Permedia2TagdTdyDom;
pBuffer[33] = 1 << 20;
pBuffer += 34;
InputBufferCommit(ppdev, pBuffer);
//
// Render rectangles
//
do
{
//
// Caclulate brush offset taking into account the brush origin
// NOTE: that the texture unit places the origin of the texture
// at the upper left of the destination rectangle
//
ulBrushX = (prcl->left - ppb->pptlBrush->x) & 7;
ulBrushY = (prcl->top - ppb->pptlBrush->y) & 7;
ulBrushOffset = pbe->ulPixelOffset
+ ulBrushX
+ (ulBrushY * CACHED_BRUSH_WIDTH);
InputBufferReserve(ppdev, 12, &pBuffer);
pBuffer[0] = __Permedia2TagTextureBaseAddress;
pBuffer[1] = ulBrushOffset;
pBuffer[2] = __Permedia2TagStartXDom;
pBuffer[3] = INTtoFIXED(prcl->left);
pBuffer[4] = __Permedia2TagStartXSub;
pBuffer[5] = INTtoFIXED(prcl->right);
pBuffer[6] = __Permedia2TagStartY;
pBuffer[7] = INTtoFIXED(prcl->top);
pBuffer[8] = __Permedia2TagCount;
pBuffer[9] = (prcl->bottom - prcl->top);
pBuffer[10] = __Permedia2TagRender;
pBuffer[11] = dwRenderBits;
pBuffer += 12;
InputBufferCommit(ppdev, pBuffer);
prcl++;
} while (--lNumRects != 0);
//
// Restore defaults
//
InputBufferReserve(ppdev, 8, &pBuffer);
pBuffer[0] = __Permedia2TagTextureAddressMode;
pBuffer[1] = (0 << PM_TEXADDRESSMODE_ENABLE);
pBuffer[2] = __Permedia2TagTextureColorMode;
pBuffer[3] = (0 << PM_TEXCOLORMODE_ENABLE);
pBuffer[4] = __Permedia2TagDitherMode;
pBuffer[5] = (0 << PM_DITHERMODE_ENABLE);
pBuffer[6] = __Permedia2TagTextureReadMode;
pBuffer[7] = __PERMEDIA_DISABLE;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((6, "vPatternFillRects done"));
}// vPatFill