Path: utzoo!yunexus!geac!syntron!jtsv16!uunet!mcvax!ukc!acorn!steve From: steve@acorn.UUCP (Steve "daffy" Hunt) Newsgroups: comp.windows.x Subject: FIXES TO CFB TILING (2 of 2 -- cfbfillsp.c) Keywords: cfb, sample server, fix, tiling, bug Message-ID: <534@acorn.UUCP> Date: 26 Oct 88 12:25:04 GMT Article-I.D.: acorn.534 Reply-To: steve@acorn.UUCP (Steve "daffy" Hunt) Organization: Acorn Computers Ltd, Cambridge, England Lines: 685 Here is the fixed cfbfillsp.c. -- Steve Hunt, daffy@acorn.co.uk, daffy@acorn.UUCP ------------------------------- cfbfillsp.c ---------------------------------- /************************************************************ Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright no- tice appear in all copies and that both that copyright no- tice and this permission notice appear in supporting docu- mentation, and that the names of Sun or MIT not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. Sun and M.I.T. make no representations about the suitability of this software for any purpose. It is provided "as is" without any express or implied warranty. SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- ABLE 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. ********************************************************/ /*********************************************************** Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, 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 names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL 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. ******************************************************************/ /* Pixmap tiling fixes by John Bowler and Steve Hunt, Acorn */ #include "X.h" #include "Xmd.h" #include "servermd.h" #include "gcstruct.h" #include "window.h" #include "pixmapstr.h" #include "scrnintstr.h" #include "windowstr.h" #include "cfb.h" #include "cfbmskbits.h" /* scanline filling for color frame buffer written by drewry, oct 1986 modified by smarks changes for compatibility with Little-endian systems Jul 1987; MIT:yba. these routines all clip. they assume that anything that has called them has already translated the points (i.e. pGC->miTranslate is non-zero, which is howit gets set in cfbCreateGC().) the number of new scnalines created by clipping == MaxRectsPerBand * nSpans. FillSolid is overloaded to be used for OpaqueStipple as well, if fgPixel == bgPixel. Note that for solids, PrivGC.rop == PrivGC.ropOpStip FillTiled is overloaded to be used for OpaqueStipple, if fgPixel != bgPixel. based on the fill style, it uses {RotatedTile, gc.alu} or {RotatedStipple, PrivGC.ropOpStip} */ #ifdef notdef #include static dumpspans(n, ppt, pwidth) int n; DDXPointPtr ppt; int *pwidth; { fprintf(stderr,"%d spans\n", n); while (n--) { fprintf(stderr, "[%d,%d] %d\n", ppt->x, ppt->y, *pwidth); ppt++; pwidth++; } fprintf(stderr, "\n"); } #endif void cfbSolidFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) DrawablePtr pDrawable; GCPtr pGC; int nInit; /* number of spans to fill */ DDXPointPtr pptInit; /* pointer to list of start points */ int *pwidthInit; /* pointer to list of n widths */ int fSorted; { /* next three parameters are post-clip */ int n; /* number of spans to fill */ register DDXPointPtr ppt; /* pointer to list of start points */ register int *pwidth; /* pointer to list of n widths */ int *addrlBase; /* pointer to start of bitmap */ int nlwidth; /* width in longwords of bitmap */ register int *addrl; /* pointer to current longword in bitmap */ register int startmask; register int endmask; register int nlmiddle; int rop; /* reduced rasterop */ int *pwidthFree; /* copies of the pointers to free */ DDXPointPtr pptFree; int fill, rrop; switch (pDrawable->depth) { case 1: rrop = ReduceRop( pGC->alu, pGC->fgPixel ); switch ( rrop ) { case RROP_BLACK: mfbBlackSolidFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); break; case RROP_WHITE: mfbWhiteSolidFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); break; case RROP_NOP: return; case RROP_INVERT: mfbInvertSolidFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); break; } return; case PSZ: break; default: FatalError("cfbSolidFS: invalid depth\n"); } if (!(pGC->planemask)) return; n = nInit * miFindMaxBand(((cfbPrivGC *)(pGC->devPriv))->pCompositeClip); pwidth = (int *)ALLOCATE_LOCAL(n * sizeof(int)); ppt = (DDXPointRec *)ALLOCATE_LOCAL(n * sizeof(DDXPointRec)); if(!ppt || !pwidth) { DEALLOCATE_LOCAL(ppt); DEALLOCATE_LOCAL(pwidth); return; } #ifdef notdef dumpspans(n, pptInit, pwidthInit); #endif pwidthFree = pwidth; pptFree = ppt; n = miClipSpans(((cfbPrivGC *)(pGC->devPriv))->pCompositeClip, pptInit, pwidthInit, nInit, ppt, pwidth, fSorted); #ifdef notdef dumpspans(n, ppt, pwidth); #endif if (pDrawable->type == DRAWABLE_WINDOW) { addrlBase = (int *) (((PixmapPtr)(pDrawable->pScreen->devPrivate))->devPrivate); nlwidth = (int) (((PixmapPtr)(pDrawable->pScreen->devPrivate))->devKind) >> 2; } else { addrlBase = (int *)(((PixmapPtr)pDrawable)->devPrivate); nlwidth = (int)(((PixmapPtr)pDrawable)->devKind) >> 2; } rop = pGC->alu; fill = PFILL(pGC->fgPixel); while (n--) { addrl = addrlBase + (ppt->y * nlwidth) + (ppt->x >> PWSH); if (*pwidth) { if ( ((ppt->x & PIM) + *pwidth) <= PPW) { /* all bits inside same longword */ putbitsrop( fill, ppt->x & PIM, *pwidth, addrl, pGC->planemask, rop ); } else { maskbits(ppt->x, *pwidth, startmask, endmask, nlmiddle); if ( startmask ) { putbitsrop( fill, ppt->x & PIM, PPW-(ppt->x&PIM), addrl, pGC->planemask, rop); ++addrl; } while ( nlmiddle-- ) { putbitsrop( fill, 0, PPW, addrl, pGC->planemask, rop ); ++addrl; } if ( endmask ) { putbitsrop( fill, 0, ((ppt->x + *pwidth)&PIM), addrl, pGC->planemask, rop ); } } } pwidth++; ppt++; } DEALLOCATE_LOCAL(pptFree); DEALLOCATE_LOCAL(pwidthFree); } /* Fill spans with tiles that aren't 32 bits wide */ void cfbUnnaturalTileFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) DrawablePtr pDrawable; GC *pGC; int nInit; /* number of spans to fill */ DDXPointPtr pptInit; /* pointer to list of start points */ int *pwidthInit; /* pointer to list of n widths */ int fSorted; { /* next three parameters are post-clip */ int n; /* number of spans to fill */ register DDXPointPtr ppt; /* pointer to list of start points */ register int *pwidth; /* pointer to list of n widths */ int *addrlBase; /* pointer to start of bitmap */ int nlwidth; /* width in longwords of bitmap */ PixmapPtr pTile; /* pointer to tile we want to fill with */ int tlwidth, tileWidth, tileHeight, rop; int *pwidthFree; /* copies of the pointers to free */ DDXPointPtr pptFree; switch (pDrawable->depth) { case 1: mfbUnnaturalTileFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); return; case PSZ: break; default: FatalError("cfbUnnaturalTileFS: invalid depth\n"); } if (!(pGC->planemask)) return; n = nInit * miFindMaxBand(((cfbPrivGC *)(pGC->devPriv))->pCompositeClip); pwidth = (int *)ALLOCATE_LOCAL(n * sizeof(int)); ppt = (DDXPointRec *)ALLOCATE_LOCAL(n * sizeof(DDXPointRec)); if(!ppt || !pwidth) { DEALLOCATE_LOCAL(ppt); DEALLOCATE_LOCAL(pwidth); return; } pwidthFree = pwidth; pptFree = ppt; n = miClipSpans(((cfbPrivGC *)(pGC->devPriv))->pCompositeClip, pptInit, pwidthInit, nInit, ppt, pwidth, fSorted); if (pGC->fillStyle == FillTiled) { pTile = ((cfbPrivGC *)(pGC->devPriv))->pRotatedTile; tlwidth = pTile->devKind >> 2; rop = pGC->alu; } else { pTile = ((cfbPrivGC *)(pGC->devPriv))->pRotatedStipple; tlwidth = pTile->devKind >> 2; rop = pGC->alu; } if (pDrawable->type == DRAWABLE_WINDOW) { addrlBase = (int *) (((PixmapPtr)(pDrawable->pScreen->devPrivate))->devPrivate); nlwidth = (int) (((PixmapPtr)(pDrawable->pScreen->devPrivate))->devKind) >> 2; } else { addrlBase = (int *)(((PixmapPtr)pDrawable)->devPrivate); nlwidth = (int)(((PixmapPtr)pDrawable)->devKind) >> 2; } /* * From here on I have significantly modified the X11.2 code to make the whole * algorithm significantly more efficient. I have also fixed bugs which picked * up the wrong part of the input tile causing strange tile rotations. */ tileWidth = pTile->width; tileHeight = pTile->height; while (n--) { int iline = ppt->y % tileHeight; int x = ppt->x; int width; int *pdst = addrlBase + (ppt->y * nlwidth) + (x >> PWSH); int *psrcT = (int *) pTile->devPrivate + (iline * tlwidth); width = *(pwidth++); while(width > 0) { int rem = x % tileWidth; /* * Set w to the minimum of the width to fill, the tile width * and the number of bits which we can get from a single tile. * Since the latter is <= tileWidth I assume that this is * simply the minimum of the last two items! */ int w = min(tileWidth-rem, width); int *psrc = psrcT + rem / PPW; width -= w; rem &= PIM; /* * Test was `(rem + w) <= PPW' - since getbits and putbitsrop * deal with bits spanning a word boundary the following test * is adequate. */ if(w <= PPW) /* less than one word */ { int tmpSrc; getbits(psrc, rem, w, tmpSrc); putbitsrop(tmpSrc, x & PIM, w, pdst, pGC->planemask, rop); if (((x & PIM) + w) >= PPW) ++pdst; x += w; } else /* more than one word of bits */ { /* * putbitsrop is special cased for the case where all the * destination bits are in the same word - cooperate with * it. (I am absolutely sure this code can be made to go * a lot faster by just doing this all the dumb way - fighting * the compiler is not a good idea.) */ int nstart = (-x) & PIM; /* 0-(PPW-1) bits to end of first dst word */ if(nstart) { int tmpSrc; getbits(psrc, rem, nstart, tmpSrc); putbitsrop(tmpSrc, x & PIM, nstart, pdst, pGC->planemask, rop); pdst++; rem += nstart; if (rem >= PPW) { psrc++; rem -= PPW; } } x += w; /* Don't use x after here - but I do change w */ w -= nstart; while(w >= PPW) { int tmpSrc; getbits(psrc, rem, PPW, tmpSrc); putbitsrop( tmpSrc, 0, PPW, pdst, pGC->planemask, rop ); pdst++; psrc++; w -= PPW; } if(w) /* Odd bits at end */ { int tmpSrc; getbits(psrc, rem, w, tmpSrc); putbitsrop(tmpSrc, 0, w, pdst, pGC->planemask, rop); } } } ppt++; } DEALLOCATE_LOCAL(pptFree); DEALLOCATE_LOCAL(pwidthFree); } /* Fill spans with stipples that aren't 32 bits wide */ void cfbUnnaturalStippleFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) DrawablePtr pDrawable; GC *pGC; int nInit; /* number of spans to fill */ DDXPointPtr pptInit; /* pointer to list of start points */ int *pwidthInit; /* pointer to list of n widths */ int fSorted; { /* next three parameters are post-clip */ int n; /* number of spans to fill */ register DDXPointPtr ppt; /* pointer to list of start points */ register int *pwidth; /* pointer to list of n widths */ int iline; /* first line of tile to use */ int *addrlBase; /* pointer to start of bitmap */ int nlwidth; /* width in longwords of bitmap */ register int *pdst; /* pointer to current word in bitmap */ PixmapPtr pStipple; /* pointer to stipple we want to fill with */ int w, width, x, xrem; unsigned int tmpSrc, tmpDst1, tmpDst2; int stwidth, stippleWidth, *psrcS, rop; int *pwidthFree; /* copies of the pointers to free */ DDXPointPtr pptFree; unsigned int fgfill, bgfill; switch (pDrawable->depth) { case 1: mfbUnnaturalStippleFS(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); return; case PSZ: break; default: FatalError("cfbUnnaturalStippleFS: invalid depth\n"); } if (!(pGC->planemask)) return; n = nInit * miFindMaxBand(((cfbPrivGC *)(pGC->devPriv))->pCompositeClip); pwidth = (int *)ALLOCATE_LOCAL(n * sizeof(int)); ppt = (DDXPointRec *)ALLOCATE_LOCAL(n * sizeof(DDXPointRec)); if(!ppt || !pwidth) { DEALLOCATE_LOCAL(ppt); DEALLOCATE_LOCAL(pwidth); return; } pwidthFree = pwidth; pptFree = ppt; n = miClipSpans(((cfbPrivGC *)(pGC->devPriv))->pCompositeClip, pptInit, pwidthInit, nInit, ppt, pwidth, fSorted); rop = ((cfbPrivGC *)(pGC->devPriv))->rop; fgfill = PFILL(pGC->fgPixel); bgfill = PFILL(pGC->bgPixel); /* * OK, so what's going on here? We have two Drawables: * * The Stipple: * Depth = 1 * Width = stippleWidth * Words per scanline = stwidth * Pointer to pixels = pStipple->devPrivate */ pStipple = ((cfbPrivGC *)(pGC->devPriv))->pRotatedStipple; if (pStipple->drawable.depth != 1) { FatalError( "Stipple depth not equal to 1!\n" ); } stwidth = pStipple->devKind >> 2; stippleWidth = pStipple->width; /* * The Target: * Depth = PSZ * Width = determined from *pwidth * Words per scanline = nlwidth * Pointer to pixels = addrlBase */ if (pDrawable->type == DRAWABLE_WINDOW) { addrlBase = (int *) (((PixmapPtr)(pDrawable->pScreen->devPrivate))->devPrivate); nlwidth = (int) (((PixmapPtr)(pDrawable->pScreen->devPrivate))->devKind) >> 2; /* SAH 30-Aug-88: this was a throwback to the times when stipples were not stored rotated. * xSrc = ((WindowPtr)pDrawable)->absCorner.x; * ySrc = ((WindowPtr)pDrawable)->absCorner.y; */ } else { addrlBase = (int *)(((PixmapPtr)pDrawable)->devPrivate); nlwidth = (int)(((PixmapPtr)pDrawable)->devKind) >> 2; } while (n--) { iline = (ppt->y) % pStipple->height; x = ppt->x; pdst = addrlBase + (ppt->y * nlwidth); psrcS = (int *) pStipple->devPrivate + (iline * stwidth); if (*pwidth) { width = *pwidth; while(width > 0) { int xtemp; unsigned int *ptemp; /* * Do a stripe through the stipple & destination w pixels * wide. w is not more than: * - the width of the destination * - the width of the stipple * - the distance between x and the next word * boundary in the destination * - the distance between x and the next word * boundary in the stipple */ /* width of dest/stipple */ xrem = (x) % stippleWidth; w = min((stippleWidth - xrem), width); /* dist to word bound in dest */ w = min(w, PPW - (x & PIM)); /* dist to word bound in stip */ w = min(w, 32 - (x & 0x1f)); xtemp = (xrem & 0x1f); ptemp = (unsigned int *)(psrcS + (xrem >> 5)); switch ( pGC->fillStyle ) { case FillOpaqueStippled: getstipplepixels(ptemp, xtemp, w, 0, &bgfill, &tmpDst1); getstipplepixels(ptemp, xtemp, w, 1, &fgfill, &tmpDst2); break; case FillStippled: /* Fill tmpSrc with the source pixels */ tmpSrc = *(pdst + (x >> PWSH)); getstipplepixels(ptemp, xtemp, w, 0, &tmpSrc, &tmpDst1); getstipplepixels(ptemp, xtemp, w, 1, &fgfill, &tmpDst2); break; } #ifdef notdef putbitsrop(tmpDst1 | tmpDst2, x & PIM, w, pdst + (x>>PWSH), pGC->planemask, rop); #else { /* * Ultrix cc hasn't enough expression stack to compile * these values in the putbitsrop call. (MIT:yba) */ int tmpDst = tmpDst1 | tmpDst2, tmpx = x & PIM; int * pdsttmp = pdst + (x>>PWSH); putbitsrop(tmpDst, tmpx, w, pdsttmp, pGC->planemask, rop); } #endif notdef x += w; width -= w; } } #ifdef notdef if (*pwidth) { width = *pwidth; while(width > 0) { psrc = psrcS; w = min(min(stippleWidth, width), PPW); if((rem = x % stippleWidth) != 0) { w = min(min(stippleWidth - rem, width), PPW); /* we want to grab from the end of the tile. Figure * out where that is. In general, the start of the last * word of data on this scanline is stwidth -1 words * away. But if we want to grab more bits than we'll * find on that line, we have to back up 1 word further. * On the other hand, if the whole tile fits in 1 word, * let's skip the work */ endinc = stwidth - 1 - w / PPW; if(endinc) { if((rem & 0x1f) + w > stippleWidth % PPW) endinc--; } getbits(psrc + endinc, rem & PIM, w, tmpSrc); putbitsrop(tmpSrc, (x & PIM), w, pdst, pGC->planemask, rop); if((x & PIM) + w >= PPW) pdst++; } else if(((x & PIM) + w) < PPW) { getbits(psrc, 0, w, tmpSrc); putbitsrop(tmpSrc, x & PIM, w, pdst, pGC->planemask, rop); } else { maskbits(x, w, startmask, endmask, nlMiddle); if (startmask) nstart = PPW - (x & PIM); else nstart = 0; if (endmask) nend = (x + w) & PIM; else nend = 0; srcStartOver = nstart > PLST; if(startmask) { getbits(psrc, 0, nstart, tmpSrc); putbitsrop(tmpSrc, (x & PIM), nstart, pdst, pGC->planemask, rop); pdst++; if(srcStartOver) psrc++; } while(nlMiddle--) { /* getbits(psrc, nstart, PPW, tmpSrc); putbitsrop( tmpSrc, 0, PPW, pdst, pGC->planemask, rop ); */ switch ( pGC->fillStyle ) { case FillStippled: /* SAH: XXX changed 4 to PPW below */ getstipplepixels( psrc, j, PPW, 1, pdst, tmp1 ); break; case FillOpaqueStippled: /* SAH: XXX changed 4 to PPW below */ getstipplepixels( psrc, j, PPW, 1, pdst, tmp1 ); break; } pdst++; psrc++; } if(endmask) { getbits(psrc, nstart, nend, tmpSrc); putbitsrop(tmpSrc, 0, nend, pdst, pGC->planemask, rop); } } x += w; width -= w; } } #endif ppt++; pwidth++; } DEALLOCATE_LOCAL(pptFree); DEALLOCATE_LOCAL(pwidthFree); }