/* * Copyright © 2004 David Reveman * * 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 * David Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * David Reveman makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL DAVID REVEMAN 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: David Reveman */ #include "xgl.h" #include "fb.h" #include "gcstruct.h" #include "migc.h" #define XGL_GC_OP_FALLBACK_PROLOGUE(pDrawable) \ xglSyncDamageBoxBits (pDrawable); \ XGL_GC_UNWRAP (funcs); \ XGL_GC_UNWRAP (ops) #define XGL_GC_OP_FALLBACK_EPILOGUE(pDrawable) \ XGL_GC_WRAP (funcs, (GCFuncs *) &xglGCFuncs); \ XGL_GC_WRAP (ops, (GCOps *) &xglGCOps); \ xglAddCurrentSurfaceDamage (pDrawable) #define XGL_GC_FILL_OP_FALLBACK_PROLOGUE(pDrawable) \ switch (pGC->fillStyle) { \ case FillSolid: \ break; \ case FillStippled: \ case FillOpaqueStippled: \ if (!xglSyncBits (&pGC->stipple->drawable, NullBox)) \ FatalError (XGL_SW_FAILURE_STRING); \ break; \ case FillTiled: \ if (!xglSyncBits (&pGC->tile.pixmap->drawable, NullBox)) \ FatalError (XGL_SW_FAILURE_STRING); \ break; \ } \ XGL_GC_OP_FALLBACK_PROLOGUE (pDrawable) static const GCFuncs xglGCFuncs = { xglValidateGC, miChangeGC, miCopyGC, xglDestroyGC, miChangeClip, miDestroyClip, miCopyClip }; static const GCOps xglGCOps = { xglFillSpans, xglSetSpans, xglPutImage, xglCopyArea, xglCopyPlane, xglPolyPoint, xglPolylines, xglPolySegment, miPolyRectangle, xglPolyArc, miFillPolygon, xglPolyFillRect, xglPolyFillArc, miPolyText8, miPolyText16, miImageText8, miImageText16, xglImageGlyphBlt, xglPolyGlyphBlt, xglPushPixels }; void xglFillSpans (DrawablePtr pDrawable, GCPtr pGC, int nspans, DDXPointPtr ppt, int *pwidth, int fSorted) { XGL_GC_PRIV (pGC); if (pGCPriv->flags || pGC->fillStyle == FillStippled) { XGL_GC_FILL_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->FillSpans) (pDrawable, pGC, nspans, ppt, pwidth, fSorted); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } else { /* xglFillSpan handles fall-back */ xglFillSpan (pDrawable, pGC, nspans, ppt, pwidth); } } void xglSetSpans (DrawablePtr pDrawable, GCPtr pGC, char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { XGL_GC_PRIV (pGC); XGL_GC_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } void xglPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { XGL_GC_PRIV (pGC); if (pGC->alu != GXcopy || (pGCPriv->flags & xglGCPlaneMaskFlag)) { XGL_GC_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } else { RegionPtr pClip = pGC->pCompositeClip; RegionRec region; BoxRec box; XGL_DRAWABLE_PIXMAP (pDrawable); if (!xglMapPixmapBits (pPixmap)) FatalError (XGL_SW_FAILURE_STRING); XGL_GC_UNWRAP (funcs); XGL_GC_UNWRAP (ops); (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); XGL_GC_WRAP (funcs, (GCFuncs *) &xglGCFuncs); XGL_GC_WRAP (ops, (GCOps *) &xglGCOps); box.x1 = pDrawable->x + x; box.y1 = pDrawable->y + y; box.x2 = box.x1 + w; box.y2 = box.y1 + h; REGION_INIT (pDrawable->pScreen, ®ion, &box, 1); REGION_INTERSECT (pDrawable->pScreen, ®ion, pClip, ®ion); xglAddSurfaceDamage (pDrawable, ®ion); REGION_UNINIT (pDrawable->pScreen, ®ion); } } RegionPtr xglCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcX, int srcY, int w, int h, int dstX, int dstY) { RegionPtr pRegion; BoxRec box; XGL_GC_PRIV (pGC); box.x1 = pSrc->x + srcX; box.y1 = pSrc->y + srcY; box.x2 = box.x1 + w; box.y2 = box.y1 + h; if (pGC->alu != GXcopy || pGCPriv->flags) { if (!xglSyncBits (pSrc, &box)) FatalError (XGL_SW_FAILURE_STRING); XGL_GC_OP_FALLBACK_PROLOGUE (pDst); pRegion = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcX, srcY, w, h, dstX, dstY); XGL_GC_OP_FALLBACK_EPILOGUE (pDst); } else { /* xglCopyProc handles fall-back */ pRegion = fbDoCopy (pSrc, pDst, pGC, srcX, srcY, w, h, dstX, dstY, xglCopyProc, 0, (void *) &box); } return pRegion; } RegionPtr xglCopyPlane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcX, int srcY, int w, int h, int dstX, int dstY, unsigned long bitPlane) { RegionPtr pRegion; BoxRec box; XGL_GC_PRIV (pGC); box.x1 = pSrc->x + srcX; box.y1 = pSrc->y + srcY; box.x2 = box.x1 + w; box.y2 = box.y1 + h; if (!xglSyncBits (pSrc, &box)) FatalError (XGL_SW_FAILURE_STRING); XGL_GC_OP_FALLBACK_PROLOGUE (pDst); pRegion = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcX, srcY, w, h, dstX, dstY, bitPlane); XGL_GC_OP_FALLBACK_EPILOGUE (pDst); return pRegion; } void xglPolyPoint (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit) { XGL_GC_PRIV (pGC); XGL_GC_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } void xglPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { if (pGC->lineWidth == 0) { XGL_GC_PRIV (pGC); if (!pGCPriv->flags) { if (pGC->lineStyle == LineSolid) { if (xglFillLine (pDrawable, pGC, mode, npt, ppt)) return; } } XGL_GC_FILL_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppt); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } else { if (pGC->lineStyle != LineSolid) miWideDash (pDrawable, pGC, mode, npt, ppt); else miWideLine (pDrawable, pGC, mode, npt, ppt); } } void xglPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nsegInit, xSegment *pSegInit) { if (pGC->lineWidth == 0) { XGL_GC_PRIV (pGC); if (!pGCPriv->flags) { if (pGC->lineStyle == LineSolid) { if (xglFillSegment (pDrawable, pGC, nsegInit, pSegInit)) return; } } XGL_GC_FILL_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PolySegment) (pDrawable, pGC, nsegInit, pSegInit); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } else miPolySegment (pDrawable, pGC, nsegInit, pSegInit); } void xglPolyArc (DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *pArcs) { if (pGC->lineWidth == 0) { XGL_GC_PRIV (pGC); XGL_GC_FILL_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, pArcs); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } else miPolyArc (pDrawable, pGC, narcs, pArcs); } void xglPolyFillRect (DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect) { XGL_GC_PRIV (pGC); if (pGC->fillStyle == FillStippled || pGCPriv->flags) { XGL_GC_FILL_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrect, prect); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } else { /* xglFillRect handles fall-back */ xglFillRect (pDrawable, pGC, nrect, prect); } } void xglPolyFillArc (DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *pArcs) { XGL_GC_PRIV (pGC); XGL_GC_FILL_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, pArcs); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } void xglImageGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { XGL_GC_PRIV (pGC); if (!pGCPriv->flags) { if (xglSolidGlyph (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)) return; } XGL_GC_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } void xglPolyGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { XGL_GC_PRIV (pGC); if (!pGCPriv->flags) { if (xglFillGlyph (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)) return; } XGL_GC_FILL_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } void xglPushPixels (GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, int w, int h, int x, int y) { XGL_GC_PRIV (pGC); if (!xglSyncBits (&pBitmap->drawable, NullBox)) FatalError (XGL_SW_FAILURE_STRING); XGL_GC_OP_FALLBACK_PROLOGUE (pDrawable); (*pGC->ops->PushPixels) (pGC, pBitmap, pDrawable, w, h, x, y); XGL_GC_OP_FALLBACK_EPILOGUE (pDrawable); } Bool xglCreateGC (GCPtr pGC) { ScreenPtr pScreen = pGC->pScreen; Bool ret; XGL_SCREEN_PRIV (pScreen); XGL_GC_PRIV (pGC); XGL_SCREEN_UNWRAP (CreateGC); ret = (*pScreen->CreateGC) (pGC); XGL_SCREEN_WRAP (CreateGC, xglCreateGC); XGL_GC_WRAP (funcs, (GCFuncs *) &xglGCFuncs); XGL_GC_WRAP (ops, (GCOps *) &xglGCOps); pGCPriv->flags = 0; pGCPriv->op = GLITZ_OPERATOR_SRC; pGCPriv->fg = NULL; pGCPriv->bg = NULL; pGCPriv->id = ~0; return ret; } void xglDestroyGC (GCPtr pGC) { XGL_GC_PRIV (pGC); if (pGCPriv->fg) glitz_surface_destroy (pGCPriv->fg); if (pGCPriv->bg) glitz_surface_destroy (pGCPriv->bg); XGL_GC_UNWRAP (funcs); XGL_GC_UNWRAP (ops); (*pGC->funcs->DestroyGC) (pGC); XGL_GC_WRAP (funcs, (GCFuncs *) &xglGCFuncs); XGL_GC_WRAP (ops, (GCOps *) &xglGCOps); } void xglValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { XGL_GC_PRIV (pGC); if (changes & GCTile) { if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width * pDrawable->bitsPerPixel)) xglSyncBits (&pGC->tile.pixmap->drawable, NULL); } if (changes & GCStipple) { if (pGC->stipple) xglSyncBits (&pGC->stipple->drawable, NULL); } XGL_GC_UNWRAP (funcs); XGL_GC_UNWRAP (ops); (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); XGL_GC_WRAP (funcs, (GCFuncs *) &xglGCFuncs); XGL_GC_WRAP (ops, (GCOps *) &xglGCOps); if (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)) { XGL_DRAWABLE_PIXMAP_PRIV (pDrawable); if (pPixmapPriv->pVisual && pPixmapPriv->pVisual->format.surface) { glitz_format_t *format; format = pPixmapPriv->pVisual->format.surface; if (format->id != pGCPriv->id) { XGL_SCREEN_PRIV (pDrawable->pScreen); pGCPriv->flags |= xglGCSoftwareDrawableFlag; if (pGCPriv->fg) glitz_surface_destroy (pGCPriv->fg); pGCPriv->fg = glitz_surface_create (pScreenPriv->drawable, format, 1, 1, 0, NULL); if (pGCPriv->fg) glitz_surface_set_fill (pGCPriv->fg, GLITZ_FILL_REPEAT); if (pGCPriv->bg) glitz_surface_destroy (pGCPriv->bg); pGCPriv->bg = glitz_surface_create (pScreenPriv->drawable, format, 1, 1, 0, NULL); if (pGCPriv->bg) glitz_surface_set_fill (pGCPriv->bg, GLITZ_FILL_REPEAT); pGCPriv->id = format->id; if (pGCPriv->fg && pGCPriv->bg) { changes |= (GCForeground | GCBackground); pGCPriv->flags &= ~xglGCSoftwareDrawableFlag; } } } else pGCPriv->flags |= xglGCSoftwareDrawableFlag; } if (changes & GCFunction) { switch (pGC->alu) { case GXclear: pGCPriv->op = GLITZ_OPERATOR_CLEAR; pGCPriv->flags &= ~xglGCBadFunctionFlag; break; case GXcopy: pGCPriv->op = GLITZ_OPERATOR_SRC; pGCPriv->flags &= ~xglGCBadFunctionFlag; break; case GXnoop: pGCPriv->op = GLITZ_OPERATOR_DST; pGCPriv->flags &= ~xglGCBadFunctionFlag; break; default: pGCPriv->flags |= xglGCBadFunctionFlag; break; } } if (changes & GCPlaneMask) { FbBits mask; mask = FbFullMask (pDrawable->depth); if ((pGC->planemask & mask) != mask) pGCPriv->flags |= xglGCPlaneMaskFlag; else pGCPriv->flags &= ~xglGCPlaneMaskFlag; } if (!(pGCPriv->flags & xglGCSoftwareDrawableFlag)) { if (changes & (GCForeground | GCBackground)) { glitz_pixel_format_t format; glitz_buffer_t *buffer; CARD32 pixel; XGL_DRAWABLE_PIXMAP_PRIV (pDrawable); format.fourcc = GLITZ_FOURCC_RGB; format.masks = pPixmapPriv->pVisual->pPixel->masks; format.xoffset = 0; format.skip_lines = 0; format.bytes_per_line = sizeof (CARD32); format.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; buffer = glitz_buffer_create_for_data (&pixel); if (changes & GCForeground) { pixel = pGC->fgPixel; glitz_set_pixels (pGCPriv->fg, 0, 0, 1, 1, &format, buffer); } if (changes & GCBackground) { pixel = pGC->bgPixel; glitz_set_pixels (pGCPriv->bg, 0, 0, 1, 1, &format, buffer); } glitz_buffer_destroy (buffer); } } }