/******************************Module*Header*******************************\ * Module Name: blt.c * * Contains the low-level 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-1996 Microsoft Corporation * Copyright (c) 1993-1996 Matrox Electronic Systems, Ltd. \**************************************************************************/ #include "precomp.h" /******************************Public*Routine******************************\ * VOID vFillPat1bpp * \**************************************************************************/ VOID vFillPat1bpp( // Type FNFILL PDEV* ppdev, LONG c, // Can't be zero RECTL* prcl, // List of rectangles to be filled, in relative // coordinates ULONG rop4, // Rop4 RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure POINTL* pptlBrush) // Pattern alignment { BYTE* pjBase; RBRUSH* prb; LONG xOffset; LONG yOffset; ULONG ulDwg; ULONG ulHwMix; ASSERTDD(rbc.prb->fl & RBRUSH_2COLOR, "Must be 2 colour pattern here"); pjBase = ppdev->pjBase; xOffset = ppdev->xOffset; yOffset = ppdev->yOffset; if ((rop4 & 0xff) == 0xf0) { ulDwg = opcode_TRAP + blockm_OFF + atype_RPL + bop_SRCCOPY; } else { ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2); ulDwg = opcode_TRAP + blockm_OFF + atype_RSTR + (ulHwMix << 16); } if (((rop4 >> 8) & 0xff) == (rop4 & 0xff)) { // Normal opaque mode: ulDwg |= transc_BG_OPAQUE; } else { // GDI guarantees us that if the foreground and background // ROPs are different, the background rop is LEAVEALONE: ulDwg |= transc_BG_TRANSP; } if ((GET_CACHE_FLAGS(ppdev, (SIGN_CACHE | ARX_CACHE))) == (SIGN_CACHE | ARX_CACHE)) { CHECK_FIFO_SPACE(pjBase, 12); } else { CHECK_FIFO_SPACE(pjBase, 17); CP_WRITE(pjBase, DWG_SGN, 0); CP_WRITE(pjBase, DWG_AR1, 0); CP_WRITE(pjBase, DWG_AR2, 0); CP_WRITE(pjBase, DWG_AR4, 0); CP_WRITE(pjBase, DWG_AR5, 0); } ppdev->HopeFlags = (SIGN_CACHE | ARX_CACHE); CP_WRITE(pjBase, DWG_DWGCTL, ulDwg); CP_WRITE(pjBase, DWG_SHIFT, ((-(pptlBrush->y + yOffset) & 7) << 4) | (-(pptlBrush->x + xOffset) & 7)); prb = rbc.prb; CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, prb->ulColor[1])); CP_WRITE(pjBase, DWG_BCOL, COLOR_REPLICATE(ppdev, prb->ulColor[0])); CP_WRITE(pjBase, DWG_SRC0, prb->aulPattern[0]); CP_WRITE(pjBase, DWG_SRC1, prb->aulPattern[1]); CP_WRITE(pjBase, DWG_SRC2, prb->aulPattern[2]); CP_WRITE(pjBase, DWG_SRC3, prb->aulPattern[3]); while(TRUE) { CP_WRITE(pjBase, DWG_FXLEFT, prcl->left + xOffset); CP_WRITE(pjBase, DWG_FXRIGHT, prcl->right + xOffset); CP_WRITE(pjBase, DWG_LEN, prcl->bottom - prcl->top); CP_START(pjBase, DWG_YDST, prcl->top + yOffset); if (--c == 0) return; prcl++; CHECK_FIFO_SPACE(pjBase, 4); } } /******************************Public*Routine******************************\ * VOID vXfer4bpp * * Does a 4bpp transfer from a bitmap to the screen. * * 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 rop4, // Rop4 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 xOffset; LONG yOffset; LONG cjPelSize; LONG dx; LONG dy; LONG cx; LONG cy; LONG lSrcDelta; BYTE* pjSrcScan0; BYTE* pjSrc; BYTE* pjDst; LONG xSrc; LONG iLoop; BYTE jSrc; ULONG* pulXlate; ULONG ulHwMix; ULONG ulCtl; LONG i; ULONG ul; LONG xBug; LONG xAbsLeft; BOOL bHwBug; LONG cjSrc; LONG cwSrc; LONG lSrcSkip; LONG cxRem; ULONG ul0; ULONG ul1; ULONG ulBoardId; ASSERTDD(psoSrc->iBitmapFormat == BMF_4BPP, "Source must be 4bpp"); ASSERTDD(c > 0, "Can't handle zero rectangles"); pjBase = ppdev->pjBase; xOffset = ppdev->xOffset; yOffset = ppdev->yOffset; cjPelSize = ppdev->cjPelSize; pulXlate = pxlo->pulXlate; ulBoardId = ppdev->ulBoardId; dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; // Add to destination to get source lSrcDelta = psoSrc->lDelta; pjSrcScan0 = psoSrc->pvScan0; if (rop4 == 0xcccc) // SRCCOPY { ulCtl = (opcode_ILOAD + atype_RPL + blockm_OFF + pattern_OFF + transc_BG_OPAQUE + bop_SRCCOPY); } else { ulHwMix = rop4 & 0xf; ulCtl = (opcode_ILOAD + atype_RSTR + blockm_OFF + pattern_OFF + transc_BG_OPAQUE + (ulHwMix << 16)); } if (ulBoardId != MGA_STORM) { if (cjPelSize >= 3) { ulCtl |= (hcprs_SRC_24_BPP | bltmod_BUCOL); xBug = 0; } else { ulCtl |= (bltmod_BFCOL); xBug = (8 >> cjPelSize); // 8bpp and 16bpp have h/w alignment bugs } } else { ulCtl |= (bltmod_BFCOL); xBug = 0; } CHECK_FIFO_SPACE(pjBase, 11); CP_WRITE(pjBase, DWG_DWGCTL, ulCtl); CP_WRITE(pjBase, DWG_SHIFT, 0); if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE))) { CP_WRITE(pjBase, DWG_SGN, 0); } if (!(GET_CACHE_FLAGS(ppdev, ARX_CACHE))) { CP_WRITE(pjBase, DWG_AR5, 0); } // The SRC0 - SRC3 registers will be trashed by the blt. AR0 will // be modified shortly: ppdev->HopeFlags = SIGN_CACHE; while(TRUE) { cx = prcl->right - prcl->left; cy = prcl->bottom - prcl->top; CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + prcl->right - 1); CP_WRITE(pjBase, DWG_YDST, yOffset + prcl->top); CP_WRITE(pjBase, DWG_LEN, cy); CP_WRITE(pjBase, DWG_AR3, 0); xSrc = prcl->left + dx; pjSrc = pjSrcScan0 + (prcl->top + dy) * lSrcDelta + (xSrc >> 1); xAbsLeft = (xOffset + prcl->left); CP_WRITE(pjBase, DWG_CXLEFT, xAbsLeft); xAbsLeft -= (xSrc & 1); // Align to start of first source byte cx += (xSrc & 1); bHwBug = (ulBoardId != MGA_STORM) && (xAbsLeft & xBug); if (!bHwBug) { CP_WRITE(pjBase, DWG_FXLEFT, xAbsLeft); CP_START(pjBase, DWG_AR0, cx - 1); } else { CP_WRITE(pjBase, DWG_FXLEFT, xAbsLeft - xBug); CP_START(pjBase, DWG_AR0, cx + xBug - 1); } cjSrc = (cx + 1) >> 1; // Number of source bytes touched lSrcSkip = lSrcDelta - cjSrc; // Make sure the MGA is ready to take the data: CHECK_FIFO_SPACE(pjBase, 32); if (cjPelSize == 1) { // This part handles 8bpp output: cwSrc = (cjSrc >> 1); // Number of whole source words do { if (bHwBug) CP_WRITE_SRC(pjBase, 0); for (i = cwSrc; i != 0; i--) { jSrc = *pjSrc++; ul = (pulXlate[jSrc >> 4]); ul |= (pulXlate[jSrc & 0xf] << 8); jSrc = *pjSrc++; ul |= (pulXlate[jSrc >> 4] << 16); ul |= (pulXlate[jSrc & 0xf] << 24); CP_WRITE_SRC(pjBase, ul); } // Handle an odd end byte, if there is one: if (cjSrc & 1) { jSrc = *pjSrc++; ul = (pulXlate[jSrc >> 4]); ul |= (pulXlate[jSrc & 0xf] << 8); CP_WRITE_SRC(pjBase, ul); } pjSrc += lSrcSkip; } while (--cy != 0); } else if (cjPelSize == 2) { // This part handles 16bpp output: do { if (bHwBug) CP_WRITE_SRC(pjBase, 0); i = cjSrc; do { jSrc = *pjSrc++; ul = (pulXlate[jSrc >> 4]); ul |= (pulXlate[jSrc & 0xf] << 16); CP_WRITE_SRC(pjBase, ul); } while (--i != 0); pjSrc += lSrcSkip; } while (--cy != 0); } else if (cjPelSize == 4) { cjSrc = cx >> 1; // Number of whole source bytes touched cxRem = cx & 1; // This part handles 32bpp output: do { if (bHwBug) CP_WRITE_SRC(pjBase, 0); i = cjSrc; while (i--) // may be 0 { jSrc = *pjSrc++; ul = (pulXlate[jSrc >> 4]); CP_WRITE_SRC(pjBase, ul); ul = (pulXlate[jSrc & 0xf]); CP_WRITE_SRC(pjBase, ul); } if (cxRem) { jSrc = *pjSrc++; ul = (pulXlate[jSrc >> 4]); CP_WRITE_SRC(pjBase, ul); } pjSrc += lSrcSkip; } while (--cy != 0); } else { // This part handles packed 24bpp output: ASSERTDD(!bHwBug, "There is no hardware bug when higher than 16bpp"); cwSrc = (cx >> 2); // Number of whole source words cxRem = (cx & 3); if (cxRem == 3) { // Merge this case into the whole word case: cwSrc++; cxRem = 0; } do { for (i = cwSrc; i != 0; i--) { jSrc = *pjSrc++; ul0 = (pulXlate[jSrc >> 4]); ul1 = (pulXlate[jSrc & 0xf]); ul = ul0 | (ul1 << 24); CP_WRITE_SRC(pjBase, ul); jSrc = *pjSrc++; ul0 = (pulXlate[jSrc >> 4]); ul = (ul1 >> 8) | (ul0 << 16); CP_WRITE_SRC(pjBase, ul); ul1 = (pulXlate[jSrc & 0xf]); ul = (ul1 << 8) | (ul0 >> 16); CP_WRITE_SRC(pjBase, ul); } if (cxRem > 0) { jSrc = *pjSrc++; ul0 = (pulXlate[jSrc >> 4]); ul1 = (pulXlate[jSrc & 0xf]); ul = ul0 | (ul1 << 24); CP_WRITE_SRC(pjBase, ul); if (cxRem > 1) { ul = (ul1 >> 8); CP_WRITE_SRC(pjBase, ul); } } pjSrc += lSrcSkip; } while (--cy != 0); } if (--c == 0) { // Restore the clipping: CHECK_FIFO_SPACE(pjBase, 1); CP_WRITE(pjBase, DWG_CXLEFT, 0); return; } prcl++; CHECK_FIFO_SPACE(pjBase, 7); } } /******************************Public*Routine******************************\ * VOID vXfer8bpp * * Does a 8bpp transfer from a bitmap to the screen. * * The reason we implement this is that a lot of resources are kept as 8bpp, * and used to initialize DFBs, some of which we of course keep off-screen. * \**************************************************************************/ VOID vXfer8bpp( // Type FNXFER PDEV* ppdev, LONG c, // Count of rectangles, can't be zero RECTL* prcl, // List of destination rectangles, in relative // coordinates ULONG rop4, // Rop4 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 xOffset; LONG yOffset; LONG cjPelSize; LONG dx; LONG dy; LONG cx; LONG cy; LONG lSrcDelta; BYTE* pjSrcScan0; BYTE* pjSrc; BYTE* pjDst; LONG xSrc; LONG iLoop; ULONG* pulXlate; ULONG ulHwMix; ULONG ulCtl; LONG i; ULONG ul; LONG xBug; LONG xAbsLeft; BOOL bHwBug; LONG cwSrc; LONG cdSrc; LONG lSrcSkip; LONG cxRem; ULONG ul0; ULONG ul1; ULONG ulBoardId; ASSERTDD(psoSrc->iBitmapFormat == BMF_8BPP, "Source must be 8bpp"); ASSERTDD(c > 0, "Can't handle zero rectangles"); ASSERTDD(pxlo->pulXlate != NULL, "Must be a translate"); pjBase = ppdev->pjBase; xOffset = ppdev->xOffset; yOffset = ppdev->yOffset; cjPelSize = ppdev->cjPelSize; pulXlate = pxlo->pulXlate; ulBoardId = ppdev->ulBoardId; dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; // Add to destination to get source lSrcDelta = psoSrc->lDelta; pjSrcScan0 = psoSrc->pvScan0; if (rop4 == 0xcccc) // SRCCOPY { ulCtl = (opcode_ILOAD + atype_RPL + blockm_OFF + pattern_OFF + transc_BG_OPAQUE + bop_SRCCOPY); } else { ulHwMix = rop4 & 0xf; ulCtl = (opcode_ILOAD + atype_RSTR + blockm_OFF + pattern_OFF + transc_BG_OPAQUE + (ulHwMix << 16)); } if (ulBoardId != MGA_STORM) { if (cjPelSize >= 3) { ulCtl |= (hcprs_SRC_24_BPP | bltmod_BUCOL); xBug = 0; } else { ulCtl |= (bltmod_BFCOL); xBug = (8 >> cjPelSize); // 8bpp and 16bpp have h/w alignment bugs } } else { ulCtl |= (bltmod_BFCOL); xBug = 0; } CHECK_FIFO_SPACE(pjBase, 11); CP_WRITE(pjBase, DWG_DWGCTL, ulCtl); CP_WRITE(pjBase, DWG_SHIFT, 0); if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE))) { CP_WRITE(pjBase, DWG_SGN, 0); } if (!(GET_CACHE_FLAGS(ppdev, ARX_CACHE))) { CP_WRITE(pjBase, DWG_AR5, 0); } // The SRC0 - SRC3 registers will be trashed by the blt. AR0 will // be modified shortly: ppdev->HopeFlags = SIGN_CACHE; while(TRUE) { cx = prcl->right - prcl->left; cy = prcl->bottom - prcl->top; CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + prcl->right - 1); CP_WRITE(pjBase, DWG_YDST, yOffset + prcl->top); CP_WRITE(pjBase, DWG_LEN, cy); CP_WRITE(pjBase, DWG_AR3, 0); xSrc = prcl->left + dx; pjSrc = pjSrcScan0 + (prcl->top + dy) * lSrcDelta + xSrc; xAbsLeft = (xOffset + prcl->left); bHwBug = (ulBoardId != MGA_STORM) && (xAbsLeft & xBug); if (!bHwBug) { CP_WRITE(pjBase, DWG_FXLEFT, xAbsLeft); CP_START(pjBase, DWG_AR0, cx - 1); } else { CP_WRITE(pjBase, DWG_CXLEFT, xAbsLeft); CP_WRITE(pjBase, DWG_FXLEFT, xAbsLeft - xBug); CP_START(pjBase, DWG_AR0, cx + xBug - 1); } lSrcSkip = lSrcDelta - cx; // Make sure the MGA is ready to take the data: CHECK_FIFO_SPACE(pjBase, 32); if (cjPelSize == 1) { // This part handles 8bpp output: cdSrc = (cx >> 2); cxRem = (cx & 3); do { if (bHwBug) CP_WRITE_SRC(pjBase, 0); for (i = cdSrc; i != 0; i--) { ul = (pulXlate[*pjSrc++]); ul |= (pulXlate[*pjSrc++] << 8); ul |= (pulXlate[*pjSrc++] << 16); ul |= (pulXlate[*pjSrc++] << 24); CP_WRITE_SRC(pjBase, ul); } if (cxRem > 0) { ul = (pulXlate[*pjSrc++]); if (cxRem > 1) { ul |= (pulXlate[*pjSrc++] << 8); if (cxRem > 2) { ul |= (pulXlate[*pjSrc++] << 16); } } CP_WRITE_SRC(pjBase, ul); } pjSrc += lSrcSkip; } while (--cy != 0); } else if (cjPelSize == 2) { // This part handles 16bpp output: cwSrc = (cx >> 1); cxRem = (cx & 1); do { if (bHwBug) CP_WRITE_SRC(pjBase, 0); for (i = cwSrc; i != 0; i--) { ul = (pulXlate[*pjSrc++]); ul |= (pulXlate[*pjSrc++] << 16); CP_WRITE_SRC(pjBase, ul); } if (cxRem > 0) { ul = (pulXlate[*pjSrc++]); CP_WRITE_SRC(pjBase, ul); } pjSrc += lSrcSkip; } while (--cy != 0); } else if (cjPelSize == 4) { // This part handles 32bpp output: cdSrc = cx; do { if (bHwBug) CP_WRITE_SRC(pjBase, 0); for (i = cdSrc; i != 0; i--) { ul = (pulXlate[*pjSrc++]); CP_WRITE_SRC(pjBase, ul); } pjSrc += lSrcSkip; } while (--cy != 0); } else { // This part handles packed 24bpp output: ASSERTDD(!bHwBug, "There is no hardware bug when higher than 16bpp"); cdSrc = (cx >> 2); cxRem = (cx & 3); do { for (i = cdSrc; i != 0; i--) { ul0 = (pulXlate[*pjSrc++]); ul1 = (pulXlate[*pjSrc++]); ul = ul0 | (ul1 << 24); CP_WRITE_SRC(pjBase, ul); ul0 = (pulXlate[*pjSrc++]); ul = (ul1 >> 8) | (ul0 << 16); CP_WRITE_SRC(pjBase, ul); ul1 = (pulXlate[*pjSrc++]); ul = (ul1 << 8) | (ul0 >> 16); CP_WRITE_SRC(pjBase, ul); } if (cxRem > 0) { ul0 = (pulXlate[*pjSrc++]); ul = ul0; if (cxRem > 1) { ul1 = (pulXlate[*pjSrc++]); ul |= (ul1 << 24); CP_WRITE_SRC(pjBase, ul); ul = (ul1 >> 8); if (cxRem > 2) { ul0 = (pulXlate[*pjSrc++]); ul |= (ul0 << 16); CP_WRITE_SRC(pjBase, ul); ul = (ul0 >> 16); } } CP_WRITE_SRC(pjBase, ul); } pjSrc += lSrcSkip; } while (--cy != 0); } if (bHwBug) { // Restore the clipping: CHECK_FIFO_SPACE(pjBase, 1); CP_WRITE(pjBase, DWG_CXLEFT, 0); } if (--c == 0) return; prcl++; CHECK_FIFO_SPACE(pjBase, 7); } } /******************************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 rop4, // Rop4 SURFOBJ* psoSrc, // Source surface POINTL* pptlSrc, // Original unclipped source point RECTL* prclDst, // Original unclipped destination rectangle XLATEOBJ* pxlo) // Not used { BYTE* pjBase; LONG xOffset; LONG yOffset; LONG cjPel; LONG dx; LONG dy; BYTE* pjSrcScan0; LONG lSrcDelta; ULONG ulCtl; ULONG ulHwMix; LONG yTop; LONG xLeft; LONG xAbsLeft; LONG xBug; BOOL bHwBug; LONG xRight; LONG cy; LONG xOriginalLeft; BYTE* pjSrc; LONG cdSrc; ULONG ulBoardId; pjBase = ppdev->pjBase; xOffset = ppdev->xOffset; yOffset = ppdev->yOffset; cjPel = ppdev->cjPelSize; ulBoardId = ppdev->ulBoardId; dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; pjSrcScan0 = psoSrc->pvScan0; lSrcDelta = psoSrc->lDelta; if (rop4 == 0xcccc) // SRCCOPY { ulCtl = (opcode_ILOAD + atype_RPL + blockm_OFF + pattern_OFF + transc_BG_OPAQUE + bop_SRCCOPY); } else { ulHwMix = rop4 & 0xf; ulCtl = (opcode_ILOAD + atype_RSTR + blockm_OFF + pattern_OFF + transc_BG_OPAQUE + (ulHwMix << 16)); } if ((ulBoardId != MGA_STORM) && (ppdev->iBitmapFormat == BMF_24BPP)) { ulCtl |= (hcprs_SRC_24_BPP | bltmod_BUCOL); } else { ulCtl |= (bltmod_BFCOL); } CHECK_FIFO_SPACE(pjBase, 11); CP_WRITE(pjBase, DWG_DWGCTL, ulCtl); CP_WRITE(pjBase, DWG_SHIFT, 0); if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE))) { CP_WRITE(pjBase, DWG_SGN, 0); } if (!(GET_CACHE_FLAGS(ppdev, ARX_CACHE))) { CP_WRITE(pjBase, DWG_AR5, 0); } // The SRC0 - SRC3 registers will be trashed by the blt. AR0 will // be modified shortly: ppdev->HopeFlags = SIGN_CACHE; while (TRUE) { yTop = prcl->top; cy = prcl->bottom - yTop; xRight = prcl->right; xLeft = prcl->left; xOriginalLeft = xLeft; // Adjust the destination so that the source is dword aligned. // Note that this works at 24bpp (but is less restrictive than // it could be at 16bpp): xLeft -= (xLeft + dx) & 3; // Since we're using hardware clipping, the start is always // dword aligned: pjSrc = pjSrcScan0 + (yTop + dy) * lSrcDelta + ((xLeft + dx) * cjPel); cdSrc = ((xRight - xLeft) * cjPel + 3) >> 2; CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + xRight - 1); CP_WRITE(pjBase, DWG_YDST, yOffset + yTop); CP_WRITE(pjBase, DWG_LEN, cy); CP_WRITE(pjBase, DWG_AR3, 0); xAbsLeft = (xOffset + xLeft); xBug = (8 >> cjPel); // 4 for 8bpp, 2 for 16bpp bHwBug = (ulBoardId != MGA_STORM) && (xAbsLeft & xBug) && (cjPel < 3); if (!bHwBug) // 24bpp doesn't have h/w bug { // Don't have to work-around the hardware bug: if (xLeft != xOriginalLeft) { // Since we always dword align the source by adjusting // the destination rectangle, we may have to set the clip // register to compensate: CP_WRITE(pjBase, DWG_CXLEFT, xOffset + xOriginalLeft); } CP_WRITE(pjBase, DWG_FXLEFT, xAbsLeft); CP_START(pjBase, DWG_AR0, xRight - xLeft - 1); // Make sure the MGA is ready to take the data: CHECK_FIFO_SPACE(pjBase, 32); do { DATA_TRANSFER(pjBase, pjSrc, cdSrc); pjSrc += lSrcDelta; } while (--cy != 0); if (xLeft != xOriginalLeft) { CHECK_FIFO_SPACE(pjBase, 1); CP_WRITE(pjBase, DWG_CXLEFT, 0); } } else { // Work-around the hardware bug: CP_WRITE(pjBase, DWG_CXLEFT, xOffset + xOriginalLeft); CP_WRITE(pjBase, DWG_FXLEFT, xAbsLeft - xBug); CP_START(pjBase, DWG_AR0, xRight - xLeft + xBug - 1); // Make sure the MGA is ready to take the data: CHECK_FIFO_SPACE(pjBase, 32); do { DATA_TRANSFER(pjBase, pjSrc, 1); // Account for h/w bug DATA_TRANSFER(pjBase, pjSrc, cdSrc); pjSrc += lSrcDelta; } while (--cy != 0); CHECK_FIFO_SPACE(pjBase, 1); CP_WRITE(pjBase, DWG_CXLEFT, 0); } if (--c == 0) break; prcl++; CHECK_FIFO_SPACE(pjBase, 7); } }