/* * 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" static glitz_buffer_hint_t xglPixmapUsageHints[] = { (glitz_buffer_hint_t) 0, /* reserved for system memory */ GLITZ_BUFFER_HINT_STREAM_DRAW, GLITZ_BUFFER_HINT_STREAM_READ, GLITZ_BUFFER_HINT_STREAM_COPY, GLITZ_BUFFER_HINT_STATIC_DRAW, GLITZ_BUFFER_HINT_STATIC_READ, GLITZ_BUFFER_HINT_STATIC_COPY, GLITZ_BUFFER_HINT_DYNAMIC_DRAW, GLITZ_BUFFER_HINT_DYNAMIC_READ, GLITZ_BUFFER_HINT_DYNAMIC_COPY }; #define NUM_XGL_PIXMAP_USAGE_HINTS \ (sizeof (xglPixmapUsageHints) / sizeof (xglPixmapUsageHints[0])) #define XGL_PIXMAP_USAGE_HINT(hint) (xglPixmapUsageHints[hint]) static void xglPixmapDamageReport (DamagePtr pDamage, RegionPtr pRegion, void *closure) { PixmapPtr pPixmap = (PixmapPtr) closure; BoxPtr pExt; XGL_PIXMAP_PRIV (pPixmap); pExt = REGION_EXTENTS (pPixmap->drawable.pScreen, pRegion); if (BOX_NOTEMPTY (&pPixmapPriv->damageBox)) { if (pExt->x1 < pPixmapPriv->damageBox.x1) pPixmapPriv->damageBox.x1 = pExt->x1; if (pExt->y1 < pPixmapPriv->damageBox.y1) pPixmapPriv->damageBox.y1 = pExt->y1; if (pExt->x2 > pPixmapPriv->damageBox.x2) pPixmapPriv->damageBox.x2 = pExt->x2; if (pExt->y2 > pPixmapPriv->damageBox.y2) pPixmapPriv->damageBox.y2 = pExt->y2; } else pPixmapPriv->damageBox = *pExt; } static Bool xglPixmapCreateDamage (PixmapPtr pPixmap) { XGL_PIXMAP_PRIV (pPixmap); pPixmapPriv->pDamage = DamageCreate (xglPixmapDamageReport, (DamageDestroyFunc) 0, DamageReportRawRegion, TRUE, pPixmap->drawable.pScreen, (void *) pPixmap); if (!pPixmapPriv->pDamage) return FALSE; DamageRegister (&pPixmap->drawable, pPixmapPriv->pDamage); return TRUE; } void xglSetPixmapVisual (PixmapPtr pPixmap, xglVisualPtr pVisual) { xglVisualPtr pOldVisual; XGL_PIXMAP_PRIV (pPixmap); pOldVisual = pPixmapPriv->pVisual; if (pOldVisual && pVisual) { glitz_surface_t *surface; if (pOldVisual->vid != pVisual->vid) { surface = pPixmapPriv->surface; if (surface) { glitz_drawable_t *drawable; drawable = glitz_surface_get_attached_drawable (surface); if (drawable) { if (pOldVisual->format.drawable->id != pVisual->format.drawable->id) { glitz_surface_detach (pPixmapPriv->surface); pPixmapPriv->target = xglPixmapTargetOut; } } if (pOldVisual->format.surface->id != pVisual->format.surface->id) { xglSyncBits (&pPixmap->drawable, NULL); glitz_surface_destroy (pPixmapPriv->surface); pPixmapPriv->surface = 0; } } } } else if (pOldVisual) { if (pPixmapPriv->surface) { xglSyncBits (&pPixmap->drawable, NULL); glitz_surface_destroy (pPixmapPriv->surface); pPixmapPriv->surface = 0; } pPixmapPriv->target = xglPixmapTargetNo; } pPixmapPriv->pVisual = pVisual; if (pPixmapPriv->pVisual && pPixmapPriv->pVisual->format.surface) { if (!pPixmapPriv->pDamage) { if (!xglPixmapCreateDamage (pPixmap)) FatalError (XGL_SW_FAILURE_STRING); } } } static Bool xglPixmapSurfaceInit (PixmapPtr pPixmap, unsigned long features, int width, int height) { BoxRec box; XGL_PIXMAP_PRIV (pPixmap); pPixmapPriv->surface = NULL; pPixmapPriv->drawable = NULL; pPixmapPriv->acceleratedTile = FALSE; pPixmapPriv->pictureMask = ~0; pPixmapPriv->target = xglPixmapTargetNo; box.x1 = 0; box.y1 = 0; box.x2 = width; box.y2 = height; REGION_INIT (pScreen, &pPixmapPriv->bitRegion, &box, 1); pPixmapPriv->pVisual = xglFindVisualWithDepth (pPixmap->drawable.pScreen, pPixmap->drawable.depth); if (pPixmapPriv->pVisual) { XGL_SCREEN_PRIV (pPixmap->drawable.pScreen); /* general pixmap acceleration */ if (pPixmapPriv->pVisual->format.drawable && pScreenPriv->accel.pixmap.enabled && xglCheckPixmapSize (pPixmap, &pScreenPriv->accel.pixmap.size)) pPixmapPriv->target = xglPixmapTargetOut; } if (pPixmapPriv->pVisual && pPixmapPriv->pVisual->format.surface) { if (!pPixmapPriv->pDamage) { if (!xglPixmapCreateDamage (pPixmap)) FatalError (XGL_SW_FAILURE_STRING); } if (width && height) { if (width == 1 && height == 1) { pPixmapPriv->acceleratedTile = TRUE; } else if (features & GLITZ_FEATURE_TEXTURE_BORDER_CLAMP_MASK) { if ((features & GLITZ_FEATURE_TEXTURE_NON_POWER_OF_TWO_MASK) || (POWER_OF_TWO (width) && POWER_OF_TWO (height))) pPixmapPriv->acceleratedTile = TRUE; } } } return TRUE; } PixmapPtr xglCreatePixmap (ScreenPtr pScreen, int width, int height, int depth, unsigned usage_hint) { xglPixmapPtr pPixmapPriv; PixmapPtr pPixmap; XGL_SCREEN_PRIV (pScreen); pPixmap = AllocatePixmap (pScreen, 0); if (!pPixmap) return NullPixmap; pPixmap->drawable.type = DRAWABLE_PIXMAP; pPixmap->drawable.class = 0; pPixmap->drawable.pScreen = pScreen; pPixmap->drawable.depth = depth; pPixmap->drawable.bitsPerPixel = BitsPerPixel (depth); pPixmap->drawable.id = 0; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap->drawable.x = 0; pPixmap->drawable.y = 0; pPixmap->drawable.width = width; pPixmap->drawable.height = height; #ifdef COMPOSITE pPixmap->screen_x = 0; pPixmap->screen_y = 0; #endif pPixmap->devKind = 0; pPixmap->refcnt = 1; pPixmap->devPrivate.ptr = 0; pPixmap->usage_hint = usage_hint; pPixmapPriv = XGL_GET_PIXMAP_PRIV (pPixmap); pPixmapPriv->pVisual = NULL; pPixmapPriv->pDamage = NULL; if (!xglPixmapSurfaceInit (pPixmap, pScreenPriv->features, width, height)) return NullPixmap; pPixmapPriv->buffer = NULL; pPixmapPriv->bits = (pointer) 0; pPixmapPriv->stride = 0; pPixmapPriv->pGeometry = NULL; pPixmapPriv->allBits = TRUE; pPixmapPriv->damageBox = miEmptyBox; return pPixmap; } void xglFiniPixmap (PixmapPtr pPixmap) { XGL_PIXMAP_PRIV (pPixmap); if (pPixmap->devPrivate.ptr) { if (pPixmapPriv->buffer) glitz_buffer_unmap (pPixmapPriv->buffer); } if (pPixmapPriv->pGeometry) GEOMETRY_UNINIT (pPixmapPriv->pGeometry); if (pPixmapPriv->buffer) glitz_buffer_destroy (pPixmapPriv->buffer); if (pPixmapPriv->bits) xfree (pPixmapPriv->bits); REGION_UNINIT (pPixmap->drawable.pScreen, &pPixmapPriv->bitRegion); if (pPixmapPriv->drawable) glitz_drawable_destroy (pPixmapPriv->drawable); if (pPixmapPriv->surface) glitz_surface_destroy (pPixmapPriv->surface); } Bool xglDestroyPixmap (PixmapPtr pPixmap) { if (--pPixmap->refcnt) return TRUE; xglFiniPixmap (pPixmap); dixFreePrivates(pPixmap->devPrivates); xfree (pPixmap); return TRUE; } Bool xglModifyPixmapHeader (PixmapPtr pPixmap, int width, int height, int depth, int bitsPerPixel, int devKind, pointer pPixData) { xglScreenPtr pScreenPriv; xglPixmapPtr pPixmapPriv; int oldWidth, oldHeight; if (!pPixmap) return FALSE; pScreenPriv = XGL_GET_SCREEN_PRIV (pPixmap->drawable.pScreen); pPixmapPriv = XGL_GET_PIXMAP_PRIV (pPixmap); oldWidth = pPixmap->drawable.width; oldHeight = pPixmap->drawable.height; if ((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) && (devKind > 0) && pPixData) { pPixmap->drawable.depth = depth; pPixmap->drawable.bitsPerPixel = bitsPerPixel; pPixmap->drawable.id = 0; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap->drawable.x = 0; pPixmap->drawable.y = 0; pPixmap->drawable.width = width; pPixmap->drawable.height = height; pPixmapPriv->stride = devKind; pPixmap->refcnt = 1; } else { if (width > 0) pPixmap->drawable.width = width; if (height > 0) pPixmap->drawable.height = height; if (depth > 0) pPixmap->drawable.depth = depth; if (bitsPerPixel > 0) pPixmap->drawable.bitsPerPixel = bitsPerPixel; else if ((bitsPerPixel < 0) && (depth > 0)) pPixmap->drawable.bitsPerPixel = BitsPerPixel (depth); if (devKind > 0) pPixmapPriv->stride = devKind; else if ((devKind < 0) && ((width > 0) || (depth > 0))) pPixmapPriv->stride = PixmapBytePad (pPixmap->drawable.width, pPixmap->drawable.depth); } if (pPixmap->drawable.width != oldWidth || pPixmap->drawable.height != oldHeight) { pPixmapPriv->pVisual = NULL; pPixmapPriv->target = xglPixmapTargetNo; if (pPixmapPriv->drawable) glitz_drawable_destroy (pPixmapPriv->drawable); if (pPixmapPriv->surface) glitz_surface_destroy (pPixmapPriv->surface); REGION_UNINIT (pPixmap->drawable.pScreen, &pPixmapPriv->bitRegion); if (!xglPixmapSurfaceInit (pPixmap, pScreenPriv->features, pPixmap->drawable.width, pPixmap->drawable.height)) return FALSE; } if (pPixData) { BoxRec box; if (pPixmap->devPrivate.ptr) { if (pPixmapPriv->buffer) glitz_buffer_unmap (pPixmapPriv->buffer); pPixmap->devPrivate.ptr = 0; } if (pPixmapPriv->pGeometry) { GEOMETRY_UNINIT (pPixmapPriv->pGeometry); pPixmapPriv->pGeometry = NULL; } if (pPixmapPriv->buffer) glitz_buffer_destroy (pPixmapPriv->buffer); if (pPixmapPriv->bits) xfree (pPixmapPriv->bits); pPixmapPriv->bits = (pointer) 0; pPixmapPriv->buffer = glitz_buffer_create_for_data (pPixData); if (!pPixmapPriv->buffer) return FALSE; pPixmapPriv->allBits = TRUE; box.x1 = 0; box.y1 = 0; box.x2 = pPixmap->drawable.width; box.y2 = pPixmap->drawable.height; REGION_UNINIT (pPixmap->drawable.pScreen, &pPixmapPriv->bitRegion); REGION_INIT (pPixmap->drawable.pScreen, &pPixmapPriv->bitRegion, &box, 1); if (pPixmapPriv->pDamage) { RegionPtr pRegion; pRegion = DamageRegion (pPixmapPriv->pDamage); REGION_UNINIT (pPixmap->drawable.pScreen, pRegion); REGION_INIT (pPixmap->drawable.pScreen, pRegion, NullBox, 0); REGION_SUBTRACT (pPixmap->drawable.pScreen, pRegion, &pPixmapPriv->bitRegion, pRegion); } } /* * Screen pixmap */ if (!pScreenPriv->pScreenPixmap || pScreenPriv->pScreenPixmap == pPixmap) { if (!pPixmapPriv->drawable) { glitz_drawable_reference (pScreenPriv->drawable); pPixmapPriv->drawable = pScreenPriv->drawable; } if (!pPixmapPriv->surface) { glitz_surface_reference (pScreenPriv->surface); pPixmapPriv->surface = pScreenPriv->surface; } pPixmapPriv->pVisual = pScreenPriv->rootVisual; pPixmapPriv->target = xglPixmapTargetIn; if (!pScreenPriv->pScreenPixmap) pScreenPriv->pScreenPixmap = pPixmap; } return TRUE; } RegionPtr xglPixmapToRegion (PixmapPtr pPixmap) { ScreenPtr pScreen = pPixmap->drawable.pScreen; RegionPtr pRegion; XGL_SCREEN_PRIV (pScreen); if (!xglSyncBits (&pPixmap->drawable, NullBox)) FatalError (XGL_SW_FAILURE_STRING); XGL_SCREEN_UNWRAP (BitmapToRegion); pRegion = (*pScreen->BitmapToRegion) (pPixmap); XGL_SCREEN_WRAP (BitmapToRegion, xglPixmapToRegion); return pRegion; } xglGeometryPtr xglPixmapToGeometry (PixmapPtr pPixmap, int xOff, int yOff) { XGL_PIXMAP_PRIV (pPixmap); if (pPixmap->devPrivate.ptr) xglUnmapPixmapBits (pPixmap); if (!pPixmapPriv->pGeometry) { xglGeometryPtr pGeometry; if (!pPixmapPriv->buffer) { if (!xglAllocatePixmapBits (pPixmap, XGL_PIXMAP_USAGE_HINT_DEFAULT)) return NULL; } pGeometry = xalloc (sizeof (xglGeometryRec)); if (!pGeometry) return NULL; GEOMETRY_INIT (pPixmap->drawable.pScreen, pGeometry, GLITZ_GEOMETRY_TYPE_BITMAP, GEOMETRY_USAGE_DYNAMIC, 0); GEOMETRY_SET_BUFFER (pGeometry, pPixmapPriv->buffer); if (pPixmapPriv->stride < 0) { pGeometry->f.bitmap.bytes_per_line = -pPixmapPriv->stride; pGeometry->f.bitmap.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; } else { pGeometry->f.bitmap.bytes_per_line = pPixmapPriv->stride; pGeometry->f.bitmap.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; } pGeometry->f.bitmap.pad = ((1 + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); pGeometry->width = pPixmap->drawable.width; pGeometry->count = pPixmap->drawable.height; pPixmapPriv->pGeometry = pGeometry; } pPixmapPriv->pGeometry->xOff = xOff << 16; pPixmapPriv->pGeometry->yOff = yOff << 16; return pPixmapPriv->pGeometry; } Bool xglCreatePixmapSurface (PixmapPtr pPixmap) { XGL_PIXMAP_PRIV (pPixmap); if (!pPixmapPriv->surface) { XGL_SCREEN_PRIV (pPixmap->drawable.pScreen); if (!pPixmapPriv->pVisual || !pPixmapPriv->pVisual->format.surface) return FALSE; pPixmapPriv->surface = glitz_surface_create (pScreenPriv->drawable, pPixmapPriv->pVisual->format.surface, pPixmap->drawable.width, pPixmap->drawable.height, 0, NULL); if (!pPixmapPriv->surface) { pPixmapPriv->pVisual = NULL; pPixmapPriv->target = xglPixmapTargetNo; return FALSE; } } return TRUE; } Bool xglAllocatePixmapBits (PixmapPtr pPixmap, int hint) { int width, height, bpp, stride; XGL_PIXMAP_PRIV (pPixmap); XGL_SCREEN_PRIV (pPixmap->drawable.pScreen); width = pPixmap->drawable.width; height = pPixmap->drawable.height; bpp = pPixmap->drawable.bitsPerPixel; stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); if (stride) { glitz_buffer_t *buffer; if ((pScreenPriv->pboMask & bpp) && hint) { buffer = glitz_pixel_buffer_create (pScreenPriv->drawable, NULL, height * stride, XGL_PIXMAP_USAGE_HINT (hint)); } else { pPixmapPriv->bits = xalloc (height * stride); if (!pPixmapPriv->bits) return FALSE; buffer = glitz_buffer_create_for_data (pPixmapPriv->bits); } if (!buffer) { if (pPixmapPriv->bits) xfree (pPixmapPriv->bits); pPixmapPriv->bits = NULL; return FALSE; } pPixmapPriv->buffer = buffer; } if (pScreenPriv->yInverted) pPixmapPriv->stride = stride; else pPixmapPriv->stride = -stride; return TRUE; } Bool xglMapPixmapBits (PixmapPtr pPixmap) { if (!pPixmap->devPrivate.ptr) { CARD8 *bits; XGL_PIXMAP_PRIV (pPixmap); if (!pPixmapPriv->buffer) if (!xglAllocatePixmapBits (pPixmap, XGL_PIXMAP_USAGE_HINT_DEFAULT)) return FALSE; bits = glitz_buffer_map (pPixmapPriv->buffer, GLITZ_BUFFER_ACCESS_READ_WRITE); if (!bits) return FALSE; pPixmap->devKind = pPixmapPriv->stride; if (pPixmapPriv->stride < 0) { pPixmap->devPrivate.ptr = bits + (pPixmap->drawable.height - 1) * -pPixmapPriv->stride; } else { pPixmap->devPrivate.ptr = bits; } } return TRUE; } Bool xglUnmapPixmapBits (PixmapPtr pPixmap) { XGL_PIXMAP_PRIV (pPixmap); pPixmap->devKind = 0; pPixmap->devPrivate.ptr = 0; if (pPixmapPriv->buffer) if (glitz_buffer_unmap (pPixmapPriv->buffer)) return FALSE; return TRUE; } Bool xglCheckPixmapSize (PixmapPtr pPixmap, xglSizeConstraintPtr pSize) { if (pPixmap->drawable.width < pSize->minWidth || pPixmap->drawable.height < pSize->minHeight) return FALSE; if (pPixmap->drawable.width > pSize->aboveWidth || pPixmap->drawable.height > pSize->aboveHeight) return TRUE; return FALSE; } void xglEnablePixmapAccel (PixmapPtr pPixmap, xglAccelInfoPtr pAccel) { XGL_SCREEN_PRIV (pPixmap->drawable.pScreen); XGL_PIXMAP_PRIV (pPixmap); if (pAccel->enabled && xglCheckPixmapSize (pPixmap, &pAccel->size)) { xglVisualPtr v; if (pAccel->pbuffer) { for (v = pScreenPriv->pVisual; v; v = v->next) { if (v->pPixel->depth != pPixmap->drawable.depth) continue; if (v->format.drawable && v->pbuffer) break; } } else { for (v = pScreenPriv->pVisual; v; v = v->next) { if (v->pPixel->depth != pPixmap->drawable.depth) continue; if (v->format.drawable && !v->pbuffer) break; } } if (v) { xglSetPixmapVisual (pPixmap, v); if (!pPixmapPriv->target) pPixmapPriv->target = xglPixmapTargetOut; } } }