uxa-render.c revision 42542f5f
103b705cfSriastradh/* 203b705cfSriastradh * Copyright © 2001 Keith Packard 303b705cfSriastradh * 403b705cfSriastradh * Partly based on code that is Copyright © The XFree86 Project Inc. 503b705cfSriastradh * 603b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its 703b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that 803b705cfSriastradh * the above copyright notice appear in all copies and that both that 903b705cfSriastradh * copyright notice and this permission notice appear in supporting 1003b705cfSriastradh * documentation, and that the name of Keith Packard not be used in 1103b705cfSriastradh * advertising or publicity pertaining to distribution of the software without 1203b705cfSriastradh * specific, written prior permission. Keith Packard makes no 1303b705cfSriastradh * representations about the suitability of this software for any purpose. It 1403b705cfSriastradh * is provided "as is" without express or implied warranty. 1503b705cfSriastradh * 1603b705cfSriastradh * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1703b705cfSriastradh * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1803b705cfSriastradh * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1903b705cfSriastradh * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 2003b705cfSriastradh * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2103b705cfSriastradh * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2203b705cfSriastradh * PERFORMANCE OF THIS SOFTWARE. 2303b705cfSriastradh */ 2403b705cfSriastradh 2503b705cfSriastradh#ifdef HAVE_DIX_CONFIG_H 2603b705cfSriastradh#include <dix-config.h> 2703b705cfSriastradh#endif 2803b705cfSriastradh 2903b705cfSriastradh#include <stdlib.h> 3003b705cfSriastradh 3103b705cfSriastradh#include "uxa-priv.h" 3203b705cfSriastradh#include "uxa-glamor.h" 3303b705cfSriastradh 3403b705cfSriastradh#ifdef RENDER 3503b705cfSriastradh#include "mipict.h" 3603b705cfSriastradh 3703b705cfSriastradh/* Note: when using glamor we can not fail through to the ordinary UXA 3803b705cfSriastradh * code paths, as glamor keeps an internal texture which will become 3903b705cfSriastradh * inconsistent with the original bo. (The texture is replaced whenever 4003b705cfSriastradh * the format changes, e.g. switching between xRGB and ARGB, for which mesa 4103b705cfSriastradh * will allocate its own bo.) 4203b705cfSriastradh * 4303b705cfSriastradh * Ergo it is unsafe to fall through to the original backend operations if 4403b705cfSriastradh * glamor is enabled. 4503b705cfSriastradh * 4603b705cfSriastradh * XXX This has some serious implications for mixing Render, DRI, scanout... 4703b705cfSriastradh */ 4803b705cfSriastradh 4903b705cfSriastradhstatic void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string, 5003b705cfSriastradh int n) 5103b705cfSriastradh{ 5203b705cfSriastradh char format[20]; 5303b705cfSriastradh char size[20]; 5403b705cfSriastradh char loc; 5503b705cfSriastradh 5603b705cfSriastradh if (!pict) { 5703b705cfSriastradh snprintf(string, n, "None"); 5803b705cfSriastradh return; 5903b705cfSriastradh } 6003b705cfSriastradh 6103b705cfSriastradh if (pict->pDrawable == NULL) { 6203b705cfSriastradh snprintf(string, n, "source-only"); 6303b705cfSriastradh return; 6403b705cfSriastradh } 6503b705cfSriastradh 6603b705cfSriastradh switch (pict->format) { 6703b705cfSriastradh case PICT_a8r8g8b8: 6803b705cfSriastradh snprintf(format, 20, "ARGB8888"); 6903b705cfSriastradh break; 7003b705cfSriastradh case PICT_x8r8g8b8: 7103b705cfSriastradh snprintf(format, 20, "XRGB8888"); 7203b705cfSriastradh break; 7303b705cfSriastradh case PICT_r5g6b5: 7403b705cfSriastradh snprintf(format, 20, "RGB565 "); 7503b705cfSriastradh break; 7603b705cfSriastradh case PICT_x1r5g5b5: 7703b705cfSriastradh snprintf(format, 20, "RGB555 "); 7803b705cfSriastradh break; 7903b705cfSriastradh case PICT_a8: 8003b705cfSriastradh snprintf(format, 20, "A8 "); 8103b705cfSriastradh break; 8203b705cfSriastradh case PICT_a1: 8303b705cfSriastradh snprintf(format, 20, "A1 "); 8403b705cfSriastradh break; 8503b705cfSriastradh default: 8603b705cfSriastradh snprintf(format, 20, "0x%x", (int)pict->format); 8703b705cfSriastradh break; 8803b705cfSriastradh } 8903b705cfSriastradh 9003b705cfSriastradh loc = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm'; 9103b705cfSriastradh 9203b705cfSriastradh snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, 9303b705cfSriastradh pict->pDrawable->height, pict->repeat ? " R" : ""); 9403b705cfSriastradh 9503b705cfSriastradh snprintf(string, n, "%p:%c fmt %s (%s)%s", 9603b705cfSriastradh pict->pDrawable, loc, format, size, 9703b705cfSriastradh pict->alphaMap ? " with alpha map" :""); 9803b705cfSriastradh} 9903b705cfSriastradh 10003b705cfSriastradhstatic const char * 10103b705cfSriastradhop_to_string(CARD8 op) 10203b705cfSriastradh{ 10303b705cfSriastradh switch (op) { 10403b705cfSriastradh#define C(x) case PictOp##x: return #x 10503b705cfSriastradh C(Clear); 10603b705cfSriastradh C(Src); 10703b705cfSriastradh C(Dst); 10803b705cfSriastradh C(Over); 10903b705cfSriastradh C(OverReverse); 11003b705cfSriastradh C(In); 11103b705cfSriastradh C(InReverse); 11203b705cfSriastradh C(Out); 11303b705cfSriastradh C(OutReverse); 11403b705cfSriastradh C(Atop); 11503b705cfSriastradh C(AtopReverse); 11603b705cfSriastradh C(Xor); 11703b705cfSriastradh C(Add); 11803b705cfSriastradh C(Saturate); 11903b705cfSriastradh 12003b705cfSriastradh /* 12103b705cfSriastradh * Operators only available in version 0.2 12203b705cfSriastradh */ 12303b705cfSriastradh#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 2 12403b705cfSriastradh C(DisjointClear); 12503b705cfSriastradh C(DisjointSrc); 12603b705cfSriastradh C(DisjointDst); 12703b705cfSriastradh C(DisjointOver); 12803b705cfSriastradh C(DisjointOverReverse); 12903b705cfSriastradh C(DisjointIn); 13003b705cfSriastradh C(DisjointInReverse); 13103b705cfSriastradh C(DisjointOut); 13203b705cfSriastradh C(DisjointOutReverse); 13303b705cfSriastradh C(DisjointAtop); 13403b705cfSriastradh C(DisjointAtopReverse); 13503b705cfSriastradh C(DisjointXor); 13603b705cfSriastradh 13703b705cfSriastradh C(ConjointClear); 13803b705cfSriastradh C(ConjointSrc); 13903b705cfSriastradh C(ConjointDst); 14003b705cfSriastradh C(ConjointOver); 14103b705cfSriastradh C(ConjointOverReverse); 14203b705cfSriastradh C(ConjointIn); 14303b705cfSriastradh C(ConjointInReverse); 14403b705cfSriastradh C(ConjointOut); 14503b705cfSriastradh C(ConjointOutReverse); 14603b705cfSriastradh C(ConjointAtop); 14703b705cfSriastradh C(ConjointAtopReverse); 14803b705cfSriastradh C(ConjointXor); 14903b705cfSriastradh#endif 15003b705cfSriastradh 15103b705cfSriastradh /* 15203b705cfSriastradh * Operators only available in version 0.11 15303b705cfSriastradh */ 15403b705cfSriastradh#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 11 15503b705cfSriastradh C(Multiply); 15603b705cfSriastradh C(Screen); 15703b705cfSriastradh C(Overlay); 15803b705cfSriastradh C(Darken); 15903b705cfSriastradh C(Lighten); 16003b705cfSriastradh C(ColorDodge); 16103b705cfSriastradh C(ColorBurn); 16203b705cfSriastradh C(HardLight); 16303b705cfSriastradh C(SoftLight); 16403b705cfSriastradh C(Difference); 16503b705cfSriastradh C(Exclusion); 16603b705cfSriastradh C(HSLHue); 16703b705cfSriastradh C(HSLSaturation); 16803b705cfSriastradh C(HSLColor); 16903b705cfSriastradh C(HSLLuminosity); 17003b705cfSriastradh#endif 17103b705cfSriastradh default: return "garbage"; 17203b705cfSriastradh#undef C 17303b705cfSriastradh } 17403b705cfSriastradh} 17503b705cfSriastradh 17603b705cfSriastradhstatic void 17703b705cfSriastradhuxa_print_composite_fallback(const char *func, CARD8 op, 17803b705cfSriastradh PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) 17903b705cfSriastradh{ 18003b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 18103b705cfSriastradh char srcdesc[40], maskdesc[40], dstdesc[40]; 18203b705cfSriastradh 18303b705cfSriastradh if (! uxa_screen->fallback_debug) 18403b705cfSriastradh return; 18503b705cfSriastradh 18603b705cfSriastradh /* Limit the noise if fallbacks are expected. */ 18703b705cfSriastradh if (uxa_screen->force_fallback) 18803b705cfSriastradh return; 18903b705cfSriastradh 19003b705cfSriastradh uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40); 19103b705cfSriastradh uxa_composite_fallback_pict_desc(pMask, maskdesc, 40); 19203b705cfSriastradh uxa_composite_fallback_pict_desc(pDst, dstdesc, 40); 19303b705cfSriastradh 19403b705cfSriastradh ErrorF("Composite fallback at %s:\n" 19503b705cfSriastradh " op %s, \n" 19603b705cfSriastradh " src %s, \n" 19703b705cfSriastradh " mask %s, \n" 19803b705cfSriastradh " dst %s, \n", 19903b705cfSriastradh func, op_to_string (op), srcdesc, maskdesc, dstdesc); 20003b705cfSriastradh} 20103b705cfSriastradh 20203b705cfSriastradhBool uxa_op_reads_destination(CARD8 op) 20303b705cfSriastradh{ 20403b705cfSriastradh /* FALSE (does not read destination) is the list of ops in the protocol 20503b705cfSriastradh * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 20603b705cfSriastradh * That's just Clear and Src. ReduceCompositeOp() will already have 20703b705cfSriastradh * converted con/disjoint clear/src to Clear or Src. 20803b705cfSriastradh */ 20903b705cfSriastradh switch (op) { 21003b705cfSriastradh case PictOpClear: 21103b705cfSriastradh case PictOpSrc: 21203b705cfSriastradh return FALSE; 21303b705cfSriastradh default: 21403b705cfSriastradh return TRUE; 21503b705cfSriastradh } 21603b705cfSriastradh} 21703b705cfSriastradh 21803b705cfSriastradhstatic Bool 21903b705cfSriastradhuxa_get_pixel_from_rgba(CARD32 * pixel, 22003b705cfSriastradh CARD16 red, 22103b705cfSriastradh CARD16 green, 22203b705cfSriastradh CARD16 blue, 22303b705cfSriastradh CARD16 alpha, 22403b705cfSriastradh CARD32 format) 22503b705cfSriastradh{ 22603b705cfSriastradh int rbits, bbits, gbits, abits; 22703b705cfSriastradh int rshift, bshift, gshift, ashift; 22803b705cfSriastradh 22903b705cfSriastradh rbits = PICT_FORMAT_R(format); 23003b705cfSriastradh gbits = PICT_FORMAT_G(format); 23103b705cfSriastradh bbits = PICT_FORMAT_B(format); 23203b705cfSriastradh abits = PICT_FORMAT_A(format); 23303b705cfSriastradh if (abits == 0) 23403b705cfSriastradh abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 23503b705cfSriastradh 23603b705cfSriastradh if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 23703b705cfSriastradh *pixel = alpha >> (16 - abits); 23803b705cfSriastradh return TRUE; 23903b705cfSriastradh } 24003b705cfSriastradh 24103b705cfSriastradh if (!PICT_FORMAT_COLOR(format)) 24203b705cfSriastradh return FALSE; 24303b705cfSriastradh 24403b705cfSriastradh if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 24503b705cfSriastradh bshift = 0; 24603b705cfSriastradh gshift = bbits; 24703b705cfSriastradh rshift = gshift + gbits; 24803b705cfSriastradh ashift = rshift + rbits; 24903b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 25003b705cfSriastradh rshift = 0; 25103b705cfSriastradh gshift = rbits; 25203b705cfSriastradh bshift = gshift + gbits; 25303b705cfSriastradh ashift = bshift + bbits; 25403b705cfSriastradh#if XORG_VERSION_CURRENT >= 10699900 25503b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 25603b705cfSriastradh ashift = 0; 25703b705cfSriastradh rshift = abits; 25803b705cfSriastradh gshift = rshift + rbits; 25903b705cfSriastradh bshift = gshift + gbits; 26003b705cfSriastradh#endif 26103b705cfSriastradh } else { 26203b705cfSriastradh return FALSE; 26303b705cfSriastradh } 26403b705cfSriastradh 26503b705cfSriastradh *pixel = 0; 26603b705cfSriastradh *pixel |= (blue >> (16 - bbits)) << bshift; 26703b705cfSriastradh *pixel |= (green >> (16 - gbits)) << gshift; 26803b705cfSriastradh *pixel |= (red >> (16 - rbits)) << rshift; 26903b705cfSriastradh *pixel |= (alpha >> (16 - abits)) << ashift; 27003b705cfSriastradh 27103b705cfSriastradh return TRUE; 27203b705cfSriastradh} 27303b705cfSriastradh 27403b705cfSriastradhBool 27503b705cfSriastradhuxa_get_rgba_from_pixel(CARD32 pixel, 27603b705cfSriastradh CARD16 * red, 27703b705cfSriastradh CARD16 * green, 27803b705cfSriastradh CARD16 * blue, 27903b705cfSriastradh CARD16 * alpha, 28003b705cfSriastradh CARD32 format) 28103b705cfSriastradh{ 28203b705cfSriastradh int rbits, bbits, gbits, abits; 28303b705cfSriastradh int rshift, bshift, gshift, ashift; 28403b705cfSriastradh 28503b705cfSriastradh rbits = PICT_FORMAT_R(format); 28603b705cfSriastradh gbits = PICT_FORMAT_G(format); 28703b705cfSriastradh bbits = PICT_FORMAT_B(format); 28803b705cfSriastradh abits = PICT_FORMAT_A(format); 28903b705cfSriastradh 29003b705cfSriastradh if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 29103b705cfSriastradh rshift = gshift = bshift = ashift = 0; 29203b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 29303b705cfSriastradh bshift = 0; 29403b705cfSriastradh gshift = bbits; 29503b705cfSriastradh rshift = gshift + gbits; 29603b705cfSriastradh ashift = rshift + rbits; 29703b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 29803b705cfSriastradh rshift = 0; 29903b705cfSriastradh gshift = rbits; 30003b705cfSriastradh bshift = gshift + gbits; 30103b705cfSriastradh ashift = bshift + bbits; 30203b705cfSriastradh#if XORG_VERSION_CURRENT >= 10699900 30303b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 30403b705cfSriastradh ashift = 0; 30503b705cfSriastradh rshift = abits; 30603b705cfSriastradh if (abits == 0) 30703b705cfSriastradh rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 30803b705cfSriastradh gshift = rshift + rbits; 30903b705cfSriastradh bshift = gshift + gbits; 31003b705cfSriastradh#endif 31103b705cfSriastradh } else { 31203b705cfSriastradh return FALSE; 31303b705cfSriastradh } 31403b705cfSriastradh 31503b705cfSriastradh if (rbits) { 31603b705cfSriastradh *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 31703b705cfSriastradh while (rbits < 16) { 31803b705cfSriastradh *red |= *red >> rbits; 31903b705cfSriastradh rbits <<= 1; 32003b705cfSriastradh } 32103b705cfSriastradh } else 32203b705cfSriastradh *red = 0; 32303b705cfSriastradh 32403b705cfSriastradh if (gbits) { 32503b705cfSriastradh *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 32603b705cfSriastradh while (gbits < 16) { 32703b705cfSriastradh *green |= *green >> gbits; 32803b705cfSriastradh gbits <<= 1; 32903b705cfSriastradh } 33003b705cfSriastradh } else 33103b705cfSriastradh *green = 0; 33203b705cfSriastradh 33303b705cfSriastradh if (bbits) { 33403b705cfSriastradh *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 33503b705cfSriastradh while (bbits < 16) { 33603b705cfSriastradh *blue |= *blue >> bbits; 33703b705cfSriastradh bbits <<= 1; 33803b705cfSriastradh } 33903b705cfSriastradh } else 34003b705cfSriastradh *blue = 0; 34103b705cfSriastradh 34203b705cfSriastradh if (abits) { 34303b705cfSriastradh *alpha = 34403b705cfSriastradh ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 34503b705cfSriastradh while (abits < 16) { 34603b705cfSriastradh *alpha |= *alpha >> abits; 34703b705cfSriastradh abits <<= 1; 34803b705cfSriastradh } 34903b705cfSriastradh } else 35003b705cfSriastradh *alpha = 0xffff; 35103b705cfSriastradh 35203b705cfSriastradh return TRUE; 35303b705cfSriastradh} 35403b705cfSriastradh 35503b705cfSriastradhBool 35603b705cfSriastradhuxa_get_color_for_pixmap (PixmapPtr pixmap, 35703b705cfSriastradh CARD32 src_format, 35803b705cfSriastradh CARD32 dst_format, 35903b705cfSriastradh CARD32 *pixel) 36003b705cfSriastradh{ 36103b705cfSriastradh CARD16 red, green, blue, alpha; 36203b705cfSriastradh 36303b705cfSriastradh *pixel = uxa_get_pixmap_first_pixel(pixmap); 36403b705cfSriastradh 36503b705cfSriastradh if (src_format != dst_format) { 36603b705cfSriastradh if (!uxa_get_rgba_from_pixel(*pixel, 36703b705cfSriastradh &red, &green, &blue, &alpha, 36803b705cfSriastradh src_format)) 36903b705cfSriastradh return FALSE; 37003b705cfSriastradh 37103b705cfSriastradh if (!uxa_get_pixel_from_rgba(pixel, 37203b705cfSriastradh red, green, blue, alpha, 37303b705cfSriastradh dst_format)) 37403b705cfSriastradh return FALSE; 37503b705cfSriastradh } 37603b705cfSriastradh 37703b705cfSriastradh return TRUE; 37803b705cfSriastradh} 37903b705cfSriastradh 38003b705cfSriastradhstatic int 38103b705cfSriastradhuxa_try_driver_solid_fill(PicturePtr pSrc, 38203b705cfSriastradh PicturePtr pDst, 38303b705cfSriastradh INT16 xSrc, 38403b705cfSriastradh INT16 ySrc, 38503b705cfSriastradh INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 38603b705cfSriastradh{ 38703b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 38803b705cfSriastradh RegionRec region; 38903b705cfSriastradh BoxPtr pbox; 39003b705cfSriastradh int nbox; 39103b705cfSriastradh int dst_off_x, dst_off_y; 39203b705cfSriastradh PixmapPtr pSrcPix = NULL, pDstPix; 39303b705cfSriastradh CARD32 pixel; 39403b705cfSriastradh 39503b705cfSriastradh if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES)) 39603b705cfSriastradh return -1; 39703b705cfSriastradh 39803b705cfSriastradh pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); 39903b705cfSriastradh if (!pDstPix) 40003b705cfSriastradh return -1; 40103b705cfSriastradh 40203b705cfSriastradh xDst += pDst->pDrawable->x; 40303b705cfSriastradh yDst += pDst->pDrawable->y; 40403b705cfSriastradh 40503b705cfSriastradh if (pSrc->pDrawable) { 40603b705cfSriastradh pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); 40703b705cfSriastradh xSrc += pSrc->pDrawable->x; 40803b705cfSriastradh ySrc += pSrc->pDrawable->y; 40903b705cfSriastradh } 41003b705cfSriastradh 41103b705cfSriastradh if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst, 41203b705cfSriastradh xSrc, ySrc, 0, 0, xDst, yDst, 41303b705cfSriastradh width, height)) 41403b705cfSriastradh return 1; 41503b705cfSriastradh 41603b705cfSriastradh if (pSrcPix) { 41703b705cfSriastradh if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) { 41803b705cfSriastradh REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 41903b705cfSriastradh return -1; 42003b705cfSriastradh } 42103b705cfSriastradh } else { 42203b705cfSriastradh SourcePict *source = pSrc->pSourcePict; 42303b705cfSriastradh PictSolidFill *solid = &source->solidFill; 42403b705cfSriastradh 42503b705cfSriastradh if (source == NULL || source->type != SourcePictTypeSolidFill) { 42603b705cfSriastradh REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 42703b705cfSriastradh return -1; 42803b705cfSriastradh } 42903b705cfSriastradh 43003b705cfSriastradh if (pDst->format == PICT_a8r8g8b8) { 43103b705cfSriastradh pixel = solid->color; 43203b705cfSriastradh } else if (pDst->format == PICT_x8r8g8b8) { 43303b705cfSriastradh pixel = solid->color | 0xff000000; 43403b705cfSriastradh } else { 43503b705cfSriastradh CARD16 red, green, blue, alpha; 43603b705cfSriastradh 43703b705cfSriastradh if (!uxa_get_rgba_from_pixel(solid->color, 43803b705cfSriastradh &red, &green, &blue, &alpha, 43903b705cfSriastradh PICT_a8r8g8b8) || 44003b705cfSriastradh !uxa_get_pixel_from_rgba(&pixel, 44103b705cfSriastradh red, green, blue, alpha, 44203b705cfSriastradh pDst->format)) { 44303b705cfSriastradh REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 44403b705cfSriastradh return -1; 44503b705cfSriastradh } 44603b705cfSriastradh } 44703b705cfSriastradh } 44803b705cfSriastradh 44903b705cfSriastradh if (!(*uxa_screen->info->prepare_solid) 45003b705cfSriastradh (pDstPix, GXcopy, FB_ALLONES, pixel)) { 45103b705cfSriastradh REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 45203b705cfSriastradh return -1; 45303b705cfSriastradh } 45403b705cfSriastradh 45503b705cfSriastradh REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); 45603b705cfSriastradh 45703b705cfSriastradh nbox = REGION_NUM_RECTS(®ion); 45803b705cfSriastradh pbox = REGION_RECTS(®ion); 45903b705cfSriastradh 46003b705cfSriastradh while (nbox--) { 46103b705cfSriastradh (*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1, 46203b705cfSriastradh pbox->x2, pbox->y2); 46303b705cfSriastradh pbox++; 46403b705cfSriastradh } 46503b705cfSriastradh 46603b705cfSriastradh (*uxa_screen->info->done_solid) (pDstPix); 46703b705cfSriastradh 46803b705cfSriastradh REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 46903b705cfSriastradh return 1; 47003b705cfSriastradh} 47103b705cfSriastradh 47203b705cfSriastradhstatic PicturePtr 47303b705cfSriastradhuxa_picture_for_pixman_format(ScreenPtr screen, 47403b705cfSriastradh pixman_format_code_t format, 47503b705cfSriastradh int width, int height) 47603b705cfSriastradh{ 47703b705cfSriastradh PicturePtr picture; 47803b705cfSriastradh PixmapPtr pixmap; 47903b705cfSriastradh int error; 48003b705cfSriastradh 48103b705cfSriastradh if (format == PIXMAN_a1) 48203b705cfSriastradh format = PIXMAN_a8; 48303b705cfSriastradh 48403b705cfSriastradh /* fill alpha if unset */ 48503b705cfSriastradh if (PIXMAN_FORMAT_A(format) == 0) 48603b705cfSriastradh format = PIXMAN_a8r8g8b8; 48703b705cfSriastradh 48803b705cfSriastradh pixmap = screen->CreatePixmap(screen, width, height, 48903b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 49003b705cfSriastradh UXA_CREATE_PIXMAP_FOR_MAP); 49103b705cfSriastradh if (!pixmap) 49203b705cfSriastradh return 0; 49303b705cfSriastradh 49403b705cfSriastradh if (!uxa_pixmap_is_offscreen(pixmap)) { 49503b705cfSriastradh screen->DestroyPixmap(pixmap); 49603b705cfSriastradh return 0; 49703b705cfSriastradh } 49803b705cfSriastradh 49903b705cfSriastradh picture = CreatePicture(0, &pixmap->drawable, 50003b705cfSriastradh PictureMatchFormat(screen, 50103b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 50203b705cfSriastradh format), 50303b705cfSriastradh 0, 0, serverClient, &error); 50403b705cfSriastradh screen->DestroyPixmap(pixmap); 50503b705cfSriastradh if (!picture) 50603b705cfSriastradh return 0; 50703b705cfSriastradh 50803b705cfSriastradh ValidatePicture(picture); 50903b705cfSriastradh 51003b705cfSriastradh return picture; 51103b705cfSriastradh} 51203b705cfSriastradh 51303b705cfSriastradhstatic PicturePtr 51403b705cfSriastradhuxa_picture_from_pixman_image(ScreenPtr screen, 51503b705cfSriastradh pixman_image_t * image, 51603b705cfSriastradh pixman_format_code_t format) 51703b705cfSriastradh{ 51803b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(screen); 51903b705cfSriastradh PicturePtr picture; 52003b705cfSriastradh PixmapPtr pixmap; 52103b705cfSriastradh int width, height; 52203b705cfSriastradh 52303b705cfSriastradh width = pixman_image_get_width(image); 52403b705cfSriastradh height = pixman_image_get_height(image); 52503b705cfSriastradh 52603b705cfSriastradh picture = uxa_picture_for_pixman_format(screen, format, 52703b705cfSriastradh width, height); 52803b705cfSriastradh if (!picture) 52903b705cfSriastradh return 0; 53003b705cfSriastradh 53103b705cfSriastradh if (uxa_screen->info->put_image && 53203b705cfSriastradh ((picture->pDrawable->depth << 24) | picture->format) == format && 53303b705cfSriastradh uxa_screen->info->put_image((PixmapPtr)picture->pDrawable, 53403b705cfSriastradh 0, 0, 53503b705cfSriastradh width, height, 53603b705cfSriastradh (char *)pixman_image_get_data(image), 53703b705cfSriastradh pixman_image_get_stride(image))) 53803b705cfSriastradh return picture; 53903b705cfSriastradh 54003b705cfSriastradh pixmap = GetScratchPixmapHeader(screen, width, height, 54103b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 54203b705cfSriastradh PIXMAN_FORMAT_BPP(format), 54303b705cfSriastradh pixman_image_get_stride(image), 54403b705cfSriastradh pixman_image_get_data(image)); 54503b705cfSriastradh if (!pixmap) { 54603b705cfSriastradh FreePicture(picture, 0); 54703b705cfSriastradh return 0; 54803b705cfSriastradh } 54903b705cfSriastradh 55003b705cfSriastradh if (((picture->pDrawable->depth << 24) | picture->format) == format) { 55103b705cfSriastradh GCPtr gc; 55203b705cfSriastradh 55303b705cfSriastradh gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen); 55403b705cfSriastradh if (!gc) { 55503b705cfSriastradh FreeScratchPixmapHeader(pixmap); 55603b705cfSriastradh FreePicture(picture, 0); 55703b705cfSriastradh return 0; 55803b705cfSriastradh } 55903b705cfSriastradh ValidateGC(picture->pDrawable, gc); 56003b705cfSriastradh 56103b705cfSriastradh (*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable, 56203b705cfSriastradh gc, 0, 0, width, height, 0, 0); 56303b705cfSriastradh 56403b705cfSriastradh FreeScratchGC(gc); 56503b705cfSriastradh } else { 56603b705cfSriastradh PicturePtr src; 56703b705cfSriastradh int error; 56803b705cfSriastradh 56903b705cfSriastradh src = CreatePicture(0, &pixmap->drawable, 57003b705cfSriastradh PictureMatchFormat(screen, 57103b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 57203b705cfSriastradh format), 57303b705cfSriastradh 0, 0, serverClient, &error); 57403b705cfSriastradh if (!src) { 57503b705cfSriastradh FreeScratchPixmapHeader(pixmap); 57603b705cfSriastradh FreePicture(picture, 0); 57703b705cfSriastradh return 0; 57803b705cfSriastradh } 57903b705cfSriastradh ValidatePicture(src); 58003b705cfSriastradh 58103b705cfSriastradh if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) { 58203b705cfSriastradh fbComposite(PictOpSrc, src, NULL, picture, 58303b705cfSriastradh 0, 0, 0, 0, 0, 0, width, height); 58403b705cfSriastradh uxa_picture_finish_access(picture, UXA_ACCESS_RW); 58503b705cfSriastradh } 58603b705cfSriastradh 58703b705cfSriastradh FreePicture(src, 0); 58803b705cfSriastradh } 58903b705cfSriastradh FreeScratchPixmapHeader(pixmap); 59003b705cfSriastradh 59103b705cfSriastradh return picture; 59203b705cfSriastradh} 59303b705cfSriastradh 59403b705cfSriastradhstatic PicturePtr 59503b705cfSriastradhuxa_create_solid(ScreenPtr screen, uint32_t color) 59603b705cfSriastradh{ 59703b705cfSriastradh PixmapPtr pixmap; 59803b705cfSriastradh PicturePtr picture; 59903b705cfSriastradh XID repeat = RepeatNormal; 60003b705cfSriastradh int error = 0; 60103b705cfSriastradh 60203b705cfSriastradh pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32, 60303b705cfSriastradh UXA_CREATE_PIXMAP_FOR_MAP); 60403b705cfSriastradh if (!pixmap) 60503b705cfSriastradh return 0; 60603b705cfSriastradh 60703b705cfSriastradh if (!uxa_prepare_access((DrawablePtr)pixmap, UXA_ACCESS_RW)) { 60803b705cfSriastradh (*screen->DestroyPixmap)(pixmap); 60903b705cfSriastradh return 0; 61003b705cfSriastradh } 61103b705cfSriastradh *((uint32_t *)pixmap->devPrivate.ptr) = color; 61203b705cfSriastradh uxa_finish_access((DrawablePtr)pixmap, UXA_ACCESS_RW); 61303b705cfSriastradh 61403b705cfSriastradh picture = CreatePicture(0, &pixmap->drawable, 61503b705cfSriastradh PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 61603b705cfSriastradh CPRepeat, &repeat, serverClient, &error); 61703b705cfSriastradh (*screen->DestroyPixmap)(pixmap); 61803b705cfSriastradh 61903b705cfSriastradh return picture; 62003b705cfSriastradh} 62103b705cfSriastradh 62203b705cfSriastradhstatic PicturePtr 62303b705cfSriastradhuxa_solid_clear(ScreenPtr screen) 62403b705cfSriastradh{ 62503b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(screen); 62603b705cfSriastradh PicturePtr picture; 62703b705cfSriastradh 62803b705cfSriastradh if (!uxa_screen->solid_clear) { 62903b705cfSriastradh uxa_screen->solid_clear = uxa_create_solid(screen, 0); 63003b705cfSriastradh if (!uxa_screen->solid_clear) 63103b705cfSriastradh return 0; 63203b705cfSriastradh } 63303b705cfSriastradh picture = uxa_screen->solid_clear; 63403b705cfSriastradh return picture; 63503b705cfSriastradh} 63603b705cfSriastradh 63703b705cfSriastradhPicturePtr 63803b705cfSriastradhuxa_acquire_solid(ScreenPtr screen, SourcePict *source) 63903b705cfSriastradh{ 64003b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(screen); 64103b705cfSriastradh PictSolidFill *solid = &source->solidFill; 64203b705cfSriastradh PicturePtr picture; 64303b705cfSriastradh int i; 64403b705cfSriastradh 64503b705cfSriastradh if ((solid->color >> 24) == 0) { 64603b705cfSriastradh picture = uxa_solid_clear(screen); 64703b705cfSriastradh if (!picture) 64803b705cfSriastradh return 0; 64903b705cfSriastradh 65003b705cfSriastradh goto DONE; 65103b705cfSriastradh } else if (solid->color == 0xff000000) { 65203b705cfSriastradh if (!uxa_screen->solid_black) { 65303b705cfSriastradh uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000); 65403b705cfSriastradh if (!uxa_screen->solid_black) 65503b705cfSriastradh return 0; 65603b705cfSriastradh } 65703b705cfSriastradh picture = uxa_screen->solid_black; 65803b705cfSriastradh goto DONE; 65903b705cfSriastradh } else if (solid->color == 0xffffffff) { 66003b705cfSriastradh if (!uxa_screen->solid_white) { 66103b705cfSriastradh uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff); 66203b705cfSriastradh if (!uxa_screen->solid_white) 66303b705cfSriastradh return 0; 66403b705cfSriastradh } 66503b705cfSriastradh picture = uxa_screen->solid_white; 66603b705cfSriastradh goto DONE; 66703b705cfSriastradh } 66803b705cfSriastradh 66903b705cfSriastradh for (i = 0; i < uxa_screen->solid_cache_size; i++) { 67003b705cfSriastradh if (uxa_screen->solid_cache[i].color == solid->color) { 67103b705cfSriastradh picture = uxa_screen->solid_cache[i].picture; 67203b705cfSriastradh goto DONE; 67303b705cfSriastradh } 67403b705cfSriastradh } 67503b705cfSriastradh 67603b705cfSriastradh picture = uxa_create_solid(screen, solid->color); 67703b705cfSriastradh if (!picture) 67803b705cfSriastradh return 0; 67903b705cfSriastradh 68003b705cfSriastradh if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) { 68103b705cfSriastradh i = rand() % UXA_NUM_SOLID_CACHE; 68203b705cfSriastradh FreePicture(uxa_screen->solid_cache[i].picture, 0); 68303b705cfSriastradh } else 68403b705cfSriastradh uxa_screen->solid_cache_size++; 68503b705cfSriastradh 68603b705cfSriastradh uxa_screen->solid_cache[i].picture = picture; 68703b705cfSriastradh uxa_screen->solid_cache[i].color = solid->color; 68803b705cfSriastradh 68903b705cfSriastradhDONE: 69003b705cfSriastradh picture->refcnt++; 69103b705cfSriastradh return picture; 69203b705cfSriastradh} 69303b705cfSriastradh 69403b705cfSriastradhPicturePtr 69503b705cfSriastradhuxa_acquire_pattern(ScreenPtr pScreen, 69603b705cfSriastradh PicturePtr pSrc, 69703b705cfSriastradh pixman_format_code_t format, 69803b705cfSriastradh INT16 x, INT16 y, CARD16 width, CARD16 height) 69903b705cfSriastradh{ 70003b705cfSriastradh PicturePtr pDst; 70103b705cfSriastradh 70203b705cfSriastradh if (pSrc->pSourcePict) { 70303b705cfSriastradh SourcePict *source = pSrc->pSourcePict; 70403b705cfSriastradh if (source->type == SourcePictTypeSolidFill) 70503b705cfSriastradh return uxa_acquire_solid (pScreen, source); 70603b705cfSriastradh } 70703b705cfSriastradh 70803b705cfSriastradh pDst = uxa_picture_for_pixman_format(pScreen, format, width, height); 70903b705cfSriastradh if (!pDst) 71003b705cfSriastradh return 0; 71103b705cfSriastradh 71203b705cfSriastradh if (uxa_picture_prepare_access(pDst, UXA_ACCESS_RW)) { 71303b705cfSriastradh fbComposite(PictOpSrc, pSrc, NULL, pDst, 71403b705cfSriastradh x, y, 0, 0, 0, 0, width, height); 71503b705cfSriastradh uxa_picture_finish_access(pDst, UXA_ACCESS_RW); 71603b705cfSriastradh return pDst; 71703b705cfSriastradh } else { 71803b705cfSriastradh FreePicture(pDst, 0); 71903b705cfSriastradh return 0; 72003b705cfSriastradh } 72103b705cfSriastradh} 72203b705cfSriastradh 72303b705cfSriastradhstatic Bool 72403b705cfSriastradhtransform_is_integer_translation(PictTransformPtr t, int *tx, int *ty) 72503b705cfSriastradh{ 72603b705cfSriastradh if (t == NULL) { 72703b705cfSriastradh *tx = *ty = 0; 72803b705cfSriastradh return TRUE; 72903b705cfSriastradh } 73003b705cfSriastradh 73103b705cfSriastradh if (t->matrix[0][0] != IntToxFixed(1) || 73203b705cfSriastradh t->matrix[0][1] != 0 || 73303b705cfSriastradh t->matrix[1][0] != 0 || 73403b705cfSriastradh t->matrix[1][1] != IntToxFixed(1) || 73503b705cfSriastradh t->matrix[2][0] != 0 || 73603b705cfSriastradh t->matrix[2][1] != 0 || 73703b705cfSriastradh t->matrix[2][2] != IntToxFixed(1)) 73803b705cfSriastradh return FALSE; 73903b705cfSriastradh 74003b705cfSriastradh if (xFixedFrac(t->matrix[0][2]) != 0 || 74103b705cfSriastradh xFixedFrac(t->matrix[1][2]) != 0) 74203b705cfSriastradh return FALSE; 74303b705cfSriastradh 74403b705cfSriastradh *tx = xFixedToInt(t->matrix[0][2]); 74503b705cfSriastradh *ty = xFixedToInt(t->matrix[1][2]); 74603b705cfSriastradh return TRUE; 74703b705cfSriastradh} 74803b705cfSriastradh 74903b705cfSriastradhstatic PicturePtr 75003b705cfSriastradhuxa_render_picture(ScreenPtr screen, 75103b705cfSriastradh PicturePtr src, 75203b705cfSriastradh pixman_format_code_t format, 75303b705cfSriastradh INT16 x, INT16 y, 75403b705cfSriastradh CARD16 width, CARD16 height) 75503b705cfSriastradh{ 75603b705cfSriastradh PicturePtr picture; 75703b705cfSriastradh int ret = 0; 75803b705cfSriastradh 75903b705cfSriastradh /* XXX we need a mechanism for the card to choose the fallback format */ 76003b705cfSriastradh 76103b705cfSriastradh /* force alpha channel in case source does not entirely cover the extents */ 76203b705cfSriastradh if (PIXMAN_FORMAT_A(format) == 0) 76303b705cfSriastradh format = PIXMAN_a8r8g8b8; /* available on all hardware */ 76403b705cfSriastradh 76503b705cfSriastradh picture = uxa_picture_for_pixman_format(screen, format, width, height); 76603b705cfSriastradh if (!picture) 76703b705cfSriastradh return 0; 76803b705cfSriastradh 76903b705cfSriastradh if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) { 77003b705cfSriastradh if (uxa_picture_prepare_access(src, UXA_ACCESS_RO)) { 77103b705cfSriastradh ret = 1; 77203b705cfSriastradh fbComposite(PictOpSrc, src, NULL, picture, 77303b705cfSriastradh x, y, 0, 0, 0, 0, width, height); 77403b705cfSriastradh uxa_picture_finish_access(src, UXA_ACCESS_RO); 77503b705cfSriastradh } 77603b705cfSriastradh uxa_picture_finish_access(picture, UXA_ACCESS_RW); 77703b705cfSriastradh } 77803b705cfSriastradh 77903b705cfSriastradh if (!ret) { 78003b705cfSriastradh FreePicture(picture, 0); 78103b705cfSriastradh return 0; 78203b705cfSriastradh } 78303b705cfSriastradh 78403b705cfSriastradh return picture; 78503b705cfSriastradh} 78603b705cfSriastradh 78703b705cfSriastradhstatic int 78803b705cfSriastradhdrawable_contains (DrawablePtr drawable, int x, int y, int w, int h) 78903b705cfSriastradh{ 79003b705cfSriastradh if (x < 0 || y < 0) 79103b705cfSriastradh return FALSE; 79203b705cfSriastradh 79303b705cfSriastradh if (x + w > drawable->width) 79403b705cfSriastradh return FALSE; 79503b705cfSriastradh 79603b705cfSriastradh if (y + h > drawable->height) 79703b705cfSriastradh return FALSE; 79803b705cfSriastradh 79903b705cfSriastradh return TRUE; 80003b705cfSriastradh} 80103b705cfSriastradh 80203b705cfSriastradhPicturePtr 80303b705cfSriastradhuxa_acquire_drawable(ScreenPtr pScreen, 80403b705cfSriastradh PicturePtr pSrc, 80503b705cfSriastradh INT16 x, INT16 y, 80603b705cfSriastradh CARD16 width, CARD16 height, 80703b705cfSriastradh INT16 * out_x, INT16 * out_y) 80803b705cfSriastradh{ 80903b705cfSriastradh PixmapPtr pPixmap; 81003b705cfSriastradh PicturePtr pDst; 81103b705cfSriastradh int depth, error; 81203b705cfSriastradh int tx, ty; 81303b705cfSriastradh GCPtr pGC; 81403b705cfSriastradh 81503b705cfSriastradh depth = pSrc->pDrawable->depth; 81603b705cfSriastradh if (!transform_is_integer_translation(pSrc->transform, &tx, &ty) || 81703b705cfSriastradh !drawable_contains(pSrc->pDrawable, x + tx, y + ty, width, height) || 81803b705cfSriastradh depth == 1 || 81903b705cfSriastradh pSrc->filter == PictFilterConvolution) { 82003b705cfSriastradh /* XXX extract the sample extents and do the transformation on the GPU */ 82103b705cfSriastradh pDst = uxa_render_picture(pScreen, pSrc, 82203b705cfSriastradh pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24), 82303b705cfSriastradh x, y, width, height); 82403b705cfSriastradh if (!pDst) 82503b705cfSriastradh return 0; 82603b705cfSriastradh 82703b705cfSriastradh goto done; 82803b705cfSriastradh } else { 82903b705cfSriastradh if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->height) { 83003b705cfSriastradh *out_x = x + pSrc->pDrawable->x; 83103b705cfSriastradh *out_y = y + pSrc->pDrawable->y; 83203b705cfSriastradh return pSrc; 83303b705cfSriastradh } 83403b705cfSriastradh } 83503b705cfSriastradh 83603b705cfSriastradh pPixmap = pScreen->CreatePixmap(pScreen, 83703b705cfSriastradh width, height, depth, 83803b705cfSriastradh CREATE_PIXMAP_USAGE_SCRATCH); 83903b705cfSriastradh if (!pPixmap) 84003b705cfSriastradh return 0; 84103b705cfSriastradh 84203b705cfSriastradh /* Skip the copy if the result remains in memory and not a bo */ 84303b705cfSriastradh if (!uxa_pixmap_is_offscreen(pPixmap)) { 84403b705cfSriastradh pScreen->DestroyPixmap(pPixmap); 84503b705cfSriastradh return 0; 84603b705cfSriastradh } 84703b705cfSriastradh 84803b705cfSriastradh pGC = GetScratchGC(depth, pScreen); 84903b705cfSriastradh if (!pGC) { 85003b705cfSriastradh pScreen->DestroyPixmap(pPixmap); 85103b705cfSriastradh return 0; 85203b705cfSriastradh } 85303b705cfSriastradh 85403b705cfSriastradh ValidateGC(&pPixmap->drawable, pGC); 85503b705cfSriastradh pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC, 85603b705cfSriastradh x + tx, y + ty, width, height, 0, 0); 85703b705cfSriastradh FreeScratchGC(pGC); 85803b705cfSriastradh 85903b705cfSriastradh pDst = CreatePicture(0, &pPixmap->drawable, 86003b705cfSriastradh PictureMatchFormat(pScreen, depth, pSrc->format), 86103b705cfSriastradh 0, 0, serverClient, &error); 86203b705cfSriastradh pScreen->DestroyPixmap(pPixmap); 86303b705cfSriastradh if (!pDst) 86403b705cfSriastradh return 0; 86503b705cfSriastradh 86603b705cfSriastradh ValidatePicture(pDst); 86703b705cfSriastradhdone: 86803b705cfSriastradh pDst->componentAlpha = pSrc->componentAlpha; 86903b705cfSriastradh *out_x = 0; 87003b705cfSriastradh *out_y = 0; 87103b705cfSriastradh return pDst; 87203b705cfSriastradh} 87303b705cfSriastradh 87403b705cfSriastradhstatic PicturePtr 87503b705cfSriastradhuxa_acquire_picture(ScreenPtr screen, 87603b705cfSriastradh PicturePtr src, 87703b705cfSriastradh pixman_format_code_t format, 87803b705cfSriastradh INT16 x, INT16 y, 87903b705cfSriastradh CARD16 width, CARD16 height, 88003b705cfSriastradh INT16 * out_x, INT16 * out_y) 88103b705cfSriastradh{ 88203b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(screen); 88303b705cfSriastradh 88403b705cfSriastradh if (uxa_screen->info->check_composite_texture && 88503b705cfSriastradh uxa_screen->info->check_composite_texture(screen, src)) { 88603b705cfSriastradh if (src->pDrawable) { 88703b705cfSriastradh *out_x = x + src->pDrawable->x; 88803b705cfSriastradh *out_y = y + src->pDrawable->y; 88903b705cfSriastradh } else { 89003b705cfSriastradh *out_x = x; 89103b705cfSriastradh *out_y = y; 89203b705cfSriastradh } 89303b705cfSriastradh return src; 89403b705cfSriastradh } 89503b705cfSriastradh 89603b705cfSriastradh if (src->pDrawable) { 89703b705cfSriastradh PicturePtr dst; 89803b705cfSriastradh 89903b705cfSriastradh dst = uxa_acquire_drawable(screen, src, 90003b705cfSriastradh x, y, width, height, 90103b705cfSriastradh out_x, out_y); 90203b705cfSriastradh if (!dst) 90303b705cfSriastradh return 0; 90403b705cfSriastradh 90503b705cfSriastradh if (uxa_screen->info->check_composite_texture && 90603b705cfSriastradh !uxa_screen->info->check_composite_texture(screen, dst)) { 90703b705cfSriastradh if (dst != src) 90803b705cfSriastradh FreePicture(dst, 0); 90903b705cfSriastradh return 0; 91003b705cfSriastradh } 91103b705cfSriastradh 91203b705cfSriastradh return dst; 91303b705cfSriastradh } 91403b705cfSriastradh 91503b705cfSriastradh *out_x = 0; 91603b705cfSriastradh *out_y = 0; 91703b705cfSriastradh return uxa_acquire_pattern(screen, src, 91803b705cfSriastradh format, x, y, width, height); 91903b705cfSriastradh} 92003b705cfSriastradh 92103b705cfSriastradhstatic PicturePtr 92203b705cfSriastradhuxa_acquire_source(ScreenPtr screen, 92303b705cfSriastradh PicturePtr pict, 92403b705cfSriastradh INT16 x, INT16 y, 92503b705cfSriastradh CARD16 width, CARD16 height, 92603b705cfSriastradh INT16 * out_x, INT16 * out_y) 92703b705cfSriastradh{ 92803b705cfSriastradh return uxa_acquire_picture (screen, pict, 92942542f5fSchristos PIXMAN_a8r8g8b8, 93003b705cfSriastradh x, y, 93103b705cfSriastradh width, height, 93203b705cfSriastradh out_x, out_y); 93303b705cfSriastradh} 93403b705cfSriastradh 93503b705cfSriastradhstatic PicturePtr 93603b705cfSriastradhuxa_acquire_mask(ScreenPtr screen, 93703b705cfSriastradh PicturePtr pict, 93803b705cfSriastradh INT16 x, INT16 y, 93903b705cfSriastradh INT16 width, INT16 height, 94003b705cfSriastradh INT16 * out_x, INT16 * out_y) 94103b705cfSriastradh{ 94203b705cfSriastradh return uxa_acquire_picture (screen, pict, 94342542f5fSchristos PIXMAN_a8, 94403b705cfSriastradh x, y, 94503b705cfSriastradh width, height, 94603b705cfSriastradh out_x, out_y); 94703b705cfSriastradh} 94803b705cfSriastradh 94903b705cfSriastradhstatic int 95003b705cfSriastradhuxa_try_driver_composite(CARD8 op, 95103b705cfSriastradh PicturePtr pSrc, 95203b705cfSriastradh PicturePtr pMask, 95303b705cfSriastradh PicturePtr pDst, 95403b705cfSriastradh INT16 xSrc, INT16 ySrc, 95503b705cfSriastradh INT16 xMask, INT16 yMask, 95603b705cfSriastradh INT16 xDst, INT16 yDst, 95703b705cfSriastradh CARD16 width, CARD16 height) 95803b705cfSriastradh{ 95903b705cfSriastradh ScreenPtr screen = pDst->pDrawable->pScreen; 96003b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(screen); 96103b705cfSriastradh RegionRec region; 96203b705cfSriastradh BoxPtr pbox; 96303b705cfSriastradh int nbox; 96403b705cfSriastradh int xDst_copy = 0, yDst_copy = 0; 96503b705cfSriastradh int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 96603b705cfSriastradh PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; 96703b705cfSriastradh PicturePtr localSrc, localMask = NULL; 96803b705cfSriastradh PicturePtr localDst = pDst; 96903b705cfSriastradh 97003b705cfSriastradh if (uxa_screen->info->check_composite && 97103b705cfSriastradh !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height)) 97203b705cfSriastradh return -1; 97303b705cfSriastradh 97403b705cfSriastradh if (uxa_screen->info->check_composite_target && 97503b705cfSriastradh !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 97603b705cfSriastradh int depth = pDst->pDrawable->depth; 97703b705cfSriastradh PixmapPtr pixmap; 97803b705cfSriastradh int error; 97903b705cfSriastradh GCPtr gc; 98003b705cfSriastradh 98103b705cfSriastradh pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 98203b705cfSriastradh if (uxa_screen->info->check_copy && 98303b705cfSriastradh !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 98403b705cfSriastradh return -1; 98503b705cfSriastradh 98603b705cfSriastradh pixmap = screen->CreatePixmap(screen, 98703b705cfSriastradh width, height, depth, 98803b705cfSriastradh CREATE_PIXMAP_USAGE_SCRATCH); 98903b705cfSriastradh if (!pixmap) 99003b705cfSriastradh return 0; 99103b705cfSriastradh 99203b705cfSriastradh gc = GetScratchGC(depth, screen); 99303b705cfSriastradh if (!gc) { 99403b705cfSriastradh screen->DestroyPixmap(pixmap); 99503b705cfSriastradh return 0; 99603b705cfSriastradh } 99703b705cfSriastradh 99803b705cfSriastradh ValidateGC(&pixmap->drawable, gc); 99903b705cfSriastradh gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 100003b705cfSriastradh xDst, yDst, width, height, 0, 0); 100103b705cfSriastradh FreeScratchGC(gc); 100203b705cfSriastradh 100303b705cfSriastradh xDst_copy = xDst; xDst = 0; 100403b705cfSriastradh yDst_copy = yDst; yDst = 0; 100503b705cfSriastradh 100603b705cfSriastradh localDst = CreatePicture(0, &pixmap->drawable, 100703b705cfSriastradh PictureMatchFormat(screen, depth, pDst->format), 100803b705cfSriastradh 0, 0, serverClient, &error); 100903b705cfSriastradh screen->DestroyPixmap(pixmap); 101003b705cfSriastradh 101103b705cfSriastradh if (!localDst) 101203b705cfSriastradh return 0; 101303b705cfSriastradh 101403b705cfSriastradh ValidatePicture(localDst); 101503b705cfSriastradh } 101603b705cfSriastradh 101703b705cfSriastradh pDstPix = 101803b705cfSriastradh uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y); 101903b705cfSriastradh if (!pDstPix) { 102003b705cfSriastradh if (localDst != pDst) 102103b705cfSriastradh FreePicture(localDst, 0); 102203b705cfSriastradh return -1; 102303b705cfSriastradh } 102403b705cfSriastradh 102503b705cfSriastradh xDst += localDst->pDrawable->x; 102603b705cfSriastradh yDst += localDst->pDrawable->y; 102703b705cfSriastradh 102803b705cfSriastradh localSrc = uxa_acquire_source(screen, pSrc, 102903b705cfSriastradh xSrc, ySrc, 103003b705cfSriastradh width, height, 103103b705cfSriastradh &xSrc, &ySrc); 103203b705cfSriastradh if (!localSrc) { 103303b705cfSriastradh if (localDst != pDst) 103403b705cfSriastradh FreePicture(localDst, 0); 103503b705cfSriastradh return 0; 103603b705cfSriastradh } 103703b705cfSriastradh 103803b705cfSriastradh if (pMask) { 103903b705cfSriastradh localMask = uxa_acquire_mask(screen, pMask, 104003b705cfSriastradh xMask, yMask, 104103b705cfSriastradh width, height, 104203b705cfSriastradh &xMask, &yMask); 104303b705cfSriastradh if (!localMask) { 104403b705cfSriastradh if (localSrc != pSrc) 104503b705cfSriastradh FreePicture(localSrc, 0); 104603b705cfSriastradh if (localDst != pDst) 104703b705cfSriastradh FreePicture(localDst, 0); 104803b705cfSriastradh 104903b705cfSriastradh return 0; 105003b705cfSriastradh } 105103b705cfSriastradh } 105203b705cfSriastradh 105303b705cfSriastradh if (!miComputeCompositeRegion(®ion, localSrc, localMask, localDst, 105403b705cfSriastradh xSrc, ySrc, xMask, yMask, xDst, yDst, 105503b705cfSriastradh width, height)) { 105603b705cfSriastradh if (localSrc != pSrc) 105703b705cfSriastradh FreePicture(localSrc, 0); 105803b705cfSriastradh if (localMask && localMask != pMask) 105903b705cfSriastradh FreePicture(localMask, 0); 106003b705cfSriastradh if (localDst != pDst) 106103b705cfSriastradh FreePicture(localDst, 0); 106203b705cfSriastradh 106303b705cfSriastradh return 1; 106403b705cfSriastradh } 106503b705cfSriastradh 106603b705cfSriastradh pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, 106703b705cfSriastradh &src_off_x, &src_off_y); 106803b705cfSriastradh if (!pSrcPix) { 106903b705cfSriastradh REGION_UNINIT(screen, ®ion); 107003b705cfSriastradh 107103b705cfSriastradh if (localSrc != pSrc) 107203b705cfSriastradh FreePicture(localSrc, 0); 107303b705cfSriastradh if (localMask && localMask != pMask) 107403b705cfSriastradh FreePicture(localMask, 0); 107503b705cfSriastradh if (localDst != pDst) 107603b705cfSriastradh FreePicture(localDst, 0); 107703b705cfSriastradh 107803b705cfSriastradh return 0; 107903b705cfSriastradh } 108003b705cfSriastradh 108103b705cfSriastradh if (localMask) { 108203b705cfSriastradh pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, 108303b705cfSriastradh &mask_off_x, &mask_off_y); 108403b705cfSriastradh if (!pMaskPix) { 108503b705cfSriastradh REGION_UNINIT(screen, ®ion); 108603b705cfSriastradh 108703b705cfSriastradh if (localSrc != pSrc) 108803b705cfSriastradh FreePicture(localSrc, 0); 108903b705cfSriastradh if (localMask && localMask != pMask) 109003b705cfSriastradh FreePicture(localMask, 0); 109103b705cfSriastradh if (localDst != pDst) 109203b705cfSriastradh FreePicture(localDst, 0); 109303b705cfSriastradh 109403b705cfSriastradh return 0; 109503b705cfSriastradh } 109603b705cfSriastradh } 109703b705cfSriastradh 109803b705cfSriastradh if (!(*uxa_screen->info->prepare_composite) 109903b705cfSriastradh (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) { 110003b705cfSriastradh REGION_UNINIT(screen, ®ion); 110103b705cfSriastradh 110203b705cfSriastradh if (localSrc != pSrc) 110303b705cfSriastradh FreePicture(localSrc, 0); 110403b705cfSriastradh if (localMask && localMask != pMask) 110503b705cfSriastradh FreePicture(localMask, 0); 110603b705cfSriastradh if (localDst != pDst) 110703b705cfSriastradh FreePicture(localDst, 0); 110803b705cfSriastradh 110903b705cfSriastradh return -1; 111003b705cfSriastradh } 111103b705cfSriastradh 111203b705cfSriastradh if (pMask) { 111303b705cfSriastradh xMask = xMask + mask_off_x - xDst; 111403b705cfSriastradh yMask = yMask + mask_off_y - yDst; 111503b705cfSriastradh } 111603b705cfSriastradh 111703b705cfSriastradh xSrc = xSrc + src_off_x - xDst; 111803b705cfSriastradh ySrc = ySrc + src_off_y - yDst; 111903b705cfSriastradh 112003b705cfSriastradh nbox = REGION_NUM_RECTS(®ion); 112103b705cfSriastradh pbox = REGION_RECTS(®ion); 112203b705cfSriastradh while (nbox--) { 112303b705cfSriastradh (*uxa_screen->info->composite) (pDstPix, 112403b705cfSriastradh pbox->x1 + xSrc, 112503b705cfSriastradh pbox->y1 + ySrc, 112603b705cfSriastradh pbox->x1 + xMask, 112703b705cfSriastradh pbox->y1 + yMask, 112803b705cfSriastradh pbox->x1 + dst_off_x, 112903b705cfSriastradh pbox->y1 + dst_off_y, 113003b705cfSriastradh pbox->x2 - pbox->x1, 113103b705cfSriastradh pbox->y2 - pbox->y1); 113203b705cfSriastradh pbox++; 113303b705cfSriastradh } 113403b705cfSriastradh (*uxa_screen->info->done_composite) (pDstPix); 113503b705cfSriastradh 113603b705cfSriastradh REGION_UNINIT(screen, ®ion); 113703b705cfSriastradh 113803b705cfSriastradh if (localSrc != pSrc) 113903b705cfSriastradh FreePicture(localSrc, 0); 114003b705cfSriastradh if (localMask && localMask != pMask) 114103b705cfSriastradh FreePicture(localMask, 0); 114203b705cfSriastradh 114303b705cfSriastradh if (localDst != pDst) { 114403b705cfSriastradh GCPtr gc; 114503b705cfSriastradh 114603b705cfSriastradh gc = GetScratchGC(pDst->pDrawable->depth, screen); 114703b705cfSriastradh if (gc) { 114803b705cfSriastradh ValidateGC(pDst->pDrawable, gc); 114903b705cfSriastradh gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 115003b705cfSriastradh 0, 0, width, height, xDst_copy, yDst_copy); 115103b705cfSriastradh FreeScratchGC(gc); 115203b705cfSriastradh } 115303b705cfSriastradh 115403b705cfSriastradh FreePicture(localDst, 0); 115503b705cfSriastradh } 115603b705cfSriastradh 115703b705cfSriastradh return 1; 115803b705cfSriastradh} 115903b705cfSriastradh 116003b705cfSriastradh/** 116103b705cfSriastradh * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of 116203b705cfSriastradh * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 116303b705cfSriastradh * alpha and limited 1-tmu cards. 116403b705cfSriastradh * 116503b705cfSriastradh * From http://anholt.livejournal.com/32058.html: 116603b705cfSriastradh * 116703b705cfSriastradh * The trouble is that component-alpha rendering requires two different sources 116803b705cfSriastradh * for blending: one for the source value to the blender, which is the 116903b705cfSriastradh * per-channel multiplication of source and mask, and one for the source alpha 117003b705cfSriastradh * for multiplying with the destination channels, which is the multiplication 117103b705cfSriastradh * of the source channels by the mask alpha. So the equation for Over is: 117203b705cfSriastradh * 117303b705cfSriastradh * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 117403b705cfSriastradh * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 117503b705cfSriastradh * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 117603b705cfSriastradh * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 117703b705cfSriastradh * 117803b705cfSriastradh * But we can do some simpler operations, right? How about PictOpOutReverse, 117903b705cfSriastradh * which has a source factor of 0 and dest factor of (1 - source alpha). We 118003b705cfSriastradh * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 118103b705cfSriastradh * blenders pretty easily. So we can do a component-alpha OutReverse, which 118203b705cfSriastradh * gets us: 118303b705cfSriastradh * 118403b705cfSriastradh * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 118503b705cfSriastradh * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 118603b705cfSriastradh * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 118703b705cfSriastradh * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 118803b705cfSriastradh * 118903b705cfSriastradh * OK. And if an op doesn't use the source alpha value for the destination 119003b705cfSriastradh * factor, then we can do the channel multiplication in the texture blenders 119103b705cfSriastradh * to get the source value, and ignore the source alpha that we wouldn't use. 119203b705cfSriastradh * We've supported this in the Radeon driver for a long time. An example would 119303b705cfSriastradh * be PictOpAdd, which does: 119403b705cfSriastradh * 119503b705cfSriastradh * dst.A = src.A * mask.A + dst.A 119603b705cfSriastradh * dst.R = src.R * mask.R + dst.R 119703b705cfSriastradh * dst.G = src.G * mask.G + dst.G 119803b705cfSriastradh * dst.B = src.B * mask.B + dst.B 119903b705cfSriastradh * 120003b705cfSriastradh * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 120103b705cfSriastradh * after it, we get: 120203b705cfSriastradh * 120303b705cfSriastradh * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 120403b705cfSriastradh * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 120503b705cfSriastradh * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 120603b705cfSriastradh * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 120703b705cfSriastradh */ 120803b705cfSriastradh 120903b705cfSriastradhstatic int 121003b705cfSriastradhuxa_try_magic_two_pass_composite_helper(CARD8 op, 121103b705cfSriastradh PicturePtr pSrc, 121203b705cfSriastradh PicturePtr pMask, 121303b705cfSriastradh PicturePtr pDst, 121403b705cfSriastradh INT16 xSrc, INT16 ySrc, 121503b705cfSriastradh INT16 xMask, INT16 yMask, 121603b705cfSriastradh INT16 xDst, INT16 yDst, 121703b705cfSriastradh CARD16 width, CARD16 height) 121803b705cfSriastradh{ 121903b705cfSriastradh ScreenPtr screen = pDst->pDrawable->pScreen; 122003b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(screen); 122103b705cfSriastradh PicturePtr localDst = pDst; 122203b705cfSriastradh int xDst_copy, yDst_copy; 122303b705cfSriastradh 122403b705cfSriastradh assert(op == PictOpOver); 122503b705cfSriastradh 122603b705cfSriastradh if (uxa_screen->info->check_composite && 122703b705cfSriastradh (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc, 122803b705cfSriastradh pMask, pDst, width, height) 122903b705cfSriastradh || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask, 123003b705cfSriastradh pDst, width, height))) { 123103b705cfSriastradh return -1; 123203b705cfSriastradh } 123303b705cfSriastradh 123403b705cfSriastradh if (uxa_screen->info->check_composite_target && 123503b705cfSriastradh !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 123603b705cfSriastradh int depth = pDst->pDrawable->depth; 123703b705cfSriastradh PixmapPtr pixmap; 123803b705cfSriastradh int error; 123903b705cfSriastradh GCPtr gc; 124003b705cfSriastradh 124103b705cfSriastradh pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 124203b705cfSriastradh if (uxa_screen->info->check_copy && 124303b705cfSriastradh !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 124403b705cfSriastradh return -1; 124503b705cfSriastradh 124603b705cfSriastradh pixmap = screen->CreatePixmap(screen, 124703b705cfSriastradh width, height, depth, 124803b705cfSriastradh CREATE_PIXMAP_USAGE_SCRATCH); 124903b705cfSriastradh if (!pixmap) 125003b705cfSriastradh return 0; 125103b705cfSriastradh 125203b705cfSriastradh gc = GetScratchGC(depth, screen); 125303b705cfSriastradh if (!gc) { 125403b705cfSriastradh screen->DestroyPixmap(pixmap); 125503b705cfSriastradh return 0; 125603b705cfSriastradh } 125703b705cfSriastradh 125803b705cfSriastradh ValidateGC(&pixmap->drawable, gc); 125903b705cfSriastradh gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 126003b705cfSriastradh xDst, yDst, width, height, 0, 0); 126103b705cfSriastradh FreeScratchGC(gc); 126203b705cfSriastradh 126303b705cfSriastradh xDst_copy = xDst; xDst = 0; 126403b705cfSriastradh yDst_copy = yDst; yDst = 0; 126503b705cfSriastradh 126603b705cfSriastradh localDst = CreatePicture(0, &pixmap->drawable, 126703b705cfSriastradh PictureMatchFormat(screen, depth, pDst->format), 126803b705cfSriastradh 0, 0, serverClient, &error); 126903b705cfSriastradh screen->DestroyPixmap(pixmap); 127003b705cfSriastradh 127103b705cfSriastradh if (!localDst) 127203b705cfSriastradh return 0; 127303b705cfSriastradh 127403b705cfSriastradh ValidatePicture(localDst); 127503b705cfSriastradh } 127603b705cfSriastradh 127703b705cfSriastradh /* Now, we think we should be able to accelerate this operation. First, 127803b705cfSriastradh * composite the destination to be the destination times the source alpha 127903b705cfSriastradh * factors. 128003b705cfSriastradh */ 128103b705cfSriastradh uxa_composite(PictOpOutReverse, pSrc, pMask, localDst, 128203b705cfSriastradh xSrc, ySrc, 128303b705cfSriastradh xMask, yMask, 128403b705cfSriastradh xDst, yDst, 128503b705cfSriastradh width, height); 128603b705cfSriastradh 128703b705cfSriastradh /* Then, add in the source value times the destination alpha factors (1.0). 128803b705cfSriastradh */ 128903b705cfSriastradh uxa_composite(PictOpAdd, pSrc, pMask, localDst, 129003b705cfSriastradh xSrc, ySrc, 129103b705cfSriastradh xMask, yMask, 129203b705cfSriastradh xDst, yDst, 129303b705cfSriastradh width, height); 129403b705cfSriastradh 129503b705cfSriastradh if (localDst != pDst) { 129603b705cfSriastradh GCPtr gc; 129703b705cfSriastradh 129803b705cfSriastradh gc = GetScratchGC(pDst->pDrawable->depth, screen); 129903b705cfSriastradh if (gc) { 130003b705cfSriastradh ValidateGC(pDst->pDrawable, gc); 130103b705cfSriastradh gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 130203b705cfSriastradh 0, 0, width, height, xDst_copy, yDst_copy); 130303b705cfSriastradh FreeScratchGC(gc); 130403b705cfSriastradh } 130503b705cfSriastradh 130603b705cfSriastradh FreePicture(localDst, 0); 130703b705cfSriastradh } 130803b705cfSriastradh 130903b705cfSriastradh return 1; 131003b705cfSriastradh} 131103b705cfSriastradh 131203b705cfSriastradhstatic int 131303b705cfSriastradhcompatible_formats (CARD8 op, PicturePtr dst, PicturePtr src) 131403b705cfSriastradh{ 131503b705cfSriastradh if (op == PictOpSrc) { 131603b705cfSriastradh if (src->format == dst->format) 131703b705cfSriastradh return 1; 131803b705cfSriastradh 131903b705cfSriastradh /* Is the destination an alpha-less version of source? */ 132003b705cfSriastradh if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format), 132103b705cfSriastradh PICT_FORMAT_TYPE(src->format), 132203b705cfSriastradh 0, 132303b705cfSriastradh PICT_FORMAT_R(src->format), 132403b705cfSriastradh PICT_FORMAT_G(src->format), 132503b705cfSriastradh PICT_FORMAT_B(src->format))) 132603b705cfSriastradh return 1; 132703b705cfSriastradh 132803b705cfSriastradh /* XXX xrgb is promoted to argb during image upload... */ 132903b705cfSriastradh#if 0 133003b705cfSriastradh if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8) 133103b705cfSriastradh return 1; 133203b705cfSriastradh#endif 133303b705cfSriastradh } else if (op == PictOpOver) { 133403b705cfSriastradh if (PICT_FORMAT_A(src->format)) 133503b705cfSriastradh return 0; 133603b705cfSriastradh 133703b705cfSriastradh return src->format == dst->format; 133803b705cfSriastradh } 133903b705cfSriastradh 134003b705cfSriastradh return 0; 134103b705cfSriastradh} 134203b705cfSriastradh 134303b705cfSriastradhvoid 134403b705cfSriastradhuxa_composite(CARD8 op, 134503b705cfSriastradh PicturePtr pSrc, 134603b705cfSriastradh PicturePtr pMask, 134703b705cfSriastradh PicturePtr pDst, 134803b705cfSriastradh INT16 xSrc, INT16 ySrc, 134903b705cfSriastradh INT16 xMask, INT16 yMask, 135003b705cfSriastradh INT16 xDst, INT16 yDst, 135103b705cfSriastradh CARD16 width, CARD16 height) 135203b705cfSriastradh{ 135303b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 135403b705cfSriastradh int ret = -1; 135503b705cfSriastradh Bool saveSrcRepeat = pSrc->repeat; 135603b705cfSriastradh Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 135703b705cfSriastradh RegionRec region; 135803b705cfSriastradh int tx, ty; 135903b705cfSriastradh 136003b705cfSriastradh if (uxa_screen->info->flags & UXA_USE_GLAMOR) { 136103b705cfSriastradh int ok; 136203b705cfSriastradh 136303b705cfSriastradh uxa_picture_prepare_access(pDst, UXA_GLAMOR_ACCESS_RW); 136403b705cfSriastradh uxa_picture_prepare_access(pSrc, UXA_GLAMOR_ACCESS_RO); 136503b705cfSriastradh if (pMask) 136603b705cfSriastradh uxa_picture_prepare_access(pMask, UXA_GLAMOR_ACCESS_RO); 136703b705cfSriastradh 136803b705cfSriastradh ok = glamor_composite_nf(op, 136903b705cfSriastradh pSrc, pMask, pDst, xSrc, ySrc, 137003b705cfSriastradh xMask, yMask, xDst, yDst, 137103b705cfSriastradh width, height); 137203b705cfSriastradh 137303b705cfSriastradh if (pMask) 137403b705cfSriastradh uxa_picture_finish_access(pMask, UXA_GLAMOR_ACCESS_RO); 137503b705cfSriastradh uxa_picture_finish_access(pSrc, UXA_GLAMOR_ACCESS_RO); 137603b705cfSriastradh uxa_picture_finish_access(pDst, UXA_GLAMOR_ACCESS_RW); 137703b705cfSriastradh 137803b705cfSriastradh if (!ok) 137903b705cfSriastradh goto fallback; 138003b705cfSriastradh 138103b705cfSriastradh return; 138203b705cfSriastradh } 138303b705cfSriastradh 138403b705cfSriastradh if (uxa_screen->force_fallback) 138503b705cfSriastradh goto fallback; 138603b705cfSriastradh 138703b705cfSriastradh if (!uxa_drawable_is_offscreen(pDst->pDrawable)) 138803b705cfSriastradh goto fallback; 138903b705cfSriastradh 139003b705cfSriastradh if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) 139103b705cfSriastradh goto fallback; 139203b705cfSriastradh 139303b705cfSriastradh /* Remove repeat in source if useless */ 139403b705cfSriastradh if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution && 139503b705cfSriastradh transform_is_integer_translation(pSrc->transform, &tx, &ty) && 139603b705cfSriastradh (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) && 139703b705cfSriastradh drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height)) 139803b705cfSriastradh pSrc->repeat = 0; 139903b705cfSriastradh 140003b705cfSriastradh if (!pMask) { 140103b705cfSriastradh if (op == PictOpClear) { 140203b705cfSriastradh PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen); 140303b705cfSriastradh if (clear && 140403b705cfSriastradh uxa_try_driver_solid_fill(clear, pDst, 140503b705cfSriastradh xSrc, ySrc, 140603b705cfSriastradh xDst, yDst, 140703b705cfSriastradh width, height) == 1) 140803b705cfSriastradh goto done; 140903b705cfSriastradh } 141003b705cfSriastradh 141103b705cfSriastradh if (pSrc->pDrawable == NULL) { 141203b705cfSriastradh if (pSrc->pSourcePict) { 141303b705cfSriastradh SourcePict *source = pSrc->pSourcePict; 141403b705cfSriastradh if (source->type == SourcePictTypeSolidFill) { 141503b705cfSriastradh if (op == PictOpSrc || 141603b705cfSriastradh (op == PictOpOver && 141703b705cfSriastradh (source->solidFill.color & 0xff000000) == 0xff000000)) { 141803b705cfSriastradh ret = uxa_try_driver_solid_fill(pSrc, pDst, 141903b705cfSriastradh xSrc, ySrc, 142003b705cfSriastradh xDst, yDst, 142103b705cfSriastradh width, height); 142203b705cfSriastradh if (ret == 1) 142303b705cfSriastradh goto done; 142403b705cfSriastradh } 142503b705cfSriastradh } 142603b705cfSriastradh } 142703b705cfSriastradh } else if (pSrc->pDrawable->width == 1 && 142803b705cfSriastradh pSrc->pDrawable->height == 1 && 142903b705cfSriastradh pSrc->repeat && 143003b705cfSriastradh (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) { 143103b705cfSriastradh ret = uxa_try_driver_solid_fill(pSrc, pDst, 143203b705cfSriastradh xSrc, ySrc, 143303b705cfSriastradh xDst, yDst, 143403b705cfSriastradh width, height); 143503b705cfSriastradh if (ret == 1) 143603b705cfSriastradh goto done; 143703b705cfSriastradh } else if (compatible_formats (op, pDst, pSrc) && 143803b705cfSriastradh pSrc->filter != PictFilterConvolution && 143903b705cfSriastradh transform_is_integer_translation(pSrc->transform, &tx, &ty)) { 144003b705cfSriastradh if (!pSrc->repeat && 144103b705cfSriastradh drawable_contains(pSrc->pDrawable, 144203b705cfSriastradh xSrc + tx, ySrc + ty, 144303b705cfSriastradh width, height)) { 144403b705cfSriastradh xDst += pDst->pDrawable->x; 144503b705cfSriastradh yDst += pDst->pDrawable->y; 144603b705cfSriastradh xSrc += pSrc->pDrawable->x + tx; 144703b705cfSriastradh ySrc += pSrc->pDrawable->y + ty; 144803b705cfSriastradh 144903b705cfSriastradh if (!miComputeCompositeRegion 145003b705cfSriastradh (®ion, pSrc, pMask, pDst, xSrc, ySrc, 145103b705cfSriastradh xMask, yMask, xDst, yDst, width, height)) 145203b705cfSriastradh goto done; 145303b705cfSriastradh 145403b705cfSriastradh uxa_copy_n_to_n(pSrc->pDrawable, 145503b705cfSriastradh pDst->pDrawable, NULL, 145603b705cfSriastradh REGION_RECTS(®ion), 145703b705cfSriastradh REGION_NUM_RECTS(®ion), 145803b705cfSriastradh xSrc - xDst, ySrc - yDst, FALSE, 145903b705cfSriastradh FALSE, 0, NULL); 146003b705cfSriastradh REGION_UNINIT(pDst->pDrawable->pScreen, 146103b705cfSriastradh ®ion); 146203b705cfSriastradh goto done; 146303b705cfSriastradh } else if (pSrc->repeat && pSrc->repeatType == RepeatNormal && 146403b705cfSriastradh pSrc->pDrawable->type == DRAWABLE_PIXMAP) { 146503b705cfSriastradh DDXPointRec patOrg; 146603b705cfSriastradh 146703b705cfSriastradh /* Let's see if the driver can do the repeat 146803b705cfSriastradh * in one go 146903b705cfSriastradh */ 147003b705cfSriastradh if (uxa_screen->info->prepare_composite) { 147103b705cfSriastradh ret = uxa_try_driver_composite(op, pSrc, 147203b705cfSriastradh pMask, pDst, 147303b705cfSriastradh xSrc, ySrc, 147403b705cfSriastradh xMask, yMask, 147503b705cfSriastradh xDst, yDst, 147603b705cfSriastradh width, height); 147703b705cfSriastradh if (ret == 1) 147803b705cfSriastradh goto done; 147903b705cfSriastradh } 148003b705cfSriastradh 148103b705cfSriastradh /* Now see if we can use 148203b705cfSriastradh * uxa_fill_region_tiled() 148303b705cfSriastradh */ 148403b705cfSriastradh xDst += pDst->pDrawable->x; 148503b705cfSriastradh yDst += pDst->pDrawable->y; 148603b705cfSriastradh xSrc += pSrc->pDrawable->x + tx; 148703b705cfSriastradh ySrc += pSrc->pDrawable->y + ty; 148803b705cfSriastradh 148903b705cfSriastradh if (!miComputeCompositeRegion 149003b705cfSriastradh (®ion, pSrc, pMask, pDst, xSrc, ySrc, 149103b705cfSriastradh xMask, yMask, xDst, yDst, width, height)) 149203b705cfSriastradh goto done; 149303b705cfSriastradh 149403b705cfSriastradh /* pattern origin is the point in the 149503b705cfSriastradh * destination drawable 149603b705cfSriastradh * corresponding to (0,0) in the source */ 149703b705cfSriastradh patOrg.x = xDst - xSrc; 149803b705cfSriastradh patOrg.y = yDst - ySrc; 149903b705cfSriastradh 150003b705cfSriastradh ret = uxa_fill_region_tiled(pDst->pDrawable, 150103b705cfSriastradh ®ion, 150203b705cfSriastradh (PixmapPtr) pSrc-> 150303b705cfSriastradh pDrawable, &patOrg, 150403b705cfSriastradh FB_ALLONES, GXcopy); 150503b705cfSriastradh 150603b705cfSriastradh REGION_UNINIT(pDst->pDrawable->pScreen, 150703b705cfSriastradh ®ion); 150803b705cfSriastradh 150903b705cfSriastradh if (ret) 151003b705cfSriastradh goto done; 151103b705cfSriastradh } 151203b705cfSriastradh } 151303b705cfSriastradh } 151403b705cfSriastradh 151503b705cfSriastradh /* Remove repeat in mask if useless */ 151603b705cfSriastradh if (pMask && pMask->pDrawable && pMask->repeat && 151703b705cfSriastradh pMask->filter != PictFilterConvolution && 151803b705cfSriastradh transform_is_integer_translation(pMask->transform, &tx, &ty) && 151903b705cfSriastradh (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) && 152003b705cfSriastradh drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height)) 152103b705cfSriastradh pMask->repeat = 0; 152203b705cfSriastradh 152303b705cfSriastradh if (uxa_screen->info->prepare_composite) { 152403b705cfSriastradh Bool isSrcSolid; 152503b705cfSriastradh 152603b705cfSriastradh ret = 152703b705cfSriastradh uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 152803b705cfSriastradh xMask, yMask, xDst, yDst, width, 152903b705cfSriastradh height); 153003b705cfSriastradh if (ret == 1) 153103b705cfSriastradh goto done; 153203b705cfSriastradh 153303b705cfSriastradh /* For generic masks and solid src pictures, mach64 can do 153403b705cfSriastradh * Over in two passes, similar to the component-alpha case. 153503b705cfSriastradh */ 153603b705cfSriastradh 153703b705cfSriastradh isSrcSolid = 153803b705cfSriastradh pSrc->pDrawable ? 153903b705cfSriastradh pSrc->pDrawable->width == 1 && 154003b705cfSriastradh pSrc->pDrawable->height == 1 && 154103b705cfSriastradh pSrc->repeat : 154203b705cfSriastradh pSrc->pSourcePict ? 154303b705cfSriastradh pSrc->pSourcePict->type == SourcePictTypeSolidFill : 154403b705cfSriastradh 0; 154503b705cfSriastradh 154603b705cfSriastradh /* If we couldn't do the Composite in a single pass, and it 154703b705cfSriastradh * was a component-alpha Over, see if we can do it in two 154803b705cfSriastradh * passes with an OutReverse and then an Add. 154903b705cfSriastradh */ 155003b705cfSriastradh if (ret == -1 && op == PictOpOver && pMask && 155103b705cfSriastradh (pMask->componentAlpha || isSrcSolid)) { 155203b705cfSriastradh ret = 155303b705cfSriastradh uxa_try_magic_two_pass_composite_helper(op, pSrc, 155403b705cfSriastradh pMask, pDst, 155503b705cfSriastradh xSrc, ySrc, 155603b705cfSriastradh xMask, yMask, 155703b705cfSriastradh xDst, yDst, 155803b705cfSriastradh width, height); 155903b705cfSriastradh if (ret == 1) 156003b705cfSriastradh goto done; 156103b705cfSriastradh } 156203b705cfSriastradh 156303b705cfSriastradh } 156403b705cfSriastradh 156503b705cfSriastradhfallback: 156603b705cfSriastradh uxa_print_composite_fallback("uxa_composite", 156703b705cfSriastradh op, pSrc, pMask, pDst); 156803b705cfSriastradh 156903b705cfSriastradh uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 157003b705cfSriastradh xMask, yMask, xDst, yDst, width, height); 157103b705cfSriastradh 157203b705cfSriastradhdone: 157303b705cfSriastradh pSrc->repeat = saveSrcRepeat; 157403b705cfSriastradh if (pMask) 157503b705cfSriastradh pMask->repeat = saveMaskRepeat; 157603b705cfSriastradh} 157703b705cfSriastradh#endif 157803b705cfSriastradh 157903b705cfSriastradh/** 158003b705cfSriastradh * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead 158103b705cfSriastradh * of PolyFillRect to initialize the pixmap after creating it, to prevent 158203b705cfSriastradh * the pixmap from being migrated. 158303b705cfSriastradh * 158403b705cfSriastradh * See the comments about uxa_trapezoids and uxa_triangles. 158503b705cfSriastradh */ 158603b705cfSriastradhstatic PicturePtr 158703b705cfSriastradhuxa_create_alpha_picture(ScreenPtr pScreen, 158803b705cfSriastradh PicturePtr pDst, 158903b705cfSriastradh PictFormatPtr pPictFormat, CARD16 width, CARD16 height) 159003b705cfSriastradh{ 159103b705cfSriastradh PixmapPtr pPixmap; 159203b705cfSriastradh PicturePtr pPicture; 159303b705cfSriastradh int error; 159403b705cfSriastradh 159503b705cfSriastradh if (width > 32767 || height > 32767) 159603b705cfSriastradh return 0; 159703b705cfSriastradh 159803b705cfSriastradh if (!pPictFormat) { 159903b705cfSriastradh if (pDst->polyEdge == PolyEdgeSharp) 160003b705cfSriastradh pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 160103b705cfSriastradh else 160203b705cfSriastradh pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 160303b705cfSriastradh if (!pPictFormat) 160403b705cfSriastradh return 0; 160503b705cfSriastradh } 160603b705cfSriastradh 160703b705cfSriastradh pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 160803b705cfSriastradh pPictFormat->depth, 160903b705cfSriastradh UXA_CREATE_PIXMAP_FOR_MAP); 161003b705cfSriastradh if (!pPixmap) 161103b705cfSriastradh return 0; 161203b705cfSriastradh pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 161303b705cfSriastradh 0, 0, serverClient, &error); 161403b705cfSriastradh (*pScreen->DestroyPixmap) (pPixmap); 161503b705cfSriastradh return pPicture; 161603b705cfSriastradh} 161703b705cfSriastradh 161803b705cfSriastradhstatic void 161903b705cfSriastradhuxa_check_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, 162003b705cfSriastradh PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 162103b705cfSriastradh int ntrap, xTrapezoid * traps) 162203b705cfSriastradh{ 162303b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 162403b705cfSriastradh 162503b705cfSriastradh if (maskFormat) { 162603b705cfSriastradh PixmapPtr scratch = NULL; 162703b705cfSriastradh PicturePtr mask; 162803b705cfSriastradh INT16 xDst, yDst; 162903b705cfSriastradh INT16 xRel, yRel; 163003b705cfSriastradh BoxRec bounds; 163103b705cfSriastradh int width, height; 163203b705cfSriastradh pixman_image_t *image; 163303b705cfSriastradh pixman_format_code_t format; 163403b705cfSriastradh int error; 163503b705cfSriastradh 163603b705cfSriastradh xDst = traps[0].left.p1.x >> 16; 163703b705cfSriastradh yDst = traps[0].left.p1.y >> 16; 163803b705cfSriastradh 163903b705cfSriastradh miTrapezoidBounds (ntrap, traps, &bounds); 164003b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 164103b705cfSriastradh return; 164203b705cfSriastradh 164303b705cfSriastradh width = bounds.x2 - bounds.x1; 164403b705cfSriastradh height = bounds.y2 - bounds.y1; 164503b705cfSriastradh 164603b705cfSriastradh format = maskFormat->format | 164703b705cfSriastradh (BitsPerPixel(maskFormat->depth) << 24); 164803b705cfSriastradh image = 164903b705cfSriastradh pixman_image_create_bits(format, width, height, NULL, 0); 165003b705cfSriastradh if (!image) 165103b705cfSriastradh return; 165203b705cfSriastradh 165303b705cfSriastradh for (; ntrap; ntrap--, traps++) 165403b705cfSriastradh pixman_rasterize_trapezoid(image, 165503b705cfSriastradh (pixman_trapezoid_t *) traps, 165603b705cfSriastradh -bounds.x1, -bounds.y1); 165703b705cfSriastradh 165803b705cfSriastradh 165903b705cfSriastradh scratch = GetScratchPixmapHeader(screen, width, height, 166003b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 166103b705cfSriastradh PIXMAN_FORMAT_BPP(format), 166203b705cfSriastradh pixman_image_get_stride(image), 166303b705cfSriastradh pixman_image_get_data(image)); 166403b705cfSriastradh if (!scratch) { 166503b705cfSriastradh pixman_image_unref(image); 166603b705cfSriastradh return; 166703b705cfSriastradh } 166803b705cfSriastradh 166903b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 167003b705cfSriastradh PictureMatchFormat(screen, 167103b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 167203b705cfSriastradh format), 167303b705cfSriastradh 0, 0, serverClient, &error); 167403b705cfSriastradh if (!mask) { 167503b705cfSriastradh FreeScratchPixmapHeader(scratch); 167603b705cfSriastradh pixman_image_unref(image); 167703b705cfSriastradh return; 167803b705cfSriastradh } 167903b705cfSriastradh 168003b705cfSriastradh xRel = bounds.x1 + xSrc - xDst; 168103b705cfSriastradh yRel = bounds.y1 + ySrc - yDst; 168203b705cfSriastradh CompositePicture(op, src, mask, dst, 168303b705cfSriastradh xRel, yRel, 168403b705cfSriastradh 0, 0, 168503b705cfSriastradh bounds.x1, bounds.y1, 168603b705cfSriastradh width, height); 168703b705cfSriastradh FreePicture(mask, 0); 168803b705cfSriastradh 168903b705cfSriastradh FreeScratchPixmapHeader(scratch); 169003b705cfSriastradh pixman_image_unref(image); 169103b705cfSriastradh } else { 169203b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 169303b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 169403b705cfSriastradh else 169503b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 169603b705cfSriastradh 169703b705cfSriastradh for (; ntrap; ntrap--, traps++) 169803b705cfSriastradh uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps); 169903b705cfSriastradh } 170003b705cfSriastradh} 170103b705cfSriastradh 170203b705cfSriastradh/** 170303b705cfSriastradh * uxa_trapezoids is essentially a copy of miTrapezoids that uses 170403b705cfSriastradh * uxa_create_alpha_picture instead of miCreateAlphaPicture. 170503b705cfSriastradh * 170603b705cfSriastradh * The problem with miCreateAlphaPicture is that it calls PolyFillRect 170703b705cfSriastradh * to initialize the contents after creating the pixmap, which 170803b705cfSriastradh * causes the pixmap to be moved in for acceleration. The subsequent 170903b705cfSriastradh * call to RasterizeTrapezoid won't be accelerated however, which 171003b705cfSriastradh * forces the pixmap to be moved out again. 171103b705cfSriastradh * 171203b705cfSriastradh * uxa_create_alpha_picture avoids this roundtrip by using 171303b705cfSriastradh * uxa_check_poly_fill_rect to initialize the contents. 171403b705cfSriastradh */ 171503b705cfSriastradhvoid 171603b705cfSriastradhuxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, 171703b705cfSriastradh PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 171803b705cfSriastradh int ntrap, xTrapezoid * traps) 171903b705cfSriastradh{ 172003b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 172103b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(screen); 172203b705cfSriastradh BoxRec bounds; 172303b705cfSriastradh Bool direct; 172403b705cfSriastradh 172503b705cfSriastradh if (uxa_screen->info->flags & UXA_USE_GLAMOR) { 172603b705cfSriastradh int ok; 172703b705cfSriastradh 172803b705cfSriastradh uxa_picture_prepare_access(dst, UXA_GLAMOR_ACCESS_RW); 172903b705cfSriastradh uxa_picture_prepare_access(src, UXA_GLAMOR_ACCESS_RO); 173003b705cfSriastradh ok = glamor_trapezoids_nf(op, 173103b705cfSriastradh src, dst, maskFormat, xSrc, 173203b705cfSriastradh ySrc, ntrap, traps); 173303b705cfSriastradh uxa_picture_finish_access(src, UXA_GLAMOR_ACCESS_RO); 173403b705cfSriastradh uxa_picture_finish_access(dst, UXA_GLAMOR_ACCESS_RW); 173503b705cfSriastradh 173603b705cfSriastradh if (!ok) 173703b705cfSriastradh goto fallback; 173803b705cfSriastradh 173903b705cfSriastradh return; 174003b705cfSriastradh } 174103b705cfSriastradh 174203b705cfSriastradh if (uxa_screen->force_fallback) { 174303b705cfSriastradhfallback: 174403b705cfSriastradh uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, ntrap, traps); 174503b705cfSriastradh return; 174603b705cfSriastradh } 174703b705cfSriastradh 174803b705cfSriastradh direct = op == PictOpAdd && miIsSolidAlpha(src); 174903b705cfSriastradh if (maskFormat || direct) { 175003b705cfSriastradh miTrapezoidBounds(ntrap, traps, &bounds); 175103b705cfSriastradh 175203b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 175303b705cfSriastradh return; 175403b705cfSriastradh } 175503b705cfSriastradh 175603b705cfSriastradh /* 175703b705cfSriastradh * Check for solid alpha add 175803b705cfSriastradh */ 175903b705cfSriastradh if (direct) { 176003b705cfSriastradh DrawablePtr pDraw = dst->pDrawable; 176103b705cfSriastradh PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw); 176203b705cfSriastradh int xoff, yoff; 176303b705cfSriastradh 176403b705cfSriastradh uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff); 176503b705cfSriastradh 176603b705cfSriastradh xoff += pDraw->x; 176703b705cfSriastradh yoff += pDraw->y; 176803b705cfSriastradh 176903b705cfSriastradh if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) { 177003b705cfSriastradh PictureScreenPtr ps = GetPictureScreen(screen); 177103b705cfSriastradh 177203b705cfSriastradh for (; ntrap; ntrap--, traps++) 177303b705cfSriastradh (*ps->RasterizeTrapezoid) (dst, traps, 0, 0); 177403b705cfSriastradh uxa_finish_access(pDraw, UXA_ACCESS_RW); 177503b705cfSriastradh } 177603b705cfSriastradh } else if (maskFormat) { 177703b705cfSriastradh PixmapPtr scratch = NULL; 177803b705cfSriastradh PicturePtr mask; 177903b705cfSriastradh INT16 xDst, yDst; 178003b705cfSriastradh INT16 xRel, yRel; 178103b705cfSriastradh int width, height; 178203b705cfSriastradh pixman_image_t *image; 178303b705cfSriastradh pixman_format_code_t format; 178403b705cfSriastradh 178503b705cfSriastradh xDst = traps[0].left.p1.x >> 16; 178603b705cfSriastradh yDst = traps[0].left.p1.y >> 16; 178703b705cfSriastradh 178803b705cfSriastradh width = bounds.x2 - bounds.x1; 178903b705cfSriastradh height = bounds.y2 - bounds.y1; 179003b705cfSriastradh 179103b705cfSriastradh format = maskFormat->format | 179203b705cfSriastradh (BitsPerPixel(maskFormat->depth) << 24); 179303b705cfSriastradh image = 179403b705cfSriastradh pixman_image_create_bits(format, width, height, NULL, 0); 179503b705cfSriastradh if (!image) 179603b705cfSriastradh return; 179703b705cfSriastradh 179803b705cfSriastradh for (; ntrap; ntrap--, traps++) 179903b705cfSriastradh pixman_rasterize_trapezoid(image, 180003b705cfSriastradh (pixman_trapezoid_t *) traps, 180103b705cfSriastradh -bounds.x1, -bounds.y1); 180203b705cfSriastradh if (uxa_drawable_is_offscreen(dst->pDrawable)) { 180303b705cfSriastradh mask = uxa_picture_from_pixman_image(screen, image, format); 180403b705cfSriastradh } else { 180503b705cfSriastradh int error; 180603b705cfSriastradh 180703b705cfSriastradh scratch = GetScratchPixmapHeader(screen, width, height, 180803b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 180903b705cfSriastradh PIXMAN_FORMAT_BPP(format), 181003b705cfSriastradh pixman_image_get_stride(image), 181103b705cfSriastradh pixman_image_get_data(image)); 181203b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 181303b705cfSriastradh PictureMatchFormat(screen, 181403b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 181503b705cfSriastradh format), 181603b705cfSriastradh 0, 0, serverClient, &error); 181703b705cfSriastradh } 181803b705cfSriastradh if (!mask) { 181903b705cfSriastradh if (scratch) 182003b705cfSriastradh FreeScratchPixmapHeader(scratch); 182103b705cfSriastradh pixman_image_unref(image); 182203b705cfSriastradh return; 182303b705cfSriastradh } 182403b705cfSriastradh 182503b705cfSriastradh xRel = bounds.x1 + xSrc - xDst; 182603b705cfSriastradh yRel = bounds.y1 + ySrc - yDst; 182703b705cfSriastradh CompositePicture(op, src, mask, dst, 182803b705cfSriastradh xRel, yRel, 182903b705cfSriastradh 0, 0, 183003b705cfSriastradh bounds.x1, bounds.y1, 183103b705cfSriastradh width, height); 183203b705cfSriastradh FreePicture(mask, 0); 183303b705cfSriastradh 183403b705cfSriastradh if (scratch) 183503b705cfSriastradh FreeScratchPixmapHeader(scratch); 183603b705cfSriastradh pixman_image_unref(image); 183703b705cfSriastradh } else { 183803b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 183903b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 184003b705cfSriastradh else 184103b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 184203b705cfSriastradh for (; ntrap; ntrap--, traps++) 184303b705cfSriastradh uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 184403b705cfSriastradh 1, traps); 184503b705cfSriastradh } 184603b705cfSriastradh} 184703b705cfSriastradh 184803b705cfSriastradhstatic void 184903b705cfSriastradhuxa_check_triangles(CARD8 op, PicturePtr src, PicturePtr dst, 185003b705cfSriastradh PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 185103b705cfSriastradh int ntri, xTriangle *tri) 185203b705cfSriastradh{ 185303b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 185403b705cfSriastradh 185503b705cfSriastradh if (maskFormat) { 185603b705cfSriastradh PixmapPtr scratch = NULL; 185703b705cfSriastradh PicturePtr mask; 185803b705cfSriastradh INT16 xDst, yDst; 185903b705cfSriastradh INT16 xRel, yRel; 186003b705cfSriastradh BoxRec bounds; 186103b705cfSriastradh int width, height; 186203b705cfSriastradh pixman_image_t *image; 186303b705cfSriastradh pixman_format_code_t format; 186403b705cfSriastradh int error; 186503b705cfSriastradh 186603b705cfSriastradh xDst = pixman_fixed_to_int(tri[0].p1.x); 186703b705cfSriastradh yDst = pixman_fixed_to_int(tri[0].p1.y); 186803b705cfSriastradh 186903b705cfSriastradh miTriangleBounds (ntri, tri, &bounds); 187003b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 187103b705cfSriastradh return; 187203b705cfSriastradh 187303b705cfSriastradh width = bounds.x2 - bounds.x1; 187403b705cfSriastradh height = bounds.y2 - bounds.y1; 187503b705cfSriastradh 187603b705cfSriastradh format = maskFormat->format | 187703b705cfSriastradh (BitsPerPixel(maskFormat->depth) << 24); 187803b705cfSriastradh image = 187903b705cfSriastradh pixman_image_create_bits(format, width, height, NULL, 0); 188003b705cfSriastradh if (!image) 188103b705cfSriastradh return; 188203b705cfSriastradh 188303b705cfSriastradh pixman_add_triangles(image, 188403b705cfSriastradh -bounds.x1, -bounds.y1, 188503b705cfSriastradh ntri, (pixman_triangle_t *)tri); 188603b705cfSriastradh 188703b705cfSriastradh scratch = GetScratchPixmapHeader(screen, width, height, 188803b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 188903b705cfSriastradh PIXMAN_FORMAT_BPP(format), 189003b705cfSriastradh pixman_image_get_stride(image), 189103b705cfSriastradh pixman_image_get_data(image)); 189203b705cfSriastradh if (!scratch) { 189303b705cfSriastradh pixman_image_unref(image); 189403b705cfSriastradh return; 189503b705cfSriastradh } 189603b705cfSriastradh 189703b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 189803b705cfSriastradh PictureMatchFormat(screen, 189903b705cfSriastradh PIXMAN_FORMAT_DEPTH(format), 190003b705cfSriastradh format), 190103b705cfSriastradh 0, 0, serverClient, &error); 190203b705cfSriastradh if (!mask) { 190303b705cfSriastradh FreeScratchPixmapHeader(scratch); 190403b705cfSriastradh pixman_image_unref(image); 190503b705cfSriastradh return; 190603b705cfSriastradh } 190703b705cfSriastradh 190803b705cfSriastradh xRel = bounds.x1 + xSrc - xDst; 190903b705cfSriastradh yRel = bounds.y1 + ySrc - yDst; 191003b705cfSriastradh CompositePicture(op, src, mask, dst, 191103b705cfSriastradh xRel, yRel, 191203b705cfSriastradh 0, 0, 191303b705cfSriastradh bounds.x1, bounds.y1, 191403b705cfSriastradh width, height); 191503b705cfSriastradh FreePicture(mask, 0); 191603b705cfSriastradh 191703b705cfSriastradh FreeScratchPixmapHeader(scratch); 191803b705cfSriastradh pixman_image_unref(image); 191903b705cfSriastradh } else { 192003b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 192103b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 192203b705cfSriastradh else 192303b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 192403b705cfSriastradh 192503b705cfSriastradh for (; ntri; ntri--, tri++) 192603b705cfSriastradh uxa_check_triangles(op, src, dst, maskFormat, xSrc, ySrc, 1, tri); 192703b705cfSriastradh } 192803b705cfSriastradh} 192903b705cfSriastradh 193003b705cfSriastradh/** 193103b705cfSriastradh * uxa_triangles is essentially a copy of miTriangles that uses 193203b705cfSriastradh * uxa_create_alpha_picture instead of miCreateAlphaPicture. 193303b705cfSriastradh * 193403b705cfSriastradh * The problem with miCreateAlphaPicture is that it calls PolyFillRect 193503b705cfSriastradh * to initialize the contents after creating the pixmap, which 193603b705cfSriastradh * causes the pixmap to be moved in for acceleration. The subsequent 193703b705cfSriastradh * call to AddTriangles won't be accelerated however, which forces the pixmap 193803b705cfSriastradh * to be moved out again. 193903b705cfSriastradh * 194003b705cfSriastradh * uxa_create_alpha_picture avoids this roundtrip by using 194103b705cfSriastradh * uxa_check_poly_fill_rect to initialize the contents. 194203b705cfSriastradh */ 194303b705cfSriastradhvoid 194403b705cfSriastradhuxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 194503b705cfSriastradh PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 194603b705cfSriastradh int ntri, xTriangle * tris) 194703b705cfSriastradh{ 194803b705cfSriastradh ScreenPtr pScreen = pDst->pDrawable->pScreen; 194903b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 195003b705cfSriastradh PictureScreenPtr ps = GetPictureScreen(pScreen); 195103b705cfSriastradh BoxRec bounds; 195203b705cfSriastradh Bool direct; 195303b705cfSriastradh 195403b705cfSriastradh if (uxa_screen->info->flags & UXA_USE_GLAMOR) { 195503b705cfSriastradh int ok; 195603b705cfSriastradh 195703b705cfSriastradh uxa_picture_prepare_access(pDst, UXA_GLAMOR_ACCESS_RW); 195803b705cfSriastradh uxa_picture_prepare_access(pSrc, UXA_GLAMOR_ACCESS_RO); 195903b705cfSriastradh ok = glamor_triangles_nf(op, 196003b705cfSriastradh pSrc, pDst, maskFormat, xSrc, 196103b705cfSriastradh ySrc, ntri, tris); 196203b705cfSriastradh uxa_picture_finish_access(pSrc, UXA_GLAMOR_ACCESS_RO); 196303b705cfSriastradh uxa_picture_finish_access(pDst, UXA_GLAMOR_ACCESS_RW); 196403b705cfSriastradh 196503b705cfSriastradh if (!ok) 196603b705cfSriastradh goto fallback; 196703b705cfSriastradh 196803b705cfSriastradh return; 196903b705cfSriastradh } 197003b705cfSriastradh 197103b705cfSriastradh if (uxa_screen->force_fallback) { 197203b705cfSriastradhfallback: 197303b705cfSriastradh uxa_check_triangles(op, pSrc, pDst, maskFormat, 197403b705cfSriastradh xSrc, ySrc, ntri, tris); 197503b705cfSriastradh return; 197603b705cfSriastradh } 197703b705cfSriastradh 197803b705cfSriastradh direct = op == PictOpAdd && miIsSolidAlpha(pSrc); 197903b705cfSriastradh if (maskFormat || direct) { 198003b705cfSriastradh miTriangleBounds(ntri, tris, &bounds); 198103b705cfSriastradh 198203b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 198303b705cfSriastradh return; 198403b705cfSriastradh } 198503b705cfSriastradh 198603b705cfSriastradh /* 198703b705cfSriastradh * Check for solid alpha add 198803b705cfSriastradh */ 198903b705cfSriastradh if (direct) { 199003b705cfSriastradh DrawablePtr pDraw = pDst->pDrawable; 199103b705cfSriastradh if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) { 199203b705cfSriastradh (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); 199303b705cfSriastradh uxa_finish_access(pDraw, UXA_ACCESS_RW); 199403b705cfSriastradh } 199503b705cfSriastradh } else if (maskFormat) { 199603b705cfSriastradh PicturePtr pPicture; 199703b705cfSriastradh INT16 xDst, yDst; 199803b705cfSriastradh INT16 xRel, yRel; 199903b705cfSriastradh int width = bounds.x2 - bounds.x1; 200003b705cfSriastradh int height = bounds.y2 - bounds.y1; 200103b705cfSriastradh GCPtr pGC; 200203b705cfSriastradh xRectangle rect; 200303b705cfSriastradh 200403b705cfSriastradh xDst = tris[0].p1.x >> 16; 200503b705cfSriastradh yDst = tris[0].p1.y >> 16; 200603b705cfSriastradh 200703b705cfSriastradh pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat, 200803b705cfSriastradh width, height); 200903b705cfSriastradh if (!pPicture) 201003b705cfSriastradh return; 201103b705cfSriastradh 201203b705cfSriastradh /* Clear the alpha picture to 0. */ 201303b705cfSriastradh pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen); 201403b705cfSriastradh if (!pGC) { 201503b705cfSriastradh FreePicture(pPicture, 0); 201603b705cfSriastradh return; 201703b705cfSriastradh } 201803b705cfSriastradh ValidateGC(pPicture->pDrawable, pGC); 201903b705cfSriastradh rect.x = 0; 202003b705cfSriastradh rect.y = 0; 202103b705cfSriastradh rect.width = width; 202203b705cfSriastradh rect.height = height; 202303b705cfSriastradh uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect); 202403b705cfSriastradh FreeScratchGC(pGC); 202503b705cfSriastradh 202603b705cfSriastradh if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) { 202703b705cfSriastradh (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, 202803b705cfSriastradh ntri, tris); 202903b705cfSriastradh uxa_finish_access(pPicture->pDrawable, UXA_ACCESS_RW); 203003b705cfSriastradh } 203103b705cfSriastradh 203203b705cfSriastradh xRel = bounds.x1 + xSrc - xDst; 203303b705cfSriastradh yRel = bounds.y1 + ySrc - yDst; 203403b705cfSriastradh CompositePicture(op, pSrc, pPicture, pDst, 203503b705cfSriastradh xRel, yRel, 0, 0, bounds.x1, bounds.y1, 203603b705cfSriastradh bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 203703b705cfSriastradh FreePicture(pPicture, 0); 203803b705cfSriastradh } else { 203903b705cfSriastradh if (pDst->polyEdge == PolyEdgeSharp) 204003b705cfSriastradh maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 204103b705cfSriastradh else 204203b705cfSriastradh maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 204303b705cfSriastradh 204403b705cfSriastradh for (; ntri; ntri--, tris++) 204503b705cfSriastradh uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, 204603b705cfSriastradh tris); 204703b705cfSriastradh } 204803b705cfSriastradh} 204903b705cfSriastradh 205003b705cfSriastradhvoid 205103b705cfSriastradhuxa_add_traps(PicturePtr pPicture, 205203b705cfSriastradh INT16 x_off, INT16 y_off, int ntrap, xTrap * traps) 205303b705cfSriastradh{ 205403b705cfSriastradh ScreenPtr pScreen = pPicture->pDrawable->pScreen; 205503b705cfSriastradh uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 205603b705cfSriastradh 205703b705cfSriastradh if (uxa_screen->info->flags & UXA_USE_GLAMOR) { 205803b705cfSriastradh int ok; 205903b705cfSriastradh 206003b705cfSriastradh uxa_picture_prepare_access(pPicture, UXA_GLAMOR_ACCESS_RW); 206103b705cfSriastradh ok = glamor_add_traps_nf(pPicture, 206203b705cfSriastradh x_off, y_off, ntrap, traps); 206303b705cfSriastradh uxa_picture_finish_access(pPicture, UXA_GLAMOR_ACCESS_RW); 206403b705cfSriastradh 206503b705cfSriastradh if (!ok) 206603b705cfSriastradh goto fallback; 206703b705cfSriastradh 206803b705cfSriastradh return; 206903b705cfSriastradh } 207003b705cfSriastradh 207103b705cfSriastradhfallback: 207203b705cfSriastradh uxa_check_add_traps(pPicture, x_off, y_off, ntrap, traps); 207303b705cfSriastradh} 2074