/* * Copyright © 2001 Keith Packard * Copyright 2011 VMWare, Inc. All Rights Reserved. * May partly be based on code that is Copyright © The XFree86 Project Inc. * * 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, sub license, 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 (including the * next paragraph) 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 NON-INFRINGEMENT. * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. * * Author: Eric Anholt * Author: Michel Dänzer * Author: Thomas Hellstrom */ #include "saa.h" #include "saa_priv.h" #ifdef RENDER #include /** * Same as miCreateAlphaPicture, except it uses * saa_check_poly_fill_rect instead */ static PicturePtr saa_create_alpha_picture(ScreenPtr pScreen, PicturePtr pDst, PictFormatPtr pPictFormat, CARD16 width, CARD16 height) { PixmapPtr pPixmap; PicturePtr pPicture; GCPtr pGC; int error; xRectangle rect; if (width > 32767 || height > 32767) return 0; if (!pPictFormat) { if (pDst->polyEdge == PolyEdgeSharp) pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); else pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); if (!pPictFormat) return 0; } pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, pPictFormat->depth, 0); if (!pPixmap) return 0; pGC = GetScratchGC(pPixmap->drawable.depth, pScreen); if (!pGC) { (*pScreen->DestroyPixmap) (pPixmap); return 0; } ValidateGC(&pPixmap->drawable, pGC); rect.x = 0; rect.y = 0; rect.width = width; rect.height = height; saa_check_poly_fill_rect(&pPixmap->drawable, pGC, 1, &rect); FreeScratchGC(pGC); pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 0, 0, serverClient, &error); (*pScreen->DestroyPixmap) (pPixmap); return pPicture; } /** * saa_trapezoids is essentially a copy of miTrapezoids that uses * saa_create_alpha_picture instead of miCreateAlphaPicture. * * The problem with miCreateAlphaPicture is that it calls PolyFillRect * to initialize the contents after creating the pixmap, which * causes the pixmap to be moved in for acceleration. The subsequent * call to RasterizeTrapezoid won't be accelerated however, which * forces the pixmap to be moved out again. * */ static void saa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid * traps) { ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); BoxRec bounds; if (maskFormat) { PicturePtr pPicture; INT16 xDst, yDst; INT16 xRel, yRel; saa_access_t access; miTrapezoidBounds(ntrap, traps, &bounds); if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) return; xDst = traps[0].left.p1.x >> 16; yDst = traps[0].left.p1.y >> 16; pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); if (!pPicture) return; if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) { for (; ntrap; ntrap--, traps++) (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1); saa_fad_write(pPicture->pDrawable, access); } xRel = bounds.x1 + xSrc - xDst; yRel = bounds.y1 + ySrc - yDst; CompositePicture(op, pSrc, pPicture, pDst, xRel, yRel, 0, 0, bounds.x1, bounds.y1, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); FreePicture(pPicture, 0); } else { if (pDst->polyEdge == PolyEdgeSharp) maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); else maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); for (; ntrap; ntrap--, traps++) saa_trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); } } /** * saa_triangles is essentially a copy of miTriangles that uses * saa_create_alpha_picture instead of miCreateAlphaPicture. * * The problem with miCreateAlphaPicture is that it calls PolyFillRect * to initialize the contents after creating the pixmap, which * causes the pixmap to be moved in for acceleration. The subsequent * call to AddTriangles won't be accelerated however, which forces the pixmap * to be moved out again. */ static void saa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntri, xTriangle * tris) { ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); BoxRec bounds; if (maskFormat) { PicturePtr pPicture; INT16 xDst, yDst; INT16 xRel, yRel; saa_access_t access; miTriangleBounds(ntri, tris, &bounds); if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) return; xDst = tris[0].p1.x >> 16; yDst = tris[0].p1.y >> 16; pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); if (!pPicture) return; if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) { (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); saa_fad_write(pPicture->pDrawable, access); } xRel = bounds.x1 + xSrc - xDst; yRel = bounds.y1 + ySrc - yDst; CompositePicture(op, pSrc, pPicture, pDst, xRel, yRel, 0, 0, bounds.x1, bounds.y1, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); FreePicture(pPicture, 0); } else { if (pDst->polyEdge == PolyEdgeSharp) maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); else maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); for (; ntri; ntri--, tris++) saa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); } } static Bool saa_driver_composite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height, RegionPtr src_reg, RegionPtr mask_reg, RegionPtr dst_reg) { struct saa_screen_priv *sscreen = saa_screen(pDst->pDrawable->pScreen); BoxPtr pbox; int nbox; int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; PixmapPtr src_pix = NULL, mask_pix = NULL, dst_pix; struct saa_driver *driver = sscreen->driver; if (!driver->composite_prepare) return FALSE; dst_pix = saa_get_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); if (saa_pixmap(dst_pix)->auth_loc != saa_loc_driver) return FALSE; if (pMask && pMask->pDrawable) { mask_pix = saa_get_pixmap(pMask->pDrawable, &mask_off_x, &mask_off_y); if (saa_pixmap(mask_pix)->auth_loc != saa_loc_driver) return FALSE; } if (pSrc->pDrawable) { src_pix = saa_get_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); if (saa_pixmap(src_pix)->auth_loc != saa_loc_driver) return FALSE; } if (!driver->composite_prepare(driver, op, pSrc, pMask, pDst, src_pix, mask_pix, dst_pix, src_reg, mask_reg, dst_reg)) return FALSE; nbox = REGION_NUM_RECTS(dst_reg); pbox = REGION_RECTS(dst_reg); xDst += pDst->pDrawable->x + dst_off_x; yDst += pDst->pDrawable->y + dst_off_y; if (src_pix) { xSrc += pSrc->pDrawable->x + src_off_x - xDst; ySrc += pSrc->pDrawable->y + src_off_y - yDst; } if (mask_pix) { xMask += pMask->pDrawable->x + mask_off_x - xDst; yMask += pMask->pDrawable->y + mask_off_y - yDst; } while (nbox--) { driver->composite(driver, pbox->x1 + xSrc, pbox->y1 + ySrc, pbox->x1 + xMask, pbox->y1 + yMask, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pbox++; } driver->composite_done(driver); saa_pixmap_dirty(dst_pix, TRUE, dst_reg); return TRUE; } /* * Try to turn a composite operation into an accelerated copy. * We can do that in some special cases for PictOpSrc and PictOpOver. */ static Bool saa_copy_composite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height, RegionPtr dst_region) { if (!pSrc->pDrawable || pSrc->transform || pSrc->repeat || xSrc < 0 || ySrc < 0 || xSrc + width > pSrc->pDrawable->width || ySrc + height > pSrc->pDrawable->height) return FALSE; if (op == PictOpSrc || (op == PictOpOver && PICT_FORMAT_A(pSrc->format) == 0 && pMask == NULL)) { int xoff, yoff; PixmapPtr dst_pix = saa_get_pixmap(pDst->pDrawable, &xoff, &yoff); struct saa_pixmap *dst_spix = saa_pixmap(dst_pix); struct saa_pixmap *src_spix = saa_pixmap(saa_get_drawable_pixmap(pSrc->pDrawable)); int ret; if (src_spix->auth_loc != saa_loc_driver || dst_spix->auth_loc != saa_loc_driver) return FALSE; src_spix->src_format = pSrc->format; dst_spix->dst_format = pDst->format; xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; xSrc += pSrc->pDrawable->x; ySrc += pSrc->pDrawable->y; /* * Dst region is in backing pixmap space. We need to * translate it. */ REGION_TRANSLATE(pScreen, dst_region, -xoff, -yoff); ret = saa_hw_copy_nton(pSrc->pDrawable, pDst->pDrawable, NULL, REGION_RECTS(dst_region), REGION_NUM_RECTS(dst_region), xSrc - xDst, ySrc - yDst, FALSE, FALSE); REGION_TRANSLATE(pScreen, dst_region, xoff, yoff); src_spix->src_format = 0; dst_spix->dst_format = 0; if (ret) return TRUE; } return FALSE; } static void saa_composite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { ScreenPtr pScreen = pDst->pDrawable->pScreen; RegionRec dst_region; RegionPtr src_region; RegionPtr mask_region; REGION_NULL(pScreen, &dst_region); if (!saa_compute_composite_regions(pScreen, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height, &dst_region, &src_region, &mask_region)) goto out; if (saa_copy_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height, &dst_region)) goto out; if (saa_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height, src_region, mask_region, &dst_region)) goto out; saa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height, src_region, mask_region, &dst_region); out: if (src_region) REGION_UNINIT(pScreen, src_region); if (mask_region && mask_region != src_region) REGION_UNINIT(pScreen, mask_region); REGION_UNINIT(pScreen, &dst_region); } void saa_render_setup(ScreenPtr pScreen) { PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); struct saa_screen_priv *sscreen = saa_screen(pScreen); if (ps) { saa_wrap(sscreen, ps, Trapezoids, saa_trapezoids); saa_wrap(sscreen, ps, Triangles, saa_triangles); saa_wrap(sscreen, ps, Composite, saa_composite); } } void saa_render_takedown(ScreenPtr pScreen) { PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); struct saa_screen_priv *sscreen = saa_screen(pScreen); if (ps) { saa_unwrap(sscreen, ps, Trapezoids); saa_unwrap(sscreen, ps, Triangles); saa_unwrap(sscreen, ps, Composite); } } #endif