/* * Acceleration for the Creator and Creator3D framebuffer - GC implementation. * * Copyright (C) 1998,1999,2000 Jakub Jelinek (jakub@redhat.com) * Copyright (C) 1998 Michal Rehacek (majkl@iname.com) * Copyright (C) 1999 David S. Miller (davem@redhat.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * JAKUB JELINEK, MICHAL REHACEK, OR DAVID MILLER BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sunffb/ffb_gc.c,v 1.2 2000/05/23 04:47:44 dawes Exp $ */ #include "ffb.h" #include "ffb_regs.h" #include "ffb_rcache.h" #include "ffb_fifo.h" #include "ffb_loops.h" #include "ffb_gc.h" #include "scrnintstr.h" #include "pixmapstr.h" #include "fontstruct.h" #include "dixfontstr.h" #define PSZ 8 #include "cfb.h" #undef PSZ #include "cfb32.h" #include "migc.h" #include "mi.h" #include "mispans.h" GCOps CreatorTEOps1Rect8 = { CreatorFillSpans, CreatorSetSpans, cfbPutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorPolylines, CreatorPolySegment, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, CreatorTEGlyphBlt, CreatorPolyTEGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; GCOps CreatorTEOps1Rect32 = { CreatorFillSpans, CreatorSetSpans, cfb32PutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorPolylines, CreatorPolySegment, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, CreatorTEGlyphBlt, CreatorPolyTEGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; GCOps CreatorTEOps8 = { CreatorFillSpans, CreatorSetSpans, cfbPutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorLineSSStub, CreatorSegmentSSStub, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, CreatorTEGlyphBlt, CreatorPolyTEGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; GCOps CreatorTEOps32 = { CreatorFillSpans, CreatorSetSpans, cfb32PutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorLineSSStub, CreatorSegmentSSStub, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, CreatorTEGlyphBlt, CreatorPolyTEGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; GCOps CreatorNonTEOps1Rect8 = { CreatorFillSpans, CreatorSetSpans, cfbPutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorPolylines, CreatorPolySegment, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, miImageGlyphBlt, CreatorPolyGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; GCOps CreatorNonTEOps1Rect32 = { CreatorFillSpans, CreatorSetSpans, cfb32PutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorPolylines, CreatorPolySegment, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, miImageGlyphBlt, CreatorPolyGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; GCOps CreatorNonTEOps8 = { CreatorFillSpans, CreatorSetSpans, cfbPutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorLineSSStub, CreatorSegmentSSStub, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, miImageGlyphBlt, CreatorPolyGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; GCOps CreatorNonTEOps32 = { CreatorFillSpans, CreatorSetSpans, cfb32PutImage, CreatorCopyArea, CreatorCopyPlane, CreatorPolyPoint, CreatorLineSSStub, CreatorSegmentSSStub, miPolyRectangle, CreatorZeroPolyArc, CreatorFillPolygon, CreatorPolyFillRect, CreatorPolyFillArcSolid, miPolyText8, miPolyText16, miImageText8, miImageText16, miImageGlyphBlt, CreatorPolyGlyphBlt, miPushPixels #ifdef NEED_LINEHELPER ,NULL #endif }; #define FONTWIDTH(font) (FONTMAXBOUNDS(font,rightSideBearing) - \ FONTMINBOUNDS(font,leftSideBearing)) #define FONTHEIGHT(font) (FONTMAXBOUNDS(font,ascent) + \ FONTMINBOUNDS(font,descent)) static GCOps * CreatorMatchCommon (GCPtr pGC, cfbPrivGCPtr devPriv) { int depth = pGC->depth; if (pGC->lineWidth != 0) return 0; if (pGC->lineStyle != LineSolid) return 0; if (pGC->fillStyle != FillSolid) return 0; if (devPriv->rop != GXcopy) return 0; if (pGC->font && FONTWIDTH (pGC->font) <= 32 && FONTHEIGHT (pGC->font) <= 100 && FONTMINBOUNDS(pGC->font,characterWidth) >= 0) { if (TERMINALFONT(pGC->font)) { if (devPriv->oneRect) { return (depth == 8 ? &CreatorTEOps1Rect8 : &CreatorTEOps1Rect32); } else { return (depth == 8 ? &CreatorTEOps8 : &CreatorTEOps32); } } else { if (devPriv->oneRect) { return (depth == 8 ? &CreatorNonTEOps1Rect8 : &CreatorNonTEOps1Rect32); } else { return (depth == 8 ? &CreatorNonTEOps8 : &CreatorNonTEOps32); } } } return 0; } static void CreatorDestroyGC (GCPtr pGC) { CreatorPrivGCPtr gcPriv = CreatorGetGCPrivate (pGC); if (gcPriv->stipple) xfree (gcPriv->stipple); miDestroyGC (pGC); } static __inline__ void CreatorNewLine(GCPtr pGC, cfbPrivGCPtr devPriv, CreatorPrivGCPtr gcPriv, int accel) { pGC->ops->FillPolygon = miFillPolygon; pGC->ops->PolyRectangle = miPolyRectangle; if (pGC->lineWidth == 0) pGC->ops->PolyArc = miZeroPolyArc; else pGC->ops->PolyArc = miPolyArc; if (accel) { pGC->ops->FillPolygon = CreatorFillPolygon; if (pGC->lineWidth == 0 && pGC->capStyle != CapNotLast) pGC->ops->PolyArc = CreatorZeroPolyArc; } pGC->ops->PolySegment = miPolySegment; gcPriv->linepat = 0; /* Segment and Line ops are only accelerated if there is * one clipping region. */ if (accel && !devPriv->oneRect) accel = 0; if (pGC->lineStyle == LineSolid) { if(pGC->lineWidth == 0) { if (pGC->fillStyle == FillSolid) { pGC->ops->Polylines = CreatorLineSSStub; pGC->ops->PolySegment = CreatorSegmentSSStub; } else pGC->ops->Polylines = miZeroLine; if (accel) { gcPriv->PolySegment = pGC->ops->PolySegment; gcPriv->Polylines = pGC->ops->Polylines; pGC->ops->PolySegment = CreatorPolySegment; pGC->ops->Polylines = CreatorPolylines; } } else { pGC->ops->Polylines = miWideLine; } } else if(pGC->lineStyle == LineOnOffDash) { if (pGC->lineWidth == 0 && pGC->fillStyle == FillSolid) { pGC->ops->Polylines = CreatorLineSDStub; pGC->ops->PolySegment = CreatorSegmentSDStub; if(accel && CreatorCheckLinePattern(pGC, gcPriv)) { gcPriv->PolySegment = pGC->ops->PolySegment; gcPriv->Polylines = pGC->ops->Polylines; pGC->ops->PolySegment = CreatorPolySegment; pGC->ops->Polylines = CreatorPolylines; } } else { pGC->ops->Polylines = miWideDash; } } else if(pGC->lineStyle == LineDoubleDash) { if (pGC->lineWidth == 0 && pGC->fillStyle == FillSolid) { pGC->ops->Polylines = CreatorLineSDStub; pGC->ops->PolySegment = CreatorSegmentSDStub; } else { pGC->ops->Polylines = miWideDash; } } } static __inline__ void CreatorNewGlyph(GCPtr pGC, CreatorPrivGCPtr gcPriv) { if (FONTWIDTH(pGC->font) > 32 || FONTHEIGHT(pGC->font) > 100 || FONTMINBOUNDS(pGC->font,characterWidth) < 0) { pGC->ops->PolyGlyphBlt = miPolyGlyphBlt; pGC->ops->ImageGlyphBlt = miImageGlyphBlt; } else { if (pGC->fillStyle == FillSolid) { if (TERMINALFONT (pGC->font)) { pGC->ops->PolyGlyphBlt = CreatorPolyTEGlyphBlt; } else { pGC->ops->PolyGlyphBlt = CreatorPolyGlyphBlt; } } else { pGC->ops->PolyGlyphBlt = miPolyGlyphBlt; } /* special case ImageGlyphBlt for terminal emulator fonts */ if (TERMINALFONT(pGC->font)) pGC->ops->ImageGlyphBlt = CreatorTEGlyphBlt; else pGC->ops->ImageGlyphBlt = miImageGlyphBlt; } } static __inline__ void CreatorNewFillSpans(GCPtr pGC, cfbPrivGCPtr devPriv, CreatorPrivGCPtr gcPriv, int accel) { if (pGC->fillStyle == FillSolid) { pGC->ops->FillSpans = CreatorSolidSpansGeneralStub; } else if(pGC->fillStyle == FillTiled) { if (pGC->pRotatedPixmap) { int pmsk = (pGC->depth == 8 ? 0xff : 0xffffff); if (pGC->alu == GXcopy && (pGC->planemask & pmsk) == pmsk) pGC->ops->FillSpans = CreatorTile32FSCopyStub; else pGC->ops->FillSpans = CreatorTile32FSGeneralStub; } else pGC->ops->FillSpans = CreatorUnnaturalTileFSStub; } else if(pGC->fillStyle == FillStippled) { if (pGC->pRotatedPixmap) pGC->ops->FillSpans = Creator8Stipple32FSStub; else pGC->ops->FillSpans = CreatorUnnaturalStippleFSStub; } else if(pGC->fillStyle == FillOpaqueStippled) { if (pGC->pRotatedPixmap) pGC->ops->FillSpans = Creator8OpaqueStipple32FSStub; else pGC->ops->FillSpans = CreatorUnnaturalStippleFSStub; } else FatalError("CreatorValidateGC: illegal fillStyle\n"); if (accel) pGC->ops->FillSpans = CreatorFillSpans; } static __inline__ void CreatorNewFillArea(GCPtr pGC, cfbPrivGCPtr devPriv, CreatorPrivGCPtr gcPriv, int accel) { if (accel) { pGC->ops->PolyFillRect = CreatorPolyFillRect; pGC->ops->PolyFillArc = CreatorPolyFillArcSolid; } else { pGC->ops->PolyFillRect = miPolyFillRect; if(pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) pGC->ops->PolyFillRect = CreatorPolyFillRectStub; pGC->ops->PolyFillArc = miPolyFillArc; } pGC->ops->PushPixels = mfbPushPixels; } void CreatorValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { int mask; /* stateChanges */ int new_rrop; int new_line, new_text, new_fillspans, new_fillarea; int new_rotate; int xrot, yrot; /* flags for changing the proc vector */ cfbPrivGCPtr devPriv; CreatorPrivGCPtr gcPriv; int oneRect, type; int accel, drawableChanged; FFBPtr pFfb = GET_FFB_FROM_SCREEN(pDrawable->pScreen); gcPriv = CreatorGetGCPrivate (pGC); type = pFfb->vtSema ? -1 : pDrawable->type; if (type != DRAWABLE_WINDOW) { if (gcPriv->type == DRAWABLE_WINDOW) { extern GCOps cfbNonTEOps; extern GCOps cfb32NonTEOps; miDestroyGCOps (pGC->ops); if (pGC->depth == 8) pGC->ops = &cfbNonTEOps; else pGC->ops = &cfb32NonTEOps; changes = (1 << (GCLastBit+1)) - 1; pGC->stateChanges = changes; gcPriv->type = type; } if (pGC->depth == 8) cfbValidateGC (pGC, changes, pDrawable); else cfb32ValidateGC (pGC, changes, pDrawable); /* Our high speed VIS copyarea can * be used on pixmaps too. * But don't clobber someones ops prototype!! */ if (!pGC->ops->devPrivate.val) { pGC->ops = miCreateGCOps(pGC->ops); pGC->ops->devPrivate.val = 1; } pGC->ops->CopyArea = CreatorCopyArea; return; } if (gcPriv->type != DRAWABLE_WINDOW) { changes = (1 << (GCLastBit+1)) - 1; gcPriv->type = DRAWABLE_WINDOW; } new_rotate = pGC->lastWinOrg.x != pDrawable->x || pGC->lastWinOrg.y != pDrawable->y; if(new_rotate != 0) { pGC->lastWinOrg.x = pDrawable->x; pGC->lastWinOrg.y = pDrawable->y; } devPriv = cfbGetGCPrivate(pGC); new_rrop = FALSE; new_line = FALSE; new_text = FALSE; new_fillspans = FALSE; new_fillarea = FALSE; drawableChanged = (pDrawable->serialNumber != (pGC->serialNumber & (DRAWABLE_SERIAL_BITS))); #define CLIP_BITS (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode) /* If the client clip is different or moved OR the subwindowMode has * changed OR the window's clip has changed since the last validation, * we need to recompute the composite clip . */ if ((changes & CLIP_BITS) != 0 || drawableChanged) { miComputeCompositeClip(pGC, pDrawable); oneRect = REGION_NUM_RECTS(cfbGetCompositeClip(pGC)) == 1; if (oneRect != devPriv->oneRect) { new_line = TRUE; devPriv->oneRect = oneRect; } } /* A while loop with a switch statement inside? No thanks. -DaveM */ mask = changes; if((mask & (GCFunction | GCForeground | GCBackground | GCPlaneMask)) != 0) new_rrop = TRUE; if((mask & (GCPlaneMask | GCFillStyle | GCFont)) != 0) new_text = TRUE; if((mask & (GCLineStyle | GCLineWidth | GCFillStyle | GCCapStyle)) != 0) new_line = TRUE; if((mask & (GCFillStyle | GCTile | GCStipple)) != 0) new_fillspans = new_fillarea = TRUE; if(new_rotate == FALSE && (mask & (GCTileStipXOrigin | GCTileStipYOrigin)) != 0) new_rotate = TRUE; if((mask & GCStipple) != 0) { if(pGC->stipple) { int width = pGC->stipple->drawable.width; PixmapPtr nstipple; if ((width <= 32) && !(width & (width - 1))) { int depth = pGC->depth; nstipple = (depth == 8 ? cfbCopyPixmap(pGC->stipple) : cfb32CopyPixmap(pGC->stipple)); if (nstipple) { if (depth == 8) cfbPadPixmap(nstipple); else cfb32PadPixmap(nstipple); (*pGC->pScreen->DestroyPixmap)(pGC->stipple); pGC->stipple = nstipple; } } } } /* If the drawable has changed, check its depth and ensure suitable * entries are in the proc vector. */ if (drawableChanged) new_fillspans = TRUE; /* deal with FillSpans later */ if (new_rotate || new_fillspans) { Bool new_pix = FALSE; xrot = pGC->patOrg.x + pDrawable->x; yrot = pGC->patOrg.y + pDrawable->y; if (!CreatorCheckFill (pGC, pDrawable)) { switch (pGC->fillStyle) { case FillTiled: if (!pGC->tileIsPixel) { int width = pGC->tile.pixmap->drawable.width; if (pGC->depth == 8) width *= 8; else width *= 32; if ((width <= 32) && !(width & (width - 1))) { if (pGC->depth == 8) cfbCopyRotatePixmap(pGC->tile.pixmap, &pGC->pRotatedPixmap, xrot, yrot); else cfb32CopyRotatePixmap(pGC->tile.pixmap, &pGC->pRotatedPixmap, xrot, yrot); new_pix = TRUE; } } break; case FillStippled: case FillOpaqueStippled: { int width = pGC->stipple->drawable.width; if ((width <= 32) && !(width & (width - 1))) { mfbCopyRotatePixmap(pGC->stipple, &pGC->pRotatedPixmap, xrot, yrot); new_pix = TRUE; } } break; } } if (!new_pix && pGC->pRotatedPixmap) { (*pGC->pScreen->DestroyPixmap)(pGC->pRotatedPixmap); pGC->pRotatedPixmap = (PixmapPtr) NULL; } } if (new_rrop) { int old_rrop; if (gcPriv->stipple) { if (pGC->fillStyle == FillStippled) gcPriv->stipple->alu = pGC->alu | FFB_ROP_EDIT_BIT; else gcPriv->stipple->alu = pGC->alu; if (pGC->fillStyle != FillTiled) { gcPriv->stipple->fg = pGC->fgPixel; gcPriv->stipple->bg = pGC->bgPixel; } } old_rrop = devPriv->rop; if (pGC->depth == 8) devPriv->rop = cfbReduceRasterOp (pGC->alu, pGC->fgPixel, pGC->planemask, &devPriv->and, &devPriv->xor); else devPriv->rop = cfb32ReduceRasterOp (pGC->alu, pGC->fgPixel, pGC->planemask, &devPriv->and, &devPriv->xor); if (old_rrop == devPriv->rop) new_rrop = FALSE; else { new_line = TRUE; new_text = TRUE; new_fillspans = TRUE; new_fillarea = TRUE; } } if (new_rrop || new_fillspans || new_text || new_fillarea || new_line) { GCOps *newops; int using_creator_ops = 0; if ((newops = CreatorMatchCommon (pGC, devPriv))) { if (pGC->ops->devPrivate.val) miDestroyGCOps (pGC->ops); pGC->ops = newops; new_rrop = new_line = new_fillspans = new_text = new_fillarea = 0; using_creator_ops = 1; } else { if (!pGC->ops->devPrivate.val) { pGC->ops = miCreateGCOps (pGC->ops); pGC->ops->devPrivate.val = 1; } /* We have to make sure the copyarea op always * points to our special routine as it maintains the * synchronization between the raster processor and direct * access to the frame buffer. */ pGC->ops->CopyArea = CreatorCopyArea; } if (pGC->depth == 8) newops = cfbMatchCommon(pGC, devPriv); else newops = cfb32MatchCommon(pGC, devPriv); if (newops) { gcPriv->PolySegment = newops->PolySegment; gcPriv->Polylines = newops->Polylines; if (using_creator_ops) { /* Fixup line/segment backup ops. */ if (pGC->ops->PolySegment == CreatorPolySegment) gcPriv->PolySegment = CreatorSegmentSSStub; if (pGC->ops->Polylines == CreatorPolylines) gcPriv->Polylines = CreatorLineSSStub; } } } accel = pGC->fillStyle == FillSolid || gcPriv->stipple; /* deal with the changes we've collected */ if (new_line) CreatorNewLine(pGC, devPriv, gcPriv, accel); if (new_text && pGC->font) CreatorNewGlyph(pGC, gcPriv); if (new_fillspans) CreatorNewFillSpans(pGC, devPriv, gcPriv, accel); if (new_fillarea) CreatorNewFillArea(pGC, devPriv, gcPriv, accel); } GCFuncs CreatorGCFuncs = { CreatorValidateGC, miChangeGC, miCopyGC, CreatorDestroyGC, miChangeClip, miDestroyClip, miCopyClip }; Bool CreatorCreateGC (GCPtr pGC) { CreatorPrivGCPtr gcPriv; if (pGC->depth == 1) return mfbCreateGC(pGC); if (pGC->depth == 8) { if (!cfbCreateGC(pGC)) return FALSE; } else { if (!cfb32CreateGC(pGC)) return FALSE; } if (pGC->depth == 8) pGC->ops = &CreatorNonTEOps8; else pGC->ops = &CreatorNonTEOps32; pGC->funcs = &CreatorGCFuncs; gcPriv = CreatorGetGCPrivate(pGC); gcPriv->type = DRAWABLE_WINDOW; gcPriv->linepat = 0; gcPriv->stipple = 0; gcPriv->PolySegment = CreatorSegmentSSStub; gcPriv->Polylines = CreatorLineSSStub; return TRUE; }