1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 2001 Keith Packard 3428d7b3dSmrg * 4428d7b3dSmrg * Partly based on code that is Copyright © The XFree86 Project Inc. 5428d7b3dSmrg * 6428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 7428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that 8428d7b3dSmrg * the above copyright notice appear in all copies and that both that 9428d7b3dSmrg * copyright notice and this permission notice appear in supporting 10428d7b3dSmrg * documentation, and that the name of Keith Packard not be used in 11428d7b3dSmrg * advertising or publicity pertaining to distribution of the software without 12428d7b3dSmrg * specific, written prior permission. Keith Packard makes no 13428d7b3dSmrg * representations about the suitability of this software for any purpose. It 14428d7b3dSmrg * is provided "as is" without express or implied warranty. 15428d7b3dSmrg * 16428d7b3dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17428d7b3dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18428d7b3dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19428d7b3dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20428d7b3dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21428d7b3dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22428d7b3dSmrg * PERFORMANCE OF THIS SOFTWARE. 23428d7b3dSmrg */ 24428d7b3dSmrg 25428d7b3dSmrg#ifdef HAVE_DIX_CONFIG_H 26428d7b3dSmrg#include <dix-config.h> 27428d7b3dSmrg#endif 28428d7b3dSmrg 29428d7b3dSmrg#include <stdlib.h> 30428d7b3dSmrg 31428d7b3dSmrg#include "uxa-priv.h" 32428d7b3dSmrg 33428d7b3dSmrg#ifdef RENDER 34428d7b3dSmrg#include "mipict.h" 35428d7b3dSmrg 36428d7b3dSmrgstatic void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string, 37428d7b3dSmrg int n) 38428d7b3dSmrg{ 39428d7b3dSmrg char format[20]; 40428d7b3dSmrg char size[20]; 41428d7b3dSmrg char loc; 42428d7b3dSmrg 43428d7b3dSmrg if (!pict) { 44428d7b3dSmrg snprintf(string, n, "None"); 45428d7b3dSmrg return; 46428d7b3dSmrg } 47428d7b3dSmrg 48428d7b3dSmrg if (pict->pDrawable == NULL) { 49428d7b3dSmrg snprintf(string, n, "source-only"); 50428d7b3dSmrg return; 51428d7b3dSmrg } 52428d7b3dSmrg 53428d7b3dSmrg switch (pict->format) { 54428d7b3dSmrg case PICT_a8r8g8b8: 55428d7b3dSmrg snprintf(format, 20, "ARGB8888"); 56428d7b3dSmrg break; 57428d7b3dSmrg case PICT_x8r8g8b8: 58428d7b3dSmrg snprintf(format, 20, "XRGB8888"); 59428d7b3dSmrg break; 60428d7b3dSmrg case PICT_r5g6b5: 61428d7b3dSmrg snprintf(format, 20, "RGB565 "); 62428d7b3dSmrg break; 63428d7b3dSmrg case PICT_x1r5g5b5: 64428d7b3dSmrg snprintf(format, 20, "RGB555 "); 65428d7b3dSmrg break; 66428d7b3dSmrg case PICT_a8: 67428d7b3dSmrg snprintf(format, 20, "A8 "); 68428d7b3dSmrg break; 69428d7b3dSmrg case PICT_a1: 70428d7b3dSmrg snprintf(format, 20, "A1 "); 71428d7b3dSmrg break; 72428d7b3dSmrg default: 73428d7b3dSmrg snprintf(format, 20, "0x%x", (int)pict->format); 74428d7b3dSmrg break; 75428d7b3dSmrg } 76428d7b3dSmrg 77428d7b3dSmrg loc = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm'; 78428d7b3dSmrg 79428d7b3dSmrg snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, 80428d7b3dSmrg pict->pDrawable->height, pict->repeat ? " R" : ""); 81428d7b3dSmrg 82428d7b3dSmrg snprintf(string, n, "%p:%c fmt %s (%s)%s", 83428d7b3dSmrg pict->pDrawable, loc, format, size, 84428d7b3dSmrg pict->alphaMap ? " with alpha map" :""); 85428d7b3dSmrg} 86428d7b3dSmrg 87428d7b3dSmrgstatic const char * 88428d7b3dSmrgop_to_string(CARD8 op) 89428d7b3dSmrg{ 90428d7b3dSmrg switch (op) { 91428d7b3dSmrg#define C(x) case PictOp##x: return #x 92428d7b3dSmrg C(Clear); 93428d7b3dSmrg C(Src); 94428d7b3dSmrg C(Dst); 95428d7b3dSmrg C(Over); 96428d7b3dSmrg C(OverReverse); 97428d7b3dSmrg C(In); 98428d7b3dSmrg C(InReverse); 99428d7b3dSmrg C(Out); 100428d7b3dSmrg C(OutReverse); 101428d7b3dSmrg C(Atop); 102428d7b3dSmrg C(AtopReverse); 103428d7b3dSmrg C(Xor); 104428d7b3dSmrg C(Add); 105428d7b3dSmrg C(Saturate); 106428d7b3dSmrg 107428d7b3dSmrg /* 108428d7b3dSmrg * Operators only available in version 0.2 109428d7b3dSmrg */ 110428d7b3dSmrg#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 2 111428d7b3dSmrg C(DisjointClear); 112428d7b3dSmrg C(DisjointSrc); 113428d7b3dSmrg C(DisjointDst); 114428d7b3dSmrg C(DisjointOver); 115428d7b3dSmrg C(DisjointOverReverse); 116428d7b3dSmrg C(DisjointIn); 117428d7b3dSmrg C(DisjointInReverse); 118428d7b3dSmrg C(DisjointOut); 119428d7b3dSmrg C(DisjointOutReverse); 120428d7b3dSmrg C(DisjointAtop); 121428d7b3dSmrg C(DisjointAtopReverse); 122428d7b3dSmrg C(DisjointXor); 123428d7b3dSmrg 124428d7b3dSmrg C(ConjointClear); 125428d7b3dSmrg C(ConjointSrc); 126428d7b3dSmrg C(ConjointDst); 127428d7b3dSmrg C(ConjointOver); 128428d7b3dSmrg C(ConjointOverReverse); 129428d7b3dSmrg C(ConjointIn); 130428d7b3dSmrg C(ConjointInReverse); 131428d7b3dSmrg C(ConjointOut); 132428d7b3dSmrg C(ConjointOutReverse); 133428d7b3dSmrg C(ConjointAtop); 134428d7b3dSmrg C(ConjointAtopReverse); 135428d7b3dSmrg C(ConjointXor); 136428d7b3dSmrg#endif 137428d7b3dSmrg 138428d7b3dSmrg /* 139428d7b3dSmrg * Operators only available in version 0.11 140428d7b3dSmrg */ 141428d7b3dSmrg#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 11 142428d7b3dSmrg C(Multiply); 143428d7b3dSmrg C(Screen); 144428d7b3dSmrg C(Overlay); 145428d7b3dSmrg C(Darken); 146428d7b3dSmrg C(Lighten); 147428d7b3dSmrg C(ColorDodge); 148428d7b3dSmrg C(ColorBurn); 149428d7b3dSmrg C(HardLight); 150428d7b3dSmrg C(SoftLight); 151428d7b3dSmrg C(Difference); 152428d7b3dSmrg C(Exclusion); 153428d7b3dSmrg C(HSLHue); 154428d7b3dSmrg C(HSLSaturation); 155428d7b3dSmrg C(HSLColor); 156428d7b3dSmrg C(HSLLuminosity); 157428d7b3dSmrg#endif 158428d7b3dSmrg default: return "garbage"; 159428d7b3dSmrg#undef C 160428d7b3dSmrg } 161428d7b3dSmrg} 162428d7b3dSmrg 163428d7b3dSmrgstatic void 164428d7b3dSmrguxa_print_composite_fallback(const char *func, CARD8 op, 165428d7b3dSmrg PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) 166428d7b3dSmrg{ 167428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 168428d7b3dSmrg char srcdesc[40], maskdesc[40], dstdesc[40]; 169428d7b3dSmrg 170428d7b3dSmrg if (! uxa_screen->fallback_debug) 171428d7b3dSmrg return; 172428d7b3dSmrg 173428d7b3dSmrg /* Limit the noise if fallbacks are expected. */ 174428d7b3dSmrg if (uxa_screen->force_fallback) 175428d7b3dSmrg return; 176428d7b3dSmrg 177428d7b3dSmrg uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40); 178428d7b3dSmrg uxa_composite_fallback_pict_desc(pMask, maskdesc, 40); 179428d7b3dSmrg uxa_composite_fallback_pict_desc(pDst, dstdesc, 40); 180428d7b3dSmrg 181428d7b3dSmrg ErrorF("Composite fallback at %s:\n" 182428d7b3dSmrg " op %s, \n" 183428d7b3dSmrg " src %s, \n" 184428d7b3dSmrg " mask %s, \n" 185428d7b3dSmrg " dst %s, \n", 186428d7b3dSmrg func, op_to_string (op), srcdesc, maskdesc, dstdesc); 187428d7b3dSmrg} 188428d7b3dSmrg 189428d7b3dSmrgBool uxa_op_reads_destination(CARD8 op) 190428d7b3dSmrg{ 191428d7b3dSmrg /* FALSE (does not read destination) is the list of ops in the protocol 192428d7b3dSmrg * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 193428d7b3dSmrg * That's just Clear and Src. ReduceCompositeOp() will already have 194428d7b3dSmrg * converted con/disjoint clear/src to Clear or Src. 195428d7b3dSmrg */ 196428d7b3dSmrg switch (op) { 197428d7b3dSmrg case PictOpClear: 198428d7b3dSmrg case PictOpSrc: 199428d7b3dSmrg return FALSE; 200428d7b3dSmrg default: 201428d7b3dSmrg return TRUE; 202428d7b3dSmrg } 203428d7b3dSmrg} 204428d7b3dSmrg 205428d7b3dSmrgstatic Bool 206428d7b3dSmrguxa_get_pixel_from_rgba(CARD32 * pixel, 207428d7b3dSmrg CARD16 red, 208428d7b3dSmrg CARD16 green, 209428d7b3dSmrg CARD16 blue, 210428d7b3dSmrg CARD16 alpha, 211428d7b3dSmrg CARD32 format) 212428d7b3dSmrg{ 213428d7b3dSmrg int rbits, bbits, gbits, abits; 214428d7b3dSmrg int rshift, bshift, gshift, ashift; 215428d7b3dSmrg 216428d7b3dSmrg rbits = PICT_FORMAT_R(format); 217428d7b3dSmrg gbits = PICT_FORMAT_G(format); 218428d7b3dSmrg bbits = PICT_FORMAT_B(format); 219428d7b3dSmrg abits = PICT_FORMAT_A(format); 220428d7b3dSmrg if (abits == 0) 221428d7b3dSmrg abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 222428d7b3dSmrg 223428d7b3dSmrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 224428d7b3dSmrg *pixel = alpha >> (16 - abits); 225428d7b3dSmrg return TRUE; 226428d7b3dSmrg } 227428d7b3dSmrg 228428d7b3dSmrg if (!PICT_FORMAT_COLOR(format)) 229428d7b3dSmrg return FALSE; 230428d7b3dSmrg 231428d7b3dSmrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 232428d7b3dSmrg bshift = 0; 233428d7b3dSmrg gshift = bbits; 234428d7b3dSmrg rshift = gshift + gbits; 235428d7b3dSmrg ashift = rshift + rbits; 236428d7b3dSmrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 237428d7b3dSmrg rshift = 0; 238428d7b3dSmrg gshift = rbits; 239428d7b3dSmrg bshift = gshift + gbits; 240428d7b3dSmrg ashift = bshift + bbits; 241428d7b3dSmrg#if XORG_VERSION_CURRENT >= 10699900 242428d7b3dSmrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 243428d7b3dSmrg ashift = 0; 244428d7b3dSmrg rshift = abits; 245428d7b3dSmrg gshift = rshift + rbits; 246428d7b3dSmrg bshift = gshift + gbits; 247428d7b3dSmrg#endif 248428d7b3dSmrg } else { 249428d7b3dSmrg return FALSE; 250428d7b3dSmrg } 251428d7b3dSmrg 252428d7b3dSmrg *pixel = 0; 253428d7b3dSmrg *pixel |= (blue >> (16 - bbits)) << bshift; 254428d7b3dSmrg *pixel |= (green >> (16 - gbits)) << gshift; 255428d7b3dSmrg *pixel |= (red >> (16 - rbits)) << rshift; 256428d7b3dSmrg *pixel |= (alpha >> (16 - abits)) << ashift; 257428d7b3dSmrg 258428d7b3dSmrg return TRUE; 259428d7b3dSmrg} 260428d7b3dSmrg 261428d7b3dSmrgBool 262428d7b3dSmrguxa_get_rgba_from_pixel(CARD32 pixel, 263428d7b3dSmrg CARD16 * red, 264428d7b3dSmrg CARD16 * green, 265428d7b3dSmrg CARD16 * blue, 266428d7b3dSmrg CARD16 * alpha, 267428d7b3dSmrg CARD32 format) 268428d7b3dSmrg{ 269428d7b3dSmrg int rbits, bbits, gbits, abits; 270428d7b3dSmrg int rshift, bshift, gshift, ashift; 271428d7b3dSmrg 272428d7b3dSmrg rbits = PICT_FORMAT_R(format); 273428d7b3dSmrg gbits = PICT_FORMAT_G(format); 274428d7b3dSmrg bbits = PICT_FORMAT_B(format); 275428d7b3dSmrg abits = PICT_FORMAT_A(format); 276428d7b3dSmrg 277428d7b3dSmrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 278428d7b3dSmrg rshift = gshift = bshift = ashift = 0; 279428d7b3dSmrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 280428d7b3dSmrg bshift = 0; 281428d7b3dSmrg gshift = bbits; 282428d7b3dSmrg rshift = gshift + gbits; 283428d7b3dSmrg ashift = rshift + rbits; 284428d7b3dSmrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 285428d7b3dSmrg rshift = 0; 286428d7b3dSmrg gshift = rbits; 287428d7b3dSmrg bshift = gshift + gbits; 288428d7b3dSmrg ashift = bshift + bbits; 289428d7b3dSmrg#if XORG_VERSION_CURRENT >= 10699900 290428d7b3dSmrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 291428d7b3dSmrg ashift = 0; 292428d7b3dSmrg rshift = abits; 293428d7b3dSmrg if (abits == 0) 294428d7b3dSmrg rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 295428d7b3dSmrg gshift = rshift + rbits; 296428d7b3dSmrg bshift = gshift + gbits; 297428d7b3dSmrg#endif 298428d7b3dSmrg } else { 299428d7b3dSmrg return FALSE; 300428d7b3dSmrg } 301428d7b3dSmrg 302428d7b3dSmrg if (rbits) { 303428d7b3dSmrg *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 304428d7b3dSmrg while (rbits < 16) { 305428d7b3dSmrg *red |= *red >> rbits; 306428d7b3dSmrg rbits <<= 1; 307428d7b3dSmrg } 308428d7b3dSmrg } else 309428d7b3dSmrg *red = 0; 310428d7b3dSmrg 311428d7b3dSmrg if (gbits) { 312428d7b3dSmrg *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 313428d7b3dSmrg while (gbits < 16) { 314428d7b3dSmrg *green |= *green >> gbits; 315428d7b3dSmrg gbits <<= 1; 316428d7b3dSmrg } 317428d7b3dSmrg } else 318428d7b3dSmrg *green = 0; 319428d7b3dSmrg 320428d7b3dSmrg if (bbits) { 321428d7b3dSmrg *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 322428d7b3dSmrg while (bbits < 16) { 323428d7b3dSmrg *blue |= *blue >> bbits; 324428d7b3dSmrg bbits <<= 1; 325428d7b3dSmrg } 326428d7b3dSmrg } else 327428d7b3dSmrg *blue = 0; 328428d7b3dSmrg 329428d7b3dSmrg if (abits) { 330428d7b3dSmrg *alpha = 331428d7b3dSmrg ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 332428d7b3dSmrg while (abits < 16) { 333428d7b3dSmrg *alpha |= *alpha >> abits; 334428d7b3dSmrg abits <<= 1; 335428d7b3dSmrg } 336428d7b3dSmrg } else 337428d7b3dSmrg *alpha = 0xffff; 338428d7b3dSmrg 339428d7b3dSmrg return TRUE; 340428d7b3dSmrg} 341428d7b3dSmrg 342428d7b3dSmrgBool 343428d7b3dSmrguxa_get_color_for_pixmap (PixmapPtr pixmap, 344428d7b3dSmrg CARD32 src_format, 345428d7b3dSmrg CARD32 dst_format, 346428d7b3dSmrg CARD32 *pixel) 347428d7b3dSmrg{ 348428d7b3dSmrg CARD16 red, green, blue, alpha; 349428d7b3dSmrg 350428d7b3dSmrg *pixel = uxa_get_pixmap_first_pixel(pixmap); 351428d7b3dSmrg 352428d7b3dSmrg if (src_format != dst_format) { 353428d7b3dSmrg if (!uxa_get_rgba_from_pixel(*pixel, 354428d7b3dSmrg &red, &green, &blue, &alpha, 355428d7b3dSmrg src_format)) 356428d7b3dSmrg return FALSE; 357428d7b3dSmrg 358428d7b3dSmrg if (!uxa_get_pixel_from_rgba(pixel, 359428d7b3dSmrg red, green, blue, alpha, 360428d7b3dSmrg dst_format)) 361428d7b3dSmrg return FALSE; 362428d7b3dSmrg } 363428d7b3dSmrg 364428d7b3dSmrg return TRUE; 365428d7b3dSmrg} 366428d7b3dSmrg 367428d7b3dSmrgstatic int 368428d7b3dSmrguxa_try_driver_solid_fill(PicturePtr pSrc, 369428d7b3dSmrg PicturePtr pDst, 370428d7b3dSmrg INT16 xSrc, 371428d7b3dSmrg INT16 ySrc, 372428d7b3dSmrg INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 373428d7b3dSmrg{ 374428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 375428d7b3dSmrg RegionRec region; 376428d7b3dSmrg BoxPtr pbox; 377428d7b3dSmrg int nbox; 378428d7b3dSmrg int dst_off_x, dst_off_y; 379428d7b3dSmrg PixmapPtr pSrcPix = NULL, pDstPix; 380428d7b3dSmrg CARD32 pixel; 381428d7b3dSmrg 382428d7b3dSmrg if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES)) 383428d7b3dSmrg return -1; 384428d7b3dSmrg 385428d7b3dSmrg pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); 386428d7b3dSmrg if (!pDstPix) 387428d7b3dSmrg return -1; 388428d7b3dSmrg 389428d7b3dSmrg xDst += pDst->pDrawable->x; 390428d7b3dSmrg yDst += pDst->pDrawable->y; 391428d7b3dSmrg 392428d7b3dSmrg if (pSrc->pDrawable) { 393428d7b3dSmrg pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); 394428d7b3dSmrg xSrc += pSrc->pDrawable->x; 395428d7b3dSmrg ySrc += pSrc->pDrawable->y; 396428d7b3dSmrg } 397428d7b3dSmrg 398428d7b3dSmrg if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst, 399428d7b3dSmrg xSrc, ySrc, 0, 0, xDst, yDst, 400428d7b3dSmrg width, height)) 401428d7b3dSmrg return 1; 402428d7b3dSmrg 403428d7b3dSmrg if (pSrcPix) { 404428d7b3dSmrg if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) { 405428d7b3dSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 406428d7b3dSmrg return -1; 407428d7b3dSmrg } 408428d7b3dSmrg } else { 409428d7b3dSmrg SourcePict *source = pSrc->pSourcePict; 410428d7b3dSmrg PictSolidFill *solid = &source->solidFill; 411428d7b3dSmrg 412428d7b3dSmrg if (source == NULL || source->type != SourcePictTypeSolidFill) { 413428d7b3dSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 414428d7b3dSmrg return -1; 415428d7b3dSmrg } 416428d7b3dSmrg 417428d7b3dSmrg if (pDst->format == PICT_a8r8g8b8) { 418428d7b3dSmrg pixel = solid->color; 419428d7b3dSmrg } else if (pDst->format == PICT_x8r8g8b8) { 420428d7b3dSmrg pixel = solid->color | 0xff000000; 421428d7b3dSmrg } else { 422428d7b3dSmrg CARD16 red, green, blue, alpha; 423428d7b3dSmrg 424428d7b3dSmrg if (!uxa_get_rgba_from_pixel(solid->color, 425428d7b3dSmrg &red, &green, &blue, &alpha, 426428d7b3dSmrg PICT_a8r8g8b8) || 427428d7b3dSmrg !uxa_get_pixel_from_rgba(&pixel, 428428d7b3dSmrg red, green, blue, alpha, 429428d7b3dSmrg pDst->format)) { 430428d7b3dSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 431428d7b3dSmrg return -1; 432428d7b3dSmrg } 433428d7b3dSmrg } 434428d7b3dSmrg } 435428d7b3dSmrg 436428d7b3dSmrg if (!(*uxa_screen->info->prepare_solid) 437428d7b3dSmrg (pDstPix, GXcopy, FB_ALLONES, pixel)) { 438428d7b3dSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 439428d7b3dSmrg return -1; 440428d7b3dSmrg } 441428d7b3dSmrg 442428d7b3dSmrg REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); 443428d7b3dSmrg 444428d7b3dSmrg nbox = REGION_NUM_RECTS(®ion); 445428d7b3dSmrg pbox = REGION_RECTS(®ion); 446428d7b3dSmrg 447428d7b3dSmrg while (nbox--) { 448428d7b3dSmrg (*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1, 449428d7b3dSmrg pbox->x2, pbox->y2); 450428d7b3dSmrg pbox++; 451428d7b3dSmrg } 452428d7b3dSmrg 453428d7b3dSmrg (*uxa_screen->info->done_solid) (pDstPix); 454428d7b3dSmrg 455428d7b3dSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 456428d7b3dSmrg return 1; 457428d7b3dSmrg} 458428d7b3dSmrg 459428d7b3dSmrgstatic PicturePtr 460428d7b3dSmrguxa_picture_for_pixman_format(ScreenPtr screen, 461428d7b3dSmrg pixman_format_code_t format, 462428d7b3dSmrg int width, int height) 463428d7b3dSmrg{ 464428d7b3dSmrg PicturePtr picture; 465428d7b3dSmrg PixmapPtr pixmap; 466428d7b3dSmrg int error; 467428d7b3dSmrg 468428d7b3dSmrg if (format == PIXMAN_a1) 469428d7b3dSmrg format = PIXMAN_a8; 470428d7b3dSmrg 471428d7b3dSmrg /* fill alpha if unset */ 472428d7b3dSmrg if (PIXMAN_FORMAT_A(format) == 0) 473428d7b3dSmrg format = PIXMAN_a8r8g8b8; 474428d7b3dSmrg 475428d7b3dSmrg pixmap = screen->CreatePixmap(screen, width, height, 476428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 477428d7b3dSmrg UXA_CREATE_PIXMAP_FOR_MAP); 478428d7b3dSmrg if (!pixmap) 479428d7b3dSmrg return 0; 480428d7b3dSmrg 481428d7b3dSmrg if (!uxa_pixmap_is_offscreen(pixmap)) { 482428d7b3dSmrg screen->DestroyPixmap(pixmap); 483428d7b3dSmrg return 0; 484428d7b3dSmrg } 485428d7b3dSmrg 486428d7b3dSmrg picture = CreatePicture(0, &pixmap->drawable, 487428d7b3dSmrg PictureMatchFormat(screen, 488428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 489428d7b3dSmrg format), 490428d7b3dSmrg 0, 0, serverClient, &error); 491428d7b3dSmrg screen->DestroyPixmap(pixmap); 492428d7b3dSmrg if (!picture) 493428d7b3dSmrg return 0; 494428d7b3dSmrg 495428d7b3dSmrg ValidatePicture(picture); 496428d7b3dSmrg 497428d7b3dSmrg return picture; 498428d7b3dSmrg} 499428d7b3dSmrg 500428d7b3dSmrgstatic PicturePtr 501428d7b3dSmrguxa_picture_from_pixman_image(ScreenPtr screen, 502428d7b3dSmrg pixman_image_t * image, 503428d7b3dSmrg pixman_format_code_t format) 504428d7b3dSmrg{ 505428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 506428d7b3dSmrg PicturePtr picture; 507428d7b3dSmrg PixmapPtr pixmap; 508428d7b3dSmrg int width, height; 509428d7b3dSmrg 510428d7b3dSmrg width = pixman_image_get_width(image); 511428d7b3dSmrg height = pixman_image_get_height(image); 512428d7b3dSmrg 513428d7b3dSmrg picture = uxa_picture_for_pixman_format(screen, format, 514428d7b3dSmrg width, height); 515428d7b3dSmrg if (!picture) 516428d7b3dSmrg return 0; 517428d7b3dSmrg 518428d7b3dSmrg if (uxa_screen->info->put_image && 519428d7b3dSmrg ((picture->pDrawable->depth << 24) | picture->format) == format && 520428d7b3dSmrg uxa_screen->info->put_image((PixmapPtr)picture->pDrawable, 521428d7b3dSmrg 0, 0, 522428d7b3dSmrg width, height, 523428d7b3dSmrg (char *)pixman_image_get_data(image), 524428d7b3dSmrg pixman_image_get_stride(image))) 525428d7b3dSmrg return picture; 526428d7b3dSmrg 527428d7b3dSmrg pixmap = GetScratchPixmapHeader(screen, width, height, 528428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 529428d7b3dSmrg PIXMAN_FORMAT_BPP(format), 530428d7b3dSmrg pixman_image_get_stride(image), 531428d7b3dSmrg pixman_image_get_data(image)); 532428d7b3dSmrg if (!pixmap) { 533428d7b3dSmrg FreePicture(picture, 0); 534428d7b3dSmrg return 0; 535428d7b3dSmrg } 536428d7b3dSmrg 537428d7b3dSmrg if (((picture->pDrawable->depth << 24) | picture->format) == format) { 538428d7b3dSmrg GCPtr gc; 539428d7b3dSmrg 540428d7b3dSmrg gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen); 541428d7b3dSmrg if (!gc) { 542428d7b3dSmrg FreeScratchPixmapHeader(pixmap); 543428d7b3dSmrg FreePicture(picture, 0); 544428d7b3dSmrg return 0; 545428d7b3dSmrg } 546428d7b3dSmrg ValidateGC(picture->pDrawable, gc); 547428d7b3dSmrg 548428d7b3dSmrg (*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable, 549428d7b3dSmrg gc, 0, 0, width, height, 0, 0); 550428d7b3dSmrg 551428d7b3dSmrg FreeScratchGC(gc); 552428d7b3dSmrg } else { 553428d7b3dSmrg PicturePtr src; 554428d7b3dSmrg int error; 555428d7b3dSmrg 556428d7b3dSmrg src = CreatePicture(0, &pixmap->drawable, 557428d7b3dSmrg PictureMatchFormat(screen, 558428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 559428d7b3dSmrg format), 560428d7b3dSmrg 0, 0, serverClient, &error); 561428d7b3dSmrg if (!src) { 562428d7b3dSmrg FreeScratchPixmapHeader(pixmap); 563428d7b3dSmrg FreePicture(picture, 0); 564428d7b3dSmrg return 0; 565428d7b3dSmrg } 566428d7b3dSmrg ValidatePicture(src); 567428d7b3dSmrg 568428d7b3dSmrg if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) { 569428d7b3dSmrg fbComposite(PictOpSrc, src, NULL, picture, 570428d7b3dSmrg 0, 0, 0, 0, 0, 0, width, height); 571428d7b3dSmrg uxa_picture_finish_access(picture, UXA_ACCESS_RW); 572428d7b3dSmrg } 573428d7b3dSmrg 574428d7b3dSmrg FreePicture(src, 0); 575428d7b3dSmrg } 576428d7b3dSmrg FreeScratchPixmapHeader(pixmap); 577428d7b3dSmrg 578428d7b3dSmrg return picture; 579428d7b3dSmrg} 580428d7b3dSmrg 581428d7b3dSmrgstatic PicturePtr 582428d7b3dSmrguxa_create_solid(ScreenPtr screen, uint32_t color) 583428d7b3dSmrg{ 584428d7b3dSmrg PixmapPtr pixmap; 585428d7b3dSmrg PicturePtr picture; 586428d7b3dSmrg XID repeat = RepeatNormal; 587428d7b3dSmrg int error = 0; 588428d7b3dSmrg 589428d7b3dSmrg pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32, 590428d7b3dSmrg UXA_CREATE_PIXMAP_FOR_MAP); 591428d7b3dSmrg if (!pixmap) 592428d7b3dSmrg return 0; 593428d7b3dSmrg 594428d7b3dSmrg if (!uxa_prepare_access((DrawablePtr)pixmap, UXA_ACCESS_RW)) { 595428d7b3dSmrg (*screen->DestroyPixmap)(pixmap); 596428d7b3dSmrg return 0; 597428d7b3dSmrg } 598428d7b3dSmrg *((uint32_t *)pixmap->devPrivate.ptr) = color; 599428d7b3dSmrg uxa_finish_access((DrawablePtr)pixmap, UXA_ACCESS_RW); 600428d7b3dSmrg 601428d7b3dSmrg picture = CreatePicture(0, &pixmap->drawable, 602428d7b3dSmrg PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 603428d7b3dSmrg CPRepeat, &repeat, serverClient, &error); 604428d7b3dSmrg (*screen->DestroyPixmap)(pixmap); 605428d7b3dSmrg 606428d7b3dSmrg return picture; 607428d7b3dSmrg} 608428d7b3dSmrg 609428d7b3dSmrgstatic PicturePtr 610428d7b3dSmrguxa_solid_clear(ScreenPtr screen) 611428d7b3dSmrg{ 612428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 613428d7b3dSmrg PicturePtr picture; 614428d7b3dSmrg 615428d7b3dSmrg if (!uxa_screen->solid_clear) { 616428d7b3dSmrg uxa_screen->solid_clear = uxa_create_solid(screen, 0); 617428d7b3dSmrg if (!uxa_screen->solid_clear) 618428d7b3dSmrg return 0; 619428d7b3dSmrg } 620428d7b3dSmrg picture = uxa_screen->solid_clear; 621428d7b3dSmrg return picture; 622428d7b3dSmrg} 623428d7b3dSmrg 624428d7b3dSmrgPicturePtr 625428d7b3dSmrguxa_acquire_solid(ScreenPtr screen, SourcePict *source) 626428d7b3dSmrg{ 627428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 628428d7b3dSmrg PictSolidFill *solid = &source->solidFill; 629428d7b3dSmrg PicturePtr picture; 630428d7b3dSmrg int i; 631428d7b3dSmrg 632428d7b3dSmrg if ((solid->color >> 24) == 0) { 633428d7b3dSmrg picture = uxa_solid_clear(screen); 634428d7b3dSmrg if (!picture) 635428d7b3dSmrg return 0; 636428d7b3dSmrg 637428d7b3dSmrg goto DONE; 638428d7b3dSmrg } else if (solid->color == 0xff000000) { 639428d7b3dSmrg if (!uxa_screen->solid_black) { 640428d7b3dSmrg uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000); 641428d7b3dSmrg if (!uxa_screen->solid_black) 642428d7b3dSmrg return 0; 643428d7b3dSmrg } 644428d7b3dSmrg picture = uxa_screen->solid_black; 645428d7b3dSmrg goto DONE; 646428d7b3dSmrg } else if (solid->color == 0xffffffff) { 647428d7b3dSmrg if (!uxa_screen->solid_white) { 648428d7b3dSmrg uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff); 649428d7b3dSmrg if (!uxa_screen->solid_white) 650428d7b3dSmrg return 0; 651428d7b3dSmrg } 652428d7b3dSmrg picture = uxa_screen->solid_white; 653428d7b3dSmrg goto DONE; 654428d7b3dSmrg } 655428d7b3dSmrg 656428d7b3dSmrg for (i = 0; i < uxa_screen->solid_cache_size; i++) { 657428d7b3dSmrg if (uxa_screen->solid_cache[i].color == solid->color) { 658428d7b3dSmrg picture = uxa_screen->solid_cache[i].picture; 659428d7b3dSmrg goto DONE; 660428d7b3dSmrg } 661428d7b3dSmrg } 662428d7b3dSmrg 663428d7b3dSmrg picture = uxa_create_solid(screen, solid->color); 664428d7b3dSmrg if (!picture) 665428d7b3dSmrg return 0; 666428d7b3dSmrg 667428d7b3dSmrg if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) { 668428d7b3dSmrg i = rand() % UXA_NUM_SOLID_CACHE; 669428d7b3dSmrg FreePicture(uxa_screen->solid_cache[i].picture, 0); 670428d7b3dSmrg } else 671428d7b3dSmrg uxa_screen->solid_cache_size++; 672428d7b3dSmrg 673428d7b3dSmrg uxa_screen->solid_cache[i].picture = picture; 674428d7b3dSmrg uxa_screen->solid_cache[i].color = solid->color; 675428d7b3dSmrg 676428d7b3dSmrgDONE: 677428d7b3dSmrg picture->refcnt++; 678428d7b3dSmrg return picture; 679428d7b3dSmrg} 680428d7b3dSmrg 681428d7b3dSmrgPicturePtr 682428d7b3dSmrguxa_acquire_pattern(ScreenPtr pScreen, 683428d7b3dSmrg PicturePtr pSrc, 684428d7b3dSmrg pixman_format_code_t format, 685428d7b3dSmrg INT16 x, INT16 y, CARD16 width, CARD16 height) 686428d7b3dSmrg{ 687428d7b3dSmrg PicturePtr pDst; 688428d7b3dSmrg 689428d7b3dSmrg if (pSrc->pSourcePict) { 690428d7b3dSmrg SourcePict *source = pSrc->pSourcePict; 691428d7b3dSmrg if (source->type == SourcePictTypeSolidFill) 692428d7b3dSmrg return uxa_acquire_solid (pScreen, source); 693428d7b3dSmrg } 694428d7b3dSmrg 695428d7b3dSmrg pDst = uxa_picture_for_pixman_format(pScreen, format, width, height); 696428d7b3dSmrg if (!pDst) 697428d7b3dSmrg return 0; 698428d7b3dSmrg 699428d7b3dSmrg if (uxa_picture_prepare_access(pDst, UXA_ACCESS_RW)) { 700428d7b3dSmrg fbComposite(PictOpSrc, pSrc, NULL, pDst, 701428d7b3dSmrg x, y, 0, 0, 0, 0, width, height); 702428d7b3dSmrg uxa_picture_finish_access(pDst, UXA_ACCESS_RW); 703428d7b3dSmrg return pDst; 704428d7b3dSmrg } else { 705428d7b3dSmrg FreePicture(pDst, 0); 706428d7b3dSmrg return 0; 707428d7b3dSmrg } 708428d7b3dSmrg} 709428d7b3dSmrg 710428d7b3dSmrgstatic Bool 711428d7b3dSmrgtransform_is_integer_translation(PictTransformPtr t, int *tx, int *ty) 712428d7b3dSmrg{ 713428d7b3dSmrg if (t == NULL) { 714428d7b3dSmrg *tx = *ty = 0; 715428d7b3dSmrg return TRUE; 716428d7b3dSmrg } 717428d7b3dSmrg 718428d7b3dSmrg if (t->matrix[0][0] != IntToxFixed(1) || 719428d7b3dSmrg t->matrix[0][1] != 0 || 720428d7b3dSmrg t->matrix[1][0] != 0 || 721428d7b3dSmrg t->matrix[1][1] != IntToxFixed(1) || 722428d7b3dSmrg t->matrix[2][0] != 0 || 723428d7b3dSmrg t->matrix[2][1] != 0 || 724428d7b3dSmrg t->matrix[2][2] != IntToxFixed(1)) 725428d7b3dSmrg return FALSE; 726428d7b3dSmrg 727428d7b3dSmrg if (xFixedFrac(t->matrix[0][2]) != 0 || 728428d7b3dSmrg xFixedFrac(t->matrix[1][2]) != 0) 729428d7b3dSmrg return FALSE; 730428d7b3dSmrg 731428d7b3dSmrg *tx = xFixedToInt(t->matrix[0][2]); 732428d7b3dSmrg *ty = xFixedToInt(t->matrix[1][2]); 733428d7b3dSmrg return TRUE; 734428d7b3dSmrg} 735428d7b3dSmrg 736428d7b3dSmrgstatic PicturePtr 737428d7b3dSmrguxa_render_picture(ScreenPtr screen, 738428d7b3dSmrg PicturePtr src, 739428d7b3dSmrg pixman_format_code_t format, 740428d7b3dSmrg INT16 x, INT16 y, 741428d7b3dSmrg CARD16 width, CARD16 height) 742428d7b3dSmrg{ 743428d7b3dSmrg PicturePtr picture; 744428d7b3dSmrg int ret = 0; 745428d7b3dSmrg 746428d7b3dSmrg /* XXX we need a mechanism for the card to choose the fallback format */ 747428d7b3dSmrg 748428d7b3dSmrg /* force alpha channel in case source does not entirely cover the extents */ 749428d7b3dSmrg if (PIXMAN_FORMAT_A(format) == 0) 750428d7b3dSmrg format = PIXMAN_a8r8g8b8; /* available on all hardware */ 751428d7b3dSmrg 752428d7b3dSmrg picture = uxa_picture_for_pixman_format(screen, format, width, height); 753428d7b3dSmrg if (!picture) 754428d7b3dSmrg return 0; 755428d7b3dSmrg 756428d7b3dSmrg if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) { 757428d7b3dSmrg if (uxa_picture_prepare_access(src, UXA_ACCESS_RO)) { 758428d7b3dSmrg ret = 1; 759428d7b3dSmrg fbComposite(PictOpSrc, src, NULL, picture, 760428d7b3dSmrg x, y, 0, 0, 0, 0, width, height); 761428d7b3dSmrg uxa_picture_finish_access(src, UXA_ACCESS_RO); 762428d7b3dSmrg } 763428d7b3dSmrg uxa_picture_finish_access(picture, UXA_ACCESS_RW); 764428d7b3dSmrg } 765428d7b3dSmrg 766428d7b3dSmrg if (!ret) { 767428d7b3dSmrg FreePicture(picture, 0); 768428d7b3dSmrg return 0; 769428d7b3dSmrg } 770428d7b3dSmrg 771428d7b3dSmrg return picture; 772428d7b3dSmrg} 773428d7b3dSmrg 774428d7b3dSmrgstatic int 775428d7b3dSmrgdrawable_contains (DrawablePtr drawable, int x, int y, int w, int h) 776428d7b3dSmrg{ 777428d7b3dSmrg if (x < 0 || y < 0) 778428d7b3dSmrg return FALSE; 779428d7b3dSmrg 780428d7b3dSmrg if (x + w > drawable->width) 781428d7b3dSmrg return FALSE; 782428d7b3dSmrg 783428d7b3dSmrg if (y + h > drawable->height) 784428d7b3dSmrg return FALSE; 785428d7b3dSmrg 786428d7b3dSmrg return TRUE; 787428d7b3dSmrg} 788428d7b3dSmrg 789428d7b3dSmrgPicturePtr 790428d7b3dSmrguxa_acquire_drawable(ScreenPtr pScreen, 791428d7b3dSmrg PicturePtr pSrc, 792428d7b3dSmrg INT16 x, INT16 y, 793428d7b3dSmrg CARD16 width, CARD16 height, 794428d7b3dSmrg INT16 * out_x, INT16 * out_y) 795428d7b3dSmrg{ 796428d7b3dSmrg PixmapPtr pPixmap; 797428d7b3dSmrg PicturePtr pDst; 798428d7b3dSmrg int depth, error; 799428d7b3dSmrg int tx, ty; 800428d7b3dSmrg GCPtr pGC; 801428d7b3dSmrg 802428d7b3dSmrg depth = pSrc->pDrawable->depth; 803428d7b3dSmrg if (!transform_is_integer_translation(pSrc->transform, &tx, &ty) || 804428d7b3dSmrg !drawable_contains(pSrc->pDrawable, x + tx, y + ty, width, height) || 805428d7b3dSmrg depth == 1 || 806428d7b3dSmrg pSrc->filter == PictFilterConvolution) { 807428d7b3dSmrg /* XXX extract the sample extents and do the transformation on the GPU */ 808428d7b3dSmrg pDst = uxa_render_picture(pScreen, pSrc, 809428d7b3dSmrg pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24), 810428d7b3dSmrg x, y, width, height); 811428d7b3dSmrg if (!pDst) 812428d7b3dSmrg return 0; 813428d7b3dSmrg 814428d7b3dSmrg goto done; 815428d7b3dSmrg } else { 816428d7b3dSmrg if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->height) { 817428d7b3dSmrg *out_x = x + pSrc->pDrawable->x; 818428d7b3dSmrg *out_y = y + pSrc->pDrawable->y; 819428d7b3dSmrg return pSrc; 820428d7b3dSmrg } 821428d7b3dSmrg } 822428d7b3dSmrg 823428d7b3dSmrg pPixmap = pScreen->CreatePixmap(pScreen, 824428d7b3dSmrg width, height, depth, 825428d7b3dSmrg CREATE_PIXMAP_USAGE_SCRATCH); 826428d7b3dSmrg if (!pPixmap) 827428d7b3dSmrg return 0; 828428d7b3dSmrg 829428d7b3dSmrg /* Skip the copy if the result remains in memory and not a bo */ 830428d7b3dSmrg if (!uxa_pixmap_is_offscreen(pPixmap)) { 831428d7b3dSmrg pScreen->DestroyPixmap(pPixmap); 832428d7b3dSmrg return 0; 833428d7b3dSmrg } 834428d7b3dSmrg 835428d7b3dSmrg pGC = GetScratchGC(depth, pScreen); 836428d7b3dSmrg if (!pGC) { 837428d7b3dSmrg pScreen->DestroyPixmap(pPixmap); 838428d7b3dSmrg return 0; 839428d7b3dSmrg } 840428d7b3dSmrg 841428d7b3dSmrg ValidateGC(&pPixmap->drawable, pGC); 842428d7b3dSmrg pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC, 843428d7b3dSmrg x + tx, y + ty, width, height, 0, 0); 844428d7b3dSmrg FreeScratchGC(pGC); 845428d7b3dSmrg 846428d7b3dSmrg pDst = CreatePicture(0, &pPixmap->drawable, 847428d7b3dSmrg PictureMatchFormat(pScreen, depth, pSrc->format), 848428d7b3dSmrg 0, 0, serverClient, &error); 849428d7b3dSmrg pScreen->DestroyPixmap(pPixmap); 850428d7b3dSmrg if (!pDst) 851428d7b3dSmrg return 0; 852428d7b3dSmrg 853428d7b3dSmrg ValidatePicture(pDst); 854428d7b3dSmrgdone: 855428d7b3dSmrg pDst->componentAlpha = pSrc->componentAlpha; 856428d7b3dSmrg *out_x = 0; 857428d7b3dSmrg *out_y = 0; 858428d7b3dSmrg return pDst; 859428d7b3dSmrg} 860428d7b3dSmrg 861428d7b3dSmrgstatic PicturePtr 862428d7b3dSmrguxa_acquire_picture(ScreenPtr screen, 863428d7b3dSmrg PicturePtr src, 864428d7b3dSmrg pixman_format_code_t format, 865428d7b3dSmrg INT16 x, INT16 y, 866428d7b3dSmrg CARD16 width, CARD16 height, 867428d7b3dSmrg INT16 * out_x, INT16 * out_y) 868428d7b3dSmrg{ 869428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 870428d7b3dSmrg 871428d7b3dSmrg if (uxa_screen->info->check_composite_texture && 872428d7b3dSmrg uxa_screen->info->check_composite_texture(screen, src)) { 873428d7b3dSmrg if (src->pDrawable) { 874428d7b3dSmrg *out_x = x + src->pDrawable->x; 875428d7b3dSmrg *out_y = y + src->pDrawable->y; 876428d7b3dSmrg } else { 877428d7b3dSmrg *out_x = x; 878428d7b3dSmrg *out_y = y; 879428d7b3dSmrg } 880428d7b3dSmrg return src; 881428d7b3dSmrg } 882428d7b3dSmrg 883428d7b3dSmrg if (src->pDrawable) { 884428d7b3dSmrg PicturePtr dst; 885428d7b3dSmrg 886428d7b3dSmrg dst = uxa_acquire_drawable(screen, src, 887428d7b3dSmrg x, y, width, height, 888428d7b3dSmrg out_x, out_y); 889428d7b3dSmrg if (!dst) 890428d7b3dSmrg return 0; 891428d7b3dSmrg 892428d7b3dSmrg if (uxa_screen->info->check_composite_texture && 893428d7b3dSmrg !uxa_screen->info->check_composite_texture(screen, dst)) { 894428d7b3dSmrg if (dst != src) 895428d7b3dSmrg FreePicture(dst, 0); 896428d7b3dSmrg return 0; 897428d7b3dSmrg } 898428d7b3dSmrg 899428d7b3dSmrg return dst; 900428d7b3dSmrg } 901428d7b3dSmrg 902428d7b3dSmrg *out_x = 0; 903428d7b3dSmrg *out_y = 0; 904428d7b3dSmrg return uxa_acquire_pattern(screen, src, 905428d7b3dSmrg format, x, y, width, height); 906428d7b3dSmrg} 907428d7b3dSmrg 908428d7b3dSmrgstatic PicturePtr 909428d7b3dSmrguxa_acquire_source(ScreenPtr screen, 910428d7b3dSmrg PicturePtr pict, 911428d7b3dSmrg INT16 x, INT16 y, 912428d7b3dSmrg CARD16 width, CARD16 height, 913428d7b3dSmrg INT16 * out_x, INT16 * out_y) 914428d7b3dSmrg{ 915428d7b3dSmrg return uxa_acquire_picture (screen, pict, 916428d7b3dSmrg PIXMAN_a8r8g8b8, 917428d7b3dSmrg x, y, 918428d7b3dSmrg width, height, 919428d7b3dSmrg out_x, out_y); 920428d7b3dSmrg} 921428d7b3dSmrg 922428d7b3dSmrgstatic PicturePtr 923428d7b3dSmrguxa_acquire_mask(ScreenPtr screen, 924428d7b3dSmrg PicturePtr pict, 925428d7b3dSmrg INT16 x, INT16 y, 926428d7b3dSmrg INT16 width, INT16 height, 927428d7b3dSmrg INT16 * out_x, INT16 * out_y) 928428d7b3dSmrg{ 929428d7b3dSmrg return uxa_acquire_picture (screen, pict, 930428d7b3dSmrg PIXMAN_a8, 931428d7b3dSmrg x, y, 932428d7b3dSmrg width, height, 933428d7b3dSmrg out_x, out_y); 934428d7b3dSmrg} 935428d7b3dSmrg 936428d7b3dSmrgstatic int 937428d7b3dSmrguxa_try_driver_composite(CARD8 op, 938428d7b3dSmrg PicturePtr pSrc, 939428d7b3dSmrg PicturePtr pMask, 940428d7b3dSmrg PicturePtr pDst, 941428d7b3dSmrg INT16 xSrc, INT16 ySrc, 942428d7b3dSmrg INT16 xMask, INT16 yMask, 943428d7b3dSmrg INT16 xDst, INT16 yDst, 944428d7b3dSmrg CARD16 width, CARD16 height) 945428d7b3dSmrg{ 946428d7b3dSmrg ScreenPtr screen = pDst->pDrawable->pScreen; 947428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 948428d7b3dSmrg RegionRec region; 949428d7b3dSmrg BoxPtr pbox; 950428d7b3dSmrg int nbox; 951428d7b3dSmrg int xDst_copy = 0, yDst_copy = 0; 952428d7b3dSmrg int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 953428d7b3dSmrg PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; 954428d7b3dSmrg PicturePtr localSrc, localMask = NULL; 955428d7b3dSmrg PicturePtr localDst = pDst; 956428d7b3dSmrg 957428d7b3dSmrg if (uxa_screen->info->check_composite && 958428d7b3dSmrg !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height)) 959428d7b3dSmrg return -1; 960428d7b3dSmrg 961428d7b3dSmrg if (uxa_screen->info->check_composite_target && 962428d7b3dSmrg !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 963428d7b3dSmrg int depth = pDst->pDrawable->depth; 964428d7b3dSmrg PixmapPtr pixmap; 965428d7b3dSmrg int error; 966428d7b3dSmrg GCPtr gc; 967428d7b3dSmrg 968428d7b3dSmrg pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 969428d7b3dSmrg if (uxa_screen->info->check_copy && 970428d7b3dSmrg !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 971428d7b3dSmrg return -1; 972428d7b3dSmrg 973428d7b3dSmrg pixmap = screen->CreatePixmap(screen, 974428d7b3dSmrg width, height, depth, 975428d7b3dSmrg CREATE_PIXMAP_USAGE_SCRATCH); 976428d7b3dSmrg if (!pixmap) 977428d7b3dSmrg return 0; 978428d7b3dSmrg 979428d7b3dSmrg gc = GetScratchGC(depth, screen); 980428d7b3dSmrg if (!gc) { 981428d7b3dSmrg screen->DestroyPixmap(pixmap); 982428d7b3dSmrg return 0; 983428d7b3dSmrg } 984428d7b3dSmrg 985428d7b3dSmrg ValidateGC(&pixmap->drawable, gc); 986428d7b3dSmrg gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 987428d7b3dSmrg xDst, yDst, width, height, 0, 0); 988428d7b3dSmrg FreeScratchGC(gc); 989428d7b3dSmrg 990428d7b3dSmrg xDst_copy = xDst; xDst = 0; 991428d7b3dSmrg yDst_copy = yDst; yDst = 0; 992428d7b3dSmrg 993428d7b3dSmrg localDst = CreatePicture(0, &pixmap->drawable, 994428d7b3dSmrg PictureMatchFormat(screen, depth, pDst->format), 995428d7b3dSmrg 0, 0, serverClient, &error); 996428d7b3dSmrg screen->DestroyPixmap(pixmap); 997428d7b3dSmrg 998428d7b3dSmrg if (!localDst) 999428d7b3dSmrg return 0; 1000428d7b3dSmrg 1001428d7b3dSmrg ValidatePicture(localDst); 1002428d7b3dSmrg } 1003428d7b3dSmrg 1004428d7b3dSmrg pDstPix = 1005428d7b3dSmrg uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y); 1006428d7b3dSmrg if (!pDstPix) { 1007428d7b3dSmrg if (localDst != pDst) 1008428d7b3dSmrg FreePicture(localDst, 0); 1009428d7b3dSmrg return -1; 1010428d7b3dSmrg } 1011428d7b3dSmrg 1012428d7b3dSmrg xDst += localDst->pDrawable->x; 1013428d7b3dSmrg yDst += localDst->pDrawable->y; 1014428d7b3dSmrg 1015428d7b3dSmrg localSrc = uxa_acquire_source(screen, pSrc, 1016428d7b3dSmrg xSrc, ySrc, 1017428d7b3dSmrg width, height, 1018428d7b3dSmrg &xSrc, &ySrc); 1019428d7b3dSmrg if (!localSrc) { 1020428d7b3dSmrg if (localDst != pDst) 1021428d7b3dSmrg FreePicture(localDst, 0); 1022428d7b3dSmrg return 0; 1023428d7b3dSmrg } 1024428d7b3dSmrg 1025428d7b3dSmrg if (pMask) { 1026428d7b3dSmrg localMask = uxa_acquire_mask(screen, pMask, 1027428d7b3dSmrg xMask, yMask, 1028428d7b3dSmrg width, height, 1029428d7b3dSmrg &xMask, &yMask); 1030428d7b3dSmrg if (!localMask) { 1031428d7b3dSmrg if (localSrc != pSrc) 1032428d7b3dSmrg FreePicture(localSrc, 0); 1033428d7b3dSmrg if (localDst != pDst) 1034428d7b3dSmrg FreePicture(localDst, 0); 1035428d7b3dSmrg 1036428d7b3dSmrg return 0; 1037428d7b3dSmrg } 1038428d7b3dSmrg } 1039428d7b3dSmrg 1040428d7b3dSmrg if (!miComputeCompositeRegion(®ion, localSrc, localMask, localDst, 1041428d7b3dSmrg xSrc, ySrc, xMask, yMask, xDst, yDst, 1042428d7b3dSmrg width, height)) { 1043428d7b3dSmrg if (localSrc != pSrc) 1044428d7b3dSmrg FreePicture(localSrc, 0); 1045428d7b3dSmrg if (localMask && localMask != pMask) 1046428d7b3dSmrg FreePicture(localMask, 0); 1047428d7b3dSmrg if (localDst != pDst) 1048428d7b3dSmrg FreePicture(localDst, 0); 1049428d7b3dSmrg 1050428d7b3dSmrg return 1; 1051428d7b3dSmrg } 1052428d7b3dSmrg 1053428d7b3dSmrg pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, 1054428d7b3dSmrg &src_off_x, &src_off_y); 1055428d7b3dSmrg if (!pSrcPix) { 1056428d7b3dSmrg REGION_UNINIT(screen, ®ion); 1057428d7b3dSmrg 1058428d7b3dSmrg if (localSrc != pSrc) 1059428d7b3dSmrg FreePicture(localSrc, 0); 1060428d7b3dSmrg if (localMask && localMask != pMask) 1061428d7b3dSmrg FreePicture(localMask, 0); 1062428d7b3dSmrg if (localDst != pDst) 1063428d7b3dSmrg FreePicture(localDst, 0); 1064428d7b3dSmrg 1065428d7b3dSmrg return 0; 1066428d7b3dSmrg } 1067428d7b3dSmrg 1068428d7b3dSmrg if (localMask) { 1069428d7b3dSmrg pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, 1070428d7b3dSmrg &mask_off_x, &mask_off_y); 1071428d7b3dSmrg if (!pMaskPix) { 1072428d7b3dSmrg REGION_UNINIT(screen, ®ion); 1073428d7b3dSmrg 1074428d7b3dSmrg if (localSrc != pSrc) 1075428d7b3dSmrg FreePicture(localSrc, 0); 1076428d7b3dSmrg if (localMask && localMask != pMask) 1077428d7b3dSmrg FreePicture(localMask, 0); 1078428d7b3dSmrg if (localDst != pDst) 1079428d7b3dSmrg FreePicture(localDst, 0); 1080428d7b3dSmrg 1081428d7b3dSmrg return 0; 1082428d7b3dSmrg } 1083428d7b3dSmrg } 1084428d7b3dSmrg 1085428d7b3dSmrg if (!(*uxa_screen->info->prepare_composite) 1086428d7b3dSmrg (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) { 1087428d7b3dSmrg REGION_UNINIT(screen, ®ion); 1088428d7b3dSmrg 1089428d7b3dSmrg if (localSrc != pSrc) 1090428d7b3dSmrg FreePicture(localSrc, 0); 1091428d7b3dSmrg if (localMask && localMask != pMask) 1092428d7b3dSmrg FreePicture(localMask, 0); 1093428d7b3dSmrg if (localDst != pDst) 1094428d7b3dSmrg FreePicture(localDst, 0); 1095428d7b3dSmrg 1096428d7b3dSmrg return -1; 1097428d7b3dSmrg } 1098428d7b3dSmrg 1099428d7b3dSmrg if (pMask) { 1100428d7b3dSmrg xMask = xMask + mask_off_x - xDst; 1101428d7b3dSmrg yMask = yMask + mask_off_y - yDst; 1102428d7b3dSmrg } 1103428d7b3dSmrg 1104428d7b3dSmrg xSrc = xSrc + src_off_x - xDst; 1105428d7b3dSmrg ySrc = ySrc + src_off_y - yDst; 1106428d7b3dSmrg 1107428d7b3dSmrg nbox = REGION_NUM_RECTS(®ion); 1108428d7b3dSmrg pbox = REGION_RECTS(®ion); 1109428d7b3dSmrg while (nbox--) { 1110428d7b3dSmrg (*uxa_screen->info->composite) (pDstPix, 1111428d7b3dSmrg pbox->x1 + xSrc, 1112428d7b3dSmrg pbox->y1 + ySrc, 1113428d7b3dSmrg pbox->x1 + xMask, 1114428d7b3dSmrg pbox->y1 + yMask, 1115428d7b3dSmrg pbox->x1 + dst_off_x, 1116428d7b3dSmrg pbox->y1 + dst_off_y, 1117428d7b3dSmrg pbox->x2 - pbox->x1, 1118428d7b3dSmrg pbox->y2 - pbox->y1); 1119428d7b3dSmrg pbox++; 1120428d7b3dSmrg } 1121428d7b3dSmrg (*uxa_screen->info->done_composite) (pDstPix); 1122428d7b3dSmrg 1123428d7b3dSmrg REGION_UNINIT(screen, ®ion); 1124428d7b3dSmrg 1125428d7b3dSmrg if (localSrc != pSrc) 1126428d7b3dSmrg FreePicture(localSrc, 0); 1127428d7b3dSmrg if (localMask && localMask != pMask) 1128428d7b3dSmrg FreePicture(localMask, 0); 1129428d7b3dSmrg 1130428d7b3dSmrg if (localDst != pDst) { 1131428d7b3dSmrg GCPtr gc; 1132428d7b3dSmrg 1133428d7b3dSmrg gc = GetScratchGC(pDst->pDrawable->depth, screen); 1134428d7b3dSmrg if (gc) { 1135428d7b3dSmrg ValidateGC(pDst->pDrawable, gc); 1136428d7b3dSmrg gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 1137428d7b3dSmrg 0, 0, width, height, xDst_copy, yDst_copy); 1138428d7b3dSmrg FreeScratchGC(gc); 1139428d7b3dSmrg } 1140428d7b3dSmrg 1141428d7b3dSmrg FreePicture(localDst, 0); 1142428d7b3dSmrg } 1143428d7b3dSmrg 1144428d7b3dSmrg return 1; 1145428d7b3dSmrg} 1146428d7b3dSmrg 1147428d7b3dSmrg/** 1148428d7b3dSmrg * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of 1149428d7b3dSmrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 1150428d7b3dSmrg * alpha and limited 1-tmu cards. 1151428d7b3dSmrg * 1152428d7b3dSmrg * From http://anholt.livejournal.com/32058.html: 1153428d7b3dSmrg * 1154428d7b3dSmrg * The trouble is that component-alpha rendering requires two different sources 1155428d7b3dSmrg * for blending: one for the source value to the blender, which is the 1156428d7b3dSmrg * per-channel multiplication of source and mask, and one for the source alpha 1157428d7b3dSmrg * for multiplying with the destination channels, which is the multiplication 1158428d7b3dSmrg * of the source channels by the mask alpha. So the equation for Over is: 1159428d7b3dSmrg * 1160428d7b3dSmrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 1161428d7b3dSmrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 1162428d7b3dSmrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 1163428d7b3dSmrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 1164428d7b3dSmrg * 1165428d7b3dSmrg * But we can do some simpler operations, right? How about PictOpOutReverse, 1166428d7b3dSmrg * which has a source factor of 0 and dest factor of (1 - source alpha). We 1167428d7b3dSmrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 1168428d7b3dSmrg * blenders pretty easily. So we can do a component-alpha OutReverse, which 1169428d7b3dSmrg * gets us: 1170428d7b3dSmrg * 1171428d7b3dSmrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 1172428d7b3dSmrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 1173428d7b3dSmrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 1174428d7b3dSmrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 1175428d7b3dSmrg * 1176428d7b3dSmrg * OK. And if an op doesn't use the source alpha value for the destination 1177428d7b3dSmrg * factor, then we can do the channel multiplication in the texture blenders 1178428d7b3dSmrg * to get the source value, and ignore the source alpha that we wouldn't use. 1179428d7b3dSmrg * We've supported this in the Radeon driver for a long time. An example would 1180428d7b3dSmrg * be PictOpAdd, which does: 1181428d7b3dSmrg * 1182428d7b3dSmrg * dst.A = src.A * mask.A + dst.A 1183428d7b3dSmrg * dst.R = src.R * mask.R + dst.R 1184428d7b3dSmrg * dst.G = src.G * mask.G + dst.G 1185428d7b3dSmrg * dst.B = src.B * mask.B + dst.B 1186428d7b3dSmrg * 1187428d7b3dSmrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 1188428d7b3dSmrg * after it, we get: 1189428d7b3dSmrg * 1190428d7b3dSmrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 1191428d7b3dSmrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 1192428d7b3dSmrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 1193428d7b3dSmrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 1194428d7b3dSmrg */ 1195428d7b3dSmrg 1196428d7b3dSmrgstatic int 1197428d7b3dSmrguxa_try_magic_two_pass_composite_helper(CARD8 op, 1198428d7b3dSmrg PicturePtr pSrc, 1199428d7b3dSmrg PicturePtr pMask, 1200428d7b3dSmrg PicturePtr pDst, 1201428d7b3dSmrg INT16 xSrc, INT16 ySrc, 1202428d7b3dSmrg INT16 xMask, INT16 yMask, 1203428d7b3dSmrg INT16 xDst, INT16 yDst, 1204428d7b3dSmrg CARD16 width, CARD16 height) 1205428d7b3dSmrg{ 1206428d7b3dSmrg ScreenPtr screen = pDst->pDrawable->pScreen; 1207428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1208428d7b3dSmrg PicturePtr localDst = pDst; 1209428d7b3dSmrg int xDst_copy, yDst_copy; 1210428d7b3dSmrg 1211428d7b3dSmrg assert(op == PictOpOver); 1212428d7b3dSmrg 1213428d7b3dSmrg if (uxa_screen->info->check_composite && 1214428d7b3dSmrg (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc, 1215428d7b3dSmrg pMask, pDst, width, height) 1216428d7b3dSmrg || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask, 1217428d7b3dSmrg pDst, width, height))) { 1218428d7b3dSmrg return -1; 1219428d7b3dSmrg } 1220428d7b3dSmrg 1221428d7b3dSmrg if (uxa_screen->info->check_composite_target && 1222428d7b3dSmrg !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 1223428d7b3dSmrg int depth = pDst->pDrawable->depth; 1224428d7b3dSmrg PixmapPtr pixmap; 1225428d7b3dSmrg int error; 1226428d7b3dSmrg GCPtr gc; 1227428d7b3dSmrg 1228428d7b3dSmrg pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 1229428d7b3dSmrg if (uxa_screen->info->check_copy && 1230428d7b3dSmrg !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 1231428d7b3dSmrg return -1; 1232428d7b3dSmrg 1233428d7b3dSmrg pixmap = screen->CreatePixmap(screen, 1234428d7b3dSmrg width, height, depth, 1235428d7b3dSmrg CREATE_PIXMAP_USAGE_SCRATCH); 1236428d7b3dSmrg if (!pixmap) 1237428d7b3dSmrg return 0; 1238428d7b3dSmrg 1239428d7b3dSmrg gc = GetScratchGC(depth, screen); 1240428d7b3dSmrg if (!gc) { 1241428d7b3dSmrg screen->DestroyPixmap(pixmap); 1242428d7b3dSmrg return 0; 1243428d7b3dSmrg } 1244428d7b3dSmrg 1245428d7b3dSmrg ValidateGC(&pixmap->drawable, gc); 1246428d7b3dSmrg gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 1247428d7b3dSmrg xDst, yDst, width, height, 0, 0); 1248428d7b3dSmrg FreeScratchGC(gc); 1249428d7b3dSmrg 1250428d7b3dSmrg xDst_copy = xDst; xDst = 0; 1251428d7b3dSmrg yDst_copy = yDst; yDst = 0; 1252428d7b3dSmrg 1253428d7b3dSmrg localDst = CreatePicture(0, &pixmap->drawable, 1254428d7b3dSmrg PictureMatchFormat(screen, depth, pDst->format), 1255428d7b3dSmrg 0, 0, serverClient, &error); 1256428d7b3dSmrg screen->DestroyPixmap(pixmap); 1257428d7b3dSmrg 1258428d7b3dSmrg if (!localDst) 1259428d7b3dSmrg return 0; 1260428d7b3dSmrg 1261428d7b3dSmrg ValidatePicture(localDst); 1262428d7b3dSmrg } 1263428d7b3dSmrg 1264428d7b3dSmrg /* Now, we think we should be able to accelerate this operation. First, 1265428d7b3dSmrg * composite the destination to be the destination times the source alpha 1266428d7b3dSmrg * factors. 1267428d7b3dSmrg */ 1268428d7b3dSmrg uxa_composite(PictOpOutReverse, pSrc, pMask, localDst, 1269428d7b3dSmrg xSrc, ySrc, 1270428d7b3dSmrg xMask, yMask, 1271428d7b3dSmrg xDst, yDst, 1272428d7b3dSmrg width, height); 1273428d7b3dSmrg 1274428d7b3dSmrg /* Then, add in the source value times the destination alpha factors (1.0). 1275428d7b3dSmrg */ 1276428d7b3dSmrg uxa_composite(PictOpAdd, pSrc, pMask, localDst, 1277428d7b3dSmrg xSrc, ySrc, 1278428d7b3dSmrg xMask, yMask, 1279428d7b3dSmrg xDst, yDst, 1280428d7b3dSmrg width, height); 1281428d7b3dSmrg 1282428d7b3dSmrg if (localDst != pDst) { 1283428d7b3dSmrg GCPtr gc; 1284428d7b3dSmrg 1285428d7b3dSmrg gc = GetScratchGC(pDst->pDrawable->depth, screen); 1286428d7b3dSmrg if (gc) { 1287428d7b3dSmrg ValidateGC(pDst->pDrawable, gc); 1288428d7b3dSmrg gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 1289428d7b3dSmrg 0, 0, width, height, xDst_copy, yDst_copy); 1290428d7b3dSmrg FreeScratchGC(gc); 1291428d7b3dSmrg } 1292428d7b3dSmrg 1293428d7b3dSmrg FreePicture(localDst, 0); 1294428d7b3dSmrg } 1295428d7b3dSmrg 1296428d7b3dSmrg return 1; 1297428d7b3dSmrg} 1298428d7b3dSmrg 1299428d7b3dSmrgstatic int 1300428d7b3dSmrgcompatible_formats (CARD8 op, PicturePtr dst, PicturePtr src) 1301428d7b3dSmrg{ 1302428d7b3dSmrg if (op == PictOpSrc) { 1303428d7b3dSmrg if (src->format == dst->format) 1304428d7b3dSmrg return 1; 1305428d7b3dSmrg 1306428d7b3dSmrg /* Is the destination an alpha-less version of source? */ 1307428d7b3dSmrg if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format), 1308428d7b3dSmrg PICT_FORMAT_TYPE(src->format), 1309428d7b3dSmrg 0, 1310428d7b3dSmrg PICT_FORMAT_R(src->format), 1311428d7b3dSmrg PICT_FORMAT_G(src->format), 1312428d7b3dSmrg PICT_FORMAT_B(src->format))) 1313428d7b3dSmrg return 1; 1314428d7b3dSmrg 1315428d7b3dSmrg /* XXX xrgb is promoted to argb during image upload... */ 1316428d7b3dSmrg#if 0 1317428d7b3dSmrg if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8) 1318428d7b3dSmrg return 1; 1319428d7b3dSmrg#endif 1320428d7b3dSmrg } else if (op == PictOpOver) { 1321428d7b3dSmrg if (PICT_FORMAT_A(src->format)) 1322428d7b3dSmrg return 0; 1323428d7b3dSmrg 1324428d7b3dSmrg return src->format == dst->format; 1325428d7b3dSmrg } 1326428d7b3dSmrg 1327428d7b3dSmrg return 0; 1328428d7b3dSmrg} 1329428d7b3dSmrg 1330428d7b3dSmrgvoid 1331428d7b3dSmrguxa_composite(CARD8 op, 1332428d7b3dSmrg PicturePtr pSrc, 1333428d7b3dSmrg PicturePtr pMask, 1334428d7b3dSmrg PicturePtr pDst, 1335428d7b3dSmrg INT16 xSrc, INT16 ySrc, 1336428d7b3dSmrg INT16 xMask, INT16 yMask, 1337428d7b3dSmrg INT16 xDst, INT16 yDst, 1338428d7b3dSmrg CARD16 width, CARD16 height) 1339428d7b3dSmrg{ 1340428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 1341428d7b3dSmrg int ret = -1; 1342428d7b3dSmrg Bool saveSrcRepeat = pSrc->repeat; 1343428d7b3dSmrg Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 1344428d7b3dSmrg RegionRec region; 1345428d7b3dSmrg int tx, ty; 1346428d7b3dSmrg 1347428d7b3dSmrg if (uxa_screen->force_fallback) 1348428d7b3dSmrg goto fallback; 1349428d7b3dSmrg 1350428d7b3dSmrg if (!uxa_drawable_is_offscreen(pDst->pDrawable)) 1351428d7b3dSmrg goto fallback; 1352428d7b3dSmrg 1353428d7b3dSmrg if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) 1354428d7b3dSmrg goto fallback; 1355428d7b3dSmrg 1356428d7b3dSmrg /* Remove repeat in source if useless */ 1357428d7b3dSmrg if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution && 1358428d7b3dSmrg transform_is_integer_translation(pSrc->transform, &tx, &ty) && 1359428d7b3dSmrg (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) && 1360428d7b3dSmrg drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height)) 1361428d7b3dSmrg pSrc->repeat = 0; 1362428d7b3dSmrg 1363428d7b3dSmrg if (!pMask) { 1364428d7b3dSmrg if (op == PictOpClear) { 1365428d7b3dSmrg PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen); 1366428d7b3dSmrg if (clear && 1367428d7b3dSmrg uxa_try_driver_solid_fill(clear, pDst, 1368428d7b3dSmrg xSrc, ySrc, 1369428d7b3dSmrg xDst, yDst, 1370428d7b3dSmrg width, height) == 1) 1371428d7b3dSmrg goto done; 1372428d7b3dSmrg } 1373428d7b3dSmrg 1374428d7b3dSmrg if (pSrc->pDrawable == NULL) { 1375428d7b3dSmrg if (pSrc->pSourcePict) { 1376428d7b3dSmrg SourcePict *source = pSrc->pSourcePict; 1377428d7b3dSmrg if (source->type == SourcePictTypeSolidFill) { 1378428d7b3dSmrg if (op == PictOpSrc || 1379428d7b3dSmrg (op == PictOpOver && 1380428d7b3dSmrg (source->solidFill.color & 0xff000000) == 0xff000000)) { 1381428d7b3dSmrg ret = uxa_try_driver_solid_fill(pSrc, pDst, 1382428d7b3dSmrg xSrc, ySrc, 1383428d7b3dSmrg xDst, yDst, 1384428d7b3dSmrg width, height); 1385428d7b3dSmrg if (ret == 1) 1386428d7b3dSmrg goto done; 1387428d7b3dSmrg } 1388428d7b3dSmrg } 1389428d7b3dSmrg } 1390428d7b3dSmrg } else if (pSrc->pDrawable->width == 1 && 1391428d7b3dSmrg pSrc->pDrawable->height == 1 && 1392428d7b3dSmrg pSrc->repeat && 1393428d7b3dSmrg (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) { 1394428d7b3dSmrg ret = uxa_try_driver_solid_fill(pSrc, pDst, 1395428d7b3dSmrg xSrc, ySrc, 1396428d7b3dSmrg xDst, yDst, 1397428d7b3dSmrg width, height); 1398428d7b3dSmrg if (ret == 1) 1399428d7b3dSmrg goto done; 1400428d7b3dSmrg } else if (compatible_formats (op, pDst, pSrc) && 1401428d7b3dSmrg pSrc->filter != PictFilterConvolution && 1402428d7b3dSmrg transform_is_integer_translation(pSrc->transform, &tx, &ty)) { 1403428d7b3dSmrg if (!pSrc->repeat && 1404428d7b3dSmrg drawable_contains(pSrc->pDrawable, 1405428d7b3dSmrg xSrc + tx, ySrc + ty, 1406428d7b3dSmrg width, height)) { 1407428d7b3dSmrg xDst += pDst->pDrawable->x; 1408428d7b3dSmrg yDst += pDst->pDrawable->y; 1409428d7b3dSmrg xSrc += pSrc->pDrawable->x + tx; 1410428d7b3dSmrg ySrc += pSrc->pDrawable->y + ty; 1411428d7b3dSmrg 1412428d7b3dSmrg if (!miComputeCompositeRegion 1413428d7b3dSmrg (®ion, pSrc, pMask, pDst, xSrc, ySrc, 1414428d7b3dSmrg xMask, yMask, xDst, yDst, width, height)) 1415428d7b3dSmrg goto done; 1416428d7b3dSmrg 1417428d7b3dSmrg uxa_copy_n_to_n(pSrc->pDrawable, 1418428d7b3dSmrg pDst->pDrawable, NULL, 1419428d7b3dSmrg REGION_RECTS(®ion), 1420428d7b3dSmrg REGION_NUM_RECTS(®ion), 1421428d7b3dSmrg xSrc - xDst, ySrc - yDst, FALSE, 1422428d7b3dSmrg FALSE, 0, NULL); 1423428d7b3dSmrg REGION_UNINIT(pDst->pDrawable->pScreen, 1424428d7b3dSmrg ®ion); 1425428d7b3dSmrg goto done; 1426428d7b3dSmrg } else if (pSrc->repeat && pSrc->repeatType == RepeatNormal && 1427428d7b3dSmrg pSrc->pDrawable->type == DRAWABLE_PIXMAP) { 1428428d7b3dSmrg DDXPointRec patOrg; 1429428d7b3dSmrg 1430428d7b3dSmrg /* Let's see if the driver can do the repeat 1431428d7b3dSmrg * in one go 1432428d7b3dSmrg */ 1433428d7b3dSmrg if (uxa_screen->info->prepare_composite) { 1434428d7b3dSmrg ret = uxa_try_driver_composite(op, pSrc, 1435428d7b3dSmrg pMask, pDst, 1436428d7b3dSmrg xSrc, ySrc, 1437428d7b3dSmrg xMask, yMask, 1438428d7b3dSmrg xDst, yDst, 1439428d7b3dSmrg width, height); 1440428d7b3dSmrg if (ret == 1) 1441428d7b3dSmrg goto done; 1442428d7b3dSmrg } 1443428d7b3dSmrg 1444428d7b3dSmrg /* Now see if we can use 1445428d7b3dSmrg * uxa_fill_region_tiled() 1446428d7b3dSmrg */ 1447428d7b3dSmrg xDst += pDst->pDrawable->x; 1448428d7b3dSmrg yDst += pDst->pDrawable->y; 1449428d7b3dSmrg xSrc += pSrc->pDrawable->x + tx; 1450428d7b3dSmrg ySrc += pSrc->pDrawable->y + ty; 1451428d7b3dSmrg 1452428d7b3dSmrg if (!miComputeCompositeRegion 1453428d7b3dSmrg (®ion, pSrc, pMask, pDst, xSrc, ySrc, 1454428d7b3dSmrg xMask, yMask, xDst, yDst, width, height)) 1455428d7b3dSmrg goto done; 1456428d7b3dSmrg 1457428d7b3dSmrg /* pattern origin is the point in the 1458428d7b3dSmrg * destination drawable 1459428d7b3dSmrg * corresponding to (0,0) in the source */ 1460428d7b3dSmrg patOrg.x = xDst - xSrc; 1461428d7b3dSmrg patOrg.y = yDst - ySrc; 1462428d7b3dSmrg 1463428d7b3dSmrg ret = uxa_fill_region_tiled(pDst->pDrawable, 1464428d7b3dSmrg ®ion, 1465428d7b3dSmrg (PixmapPtr) pSrc-> 1466428d7b3dSmrg pDrawable, &patOrg, 1467428d7b3dSmrg FB_ALLONES, GXcopy); 1468428d7b3dSmrg 1469428d7b3dSmrg REGION_UNINIT(pDst->pDrawable->pScreen, 1470428d7b3dSmrg ®ion); 1471428d7b3dSmrg 1472428d7b3dSmrg if (ret) 1473428d7b3dSmrg goto done; 1474428d7b3dSmrg } 1475428d7b3dSmrg } 1476428d7b3dSmrg } 1477428d7b3dSmrg 1478428d7b3dSmrg /* Remove repeat in mask if useless */ 1479428d7b3dSmrg if (pMask && pMask->pDrawable && pMask->repeat && 1480428d7b3dSmrg pMask->filter != PictFilterConvolution && 1481428d7b3dSmrg transform_is_integer_translation(pMask->transform, &tx, &ty) && 1482428d7b3dSmrg (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) && 1483428d7b3dSmrg drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height)) 1484428d7b3dSmrg pMask->repeat = 0; 1485428d7b3dSmrg 1486428d7b3dSmrg if (uxa_screen->info->prepare_composite) { 1487428d7b3dSmrg Bool isSrcSolid; 1488428d7b3dSmrg 1489428d7b3dSmrg ret = 1490428d7b3dSmrg uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 1491428d7b3dSmrg xMask, yMask, xDst, yDst, width, 1492428d7b3dSmrg height); 1493428d7b3dSmrg if (ret == 1) 1494428d7b3dSmrg goto done; 1495428d7b3dSmrg 1496428d7b3dSmrg /* For generic masks and solid src pictures, mach64 can do 1497428d7b3dSmrg * Over in two passes, similar to the component-alpha case. 1498428d7b3dSmrg */ 1499428d7b3dSmrg 1500428d7b3dSmrg isSrcSolid = 1501428d7b3dSmrg pSrc->pDrawable ? 1502428d7b3dSmrg pSrc->pDrawable->width == 1 && 1503428d7b3dSmrg pSrc->pDrawable->height == 1 && 1504428d7b3dSmrg pSrc->repeat : 1505428d7b3dSmrg pSrc->pSourcePict ? 1506428d7b3dSmrg pSrc->pSourcePict->type == SourcePictTypeSolidFill : 1507428d7b3dSmrg 0; 1508428d7b3dSmrg 1509428d7b3dSmrg /* If we couldn't do the Composite in a single pass, and it 1510428d7b3dSmrg * was a component-alpha Over, see if we can do it in two 1511428d7b3dSmrg * passes with an OutReverse and then an Add. 1512428d7b3dSmrg */ 1513428d7b3dSmrg if (ret == -1 && op == PictOpOver && pMask && 1514428d7b3dSmrg (pMask->componentAlpha || isSrcSolid)) { 1515428d7b3dSmrg ret = 1516428d7b3dSmrg uxa_try_magic_two_pass_composite_helper(op, pSrc, 1517428d7b3dSmrg pMask, pDst, 1518428d7b3dSmrg xSrc, ySrc, 1519428d7b3dSmrg xMask, yMask, 1520428d7b3dSmrg xDst, yDst, 1521428d7b3dSmrg width, height); 1522428d7b3dSmrg if (ret == 1) 1523428d7b3dSmrg goto done; 1524428d7b3dSmrg } 1525428d7b3dSmrg 1526428d7b3dSmrg } 1527428d7b3dSmrg 1528428d7b3dSmrgfallback: 1529428d7b3dSmrg uxa_print_composite_fallback("uxa_composite", 1530428d7b3dSmrg op, pSrc, pMask, pDst); 1531428d7b3dSmrg 1532428d7b3dSmrg uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 1533428d7b3dSmrg xMask, yMask, xDst, yDst, width, height); 1534428d7b3dSmrg 1535428d7b3dSmrgdone: 1536428d7b3dSmrg pSrc->repeat = saveSrcRepeat; 1537428d7b3dSmrg if (pMask) 1538428d7b3dSmrg pMask->repeat = saveMaskRepeat; 1539428d7b3dSmrg} 1540428d7b3dSmrg#endif 1541428d7b3dSmrg 1542428d7b3dSmrg/** 1543428d7b3dSmrg * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead 1544428d7b3dSmrg * of PolyFillRect to initialize the pixmap after creating it, to prevent 1545428d7b3dSmrg * the pixmap from being migrated. 1546428d7b3dSmrg * 1547428d7b3dSmrg * See the comments about uxa_trapezoids and uxa_triangles. 1548428d7b3dSmrg */ 1549428d7b3dSmrgstatic PicturePtr 1550428d7b3dSmrguxa_create_alpha_picture(ScreenPtr pScreen, 1551428d7b3dSmrg PicturePtr pDst, 1552428d7b3dSmrg PictFormatPtr pPictFormat, CARD16 width, CARD16 height) 1553428d7b3dSmrg{ 1554428d7b3dSmrg PixmapPtr pPixmap; 1555428d7b3dSmrg PicturePtr pPicture; 1556428d7b3dSmrg int error; 1557428d7b3dSmrg 1558428d7b3dSmrg if (width > 32767 || height > 32767) 1559428d7b3dSmrg return 0; 1560428d7b3dSmrg 1561428d7b3dSmrg if (!pPictFormat) { 1562428d7b3dSmrg if (pDst->polyEdge == PolyEdgeSharp) 1563428d7b3dSmrg pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1564428d7b3dSmrg else 1565428d7b3dSmrg pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1566428d7b3dSmrg if (!pPictFormat) 1567428d7b3dSmrg return 0; 1568428d7b3dSmrg } 1569428d7b3dSmrg 1570428d7b3dSmrg pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1571428d7b3dSmrg pPictFormat->depth, 1572428d7b3dSmrg UXA_CREATE_PIXMAP_FOR_MAP); 1573428d7b3dSmrg if (!pPixmap) 1574428d7b3dSmrg return 0; 1575428d7b3dSmrg pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 1576428d7b3dSmrg 0, 0, serverClient, &error); 1577428d7b3dSmrg (*pScreen->DestroyPixmap) (pPixmap); 1578428d7b3dSmrg return pPicture; 1579428d7b3dSmrg} 1580428d7b3dSmrg 1581428d7b3dSmrgstatic void 1582428d7b3dSmrguxa_check_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, 1583428d7b3dSmrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1584428d7b3dSmrg int ntrap, xTrapezoid * traps) 1585428d7b3dSmrg{ 1586428d7b3dSmrg ScreenPtr screen = dst->pDrawable->pScreen; 1587428d7b3dSmrg 1588428d7b3dSmrg if (maskFormat) { 1589428d7b3dSmrg PixmapPtr scratch = NULL; 1590428d7b3dSmrg PicturePtr mask; 1591428d7b3dSmrg INT16 xDst, yDst; 1592428d7b3dSmrg INT16 xRel, yRel; 1593428d7b3dSmrg BoxRec bounds; 1594428d7b3dSmrg int width, height; 1595428d7b3dSmrg pixman_image_t *image; 1596428d7b3dSmrg pixman_format_code_t format; 1597428d7b3dSmrg int error; 1598428d7b3dSmrg 1599428d7b3dSmrg xDst = traps[0].left.p1.x >> 16; 1600428d7b3dSmrg yDst = traps[0].left.p1.y >> 16; 1601428d7b3dSmrg 1602428d7b3dSmrg miTrapezoidBounds (ntrap, traps, &bounds); 1603428d7b3dSmrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1604428d7b3dSmrg return; 1605428d7b3dSmrg 1606428d7b3dSmrg width = bounds.x2 - bounds.x1; 1607428d7b3dSmrg height = bounds.y2 - bounds.y1; 1608428d7b3dSmrg 1609428d7b3dSmrg format = maskFormat->format | 1610428d7b3dSmrg (BitsPerPixel(maskFormat->depth) << 24); 1611428d7b3dSmrg image = 1612428d7b3dSmrg pixman_image_create_bits(format, width, height, NULL, 0); 1613428d7b3dSmrg if (!image) 1614428d7b3dSmrg return; 1615428d7b3dSmrg 1616428d7b3dSmrg for (; ntrap; ntrap--, traps++) 1617428d7b3dSmrg pixman_rasterize_trapezoid(image, 1618428d7b3dSmrg (pixman_trapezoid_t *) traps, 1619428d7b3dSmrg -bounds.x1, -bounds.y1); 1620428d7b3dSmrg 1621428d7b3dSmrg 1622428d7b3dSmrg scratch = GetScratchPixmapHeader(screen, width, height, 1623428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 1624428d7b3dSmrg PIXMAN_FORMAT_BPP(format), 1625428d7b3dSmrg pixman_image_get_stride(image), 1626428d7b3dSmrg pixman_image_get_data(image)); 1627428d7b3dSmrg if (!scratch) { 1628428d7b3dSmrg pixman_image_unref(image); 1629428d7b3dSmrg return; 1630428d7b3dSmrg } 1631428d7b3dSmrg 1632428d7b3dSmrg mask = CreatePicture(0, &scratch->drawable, 1633428d7b3dSmrg PictureMatchFormat(screen, 1634428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 1635428d7b3dSmrg format), 1636428d7b3dSmrg 0, 0, serverClient, &error); 1637428d7b3dSmrg if (!mask) { 1638428d7b3dSmrg FreeScratchPixmapHeader(scratch); 1639428d7b3dSmrg pixman_image_unref(image); 1640428d7b3dSmrg return; 1641428d7b3dSmrg } 1642428d7b3dSmrg 1643428d7b3dSmrg xRel = bounds.x1 + xSrc - xDst; 1644428d7b3dSmrg yRel = bounds.y1 + ySrc - yDst; 1645428d7b3dSmrg CompositePicture(op, src, mask, dst, 1646428d7b3dSmrg xRel, yRel, 1647428d7b3dSmrg 0, 0, 1648428d7b3dSmrg bounds.x1, bounds.y1, 1649428d7b3dSmrg width, height); 1650428d7b3dSmrg FreePicture(mask, 0); 1651428d7b3dSmrg 1652428d7b3dSmrg FreeScratchPixmapHeader(scratch); 1653428d7b3dSmrg pixman_image_unref(image); 1654428d7b3dSmrg } else { 1655428d7b3dSmrg if (dst->polyEdge == PolyEdgeSharp) 1656428d7b3dSmrg maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 1657428d7b3dSmrg else 1658428d7b3dSmrg maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 1659428d7b3dSmrg 1660428d7b3dSmrg for (; ntrap; ntrap--, traps++) 1661428d7b3dSmrg uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps); 1662428d7b3dSmrg } 1663428d7b3dSmrg} 1664428d7b3dSmrg 1665428d7b3dSmrg/** 1666428d7b3dSmrg * uxa_trapezoids is essentially a copy of miTrapezoids that uses 1667428d7b3dSmrg * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1668428d7b3dSmrg * 1669428d7b3dSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1670428d7b3dSmrg * to initialize the contents after creating the pixmap, which 1671428d7b3dSmrg * causes the pixmap to be moved in for acceleration. The subsequent 1672428d7b3dSmrg * call to RasterizeTrapezoid won't be accelerated however, which 1673428d7b3dSmrg * forces the pixmap to be moved out again. 1674428d7b3dSmrg * 1675428d7b3dSmrg * uxa_create_alpha_picture avoids this roundtrip by using 1676428d7b3dSmrg * uxa_check_poly_fill_rect to initialize the contents. 1677428d7b3dSmrg */ 1678428d7b3dSmrgvoid 1679428d7b3dSmrguxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, 1680428d7b3dSmrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1681428d7b3dSmrg int ntrap, xTrapezoid * traps) 1682428d7b3dSmrg{ 1683428d7b3dSmrg ScreenPtr screen = dst->pDrawable->pScreen; 1684428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1685428d7b3dSmrg BoxRec bounds; 1686428d7b3dSmrg Bool direct; 1687428d7b3dSmrg 1688428d7b3dSmrg if (uxa_screen->force_fallback) { 1689428d7b3dSmrg uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, ntrap, traps); 1690428d7b3dSmrg return; 1691428d7b3dSmrg } 1692428d7b3dSmrg 1693428d7b3dSmrg direct = op == PictOpAdd && miIsSolidAlpha(src); 1694428d7b3dSmrg if (maskFormat || direct) { 1695428d7b3dSmrg miTrapezoidBounds(ntrap, traps, &bounds); 1696428d7b3dSmrg 1697428d7b3dSmrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1698428d7b3dSmrg return; 1699428d7b3dSmrg } 1700428d7b3dSmrg 1701428d7b3dSmrg /* 1702428d7b3dSmrg * Check for solid alpha add 1703428d7b3dSmrg */ 1704428d7b3dSmrg if (direct) { 1705428d7b3dSmrg DrawablePtr pDraw = dst->pDrawable; 1706428d7b3dSmrg PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw); 1707428d7b3dSmrg int xoff, yoff; 1708428d7b3dSmrg 1709428d7b3dSmrg uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff); 1710428d7b3dSmrg 1711428d7b3dSmrg xoff += pDraw->x; 1712428d7b3dSmrg yoff += pDraw->y; 1713428d7b3dSmrg 1714428d7b3dSmrg if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) { 1715428d7b3dSmrg PictureScreenPtr ps = GetPictureScreen(screen); 1716428d7b3dSmrg 1717428d7b3dSmrg for (; ntrap; ntrap--, traps++) 1718428d7b3dSmrg (*ps->RasterizeTrapezoid) (dst, traps, 0, 0); 1719428d7b3dSmrg uxa_finish_access(pDraw, UXA_ACCESS_RW); 1720428d7b3dSmrg } 1721428d7b3dSmrg } else if (maskFormat) { 1722428d7b3dSmrg PixmapPtr scratch = NULL; 1723428d7b3dSmrg PicturePtr mask; 1724428d7b3dSmrg INT16 xDst, yDst; 1725428d7b3dSmrg INT16 xRel, yRel; 1726428d7b3dSmrg int width, height; 1727428d7b3dSmrg pixman_image_t *image; 1728428d7b3dSmrg pixman_format_code_t format; 1729428d7b3dSmrg 1730428d7b3dSmrg xDst = traps[0].left.p1.x >> 16; 1731428d7b3dSmrg yDst = traps[0].left.p1.y >> 16; 1732428d7b3dSmrg 1733428d7b3dSmrg width = bounds.x2 - bounds.x1; 1734428d7b3dSmrg height = bounds.y2 - bounds.y1; 1735428d7b3dSmrg 1736428d7b3dSmrg format = maskFormat->format | 1737428d7b3dSmrg (BitsPerPixel(maskFormat->depth) << 24); 1738428d7b3dSmrg image = 1739428d7b3dSmrg pixman_image_create_bits(format, width, height, NULL, 0); 1740428d7b3dSmrg if (!image) 1741428d7b3dSmrg return; 1742428d7b3dSmrg 1743428d7b3dSmrg for (; ntrap; ntrap--, traps++) 1744428d7b3dSmrg pixman_rasterize_trapezoid(image, 1745428d7b3dSmrg (pixman_trapezoid_t *) traps, 1746428d7b3dSmrg -bounds.x1, -bounds.y1); 1747428d7b3dSmrg if (uxa_drawable_is_offscreen(dst->pDrawable)) { 1748428d7b3dSmrg mask = uxa_picture_from_pixman_image(screen, image, format); 1749428d7b3dSmrg } else { 1750428d7b3dSmrg int error; 1751428d7b3dSmrg 1752428d7b3dSmrg scratch = GetScratchPixmapHeader(screen, width, height, 1753428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 1754428d7b3dSmrg PIXMAN_FORMAT_BPP(format), 1755428d7b3dSmrg pixman_image_get_stride(image), 1756428d7b3dSmrg pixman_image_get_data(image)); 1757428d7b3dSmrg mask = CreatePicture(0, &scratch->drawable, 1758428d7b3dSmrg PictureMatchFormat(screen, 1759428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 1760428d7b3dSmrg format), 1761428d7b3dSmrg 0, 0, serverClient, &error); 1762428d7b3dSmrg } 1763428d7b3dSmrg if (!mask) { 1764428d7b3dSmrg if (scratch) 1765428d7b3dSmrg FreeScratchPixmapHeader(scratch); 1766428d7b3dSmrg pixman_image_unref(image); 1767428d7b3dSmrg return; 1768428d7b3dSmrg } 1769428d7b3dSmrg 1770428d7b3dSmrg xRel = bounds.x1 + xSrc - xDst; 1771428d7b3dSmrg yRel = bounds.y1 + ySrc - yDst; 1772428d7b3dSmrg CompositePicture(op, src, mask, dst, 1773428d7b3dSmrg xRel, yRel, 1774428d7b3dSmrg 0, 0, 1775428d7b3dSmrg bounds.x1, bounds.y1, 1776428d7b3dSmrg width, height); 1777428d7b3dSmrg FreePicture(mask, 0); 1778428d7b3dSmrg 1779428d7b3dSmrg if (scratch) 1780428d7b3dSmrg FreeScratchPixmapHeader(scratch); 1781428d7b3dSmrg pixman_image_unref(image); 1782428d7b3dSmrg } else { 1783428d7b3dSmrg if (dst->polyEdge == PolyEdgeSharp) 1784428d7b3dSmrg maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 1785428d7b3dSmrg else 1786428d7b3dSmrg maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 1787428d7b3dSmrg for (; ntrap; ntrap--, traps++) 1788428d7b3dSmrg uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1789428d7b3dSmrg 1, traps); 1790428d7b3dSmrg } 1791428d7b3dSmrg} 1792428d7b3dSmrg 1793428d7b3dSmrgstatic void 1794428d7b3dSmrguxa_check_triangles(CARD8 op, PicturePtr src, PicturePtr dst, 1795428d7b3dSmrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1796428d7b3dSmrg int ntri, xTriangle *tri) 1797428d7b3dSmrg{ 1798428d7b3dSmrg ScreenPtr screen = dst->pDrawable->pScreen; 1799428d7b3dSmrg 1800428d7b3dSmrg if (maskFormat) { 1801428d7b3dSmrg PixmapPtr scratch = NULL; 1802428d7b3dSmrg PicturePtr mask; 1803428d7b3dSmrg INT16 xDst, yDst; 1804428d7b3dSmrg INT16 xRel, yRel; 1805428d7b3dSmrg BoxRec bounds; 1806428d7b3dSmrg int width, height; 1807428d7b3dSmrg pixman_image_t *image; 1808428d7b3dSmrg pixman_format_code_t format; 1809428d7b3dSmrg int error; 1810428d7b3dSmrg 1811428d7b3dSmrg xDst = pixman_fixed_to_int(tri[0].p1.x); 1812428d7b3dSmrg yDst = pixman_fixed_to_int(tri[0].p1.y); 1813428d7b3dSmrg 1814428d7b3dSmrg miTriangleBounds (ntri, tri, &bounds); 1815428d7b3dSmrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1816428d7b3dSmrg return; 1817428d7b3dSmrg 1818428d7b3dSmrg width = bounds.x2 - bounds.x1; 1819428d7b3dSmrg height = bounds.y2 - bounds.y1; 1820428d7b3dSmrg 1821428d7b3dSmrg format = maskFormat->format | 1822428d7b3dSmrg (BitsPerPixel(maskFormat->depth) << 24); 1823428d7b3dSmrg image = 1824428d7b3dSmrg pixman_image_create_bits(format, width, height, NULL, 0); 1825428d7b3dSmrg if (!image) 1826428d7b3dSmrg return; 1827428d7b3dSmrg 1828428d7b3dSmrg pixman_add_triangles(image, 1829428d7b3dSmrg -bounds.x1, -bounds.y1, 1830428d7b3dSmrg ntri, (pixman_triangle_t *)tri); 1831428d7b3dSmrg 1832428d7b3dSmrg scratch = GetScratchPixmapHeader(screen, width, height, 1833428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 1834428d7b3dSmrg PIXMAN_FORMAT_BPP(format), 1835428d7b3dSmrg pixman_image_get_stride(image), 1836428d7b3dSmrg pixman_image_get_data(image)); 1837428d7b3dSmrg if (!scratch) { 1838428d7b3dSmrg pixman_image_unref(image); 1839428d7b3dSmrg return; 1840428d7b3dSmrg } 1841428d7b3dSmrg 1842428d7b3dSmrg mask = CreatePicture(0, &scratch->drawable, 1843428d7b3dSmrg PictureMatchFormat(screen, 1844428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 1845428d7b3dSmrg format), 1846428d7b3dSmrg 0, 0, serverClient, &error); 1847428d7b3dSmrg if (!mask) { 1848428d7b3dSmrg FreeScratchPixmapHeader(scratch); 1849428d7b3dSmrg pixman_image_unref(image); 1850428d7b3dSmrg return; 1851428d7b3dSmrg } 1852428d7b3dSmrg 1853428d7b3dSmrg xRel = bounds.x1 + xSrc - xDst; 1854428d7b3dSmrg yRel = bounds.y1 + ySrc - yDst; 1855428d7b3dSmrg CompositePicture(op, src, mask, dst, 1856428d7b3dSmrg xRel, yRel, 1857428d7b3dSmrg 0, 0, 1858428d7b3dSmrg bounds.x1, bounds.y1, 1859428d7b3dSmrg width, height); 1860428d7b3dSmrg FreePicture(mask, 0); 1861428d7b3dSmrg 1862428d7b3dSmrg FreeScratchPixmapHeader(scratch); 1863428d7b3dSmrg pixman_image_unref(image); 1864428d7b3dSmrg } else { 1865428d7b3dSmrg if (dst->polyEdge == PolyEdgeSharp) 1866428d7b3dSmrg maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 1867428d7b3dSmrg else 1868428d7b3dSmrg maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 1869428d7b3dSmrg 1870428d7b3dSmrg for (; ntri; ntri--, tri++) 1871428d7b3dSmrg uxa_check_triangles(op, src, dst, maskFormat, xSrc, ySrc, 1, tri); 1872428d7b3dSmrg } 1873428d7b3dSmrg} 1874428d7b3dSmrg 1875428d7b3dSmrg/** 1876428d7b3dSmrg * uxa_triangles is essentially a copy of miTriangles that uses 1877428d7b3dSmrg * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1878428d7b3dSmrg * 1879428d7b3dSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1880428d7b3dSmrg * to initialize the contents after creating the pixmap, which 1881428d7b3dSmrg * causes the pixmap to be moved in for acceleration. The subsequent 1882428d7b3dSmrg * call to AddTriangles won't be accelerated however, which forces the pixmap 1883428d7b3dSmrg * to be moved out again. 1884428d7b3dSmrg * 1885428d7b3dSmrg * uxa_create_alpha_picture avoids this roundtrip by using 1886428d7b3dSmrg * uxa_check_poly_fill_rect to initialize the contents. 1887428d7b3dSmrg */ 1888428d7b3dSmrgvoid 1889428d7b3dSmrguxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1890428d7b3dSmrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1891428d7b3dSmrg int ntri, xTriangle * tris) 1892428d7b3dSmrg{ 1893428d7b3dSmrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 1894428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 1895428d7b3dSmrg PictureScreenPtr ps = GetPictureScreen(pScreen); 1896428d7b3dSmrg BoxRec bounds; 1897428d7b3dSmrg Bool direct; 1898428d7b3dSmrg 1899428d7b3dSmrg if (uxa_screen->force_fallback) { 1900428d7b3dSmrg uxa_check_triangles(op, pSrc, pDst, maskFormat, 1901428d7b3dSmrg xSrc, ySrc, ntri, tris); 1902428d7b3dSmrg return; 1903428d7b3dSmrg } 1904428d7b3dSmrg 1905428d7b3dSmrg direct = op == PictOpAdd && miIsSolidAlpha(pSrc); 1906428d7b3dSmrg if (maskFormat || direct) { 1907428d7b3dSmrg miTriangleBounds(ntri, tris, &bounds); 1908428d7b3dSmrg 1909428d7b3dSmrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1910428d7b3dSmrg return; 1911428d7b3dSmrg } 1912428d7b3dSmrg 1913428d7b3dSmrg /* 1914428d7b3dSmrg * Check for solid alpha add 1915428d7b3dSmrg */ 1916428d7b3dSmrg if (direct) { 1917428d7b3dSmrg DrawablePtr pDraw = pDst->pDrawable; 1918428d7b3dSmrg if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) { 1919428d7b3dSmrg (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); 1920428d7b3dSmrg uxa_finish_access(pDraw, UXA_ACCESS_RW); 1921428d7b3dSmrg } 1922428d7b3dSmrg } else if (maskFormat) { 1923428d7b3dSmrg PicturePtr pPicture; 1924428d7b3dSmrg INT16 xDst, yDst; 1925428d7b3dSmrg INT16 xRel, yRel; 1926428d7b3dSmrg int width = bounds.x2 - bounds.x1; 1927428d7b3dSmrg int height = bounds.y2 - bounds.y1; 1928428d7b3dSmrg GCPtr pGC; 1929428d7b3dSmrg xRectangle rect; 1930428d7b3dSmrg 1931428d7b3dSmrg xDst = tris[0].p1.x >> 16; 1932428d7b3dSmrg yDst = tris[0].p1.y >> 16; 1933428d7b3dSmrg 1934428d7b3dSmrg pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat, 1935428d7b3dSmrg width, height); 1936428d7b3dSmrg if (!pPicture) 1937428d7b3dSmrg return; 1938428d7b3dSmrg 1939428d7b3dSmrg /* Clear the alpha picture to 0. */ 1940428d7b3dSmrg pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen); 1941428d7b3dSmrg if (!pGC) { 1942428d7b3dSmrg FreePicture(pPicture, 0); 1943428d7b3dSmrg return; 1944428d7b3dSmrg } 1945428d7b3dSmrg ValidateGC(pPicture->pDrawable, pGC); 1946428d7b3dSmrg rect.x = 0; 1947428d7b3dSmrg rect.y = 0; 1948428d7b3dSmrg rect.width = width; 1949428d7b3dSmrg rect.height = height; 1950428d7b3dSmrg uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect); 1951428d7b3dSmrg FreeScratchGC(pGC); 1952428d7b3dSmrg 1953428d7b3dSmrg if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) { 1954428d7b3dSmrg (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, 1955428d7b3dSmrg ntri, tris); 1956428d7b3dSmrg uxa_finish_access(pPicture->pDrawable, UXA_ACCESS_RW); 1957428d7b3dSmrg } 1958428d7b3dSmrg 1959428d7b3dSmrg xRel = bounds.x1 + xSrc - xDst; 1960428d7b3dSmrg yRel = bounds.y1 + ySrc - yDst; 1961428d7b3dSmrg CompositePicture(op, pSrc, pPicture, pDst, 1962428d7b3dSmrg xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1963428d7b3dSmrg bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1964428d7b3dSmrg FreePicture(pPicture, 0); 1965428d7b3dSmrg } else { 1966428d7b3dSmrg if (pDst->polyEdge == PolyEdgeSharp) 1967428d7b3dSmrg maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1968428d7b3dSmrg else 1969428d7b3dSmrg maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1970428d7b3dSmrg 1971428d7b3dSmrg for (; ntri; ntri--, tris++) 1972428d7b3dSmrg uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, 1973428d7b3dSmrg tris); 1974428d7b3dSmrg } 1975428d7b3dSmrg} 1976428d7b3dSmrg 1977428d7b3dSmrgvoid 1978428d7b3dSmrguxa_add_traps(PicturePtr pPicture, 1979428d7b3dSmrg INT16 x_off, INT16 y_off, int ntrap, xTrap * traps) 1980428d7b3dSmrg{ 1981428d7b3dSmrg uxa_check_add_traps(pPicture, x_off, y_off, ntrap, traps); 1982428d7b3dSmrg} 1983