/* * Id: s3draw.c,v 1.1 1999/11/02 03:54:47 keithp Exp $ * * Copyright 1999 SuSE, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of SuSE not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. SuSE makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Keith Packard, SuSE, Inc. */ /* $XFree86: xc/programs/Xserver/hw/kdrive/savage/s3draw.c,v 1.6 2001/05/29 04:54:11 keithp Exp $ */ #include "s3.h" #include "s3draw.h" #include "Xmd.h" #include "gcstruct.h" #include "scrnintstr.h" #include "pixmapstr.h" #include "regionstr.h" #include "mistruct.h" #include "fontstruct.h" #include "dixfontstr.h" #include "fb.h" #include "migc.h" #include "miline.h" /* * Map X rops to S3 rops */ short s3alu[16] = { MIX_0, MIX_AND, MIX_SRC_AND_NOT_DST, MIX_SRC, MIX_NOT_SRC_AND_DST, MIX_DST, MIX_XOR, MIX_OR, MIX_NOR, MIX_XNOR, MIX_NOT_DST, MIX_SRC_OR_NOT_DST, MIX_NOT_SRC, MIX_NOT_SRC_OR_DST, MIX_NAND, MIX_1 }; /* * Handle pixel transfers */ #define BURST #ifdef BURST #define PixTransDeclare VOL32 *pix_trans_base = (VOL32 *) (s3c->registers),\ *pix_trans = pix_trans_base #define PixTransStart(n) if (pix_trans + (n) > pix_trans_base + 8192) pix_trans = pix_trans_base #define PixTransStore(t) *pix_trans++ = (t) #else #define PixTransDeclare VOL32 *pix_trans = &s3->pix_trans #define PixTransStart(n) #define PixTransStore(t) *pix_trans = (t) #endif int s3GCPrivateIndex; int s3WindowPrivateIndex; int s3Generation; /* s3DoBitBlt ============= Bit Blit for all window to window blits. */ #define sourceInvarient(alu) (((alu) & 3) == (((alu) >> 2) & 3)) void s3CopyNtoN (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { SetupS3(pDstDrawable->pScreen); int srcX, srcY, dstX, dstY; int w, h; int flags; if (sourceInvarient (pGC->alu)) { s3FillBoxSolid (pDstDrawable, nbox, pbox, 0, pGC->alu, pGC->planemask); return; } s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC)); _s3SetBlt(s3,pGC->alu,pGC->planemask); DRAW_DEBUG ((DEBUG_RENDER, "s3CopyNtoN alu %d planemask 0x%x", pGC->alu, pGC->planemask)); while (nbox--) { w = pbox->x2 - pbox->x1; h = pbox->y2 - pbox->y1; flags = 0; if (reverse) { dstX = pbox->x2 - 1; } else { dstX = pbox->x1; flags |= INC_X; } srcX = dstX + dx; if (upsidedown) { dstY = pbox->y2 - 1; } else { dstY = pbox->y1; flags |= INC_Y; } srcY = dstY + dy; _s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags); pbox++; } MarkSyncS3 (pSrcDrawable->pScreen); } RegionPtr s3CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, int srcx, int srcy, int width, int height, int dstx, int dsty) { SetupS3(pDstDrawable->pScreen); if (pSrcDrawable->type == DRAWABLE_WINDOW && pDstDrawable->type == DRAWABLE_WINDOW) { return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, s3CopyNtoN, 0, 0); } return KdCheckCopyArea (pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty); } typedef struct _s31toNargs { unsigned long copyPlaneFG, copyPlaneBG; Bool opaque; } s31toNargs; void _s3Stipple (S3CardInfo *s3c, FbStip *psrcBase, FbStride widthSrc, int srcx, int srcy, int dstx, int dsty, int width, int height) { S3Ptr s3 = s3c->s3; FbStip *psrcLine, *psrc; FbStride widthRest; FbStip bits, tmp, lastTmp; int leftShift, rightShift; int nl, nlMiddle; int r; PixTransDeclare; /* Compute blt address and parameters */ psrc = psrcBase + srcy * widthSrc + (srcx >> 5); nlMiddle = (width + 31) >> 5; leftShift = srcx & 0x1f; rightShift = 32 - leftShift; widthRest = widthSrc - nlMiddle; _s3PlaneBlt(s3,dstx,dsty,width,height); if (leftShift == 0) { while (height--) { nl = nlMiddle; PixTransStart(nl); while (nl--) { tmp = *psrc++; S3AdjustBits32 (tmp); PixTransStore (tmp); } psrc += widthRest; } } else { widthRest--; while (height--) { bits = *psrc++; nl = nlMiddle; PixTransStart(nl); while (nl--) { tmp = FbStipLeft(bits, leftShift); bits = *psrc++; tmp |= FbStipRight(bits, rightShift); S3AdjustBits32(tmp); PixTransStore (tmp); } psrc += widthRest; } } } void s3Copy1toN (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { SetupS3(pDstDrawable->pScreen); s31toNargs *args = closure; int dstx, dsty; FbStip *psrcBase; FbStride widthSrc; int srcBpp; int srcXoff, srcYoff; if (args->opaque && sourceInvarient (pGC->alu)) { s3FillBoxSolid (pDstDrawable, nbox, pbox, pGC->bgPixel, pGC->alu, pGC->planemask); return; } s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC)); fbGetStipDrawable (pSrcDrawable, psrcBase, widthSrc, srcBpp, srcXoff, srcYoff); if (args->opaque) { _s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,args->copyPlaneFG, args->copyPlaneBG); } else { _s3SetTransparentPlaneBlt (s3, pGC->alu, pGC->planemask, args->copyPlaneFG); } while (nbox--) { dstx = pbox->x1; dsty = pbox->y1; _s3Stipple (s3c, psrcBase, widthSrc, dstx + dx - srcXoff, dsty + dy - srcYoff, dstx, dsty, pbox->x2 - dstx, pbox->y2 - dsty); pbox++; } MarkSyncS3 (pDstDrawable->pScreen); } RegionPtr s3CopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, int srcx, int srcy, int width, int height, int dstx, int dsty, unsigned long bitPlane) { SetupS3 (pDstDrawable->pScreen); RegionPtr ret; s31toNargs args; if (pDstDrawable->type == DRAWABLE_WINDOW && pSrcDrawable->depth == 1) { args.copyPlaneFG = pGC->fgPixel; args.copyPlaneBG = pGC->bgPixel; args.opaque = TRUE; return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, s3Copy1toN, bitPlane, &args); } return KdCheckCopyPlane(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); } void s3PushPixels (GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, int w, int h, int x, int y) { SetupS3 (pDrawable->pScreen); s31toNargs args; if (pDrawable->type == DRAWABLE_WINDOW && pGC->fillStyle == FillSolid) { args.opaque = FALSE; args.copyPlaneFG = pGC->fgPixel; (void) fbDoCopy ((DrawablePtr) pBitmap, pDrawable, pGC, 0, 0, w, h, x, y, s3Copy1toN, 1, &args); } else { KdCheckPushPixels (pGC, pBitmap, pDrawable, w, h, x, y); } } void s3FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox, unsigned long pixel, int alu, unsigned long planemask) { SetupS3(pDrawable->pScreen); register int r; s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable)); _s3SetSolidFill(s3,pixel,alu,planemask); while (nBox--) { _s3SolidRect(s3,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1); pBox++; } MarkSyncS3 (pDrawable->pScreen); } void _s3SetPattern (ScreenPtr pScreen, int ma, int alu, unsigned long planemask, s3PatternPtr pPattern) { SetupS3(pScreen); S3PatternCache *cache; _s3LoadPattern (pScreen, ma, pPattern); cache = pPattern->cache; switch (pPattern->fillStyle) { case FillTiled: _s3SetTile(s3,alu,planemask); break; case FillStippled: _s3SetStipple(s3,alu,planemask,pPattern->fore); break; case FillOpaqueStippled: _s3SetOpaqueStipple(s3,alu,planemask,pPattern->fore,pPattern->back); break; } } void s3FillBoxPattern (DrawablePtr pDrawable, int nBox, BoxPtr pBox, int alu, unsigned long planemask, s3PatternPtr pPattern) { SetupS3(pDrawable->pScreen); S3PatternCache *cache; int patx, paty; s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable)); _s3SetPattern (pDrawable->pScreen, s3DrawMap(pDrawable), alu, planemask, pPattern); cache = pPattern->cache; while (nBox--) { _s3PatRect(s3,cache->x, cache->y, pBox->x1, pBox->y1, pBox->x2-pBox->x1, pBox->y2-pBox->y1); pBox++; } MarkSyncS3 (pDrawable->pScreen); } void s3FillBoxLargeStipple (DrawablePtr pDrawable, GCPtr pGC, int nBox, BoxPtr pBox) { SetupS3(pDrawable->pScreen); DrawablePtr pStipple = &pGC->stipple->drawable; int xRot = pGC->patOrg.x + pDrawable->x; int yRot = pGC->patOrg.y + pDrawable->y; FbStip *stip; FbStride stipStride; int stipBpp; int stipXoff, stipYoff; int stipWidth, stipHeight; int dstX, dstY, width, height; stipWidth = pStipple->width; stipHeight = pStipple->height; fbGetStipDrawable (pStipple, stip, stipStride, stipBpp, stipXoff, stipYoff); s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable)); if (pGC->fillStyle == FillOpaqueStippled) { _s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel, pGC->bgPixel); } else { _s3SetTransparentPlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel); } while (nBox--) { int stipX, stipY, sx; int widthTmp; int h, w; int x, y; dstX = pBox->x1; dstY = pBox->y1; width = pBox->x2 - pBox->x1; height = pBox->y2 - pBox->y1; pBox++; modulus (dstY - yRot - stipYoff, stipHeight, stipY); modulus (dstX - xRot - stipXoff, stipWidth, stipX); y = dstY; while (height) { h = stipHeight - stipY; if (h > height) h = height; height -= h; widthTmp = width; x = dstX; sx = stipX; while (widthTmp) { w = (stipWidth - sx); if (w > widthTmp) w = widthTmp; widthTmp -= w; _s3Stipple (s3c, stip, stipStride, sx, stipY, x, y, w, h); x += w; sx = 0; } y += h; stipY = 0; } } MarkSyncS3 (pDrawable->pScreen); } #define NUM_STACK_RECTS 1024 void s3PolyFillRect (DrawablePtr pDrawable, GCPtr pGC, int nrectFill, xRectangle *prectInit) { s3GCPrivate(pGC); xRectangle *prect; RegionPtr prgnClip; register BoxPtr pbox; register BoxPtr pboxClipped; BoxPtr pboxClippedBase; BoxPtr pextent; BoxRec stackRects[NUM_STACK_RECTS]; int numRects; int n; int xorg, yorg; int x, y; prgnClip = fbGetCompositeClip(pGC); xorg = pDrawable->x; yorg = pDrawable->y; if (xorg || yorg) { prect = prectInit; n = nrectFill; while(n--) { prect->x += xorg; prect->y += yorg; prect++; } } prect = prectInit; numRects = REGION_NUM_RECTS(prgnClip) * nrectFill; if (numRects > NUM_STACK_RECTS) { pboxClippedBase = (BoxPtr)ALLOCATE_LOCAL(numRects * sizeof(BoxRec)); if (!pboxClippedBase) return; } else pboxClippedBase = stackRects; pboxClipped = pboxClippedBase; if (REGION_NUM_RECTS(prgnClip) == 1) { int x1, y1, x2, y2, bx2, by2; pextent = REGION_RECTS(prgnClip); x1 = pextent->x1; y1 = pextent->y1; x2 = pextent->x2; y2 = pextent->y2; while (nrectFill--) { if ((pboxClipped->x1 = prect->x) < x1) pboxClipped->x1 = x1; if ((pboxClipped->y1 = prect->y) < y1) pboxClipped->y1 = y1; bx2 = (int) prect->x + (int) prect->width; if (bx2 > x2) bx2 = x2; pboxClipped->x2 = bx2; by2 = (int) prect->y + (int) prect->height; if (by2 > y2) by2 = y2; pboxClipped->y2 = by2; prect++; if ((pboxClipped->x1 < pboxClipped->x2) && (pboxClipped->y1 < pboxClipped->y2)) { pboxClipped++; } } } else { int x1, y1, x2, y2, bx2, by2; pextent = REGION_EXTENTS(pGC->pScreen, prgnClip); x1 = pextent->x1; y1 = pextent->y1; x2 = pextent->x2; y2 = pextent->y2; while (nrectFill--) { BoxRec box; if ((box.x1 = prect->x) < x1) box.x1 = x1; if ((box.y1 = prect->y) < y1) box.y1 = y1; bx2 = (int) prect->x + (int) prect->width; if (bx2 > x2) bx2 = x2; box.x2 = bx2; by2 = (int) prect->y + (int) prect->height; if (by2 > y2) by2 = y2; box.y2 = by2; prect++; if ((box.x1 >= box.x2) || (box.y1 >= box.y2)) continue; n = REGION_NUM_RECTS (prgnClip); pbox = REGION_RECTS(prgnClip); /* clip the rectangle to each box in the clip region this is logically equivalent to calling Intersect() */ while(n--) { pboxClipped->x1 = max(box.x1, pbox->x1); pboxClipped->y1 = max(box.y1, pbox->y1); pboxClipped->x2 = min(box.x2, pbox->x2); pboxClipped->y2 = min(box.y2, pbox->y2); pbox++; /* see if clipping left anything */ if(pboxClipped->x1 < pboxClipped->x2 && pboxClipped->y1 < pboxClipped->y2) { pboxClipped++; } } } } if (pboxClipped != pboxClippedBase) { if (pGC->fillStyle == FillSolid) s3FillBoxSolid(pDrawable, pboxClipped-pboxClippedBase, pboxClippedBase, pGC->fgPixel, pGC->alu, pGC->planemask); else if (s3Priv->pPattern) s3FillBoxPattern (pDrawable, pboxClipped-pboxClippedBase, pboxClippedBase, pGC->alu, pGC->planemask, s3Priv->pPattern); else s3FillBoxLargeStipple (pDrawable, pGC, pboxClipped-pboxClippedBase, pboxClippedBase); } if (pboxClippedBase != stackRects) DEALLOCATE_LOCAL(pboxClippedBase); } void _s3FillSpanLargeStipple (DrawablePtr pDrawable, GCPtr pGC, int n, DDXPointPtr ppt, int *pwidth) { SetupS3 (pDrawable->pScreen); DrawablePtr pStipple = &pGC->stipple->drawable; int xRot = pGC->patOrg.x + pDrawable->x; int yRot = pGC->patOrg.y + pDrawable->y; FbStip *stip; FbStride stipStride; int stipBpp; int stipXoff, stipYoff; int stipWidth, stipHeight; int dstX, dstY, width, height; s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); stipWidth = pStipple->width; stipHeight = pStipple->height; fbGetStipDrawable (pStipple, stip, stipStride, stipBpp, stipXoff, stipYoff); if (pGC->fillStyle == FillOpaqueStippled) { _s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel, pGC->bgPixel); } else { _s3SetTransparentPlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel); } while (n--) { int stipX, stipY, sx; int w; int x, y; dstX = ppt->x; dstY = ppt->y; ppt++; width = *pwidth++; modulus (dstY - yRot - stipYoff, stipHeight, stipY); modulus (dstX - xRot - stipXoff, stipWidth, stipX); y = dstY; x = dstX; sx = stipX; while (width) { w = (stipWidth - sx); if (w > width) w = width; width -= w; _s3Stipple (s3c, stip, stipStride, sx, stipY, x, y, w, 1); x += w; sx = 0; } } } void s3FillSpans (DrawablePtr pDrawable, GCPtr pGC, int n, DDXPointPtr ppt, int *pwidth, int fSorted) { s3GCPrivate(pGC); SetupS3(pDrawable->pScreen); int x, y, x1, y1, x2, y2; int width; /* next three parameters are post-clip */ int nTmp; int *pwidthFree;/* copies of the pointers to free */ DDXPointPtr pptFree; BoxPtr extents; S3PatternCache *cache; RegionPtr pClip = fbGetCompositeClip (pGC); s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); if (REGION_NUM_RECTS(pClip) == 1 && (pGC->fillStyle == FillSolid || s3Priv->pPattern)) { extents = REGION_RECTS(pClip); x1 = extents->x1; x2 = extents->x2; y1 = extents->y1; y2 = extents->y2; if (pGC->fillStyle == FillSolid) { _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask); cache = 0; } else { _s3SetPattern (pDrawable->pScreen, s3GCMap(pGC), pGC->alu, pGC->planemask, s3Priv->pPattern); cache = s3Priv->pPattern->cache; } while (n--) { y = ppt->y; if (y1 <= y && y < y2) { x = ppt->x; width = *pwidth; if (x < x1) { width -= (x1 - x); x = x1; } if (x2 < x + width) width = x2 - x; if (width > 0) { if (cache) { _s3PatRect(s3, cache->x, cache->y, x, y, width, 1); } else { _s3SolidRect(s3,x,y,width,1); } } } ppt++; pwidth++; } } else { nTmp = n * miFindMaxBand(pClip); pwidthFree = (int *)ALLOCATE_LOCAL(nTmp * sizeof(int)); pptFree = (DDXPointRec *)ALLOCATE_LOCAL(nTmp * sizeof(DDXPointRec)); if(!pptFree || !pwidthFree) { if (pptFree) DEALLOCATE_LOCAL(pptFree); if (pwidthFree) DEALLOCATE_LOCAL(pwidthFree); return; } n = miClipSpans(fbGetCompositeClip(pGC), ppt, pwidth, n, pptFree, pwidthFree, fSorted); pwidth = pwidthFree; ppt = pptFree; if (pGC->fillStyle == FillSolid) { _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask); while (n--) { x = ppt->x; y = ppt->y; ppt++; width = *pwidth++; if (width) { _s3SolidRect(s3,x,y,width,1); } } } else if (s3Priv->pPattern) { _s3SetPattern (pDrawable->pScreen, s3GCMap(pGC), pGC->alu, pGC->planemask, s3Priv->pPattern); cache = s3Priv->pPattern->cache; while (n--) { x = ppt->x; y = ppt->y; ppt++; width = *pwidth++; if (width) { _s3PatRect(s3, cache->x, cache->y, x, y, width, 1); } } } else { _s3FillSpanLargeStipple (pDrawable, pGC, n, ppt, pwidth); } DEALLOCATE_LOCAL(pptFree); DEALLOCATE_LOCAL(pwidthFree); } MarkSyncS3 (pDrawable->pScreen); } #include "mifillarc.h" #define FILLSPAN(s3,y,__x1,__x2) {\ DRAW_DEBUG ((DEBUG_ARCS, "FILLSPAN %d: %d->%d", y, __x1, __x2)); \ if ((__x2) >= (__x1)) {\ _s3SolidRect(s3,(__x1),(y),(__x2)-(__x1)+1,1); \ } \ } #define FILLSLICESPANS(flip,__y) \ if (!flip) \ { \ FILLSPAN(s3,__y,xl,xr) \ } \ else \ { \ xc = xorg - x; \ FILLSPAN(s3, __y, xc, xr) \ xc += slw - 1; \ FILLSPAN(s3, __y, xl, xc) \ } static void _s3FillEllipse (DrawablePtr pDraw, S3Ptr s3, xArc *arc) { KdScreenPriv(pDraw->pScreen); int x, y, e; int yk, xk, ym, xm, dx, dy, xorg, yorg; int y_top, y_bot; miFillArcRec info; register int xpos; int slw; s3SetGlobalBitmap (pDraw->pScreen, s3DrawMap (pDraw)); miFillArcSetup(arc, &info); MIFILLARCSETUP(); y_top = pDraw->y + yorg - y; y_bot = pDraw->y + yorg + y + dy; xorg += pDraw->x; while (y) { y_top++; y_bot--; MIFILLARCSTEP(slw); if (!slw) continue; xpos = xorg - x; _s3SolidRect (s3,xpos,y_top,slw,1); if (miFillArcLower(slw)) _s3SolidRect (s3,xpos,y_bot,slw,1); } } static void _s3FillArcSlice (DrawablePtr pDraw, GCPtr pGC, S3Ptr s3, xArc *arc) { KdScreenPriv(pDraw->pScreen); int yk, xk, ym, xm, dx, dy, xorg, yorg, slw; register int x, y, e; miFillArcRec info; miArcSliceRec slice; int xl, xr, xc; int y_top, y_bot; s3SetGlobalBitmap (pDraw->pScreen, s3DrawMap (pDraw)); DRAW_DEBUG ((DEBUG_ARCS, "slice %dx%d+%d+%d %d->%d", arc->width, arc->height, arc->x, arc->y, arc->angle1, arc->angle2)); miFillArcSetup(arc, &info); miFillArcSliceSetup(arc, &slice, pGC); DRAW_DEBUG ((DEBUG_ARCS, "edge1.x %d edge2.x %d", slice.edge1.x, slice.edge2.x)); MIFILLARCSETUP(); DRAW_DEBUG ((DEBUG_ARCS, "xorg %d yorg %d", xorg, yorg)); xorg += pDraw->x; yorg += pDraw->y; y_top = yorg - y; y_bot = yorg + y + dy; slice.edge1.x += pDraw->x; slice.edge2.x += pDraw->x; DRAW_DEBUG ((DEBUG_ARCS, "xorg %d y_top %d y_bot %d", xorg, y_top, y_bot)); while (y > 0) { y_top++; y_bot--; MIFILLARCSTEP(slw); MIARCSLICESTEP(slice.edge1); MIARCSLICESTEP(slice.edge2); if (miFillSliceUpper(slice)) { MIARCSLICEUPPER(xl, xr, slice, slw); FILLSLICESPANS(slice.flip_top, y_top); } if (miFillSliceLower(slice)) { MIARCSLICELOWER(xl, xr, slice, slw); FILLSLICESPANS(slice.flip_bot, y_bot); } } } void s3PolyFillArcSolid (DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) { SetupS3(pDraw->pScreen); xArc *arc; int i; int x, y; BoxRec box; RegionPtr pClip = fbGetCompositeClip(pGC); BOOL set; set = FALSE; for (; --narcs >= 0; parcs++) { if (miFillArcEmpty(parcs)) continue; if (miCanFillArc(parcs)) { box.x1 = parcs->x + pDraw->x; box.y1 = parcs->y + pDraw->y; box.x2 = box.x1 + (int)parcs->width + 1; box.y2 = box.y1 + (int)parcs->height + 1; switch (RECT_IN_REGION(pDraw->pScreen, pClip, &box)) { case rgnIN: if (!set) { _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask); set = TRUE; } if ((parcs->angle2 >= FULLCIRCLE) || (parcs->angle2 <= -FULLCIRCLE)) { DRAW_DEBUG ((DEBUG_ARCS, "Full circle ellipse %dx%d", parcs->width, parcs->height)); _s3FillEllipse (pDraw, s3, parcs); } else { DRAW_DEBUG ((DEBUG_ARCS, "Partial ellipse %dx%d", parcs->width, parcs->height)); _s3FillArcSlice (pDraw, pGC, s3, parcs); } /* fall through ... */ case rgnOUT: continue; case rgnPART: break; } } if (set) { MarkSyncS3 (pDraw->pScreen); set = FALSE; } KdCheckPolyFillArc(pDraw, pGC, 1, parcs); } if (set) { MarkSyncS3 (pDraw->pScreen); set = FALSE; } } void s3FillPoly (DrawablePtr pDrawable, GCPtr pGC, int shape, int mode, int countInit, DDXPointPtr ptsIn) { SetupS3(pDrawable->pScreen); int nwidth; int maxy; int origin; int count; register int vertex1, vertex2; int c; RegionPtr pClip = fbGetCompositeClip(pGC); BoxPtr extents; int clip; int y, sy; int *vertex1p, *vertex2p; int *endp; int x1, x2, sx; int dx1, dx2; int dy1, dy2; int e1, e2; int step1, step2; int sign1, sign2; int h; int l, r; int nmiddle; if (mode == CoordModePrevious || REGION_NUM_RECTS(pClip) != 1) { KdCheckFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn); return; } s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); sy = pDrawable->y; sx = pDrawable->x; origin = *((int *) &pDrawable->x); origin -= (origin & 0x8000) << 1; extents = &pClip->extents; vertex1 = *((int *) &extents->x1) - origin; vertex2 = *((int *) &extents->x2) - origin - 0x00010001; clip = 0; y = 32767; maxy = 0; vertex2p = (int *) ptsIn; endp = vertex2p + countInit; if (shape == Convex) { count = countInit; while (count--) { c = *vertex2p; clip |= (c - vertex1) | (vertex2 - c); c = intToY(c); DRAW_DEBUG ((DEBUG_POLYGON, "Y coordinate %d", c)); if (c < y) { y = c; vertex1p = vertex2p; } vertex2p++; if (c > maxy) maxy = c; } } else { int yFlip = 0; dx1 = 1; x2 = -1; x1 = -1; count = countInit; while (count--) { c = *vertex2p; clip |= (c - vertex1) | (vertex2 - c); c = intToY(c); DRAW_DEBUG ((DEBUG_POLYGON, "Y coordinate %d", c)); if (c < y) { y = c; vertex1p = vertex2p; } vertex2p++; if (c > maxy) maxy = c; if (c == x1) continue; if (dx1 > 0) { if (x2 < 0) x2 = c; else dx2 = dx1 = (c - x1) >> 31; } else if ((c - x1) >> 31 != dx1) { dx1 = ~dx1; yFlip++; } x1 = c; } x1 = (x2 - c) >> 31; if (x1 != dx1) yFlip++; if (x1 != dx2) yFlip++; if (yFlip != 2) clip = 0x8000; } if (y == maxy) return; if (clip & 0x80008000) { KdCheckFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn); return; } _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask); vertex2p = vertex1p; vertex2 = vertex1 = *vertex2p++; if (vertex2p == endp) vertex2p = (int *) ptsIn; #define Setup(c,x,vertex,dx,dy,e,sign,step) {\ x = intToX(vertex); \ if (dy = intToY(c) - y) { \ dx = intToX(c) - x; \ step = 0; \ if (dx >= 0) \ { \ e = 0; \ sign = 1; \ if (dx >= dy) {\ step = dx / dy; \ dx = dx % dy; \ } \ } \ else \ { \ e = 1 - dy; \ sign = -1; \ dx = -dx; \ if (dx >= dy) { \ step = - (dx / dy); \ dx = dx % dy; \ } \ } \ } \ x += sx; \ vertex = c; \ } #define Step(x,dx,dy,e,sign,step) {\ x += step; \ if ((e += dx) > 0) \ { \ x += sign; \ e -= dy; \ } \ } sy += y; DRAW_DEBUG ((DEBUG_POLYGON, "Starting polygon at %d", sy)); for (;;) { DRAW_DEBUG ((DEBUG_POLYGON, "vertex1 0x%x vertex2 0x%x y %d vy1 %d vy2 %d", vertex1, vertex2, y, intToY(vertex1), intToY (vertex2))); if (y == intToY(vertex1)) { DRAW_DEBUG ((DEBUG_POLYGON, "Find next -- vertext")); do { if (vertex1p == (int *) ptsIn) vertex1p = endp; c = *--vertex1p; Setup (c,x1,vertex1,dx1,dy1,e1,sign1,step1); DRAW_DEBUG ((DEBUG_POLYGON, "-- vertex 0x%x y %d", vertex1, intToY(vertex1))); } while (y >= intToY(vertex1)); h = dy1; } else { Step(x1,dx1,dy1,e1,sign1,step1) h = intToY(vertex1) - y; } if (y == intToY(vertex2)) { DRAW_DEBUG ((DEBUG_POLYGON, "Find next ++ vertext")); do { c = *vertex2p++; if (vertex2p == endp) vertex2p = (int *) ptsIn; Setup (c,x2,vertex2,dx2,dy2,e2,sign2,step2) DRAW_DEBUG ((DEBUG_POLYGON, "++ vertex 0x%x y %d", vertex1, intToY(vertex1))); } while (y >= intToY(vertex2)); if (dy2 < h) h = dy2; } else { Step(x2,dx2,dy2,e2,sign2,step2) if ((c = (intToY(vertex2) - y)) < h) h = c; } DRAW_DEBUG ((DEBUG_POLYGON, "This band %d", h)); /* fill spans for this segment */ for (;;) { nmiddle = x2 - x1; DRAW_DEBUG ((DEBUG_POLYGON, "This span %d->%d", x1, x2)); if (nmiddle) { l = x1; if (nmiddle < 0) { nmiddle = -nmiddle; l = x2; } _s3SolidRect(s3,l,sy,nmiddle,1); } y++; sy++; if (!--h) break; Step(x1,dx1,dy1,e1,sign1,step1) Step(x2,dx2,dy2,e2,sign2,step2) } if (y == maxy) break; } MarkSyncS3 (pDrawable->pScreen); } void s3PolyGlyphBltClipped (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppciInit, pointer pglyphBase) { SetupS3(pDrawable->pScreen); int h; int w; int xBack, yBack; int hBack, wBack; int lw; FontPtr pfont = pGC->font; CharInfoPtr pci; unsigned long *bits; BoxPtr extents; BoxRec bbox; CARD32 b; CharInfoPtr *ppci; FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC); RegionPtr pClip = fbGetCompositeClip(pGC); BoxPtr pBox; int nbox; int x1, y1, x2, y2; unsigned char alu; Bool set; PixTransDeclare; s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); x += pDrawable->x; y += pDrawable->y; if (pglyphBase == (pointer) 1) { xBack = x; yBack = y - FONTASCENT(pGC->font); wBack = 0; hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); if (hBack) { h = nglyph; ppci = ppciInit; while (h--) wBack += (*ppci++)->metrics.characterWidth; } if (wBack < 0) { xBack = xBack + wBack; wBack = -wBack; } if (hBack < 0) { yBack = yBack + hBack; hBack = -hBack; } alu = GXcopy; } else { wBack = 0; alu = pGC->alu; } if (wBack) { _s3SetSolidFill (s3, pGC->bgPixel, GXcopy, pGC->planemask); for (nbox = REGION_NUM_RECTS (pClip), pBox = REGION_RECTS (pClip); nbox--; pBox++) { x1 = xBack; x2 = xBack + wBack; y1 = yBack; y2 = yBack + hBack; if (x1 < pBox->x1) x1 = pBox->x1; if (x2 > pBox->x2) x2 = pBox->x2; if (y1 < pBox->y1) y1 = pBox->y1; if (y2 > pBox->y2) y2 = pBox->y2; if (x1 < x2 && y1 < y2) { _s3SolidRect (s3, x1, y1, x2 - x1, y2 - y1); } } MarkSyncS3 (pDrawable->pScreen); } ppci = ppciInit; set = FALSE; while (nglyph--) { pci = *ppci++; h = pci->metrics.ascent + pci->metrics.descent; w = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing; x1 = x + pci->metrics.leftSideBearing; y1 = y - pci->metrics.ascent; bbox.x1 = x1; bbox.y1 = y1; bbox.x2 = x1 + w; bbox.y2 = y1 + h; switch (RECT_IN_REGION(pGC->pScreen, pClip, &bbox)) { case rgnIN: #if 1 lw = h * ((w + 31) >> 5); if (lw) { if (!set) { _s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel); set = TRUE; } _s3PlaneBlt(s3, x + pci->metrics.leftSideBearing, y - pci->metrics.ascent, w, h); bits = (unsigned long *) pci->bits; PixTransStart (lw); while (lw--) { b = *bits++; S3AdjustBits32 (b); PixTransStore(b); } MarkSyncS3 (pDrawable->pScreen); } break; #endif case rgnPART: set = FALSE; CheckSyncS3 (pDrawable->pScreen); fbPutXYImage (pDrawable, pClip, fbPriv->fg, fbPriv->bg, fbPriv->pm, alu, FALSE, x1, y1, w, h, (FbStip *) pci->bits, (w + 31) >> 5, 0); break; case rgnOUT: break; } x += pci->metrics.characterWidth; } } /* * Blt glyphs using S3 image transfer register, this does both * poly glyph blt and image glyph blt (when pglyphBase == 1) */ void s3PolyGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppciInit, pointer pglyphBase) { SetupS3(pDrawable->pScreen); int h; int w; int xBack, yBack; int hBack, wBack; int lw; FontPtr pfont = pGC->font; CharInfoPtr pci; unsigned long *bits; BoxPtr extents; BoxRec bbox; CARD32 b; CharInfoPtr *ppci; unsigned char alu; PixTransDeclare; s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); x += pDrawable->x; y += pDrawable->y; /* compute an approximate (but covering) bounding box */ ppci = ppciInit; w = 0; h = nglyph; while (h--) w += (*ppci++)->metrics.characterWidth; if (w < 0) { bbox.x1 = x + w; bbox.x2 = x; } else { bbox.x1 = x; bbox.x2 = x + w; } w = FONTMINBOUNDS(pfont,leftSideBearing); if (w < 0) bbox.x1 += w; w = FONTMAXBOUNDS(pfont, rightSideBearing) - FONTMINBOUNDS(pfont, characterWidth); if (w > 0) bbox.x2 += w; bbox.y1 = y - FONTMAXBOUNDS(pfont,ascent); bbox.y2 = y + FONTMAXBOUNDS(pfont,descent); DRAW_DEBUG ((DEBUG_TEXT, "PolyGlyphBlt %d box is %d %d", nglyph, bbox.x1, bbox.x2)); switch (RECT_IN_REGION(pGC->pScreen, fbGetCompositeClip(pGC), &bbox)) { case rgnIN: break; case rgnPART: s3PolyGlyphBltClipped(pDrawable, pGC, x - pDrawable->x, y - pDrawable->y, nglyph, ppciInit, pglyphBase); case rgnOUT: return; } if (pglyphBase == (pointer) 1) { xBack = x; yBack = y - FONTASCENT(pGC->font); wBack = 0; hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); if (hBack) { h = nglyph; ppci = ppciInit; while (h--) wBack += (*ppci++)->metrics.characterWidth; } if (wBack < 0) { xBack = xBack + wBack; wBack = -wBack; } if (hBack < 0) { yBack = yBack + hBack; hBack = -hBack; } alu = GXcopy; } else { wBack = 0; alu = pGC->alu; } if (wBack) { _s3SetSolidFill (s3, pGC->bgPixel, GXcopy, pGC->planemask); _s3SolidRect (s3, xBack, yBack, wBack, hBack); } _s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel); ppci = ppciInit; while (nglyph--) { pci = *ppci++; h = pci->metrics.ascent + pci->metrics.descent; w = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing; lw = h * ((w + 31) >> 5); if (lw) { _s3PlaneBlt(s3, x + pci->metrics.leftSideBearing, y - pci->metrics.ascent, w, h); bits = (unsigned long *) pci->bits; PixTransStart(lw); while (lw--) { b = *bits++; S3AdjustBits32 (b); PixTransStore(b); } } x += pci->metrics.characterWidth; } MarkSyncS3 (pDrawable->pScreen); } void s3ImageGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { s3PolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, (pointer) 1); } /* * Blt TE fonts using S3 image transfer. Differs from * above in that it doesn't need to fill a solid rect for * the background and it can draw multiple characters at a time */ void s3ImageTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int xInit, int yInit, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { SetupS3(pDrawable->pScreen); int x, y; int h, lw, lwTmp; int w; FontPtr pfont = pGC->font; unsigned long *char1, *char2, *char3, *char4; int widthGlyphs, widthGlyph; BoxRec bbox; CARD32 tmp; PixTransDeclare; s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); widthGlyph = FONTMAXBOUNDS(pfont,characterWidth); if (!widthGlyph) return; h = FONTASCENT(pfont) + FONTDESCENT(pfont); if (!h) return; DRAW_DEBUG ((DEBUG_TEXT, "ImageTEGlyphBlt chars are %d %d", widthGlyph, h)); x = xInit + FONTMAXBOUNDS(pfont,leftSideBearing) + pDrawable->x; y = yInit - FONTASCENT(pfont) + pDrawable->y; bbox.x1 = x; bbox.x2 = x + (widthGlyph * nglyph); bbox.y1 = y; bbox.y2 = y + h; switch (RECT_IN_REGION(pGC->pScreen, fbGetCompositeClip(pGC), &bbox)) { case rgnIN: break; case rgnPART: if (pglyphBase == (pointer) 1) pglyphBase = 0; else pglyphBase = (pointer) 1; s3PolyGlyphBltClipped(pDrawable, pGC, xInit, yInit, nglyph, ppci, pglyphBase); case rgnOUT: return; } if (pglyphBase == (pointer) 1) { _s3SetTransparentPlaneBlt (s3, pGC->alu, pGC->planemask, pGC->fgPixel); } else { _s3SetOpaquePlaneBlt (s3, GXcopy, pGC->planemask, pGC->fgPixel, pGC->bgPixel); } #if BITMAP_BIT_ORDER == LSBFirst #define SHIFT << #else #define SHIFT >> #endif #define LoopIt(count, w, loadup, fetch) \ while (nglyph >= count) \ { \ nglyph -= count; \ _s3PlaneBlt (s3, x, y, w, h); \ x += w; \ loadup \ lwTmp = h; \ PixTransStart(h); \ while (lwTmp--) { \ tmp = fetch; \ S3AdjustBits32(tmp); \ PixTransStore(tmp); \ } \ } if (widthGlyph <= 8) { widthGlyphs = widthGlyph << 2; LoopIt(4, widthGlyphs, char1 = (unsigned long *) (*ppci++)->bits; char2 = (unsigned long *) (*ppci++)->bits; char3 = (unsigned long *) (*ppci++)->bits; char4 = (unsigned long *) (*ppci++)->bits;, (*char1++ | ((*char2++ | ((*char3++ | (*char4++ SHIFT widthGlyph)) SHIFT widthGlyph)) SHIFT widthGlyph))) } else if (widthGlyph <= 10) { widthGlyphs = (widthGlyph << 1) + widthGlyph; LoopIt(3, widthGlyphs, char1 = (unsigned long *) (*ppci++)->bits; char2 = (unsigned long *) (*ppci++)->bits; char3 = (unsigned long *) (*ppci++)->bits;, (*char1++ | ((*char2++ | (*char3++ SHIFT widthGlyph)) SHIFT widthGlyph))) } else if (widthGlyph <= 16) { widthGlyphs = widthGlyph << 1; LoopIt(2, widthGlyphs, char1 = (unsigned long *) (*ppci++)->bits; char2 = (unsigned long *) (*ppci++)->bits;, (*char1++ | (*char2++ SHIFT widthGlyph))) } lw = h * ((widthGlyph + 31) >> 5); while (nglyph--) { _s3PlaneBlt (s3, x, y, widthGlyph, h); x += widthGlyph; char1 = (unsigned long *) (*ppci++)->bits; lwTmp = lw; PixTransStart(lw); while (lwTmp--) { tmp = *char1++; S3AdjustBits32(tmp); PixTransStore(tmp); } } MarkSyncS3 (pDrawable->pScreen); } void s3PolyTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { s3ImageTEGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, (pointer) 1); } Bool _s3Segment (DrawablePtr pDrawable, GCPtr pGC, int x1, int y1, int x2, int y2, Bool drawLast, Bool s3Set) { SetupS3(pDrawable->pScreen); FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); RegionPtr pClip = fbGetCompositeClip(pGC); BoxPtr pBox; int nBox; int adx; /* abs values of dx and dy */ int ady; int signdx; /* sign of dx and dy */ int signdy; int e, e1, e2; /* bresenham error and increments */ int len; /* length of segment */ int axis; /* major axis */ int octant; int cmd; unsigned int bias = miGetZeroLineBias(pDrawable->pScreen); unsigned int oc1; /* outcode of point 1 */ unsigned int oc2; /* outcode of point 2 */ CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant); cmd = LASTPIX; if (adx > ady) { axis = X_AXIS; e1 = ady << 1; e2 = e1 - (adx << 1); e = e1 - adx; len = adx; } else { cmd |= YMAJAXIS; axis = Y_AXIS; e1 = adx << 1; e2 = e1 - (ady << 1); e = e1 - ady; SetYMajorOctant(octant); len = ady; } /* S3 line drawing hardware has limited resolution for error terms */ if (len >= 4096) { int dashOff = 0; KdCheckSync (pDrawable->pScreen); fbSegment (pDrawable, pGC, x1, y1, x2, y2, drawLast, &dashOff); return FALSE; } FIXUP_ERROR (e, octant, bias); nBox = REGION_NUM_RECTS (pClip); pBox = REGION_RECTS (pClip); if (signdx > 0) cmd |= INC_X; if (signdy > 0) cmd |= INC_Y; /* we have bresenham parameters and two points. all we have to do now is clip and draw. */ if (drawLast) len++; while(nBox--) { oc1 = 0; oc2 = 0; OUTCODES(oc1, x1, y1, pBox); OUTCODES(oc2, x2, y2, pBox); if ((oc1 | oc2) == 0) { if (!s3Set) { s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask); s3Set = TRUE; } _s3SetCur (s3, x1, y1); _s3ClipLine (s3, cmd, e1, e2, e, len); break; } else if (oc1 & oc2) { pBox++; } else { int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2; int clip1 = 0, clip2 = 0; int clipdx, clipdy; int err; if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1, pBox->y2-1, &new_x1, &new_y1, &new_x2, &new_y2, adx, ady, &clip1, &clip2, octant, bias, oc1, oc2) == -1) { pBox++; continue; } if (axis == X_AXIS) len = abs(new_x2 - new_x1); else len = abs(new_y2 - new_y1); if (clip2 != 0 || drawLast) len++; if (len) { /* unwind bresenham error term to first point */ err = e; if (clip1) { clipdx = abs(new_x1 - x1); clipdy = abs(new_y1 - y1); if (axis == X_AXIS) err += (e2 - e1) * clipdy + e1 * clipdx; else err += (e2 - e1) * clipdx + e1 * clipdy; } if (!s3Set) { s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask); s3Set = TRUE; } _s3SetCur (s3, new_x1, new_y1); _s3ClipLine (s3, cmd, e1, e2, err, len); } pBox++; } } /* while (nBox--) */ return s3Set; } void s3Polylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { SetupS3(pDrawable->pScreen); int x, y, nx, ny; int ox = pDrawable->x, oy = pDrawable->y; Bool s3Set = FALSE; if (!npt) return; x = ppt->x + ox; y = ppt->y + oy; while (--npt) { ++ppt; if (mode == CoordModePrevious) { nx = x + ppt->x; ny = y + ppt->y; } else { nx = ppt->x + ox; ny = ppt->y + oy; } s3Set = _s3Segment (pDrawable, pGC, x, y, nx, ny, npt == 1 && pGC->capStyle != CapNotLast, s3Set); x = nx; y = ny; } if (s3Set) MarkSyncS3 (pDrawable->pScreen); } void s3PolySegment (DrawablePtr pDrawable, GCPtr pGC, int nsegInit, xSegment *pSegInit) { SetupS3(pDrawable->pScreen); int x, y; int ox = pDrawable->x, oy = pDrawable->y; RegionPtr pClip = fbGetCompositeClip (pGC); BoxPtr pBox; int nbox; int nseg; xSegment *pSeg; int dx, dy; int maj, min, len, inc; int t; CARD32 cmd; CARD32 init_cmd; Bool drawLast; Bool s3Set = FALSE; drawLast = pGC->capStyle != CapNotLast; for (nseg = nsegInit, pSeg = pSegInit; nseg--; pSeg++) { s3Set = _s3Segment (pDrawable, pGC, pSeg->x1 + ox, pSeg->y1 + oy, pSeg->x2 + ox, pSeg->y2 + oy, drawLast, s3Set); } if (s3Set) MarkSyncS3 (pDrawable->pScreen); } /* * Check to see if a pattern can be painted with the S3 */ #define _s3CheckPatternSize(s) ((s) <= S3_TILE_SIZE && ((s) & ((s) - 1)) == 0) #define s3CheckPattern(w,h) (_s3CheckPatternSize(w) && _s3CheckPatternSize(h)) Bool s3AllocPattern (ScreenPtr pScreen, int ma, PixmapPtr pPixmap, int xorg, int yorg, int fillStyle, Pixel fg, Pixel bg, s3PatternPtr *ppPattern) { KdScreenPriv(pScreen); s3ScreenInfo(pScreenPriv); s3PatternPtr pPattern; if (s3s->fb[ma].patterns.cache && fillStyle != FillSolid && s3CheckPattern (pPixmap->drawable.width, pPixmap->drawable.height)) { if (!(pPattern = *ppPattern)) { pPattern = (s3PatternPtr) xalloc (sizeof (s3PatternRec)); if (!pPattern) return FALSE; *ppPattern = pPattern; } pPattern->cache = 0; pPattern->id = 0; pPattern->pPixmap = pPixmap; pPattern->fillStyle = fillStyle; pPattern->xrot = (-xorg) & (S3_TILE_SIZE-1); pPattern->yrot = (-yorg) & (S3_TILE_SIZE-1); pPattern->fore = fg; pPattern->back = bg; return TRUE; } else { if (*ppPattern) { xfree (*ppPattern); *ppPattern = 0; } return FALSE; } } void s3CheckGCFill (GCPtr pGC) { s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC); PixmapPtr pPixmap; switch (pGC->fillStyle) { case FillSolid: pPixmap = 0; break; case FillOpaqueStippled: case FillStippled: pPixmap = pGC->stipple; break; case FillTiled: pPixmap = pGC->tile.pixmap; break; } s3AllocPattern (pGC->pScreen, s3GCMap(pGC), pPixmap, pGC->patOrg.x + pGC->lastWinOrg.x, pGC->patOrg.y + pGC->lastWinOrg.y, pGC->fillStyle, pGC->fgPixel, pGC->bgPixel, &s3Priv->pPattern); } void s3MoveGCFill (GCPtr pGC) { s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC); int xorg, yorg; s3PatternPtr pPattern; if (pPattern = s3Priv->pPattern) { /* * Reset origin */ xorg = pGC->patOrg.x + pGC->lastWinOrg.x; yorg = pGC->patOrg.y + pGC->lastWinOrg.y; pPattern->xrot = (-xorg) & (S3_TILE_SIZE - 1); pPattern->yrot = (-yorg) & (S3_TILE_SIZE - 1); /* * Invalidate cache entry */ pPattern->id = 0; pPattern->cache = 0; } } /* * S3 Patterns. These are always full-depth images, stored in off-screen * memory. */ Pixel s3FetchPatternPixel (s3PatternPtr pPattern, int x, int y) { CARD8 *src; CARD16 *src16; CARD32 *src32; PixmapPtr pPixmap = pPattern->pPixmap; x = (x + pPattern->xrot) % pPixmap->drawable.width; y = (y + pPattern->yrot) % pPixmap->drawable.height; src = (CARD8 *) pPixmap->devPrivate.ptr + y * pPixmap->devKind; switch (pPixmap->drawable.bitsPerPixel) { case 1: return (src[x>>3] >> (x & 7)) & 1 ? 0xffffffff : 0x00; case 4: if (x & 1) return src[x>>1] >> 4; else return src[x>>1] & 0xf; case 8: return src[x]; case 16: src16 = (CARD16 *) src; return src16[x]; case 32: src32 = (CARD32 *) src; return src32[x]; } } /* * Place pattern image on screen; done with S3 locked */ void _s3PutPattern (ScreenPtr pScreen, int ma, s3PatternPtr pPattern) { SetupS3(pScreen); s3ScreenInfo(pScreenPriv); int x, y; CARD8 *dstLine, *dst8; CARD16 *dst16; CARD32 *dst32; S3PatternCache *cache = pPattern->cache; #ifdef S3_TRIO int fb = 0; #else int fb = s3s->fbmap[ma]; #endif DRAW_DEBUG ((DEBUG_PATTERN, "_s3PutPattern 0x%x id %d to %d %d", pPattern, pPattern->id, cache->x, cache->y)); dstLine = (pScreenPriv->screen->fb[fb].frameBuffer + cache->y * pScreenPriv->screen->fb[fb].byteStride + cache->x * pScreenPriv->bytesPerPixel[fb]); CheckSyncS3 (pScreen); for (y = 0; y < S3_TILE_SIZE; y++) { switch (pScreenPriv->screen->fb[fb].bitsPerPixel) { case 8: dst8 = dstLine; for (x = 0; x < S3_TILE_SIZE; x++) *dst8++ = s3FetchPatternPixel (pPattern, x, y); DRAW_DEBUG ((DEBUG_PATTERN, "%c%c%c%c%c%c%c%c", dstLine[0] ? 'X' : ' ', dstLine[1] ? 'X' : ' ', dstLine[2] ? 'X' : ' ', dstLine[3] ? 'X' : ' ', dstLine[4] ? 'X' : ' ', dstLine[5] ? 'X' : ' ', dstLine[6] ? 'X' : ' ', dstLine[7] ? 'X' : ' ')); break; case 16: dst16 = (CARD16 *) dstLine; for (x = 0; x < S3_TILE_SIZE; x++) *dst16++ = s3FetchPatternPixel (pPattern, x, y); break; case 32: dst32 = (CARD32 *) dstLine; for (x = 0; x < S3_TILE_SIZE; x++) *dst32++ = s3FetchPatternPixel (pPattern, x, y); break; } dstLine += pScreenPriv->screen->fb[fb].byteStride; } } /* * Load a stipple to off-screen memory; done with S3 locked */ void _s3LoadPattern (ScreenPtr pScreen, int ma, s3PatternPtr pPattern) { SetupS3(pScreen); s3ScreenInfo(pScreenPriv); S3PatternCache *cache; DRAW_DEBUG((DEBUG_PATTERN, "s3LoadPattern 0x%x id %d cache 0x%x cacheid %d", pPattern, pPattern->id, pPattern->cache, pPattern->cache ? pPattern->cache->id : -1)); /* * Check to see if its still loaded */ cache = pPattern->cache; if (cache && cache->id == pPattern->id) return; /* * Lame replacement strategy; assume we'll have plenty of room. */ cache = &s3s->fb[ma].patterns.cache[s3s->fb[ma].patterns.last_used]; if (++s3s->fb[ma].patterns.last_used == s3s->fb[ma].patterns.ncache) s3s->fb[ma].patterns.last_used = 0; cache->id = ++s3s->fb[ma].patterns.last_id; pPattern->id = cache->id; pPattern->cache = cache; _s3PutPattern (pScreen, ma, pPattern); } void s3DestroyGC (GCPtr pGC) { s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC); if (s3Priv->pPattern) xfree (s3Priv->pPattern); miDestroyGC (pGC); } GCFuncs s3GCFuncs = { s3ValidateGC, miChangeGC, miCopyGC, s3DestroyGC, miChangeClip, miDestroyClip, miCopyClip }; int s3CreateGC (GCPtr pGC) { KdScreenPriv(pGC->pScreen); s3ScreenInfo(pScreenPriv); s3PrivGCPtr s3Priv; if (!fbCreateGC (pGC)) return FALSE; if (pGC->depth != 1) pGC->funcs = &s3GCFuncs; s3Priv = s3GetGCPrivate(pGC); s3Priv->type = DRAWABLE_PIXMAP; s3Priv->pPattern = 0; #ifndef S3_TRIO if (pGC->depth == s3s->primary_depth) s3Priv->ma = 0; else s3Priv->ma = 1; #endif return TRUE; } Bool s3CreateWindow (WindowPtr pWin) { KdScreenPriv(pWin->drawable.pScreen); s3ScreenInfo(pScreenPriv); pWin->devPrivates[s3WindowPrivateIndex].ptr = 0; return KdCreateWindow (pWin); } Bool s3DestroyWindow (WindowPtr pWin) { s3PatternPtr pPattern; if (pPattern = s3GetWindowPrivate(pWin)) xfree (pPattern); return fbDestroyWindow (pWin); } Bool s3ChangeWindowAttributes (WindowPtr pWin, Mask mask) { KdScreenPriv(pWin->drawable.pScreen); Bool ret; s3PatternPtr pPattern; PixmapPtr pPixmap; int fillStyle; ret = fbChangeWindowAttributes (pWin, mask); if (mask & CWBackPixmap) { if (pWin->backgroundState == BackgroundPixmap) { pPixmap = pWin->background.pixmap; fillStyle = FillTiled; } else { pPixmap = 0; fillStyle = FillSolid; } pPattern = s3GetWindowPrivate(pWin); s3AllocPattern (pWin->drawable.pScreen, s3DrawMap (&pWin->drawable), pPixmap, pWin->drawable.x, pWin->drawable.y, fillStyle, 0, 0, &pPattern); DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "Background pattern 0x%x pixmap 0x%x style %d", pPattern, pPixmap, fillStyle)); s3SetWindowPrivate (pWin, pPattern); } return ret; } #ifndef S3_TRIO void s3PaintKey (DrawablePtr pDrawable, RegionPtr pRegion, CARD32 pixel, int fb) { SetupS3 (pDrawable->pScreen); s3ScreenInfo (pScreenPriv); int nBox = REGION_NUM_RECTS(pRegion); BoxPtr pBox = REGION_RECTS(pRegion); int ma; if (!nBox) return; for (ma = 0; s3s->fbmap[ma] >= 0; ma++) if (s3s->fbmap[ma] == fb) break; s3SetGlobalBitmap (pDrawable->pScreen, ma); _s3SetSolidFill (s3, pixel, GXcopy, 0xffffffff); while (nBox--) { _s3SolidRect(s3,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1); pBox++; } MarkSyncS3 (pDrawable->pScreen); } #endif void s3PaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) { SetupS3(pWin->drawable.pScreen); s3ScreenInfo(pScreenPriv); s3PatternPtr pPattern; DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "s3PaintWindow 0x%x extents %d %d %d %d n %d", pWin->drawable.id, pRegion->extents.x1, pRegion->extents.y1, pRegion->extents.x2, pRegion->extents.y2, REGION_NUM_RECTS(pRegion))); if (!REGION_NUM_RECTS(pRegion)) return; switch (what) { case PW_BACKGROUND: switch (pWin->backgroundState) { case None: return; case ParentRelative: do { pWin = pWin->parent; } while (pWin->backgroundState == ParentRelative); (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion, what); return; case BackgroundPixmap: pPattern = s3GetWindowPrivate(pWin); if (pPattern) { s3FillBoxPattern ((DrawablePtr)pWin, (int)REGION_NUM_RECTS(pRegion), REGION_RECTS(pRegion), GXcopy, ~0, pPattern); return; } break; case BackgroundPixel: s3FillBoxSolid((DrawablePtr)pWin, (int)REGION_NUM_RECTS(pRegion), REGION_RECTS(pRegion), pWin->background.pixel, GXcopy, ~0); return; } break; case PW_BORDER: #ifndef S3_TRIO if (s3s->fbmap[1] >= 0) fbOverlayUpdateLayerRegion (pWin->drawable.pScreen, fbOverlayWindowLayer (pWin), pRegion); #endif if (pWin->borderIsPixel) { s3FillBoxSolid((DrawablePtr)pWin, (int)REGION_NUM_RECTS(pRegion), REGION_RECTS(pRegion), pWin->border.pixel, GXcopy, ~0); return; } break; } KdCheckPaintWindow (pWin, pRegion, what); } void s3CopyWindowProc (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pboxOrig, int nboxOrig, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { SetupS3(pDstDrawable->pScreen); s3ScreenInfo(pScreenPriv); KdScreenInfo *screen = pScreenPriv->screen; int srcX, srcY, dstX, dstY; int x1, x2; int w, h; int flags; int fb = (int) closure; int ma; BoxPtr pbox; int nbox; int bitsPerPixel; #ifdef S3_TRIO ma = 0; #else for (ma = 0; s3s->fbmap[ma] >= 0; ma++) if (s3s->fbmap[ma] == fb) break; #endif bitsPerPixel = screen->fb[fb].bitsPerPixel; if (bitsPerPixel == 24) dx *= 3; nbox = nboxOrig; pbox = pboxOrig; s3SetGlobalBitmap (pDstDrawable->pScreen, ma); _s3SetBlt(s3,GXcopy,~0); while (nbox--) { x1 = pbox->x1; x2 = pbox->x2; if (bitsPerPixel == 24) { x1 *= 3; x2 *= 3; } w = x2 - x1; h = pbox->y2 - pbox->y1; flags = 0; if (reverse) { dstX = x2 - 1; } else { dstX = x1; flags |= INC_X; } srcX = dstX + dx; if (upsidedown) { dstY = pbox->y2 - 1; } else { dstY = pbox->y1; flags |= INC_Y; } srcY = dstY + dy; _s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags); pbox++; } MarkSyncS3 (pDstDrawable->pScreen); } void s3CopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) { ScreenPtr pScreen = pWin->drawable.pScreen; KdScreenPriv (pScreen); s3ScreenInfo (pScreenPriv); KdScreenInfo *screen = pScreenPriv->screen; RegionRec rgnDst; int dx, dy; WindowPtr pwinRoot; pwinRoot = WindowTable[pWin->drawable.pScreen->myNum]; dx = ptOldOrg.x - pWin->drawable.x; dy = ptOldOrg.y - pWin->drawable.y; REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); fbCopyRegion ((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot, 0, &rgnDst, dx, dy, s3CopyWindowProc, 0, 0); REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); } void s3_24FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox, unsigned long pixel, int alu, unsigned long planemask) { SetupS3(pDrawable->pScreen); register int r; int x1, x2; s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable)); _s3SetSolidFill(s3,pixel,alu,planemask); while (nBox--) { x1 = pBox->x1 * 3; x2 = pBox->x2 * 3; _s3SolidRect(s3,x1,pBox->y1,x2-x1,pBox->y2-pBox->y1); pBox++; } MarkSyncS3 (pDrawable->pScreen); } #define ok24(p) (((p) & 0xffffff) == ((((p) & 0xff) << 16) | (((p) >> 8) & 0xffff))) void s3_24FillSpans (DrawablePtr pDrawable, GCPtr pGC, int n, DDXPointPtr ppt, int *pwidth, int fSorted) { SetupS3(pDrawable->pScreen); int x, y, x1, y1, x2, y2; int width; /* next three parameters are post-clip */ int nTmp; int *pwidthFree;/* copies of the pointers to free */ DDXPointPtr pptFree; BoxPtr extents; RegionPtr pClip = fbGetCompositeClip (pGC); if (pGC->fillStyle != FillSolid || !ok24 (pGC->fgPixel) || !ok24(pGC->planemask)) { KdCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); return; } s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC)); if (REGION_NUM_RECTS(pClip) == 1) { extents = REGION_RECTS(pClip); x1 = extents->x1; x2 = extents->x2; y1 = extents->y1; y2 = extents->y2; _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask); while (n--) { y = ppt->y; if (y1 <= y && y < y2) { x = ppt->x; width = *pwidth; if (x < x1) { width -= (x1 - x); x = x1; } if (x2 < x + width) width = x2 - x; if (width > 0) { _s3SolidRect(s3,x*3,y,width*3,1); } } ppt++; pwidth++; } } else { nTmp = n * miFindMaxBand(pClip); pwidthFree = (int *)ALLOCATE_LOCAL(nTmp * sizeof(int)); pptFree = (DDXPointRec *)ALLOCATE_LOCAL(nTmp * sizeof(DDXPointRec)); if(!pptFree || !pwidthFree) { if (pptFree) DEALLOCATE_LOCAL(pptFree); if (pwidthFree) DEALLOCATE_LOCAL(pwidthFree); return; } n = miClipSpans(fbGetCompositeClip(pGC), ppt, pwidth, n, pptFree, pwidthFree, fSorted); pwidth = pwidthFree; ppt = pptFree; _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask); while (n--) { x = ppt->x; y = ppt->y; ppt++; width = *pwidth++; if (width) { _s3SolidRect(s3,x*3,y,width*3,1); } } DEALLOCATE_LOCAL(pptFree); DEALLOCATE_LOCAL(pwidthFree); } MarkSyncS3 (pDrawable->pScreen); } void s3_24CopyNtoN (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { SetupS3(pDstDrawable->pScreen); int srcX, srcY, dstX, dstY; int w, h; int flags; int x1, x2; if (sourceInvarient (pGC->alu)) { s3_24FillBoxSolid (pDstDrawable, nbox, pbox, 0, pGC->alu, pGC->planemask); return; } s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC)); _s3SetBlt(s3,pGC->alu,pGC->planemask); DRAW_DEBUG ((DEBUG_RENDER, "s3CopyNtoN alu %d planemask 0x%x", pGC->alu, pGC->planemask)); dx *= 3; while (nbox--) { x1 = pbox->x1 * 3; x2 = pbox->x2 * 3; w = x2 - x1; h = pbox->y2 - pbox->y1; flags = 0; if (reverse) { dstX = x2 - 1; } else { dstX = x1; flags |= INC_X; } srcX = dstX + dx; if (upsidedown) { dstY = pbox->y2 - 1; } else { dstY = pbox->y1; flags |= INC_Y; } srcY = dstY + dy; _s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags); pbox++; } MarkSyncS3 (pSrcDrawable->pScreen); } RegionPtr s3_24CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, int srcx, int srcy, int width, int height, int dstx, int dsty) { SetupS3(pDstDrawable->pScreen); if (pSrcDrawable->type == DRAWABLE_WINDOW && pDstDrawable->type == DRAWABLE_WINDOW && ok24(pGC->planemask)) { return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, s3_24CopyNtoN, 0, 0); } return KdCheckCopyArea (pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty); } #define NUM_STACK_RECTS 1024 void s3_24PolyFillRect (DrawablePtr pDrawable, GCPtr pGC, int nrectFill, xRectangle *prectInit) { s3GCPrivate(pGC); xRectangle *prect; RegionPtr prgnClip; register BoxPtr pbox; register BoxPtr pboxClipped; BoxPtr pboxClippedBase; BoxPtr pextent; BoxRec stackRects[NUM_STACK_RECTS]; int numRects; int n; int xorg, yorg; int x, y; if (pGC->fillStyle != FillSolid || !ok24 (pGC->fgPixel) || !ok24(pGC->planemask)) { KdCheckPolyFillRect (pDrawable, pGC, nrectFill, prectInit); return; } prgnClip = fbGetCompositeClip(pGC); xorg = pDrawable->x; yorg = pDrawable->y; if (xorg || yorg) { prect = prectInit; n = nrectFill; while(n--) { prect->x += xorg; prect->y += yorg; prect++; } } prect = prectInit; numRects = REGION_NUM_RECTS(prgnClip) * nrectFill; if (numRects > NUM_STACK_RECTS) { pboxClippedBase = (BoxPtr)ALLOCATE_LOCAL(numRects * sizeof(BoxRec)); if (!pboxClippedBase) return; } else pboxClippedBase = stackRects; pboxClipped = pboxClippedBase; if (REGION_NUM_RECTS(prgnClip) == 1) { int x1, y1, x2, y2, bx2, by2; pextent = REGION_RECTS(prgnClip); x1 = pextent->x1; y1 = pextent->y1; x2 = pextent->x2; y2 = pextent->y2; while (nrectFill--) { if ((pboxClipped->x1 = prect->x) < x1) pboxClipped->x1 = x1; if ((pboxClipped->y1 = prect->y) < y1) pboxClipped->y1 = y1; bx2 = (int) prect->x + (int) prect->width; if (bx2 > x2) bx2 = x2; pboxClipped->x2 = bx2; by2 = (int) prect->y + (int) prect->height; if (by2 > y2) by2 = y2; pboxClipped->y2 = by2; prect++; if ((pboxClipped->x1 < pboxClipped->x2) && (pboxClipped->y1 < pboxClipped->y2)) { pboxClipped++; } } } else { int x1, y1, x2, y2, bx2, by2; pextent = REGION_EXTENTS(pGC->pScreen, prgnClip); x1 = pextent->x1; y1 = pextent->y1; x2 = pextent->x2; y2 = pextent->y2; while (nrectFill--) { BoxRec box; if ((box.x1 = prect->x) < x1) box.x1 = x1; if ((box.y1 = prect->y) < y1) box.y1 = y1; bx2 = (int) prect->x + (int) prect->width; if (bx2 > x2) bx2 = x2; box.x2 = bx2; by2 = (int) prect->y + (int) prect->height; if (by2 > y2) by2 = y2; box.y2 = by2; prect++; if ((box.x1 >= box.x2) || (box.y1 >= box.y2)) continue; n = REGION_NUM_RECTS (prgnClip); pbox = REGION_RECTS(prgnClip); /* clip the rectangle to each box in the clip region this is logically equivalent to calling Intersect() */ while(n--) { pboxClipped->x1 = max(box.x1, pbox->x1); pboxClipped->y1 = max(box.y1, pbox->y1); pboxClipped->x2 = min(box.x2, pbox->x2); pboxClipped->y2 = min(box.y2, pbox->y2); pbox++; /* see if clipping left anything */ if(pboxClipped->x1 < pboxClipped->x2 && pboxClipped->y1 < pboxClipped->y2) { pboxClipped++; } } } } if (pboxClipped != pboxClippedBase) { s3_24FillBoxSolid(pDrawable, pboxClipped-pboxClippedBase, pboxClippedBase, pGC->fgPixel, pGC->alu, pGC->planemask); } if (pboxClippedBase != stackRects) DEALLOCATE_LOCAL(pboxClippedBase); } void s3_24SolidBoxClipped (DrawablePtr pDrawable, RegionPtr pClip, int x1, int y1, int x2, int y2, FbBits fg) { SetupS3 (pDrawable->pScreen); BoxPtr pbox; int nbox; int partX1, partX2, partY1, partY2; s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable)); _s3SetSolidFill(s3,fg,GXcopy,~0); for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip); nbox--; pbox++) { partX1 = pbox->x1; if (partX1 < x1) partX1 = x1; partX2 = pbox->x2; if (partX2 > x2) partX2 = x2; if (partX2 <= partX1) continue; partY1 = pbox->y1; if (partY1 < y1) partY1 = y1; partY2 = pbox->y2; if (partY2 > y2) partY2 = y2; if (partY2 <= partY1) continue; partX1 *= 3; partX2 *= 3; _s3SolidRect(s3,partX1, partY1, partX2-partX1, partY2-partY1); } MarkSyncS3(pDrawable->pScreen); } void s3_24ImageGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppciInit, pointer pglyphBase) { FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); CharInfoPtr *ppci; CharInfoPtr pci; unsigned char *pglyph; /* pointer bits in glyph */ int gWidth, gHeight; /* width and height of glyph */ FbStride gStride; /* stride of glyph */ Bool opaque; int n; int gx, gy; FbBits *dst; FbStride dstStride; int dstBpp; int dstXoff, dstYoff; FbBits depthMask; int xBack, widthBack; int yBack, heightBack; depthMask = FbFullMask(pDrawable->depth); if (!ok24 (pGC->fgPixel) || !ok24(pGC->bgPixel) || !ok24(pGC->planemask)) { KdCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase); return; } fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); x += pDrawable->x; y += pDrawable->y; ppci = ppciInit; n = nglyph; widthBack = 0; while (n--) widthBack += (*ppci++)->metrics.characterWidth; xBack = x; if (widthBack < 0) { xBack += widthBack; widthBack = -widthBack; } yBack = y - FONTASCENT(pGC->font); heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); s3_24SolidBoxClipped (pDrawable, fbGetCompositeClip(pGC), xBack, yBack, xBack + widthBack, yBack + heightBack, pPriv->bg); KdCheckSync (pDrawable->pScreen); ppci = ppciInit; while (nglyph--) { pci = *ppci++; pglyph = FONTGLYPHBITS(pglyphBase, pci); gWidth = GLYPHWIDTHPIXELS(pci); gHeight = GLYPHHEIGHTPIXELS(pci); if (gWidth && gHeight) { gx = x + pci->metrics.leftSideBearing; gy = y - pci->metrics.ascent; if (gWidth <= sizeof (FbStip) * 8 && fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) { fbGlyph24 (dst + (gy - dstYoff) * dstStride, dstStride, dstBpp, (FbStip *) pglyph, pPriv->fg, gx - dstXoff, gHeight); } else { gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip); fbPutXYImage (pDrawable, fbGetCompositeClip(pGC), pPriv->fg, pPriv->bg, pPriv->pm, GXcopy, FALSE, gx, gy, gWidth, gHeight, (FbStip *) pglyph, gStride, 0); } } x += pci->metrics.characterWidth; } } static const GCOps s3_24GCOps = { s3_24FillSpans, KdCheckSetSpans, KdCheckPutImage, KdCheckCopyArea, KdCheckCopyPlane, KdCheckPolyPoint, KdCheckPolylines, KdCheckPolySegment, KdCheckPolyRectangle, KdCheckPolyArc, KdCheckFillPolygon, s3_24PolyFillRect, KdCheckPolyFillArc, miPolyText8, miPolyText16, miImageText8, miImageText16, s3_24ImageGlyphBlt, KdCheckPolyGlyphBlt, KdCheckPushPixels, #ifdef NEED_LINEHELPER ,NULL #endif }; void s3_24ValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable) { if (pDrawable->type != DRAWABLE_WINDOW) pGC->ops = (GCOps *) &kdAsyncPixmapGCOps; else pGC->ops = (GCOps *) &s3_24GCOps; fbValidateGC (pGC, changes, pDrawable); } GCFuncs s3_24GCFuncs = { s3_24ValidateGC, miChangeGC, miCopyGC, miDestroyGC, miChangeClip, miDestroyClip, miCopyClip }; Bool s3_24CreateGC (GCPtr pGC) { if (!fbCreateGC (pGC)) return FALSE; if (pGC->depth != 1) pGC->funcs = &s3_24GCFuncs; return TRUE; } Bool s3_24CreateWindow(WindowPtr pWin) { return fbCreateWindow (pWin); } void s3_24PaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) { SetupS3(pWin->drawable.pScreen); s3PatternPtr pPattern; DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "s3PaintWindow 0x%x extents %d %d %d %d n %d", pWin->drawable.id, pRegion->extents.x1, pRegion->extents.y1, pRegion->extents.x2, pRegion->extents.y2, REGION_NUM_RECTS(pRegion))); if (!REGION_NUM_RECTS(pRegion)) return; switch (what) { case PW_BACKGROUND: switch (pWin->backgroundState) { case None: return; case ParentRelative: do { pWin = pWin->parent; } while (pWin->backgroundState == ParentRelative); (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion, what); return; case BackgroundPixel: if (ok24(pWin->background.pixel)) { s3_24FillBoxSolid((DrawablePtr)pWin, (int)REGION_NUM_RECTS(pRegion), REGION_RECTS(pRegion), pWin->background.pixel, GXcopy, ~0); return; } } break; case PW_BORDER: if (pWin->borderIsPixel && ok24(pWin->border.pixel)) { s3_24FillBoxSolid((DrawablePtr)pWin, (int)REGION_NUM_RECTS(pRegion), REGION_RECTS(pRegion), pWin->border.pixel, GXcopy, ~0); return; } break; } KdCheckPaintWindow (pWin, pRegion, what); } Bool s3DrawInit (ScreenPtr pScreen) { KdScreenPriv(pScreen); s3ScreenInfo(pScreenPriv); int ncache_w, ncache_h, ncache; int px, py; S3PatternCache *cache; Bool dumb = FALSE; int ma; switch (pScreenPriv->screen->fb[0].bitsPerPixel) { case 8: case 16: case 32: break; case 24: dumb = TRUE; break; default: return FALSE; } /* * Hook up asynchronous drawing */ RegisterSync (pScreen); /* * Replace various fb screen functions */ if (dumb) { pScreen->CreateGC = s3_24CreateGC; pScreen->CreateWindow = s3_24CreateWindow; pScreen->PaintWindowBackground = s3_24PaintWindow; pScreen->PaintWindowBorder = s3_24PaintWindow; pScreen->CopyWindow = s3CopyWindow; } else { if (serverGeneration != s3Generation) { s3GCPrivateIndex = AllocateGCPrivateIndex (); s3WindowPrivateIndex = AllocateWindowPrivateIndex (); s3Generation = serverGeneration; } if (!AllocateWindowPrivate(pScreen, s3WindowPrivateIndex, 0)) return FALSE; if (!AllocateGCPrivate(pScreen, s3GCPrivateIndex, sizeof (s3PrivGCRec))) return FALSE; pScreen->CreateGC = s3CreateGC; pScreen->CreateWindow = s3CreateWindow; pScreen->ChangeWindowAttributes = s3ChangeWindowAttributes; pScreen->DestroyWindow = s3DestroyWindow; pScreen->PaintWindowBackground = s3PaintWindow; pScreen->PaintWindowBorder = s3PaintWindow; #ifndef S3_TRIO if (pScreenPriv->screen->fb[1].depth) { FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); pScrPriv->PaintKey = s3PaintKey; pScrPriv->CopyWindow = s3CopyWindowProc; pScreen->CopyWindow = fbOverlayCopyWindow; } else #endif pScreen->CopyWindow = s3CopyWindow; /* * Initialize patterns */ #ifdef S3_TRIO ma = 0; #else for (ma = 0; s3s->fbmap[ma] >= 0; ma++) #endif { ncache_w = s3s->fb[ma].offscreen_width / S3_TILE_SIZE; ncache_h = s3s->fb[ma].offscreen_height / S3_TILE_SIZE; ncache = ncache_w * ncache_h; if (ncache > 64) ncache = 64; DRAW_DEBUG ((DEBUG_S3INIT, "ncache_w %d ncache_h %d ncache %d", ncache_w, ncache_h, ncache)); s3s->fb[ma].patterns.cache = (S3PatternCache *) xalloc (ncache * sizeof (S3PatternCache)); if (s3s->fb[ma].patterns.cache) { DRAW_DEBUG ((DEBUG_S3INIT, "Have pattern cache")); s3s->fb[ma].patterns.ncache = ncache; s3s->fb[ma].patterns.last_used = 0; s3s->fb[ma].patterns.last_id = 0; cache = s3s->fb[ma].patterns.cache; for (py = 0; py < ncache_h && ncache; py++) for (px = 0; px < ncache_w && ncache; px++) { cache->id = 0; cache->x = s3s->fb[ma].offscreen_x + px * S3_TILE_SIZE; cache->y = s3s->fb[ma].offscreen_y + py * S3_TILE_SIZE; cache++; ncache--; } } } } return TRUE; } void s3DrawEnable (ScreenPtr pScreen) { SetupS3(pScreen); s3ScreenInfo(pScreenPriv); int c; int ma; s3SetGlobalBitmap (pScreen, 0); _s3WaitIdleEmpty (s3); if (pScreenPriv->screen->fb[0].bitsPerPixel == 24) { _s3SetScissorsTl(s3, 0, 0); _s3SetScissorsBr(s3, pScreenPriv->screen->width*3 - 1, pScreenPriv->screen->height - 1); _s3SetSolidFill(s3, pScreen->whitePixel, GXcopy, ~0); _s3SolidRect (s3, 0, 0, pScreenPriv->screen->width*3, pScreenPriv->screen->height); } else { /* * Flush pattern cache */ #ifdef S3_TRIO ma = 0; #else for (ma = 0; s3s->fbmap[ma] >= 0; ma++) #endif { for (c = 0; c < s3s->fb[ma].patterns.ncache; c++) s3s->fb[ma].patterns.cache[c].id = 0; } _s3SetScissorsTl(s3, 0, 0); _s3SetScissorsBr(s3, pScreenPriv->screen->width - 1, pScreenPriv->screen->height - 1); _s3SetSolidFill(s3, pScreen->blackPixel, GXcopy, ~0); _s3SolidRect (s3, 0, 0, pScreenPriv->screen->width, pScreenPriv->screen->height); } MarkSyncS3 (pScreen); } void s3DrawDisable (ScreenPtr pScreen) { SetupS3 (pScreen); _s3WaitIdleEmpty (s3); } void s3DrawFini (ScreenPtr pScreen) { SetupS3(pScreen); s3ScreenInfo(pScreenPriv); int ma; #ifdef S3_TRIO ma = 0; #else for (ma = 0; s3s->fbmap[ma] >= 0; ma++) #endif { if (s3s->fb[ma].patterns.cache) { xfree (s3s->fb[ma].patterns.cache); s3s->fb[ma].patterns.cache = 0; s3s->fb[ma].patterns.ncache = 0; } } } void s3DrawSync (ScreenPtr pScreen) { SetupS3(pScreen); _s3WaitIdleEmpty(s3c->s3); }