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