aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xgl/xgltrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xgl/xgltrap.c')
-rw-r--r--xorg-server/hw/xgl/xgltrap.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/xorg-server/hw/xgl/xgltrap.c b/xorg-server/hw/xgl/xgltrap.c
new file mode 100644
index 000000000..6e7a5082c
--- /dev/null
+++ b/xorg-server/hw/xgl/xgltrap.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright © 2005 Novell, 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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 <davidr@novell.com>
+ */
+
+#include "xgl.h"
+#include "gcstruct.h"
+#include "damage.h"
+
+#ifdef RENDER
+
+#define XGL_TRAP_FALLBACK_PROLOGUE(pPicture, func) \
+ xglSyncDamageBoxBits (pPicture->pDrawable); \
+ XGL_PICTURE_SCREEN_UNWRAP (func)
+
+#define XGL_TRAP_FALLBACK_EPILOGUE(pPicture, func, xglfunc) \
+ XGL_PICTURE_SCREEN_WRAP (func, xglfunc); \
+ xglAddCurrentSurfaceDamage (pPicture->pDrawable)
+
+/* just a guess */
+#define SMOOTH_TRAPS_ESTIMATE_RECTS(nTrap) (30 * nTrap)
+
+#define LINE_FIXED_X(l, _y, v) \
+ dx = (l)->p2.x - (l)->p1.x; \
+ ex = (xFixed_32_32) ((_y) - (l)->p1.y) * dx; \
+ dy = (l)->p2.y - (l)->p1.y; \
+ (v) = (l)->p1.x + (xFixed) (ex / dy)
+
+#define LINE_FIXED_X_CEIL(l, _y, v) \
+ dx = (l)->p2.x - (l)->p1.x; \
+ ex = (xFixed_32_32) ((_y) - (l)->p1.y) * dx; \
+ dy = (l)->p2.y - (l)->p1.y; \
+ (v) = (l)->p1.x + (xFixed) ((ex + (dy - 1)) / dy)
+
+static Bool
+xglTrapezoidExtents (PicturePtr pDst,
+ int ntrap,
+ xTrapezoid *traps,
+ BoxPtr extents)
+{
+ Bool x_overlap, overlap = FALSE;
+ xFixed dx, dy, top, bottom;
+ xFixed_32_32 ex;
+
+ if (!ntrap)
+ {
+ extents->x1 = MAXSHORT;
+ extents->x2 = MINSHORT;
+ extents->y1 = MAXSHORT;
+ extents->y2 = MINSHORT;
+
+ return FALSE;
+ }
+
+ extents->y1 = xFixedToInt (traps->top);
+ extents->y2 = xFixedToInt (xFixedCeil (traps->bottom));
+
+ LINE_FIXED_X (&traps->left, traps->top, top);
+ LINE_FIXED_X (&traps->left, traps->bottom, bottom);
+ extents->x1 = xFixedToInt (MIN (top, bottom));
+
+ LINE_FIXED_X_CEIL (&traps->right, traps->top, top);
+ LINE_FIXED_X_CEIL (&traps->right, traps->bottom, bottom);
+ extents->x2 = xFixedToInt (xFixedCeil (MAX (top, bottom)));
+
+ ntrap--;
+ traps++;
+
+ for (; ntrap; ntrap--, traps++)
+ {
+ INT16 x1, y1, x2, y2;
+
+ if (!xTrapezoidValid (traps))
+ continue;
+
+ y1 = xFixedToInt (traps->top);
+ y2 = xFixedToInt (xFixedCeil (traps->bottom));
+
+ LINE_FIXED_X (&traps->left, traps->top, top);
+ LINE_FIXED_X (&traps->left, traps->bottom, bottom);
+ x1 = xFixedToInt (MIN (top, bottom));
+
+ LINE_FIXED_X_CEIL (&traps->right, traps->top, top);
+ LINE_FIXED_X_CEIL (&traps->right, traps->bottom, bottom);
+ x2 = xFixedToInt (xFixedCeil (MAX (top, bottom)));
+
+ x_overlap = FALSE;
+ if (x1 >= extents->x2)
+ extents->x2 = x2;
+ else if (x2 <= extents->x1)
+ extents->x1 = x1;
+ else
+ {
+ x_overlap = TRUE;
+ if (x1 < extents->x1)
+ extents->x1 = x1;
+ if (x2 > extents->x2)
+ extents->x2 = x2;
+ }
+
+ if (y1 >= extents->y2)
+ extents->y2 = y2;
+ else if (y2 <= extents->y1)
+ extents->y1 = y1;
+ else
+ {
+ if (y1 < extents->y1)
+ extents->y1 = y1;
+ if (y2 > extents->y2)
+ extents->y2 = y2;
+
+ if (x_overlap)
+ overlap = TRUE;
+ }
+ }
+
+ xglPictureClipExtents (pDst, extents);
+
+ return overlap;
+}
+
+void
+xglTrapezoids (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc,
+ int nTrap,
+ xTrapezoid *traps)
+{
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ PicturePtr pMask = NULL, pSrcPicture, pDstPicture;
+ PicturePtr pMaskPicture = NULL;
+ xglGeometryPtr pGeometry = NULL;
+ unsigned int polyEdge = pDst->polyEdge;
+ INT16 xDst, yDst;
+ INT16 xOff, yOff;
+ BoxRec extents;
+ Bool overlap;
+ Bool target;
+
+ XGL_SCREEN_PRIV (pScreen);
+
+ xDst = traps[0].left.p1.x >> 16;
+ yDst = traps[0].left.p1.y >> 16;
+
+ overlap = xglTrapezoidExtents (pDst, nTrap, traps, &extents);
+ if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2)
+ return;
+
+ target = xglPrepareTarget (pDst->pDrawable);
+
+ if (nTrap > 1 && op != PictOpAdd && maskFormat &&
+ (!target || overlap || op != PictOpOver))
+ {
+ PixmapPtr pPixmap;
+ GCPtr pGC;
+ xRectangle rect;
+ int error;
+ int area;
+
+ if (!pScreenPriv->pSolidAlpha)
+ {
+ xglCreateSolidAlphaPicture (pScreen);
+ if (!pScreenPriv->pSolidAlpha)
+ return;
+ }
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = extents.x2 - extents.x1;
+ rect.height = extents.y2 - extents.y1;
+
+ pPixmap = (*pScreen->CreatePixmap) (pScreen,
+ rect.width, rect.height,
+ maskFormat->depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pPixmap)
+ return;
+
+ pMask = CreatePicture (0, &pPixmap->drawable, maskFormat,
+ 0, 0, serverClient, &error);
+ if (!pMask)
+ {
+ (*pScreen->DestroyPixmap) (pPixmap);
+ return;
+ }
+
+ if (!target)
+ {
+ /* make sure we don't do accelerated drawing to mask */
+ xglSetPixmapVisual (pPixmap, NULL);
+ }
+
+ area = rect.width * rect.height;
+ if ((SMOOTH_TRAPS_ESTIMATE_RECTS (nTrap) * 4) > area)
+ XGL_GET_PIXMAP_PRIV (pPixmap)->target = xglPixmapTargetNo;
+
+ ValidatePicture (pMask);
+ pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
+ ValidateGC (&pPixmap->drawable, pGC);
+ (*pGC->ops->PolyFillRect) (&pPixmap->drawable, pGC, 1, &rect);
+ FreeScratchGC (pGC);
+
+ (*pScreen->DestroyPixmap) (pPixmap);
+
+ target = xglPrepareTarget (pMask->pDrawable);
+
+ xOff = -extents.x1;
+ yOff = -extents.y1;
+ pSrcPicture = pScreenPriv->pSolidAlpha;
+ pDstPicture = pMask;
+ }
+ else
+ {
+ if (maskFormat)
+ {
+ if (maskFormat->depth == 1)
+ polyEdge = PolyEdgeSharp;
+ else
+ polyEdge = PolyEdgeSmooth;
+ }
+
+ xOff = 0;
+ yOff = 0;
+ pSrcPicture = pSrc;
+ pDstPicture = pDst;
+ }
+
+ if (target)
+ {
+ if (maskFormat || polyEdge == PolyEdgeSmooth)
+ {
+ glitz_vertex_format_t *format;
+ glitz_surface_t *mask;
+ xTrapezoid *pTrap = traps;
+ int nAddedTrap, n = nTrap;
+ int offset = 0;
+ int size = SMOOTH_TRAPS_ESTIMATE_RECTS (n);
+
+ pMaskPicture = pScreenPriv->trapInfo.pMask;
+ format = &pScreenPriv->trapInfo.format.vertex;
+ mask = pMaskPicture->pSourcePict->source.devPrivate.ptr;
+
+ size *= format->bytes_per_vertex;
+ pGeometry = xglGetScratchGeometryWithSize (pScreen, size);
+
+ while (n)
+ {
+ if (pGeometry->size < size)
+ GEOMETRY_RESIZE (pScreen, pGeometry, size);
+
+ if (!pGeometry->buffer)
+ {
+ if (pMask)
+ FreePicture (pMask, 0);
+
+ return;
+ }
+
+ offset +=
+ glitz_add_trapezoids (pGeometry->buffer,
+ offset, size - offset, format->type,
+ mask, (glitz_trapezoid_t *) pTrap, n,
+ &nAddedTrap);
+
+ n -= nAddedTrap;
+ pTrap += nAddedTrap;
+ size *= 2;
+ }
+
+ pGeometry->f = pScreenPriv->trapInfo.format;
+ pGeometry->count = offset / format->bytes_per_vertex;
+ }
+ else
+ {
+ pGeometry =
+ xglGetScratchVertexGeometryWithType (pScreen,
+ GEOMETRY_DATA_TYPE_FLOAT,
+ 4 * nTrap);
+ if (!pGeometry->buffer)
+ {
+ if (pMask)
+ FreePicture (pMask, 0);
+
+ return;
+ }
+
+ GEOMETRY_ADD_TRAPEZOID (pScreen, pGeometry, traps, nTrap);
+ }
+
+ GEOMETRY_TRANSLATE (pGeometry,
+ pDstPicture->pDrawable->x + xOff,
+ pDstPicture->pDrawable->y + yOff);
+ }
+
+ if (pGeometry &&
+ xglCompositeGeneral (pMask ? PictOpAdd : op,
+ pSrcPicture,
+ pMaskPicture,
+ pDstPicture,
+ pGeometry,
+ extents.x1 + xOff + xSrc - xDst,
+ extents.y1 + yOff + ySrc - yDst,
+ 0, 0,
+ pDstPicture->pDrawable->x + extents.x1 + xOff,
+ pDstPicture->pDrawable->y + extents.y1 + yOff,
+ extents.x2 - extents.x1,
+ extents.y2 - extents.y1))
+ {
+ /* no intermediate mask? we need to register damage from here as
+ CompositePicture will never be called. */
+ if (!pMask)
+ {
+ RegionRec region;
+
+ REGION_INIT (pScreen, &region, &extents, 1);
+ REGION_TRANSLATE (pScreen, &region,
+ pDst->pDrawable->x, pDst->pDrawable->y);
+
+ DamageDamageRegion (pDst->pDrawable, &region);
+
+ REGION_UNINIT (pScreen, &region);
+ }
+
+ xglAddCurrentBitDamage (pDstPicture->pDrawable);
+ }
+ else
+ {
+ XGL_DRAWABLE_PIXMAP_PRIV (pDstPicture->pDrawable);
+
+ pPixmapPriv->damageBox.x1 = extents.x1 + xOff;
+ pPixmapPriv->damageBox.y1 = extents.y1 + yOff;
+ pPixmapPriv->damageBox.x2 = extents.x2 + xOff;
+ pPixmapPriv->damageBox.y2 = extents.y2 + yOff;
+
+ xglSyncDamageBoxBits (pDstPicture->pDrawable);
+
+ if (pMask || (polyEdge == PolyEdgeSmooth &&
+ op == PictOpAdd && miIsSolidAlpha (pSrc)))
+ {
+ PictureScreenPtr ps = GetPictureScreen (pScreen);
+
+ for (; nTrap; nTrap--, traps++)
+ (*ps->RasterizeTrapezoid) (pDstPicture, traps, xOff, yOff);
+
+ xglAddCurrentSurfaceDamage (pDstPicture->pDrawable);
+ }
+ else
+ miTrapezoids (op, pSrc, pDstPicture, maskFormat,
+ xSrc, ySrc, nTrap, traps);
+ }
+
+ if (pMask)
+ {
+ CompositePicture (op, pSrc, pMask, pDst,
+ extents.x1 + xSrc - xDst,
+ extents.y1 + ySrc - yDst,
+ 0, 0,
+ extents.x1, extents.y1,
+ extents.x2 - extents.x1,
+ extents.y2 - extents.y1);
+
+ FreePicture (pMask, 0);
+ }
+}
+
+void
+xglAddTraps (PicturePtr pDst,
+ INT16 xOff,
+ INT16 yOff,
+ int nTrap,
+ xTrap *traps)
+{
+ PictureScreenPtr pPictureScreen;
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+
+ XGL_SCREEN_PRIV (pScreen);
+ XGL_DRAWABLE_PIXMAP_PRIV (pDst->pDrawable);
+
+ if (!pScreenPriv->pSolidAlpha)
+ {
+ xglCreateSolidAlphaPicture (pScreen);
+ if (!pScreenPriv->pSolidAlpha)
+ return;
+ }
+
+ pPixmapPriv->damageBox.x1 = 0;
+ pPixmapPriv->damageBox.y1 = 0;
+ pPixmapPriv->damageBox.x2 = pDst->pDrawable->width;
+ pPixmapPriv->damageBox.y2 = pDst->pDrawable->height;
+
+ if (xglPrepareTarget (pDst->pDrawable))
+ {
+ PicturePtr pMask;
+ glitz_vertex_format_t *format;
+ glitz_surface_t *mask;
+ xglGeometryPtr pGeometry;
+ xTrap *pTrap = traps;
+ int nAddedTrap, n = nTrap;
+ int offset = 0;
+ int size = SMOOTH_TRAPS_ESTIMATE_RECTS (n);
+
+ pMask = pScreenPriv->trapInfo.pMask;
+ format = &pScreenPriv->trapInfo.format.vertex;
+ mask = pMask->pSourcePict->source.devPrivate.ptr;
+
+ size *= format->bytes_per_vertex;
+ pGeometry = xglGetScratchGeometryWithSize (pScreen, size);
+
+ while (n)
+ {
+ if (pGeometry->size < size)
+ GEOMETRY_RESIZE (pScreen, pGeometry, size);
+
+ if (!pGeometry->buffer)
+ return;
+
+ offset +=
+ glitz_add_traps (pGeometry->buffer,
+ offset, size - offset, format->type, mask,
+ (glitz_trap_t *) pTrap, n,
+ &nAddedTrap);
+
+ n -= nAddedTrap;
+ pTrap += nAddedTrap;
+ size *= 2;
+ }
+
+ pGeometry->f = pScreenPriv->trapInfo.format;
+ pGeometry->count = offset / format->bytes_per_vertex;
+
+ GEOMETRY_TRANSLATE (pGeometry,
+ pDst->pDrawable->x + xOff,
+ pDst->pDrawable->y + yOff);
+
+ if (xglCompositeGeneral (PictOpAdd,
+ pScreenPriv->pSolidAlpha,
+ pMask,
+ pDst,
+ pGeometry,
+ 0, 0,
+ 0, 0,
+ pDst->pDrawable->x, pDst->pDrawable->y,
+ pDst->pDrawable->width,
+ pDst->pDrawable->height))
+ {
+ xglAddCurrentBitDamage (pDst->pDrawable);
+ return;
+ }
+ }
+
+ pPictureScreen = GetPictureScreen (pScreen);
+
+ XGL_TRAP_FALLBACK_PROLOGUE (pDst, AddTraps);
+ (*pPictureScreen->AddTraps) (pDst, xOff, yOff, nTrap, traps);
+ XGL_TRAP_FALLBACK_EPILOGUE (pDst, AddTraps, xglAddTraps);
+}
+
+#endif