/******************************************************************************\ * * $Workfile: stroke.c $ * * DrvStrokePath for the display driver. * * Copyright (c) 1992-1995 Microsoft Corporation * Copyright (c) 1996 Cirrus Logic, Inc. * * $Log: S:/projects/drivers/ntsrc/display/STROKE.C_V $ * * Rev 1.3 10 Jan 1997 15:40:18 PLCHU * * * Rev 1.2 Nov 07 1996 16:48:06 unknown * * * Rev 1.1 Oct 10 1996 15:39:26 unknown * * * Rev 1.1 12 Aug 1996 16:55:06 frido * Removed unaccessed local variables. * * chu01 : 01-02-97 5480 BitBLT enhancement * * \******************************************************************************/ #include "precomp.h" VOID (*gapfnStripMm[])(PDEV*, STRIP*, LINESTATE*) = { vMmSolidHorizontal, vMmSolidVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal // Should be NUM_STRIP_DRAW_DIRECTIONS = 4 strip drawers in every group vMmSolidHorizontal, vMmSolidVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal // Should be NUM_STRIP_DRAW_STYLES = 8 strip drawers in total for doing // solid lines, and the same number for non-solid lines: vMmStyledHorizontal, vMmStyledVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal vMmStyledHorizontal, vMmStyledVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal }; VOID (*gapfnStripIo[])(PDEV*, STRIP*, LINESTATE*) = { vIoSolidHorizontal, vIoSolidVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal // Should be NUM_STRIP_DRAW_DIRECTIONS = 4 strip drawers in every group vIoSolidHorizontal, vIoSolidVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal // Should be NUM_STRIP_DRAW_STYLES = 8 strip drawers in total for doing // solid lines, and the same number for non-solid lines: vIoStyledHorizontal, vIoStyledVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal vIoStyledHorizontal, vIoStyledVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal }; // chu01 VOID (*gapfnPackedStripMm[])(PDEV*, STRIP*, LINESTATE*) = { vMmSolidHorizontal80, vMmSolidVertical80, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal // Should be NUM_STRIP_DRAW_DIRECTIONS = 4 strip drawers in every group vMmSolidHorizontal80, vMmSolidVertical80, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal // Should be NUM_STRIP_DRAW_STYLES = 8 strip drawers in total for doing // solid lines, and the same number for non-solid lines: vMmStyledHorizontal, vMmStyledVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal vMmStyledHorizontal, vMmStyledVertical, vInvalidStrip, // Diagonal vInvalidStrip, // Diagonal }; // Style array for alternate style (alternates one pixel on, one pixel off): STYLEPOS gaspAlternateStyle[] = { 1 }; BOOL bPuntStrokePath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, LINEATTRS *plineattrs, MIX mix); /******************************Public*Routine******************************\ * BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix) * * Strokes the path. * \**************************************************************************/ BOOL DrvStrokePath( SURFOBJ* pso, PATHOBJ* ppo, CLIPOBJ* pco, XFORMOBJ* pxo, BRUSHOBJ* pbo, POINTL* pptlBrush, LINEATTRS* pla, MIX mix) { PDEV *ppdev = (PDEV*) pso->dhpdev; DSURF *pdsurf; OH* poh; LONG cBpp; BYTE jHwRop; BYTE jMode; ULONG ulSolidColor; STYLEPOS aspLtoR[STYLE_MAX_COUNT]; STYLEPOS aspRtoL[STYLE_MAX_COUNT]; LINESTATE ls; PFNSTRIP* apfn; FLONG fl; RECTL arclClip[4]; // For rectangular clipping if ((mix & 0xf) != 0x0d) DISPDBG((3,"Line with mix(%x)", mix)); // Pass the surface off to GDI if it's a device bitmap that we've // converted to a DIB: pdsurf = (DSURF*) pso->dhsurf; if (pdsurf->dt == DT_DIB) { return(EngStrokePath(pdsurf->pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix)); } // We'll be drawing to the screen or an off-screen DFB; copy the surface's // offset now so that we won't need to refer to the DSURF again: poh = pdsurf->poh; cBpp = ppdev->cBpp; ppdev->xOffset = poh->x; ppdev->yOffset = poh->y; ppdev->xyOffset = poh->xy; if ((DRIVER_PUNT_ALL) || (DRIVER_PUNT_LINES)) { return bPuntStrokePath(pso,ppo,pco,pxo,pbo,pptlBrush,pla,mix); } // // Get the device ready: // jHwRop = gajHwMixFromMix[mix & 0xf]; // Get the color expanded to a DWORD in the blt parameters. // replicate the color from a byte to a dword. // NOTE: this is pixel depth specific. jMode = ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY | ppdev->jModeColor; ulSolidColor = pbo->iSolidColor; if (cBpp == 1) { ulSolidColor |= ulSolidColor << 8; ulSolidColor |= ulSolidColor << 16; } else if (cBpp == 2) { ulSolidColor |= ulSolidColor << 16; } // // chu01 // if ((ppdev->flCaps & CAPS_COMMAND_LIST) && (ppdev->pCommandList != NULL)) { ULONG jULHwRop ; DWORD jExtMode = 0 ; BYTE* pjBase = ppdev->pjBase ; jULHwRop = gajHwPackedMixFromMix[mix & 0xf] ; jExtMode = (ENABLE_XY_POSITION_PACKED | ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY | ppdev->jModeColor) ; CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ; CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset) ; CP_MM_DST_Y_OFFSET(ppdev, pjBase, ppdev->lDelta) ; CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jULHwRop) ; CP_MM_FG_COLOR(ppdev, pjBase, ulSolidColor) ; } else { if (ppdev->flCaps & CAPS_MM_IO) { BYTE * pjBase = ppdev->pjBase; CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset); CP_MM_DST_Y_OFFSET(ppdev, pjBase, ppdev->lDelta); CP_MM_BLT_MODE(ppdev, pjBase, jMode); CP_MM_FG_COLOR(ppdev, pjBase, ulSolidColor); } else { BYTE * pjPorts = ppdev->pjPorts; CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_ROP(ppdev, pjPorts, jHwRop); CP_IO_SRC_ADDR(ppdev, pjPorts, ppdev->ulSolidColorOffset); CP_IO_DST_Y_OFFSET(ppdev, pjPorts, ppdev->lDelta); CP_IO_BLT_MODE(ppdev, pjPorts, jMode); CP_IO_FG_COLOR(ppdev, pjPorts, ulSolidColor); } } fl = 0; // Look after styling initialization: if (pla->fl & LA_ALTERNATE) { ls.cStyle = 1; ls.spTotal = 1; ls.spTotal2 = 2; ls.spRemaining = 1; ls.aspRtoL = &gaspAlternateStyle[0]; ls.aspLtoR = &gaspAlternateStyle[0]; ls.spNext = HIWORD(pla->elStyleState.l); ls.xyDensity = 1; fl |= FL_STYLED; ls.ulStartMask = 0L; } else if (pla->pstyle != (FLOAT_LONG*) NULL) { PFLOAT_LONG pstyle; STYLEPOS* pspDown; STYLEPOS* pspUp; pstyle = &pla->pstyle[pla->cstyle]; ls.xyDensity = STYLE_DENSITY; ls.spTotal = 0; while (pstyle-- > pla->pstyle) { ls.spTotal += pstyle->l; } ls.spTotal *= STYLE_DENSITY; ls.spTotal2 = 2 * ls.spTotal; // Compute starting style position (this is guaranteed not to overflow): ls.spNext = HIWORD(pla->elStyleState.l) * STYLE_DENSITY + LOWORD(pla->elStyleState.l); fl |= FL_STYLED; ls.cStyle = pla->cstyle; ls.aspRtoL = aspRtoL; ls.aspLtoR = aspLtoR; if (pla->fl & LA_STARTGAP) ls.ulStartMask = 0xffffffffL; else ls.ulStartMask = 0L; pstyle = pla->pstyle; pspDown = &ls.aspRtoL[ls.cStyle - 1]; pspUp = &ls.aspLtoR[0]; while (pspDown >= &ls.aspRtoL[0]) { *pspDown = pstyle->l * STYLE_DENSITY; *pspUp = *pspDown; pspUp++; pspDown--; pstyle++; } } // chu01 if ((ppdev->flCaps & CAPS_COMMAND_LIST) && (ppdev->pCommandList != NULL)) { apfn = &gapfnPackedStripMm[NUM_STRIP_DRAW_STYLES * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT)]; } else if (ppdev->flCaps & CAPS_MM_IO) { apfn = &gapfnStripMm[NUM_STRIP_DRAW_STYLES * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT)]; } else { apfn = &gapfnStripIo[NUM_STRIP_DRAW_STYLES * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT)]; } // Set up to enumerate the path: if (pco->iDComplexity != DC_COMPLEX) { PATHDATA pd; RECTL* prclClip = (RECTL*) NULL; BOOL bMore; ULONG cptfx; POINTFIX ptfxStartFigure; POINTFIX ptfxLast; POINTFIX* pptfxFirst; POINTFIX* pptfxBuf; if (pco->iDComplexity == DC_RECT) { fl |= FL_SIMPLE_CLIP; arclClip[0] = pco->rclBounds; // FL_FLIP_D: arclClip[1].top = pco->rclBounds.left; arclClip[1].left = pco->rclBounds.top; arclClip[1].bottom = pco->rclBounds.right; arclClip[1].right = pco->rclBounds.bottom; // FL_FLIP_V: arclClip[2].top = -pco->rclBounds.bottom + 1; arclClip[2].left = pco->rclBounds.left; arclClip[2].bottom = -pco->rclBounds.top + 1; arclClip[2].right = pco->rclBounds.right; // FL_FLIP_V | FL_FLIP_D: arclClip[3].top = pco->rclBounds.left; arclClip[3].left = -pco->rclBounds.bottom + 1; arclClip[3].bottom = pco->rclBounds.right; arclClip[3].right = -pco->rclBounds.top + 1; prclClip = arclClip; } pd.flags = 0; PATHOBJ_vEnumStart(ppo); do { bMore = PATHOBJ_bEnum(ppo, &pd); cptfx = pd.count; if (cptfx == 0) { break; } if (pd.flags & PD_BEGINSUBPATH) { ptfxStartFigure = *pd.pptfx; pptfxFirst = pd.pptfx; pptfxBuf = pd.pptfx + 1; cptfx--; } else { pptfxFirst = &ptfxLast; pptfxBuf = pd.pptfx; } if (pd.flags & PD_RESETSTYLE) ls.spNext = 0; if (cptfx > 0) { if (!bLines(ppdev, pptfxFirst, pptfxBuf, (RUN*) NULL, cptfx, &ls, prclClip, apfn, fl)) goto ReturnFalse; } ptfxLast = pd.pptfx[pd.count - 1]; if (pd.flags & PD_CLOSEFIGURE) { if (!bLines(ppdev, &ptfxLast, &ptfxStartFigure, (RUN*) NULL, 1, &ls, prclClip, apfn, fl)) goto ReturnFalse; } } while (bMore); if (fl & FL_STYLED) { // Save the style state: ULONG ulHigh; ULONG ulLow; // Masked styles don't normalize the style state. It's a good // thing to do, so let's do it now: if ((ULONG) ls.spNext >= (ULONG) ls.spTotal2) ls.spNext = (ULONG) ls.spNext % (ULONG) ls.spTotal2; ulHigh = ls.spNext / ls.xyDensity; ulLow = ls.spNext % ls.xyDensity; pla->elStyleState.l = MAKELONG(ulLow, ulHigh); } } else { // Local state for path enumeration: BOOL bMore; union { BYTE aj[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)]; CLIPLINE cl; } cl; fl |= FL_COMPLEX_CLIP; // We use the clip object when non-simple clipping is involved: PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pla); do { bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl); if (cl.cl.c != 0) { if (fl & FL_STYLED) { ls.spComplex = HIWORD(cl.cl.lStyleState) * ls.xyDensity + LOWORD(cl.cl.lStyleState); } if (!bLines(ppdev, &cl.cl.ptfxA, &cl.cl.ptfxB, &cl.cl.arun[0], cl.cl.c, &ls, (RECTL*) NULL, apfn, fl)) goto ReturnFalse; } } while (bMore); } return(TRUE); ReturnFalse: return(FALSE); } BOOL bPuntStrokePath( SURFOBJ* pso, PATHOBJ* ppo, CLIPOBJ* pco, XFORMOBJ* pxo, BRUSHOBJ* pbo, POINTL* pptlBrush, LINEATTRS* pla, MIX mix) { PDEV* ppdev = (PDEV*) pso->dhpdev; BOOL b = TRUE; if (pso->iType == STYPE_BITMAP) { b = EngStrokePath(pso,ppo,pco,pxo,pbo, pptlBrush,pla,mix); goto ReturnStatus; } if (DIRECT_ACCESS(ppdev)) { ////////////////////////////////////////////////////////////////////// // Banked Framebuffer bPuntBlt // // This section of code handles a PuntBlt when GDI can directly draw // on the framebuffer, but the drawing has to be done in banks: BANK bnk; { ASSERTDD(pso->iType != STYPE_BITMAP, "Dest should be the screen"); // Do a memory-to-screen blt: if (ppdev->bLinearMode) { SURFOBJ* psoPunt = ppdev->psoPunt; OH* poh = ((DSURF*) pso->dhsurf)->poh; psoPunt->pvScan0 = poh->pvScan0; ppdev->pfnBankSelectMode(ppdev, BANK_ON); b = EngStrokePath(psoPunt,ppo,pco,pxo,pbo, pptlBrush,pla,mix); goto ReturnStatus; } { RECTL rclDraw; RECTL *prclDst = &pco->rclBounds; FLOAT_LONG elSavedStyleState = pla->elStyleState; { // The bank manager requires that the 'draw' rectangle be // well-ordered: rclDraw = *prclDst; if (rclDraw.left > rclDraw.right) { rclDraw.left = prclDst->right; rclDraw.right = prclDst->left; } if (rclDraw.top > rclDraw.bottom) { rclDraw.top = prclDst->bottom; rclDraw.bottom = prclDst->top; } vBankStart(ppdev, &rclDraw, pco, &bnk); b = TRUE; do { pla->elStyleState = elSavedStyleState; b &= EngStrokePath(bnk.pso, ppo, bnk.pco, pxo, pbo, pptlBrush, pla, mix); } while (bBankEnum(&bnk)); } } } goto ReturnStatus; } else { ////////////////////////////////////////////////////////////////////// // Really Slow bPuntStrokePath // // Here we handle a bPuntStrokePath when GDI can't draw directly on the // framebuffer (as on the Alpha, which can't do it because of its // 32 bit bus). If you thought the banked version was slow, just // look at this one. Guaranteed, there will one bitmap // allocation and extra copy involved RECTL rclDst; RECTFX rcfxBounds; SIZEL sizl; LONG lDelta; BYTE* pjBits; BYTE* pjScan0; HSURF hsurfDst; RECTL rclScreen; PATHOBJ_vGetBounds(ppo, &rcfxBounds); rclDst.left = (rcfxBounds.xLeft >> 4); rclDst.top = (rcfxBounds.yTop >> 4); rclDst.right = (rcfxBounds.xRight >> 4) + 2; rclDst.bottom = (rcfxBounds.yBottom >> 4) + 2; // // This function is guarenteed to get a clip object. Since the // rounding of the above calculation can give us a rectangle // outside the screen area, we must clip to the drawing area. // { ASSERTDD(pco != NULL, "clip object pointer is NULL"); // We have to intersect the destination rectangle with // the clip bounds if there is one (consider the case // where the app asked to blt a really, really big // rectangle from the screen -- prclDst would be really, // really big but pco->rclBounds would be the actual // area of interest): rclDst.left = max(rclDst.left, pco->rclBounds.left); rclDst.top = max(rclDst.top, pco->rclBounds.top); rclDst.right = min(rclDst.right, pco->rclBounds.right); rclDst.bottom = min(rclDst.bottom, pco->rclBounds.bottom); } sizl.cx = rclDst.right - rclDst.left; sizl.cy = rclDst.bottom - rclDst.top; // We need to create a temporary work buffer. We have to do // some fudging with the offsets so that the upper-left corner // of the (relative coordinates) clip object bounds passed to // GDI will be transformed to the upper-left corner of our // temporary bitmap. // The alignment doesn't have to be as tight as this at 16bpp // and 32bpp, but it won't hurt: lDelta = PELS_TO_BYTES(((rclDst.right + 3) & ~3L) - (rclDst.left & ~3L)); // We're actually only allocating a bitmap that is 'sizl.cx' x // 'sizl.cy' in size: pjBits = ALLOC(lDelta * sizl.cy); if (pjBits == NULL) goto ReturnStatus; // We now adjust the surface's 'pvScan0' so that when GDI thinks // it's writing to pixel (rclDst.top, rclDst.left), it will // actually be writing to the upper-left pixel of our temporary // bitmap: pjScan0 = pjBits - (rclDst.top * lDelta) - PELS_TO_BYTES(rclDst.left & ~3L); ASSERTDD((((ULONG_PTR) pjScan0) & 3) == 0, "pvScan0 must be dword aligned!"); // The checked build of GDI sometimes checks on blts that // prclDst->right <= pso->sizl.cx, so we lie to it about // the size of our bitmap: sizl.cx = rclDst.right; sizl.cy = rclDst.bottom; hsurfDst = (HSURF) EngCreateBitmap( sizl, // Bitmap covers rectangle lDelta, // Use this delta ppdev->iBitmapFormat, // Same colour depth BMF_TOPDOWN, // Must have a positive delta NULL); //pjScan0); // Where (0, 0) would be if ((hsurfDst == 0) || (!EngAssociateSurface(hsurfDst, ppdev->hdevEng, 0))) { DISPDBG((0,"bPuntStrokePath - EngCreateBitmap or " "EngAssociateSurface failed")); goto Error_3; } pso = EngLockSurface(hsurfDst); if (pso == NULL) { DISPDBG((0,"bPuntStrokePath - EngLockSurface failed")); goto Error_4; } // Make sure that the rectangle we Get/Put from/to the screen // is in absolute coordinates: rclScreen.left = rclDst.left + ppdev->xOffset; rclScreen.right = rclDst.right + ppdev->xOffset; rclScreen.top = rclDst.top + ppdev->yOffset; rclScreen.bottom = rclDst.bottom + ppdev->yOffset; // It would be nice to get a copy of the destination rectangle // only when the ROP involves the destination (or when the source // is an RLE), but we can't do that. If the brush is truly NULL, // GDI will immediately return TRUE from EngBitBlt, without // modifying the temporary bitmap -- and we would proceed to // copy the uninitialized temporary bitmap back to the screen. ppdev->pfnGetBits(ppdev, pso, &rclDst, (POINTL*) &rclScreen); b = EngStrokePath(pso,ppo,pco,pxo,pbo, pptlBrush,pla,mix); ppdev->pfnPutBits(ppdev, pso, &rclScreen, (POINTL*) &rclDst); EngUnlockSurface(pso); Error_4: EngDeleteSurface(hsurfDst); Error_3: FREE(pjBits); } ReturnStatus: return(b); }