/******************************Module*Header*******************************\ * Module Name: blt.c * * Contains the low-level in/out blt functions. * * Hopefully, if you're basing your display driver on this code, to * support all of DrvBitBlt and DrvCopyBits, you'll only have to implement * the following routines. You shouldn't have to modify much in * 'bitblt.c'. I've tried to make these routines as few, modular, simple, * and efficient as I could, while still accelerating as many calls as * possible that would be cost-effective in terms of performance wins * versus size and effort. * * Note: In the following, 'relative' coordinates refers to coordinates * that haven't yet had the offscreen bitmap (DFB) offset applied. * 'Absolute' coordinates have had the offset applied. For example, * we may be told to blt to (1, 1) of the bitmap, but the bitmap may * be sitting in offscreen memory starting at coordinate (0, 768) -- * (1, 1) would be the 'relative' start coordinate, and (1, 769) * would be the 'absolute' start coordinate'. * * Copyright (c) 1992-1995 Microsoft Corporation * \**************************************************************************/ #include "precomp.h" /******************************Public*Table********************************\ * BYTE gaulP9000OpaqueFromRop2[] * * Convert an opaque Rop2 to a P9000 minterm. * \**************************************************************************/ #define P9000_P ((P9000_S & P9000_F) | (~P9000_S & P9000_B)) #define P9000_DSo (P9000_S | P9000_D) #define P9000_DSna (~P9000_S & P9000_D) ULONG gaulP9000OpaqueFromRop2[] = { (0 ) & 0xFFFF, // 0 -- 0 (~(P9000_P | P9000_D)) & 0xFFFF, // 1 -- DPon (~P9000_P & P9000_D ) & 0xFFFF, // 2 -- DPna (~P9000_P ) & 0xFFFF, // 3 -- Pn (~P9000_D & P9000_P ) & 0xFFFF, // 4 -- PDna (~P9000_D ) & 0xFFFF, // 5 -- Dn (P9000_D ^ P9000_P ) & 0xFFFF, // 6 -- DPx (~(P9000_P & P9000_D)) & 0xFFFF, // 7 -- DPan (P9000_P & P9000_D ) & 0xFFFF, // 8 -- DPa (~(P9000_P ^ P9000_D)) & 0xFFFF, // 9 -- DPxn (P9000_D ) & 0xFFFF, // 10 -- D (~P9000_P | P9000_D ) & 0xFFFF, // 11 -- DPno (P9000_P ) & 0xFFFF, // 12 -- P (~P9000_D | P9000_P ) & 0xFFFF, // 13 -- PDno (P9000_P | P9000_D ) & 0xFFFF, // 14 -- DPo (~0 ) & 0xFFFF, // 15 -- 1 }; /******************************Public*Table********************************\ * BYTE gaulP9000TransparentFromRop2[] * * Convert a transparent Rop2 to a P9000 minterm. * \**************************************************************************/ ULONG gaulP9000TransparentFromRop2[] = { (((0 ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 0 -- 0 (((~(P9000_P | P9000_D)) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 1 -- DPon (((~P9000_P & P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 2 -- DPna (((~P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 3 -- Pn (((~P9000_D & P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 4 -- PDna (((~P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 5 -- Dn (((P9000_D ^ P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 6 -- DPx (((~(P9000_P & P9000_D)) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 7 -- DPan (((P9000_P & P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 8 -- DPa (((~(P9000_P ^ P9000_D)) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 9 -- DPxn (((P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 10 -- D (((~P9000_P | P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 11 -- DPno (((P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 12 -- P (((~P9000_D | P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 13 -- PDno (((P9000_P | P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 14 -- DPo (((~0 ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 15 -- 1 }; /******************************Public*Routine******************************\ * VOID vFillSolid * * Fills a list of rectangles with a solid colour. * \**************************************************************************/ VOID vFillSolid( // Type FNFILL PDEV* ppdev, LONG c, // Can't be zero RECTL* prcl, // List of rectangles to be filled, in relative // coordinates ULONG ulHwMix, // Hardware mix mode RBRUSH_COLOR rbc, // Drawing colour is rbc.iSolidColor POINTL* pptlBrush) // Not used { BYTE* pjBase; ASSERTDD(c > 0, "Can't handle zero rectangles"); pjBase = ppdev->pjBase; CP_METARECT(ppdev, pjBase, prcl->left, prcl->top); CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom); CP_WAIT(ppdev, pjBase); if (P9000(ppdev)) { CP_BACKGROUND(ppdev, pjBase, rbc.iSolidColor); CP_RASTER(ppdev, pjBase, ulHwMix); } else { CP_COLOR0(ppdev, pjBase, rbc.iSolidColor); CP_RASTER(ppdev, pjBase, ulHwMix & 0xff); } CP_START_QUAD(ppdev, pjBase); while (prcl++, --c) { CP_METARECT(ppdev, pjBase, prcl->left, prcl->top); CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom); CP_START_QUAD_WAIT(ppdev, pjBase); } } /******************************Public*Routine******************************\ * VOID vSlowPatRealize * * This routine transfers an 8x8 pattern to off-screen display memory, and * duplicates it to make a 64x64 cached realization which is then used by * vFillPatSlow as the basic building block for doing 'slow' pattern output * via repeated screen-to-screen blts. * \**************************************************************************/ VOID vSlowPatRealize( PDEV* ppdev, RBRUSH* prb) // Points to brush realization structure { BYTE* pjBase; LONG cjPel; BRUSHENTRY* pbe; LONG iBrushCache; LONG x; LONG y; ULONG* pulSrc; LONG i; ASSERTDD(!(prb->fl & (RBRUSH_2COLOR | RBRUSH_4COLOR)), "Shouldn't realize hardware brushes"); pbe = prb->apbe[IBOARD(ppdev)]; if ((pbe == NULL) || (pbe->prbVerify != prb)) { // We have to allocate a new off-screen cache brush entry for // the brush: iBrushCache = ppdev->iBrushCache; pbe = &ppdev->abe[iBrushCache]; iBrushCache++; if (iBrushCache >= ppdev->cBrushCache) iBrushCache = 0; ppdev->iBrushCache = iBrushCache; // Update our links: pbe->prbVerify = prb; prb->apbe[IBOARD(ppdev)] = pbe; } pjBase = ppdev->pjBase; cjPel = ppdev->cjPel; // Load some pointer variables onto the stack, so that we don't have // to keep dereferencing their pointers: x = pbe->x; y = pbe->y; CP_ABS_XY0(ppdev, pjBase, x * cjPel, y); CP_ABS_XY1(ppdev, pjBase, x * cjPel, y); CP_ABS_XY2(ppdev, pjBase, (x + 8) * cjPel, y); CP_ABS_Y3(ppdev, pjBase, 1); pulSrc = (ULONG*) &prb->aulPattern[0]; CP_WAIT(ppdev, pjBase); CP_RASTER(ppdev, pjBase, P9000(ppdev) ? P9000_S : P9100_S); for (i = 4 * cjPel; i != 0; i--) { CP_PIXEL8(ppdev, pjBase, *(pulSrc)); CP_PIXEL8(ppdev, pjBase, *(pulSrc + 1)); CP_PIXEL8(ppdev, pjBase, *(pulSrc + 2)); CP_PIXEL8(ppdev, pjBase, *(pulSrc + 3)); pulSrc += 4; } // ÚÄÂÄÂÄÂÄÄÄÂÄÄÄÄÄÄÄ¿ // ³0³1³2³3 ³4 ³ We now have an 8x8 colour-expanded copy of // ÃÄÁÄÁÄÁÄÄÄÁÄÄÄÄÄÄÄ´ the pattern sitting in off-screen memory, // ³5 ³ represented here by square '0'. // ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ // ³6 ³ We're now going to expand the pattern to // ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 72x72 by repeatedly copying larger rectangles // ³7 ³ in the indicated order. // ³ ³ // ³ ³ // ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ // ³8 ³ // ³ ³ // ³ ³ // ³ ³ // ³ ³ // ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ // Copy '1': CP_ABS_XY1(ppdev, pjBase, x + 7, y + 7); CP_ABS_XY3(ppdev, pjBase, x + 15, y + 7); CP_WAIT(ppdev, pjBase); CP_START_BLT(ppdev, pjBase); // Copy '2': CP_ABS_X2(ppdev, pjBase, x + 16); CP_ABS_X3(ppdev, pjBase, x + 23); CP_START_BLT_WAIT(ppdev, pjBase); // Copy '3': CP_ABS_X1(ppdev, pjBase, x + 15); CP_ABS_X2(ppdev, pjBase, x + 24); CP_ABS_X3(ppdev, pjBase, x + 39); CP_START_BLT_WAIT(ppdev, pjBase); // Copy '4': CP_ABS_X1(ppdev, pjBase, x + 31); CP_ABS_X2(ppdev, pjBase, x + 40); CP_ABS_X3(ppdev, pjBase, x + 71); CP_START_BLT_WAIT(ppdev, pjBase); // Copy '5': CP_ABS_XY1(ppdev, pjBase, x + 71, y + 7); CP_ABS_XY2(ppdev, pjBase, x, y + 8); CP_ABS_XY3(ppdev, pjBase, x + 71, y + 15); CP_START_BLT_WAIT(ppdev, pjBase); // Copy '6': CP_ABS_Y2(ppdev, pjBase, y + 16); CP_ABS_Y3(ppdev, pjBase, y + 23); CP_START_BLT_WAIT(ppdev, pjBase); // Copy '7': CP_ABS_Y1(ppdev, pjBase, y + 15); CP_ABS_Y2(ppdev, pjBase, y + 24); CP_ABS_Y3(ppdev, pjBase, y + 39); CP_START_BLT_WAIT(ppdev, pjBase); // Copy '8': CP_ABS_Y1(ppdev, pjBase, y + 31); CP_ABS_Y2(ppdev, pjBase, y + 40); CP_ABS_Y3(ppdev, pjBase, y + 71); CP_START_BLT_WAIT(ppdev, pjBase); } /******************************Public*Routine******************************\ * VOID vFillSlowPat * \**************************************************************************/ VOID vFillSlowPat( // Type FNFILL PDEV* ppdev, LONG c, // Can't be zero RECTL* prcl, // List of rectangles to be filled, in relative // coordinates ULONG ulHwMix, // Hardware mix mode RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure POINTL* pptlBrush) // Pattern alignment { BYTE* pjBase; BOOL bExponential; ULONG ulRaster; LONG xBrush; LONG yBrush; LONG xSrc; LONG ySrc; LONG x; LONG y; LONG xFrom; LONG yFrom; LONG cxToGo; LONG cyToGo; LONG cxThis; LONG cyThis; LONG xOrg; LONG yOrg; LONG cyOriginal; LONG yOriginal; LONG xOriginal; BRUSHENTRY* pbe; // Pointer to brush entry data, which is used // for keeping track of the location and status // of the pattern bits cached in off-screen // memory if (rbc.prb->apbe[IBOARD(ppdev)]->prbVerify != rbc.prb) { vSlowPatRealize(ppdev, rbc.prb); } pjBase = ppdev->pjBase; // We special case PATCOPY mixes because we can implement // an exponential fill: every blt will double the size of // the current rectangle by using the portion of the pattern // that has already been done for this rectangle as the source. // // Note that there's no point in also checking for BLACK // or WHITE because those will be taken care of by the // solid fill routines, and I can't be bothered to check for // NOTCOPYPEN: bExponential = (ulHwMix == 0xf0f0); // Convert the rop from a Rop3 between P and D to the corresponding // Rop3 between S and D: ulRaster = (ulHwMix & 0x3C) >> 2; ulRaster |= (ulRaster << 4); if (P9000(ppdev)) { // Make the Rop3 into a true P9000 minterm: ulRaster |= (ulRaster << 8); } // Note that since we do our brush alignment calculations in // relative coordinates, we should keep the brush origin in // relative coordinates as well: xOrg = pptlBrush->x; yOrg = pptlBrush->y; pbe = rbc.prb->apbe[IBOARD(ppdev)]; xBrush = pbe->x; yBrush = pbe->y; do { x = prcl->left; y = prcl->top; xSrc = xBrush + ((x - xOrg) & 7); ySrc = yBrush + ((y - yOrg) & 7); cxToGo = prcl->right - x; cyToGo = prcl->bottom - y; if ((cxToGo <= SLOW_BRUSH_DIMENSION) && (cyToGo <= SLOW_BRUSH_DIMENSION)) { CP_ABS_XY0(ppdev, pjBase, xSrc, ySrc); CP_ABS_XY1(ppdev, pjBase, xSrc + cxToGo - 1, ySrc + cyToGo - 1); CP_XY2(ppdev, pjBase, x, y); CP_XY3(ppdev, pjBase, x + cxToGo - 1, y + cyToGo - 1); CP_WAIT(ppdev, pjBase); CP_RASTER(ppdev, pjBase, ulRaster); CP_START_BLT(ppdev, pjBase); } else if (bExponential) { cyThis = SLOW_BRUSH_DIMENSION; cyToGo -= cyThis; if (cyToGo < 0) cyThis += cyToGo; cxThis = SLOW_BRUSH_DIMENSION; cxToGo -= cxThis; if (cxToGo < 0) cxThis += cxToGo; CP_ABS_XY0(ppdev, pjBase, xSrc, ySrc); CP_ABS_XY1(ppdev, pjBase, xSrc + cxThis - 1, ySrc + cyThis - 1); CP_XY2(ppdev, pjBase, x, y); CP_XY3(ppdev, pjBase, x + cxThis - 1, y + cyThis - 1); CP_WAIT(ppdev, pjBase); CP_RASTER(ppdev, pjBase, ulRaster); CP_START_BLT(ppdev, pjBase); CP_XY0(ppdev, pjBase, x, y); xOriginal = x; x += cxThis; y += cyThis; while (cxToGo > 0) { // First, expand out to the right, doubling our size // each time: xFrom = x; cxToGo -= cxThis; if (cxToGo < 0) { cxThis += cxToGo; xFrom += cxToGo; } CP_XY1(ppdev, pjBase, xFrom - 1, y - 1); CP_X2(ppdev, pjBase, x); CP_X3(ppdev, pjBase, x + cxThis - 1); CP_START_BLT_WAIT(ppdev, pjBase); x += cxThis; cxThis *= 2; } while (cyToGo > 0) { // Now do the same thing vertically: yFrom = y; cyToGo -= cyThis; if (cyToGo < 0) { cyThis += cyToGo; yFrom += cyToGo; } CP_XY1(ppdev, pjBase, x - 1, yFrom - 1); CP_XY2(ppdev, pjBase, xOriginal, y); CP_Y3(ppdev, pjBase, y + cyThis - 1); CP_START_BLT_WAIT(ppdev, pjBase); y += cyThis; cyThis *= 2; } } else { // We handle arbitrary mixes simply by repeatedly tiling // our cached pattern over the entire rectangle: CP_ABS_XY0(ppdev, pjBase, xSrc, ySrc); CP_WAIT(ppdev, pjBase); CP_RASTER(ppdev, pjBase, ulRaster); cyOriginal = cyToGo; // Have to remember for later... yOriginal = y; do { cxThis = SLOW_BRUSH_DIMENSION; cxToGo -= cxThis; if (cxToGo < 0) cxThis += cxToGo; cyToGo = cyOriginal; // Have to reset for each new column y = yOriginal; do { cyThis = SLOW_BRUSH_DIMENSION; cyToGo -= cyThis; if (cyToGo < 0) cyThis += cyToGo; CP_ABS_XY1(ppdev, pjBase, xSrc + cxThis - 1, ySrc + cyThis - 1); CP_XY2(ppdev, pjBase, x, y); CP_XY3(ppdev, pjBase, x + cxThis - 1, y + cyThis - 1); CP_START_BLT_WAIT(ppdev, pjBase); y += cyThis; } while (cyToGo > 0); x += cxThis; // Get ready for next column } while (cxToGo > 0); } prcl++; } while (--c != 0); } /******************************Public*Routine******************************\ * VOID vFillPat * \**************************************************************************/ VOID vFillPat( // Type FNFILL PDEV* ppdev, LONG c, // Can't be zero RECTL* prcl, // List of rectangles to be filled, in relative // coordinates ULONG ulHwMix, // Hardware mix mode RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure POINTL* pptlBrush) // Pattern alignment { BYTE* pjBase; LONG i; ULONG* pulPattern; ULONG ulPattern; ASSERTDD(((ulHwMix >> 8) == (ulHwMix & 0xff)) || ((ulHwMix & 0xff00) == 0xaa00), "This routine handles only opaque or transparent mixes"); if (rbc.prb->fl & (RBRUSH_2COLOR | RBRUSH_4COLOR)) { // Hardware pattern pjBase = ppdev->pjBase; CP_METARECT(ppdev, pjBase, prcl->left, prcl->top); CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom); CP_WAIT(ppdev, pjBase); if (P9000(ppdev)) { CP_PATTERN_ORGX(ppdev, pjBase, ppdev->xOffset + pptlBrush->x); CP_PATTERN_ORGY(ppdev, pjBase, ppdev->yOffset + pptlBrush->y); CP_BACKGROUND(ppdev, pjBase, rbc.prb->ulColor[0]); CP_FOREGROUND(ppdev, pjBase, rbc.prb->ulColor[1]); pulPattern = &rbc.prb->aulPattern[0]; for (i = 0; i < 4; i++) { ulPattern = *pulPattern++; CP_PATTERN(ppdev, pjBase, i, ulPattern); CP_PATTERN(ppdev, pjBase, i + 4, ulPattern); } if (((ulHwMix >> 8) & 0xff) == (ulHwMix & 0xff)) { ulHwMix = gaulP9000OpaqueFromRop2[(ulHwMix & 0x3C) >> 2]; CP_RASTER(ppdev, pjBase, ulHwMix | P9000_ENABLE_PATTERN); } else { ulHwMix = gaulP9000TransparentFromRop2[(ulHwMix & 0x3C) >> 2]; CP_RASTER(ppdev, pjBase, ulHwMix | P9000_ENABLE_PATTERN); } } else { CP_PATTERN_ORGX(ppdev, pjBase, -(ppdev->xOffset + pptlBrush->x)); CP_PATTERN_ORGY(ppdev, pjBase, -(ppdev->yOffset + pptlBrush->y)); CP_COLOR0_FAST(ppdev, pjBase, rbc.prb->ulColor[0]); CP_COLOR1_FAST(ppdev, pjBase, rbc.prb->ulColor[1]); CP_PATTERN(ppdev, pjBase, 0, rbc.prb->aulPattern[0]); CP_PATTERN(ppdev, pjBase, 1, rbc.prb->aulPattern[1]); CP_PATTERN(ppdev, pjBase, 2, rbc.prb->aulPattern[2]); CP_PATTERN(ppdev, pjBase, 3, rbc.prb->aulPattern[3]); if (rbc.prb->fl & RBRUSH_2COLOR) { if (((ulHwMix >> 8) & 0xff) == (ulHwMix & 0xff)) { CP_RASTER(ppdev, pjBase, (ulHwMix & 0xff) | P9100_ENABLE_PATTERN); } else { CP_RASTER(ppdev, pjBase, (ulHwMix & 0xff) | P9100_ENABLE_PATTERN | P9100_TRANSPARENT_PATTERN); } } else { CP_COLOR2_FAST(ppdev, pjBase, rbc.prb->ulColor[2]); CP_COLOR3_FAST(ppdev, pjBase, rbc.prb->ulColor[3]); CP_RASTER(ppdev, pjBase, (ulHwMix & 0xff) | P9100_ENABLE_PATTERN | P9100_FOUR_COLOR_PATTERN); } } CP_START_QUAD(ppdev, pjBase); while (prcl++, --c) { CP_METARECT(ppdev, pjBase, prcl->left, prcl->top); CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom); CP_START_QUAD_WAIT(ppdev, pjBase); } } else { vFillSlowPat(ppdev, c, prcl, ulHwMix, rbc, pptlBrush); } } /******************************Public*Routine******************************\ * VOID vXfer1bpp * * This routine colour expands a monochrome bitmap. * \**************************************************************************/ VOID vXfer1bpp( // Type FNXFER PDEV* ppdev, LONG c, // Count of rectangles, can't be zero RECTL* prcl, // List of destination rectangles, in relative // coordinates ULONG ulHwMix, // Foreground and background hardware mix SURFOBJ* psoSrc, // Source surface POINTL* pptlSrc, // Original unclipped source point RECTL* prclDst, // Original unclipped destination rectangle XLATEOBJ* pxlo) // Translate that provides colour-expansion information { BYTE* pjBase; LONG dx; LONG dy; LONG lSrcDelta; BYTE* pjSrcScan0; ULONG* pulXlate; LONG xLeft; LONG xRight; LONG yTop; LONG cyScan; LONG xBias; LONG culScan; LONG lSrcSkip; ULONG* pulSrc; LONG cRem; LONG i; ASSERTDD(((ulHwMix >> 8) & 0xff) == (ulHwMix & 0xff), "Expected only an opaquing rop"); pjBase = ppdev->pjBase; dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; lSrcDelta = psoSrc->lDelta; pjSrcScan0 = psoSrc->pvScan0; do { xLeft = prcl->left; xRight = prcl->right; yTop = prcl->top; xBias = (xLeft + dx) & 31; xLeft -= xBias; CP_XY1(ppdev, pjBase, xLeft, yTop); CP_X0(ppdev, pjBase, xLeft); CP_X2(ppdev, pjBase, xRight); CP_ABS_Y3(ppdev, pjBase, 1); culScan = ((xRight - xLeft) >> 5); cRem = ((xRight - xLeft) & 31) - 1; if (cRem < 0) { culScan--; cRem = 31; } pulSrc = (ULONG*) (pjSrcScan0 + (yTop + dy) * lSrcDelta + ((xLeft + dx) >> 3)); lSrcSkip = lSrcDelta - (culScan << 2); cyScan = (prcl->bottom - yTop); CP_WAIT(ppdev, pjBase); CP_WLEFT(ppdev, pjBase, prcl->left); // The following three accelerator states are invariant to this // loop, but we set them each time anyway because we expect // usually to have only to do one iteration of this loop, and this // state must to be set after doing a CP_WAIT, which we want to // delay until we get as much processing done as possible, for // maximum overlap. pulXlate = pxlo->pulXlate; if (P9000(ppdev)) { CP_BACKGROUND(ppdev, pjBase, pulXlate[0]); CP_FOREGROUND(ppdev, pjBase, pulXlate[1]); CP_RASTER(ppdev, pjBase, gaulP9000OpaqueFromRop2[ulHwMix & 0xf]); } else { CP_COLOR0(ppdev, pjBase, pulXlate[0]); CP_COLOR1(ppdev, pjBase, pulXlate[1]); CP_RASTER(ppdev, pjBase, ulHwMix & 0xff); } CP_START_PIXEL1(ppdev, pjBase); do { for (i = culScan; i != 0; i--) { CP_PIXEL1(ppdev, pjBase, *pulSrc); pulSrc++; } CP_PIXEL1_REM(ppdev, pjBase, cRem, *pulSrc); pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip); } while (--cyScan != 0); CP_END_PIXEL1(ppdev, pjBase); } while (prcl++, --c); // Don't forget to reset the clip register: CP_WAIT(ppdev, pjBase); CP_ABS_WMIN(ppdev, pjBase, 0, 0); } /******************************Public*Routine******************************\ * VOID vXfer4bpp * * Does a 4bpp transfer from a bitmap to the screen. * * NOTE: The screen must be 8bpp for this function to be called! * * The reason we implement this is that a lot of resources are kept as 4bpp, * and used to initialize DFBs, some of which we of course keep off-screen. * \**************************************************************************/ VOID vXfer4bpp( // Type FNXFER PDEV* ppdev, LONG c, // Count of rectangles, can't be zero RECTL* prcl, // List of destination rectangles, in relative // coordinates ULONG ulHwMix, // Hardware mix SURFOBJ* psoSrc, // Source surface POINTL* pptlSrc, // Original unclipped source point RECTL* prclDst, // Original unclipped destination rectangle XLATEOBJ* pxlo) // Translate that provides colour-expansion information { BYTE* pjBase; LONG dx; LONG dy; LONG lSrcDelta; BYTE* pjSrcScan0; ULONG* pulXlate; LONG xLeft; LONG xRight; LONG yTop; LONG cyScan; LONG xBias; LONG cwSrc; LONG lSrcSkip; LONG cw; BYTE* pjSrc; BYTE jSrc; ULONG ul; ASSERTDD(ppdev->cjPel == 1, "This function assumes 8bpp"); pjBase = ppdev->pjBase; dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; lSrcDelta = psoSrc->lDelta; pjSrcScan0 = psoSrc->pvScan0; pulXlate = pxlo->pulXlate; do { xLeft = prcl->left; xRight = prcl->right; yTop = prcl->top; // We compute 'xBias' in order to word-align the source pointer. // This way, since we're processing a word of the source at a // time, we're guaranteed not to read even a byte past the end of // the bitmap. xBias = ((xLeft + dx) & 3); xLeft -= xBias; CP_XY1(ppdev, pjBase, xLeft, yTop); CP_X0(ppdev, pjBase, xLeft); CP_X2(ppdev, pjBase, xRight); CP_ABS_Y3(ppdev, pjBase, 1); // Every word in the source is one dword in the destination: cwSrc = ((xRight - xLeft) + 3) >> 2; lSrcSkip = lSrcDelta - (cwSrc << 1); pjSrc = pjSrcScan0 + (yTop + dy) * lSrcDelta + ((xLeft + dx) >> 1); cyScan = prcl->bottom - yTop; ASSERTDD(((ULONG_PTR) pjSrc & 1) == 0, "Source should be word aligned"); // Yes, we're setting the raster every time in the loop. But we // have to wait for not-busy before setting the raster, and the // chances are that we'll only have one rectangle to blt, so // we do this here: CP_WAIT(ppdev, pjBase); CP_WLEFT(ppdev, pjBase, prcl->left); CP_RASTER(ppdev, pjBase, P9000(ppdev) ? ulHwMix : (ulHwMix & 0xff)); CP_START_PIXEL8(ppdev, pjBase); do { cw = cwSrc; do { jSrc = *(pjSrc + 1); ul = pulXlate[jSrc & 0xf]; ul <<= 8; ul |= pulXlate[jSrc >> 4]; jSrc = *(pjSrc); ul <<= 8; ul |= pulXlate[jSrc & 0xf]; ul <<= 8; ul |= pulXlate[jSrc >> 4]; CP_PIXEL8(ppdev, pjBase, ul); pjSrc += 2; } while (--cw != 0); pjSrc += lSrcSkip; } while (--cyScan != 0); CP_END_PIXEL8(ppdev, pjBase); } while (prcl++, --c); // Don't forget to reset the clip register: CP_WAIT(ppdev, pjBase); CP_ABS_WMIN(ppdev, pjBase, 0, 0); } /******************************Public*Routine******************************\ * VOID vXferNative * * Transfers a bitmap that is the same colour depth as the display to * the screen via the data transfer register, with no translation. * \**************************************************************************/ VOID vXferNative( // Type FNXFER PDEV* ppdev, LONG c, // Count of rectangles, can't be zero RECTL* prcl, // Array of relative coordinates destination rectangles ULONG ulHwMix, // Hardware mix SURFOBJ* psoSrc, // Source surface POINTL* pptlSrc, // Original unclipped source point RECTL* prclDst, // Original unclipped destination rectangle XLATEOBJ* pxlo) // Not used { BYTE* pjBase; LONG cjPel; LONG xOffset; LONG yOffset; LONG dx; LONG dy; LONG lSrcDelta; BYTE* pjSrcScan0; LONG xLeft; LONG xRight; LONG yTop; LONG cyScan; LONG xBias; LONG culScan; LONG lSrcSkip; LONG cu; ULONG* pulSrc; pjBase = ppdev->pjBase; cjPel = ppdev->cjPel; xOffset = ppdev->xOffset; yOffset = ppdev->yOffset; dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; lSrcDelta = psoSrc->lDelta; pjSrcScan0 = psoSrc->pvScan0; do { xLeft = prcl->left; xRight = prcl->right; yTop = prcl->top; // We compute 'xBias' in order to dword-align the source pointer. // This way, we don't have to do unaligned reads of the source, // and we're guaranteed not to read even a byte past the end of // the bitmap. // // Note that this bias works at 24bpp, too: xBias = ((xLeft + dx) & 3); xLeft -= xBias; CP_ABS_XY1(ppdev, pjBase, (xLeft + xOffset) * cjPel, yTop + yOffset); CP_ABS_X0(ppdev, pjBase, (xLeft + xOffset) * cjPel); CP_ABS_X2(ppdev, pjBase, (xRight + xOffset) * cjPel); CP_ABS_Y3(ppdev, pjBase, 1); culScan = ((xRight - xLeft) * cjPel + 3) >> 2; lSrcSkip = lSrcDelta - (culScan << 2); pulSrc = (ULONG*) (pjSrcScan0 + (yTop + dy) * lSrcDelta + (xLeft + dx) * cjPel); cyScan = prcl->bottom - yTop; ASSERTDD(((ULONG_PTR)pulSrc & 3) == 0, "Source should be dword aligned"); // Yes, we're setting the raster every time in the loop. But we // have to wait for not-busy before setting the raster, and the // chances are that we'll only have one rectangle to blt, so // we do this here: CP_WAIT(ppdev, pjBase); CP_ABS_WLEFT(ppdev, pjBase, prcl->left + xOffset); CP_RASTER(ppdev, pjBase, P9000(ppdev) ? ulHwMix : (ulHwMix & 0xff)); CP_START_PIXEL8(ppdev, pjBase); do { cu = culScan; do { CP_PIXEL8(ppdev, pjBase, *pulSrc); pulSrc++; } while (--cu != 0); pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip); } while (--cyScan != 0); CP_END_PIXEL8(ppdev, pjBase); } while (prcl++, --c); // Don't forget to reset the clip register: CP_WAIT(ppdev, pjBase); CP_ABS_WMIN(ppdev, pjBase, 0, 0); } /******************************Public*Routine******************************\ * VOID vCopyBlt * * Does a screen-to-screen blt of a list of rectangles. * * Note: We may call this function with weird ROPs to do colour-expansion * from off-screen monochrome bitmaps. * \**************************************************************************/ VOID vCopyBlt( // Type FNCOPY PDEV* ppdev, LONG c, // Can't be zero RECTL* prcl, // Array of relative coordinates destination rectangles ULONG ulHwMix, // Hardware mix POINTL* pptlSrc, // Original unclipped source point RECTL* prclDst) // Original unclipped destination rectangle { BYTE* pjBase; LONG cjPel; LONG xOffset; LONG yOffset; LONG dx; LONG dy; LONG xSrc; LONG ySrc; pjBase = ppdev->pjBase; cjPel = ppdev->cjPel; // Our DFB xOffset has to be scaled by the pixel size too: xOffset = ppdev->xOffset; yOffset = ppdev->yOffset; dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; xSrc = prcl->left + dx; ySrc = prcl->top + dy; CP_ABS_XY0(ppdev, pjBase, (xOffset + xSrc) * cjPel, (yOffset + ySrc)); CP_ABS_XY1(ppdev, pjBase, (xOffset + xSrc + prcl->right - prcl->left) * cjPel - 1, (yOffset + ySrc + prcl->bottom - prcl->top - 1)); CP_ABS_XY2(ppdev, pjBase, (xOffset + prcl->left) * cjPel, (yOffset + prcl->top)); CP_ABS_XY3(ppdev, pjBase, (xOffset + prcl->right) * cjPel - 1, (yOffset + prcl->bottom - 1)); CP_WAIT(ppdev, pjBase); CP_RASTER(ppdev, pjBase, P9000(ppdev) ? ulHwMix : (ulHwMix & 0xff)); CP_START_BLT(ppdev, pjBase); while (prcl++, --c) { xSrc = prcl->left + dx; ySrc = prcl->top + dy; CP_ABS_XY0(ppdev, pjBase, (xOffset + xSrc) * cjPel, (yOffset + ySrc)); CP_ABS_XY1(ppdev, pjBase, (xOffset + xSrc + prcl->right - prcl->left) * cjPel - 1, (yOffset + ySrc + prcl->bottom - prcl->top - 1)); CP_ABS_XY2(ppdev, pjBase, (xOffset + prcl->left) * cjPel, (yOffset + prcl->top)); CP_ABS_XY3(ppdev, pjBase, (xOffset + prcl->right) * cjPel - 1, (yOffset + prcl->bottom - 1)); CP_START_BLT_WAIT(ppdev, pjBase); } } /******************************Public*Routine******************************\ * VOID vFillSolidP9000HighColor * * Fills a list of rectangles with a solid colour when running at 16bpp * on the P9000, using the pattern hardware. * \**************************************************************************/ VOID vFillSolidP9000HighColor( // Type FNFILL PDEV* ppdev, LONG c, // Can't be zero RECTL* prcl, // List of rectangles to be filled, in relative // coordinates ULONG ulHwMix, // Hardware mix mode RBRUSH_COLOR rbc, // Drawing colour is rbc.iSolidColor POINTL* pptlBrush) // Not used { BYTE* pjBase; LONG xOffset; LONG yOffset; ASSERTDD(c > 0, "Can't handle zero rectangles"); ASSERTDD(P9000(ppdev), "Shouldn't need to be called on the P9100"); ASSERTDD(ppdev->iBitmapFormat == BMF_16BPP, "Only handle 16bpp for now"); pjBase = ppdev->pjBase; // Our DFB xOffset has to be scaled by the pixel size too: xOffset = 2 * ppdev->xOffset; yOffset = ppdev->yOffset; CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->left, yOffset + prcl->top); CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->right, yOffset + prcl->bottom); // We've already downloaded and set the pattern origin in // vAssertModeBrushCache: CP_WAIT(ppdev, pjBase); CP_RASTER(ppdev, pjBase, P9000_ENABLE_PATTERN | gaulP9000OpaqueFromRop2[(ulHwMix & 0x3C) >> 2]); CP_FOREGROUND(ppdev, pjBase, rbc.iSolidColor); CP_BACKGROUND(ppdev, pjBase, rbc.iSolidColor >> 8); CP_START_QUAD(ppdev, pjBase); while (prcl++, --c) { CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->left, yOffset + prcl->top); CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->right, yOffset + prcl->bottom); CP_START_QUAD_WAIT(ppdev, pjBase); } }