Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1905 lines
61 KiB

/*
* Copyright (C) 1993, 1995 by
* DIGITAL EQUIPMENT CORPORATION, Maynard, MA.
*
* This software is furnished under a license and may be used and copied
* only in accordance with the terms of such license and with the inclusion
* of the above copyright notice. This software or any other copies there-
* of may not be provided or otherwise made available to any other person.
* No title to and ownership of the software is hereby transferred.
*
* The information in this software is subject to change without notice
* and should not be construed as a commitment by DIGITAL EQUIPMENT COR-
* PORATION.
*
* DIGITAL assumes no responsibility for the use or reliability of its
* software on equipment which is not supplied by DIGITAL.
*
*******************************************************************************
*
* Module: paint.c
*
* Abstract: TGA support for the DrvPaint call
*
* History
*
* 4-Nov-1993 Barry Tannenbaum
* Hack version to test brush support. This version *only* supports 8x8
* tiles. Everything else is punted. There is a known problem which is
* causing dither patterns to be off-by-4. I'll hunt it down tomorrow.
*
* 5-Nov-1993 Barry Tannenbaum
* Found the dither pattern problem. Tiles must be aligned to 8 pixels,
* not 4 as implied by the documentation.
*
* 7-Nov-1993 Barry Tannenbaum
* Protect against null brush objects. Was causing a GDI server-side
* ACCVIO. Cleaned up the code while I was at it.
*
* 7-Nov-1993 Barry Tannenbaum
* Checking brush->sizlPattern.cx when you haven't initialized brush
* is hazardous to the health of GDI...
*
* 8-Nov-1993 Barry Tannenbaum
* Handle framebuffer aliasing
*
* 10-Nov-1993 Barry Tannenbaum
* Added check for ppdev->bInPuntRoutine. Also added code to save, set
* and restore bInPuntRoutine in punt_paint.
*
* 15-NOV-1993 Bill Wernsing
* Moved call to WBFLUSH from PuntPaint to DrvPaint
*
* 06-Dec-1993 Bob Seitsinger
* Modify do_pattern_8 to handle 4xN and 2xN dimension patterns.
*
* 09-Dec-1993 Bob Seitsinger
* Modify do_pattern_8 to correctly calculate xOffset.
*
* 10-Dec-1993 Bob Seitsinger
* Handle only 8 and 4 pixel wide patterns in do_pattern_8.
*
* 02-Jan-1994 Barry Tannenbaum
* Added support for sparse space in punt routine.
*
* 03-Feb-1994 Bob Seitsinger
* Re-insert support for 2x2 brushes in do_pattern_8.
*
* 14-Feb-1994 Bob Seitsinger
* Make use of the new routines for surface object address, stride
* and format.
*
* 22-Feb-1994 Barry Tannenbaum
* - Complete conversion to surfaces.
* - Added optimization for solid, "narrow" vertical fills to use the
* line drawing hardware
* - Merged fill code from bitblt.c and text.c into this module.
*
* 24-Feb-1994 Barry Tannenbaum
* Use TRANSPARENT_FILL mode in do_solid when the ROP is not COPY.
* BLOCK_FILL mode is faster, but it ignores the ROP.
*
* 24-Feb-1994 Barry Tannenbaum
* The value written to the ADDRESS register should be an offset into
* the framebuffer, not a virtual address. This fixes the flakiness
* with lines and sparse space!
*
* 25-Feb-1994 Barry Tannenbaum
* Put back the code I dropped from BITBLT.C which handles 1 Bit-Per-Pixel
* patterns.
*
* 4-Mar-1994 Barry Tannenbaum
* - Added stipple fill for 1BPP brushes.
* - Moved pattern shifting to fill_pattern from do_pattern_8. This way
* we don't have to shift the pattern for every scanline.
*
* 07-Mar-1994 Bob Seitsinger
* Fixed 2 bugs in fill_solid:
* 1. DC_TRIVIAL and DC_RECT cases were executing the wrong code and needed
* to be swapped.
* 2. DC_TRIVIAL was passing the wrong target rectangle to do_solid.
*
* 8-Mar-1994 Barry Tannenbaum
* - Fixed pattern alignment
* - Punt if we get a null brush
*
* 9-Mar-1994 Barry Tannenbaum
* Fixed write buffer bug in fill_lines. Prevented DrvPaint from calling
* fill_lines for long skinny objects which are complex.
*
* 21-Mar-1994 Bob Seitsinger
* Check # clip objects returned from CLIPOBJ_bEnum before calling
* subroutine.
*
* 24-Mar-1994 Barry Tannenbaum
* Handle invert (R2_NOT) properly by ignoring the pattern, if any
*
* 4-Apr-1994 Barry Tannenbaum
* Fixed bug which prevented filling 1 pixel wide patterns
*
* 18-Apr-1994 Bob Seitsinger
* Fix DrvPaint to not punt back to GDI until first checking the
* mix. If the mix is black, white or not (i.e. invert) then it
* is ok to have a NULL brush object.
*
* 12-May-1994 Barry Tannenbaum
* For Blackness and Whiteness, use TGA_ROP_COPY if the size is
* greater than 40x40.
*
* 13-May-1994 Barry Tannenbaum
* Fixed typo in TGA_ROP_CLEAR code that Bob found.
*
* 16-May-1994 Bob Seitsinger
* Modify DrvPaint in support of the DPna (0x0A) blit rop.
* This rop requires the pattern bits to be NOT'd and
* AND'd with the destination bits.
*
* 21-May-1994 Barry Tannenbaum
* Remeasured difference between using BLOCK_FILL and OPAQUE_FILL for
* small rectangles and concluded that the difference was a wash.
* We now use BLOCK_FILL for all Whiteness and Blackness ROPs.
*
* 21-May-1994 Barry Tannenbaum
* Save the last aligned brush and mask. Also expanded the mask data to
* include the version shifted left 4 bits for lining up with the color
* registers. a bit, the
*
* 22-May-1994 Barry Tannenbaum
* Moved fill_solid back to text.c. We seem to have crossed some
* locality threshold since this gave us a 10% performance boost in
* many of the WinBench 4.0 text tests
*
* 26-May-1994 Bob Seitsinger
* Don't bother checking for a NULL clip object if blit calls
* DrvPaint. Blit guarantees a valid pco.
*
* 30-May-1994 Barry Tannenbaum
* Attempted to optimize block fills
*
* 31-May-1994 Barry Tannenbaum
* More solid color optimizations
*
* 21-Jul-1994 Bob Seitsinger
* We still have to set the ROP register when in Block
* Fill mode, because we need to make sure that the
* destination visual and rotation is set appropriately.
*
* 2-Aug-1994 Barry Tannenbaum
* Save last mode setting in ppdev->TGAModeShadow in private copy of
* TGAMODE
*
* 9-Aug-1994 Barry Tannenbaum
* Setup for 24 plane support:
* - TGAMODE and TGAROP now take simple ULONGs instead of structures
* - Use default values from ppdev->ulModeTemplate & ppdev->ulRopTemplate
*
* 25-Aug-1994 Barry Tannenbaum
* Added support for 24 plane boards. Still need to handle opaque fill
*
* 26-Aug-1994 Bob Seitsinger
* Remove unnecessary OR of 0x00000000 in fill_solid_color.
*
* 31-Aug-1994 Barry Tannenbaum
* Planemask is always 0xffffffff. Mask color to remove high byte in
* 24 plane mode
*
* 13-Sep-1994 Barry Tannenbaum
* Convert TGA ROP to mix when punting to EngPaint
*
* 19-Sep-1994 Bob Seitsinger
* Force the background to be 'copy' in punt_paint when handling a
* mix passed down from Bitblt.
*
* 19-Sep-1994 Bob Seitsinger
* Mask off the tag (high 8) 'xor' bits in the block_fill routine for
* the 24 plane board. This fixes a bug reproduced by Guiman/Bitblt05.
* Move the background operation in the rop_to_mix conversion into
* the table.
*
* 21-Sep-1994 Bob Seitsinger
* In fill_solid_color - planemask = 0x00ffffff when rop is not = copy.
*
* 4-Oct-1994 Barry Tannenbaum
* If we attempt to punt when the mix is a TGA ROP, simply return FALSE.
* DrvBitBlt will punt the call.
*
* 6-Oct-1994 Bob Seitsinger
* Add simple_fill_32 and do_simple_32 routines to handle pattern copies
* on 32bpp frame buffers where block fill won't due, i.e. we have a
* rop other than 'copy'.
*
* 14-Oct-1994 Bob Seitsinger
* Use TGAPIXELMASK() instead of TGAPERSISTENTPIXELMASK() in
* simple_fill_32. This saves us from having to 'reset' the one-shot
* pixel mask register.
*
* 25-Oct-1994 Bob Seitsinger
* Write plane mask with ppdev->ulPlanemaskTemplate all the
* time.
*
* For 24 plane boards we don't want to blow away the
* windows ids for 3d windows. The GL driver removes the
* window ids when it relinquishes a rectangular area.
*
* 03-Nov-1994 Tim Dziechowski
* Stats support
*
* 2-Mar-1995 Barry Tannenbaum
* EV5 changes
*
* 28-Mar-1995 Eric Rehm
* Fix aligment faults in align_color_brush_8 using _unaligned keyword.
*/
#include "driver.h"
#include "tgablt.h"
#include "tgastats.h"
extern LONG mix_to_rop[16];
typedef VOID (* PATTERN_PROC) (SURFOBJ *pso,
RECTL *rect,
ULONG *pattern,
int yOffset,
ULONG xor_bits);
/*
* dump_paint
*
* This routine is used to debug calls to DrvPaint. Dumps the parameters to
* the debug output
*/
VOID dump_paint (char *prefix,
SURFOBJ *pso,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
MIX mix)
{
#ifndef TEST_ENV
static int count = 0;
DISPDBG ((0, "\n\nPaint %d\n", count++));
DISPDBG ((0, "\n%s", prefix));
DISPDBG ((0, "Clip Object:\n"));
DumpCLIPOBJ (pco);
DISPDBG ((0, "Brush:\n"));
DumpBRUSHOBJ (pbo);
DISPDBG ((0, "Brush Origin: \n"));
DumpPOINTL (pptlBrushOrg);
DISPDBG ((0, "Mix: %08x ", mix));
if (mix & TGA_ROP_FLAG)
DISPDBG ((0, "TGA ROP: %s\n", name_tgarop (mix & 0xff)));
else
DISPDBG ((0, "R2: %s TGA ROP %s\n",
name_r2 (mix & 0x0f),
name_tgarop (mix_to_rop [mix & 0x0f])));
#endif
}
/*
* punt_paint
*
* This routine is called to punt a call to DrvPaint back to NT
*/
BOOL punt_paint (SURFOBJ *pso,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
MIX mix)
{
#ifdef TEST_ENV
return FALSE;
#else
BOOL status;
BOOL old_bInPuntRoutine;
PPDEV ppdev = (PPDEV) pso->dhpdev;
DISPDBG ((1, "Paint Punted\n"));
BUMP_TGA_STAT(pStats->paintpunts);
// If we've got a TGA ROP, return 0 since this is from DrvBitBlt.
// Attempting to punt in DrvPaint sometimes gets an ACCVIO
if (mix & TGA_ROP_FLAG)
return FALSE;
// Force back to simple mode and wait for memory to flush
if (! ppdev->bSimpleMode)
vSetSimpleMode (ppdev);
// Fetch the bits from the screen. For dense space systems this is a NOP
PUNT_GET_BITS (ppdev, CHOOSE_RECT (ppdev, pco));
// Let NT do it
old_bInPuntRoutine = ppdev->bInPuntRoutine;
ppdev->bInPuntRoutine = TRUE;
status = EngPaint (ppdev->pPuntSurf, pco, pbo, pptlBrushOrg, mix);
ppdev->bInPuntRoutine = old_bInPuntRoutine;
// Put the bits on the screen. For dense space systems this is a NOP
PUNT_PUT_BITS (status, ppdev, CHOOSE_RECT (ppdev, pco));
return status;
#endif
}
/*
* align_color_brush_8
*
* This routine builds an copy of the brush pattern aligned to the brush
* origin in X. It should not be called if the brush pattern is already
* aligned with the brush origin.
*/
#ifdef _ALPHA_ // If we can use 64 bit integers, it makes our life easier
ULONG *align_color_brush_8 (TGABRUSH *brush, ULONG left_shift)
{
int right_shift;
_unaligned unsigned __int64 *source;
_unaligned unsigned __int64 *aligned;
brush->aligned_x = left_shift;
source = (unsigned __int64 *)brush->ajPattern;
aligned = (unsigned __int64 *)(brush->ajPattern + brush->aligned_offset);
left_shift <<= 3;
right_shift = 64 - left_shift;
aligned[0] = (source[0] << left_shift) | (source[0] >> right_shift);
aligned[1] = (source[1] << left_shift) | (source[1] >> right_shift);
aligned[2] = (source[2] << left_shift) | (source[2] >> right_shift);
aligned[3] = (source[3] << left_shift) | (source[3] >> right_shift);
aligned[4] = (source[4] << left_shift) | (source[4] >> right_shift);
aligned[5] = (source[5] << left_shift) | (source[5] >> right_shift);
aligned[6] = (source[6] << left_shift) | (source[6] >> right_shift);
aligned[7] = (source[7] << left_shift) | (source[7] >> right_shift);
return (ULONG *)aligned;
}
#else
ULONG *align_color_brush_8 (TGABRUSH *brush, ULONG left_shift)
{
int y;
int right_shift;
ULONG *source;
ULONG *aligned;
brush->aligned_x = left_shift;
source = (ULONG *)brush->ajPattern;
aligned = (ULONG *)(brush->ajPattern + brush->aligned_offset);
if (left_shift < 4)
{
left_shift <<= 3;
right_shift = 32 - left_shift;
for (y = 0; y < 16; y +=2)
{
aligned[y] = (source[y] << left_shift) |
(source[y+1] >> right_shift);
aligned[y+1] = (source[y+1] << left_shift) |
(source[y] >> right_shift);
}
}
else if (left_shift == 4)
{
for (y = 0; y < 16; y +=2)
{
aligned[y] = source[y+1];
aligned[y+1] = source[y];
}
}
else
{
left_shift = (left_shift - 4) << 3;
right_shift = 32 - left_shift;
for (y = 0; y < 16; y +=2)
{
aligned[y] = (source[y+1] << left_shift) |
(source[y] >> right_shift);
aligned[y+1] = (source[y] << left_shift) |
(source[y+1] >> right_shift);
}
}
return aligned;
}
#endif
ULONG *align_color_brush (TGABRUSH *brush, ULONG left_shift)
{
return align_color_brush_8 (brush, left_shift);
}
/*
* align_color_brush_32
*
* This routine builds an copy of the brush pattern aligned to the brush
* origin in X. It should not be called if the brush pattern is already
* aligned with the brush origin.
*/
ULONG *align_color_brush_32 (TGABRUSH *brush, ULONG left_shift)
{
int i, x, y, base;
ULONG *source;
ULONG *aligned;
brush->aligned_x = left_shift;
left_shift = 8 - left_shift;
source = (ULONG *)brush->ajPattern;
aligned = (ULONG *)(brush->ajPattern + brush->aligned_offset);
i = 0;
for (y = 0; y < 8; y++)
{
base = i;
for (x = 0; x < 8; x++)
aligned[i++] = source[base + ((x + left_shift) & 0x07)];
}
return aligned;
}
/*
* align_mask
*
* This routine builds an aligned set of masks for use with the
* masked_block_fill and transparent_fill routines. It actually makes two
* copies; the first simply aligned to the brush origin, the second shifted
* by 4 pixels. We choose which to use based on whether bit 2 of the frame
* buffer address is set (FB address is divisible by 8 or 4)
*/
ULONG *align_mask (TGABRUSH *brush,
ULONG left_shift)
{
int y;
int right_shift = 32 - left_shift;
ULONG *source;
ULONG *aligned;
source = (ULONG *)(brush->ajPattern + brush->mask_offset);
aligned = (ULONG *)(brush->ajPattern + brush->aligned_mask_offset);
for (y = 0; y < 8; y++)
{
aligned[y] = (source[y] << left_shift) |
(source[y] >> right_shift);
aligned[y+8] = (aligned[y] << 4) |
(aligned[y] >> 28);
}
brush->aligned_mask_x = left_shift;
return aligned;
}
/*
* do_masked_pattern
*
* This routine actually fills the target rectangle with a masked pattern. It
* assumes that it's been given clipped rectangles.
*/
static __inline
VOID do_masked_pattern (SURFOBJ *pso, // Target surface
RECTL *rect, // Rectangle to be filled
ULONG *mask, // Aligned mask
int yOffset) // Origin for pattern
{
ULONG bytes_per_pixel;
PBYTE left_edge; // Framebuffer address of left edge of rectangle
PBYTE base_address;
int y; // Counts number of scanlines written
int width; // Width of the rectangle
int height; // Height of the rectangle
ULONG stride; // Width of surface being filled
ULONG *mask_ptr;
int align_pixels; // Pixels shifted to align
int i; // Index for pattern
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
// Fill each line of the rectangle. In block mode we can fill up to 2048
// pixels each write. Since none of the displays we're considering are
// wider than 1280 pixels/scanline, it should be safe to ignore considering
// whether we need more than 1 write/scanline
stride = SURFOBJ_stride(pso);
bytes_per_pixel = SURFOBJ_bytes_per_pixel(pso);
base_address = SURFOBJ_base_address(pso) +
(rect->top * stride) +
(rect->left * bytes_per_pixel);
// Calculate the alignment pixels and subtract them from the left edge to
// align to a 4-pixel boundry
align_pixels = (unsigned int)base_address & 0x03;
base_address -= align_pixels;
// Calculate the PixelCount and check for a valid number. Remember that
// the PixelCount is one minus the width
width = (rect->right - rect->left) - 1;
if (width < 0)
return;
// OR in the low bits of the address (the alignment pixels) into the upper
// word, since that's where BLOCK FILL mode looks for them
width |= (align_pixels << 16);
// Calculate the initial pattern index
i = (rect->top - yOffset) & 0x07;
// For each of the masks that we use
if ((ULONG)base_address & (0x04 * bytes_per_pixel))
mask_ptr = mask + 8;
else
mask_ptr = mask;
height = rect->bottom - rect->top;
if (height < 8)
{
left_edge = base_address;
while (height)
{
// Load the mask and pattern into the color registers taking the
// brush origin into account. Note that we don't have to worry
// about where we're starting to paint since the color registers
// always start at an octa-pixel boundry
CYCLE_REGS (ppdev);
TGADATA (ppdev, mask_ptr[i]);
i = (i + 1) & 0x07;
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height--;
}
}
else
{
ULONG stride8;
int j;
stride8 = stride << 3; // stride * 8
// Load the data register, then write to each scanline which uses
// this mask. Note that we don't have to worry about cycling the
// frame buffer, since each frame buffer write will be at least
// 7 * stride apart
for (j = 0; j < 8; j++)
{
CYCLE_REGS (ppdev);
TGADATA (ppdev, mask_ptr[i]);
i = (i + 1) & 0x07;
// Set the base address for this set of writes
left_edge = base_address;
base_address += stride;
// Fill each scanline
for (y = height - j; y > 0; y -= 8)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride8;
}
}
}
CYCLE_FB (ppdev);
}
/*
* masked_block_fill
*
* This routine paints one or more rectangles using TGA's block fill mode.
* The limitations on block fill mode are:
* - The length of the span is limited to 2K (not a problem since the
* biggest screen we support is 1280 pixels wide)
* - The stipple mask is specified only once
* - ROPs are ignored - Only copy is supported
*/
static
void masked_block_fill (SURFOBJ *pso, // Surface Object
CLIPOBJ *pco, // Clip List
ULONG *mask, // Aligned mask array to use
int yOffset, // Y index into brush
ULONG color) // Foreground color
{
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
ppdev->bSimpleMode = FALSE;
// Set the mode and raster op registers
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_BLOCK_FILL);
TGAROP (ppdev, ppdev->ulRopTemplate); // The rop isn't used in Block Fill mode
// Fill the color registers.
TGACOLOR0 (ppdev, color);
TGACOLOR1 (ppdev, color);
if (BMF_8BPP != SURFOBJ_format (pso))
{
TGACOLOR2 (ppdev, color);
TGACOLOR3 (ppdev, color);
TGACOLOR4 (ppdev, color);
TGACOLOR5 (ppdev, color);
TGACOLOR6 (ppdev, color);
TGACOLOR7 (ppdev, color);
}
// Clip the opaque rectangle as necessary
if (pco->iDComplexity != DC_COMPLEX)
do_masked_pattern (pso, &pco->rclBounds, mask, yOffset);
else
{
ULONG i; // Index into list of rectangles
BOOL more_rects; // Flags whether more rectangles to fill
ENUMRECTS8 cur_rect; // List of rectangles to fill
CLIPOBJ_cEnumStart (pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
more_rects = CLIPOBJ_bEnum (pco, sizeof(cur_rect),
(ULONG *)&cur_rect);
for (i = 0; i < cur_rect.c; i++)
do_masked_pattern (pso, &cur_rect.arcl[i], mask, yOffset);
} while (more_rects);
}
}
/*
* do_simple_32
*
* This routine paints one or more rectangles onto a 32bpp surface. This
* is being implemented using Simple mode.
*/
static
void do_simple_32 (SURFOBJ *pso, // Surface Object
RECTL *prcl, // Target rectangle
ULONG *pattern, // 8x8 brush to use
POINTL *pptlOrigin) // Brush origin
{
PPDEV ppdev = (PPDEV) pso->dhpdev;
ULONG *psrcLine;
PBYTE pdstLine;
ULONG *pdst;
int width;
int dstStride;
int i, j;
int xOffset;
int yOffset;
// Return if there's nothing to copy.
width = prcl->right - prcl->left;
if (width < 0)
return;
// Put destination in a different frame buffer alias,
// because this routine may have been called multiple
// times due to multiple clip objects.
//
// Cycle 'after' we get the base address, in the event
// we're dealing with an offscreen memory object, which
// will 'always' be first-alias based.
pdstLine = SURFOBJ_base_address(pso);
pdstLine = cycle_fb_address(ppdev, pdstLine);
// Get the destination scan line stride.
dstStride = SURFOBJ_stride(pso);
// Starting location of destination.
pdstLine = pdstLine + (prcl->top * dstStride) + (prcl->left << 2);
// Figure out the x and y offset into the pattern, taking into
// account the pattern origin and target rectangle.
if (pptlOrigin->x <= prcl->left)
xOffset = (prcl->left - pptlOrigin->x) & 0x07;
else
xOffset = 8 - ((pptlOrigin->x - prcl->left) & 0x07);
if (pptlOrigin->y <= prcl->top)
yOffset = ((prcl->top - pptlOrigin->y) & 0x07) << 3;
else
yOffset = (8 - ((pptlOrigin->y - prcl->top) & 0x07)) << 3;
// Write the pattern to the frame buffer one longword at a time.
for (i = 0; i < (prcl->bottom - prcl->top); i++)
{
psrcLine = &pattern[yOffset];
pdst = (ULONG *) pdstLine;
for (j = 0; j < width; j++, pdst++)
{
TGAWRITE (ppdev, pdst, psrcLine[(j + xOffset) & 0x7]);
}
pdstLine += dstStride;
pdstLine = cycle_fb_address(ppdev, pdstLine);
//
// yOffset + 8 to get to the next line of the brush (8 longwords).
// & 0x3f to recycle to the beginning of the brush.
//
yOffset = (yOffset + 8) & 0x3f;
}
}
/*
* simple_fill_32
*
* This routine paints one or more rectangles with an opaque pattern. It takes
* advantage of an undocumented feature of the TGA chip in 8BPP mode. Opaque
* fill mode will use the data from the foreground and background registers
* as 4 colors each. That is, an 8 pixel wide, 8BPP brush will fit into the
* foreground and background registers. We'll have to come up with some other
* way to handle opaque fill for 24 bit pixels...
*/
static
void simple_fill_32 (SURFOBJ *pso, // Surface Object
CLIPOBJ *pco, // Clip List
ULONG *pattern, // 8x8 brush to use
POINTL *pptlOrigin, // Brush origin
ULONG tga_rop) // TGA ROP to use
{
PPDEV ppdev = (PPDEV) pso->dhpdev; // Device context block
DISPDBG ((1, "TGA.DLL!simple_fill_32 - Entry\n"));
// Determine which bits to write for a given pixel.
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
// We'll always want to write to all the pixels for
// 32bpp targets, so set the pixel mask register here.
// And no, we don't have to set all the mask bits, since
// simple mode really only uses the low-order nibble,
// but what the heck, it can't hurt anything, right!?
TGAPIXELMASK (ppdev, 0xffffffff);
// Set the MODE and ROP registers.
// We don't need to conditionally set the 'source bitmap'
// bits, because Simple mode ignores them anyway.
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_SIMPLE);
TGAROP (ppdev, ppdev->ulRopTemplate | tga_rop);
// Clip the opaque rectangle as necessary
if (pco->iDComplexity != DC_COMPLEX)
do_simple_32 (pso, &pco->rclBounds, pattern, pptlOrigin);
else
{
ULONG i; // Index into list of rectangles
BOOL more_rects; // Flags whether more rectangles to fill
ENUMRECTS8 cur_rect; // List of rectangles to fill
CLIPOBJ_cEnumStart (pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
more_rects = CLIPOBJ_bEnum (pco, sizeof(cur_rect),
(ULONG *)&cur_rect);
for (i = 0; i < cur_rect.c; i++)
{
do_simple_32 (pso, &cur_rect.arcl[i], pattern, pptlOrigin);
CYCLE_FB (ppdev);
}
} while (more_rects);
}
DISPDBG ((1, "TGA.DLL!simple_fill_32 - Exit\n"));
}
/*
* do_opaque_8
*
* This routine actually fills the target rectangle. It assumes that
* it's been given clipped rectangles.
*/
static __inline
VOID do_opaque_8 (SURFOBJ *pso, // Target surface
RECTL *rect, // Rectangle to be filled
ULONG *pattern, // Aligned pattern
int yOffset) // Origin for pattern
{
PBYTE left_edge; // Framebuffer address of left edge of rectangle
PBYTE base_address;
int y; // Counts number of scanlines written
int width; // Width of the rectangle
ULONG height;
ULONG stride; // Width of surface being filled
ULONG fg_inc, bg_inc; // Increment for foreground & background colors
int align_pixels; // Pixels shifted to align
int i; // Index for pattern
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
// Fill each line of the rectangle. In block mode we can fill up to 2048
// pixels each write. Since none of the displays we're considering are
// wider than 1280 pixels/scanline, it should be safe to ignore considering
// whether we need more than 1 write/scanline
stride = SURFOBJ_stride(pso);
base_address = SURFOBJ_base_address(pso) +
(rect->top * stride) +
rect->left;
// Calculate the alignment pixels and subtract them from the left edge to
// align to a 4-pixel boundry
align_pixels = (unsigned int)base_address & 0x03;
base_address -= align_pixels;
// Since we're aligned to a 4 pixel boundry, and the pattern is aligned
// to an 8 pixel boundry, we have to potentially swap the foreground
// and background colors
if ((ULONG)base_address & 0x04)
{
fg_inc = 0;
bg_inc = 1;
}
else
{
fg_inc = 1;
bg_inc = 0;
}
// Calculate the PixelCount and check for a valid number. Remember that
// the PixelCount is one minus the width
width = (rect->right - rect->left) - 1;
if (width < 0)
return;
// OR in the low bits of the address (the alignment pixels) into the upper
// word, since that's where BLOCK FILL mode looks for them
width |= (align_pixels << 16);
// Calculate the initial pattern index
i = (rect->top - yOffset) & 0x07;
i <<= 1;
// Fill each scanline
// For each of the sets of data registers that we use
height = rect->bottom - rect->top;
if (height < 8)
{
left_edge = base_address;
// We've got less than 8 scanlines to fill, so load each set of color
// registers and then write to the appropriate scanline
while (height)
{
CYCLE_REGS (ppdev);
TGAFOREGROUND (ppdev, pattern[i+fg_inc]);
TGABACKGROUND (ppdev, pattern[i+bg_inc]);
i = (i + 2) & 0x0f;
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height--;
}
}
else
{
ULONG stride8;
ULONG j;
stride8 = stride << 3; // stride * 8
// Load each set of color registers and then write to all of the
// scanlines that are to be colored. We don't have to worry about
// cycling the FB address, since the write to the frame buffer at
// the top of the loop will be at least 7 * stride away from the
// last write to the frame buffer
for (j = 0; j < 8; j++)
{
CYCLE_REGS (ppdev);
TGAFOREGROUND (ppdev, pattern[i+fg_inc]);
TGABACKGROUND (ppdev, pattern[i+bg_inc]);
i = (i + 2) & 0x0f;
// Set the base address for this set of writes
left_edge = base_address;
base_address += stride;
// Fill each scanline which uses this set of colors
for (y = height - j; y > 0; y -= 8)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride8;
}
}
}
}
/*
* opaque_fill_8
*
* This routine paints one or more rectangles with an opaque pattern. It takes
* advantage of an undocumented feature of the TGA chip in 8BPP mode. Opaque
* fill mode will use the data from the foreground and background registers
* as 4 colors each. That is, an 8 pixel wide, 8BPP brush will fit into the
* foreground and background registers. We'll have to come up with some other
* way to handle opaque fill for 24 bit pixels...
*/
static
void opaque_fill_8 (SURFOBJ *pso, // Surface Object
CLIPOBJ *pco, // Clip List
ULONG *pattern, // Aligned 8x8 brush to use
int yOffset, // Y index into brush
ULONG tga_rop) // TGA ROP to use
{
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
ppdev->bSimpleMode = FALSE;
// Set the mode and raster op registers
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
TGAPIXELMASK (ppdev, 0xffffffff);
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_OPAQUE_FILL);
TGAROP (ppdev, ppdev->ulRopTemplate | tga_rop);
TGADATA (ppdev, 0xf0f0f0f0); // Foreground/Background mask
// Clip the opaque rectangle as necessary
if (pco->iDComplexity != DC_COMPLEX)
do_opaque_8 (pso, &pco->rclBounds, pattern, yOffset);
else
{
ULONG i; // Index into list of rectangles
BOOL more_rects; // Flags whether more rectangles to fill
ENUMRECTS8 cur_rect; // List of rectangles to fill
CLIPOBJ_cEnumStart (pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
more_rects = CLIPOBJ_bEnum (pco, sizeof(cur_rect),
(ULONG *)&cur_rect);
for (i = 0; i < cur_rect.c; i++)
{
do_opaque_8 (pso, &cur_rect.arcl[i], pattern, yOffset);
CYCLE_FB (ppdev);
}
} while (more_rects);
}
}
/*
* do_pattern_8
*
* This routine actually fills the target rectangle. It assumes that
* it's been given clipped rectangles.
*/
static
VOID do_pattern_8 (SURFOBJ *pso, // Target surface
RECTL *rect, // Rectangle to be filled
ULONG *pattern, // Aligned pattern
int yOffset, // Origin for pattern
ULONG xor_bits) // Bits to XOR with pattern
{
PBYTE left_edge; // Framebuffer address of left edge of rectangle
PBYTE base_address;
int y; // Counts number of scanlines written
int width; // Width of the rectangle
int height; // Height of the rectangle
ULONG stride; // Width of surface being filled
int align_pixels; // Pixels shifted to align
int i; // Index for pattern
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
// Fill each line of the rectangle. In block mode we can fill up to 2048
// pixels each write. Since none of the displays we're considering are
// wider than 1280 pixels/scanline, it should be safe to ignore considering
// whether we need more than 1 write/scanline
stride = SURFOBJ_stride(pso);
base_address = SURFOBJ_base_address(pso) +
(rect->top * stride) +
rect->left;
// Calculate the alignment pixels and subtract them from the left edge to
// align to a 4-pixel boundry
align_pixels = (unsigned int)base_address & 0x03;
base_address -= align_pixels;
// Calculate the PixelCount and check for a valid number. Remember that
// the PixelCount is one minus the width
width = (rect->right - rect->left) - 1;
if (width < 0)
return;
// OR in the low bits of the address (the alignment pixels) into the upper
// word, since that's where BLOCK FILL mode looks for them
width |= (align_pixels << 16);
// Calculate the initial pattern index
i = (rect->top - yOffset) & 0x07;
i <<= 1;
// For each of the sets of data registers that we use
height = rect->bottom - rect->top;
if (height < 8)
{
left_edge = base_address;
while (height)
{
// Load the pattern into the color registers taking the brush origin
// into account. Note that we don't have to worry about where we're
// starting to paint since the color registers always start at an
// octa-pixel boundry
CYCLE_REGS (ppdev);
TGACOLOR0 (ppdev, pattern[i] ^ xor_bits);
TGACOLOR1 (ppdev, pattern[i+1] ^ xor_bits);
i += 2;
i &= 0x0f;
// Fill each scanline which uses this set of colors
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height--;
}
}
else
{
ULONG stride8;
int j; // Index for pattern
stride8 = stride << 3; // stride * 8
for (j = 0; j < 8; j++)
{
// Load the pattern into the color registers taking the brush origin
// into account. Note that we don't have to worry about where we're
// starting to paint since the color registers always start at an
// octa-pixel boundry
CYCLE_REGS (ppdev);
TGACOLOR0 (ppdev, pattern[i] ^ xor_bits);
TGACOLOR1 (ppdev, pattern[i+1] ^ xor_bits);
i = (i + 2) & 0x0f;
// Set the base address for this set of writes
left_edge = base_address;
base_address += stride;
// Fill each scanline which uses this set of colors
for (y = height - j; y > 0; y -= 8)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride8;
}
}
}
CYCLE_FB (ppdev);
}
/*
* do_pattern_32
*
* This routine actually fills the target rectangle. It assumes that
* it's been given clipped rectangles.
*/
static
VOID do_pattern_32 (SURFOBJ *pso, // Target surface
RECTL *rect, // Rectangle to be filled
ULONG *pattern, // Aligned pattern
int yOffset, // Origin for pattern
ULONG xor_bits) // Bits to XOR with pattern
{
PBYTE left_edge; // Framebuffer address of left edge of rectangle
PBYTE base_address;
int y; // Counts number of scanlines written
int width; // Width of the rectangle
int height; // Height of the rectangle
ULONG stride; // Width of surface being filled
int align_pixels; // Pixels shifted to align
int i; // Index for pattern
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
// Fill each line of the rectangle. In block mode we can fill up to 2048
// pixels each write. Since none of the displays we're considering are
// wider than 1280 pixels/scanline, it should be safe to ignore considering
// whether we need more than 1 write/scanline
stride = SURFOBJ_stride(pso);
base_address = SURFOBJ_base_address(pso) +
(rect->top * stride) +
(rect->left << 2); // * sizeof(ULONG)
// Calculate the alignment pixels and subtract them from the left edge to
// align to a 4-pixel boundry
align_pixels = (unsigned int)base_address & 0x03;
base_address -= align_pixels;
// Calculate the PixelCount and check for a valid number. Remember that
// the PixelCount is one minus the width
width = (rect->right - rect->left) - 1;
if (width < 0)
return;
// OR in the low bits of the address (the alignment pixels) into the upper
// word, since that's where BLOCK FILL mode looks for them
width |= (align_pixels << 16);
// Calculate the initial pattern index
i = (rect->top - yOffset) & 0x07;
i <<= 3; // *8
// For each of the sets of data registers that we use
height = rect->bottom - rect->top;
if (height < 8)
{
left_edge = base_address;
while (height)
{
// Load the pattern into the color registers taking the brush origin
// into account. Note that we don't have to worry about where we're
// starting to paint since the color registers always start at an
// octa-pixel boundry
CYCLE_REGS (ppdev);
TGACOLOR0 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR1 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR2 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR3 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR4 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR5 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR6 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR7 (ppdev, pattern[i++] ^ xor_bits);
i &= 0x3f;
// Fill each scanline which uses this set of colors
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height--;
}
}
else
{
ULONG stride8;
int j; // Index for pattern
stride8 = stride << 3; // stride * 8
for (j = 0; j < 8; j++)
{
// Load the pattern into the color registers taking the brush origin
// into account. Note that we don't have to worry about where we're
// starting to paint since the color registers always start at an
// octa-pixel boundry
CYCLE_REGS (ppdev);
TGACOLOR0 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR1 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR2 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR3 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR4 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR5 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR6 (ppdev, pattern[i++] ^ xor_bits);
TGACOLOR7 (ppdev, pattern[i++] ^ xor_bits);
i &= 0x3f;
// Set the base address for this set of writes
left_edge = base_address;
base_address += stride;
// Fill each scanline which uses this set of colors
for (y = height - j; y > 0; y -= 8)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride8;
}
}
}
CYCLE_FB (ppdev);
}
/*
* block_fill
*
* This routine paints one or more rectangles using TGA's block fill mode.
* The limitations on block fill mode are:
* - The length of the span is limited to 2K (not a problem since the
* biggest screen we support is 1280 pixels wide)
* - The stipple mask is specified only once
* - ROPs are ignored - Only copy is supported
*/
static
void block_fill (SURFOBJ *pso, // Surface Object
CLIPOBJ *pco, // Clip List
ULONG *pattern, // Aligned 8x8 brush to use
int yOffset, // Y index into brush
ULONG xor_bits) // Bits to XOR with pattern
{
PATTERN_PROC pattern_rtn;
PPDEV ppdev = (PPDEV) pso->dhpdev;
// Note that the chip is no long in simple mode
ppdev->bSimpleMode = FALSE;
// Choose between 8BPP and 24BPP boards
// Make sure to mask off the high 8 bits if 24 plane.
if (BMF_8BPP == SURFOBJ_format (pso))
pattern_rtn = do_pattern_8;
else
pattern_rtn = do_pattern_32;
// Set the mode and raster op registers
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_BLOCK_FILL);
TGAROP (ppdev, ppdev->ulRopTemplate); // The rop isn't used in Block Fill mode
TGADATA (ppdev, 0xffffffff); // Write to all 32 pixels
// Clip the opaque rectangle as necessary
if (pco->iDComplexity != DC_COMPLEX)
pattern_rtn (pso, &pco->rclBounds, pattern, yOffset, xor_bits);
else
{
ULONG i; // Index into list of rectangles
BOOL more_rects; // Flags whether more rectangles to fill
ENUMRECTS8 cur_rect; // List of rectangles to fill
CLIPOBJ_cEnumStart (pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
more_rects = CLIPOBJ_bEnum (pco, sizeof(cur_rect),
(ULONG *)&cur_rect);
for (i = 0; i < cur_rect.c; i++)
pattern_rtn (pso, &cur_rect.arcl[i], pattern, yOffset, xor_bits);
} while (more_rects);
}
}
/*
* do_transparent
*
* This routine actually fills the target rectangle. It assumes that
* it's been given clipped rectangles.
*/
static __inline
VOID do_transparent (SURFOBJ *pso, // Target surface
RECTL *rect, // Rectangle to be filled
ULONG *mask, // Aligned pattern
int yOffset) // Origin for mask
{
PBYTE left_edge; // Framebuffer address of left edge of rectangle
PBYTE base_address;
int y; // Counts number of scanlines written
int width; // Width of the rectangle
ULONG height; // Height of the rectangle
ULONG stride; // Width of surface being filled
int align_pixels; // Pixels shifted to align
int i; // Index for pattern
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
// Fill each line of the rectangle. In block mode we can fill up to 2048
// pixels each write. Since none of the displays we're considering are
// wider than 1280 pixels/scanline, it should be safe to ignore considering
// whether we need more than 1 write/scanline
stride = SURFOBJ_stride(pso);
base_address = SURFOBJ_base_address(pso) +
(rect->top * stride) +
(rect->left * SURFOBJ_bytes_per_pixel (pso));
// Calculate the alignment pixels and subtract them from the left edge to
// align to a 4-pixel boundry
align_pixels = (unsigned int)base_address & 0x03;
base_address -= align_pixels;
// Calculate the PixelCount and check for a valid number. Remember that
// the PixelCount is one minus the width
width = (rect->right - rect->left) - 1;
if (width < 0)
return;
// OR in the low bits of the address (the alignment pixels) into the upper
// word, since that's where BLOCK FILL mode looks for them
width |= (align_pixels << 16);
// Calculate the initial pattern index
i = (rect->top - yOffset) & 0x07;
// For each of the sets of data registers that we use
height = rect->bottom - rect->top;
if (height < 8)
{
left_edge = base_address;
while (height)
{
// Load the pattern into the color registers taking the brush origin
// into account. Note that we don't have to worry about where we're
// starting to paint since the color registers always start at an
// octa-pixel boundry
CYCLE_REGS (ppdev);
TGADATA (ppdev, mask[i]);
i = (i + 1) & 0x07;
// Fill each scanline which uses this pattern
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height--;
}
}
else
{
ULONG stride8;
int j; // Index for pattern
stride8 = stride << 3; // stride * 8
for (j = 0; j < 8; j++)
{
// Load the pattern into the color registers taking the brush origin
// into account. Note that we don't have to worry about where we're
// starting to paint since the color registers always start at an
// octa-pixel boundry
CYCLE_REGS (ppdev);
TGADATA (ppdev, mask[i]);
i = (i + 1) & 0x07;
// Set the base address for this set of writes
left_edge = base_address;
base_address += stride;
// Fill each scanline which uses this set of colors
for (y = height - j; y > 0; y -= 8)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride8;
}
}
}
CYCLE_FB (ppdev);
}
/*
* transparent_fill
*
* This routine paints one or more rectangles with an opaque pattern. It takes
* advantage of an undocumented feature of the TGA chip in 8BPP mode. Opaque
* fill mode will use the data from the foreground and background registers
* as 4 colors each. That is, an 8 pixel wide, 8BPP brush will fit into the
* foreground and background registers. We'll have to come up with some other
* way to handle opaque fill for 24 bit pixels...
*/
static __inline
void transparent_fill (SURFOBJ *pso, // Surface Object
CLIPOBJ *pco, // Clip List
ULONG *mask, // Aligned mask to use
int yOffset, // Y index into brush
ULONG color, // Foreground color to use
ULONG tga_rop) // TGA ROP to use
{
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
// Note that the chip is no long in simple mode
ppdev->bSimpleMode = FALSE;
// Set the foreground color and plane mask
TGAFOREGROUND (ppdev, color);
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
// Set the mode and raster op registers
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_TRANSPARENT_FILL);
TGAROP (ppdev, ppdev->ulRopTemplate | tga_rop);
// Clip the opaque rectangle as necessary
if (pco->iDComplexity != DC_COMPLEX)
do_transparent (pso, &pco->rclBounds, mask, yOffset);
else
{
ULONG i; // Index into list of rectangles
BOOL more_rects; // Flags whether more rectangles to fill
ENUMRECTS8 cur_rect; // List of rectangles to fill
CLIPOBJ_cEnumStart (pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
more_rects = CLIPOBJ_bEnum (pco, sizeof(cur_rect),
(ULONG *)&cur_rect);
for (i = 0; i < cur_rect.c; i++)
do_transparent (pso, &cur_rect.arcl[i], mask, yOffset);
} while (more_rects);
}
}
/*
* do_solid
*
* This routine actually fills the opaque rectangle. It assumes that
* it's been given clipped rectangles.
*/
static __inline
VOID do_solid (SURFOBJ *pso, // Surface to fill
RECTL *rect) // Rectangle to be filled
{
PBYTE left_edge; // Framebuffer address of left edge of rectangle
int width; // Width of the opaque rectangle
ULONG height; // Height of the opaque rectangle
int align_pixels; // Pixels shifted to align
PPDEV ppdev = // Device context
(PPDEV) pso->dhpdev;
ULONG stride; // Width of destination
// Fill each line of the rectangle. In block mode we can fill up to 2048
// pixels each write. Since none of the displays we're considering are
// wider than 1280 pixels/scanline, it should be safe to ignore considering
// whether we need more than 1 write/scanline
stride = SURFOBJ_stride (pso);
left_edge = SURFOBJ_base_address (pso) +
(rect->top * stride) +
(rect->left * SURFOBJ_bytes_per_pixel (pso));
// Calculate the alignment pixels and subtract them from the left edge to
// align to a 4-pixel boundry
align_pixels = (unsigned int)left_edge & 0x03;
left_edge -= align_pixels;
// Remember that the width does *not* include the right edge, so subtract
// one
width = (rect->right - rect->left) - 1;
// OR in the low bits of the address (the alignment pixels) into the upper
// word, since that's where BLOCK FILL mode looks for them
width |= (align_pixels << 16);
// Fill each scanline
height = rect->bottom - rect->top;
if (height & 0x01)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height--;
}
if (height & 0x02)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height -= 2;
}
while (height)
{
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
TGAWRITE (ppdev, left_edge, width);
left_edge += stride;
height -= 4;
}
CYCLE_FB (ppdev);
}
/*
* fill_solid_color
*
* This routine paints one or more rectangles with a solid color
*/
BOOL fill_solid_color (SURFOBJ *pso, // Surface to fill
CLIPOBJ *pco, // Clip List
ULONG color, // Color to fill rectangle with
ULONG tga_rop) // ROP to use
{
PPDEV ppdev = // Device context block
(PPDEV) pso->dhpdev;
// Note that the chip is no long in simple mode
ppdev->bSimpleMode = FALSE;
// If the ROP is COPY (simply set the rectangle(s) to the solid color) we
// can use BLOCK_FILL mode. Unfortunately, BLOCK_FILL mode doesn't pay any
// attention to the ROP, so if we want to do anything fancy (say, XOR the
// the data onto the screen) we have to use TRANSPARENT_FILL. BLOCK_FILL
// is faster (about 4x, but TRANSPARENT_FILL is more flexible)
if (TGA_ROP_COPY == tga_rop)
{
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_BLOCK_FILL);
TGAROP (ppdev, ppdev->ulRopTemplate); // The rop isn't used in Block Fill mode
TGADATA (ppdev, 0xffffffff); // Write to all 32 pixels
TGACOLOR0 (ppdev, color);
TGACOLOR1 (ppdev, color);
if (BMF_8BPP != SURFOBJ_format (pso))
{
TGACOLOR2 (ppdev, color);
TGACOLOR3 (ppdev, color);
TGACOLOR4 (ppdev, color);
TGACOLOR5 (ppdev, color);
TGACOLOR6 (ppdev, color);
TGACOLOR7 (ppdev, color);
}
}
else
{
TGAFOREGROUND (ppdev, color);
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_TRANSPARENT_FILL);
TGAROP (ppdev, ppdev->ulRopTemplate | tga_rop);
TGADATA (ppdev, 0xffffffff); // Write to all 32 pixels
}
// Fill the assorted clipping rectangles
if (DC_COMPLEX != pco->iDComplexity)
do_solid (pso, &pco->rclBounds);
else
{
ULONG i; // Index into list of rectangles
BOOL more_rects; // Flags whether more rectangles to fill
ENUMRECTS8 cur_rect; // List of rectangles to fill
CLIPOBJ_cEnumStart (pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
more_rects = CLIPOBJ_bEnum (pco, sizeof(cur_rect),
(ULONG *)&cur_rect);
for (i = 0; i < cur_rect.c; i++)
do_solid (pso, &cur_rect.arcl[i]);
} while (more_rects);
}
return TRUE;
}
/*
* DrvPaint
*
* GDI (and bBitBlt) calls this routine to fill a rectangle with a color or
* a pattern
*/
BOOL DrvPaint (SURFOBJ *pso,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
MIX mix)
{
PPDEV ppdev;
ULONG tga_rop;
BOOL solid_pattern;
DISPDBG ((1, "TGA.DLL!DrvPaint - Entry\n"));
BUMP_TGA_STAT(pStats->paints);
ppdev = (PPDEV) pso->dhpdev;
// We only look at the lower half of the mix to figure out what raster op
// to use. If the high bit is set, then bBitBlt has called us and passed
// us the TGA ROP with the high bit set.
if (mix & TGA_ROP_FLAG)
{
tga_rop = mix & 0xff;
solid_pattern = TRUE;
}
else
{
// Protect against NULL clip objects.
// Blit code guarantees a valid pco.
if (NULL == pco)
{
DISPDBG ((0, "DrvPaint - Null clip object found!!!\n"));
BUMP_TGA_STAT(pStats->paintpunts);
return FALSE;
}
tga_rop = mix_to_rop [mix & 0x0f];
solid_pattern = (R2_COPYPEN == ((mix & 0xff00) >> 8));
}
WBFLUSH (ppdev);
// Now that we know the ROP, we can check for the brush if it's needed
switch (tga_rop)
{
case TGA_ROP_SET: // Whiteness - Set region to 0xff
fill_solid_color (pso, pco, 0xffffffff, TGA_ROP_COPY);
break;
case TGA_ROP_CLEAR: // Blackness - Set region to 0x00
fill_solid_color (pso, pco, 0, TGA_ROP_COPY);
break;
case TGA_ROP_INVERT: // DstInvert - Invert region
fill_solid_color (pso, pco, 0, tga_rop);
break;
case TGA_ROP_NOP:
return TRUE; // Nop - We can do nothing real fast!
default: // A rop with expects a brush
{
ULONG color;
TGABRUSH *brush;
LONG xOffset;
if (NULL == pbo)
{
DISPDBG ((0, "DrvPaint - Null brush found!!!\n"));
return FALSE;
}
// If the we've got a solid color fill the region with the given
// color
color = pbo->iSolidColor;
if (0xffffffff != color)
{
if (BMF_8BPP == SURFOBJ_format (pso))
{
color |= color << 8;
color |= color << 16;
}
// If the ROP is COPY_INVERTED, invert the color and switch
// to COPY. This allows us to use block fill mode with is
// 4x faster than transparent or opaque fill
if (tga_rop == TGA_ROP_COPY_INVERTED)
{
color = ~color;
tga_rop = TGA_ROP_COPY;
}
fill_solid_color (pso, pco, color, tga_rop);
break;
}
// Nope. We've got a pattern. Fetch it if necessary
//dump_paint ("", pso, pco, pbo, pptlBrushOrg, mix);
brush = pbo->pvRbrush;
if (NULL == brush)
{
brush = BRUSHOBJ_pvGetRbrush (pbo);
if (NULL == brush)
{
DISPDBG ((1, "Null brush returned - DrvPaint punted\n"));
return punt_paint (pso, pco, pbo, pptlBrushOrg, mix);
}
}
xOffset = pptlBrushOrg->x & 0x07;
// If this is a solid pattern, align the pattern to the origin
// of the brush and then fill. Block fill is fastest, but can
// only handle a simple copy. Opaque fill can handle a ROP,
// but is slower.
if (solid_pattern)
{
ULONG *pattern;
// Check whether we've got an aligned pattern handy. If
// not, then we've got to create one.
if (0 == xOffset)
pattern = (ULONG *)brush->ajPattern;
else
{
if (xOffset == brush->aligned_x)
pattern = (ULONG *)(brush->ajPattern +
brush->aligned_offset);
else
if (BMF_8BPP == SURFOBJ_format (pso))
pattern = align_color_brush_8 (brush, xOffset);
else
pattern = align_color_brush_32 (brush, xOffset);
}
if (TGA_ROP_COPY == tga_rop)
block_fill (pso, pco, pattern, pptlBrushOrg->y, 0x00000000);
else if (TGA_ROP_COPY_INVERTED == tga_rop)
block_fill (pso, pco, pattern, pptlBrushOrg->y, 0xffffffff);
else
if (BMF_8BPP == SURFOBJ_format (pso))
opaque_fill_8 (pso, pco, pattern, pptlBrushOrg->y, tga_rop);
else
simple_fill_32 (pso, pco, (ULONG *) brush->ajPattern,
pptlBrushOrg, tga_rop);
}
else
{
// A transparent pattern. We only handle transparent 1BPP
// brushes, so punt if we've got something different.
// Align the mask to the origin of the brush and then fill.
// Again, block fill is fastest, but only can't handle a
// ROP. Transparent fill is more flexible, but slower.
if (BMF_1BPP != brush->iBitmapFormat)
{
DISPDBG ((0, "Transparent paint for non-monochrome bitmap\n"));
return punt_paint (pso, pco, pbo, pptlBrushOrg, mix);
}
else
{
ULONG *mask;
if (0 == xOffset)
mask = (ULONG *)(brush->ajPattern +
brush->mask_offset);
else
if (brush->aligned_mask_x == xOffset)
mask = (ULONG *)(brush->ajPattern +
brush->aligned_mask_offset);
else
mask = align_mask (brush, xOffset);
if (TGA_ROP_COPY == tga_rop)
masked_block_fill (pso, pco, mask, pptlBrushOrg->y,
brush->ulForeColor);
else if (TGA_ROP_COPY_INVERTED == tga_rop)
masked_block_fill (pso, pco, mask, pptlBrushOrg->y,
~brush->ulForeColor);
else
transparent_fill (pso, pco, mask, pptlBrushOrg->y,
brush->ulForeColor, tga_rop);
}
}
}
}
// Check whether we have to leave TGA in simple mode
#ifndef TEST_ENV
if (ppdev->bInPuntRoutine)
vSetSimpleMode (ppdev);
#endif
DISPDBG ((1, "TGA.DLL!DrvPaint - Exit\n"));
return TRUE;
}