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.
928 lines
30 KiB
928 lines
30 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: bitblt.c
|
|
*
|
|
* Banked Frame Buffer bitblit
|
|
*
|
|
* Copyright (c) 1992 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "driver.h"
|
|
|
|
/************************************************************************\
|
|
* bIntersectRect
|
|
*
|
|
* Calculates the intersection between *prcSrc1 and *prcSrc2,
|
|
* returning the resulting rect in *prcDst. Returns TRUE if
|
|
* *prcSrc1 intersects *prcSrc2, FALSE otherwise. If there is no
|
|
* intersection, an empty rect is returned in *prcDst.
|
|
\************************************************************************/
|
|
|
|
static const RECTL rclEmpty = { 0, 0, 0, 0 };
|
|
|
|
BOOL bIntersectRect(
|
|
PRECTL prcDst,
|
|
PRECTL prcSrc1,
|
|
PRECTL prcSrc2)
|
|
|
|
{
|
|
prcDst->left = max(prcSrc1->left, prcSrc2->left);
|
|
prcDst->right = min(prcSrc1->right, prcSrc2->right);
|
|
|
|
// check for empty rect
|
|
|
|
if (prcDst->left < prcDst->right)
|
|
{
|
|
prcDst->top = max(prcSrc1->top, prcSrc2->top);
|
|
prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
|
|
|
|
// check for empty rect
|
|
|
|
if (prcDst->top < prcDst->bottom)
|
|
return(TRUE); // not empty
|
|
}
|
|
|
|
// empty rect
|
|
|
|
*prcDst = rclEmpty;
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bPuntScreenToScreenCopyBits(ppdev, pco, pxlo, prclDest, pptlSrc)
|
|
*
|
|
* Performs a screen-to-screen CopyBits entirely using an intermediate
|
|
* temporary buffer and GDI.
|
|
*
|
|
* We found that on most machines it was faster to have the engine copy
|
|
* the source to a buffer, then blit the buffer to the destination, than
|
|
* to have optimized ASM code that copies a word at a time. The reason?
|
|
* The engine does d-word moves, which are faster than word moves even
|
|
* going over the bus to a 16 bit display device.
|
|
*
|
|
* We could also write optimized ASM code that does d-word moves, but the
|
|
* win will be marginal, we're time constrained, we also need a routine
|
|
* like this to handle complex clip objects and palette translates, and
|
|
* most of the other times we can use planar copies for important things
|
|
* like scrolls, anyways.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bPuntScreenToScreenCopyBits(
|
|
PPDEV ppdev,
|
|
CLIPOBJ* pco,
|
|
XLATEOBJ* pxlo,
|
|
RECTL* prclDest,
|
|
POINTL* pptlSrc)
|
|
{
|
|
RECTL rclDest;
|
|
POINTL ptlSrc;
|
|
BOOL b = TRUE;
|
|
|
|
SURFOBJ* pso = ppdev->pSurfObj;
|
|
SURFOBJ* psoTmp = ppdev->psoTmp;
|
|
|
|
if (prclDest->top < pptlSrc->y)
|
|
{
|
|
////////////////////////////////////////////////////////////////
|
|
// Do a top-to-bottom copy:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
LONG ySrcBottom;
|
|
LONG yDestBottom;
|
|
|
|
LONG yDestTop = prclDest->top;
|
|
LONG ySrcTop = pptlSrc->y;
|
|
LONG ySrcLast = ySrcTop + (prclDest->bottom - prclDest->top);
|
|
|
|
if (ySrcTop < ppdev->rcl1WindowClip.top ||
|
|
ySrcTop >= ppdev->rcl1WindowClip.bottom)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop);
|
|
}
|
|
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy an entire source bank into the temporary buffer:
|
|
|
|
ySrcBottom = min(ySrcLast, ppdev->rcl1WindowClip.bottom);
|
|
|
|
ptlSrc.x = pptlSrc->x;
|
|
ptlSrc.y = ySrcTop;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = 0;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = ySrcBottom - ySrcTop;
|
|
|
|
b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc);
|
|
|
|
yDestBottom = yDestTop + rclDest.bottom;
|
|
|
|
if (ppdev->rcl1WindowClip.top >= yDestBottom)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, yDestBottom - 1, JustifyBottom);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy the temporary buffer into one or more destination
|
|
// banks:
|
|
|
|
LONG yThisTop;
|
|
LONG yThisBottom;
|
|
LONG yOffset;
|
|
|
|
yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom);
|
|
yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top);
|
|
yOffset = yThisTop - yDestTop;
|
|
|
|
ptlSrc.x = prclDest->left;
|
|
ptlSrc.y = yOffset;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = yThisTop;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = yThisBottom;
|
|
|
|
b &= EngCopyBits(pso, psoTmp, pco, pxlo, &rclDest, &ptlSrc);
|
|
|
|
if (yOffset == 0)
|
|
break;
|
|
|
|
ppdev->pfnBankControl(ppdev, yThisTop - 1, JustifyBottom);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
if (ySrcBottom >= ySrcLast)
|
|
break;
|
|
|
|
yDestTop = yDestBottom;
|
|
ySrcTop = ySrcBottom;
|
|
|
|
ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
////////////////////////////////////////////////////////////////
|
|
// Do a bottom-to-top copy:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
LONG ySrcTop;
|
|
LONG yDestTop;
|
|
|
|
LONG yDestBottom = prclDest->bottom;
|
|
LONG ySrcFirst = pptlSrc->y;
|
|
LONG ySrcBottom = ySrcFirst + (prclDest->bottom - prclDest->top);
|
|
|
|
if (ySrcBottom <= ppdev->rcl1WindowClip.top ||
|
|
ySrcBottom > ppdev->rcl1WindowClip.bottom)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom);
|
|
}
|
|
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy an entire source bank into the temporary buffer:
|
|
|
|
ySrcTop = max(ySrcFirst, ppdev->rcl1WindowClip.top);
|
|
|
|
ptlSrc.x = pptlSrc->x;
|
|
ptlSrc.y = ySrcTop;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = 0;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = ySrcBottom - ySrcTop;
|
|
|
|
b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc);
|
|
|
|
yDestTop = yDestBottom - rclDest.bottom;
|
|
|
|
if (ppdev->rcl1WindowClip.bottom <= yDestTop)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, yDestTop, JustifyTop);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy the temporary buffer into one or more destination
|
|
// banks:
|
|
|
|
LONG yThisTop;
|
|
LONG yThisBottom;
|
|
LONG yOffset;
|
|
|
|
yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top);
|
|
yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom);
|
|
yOffset = yThisTop - yDestTop;
|
|
|
|
ptlSrc.x = prclDest->left;
|
|
ptlSrc.y = yOffset;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = yThisTop;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = yThisBottom;
|
|
|
|
b &= EngCopyBits(pso, psoTmp, pco, pxlo, &rclDest, &ptlSrc);
|
|
|
|
if (yThisBottom == yDestBottom)
|
|
break;
|
|
|
|
ppdev->pfnBankControl(ppdev, yThisBottom, JustifyTop);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
if (ySrcTop <= ySrcFirst)
|
|
break;
|
|
|
|
yDestBottom = yDestTop;
|
|
ySrcBottom = ySrcTop;
|
|
|
|
ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bPuntScreenToScreenBitBlt(...)
|
|
*
|
|
* Performs a screen-to-screen BitBlt entirely using an intermediate temporary
|
|
* buffer and GDI.
|
|
*
|
|
* This function is basically a clone of bPuntScreenToScreenCopyBits,
|
|
* except that it can handle funky ROPs and stuff.
|
|
\**************************************************************************/
|
|
|
|
BOOL bPuntScreenToScreenBitBlt(
|
|
PPDEV ppdev,
|
|
SURFOBJ* psoMask,
|
|
CLIPOBJ* pco,
|
|
XLATEOBJ* pxlo,
|
|
RECTL* prclDest,
|
|
POINTL* pptlSrc,
|
|
POINTL* pptlMask,
|
|
BRUSHOBJ* pbo,
|
|
POINTL* pptlBrush,
|
|
ROP4 rop4)
|
|
{
|
|
RECTL rclDest; // Temporary destination rectangle
|
|
POINTL ptlSrc; // Temporary source point
|
|
POINTL ptlMask; // Temporary mask offset
|
|
POINTL ptlMaskAdjust; // Adjustment for mask offset
|
|
BOOL b = TRUE;
|
|
|
|
SURFOBJ* pso = ppdev->pSurfObj;
|
|
SURFOBJ* psoTmp = ppdev->psoTmp;
|
|
|
|
if (psoMask != NULL)
|
|
{
|
|
ptlMaskAdjust.x = prclDest->left - pptlMask->x;
|
|
ptlMaskAdjust.y = prclDest->top - pptlMask->y;
|
|
}
|
|
|
|
if (prclDest->top < pptlSrc->y)
|
|
{
|
|
////////////////////////////////////////////////////////////////
|
|
// Do a top-to-bottom copy:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
LONG ySrcBottom;
|
|
LONG yDestBottom;
|
|
|
|
LONG yDestTop = prclDest->top;
|
|
LONG ySrcTop = pptlSrc->y;
|
|
LONG ySrcLast = ySrcTop + (prclDest->bottom - prclDest->top);
|
|
|
|
if (ySrcTop < ppdev->rcl1WindowClip.top ||
|
|
ySrcTop >= ppdev->rcl1WindowClip.bottom)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop);
|
|
}
|
|
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy an entire source bank into the temporary buffer:
|
|
|
|
ySrcBottom = min(ySrcLast, ppdev->rcl1WindowClip.bottom);
|
|
|
|
ptlSrc.x = pptlSrc->x;
|
|
ptlSrc.y = ySrcTop;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = 0;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = ySrcBottom - ySrcTop;
|
|
|
|
b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc);
|
|
|
|
yDestBottom = yDestTop + rclDest.bottom;
|
|
|
|
if (ppdev->rcl1WindowClip.top >= yDestBottom)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, yDestBottom - 1, JustifyBottom);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy the temporary buffer into one or more destination
|
|
// banks:
|
|
|
|
LONG yThisTop;
|
|
LONG yThisBottom;
|
|
LONG yOffset;
|
|
|
|
yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom);
|
|
yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top);
|
|
yOffset = yThisTop - yDestTop;
|
|
|
|
ptlSrc.x = prclDest->left;
|
|
ptlSrc.y = yOffset;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = yThisTop;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = yThisBottom;
|
|
|
|
ptlMask.x = rclDest.left - ptlMaskAdjust.x;
|
|
ptlMask.y = rclDest.top - ptlMaskAdjust.y;
|
|
|
|
b &= EngBitBlt(pso, psoTmp, psoMask, pco, pxlo, &rclDest,
|
|
&ptlSrc, &ptlMask, pbo, pptlBrush, rop4);
|
|
|
|
if (yOffset == 0)
|
|
break;
|
|
|
|
ppdev->pfnBankControl(ppdev, yThisTop - 1, JustifyBottom);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
if (ySrcBottom >= ySrcLast)
|
|
break;
|
|
|
|
yDestTop = yDestBottom;
|
|
ySrcTop = ySrcBottom;
|
|
|
|
ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
////////////////////////////////////////////////////////////////
|
|
// Do a bottom-to-top copy:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
LONG ySrcTop;
|
|
LONG yDestTop;
|
|
|
|
LONG yDestBottom = prclDest->bottom;
|
|
LONG ySrcFirst = pptlSrc->y;
|
|
LONG ySrcBottom = ySrcFirst + (prclDest->bottom - prclDest->top);
|
|
|
|
if (ySrcBottom <= ppdev->rcl1WindowClip.top ||
|
|
ySrcBottom > ppdev->rcl1WindowClip.bottom)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom);
|
|
}
|
|
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy an entire source bank into the temporary buffer:
|
|
|
|
ySrcTop = max(ySrcFirst, ppdev->rcl1WindowClip.top);
|
|
|
|
ptlSrc.x = pptlSrc->x;
|
|
ptlSrc.y = ySrcTop;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = 0;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = ySrcBottom - ySrcTop;
|
|
|
|
b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc);
|
|
|
|
yDestTop = yDestBottom - rclDest.bottom;
|
|
|
|
if (ppdev->rcl1WindowClip.bottom <= yDestTop)
|
|
{
|
|
ppdev->pfnBankControl(ppdev, yDestTop, JustifyTop);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
// Copy the temporary buffer into one or more destination
|
|
// banks:
|
|
|
|
LONG yThisTop;
|
|
LONG yThisBottom;
|
|
LONG yOffset;
|
|
|
|
yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top);
|
|
yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom);
|
|
yOffset = yThisTop - yDestTop;
|
|
|
|
ptlSrc.x = prclDest->left;
|
|
ptlSrc.y = yOffset;
|
|
|
|
rclDest.left = prclDest->left;
|
|
rclDest.top = yThisTop;
|
|
rclDest.right = prclDest->right;
|
|
rclDest.bottom = yThisBottom;
|
|
|
|
ptlMask.x = rclDest.left - ptlMaskAdjust.x;
|
|
ptlMask.y = rclDest.top - ptlMaskAdjust.y;
|
|
|
|
b &= EngBitBlt(pso, psoTmp, psoMask, pco, pxlo, &rclDest,
|
|
&ptlSrc, &ptlMask, pbo, pptlBrush, rop4);
|
|
|
|
if (yThisBottom == yDestBottom)
|
|
break;
|
|
|
|
ppdev->pfnBankControl(ppdev, yThisBottom, JustifyTop);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
|
|
if (ySrcTop <= ySrcFirst)
|
|
break;
|
|
|
|
yDestBottom = yDestTop;
|
|
ySrcBottom = ySrcTop;
|
|
|
|
ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom);
|
|
pso->pvScan0 = ppdev->pvBitmapStart;
|
|
}
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Data*********************************\
|
|
* ROP to mix translation table
|
|
*
|
|
* Table to translate ternary raster ops to mixes (binary raster ops). Ternary
|
|
* raster ops that can't be translated to mixes are translated to 0 (0 is not
|
|
* a valid mix).
|
|
*
|
|
\**************************************************************************/
|
|
|
|
UCHAR jRop3ToMix[256] = {
|
|
R2_BLACK, 0, 0, 0, 0, R2_NOTMERGEPEN, 0, 0,
|
|
0, 0, R2_MASKNOTPEN, 0, 0, 0, 0, R2_NOTCOPYPEN,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
R2_MASKPENNOT, 0, 0, 0, 0, R2_NOT, 0, 0,
|
|
0, 0, R2_XORPEN, 0, 0, 0, 0, R2_NOTMASKPEN,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
R2_MASKPEN, 0, 0, 0, 0, R2_NOTXORPEN, 0, 0,
|
|
0, 0, R2_NOP, 0, 0, 0, 0, R2_MERGENOTPEN,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
R2_COPYPEN, 0, 0, 0, 0, R2_MERGEPENNOT, 0, 0,
|
|
0, 0, R2_MERGEPEN, 0, 0, 0, 0, R2_WHITE
|
|
};
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DrvBitBlt(psoDest, psoSrc, psoMask, pco, pxlo, prclDest, pptlSrc,
|
|
* pptlMask, pbo, pptlBrush, rop4)
|
|
*
|
|
* This routine will handle any blit. Perhaps glacially, but it will be
|
|
* handled.
|
|
\**************************************************************************/
|
|
|
|
BOOL DrvBitBlt(
|
|
SURFOBJ* psoDest,
|
|
SURFOBJ* psoSrc,
|
|
SURFOBJ* psoMask,
|
|
CLIPOBJ* pco,
|
|
XLATEOBJ* pxlo,
|
|
RECTL* prclDest,
|
|
POINTL* pptlSrc,
|
|
POINTL* pptlMask,
|
|
BRUSHOBJ* pbo,
|
|
POINTL* pptlBrush,
|
|
ROP4 rop4)
|
|
{
|
|
BOOL b;
|
|
POINTL ptlSrc;
|
|
RECTL rclDest;
|
|
PPDEV ppdev;
|
|
SURFOBJ* pso;
|
|
BYTE jClipping;
|
|
RECTL rclTmp;
|
|
POINTL ptlTmp;
|
|
BBENUM bben; // Clip enumerator
|
|
BOOL bMore; // Clip continuation flag
|
|
POINTL ptlMask; // Temporary mask for engine call-backs
|
|
POINTL ptlMaskAdjust; // Adjustment for mask
|
|
INT iCopyDir;
|
|
|
|
// Set up the clipping type
|
|
if (pco == (CLIPOBJ *) NULL) {
|
|
// No CLIPOBJ provided, so we don't have to worry about clipping
|
|
jClipping = DC_TRIVIAL;
|
|
} else {
|
|
// Use the CLIPOBJ-provided clipping
|
|
jClipping = pco->iDComplexity;
|
|
}
|
|
|
|
// Get the correct surface object for the target and the source
|
|
|
|
if (psoDest->iType == STYPE_DEVICE) {
|
|
|
|
if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE)) {
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// BitBlt screen-to-screen:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
ppdev = (PPDEV) psoDest->dhsurf;
|
|
|
|
// See if we can do a simple CopyBits:
|
|
|
|
if (rop4 == 0x0000CCCC)
|
|
{
|
|
ppdev = (PPDEV) psoDest->dhsurf;
|
|
|
|
// We can handle quadpixel-aligned screen-to-screen blts with
|
|
// no translation:
|
|
|
|
if ((((pptlSrc->x ^ prclDest->left) & 1) == 0) &&
|
|
(ppdev->fl & DRIVER_PLANAR_CAPABLE) &&
|
|
((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)))
|
|
{
|
|
switch(jClipping)
|
|
{
|
|
case DC_TRIVIAL:
|
|
vPlanarCopyBits(ppdev, prclDest, pptlSrc);
|
|
return(TRUE);
|
|
|
|
case DC_RECT:
|
|
|
|
// Clip the target rectangle to the clip rectangle:
|
|
|
|
if (!bIntersectRect(&rclTmp, prclDest, &pco->rclBounds))
|
|
{
|
|
DISPDBG((0, "DrvBitBlt: Nothing to draw."));
|
|
return(TRUE);
|
|
}
|
|
|
|
ptlTmp.x = pptlSrc->x + rclTmp.left - prclDest->left;
|
|
ptlTmp.y = pptlSrc->y + rclTmp.top - prclDest->top;
|
|
|
|
vPlanarCopyBits(ppdev, &rclTmp, &ptlTmp);
|
|
return(TRUE);
|
|
|
|
case DC_COMPLEX:
|
|
if (pptlSrc->y >= prclDest->top)
|
|
{
|
|
if (pptlSrc->x >= prclDest->left)
|
|
iCopyDir = CD_RIGHTDOWN;
|
|
else
|
|
iCopyDir = CD_LEFTDOWN;
|
|
}
|
|
else
|
|
{
|
|
if (pptlSrc->x >= prclDest->left)
|
|
iCopyDir = CD_RIGHTUP;
|
|
else
|
|
iCopyDir = CD_LEFTUP;
|
|
}
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iCopyDir, 0);
|
|
|
|
do {
|
|
RECTL* prcl;
|
|
RECTL* prclEnd;
|
|
|
|
bMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(bben),
|
|
(PVOID) &bben);
|
|
|
|
prclEnd = &bben.arcl[bben.c];
|
|
for (prcl = bben.arcl; prcl < prclEnd; prcl++)
|
|
{
|
|
if (bIntersectRect(prcl, prclDest, prcl))
|
|
{
|
|
ptlTmp.x = pptlSrc->x + prcl->left - prclDest->left;
|
|
ptlTmp.y = pptlSrc->y + prcl->top - prclDest->top;
|
|
|
|
vPlanarCopyBits(ppdev, prcl, &ptlTmp);
|
|
}
|
|
}
|
|
} while (bMore);
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// Can't handle in hardware, so punt:
|
|
|
|
return(bPuntScreenToScreenCopyBits(ppdev,
|
|
pco,
|
|
pxlo,
|
|
prclDest,
|
|
pptlSrc));
|
|
}
|
|
|
|
// It's more complicated than a CopyBits, so punt it:
|
|
|
|
return(bPuntScreenToScreenBitBlt(ppdev,
|
|
psoMask,
|
|
pco,
|
|
pxlo,
|
|
prclDest,
|
|
pptlSrc,
|
|
pptlMask,
|
|
pbo,
|
|
pptlBrush,
|
|
rop4));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// BitBlt to screen:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
ppdev = (PPDEV) psoDest->dhsurf;
|
|
|
|
// Punt the memory-to-screen call back to the engine:
|
|
|
|
if (psoMask != NULL)
|
|
{
|
|
ptlMaskAdjust.x = prclDest->left - pptlMask->x;
|
|
ptlMaskAdjust.y = prclDest->top - pptlMask->y;
|
|
}
|
|
|
|
pso = ppdev->pSurfObj;
|
|
|
|
vBankStartBltDest(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest);
|
|
|
|
do {
|
|
ptlMask.x = rclDest.left - ptlMaskAdjust.x;
|
|
ptlMask.y = rclDest.top - ptlMaskAdjust.y;
|
|
|
|
b = EngBitBlt(pso,
|
|
psoSrc,
|
|
psoMask,
|
|
pco,
|
|
pxlo,
|
|
&rclDest,
|
|
&ptlSrc,
|
|
&ptlMask,
|
|
pbo,
|
|
pptlBrush,
|
|
rop4);
|
|
|
|
} while (b && bBankEnumBltDest(ppdev, pso, pptlSrc, prclDest,
|
|
&ptlSrc, &rclDest));
|
|
|
|
return(b);
|
|
}
|
|
else if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE))
|
|
{
|
|
////////////////////////////////////////////////////////////////
|
|
// BitBlt from screen:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
if (psoMask != NULL)
|
|
{
|
|
ptlMaskAdjust.x = prclDest->left - pptlMask->x;
|
|
ptlMaskAdjust.y = prclDest->top - pptlMask->y;
|
|
}
|
|
|
|
ppdev = (PPDEV) psoSrc->dhsurf;
|
|
pso = ppdev->pSurfObj;
|
|
|
|
vBankStartBltSrc(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest);
|
|
|
|
do {
|
|
ptlMask.x = rclDest.left - ptlMaskAdjust.x;
|
|
ptlMask.y = rclDest.top - ptlMaskAdjust.y;
|
|
|
|
b = EngBitBlt(psoDest,
|
|
pso,
|
|
psoMask,
|
|
pco,
|
|
pxlo,
|
|
&rclDest,
|
|
&ptlSrc,
|
|
&ptlMask,
|
|
pbo,
|
|
pptlBrush,
|
|
rop4);
|
|
|
|
} while (b && bBankEnumBltSrc(ppdev, pso, pptlSrc, prclDest,
|
|
&ptlSrc, &rclDest));
|
|
|
|
return(b);
|
|
}
|
|
|
|
RIP("Got a funky format?");
|
|
return(FALSE);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DrvCopyBits
|
|
\***************************************************************************/
|
|
|
|
BOOL DrvCopyBits(
|
|
SURFOBJ* psoDest,
|
|
SURFOBJ* psoSrc,
|
|
CLIPOBJ* pco,
|
|
XLATEOBJ* pxlo,
|
|
RECTL* prclDest,
|
|
POINTL* pptlSrc)
|
|
{
|
|
BOOL b;
|
|
POINTL ptlSrc;
|
|
RECTL rclDest;
|
|
PPDEV ppdev;
|
|
SURFOBJ* pso;
|
|
BBENUM bben;
|
|
BOOL bMore;
|
|
BYTE jClipping;
|
|
POINTL ptlTmp;
|
|
RECTL rclTmp;
|
|
INT iCopyDir;
|
|
|
|
// Get the correct surface object for the target and the source
|
|
|
|
if (psoDest->iType == STYPE_DEVICE)
|
|
{
|
|
// We have to special case screen-to-screen operations:
|
|
|
|
if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE))
|
|
{
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// CopyBits screen-to-screen:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
ppdev = (PPDEV) psoDest->dhsurf;
|
|
|
|
// We check to see if we can do a planar copy, because usually
|
|
// it will be faster. But the hardware has to be capable of
|
|
// doing it, and the source and destination must be 4-pel
|
|
// aligned.
|
|
|
|
if ((((pptlSrc->x ^ prclDest->left) & 1) == 0) &&
|
|
(ppdev->fl & DRIVER_PLANAR_CAPABLE) &&
|
|
((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)))
|
|
{
|
|
jClipping = (pco != NULL) ? pco->iDComplexity : DC_TRIVIAL;
|
|
|
|
switch(jClipping)
|
|
{
|
|
case DC_TRIVIAL:
|
|
vPlanarCopyBits(ppdev, prclDest, pptlSrc);
|
|
return(TRUE);
|
|
|
|
case DC_RECT:
|
|
// Clip the target rectangle to the clip rectangle:
|
|
|
|
if (!bIntersectRect(&rclTmp, prclDest, &pco->rclBounds))
|
|
{
|
|
DISPDBG((0, "DrvCopyBits: Nothing to draw."));
|
|
return(TRUE);
|
|
}
|
|
|
|
ptlTmp.x = pptlSrc->x + rclTmp.left - prclDest->left;
|
|
ptlTmp.y = pptlSrc->y + rclTmp.top - prclDest->top;
|
|
|
|
vPlanarCopyBits(ppdev, &rclTmp, &ptlTmp);
|
|
return(TRUE);
|
|
|
|
case DC_COMPLEX:
|
|
if (pptlSrc->y >= prclDest->top)
|
|
{
|
|
if (pptlSrc->x >= prclDest->left)
|
|
iCopyDir = CD_RIGHTDOWN;
|
|
else
|
|
iCopyDir = CD_LEFTDOWN;
|
|
}
|
|
else
|
|
{
|
|
if (pptlSrc->x >= prclDest->left)
|
|
iCopyDir = CD_RIGHTUP;
|
|
else
|
|
iCopyDir = CD_LEFTUP;
|
|
}
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iCopyDir, 0);
|
|
|
|
do {
|
|
RECTL* prcl;
|
|
RECTL* prclEnd;
|
|
|
|
bMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(bben),
|
|
(PVOID) &bben);
|
|
|
|
prclEnd = &bben.arcl[bben.c];
|
|
for (prcl = bben.arcl; prcl < prclEnd; prcl++)
|
|
{
|
|
if (bIntersectRect(prcl, prclDest, prcl))
|
|
{
|
|
ptlTmp.x = pptlSrc->x + prcl->left - prclDest->left;
|
|
ptlTmp.y = pptlSrc->y + prcl->top - prclDest->top;
|
|
|
|
vPlanarCopyBits(ppdev, prcl, &ptlTmp);
|
|
}
|
|
}
|
|
} while (bMore);
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(bPuntScreenToScreenCopyBits(ppdev,
|
|
pco,
|
|
pxlo,
|
|
prclDest,
|
|
pptlSrc));
|
|
}
|
|
|
|
ppdev = (PPDEV) psoDest->dhsurf;
|
|
|
|
// Fall back to the engine:
|
|
|
|
pso = ppdev->pSurfObj;
|
|
vBankStartBltDest(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest);
|
|
|
|
do {
|
|
b = EngCopyBits(pso,
|
|
psoSrc,
|
|
pco,
|
|
pxlo,
|
|
&rclDest,
|
|
&ptlSrc);
|
|
|
|
} while (b && bBankEnumBltDest(ppdev, pso, pptlSrc, prclDest,
|
|
&ptlSrc, &rclDest));
|
|
|
|
return(b);
|
|
}
|
|
else if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE))
|
|
{
|
|
////////////////////////////////////////////////////////////////
|
|
// CopyBits from screen:
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
ppdev = (PPDEV) psoSrc->dhsurf;
|
|
pso = ppdev->pSurfObj;
|
|
|
|
vBankStartBltSrc(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest);
|
|
|
|
do {
|
|
b = EngCopyBits(psoDest,
|
|
pso,
|
|
pco,
|
|
pxlo,
|
|
&rclDest,
|
|
&ptlSrc);
|
|
|
|
} while (b && bBankEnumBltSrc(ppdev, pso, pptlSrc, prclDest,
|
|
&ptlSrc, &rclDest));
|
|
|
|
return(b);
|
|
}
|
|
|
|
/* we should never be here */
|
|
return FALSE;
|
|
}
|