mirror of https://github.com/lianthony/NT4.0
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.
607 lines
17 KiB
607 lines
17 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: bitblt.c *
|
|
* *
|
|
* This module hooks DrvBitBlt and DrvCopyBits. *
|
|
* *
|
|
* Copyright (c) 1992 Microsoft Corporation *
|
|
* Copyright (c) 1995 IBM Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "driver.h"
|
|
#include "hw.h"
|
|
|
|
//
|
|
// function prototypes
|
|
//
|
|
BOOL bIntersect (
|
|
RECTL *prcl1,
|
|
RECTL *prcl2,
|
|
RECTL *prclResult );
|
|
|
|
VOID vHwScrnToScrnCpy (
|
|
PPDEV ppdev,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc );
|
|
|
|
BOOL bScrnToScrnCpy (
|
|
PPDEV ppdev,
|
|
CLIPOBJ *pco,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc );
|
|
|
|
VOID vHwSolidFill(
|
|
PPDEV ppdev,
|
|
RECTL *prclDst,
|
|
ULONG color );
|
|
|
|
BOOL bSolidFill (
|
|
PPDEV ppdev,
|
|
CLIPOBJ *pco,
|
|
RECTL *prclDst,
|
|
ULONG color );
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bIntersect
|
|
*
|
|
* If 'prcl1' and 'prcl2' intersect, has a return value of TRUE and returns
|
|
* the intersection in 'prclResult'. If they don't intersect, has a return
|
|
* value of FALSE, and 'prclResult' is undefined.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bIntersect (
|
|
RECTL *prcl1,
|
|
RECTL *prcl2,
|
|
RECTL *prclResult )
|
|
|
|
{
|
|
|
|
//
|
|
// Compute the maximum left edge and the minimum right edge.
|
|
//
|
|
|
|
prclResult->left = max(prcl1->left, prcl2->left);
|
|
prclResult->right = min(prcl1->right, prcl2->right);
|
|
|
|
//
|
|
// If the minimum right edge is greater than the maximum left edge,
|
|
// then the rectanges may intersect. Otherwise, they do not intersect.
|
|
//
|
|
|
|
if (prclResult->left < prclResult->right) {
|
|
|
|
//
|
|
// Compute the maximum top edge and the minimum bottom edge.
|
|
//
|
|
|
|
prclResult->top = max(prcl1->top, prcl2->top);
|
|
prclResult->bottom = min(prcl1->bottom, prcl2->bottom);
|
|
|
|
//
|
|
// If the minimum bottom edge is greater than the maximum top
|
|
// edge, then the rectanges intersect. Otherwise, they do not
|
|
// intersect.
|
|
//
|
|
|
|
if (prclResult->top < prclResult->bottom) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vHwScrnToScrnCpy
|
|
*
|
|
* Does screen-to-screen copy using WD hardware accelerator
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vHwScrnToScrnCpy (
|
|
PPDEV ppdev,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc )
|
|
|
|
{
|
|
ULONG source, target, direction, width, height;
|
|
|
|
width = prclDst->right - prclDst->left;
|
|
height = prclDst->bottom - prclDst->top;
|
|
|
|
if ((pptlSrc->y < prclDst->top) ||
|
|
((pptlSrc->y == prclDst->top) && (pptlSrc->x < prclDst->left))) {
|
|
|
|
//
|
|
// Start BITBLT at bottom right corner of rectangle increasing left and up
|
|
//
|
|
direction = 0x0400;
|
|
source = (pptlSrc->y + height - 1) * ppdev->lDeltaScreen + (pptlSrc->x + width - 1);
|
|
target = (prclDst->top + height - 1) * ppdev->lDeltaScreen + (prclDst->left + width - 1);
|
|
|
|
//
|
|
// Adjust start address if 16bpp mode
|
|
//
|
|
if (ppdev->ulBitCount == 16) {
|
|
source += pptlSrc->x + width;
|
|
target += prclDst->left + width;
|
|
width *= 2;
|
|
} /* endif */
|
|
|
|
} else {
|
|
|
|
//
|
|
// Start BITBLT at top left corner of rectangle increasing right and down
|
|
//
|
|
direction = 0;
|
|
source = pptlSrc->y * ppdev->lDeltaScreen + pptlSrc->x;
|
|
target = prclDst->top * ppdev->lDeltaScreen + prclDst->left;
|
|
|
|
//
|
|
// Adjust start address if 16bpp mode
|
|
//
|
|
if (ppdev->ulBitCount == 16) {
|
|
source += pptlSrc->x;
|
|
target += prclDst->left;
|
|
width *= 2;
|
|
} /* endif */
|
|
|
|
} /* endif */
|
|
|
|
WAIT_BLT_COMPLETE(); // wait for BITBLT completion
|
|
|
|
OUTPW(EPR_DATA, BLT_CTRL2 | 0);
|
|
OUTPW(EPR_DATA, BLT_SRC_LO | (USHORT)( source & 0x0FFF));
|
|
OUTPW(EPR_DATA, BLT_SRC_HI | (USHORT)((source >> 12) & 0x01FF));
|
|
OUTPW(EPR_DATA, BLT_DST_LO | (USHORT)( target & 0x0FFF));
|
|
OUTPW(EPR_DATA, BLT_DST_HI | (USHORT)((target >> 12) & 0x01FF));
|
|
OUTPW(EPR_DATA, BLT_SIZE_X | (USHORT)width);
|
|
OUTPW(EPR_DATA, BLT_SIZE_Y | (USHORT)height);
|
|
OUTPW(EPR_DATA, BLT_DELTA | (USHORT)ppdev->lDeltaScreen);
|
|
OUTPW(EPR_DATA, BLT_ROPS | 0x0300); // source copy operation
|
|
OUTPW(EPR_DATA, BLT_PLANE | 0x00FF); // enable all planes
|
|
OUTPW(EPR_DATA, BLT_CTRL1 | 0x0900 | (USHORT)direction ); // start BITBLT
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bScrnToScrnCpy
|
|
*
|
|
* Clips and moves the data from screen to screen
|
|
* Returns TRUE if it is successfully completed
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bScrnToScrnCpy (
|
|
PPDEV ppdev,
|
|
CLIPOBJ *pco,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc )
|
|
|
|
{
|
|
RECTL BltRectl;
|
|
ENUMRECTS ClipEnum;
|
|
BOOL MoreClipRects;
|
|
ULONG ClipRegions;
|
|
POINTL SrcPoint;
|
|
|
|
//
|
|
// Figure out the real clipping complexity
|
|
//
|
|
|
|
switch ((pco != NULL) ? pco->iDComplexity : DC_TRIVIAL) {
|
|
|
|
case DC_TRIVIAL:
|
|
|
|
vHwScrnToScrnCpy(ppdev, prclDst, pptlSrc);
|
|
|
|
return TRUE;
|
|
|
|
case DC_RECT:
|
|
|
|
//
|
|
// only do the BLT if there is an intersection
|
|
//
|
|
|
|
if (bIntersect(prclDst,&pco->rclBounds,&BltRectl)) {
|
|
|
|
//
|
|
// Adjust the Source for the intersection rectangle.
|
|
//
|
|
|
|
pptlSrc->x += BltRectl.left - prclDst->left;
|
|
pptlSrc->y += BltRectl.top - prclDst->top;
|
|
|
|
vHwScrnToScrnCpy(ppdev, &BltRectl, pptlSrc);
|
|
|
|
} /* endif */
|
|
|
|
return TRUE;
|
|
|
|
case DC_COMPLEX:
|
|
|
|
if (-1 != CLIPOBJ_cEnumStart(pco,FALSE,CT_RECTANGLES,CD_ANY,0)) {
|
|
|
|
do {
|
|
|
|
//
|
|
// Get list of clip rectangles.
|
|
//
|
|
|
|
MoreClipRects = CLIPOBJ_bEnum(pco,sizeof(ClipEnum),(PVOID)&ClipEnum);
|
|
|
|
for (ClipRegions=0;ClipRegions<ClipEnum.c;ClipRegions++) {
|
|
|
|
//
|
|
// If the rectangles intersect calculate the offset to the
|
|
// source start location to match and do the BitBlt.
|
|
//
|
|
if (bIntersect(prclDst,
|
|
&ClipEnum.arcl[ClipRegions],
|
|
&BltRectl)) {
|
|
SrcPoint.x = pptlSrc->x + BltRectl.left - prclDst->left;
|
|
SrcPoint.y = pptlSrc->y + BltRectl.top - prclDst->top;
|
|
|
|
vHwScrnToScrnCpy(ppdev, &BltRectl, &SrcPoint);
|
|
|
|
} /* endif */
|
|
} /* endfor */
|
|
} while (MoreClipRects); /* enddo */
|
|
|
|
return TRUE;
|
|
|
|
} /* endif */
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
} /* endswitch */
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vHwSolidFill
|
|
*
|
|
* Fills the rectangle with a solid color using WD hardware accelerator
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vHwSolidFill(
|
|
PPDEV ppdev,
|
|
RECTL *prclDst,
|
|
ULONG color )
|
|
|
|
{
|
|
ULONG source, target, width, height;
|
|
PUSHORT pusBitbltPattern;
|
|
LONG i;
|
|
|
|
width = prclDst->right - prclDst->left;
|
|
height = prclDst->bottom - prclDst->top;
|
|
target = prclDst->top * ppdev->lDeltaScreen + prclDst->left;
|
|
|
|
WAIT_BLT_COMPLETE(); // wait for BITBLT completion
|
|
|
|
if (ppdev->ulBitCount == 8) {
|
|
|
|
//
|
|
// Use Fixed Color Fill in 8bpp mode
|
|
//
|
|
OUTPW(EPR_DATA, BLT_CTRL2 | 0);
|
|
OUTPW(EPR_DATA, BLT_F_CLR | (USHORT)(color & 0x00FF));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Use Pattern Fill in 16bpp mode
|
|
//
|
|
target += prclDst->left;
|
|
width *= 2;
|
|
|
|
//
|
|
// Prepare a 4x8 pattern in the off-screen
|
|
//
|
|
source = ppdev->cyScreen * ppdev->lDeltaScreen;
|
|
pusBitbltPattern = (PUSHORT)(ppdev->pjScreen + source);
|
|
for (i = 0; i < 32; i++) {
|
|
*pusBitbltPattern++ = (USHORT)(color & 0x0000FFFF);
|
|
} /* endfor */
|
|
|
|
OUTPW(EPR_DATA, BLT_CTRL2 | 0x0010);
|
|
OUTPW(EPR_DATA, BLT_SRC_LO | (USHORT)( source & 0x0FFF));
|
|
OUTPW(EPR_DATA, BLT_SRC_HI | (USHORT)((source >> 12) & 0x01FF));
|
|
|
|
} /* endif */
|
|
|
|
OUTPW(EPR_DATA, BLT_DST_LO | (USHORT)( target & 0x0FFF));
|
|
OUTPW(EPR_DATA, BLT_DST_HI | (USHORT)((target >> 12) & 0x01FF));
|
|
OUTPW(EPR_DATA, BLT_SIZE_X | (USHORT)width);
|
|
OUTPW(EPR_DATA, BLT_SIZE_Y | (USHORT)height);
|
|
OUTPW(EPR_DATA, BLT_DELTA | (USHORT)ppdev->lDeltaScreen);
|
|
OUTPW(EPR_DATA, BLT_ROPS | 0x0300); // source copy operation
|
|
OUTPW(EPR_DATA, BLT_PLANE | 0x00FF); // enable all planes
|
|
OUTPW(EPR_DATA, BLT_CTRL1 | (ppdev->ulBitCount == 8) ? 0x0908 : 0x0900);
|
|
// start BITBLT
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bSolidFill
|
|
*
|
|
* Clips and fills the rectangle with specified color
|
|
* Returns TRUE if it is successfully completed
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bSolidFill (
|
|
PPDEV ppdev,
|
|
CLIPOBJ *pco,
|
|
RECTL *prclDst,
|
|
ULONG color )
|
|
|
|
{
|
|
RECTL BltRectl;
|
|
ENUMRECTS ClipEnum;
|
|
BOOL MoreClipRects;
|
|
ULONG ClipRegions;
|
|
|
|
//
|
|
// Figure out the real clipping complexity
|
|
//
|
|
|
|
switch ((pco != NULL) ? pco->iDComplexity : DC_TRIVIAL) {
|
|
|
|
case DC_TRIVIAL:
|
|
|
|
vHwSolidFill(ppdev, prclDst, color);
|
|
|
|
return TRUE;
|
|
|
|
case DC_RECT:
|
|
|
|
//
|
|
// only do the BLT if there is an intersection
|
|
//
|
|
|
|
if (bIntersect(prclDst,&pco->rclBounds,&BltRectl)) {
|
|
|
|
vHwSolidFill(ppdev, &BltRectl, color);
|
|
|
|
} /* endif */
|
|
|
|
return TRUE;
|
|
|
|
case DC_COMPLEX:
|
|
|
|
if (-1 != CLIPOBJ_cEnumStart(pco,FALSE,CT_RECTANGLES,CD_ANY,0)) {
|
|
|
|
do {
|
|
|
|
//
|
|
// Get list of clip rectangles.
|
|
//
|
|
|
|
MoreClipRects = CLIPOBJ_bEnum(pco,sizeof(ClipEnum),(PVOID)&ClipEnum);
|
|
|
|
for (ClipRegions=0;ClipRegions<ClipEnum.c;ClipRegions++) {
|
|
|
|
//
|
|
// only do the BLT if there is an intersection
|
|
//
|
|
|
|
if (bIntersect(prclDst,
|
|
&ClipEnum.arcl[ClipRegions],
|
|
&BltRectl)) {
|
|
|
|
vHwSolidFill(ppdev, &BltRectl, color);
|
|
|
|
} /* endif */
|
|
} /* endfor */
|
|
} while (MoreClipRects); /* enddo */
|
|
|
|
return TRUE;
|
|
|
|
} /* endif */
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
} /* endswitch */
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DrvBitBlt
|
|
*
|
|
* Implements the workhorse routine of a display driver.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL DrvBitBlt (
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
SURFOBJ *psoMsk,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc,
|
|
POINTL *pptlMsk,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrush,
|
|
ROP4 rop4 )
|
|
|
|
{
|
|
PPDEV ppdev = (PPDEV) psoDst->dhpdev;
|
|
BOOL b;
|
|
|
|
//
|
|
// Check that there is no color translation.
|
|
//
|
|
|
|
if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) {
|
|
|
|
//
|
|
// Check that the blt operation has the screen as target surface.
|
|
//
|
|
|
|
if ((psoDst != NULL) && (psoDst->iType == STYPE_DEVICE)) {
|
|
|
|
//
|
|
// Check for ROPs
|
|
//
|
|
|
|
switch(rop4) {
|
|
case 0x00000000: // DDx (BLACKNESS)
|
|
|
|
if (bSolidFill(ppdev, pco, prclDst, 0))
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
case 0x0000FFFF: // DDxn (WHITENESS)
|
|
|
|
if (bSolidFill(ppdev, pco, prclDst, 0xFFFFFFFF))
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
case 0x0000F0F0: // P (PATCOPY)
|
|
case 0x00000F0F: // Pn (NOTPATCOPY)
|
|
|
|
//
|
|
// This is a pattern fill. Check if the brush pattern
|
|
// is just a plain color, in this case proceed with the
|
|
// Solid Color Fill.
|
|
//
|
|
|
|
if (pbo->iSolidColor != 0xFFFFFFFF) {
|
|
|
|
if (bSolidFill(ppdev, pco, prclDst,
|
|
(rop4 == 0x00000F0F) ? ~(pbo->iSolidColor) : pbo->iSolidColor))
|
|
return TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x0000CCCC: // (SRCCOPY)
|
|
|
|
//
|
|
// Check that Source and Destination Surfaces are the same.
|
|
//
|
|
|
|
if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE)) {
|
|
|
|
if (bScrnToScrnCpy(ppdev, pco, prclDst, pptlSrc))
|
|
return TRUE;
|
|
|
|
} /* endif */
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
} /* endswitch */
|
|
} /* endif */
|
|
} /* endif */
|
|
|
|
//
|
|
// Call GDI to do the Blt for us. No need to syncrhonize here since
|
|
// EngXXX routines call DrvSynchronize.
|
|
//
|
|
|
|
if ((psoDst != NULL) && (psoDst->iType == STYPE_DEVICE))
|
|
psoDst = (SURFOBJ *)(((PPDEV)(psoDst->dhpdev))->pSurfObj);
|
|
|
|
if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE))
|
|
psoSrc = (SURFOBJ *)(((PPDEV)(psoSrc->dhpdev))->pSurfObj);
|
|
|
|
b = EngBitBlt(psoDst, // Target surface
|
|
psoSrc, // Source surface
|
|
psoMsk, // Mask
|
|
pco, // Clip through this
|
|
pxlo, // Color translation
|
|
prclDst, // Target offset and extent
|
|
pptlSrc, // Source offset
|
|
pptlMsk, // Mask offset
|
|
pbo, // Brush data (from cbRealizeBrush)
|
|
pptlBrush, // Brush offset (origin)
|
|
rop4); // Raster operation
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DrvCopyBits
|
|
*
|
|
* Do fast bitmap copies.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL DrvCopyBits (
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc )
|
|
|
|
{
|
|
PPDEV ppdev = (PPDEV) psoDst->dhpdev;
|
|
BOOL b;
|
|
|
|
//
|
|
// Check that there is no color translation.
|
|
//
|
|
|
|
if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) {
|
|
|
|
//
|
|
// Check that source and destination surfaces are the frame buffer.
|
|
//
|
|
|
|
if (((psoDst != NULL) && (psoDst->iType == STYPE_DEVICE)) &&
|
|
((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE))) {
|
|
|
|
if (bScrnToScrnCpy(ppdev, pco, prclDst, pptlSrc))
|
|
return TRUE;
|
|
|
|
} /* endif */
|
|
} /* endif */
|
|
|
|
if ((psoDst != NULL) && (psoDst->iType == STYPE_DEVICE))
|
|
psoDst = (SURFOBJ *)(((PPDEV)(psoDst->dhpdev))->pSurfObj);
|
|
|
|
if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE))
|
|
psoSrc = (SURFOBJ *)(((PPDEV)(psoSrc->dhpdev))->pSurfObj);
|
|
|
|
//
|
|
// If the copy operation could be performed by the accelerator,
|
|
// this routine has already returned.
|
|
// If execution falls here, call the Engine routine.
|
|
// No need to Synchronize here since the Eng routine will call DrvSyncrhonize.
|
|
//
|
|
|
|
b = EngCopyBits(psoDst, // Target surface
|
|
psoSrc, // Source surface
|
|
pco, // Clip through this
|
|
pxlo, // Color translation
|
|
prclDst, // Target offset and extent
|
|
pptlSrc); // Source offset
|
|
|
|
return b;
|
|
|
|
}
|