1d514b0f3Smrg/* 2d514b0f3Smrg * Copyright © 2001 Keith Packard 3d514b0f3Smrg * 4d514b0f3Smrg * Partly based on code that is Copyright © The XFree86 Project Inc. 5d514b0f3Smrg * 6d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its 7d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that 8d514b0f3Smrg * the above copyright notice appear in all copies and that both that 9d514b0f3Smrg * copyright notice and this permission notice appear in supporting 10d514b0f3Smrg * documentation, and that the name of Keith Packard not be used in 11d514b0f3Smrg * advertising or publicity pertaining to distribution of the software without 12d514b0f3Smrg * specific, written prior permission. Keith Packard makes no 13d514b0f3Smrg * representations about the suitability of this software for any purpose. It 14d514b0f3Smrg * is provided "as is" without express or implied warranty. 15d514b0f3Smrg * 16d514b0f3Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17d514b0f3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18d514b0f3Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19d514b0f3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20d514b0f3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21d514b0f3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22d514b0f3Smrg * PERFORMANCE OF THIS SOFTWARE. 23d514b0f3Smrg */ 24d514b0f3Smrg 25d514b0f3Smrg#ifdef HAVE_DIX_CONFIG_H 26d514b0f3Smrg#include <dix-config.h> 27d514b0f3Smrg#endif 28d514b0f3Smrg 29d514b0f3Smrg#include <stdlib.h> 30d514b0f3Smrg 31d514b0f3Smrg#include "uxa-priv.h" 32d514b0f3Smrg#include <xorgVersion.h> 33d514b0f3Smrg 34d514b0f3Smrg#ifdef RENDER 35d514b0f3Smrg#include "mipict.h" 36d514b0f3Smrg 37d514b0f3Smrgstatic void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string, 38d514b0f3Smrg int n) 39d514b0f3Smrg{ 40d514b0f3Smrg char format[20]; 41d514b0f3Smrg char size[20]; 42d514b0f3Smrg char loc; 43d514b0f3Smrg 44d514b0f3Smrg if (!pict) { 45d514b0f3Smrg snprintf(string, n, "None"); 46d514b0f3Smrg return; 47d514b0f3Smrg } 48d514b0f3Smrg 49d514b0f3Smrg if (pict->pDrawable == NULL) { 50d514b0f3Smrg snprintf(string, n, "source-only"); 51d514b0f3Smrg return; 52d514b0f3Smrg } 53d514b0f3Smrg 54d514b0f3Smrg switch (pict->format) { 55d514b0f3Smrg case PICT_a8r8g8b8: 56d514b0f3Smrg snprintf(format, 20, "ARGB8888"); 57d514b0f3Smrg break; 58d514b0f3Smrg case PICT_x8r8g8b8: 59d514b0f3Smrg snprintf(format, 20, "XRGB8888"); 60d514b0f3Smrg break; 61d514b0f3Smrg case PICT_r5g6b5: 62d514b0f3Smrg snprintf(format, 20, "RGB565 "); 63d514b0f3Smrg break; 64d514b0f3Smrg case PICT_x1r5g5b5: 65d514b0f3Smrg snprintf(format, 20, "RGB555 "); 66d514b0f3Smrg break; 67d514b0f3Smrg case PICT_a8: 68d514b0f3Smrg snprintf(format, 20, "A8 "); 69d514b0f3Smrg break; 70d514b0f3Smrg case PICT_a1: 71d514b0f3Smrg snprintf(format, 20, "A1 "); 72d514b0f3Smrg break; 73d514b0f3Smrg default: 74d514b0f3Smrg snprintf(format, 20, "0x%x", (int)pict->format); 75d514b0f3Smrg break; 76d514b0f3Smrg } 77d514b0f3Smrg 78d514b0f3Smrg loc = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm'; 79d514b0f3Smrg 80d514b0f3Smrg snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, 81d514b0f3Smrg pict->pDrawable->height, pict->repeat ? " R" : ""); 82d514b0f3Smrg 83d514b0f3Smrg snprintf(string, n, "%p:%c fmt %s (%s)%s", 84d514b0f3Smrg pict->pDrawable, loc, format, size, 85d514b0f3Smrg pict->alphaMap ? " with alpha map" :""); 86d514b0f3Smrg} 87d514b0f3Smrg 88d514b0f3Smrgstatic const char * 89d514b0f3Smrgop_to_string(CARD8 op) 90d514b0f3Smrg{ 91d514b0f3Smrg switch (op) { 92d514b0f3Smrg#define C(x) case PictOp##x: return #x 93d514b0f3Smrg C(Clear); 94d514b0f3Smrg C(Src); 95d514b0f3Smrg C(Dst); 96d514b0f3Smrg C(Over); 97d514b0f3Smrg C(OverReverse); 98d514b0f3Smrg C(In); 99d514b0f3Smrg C(InReverse); 100d514b0f3Smrg C(Out); 101d514b0f3Smrg C(OutReverse); 102d514b0f3Smrg C(Atop); 103d514b0f3Smrg C(AtopReverse); 104d514b0f3Smrg C(Xor); 105d514b0f3Smrg C(Add); 106d514b0f3Smrg C(Saturate); 107d514b0f3Smrg 108d514b0f3Smrg /* 109d514b0f3Smrg * Operators only available in version 0.2 110d514b0f3Smrg */ 111d514b0f3Smrg C(DisjointClear); 112d514b0f3Smrg C(DisjointSrc); 113d514b0f3Smrg C(DisjointDst); 114d514b0f3Smrg C(DisjointOver); 115d514b0f3Smrg C(DisjointOverReverse); 116d514b0f3Smrg C(DisjointIn); 117d514b0f3Smrg C(DisjointInReverse); 118d514b0f3Smrg C(DisjointOut); 119d514b0f3Smrg C(DisjointOutReverse); 120d514b0f3Smrg C(DisjointAtop); 121d514b0f3Smrg C(DisjointAtopReverse); 122d514b0f3Smrg C(DisjointXor); 123d514b0f3Smrg 124d514b0f3Smrg C(ConjointClear); 125d514b0f3Smrg C(ConjointSrc); 126d514b0f3Smrg C(ConjointDst); 127d514b0f3Smrg C(ConjointOver); 128d514b0f3Smrg C(ConjointOverReverse); 129d514b0f3Smrg C(ConjointIn); 130d514b0f3Smrg C(ConjointInReverse); 131d514b0f3Smrg C(ConjointOut); 132d514b0f3Smrg C(ConjointOutReverse); 133d514b0f3Smrg C(ConjointAtop); 134d514b0f3Smrg C(ConjointAtopReverse); 135d514b0f3Smrg C(ConjointXor); 136d514b0f3Smrg 137d514b0f3Smrg /* 138d514b0f3Smrg * Operators only available in version 0.11 139d514b0f3Smrg */ 140d514b0f3Smrg C(Multiply); 141d514b0f3Smrg C(Screen); 142d514b0f3Smrg C(Overlay); 143d514b0f3Smrg C(Darken); 144d514b0f3Smrg C(Lighten); 145d514b0f3Smrg C(ColorDodge); 146d514b0f3Smrg C(ColorBurn); 147d514b0f3Smrg C(HardLight); 148d514b0f3Smrg C(SoftLight); 149d514b0f3Smrg C(Difference); 150d514b0f3Smrg C(Exclusion); 151d514b0f3Smrg C(HSLHue); 152d514b0f3Smrg C(HSLSaturation); 153d514b0f3Smrg C(HSLColor); 154d514b0f3Smrg C(HSLLuminosity); 155d514b0f3Smrg default: return "garbage"; 156d514b0f3Smrg#undef C 157d514b0f3Smrg } 158d514b0f3Smrg} 159d514b0f3Smrg 160d514b0f3Smrgstatic void 161d514b0f3Smrguxa_print_composite_fallback(const char *func, CARD8 op, 162d514b0f3Smrg PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) 163d514b0f3Smrg{ 164d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 165d514b0f3Smrg char srcdesc[40], maskdesc[40], dstdesc[40]; 166d514b0f3Smrg 167d514b0f3Smrg if (! uxa_screen->fallback_debug) 168d514b0f3Smrg return; 169d514b0f3Smrg 170d514b0f3Smrg /* Limit the noise if fallbacks are expected. */ 171d514b0f3Smrg if (uxa_screen->force_fallback) 172d514b0f3Smrg return; 173d514b0f3Smrg 174d514b0f3Smrg uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40); 175d514b0f3Smrg uxa_composite_fallback_pict_desc(pMask, maskdesc, 40); 176d514b0f3Smrg uxa_composite_fallback_pict_desc(pDst, dstdesc, 40); 177d514b0f3Smrg 178d514b0f3Smrg ErrorF("Composite fallback at %s:\n" 179d514b0f3Smrg " op %s, \n" 180d514b0f3Smrg " src %s, \n" 181d514b0f3Smrg " mask %s, \n" 182d514b0f3Smrg " dst %s, \n" 183d514b0f3Smrg " screen %s\n", 184d514b0f3Smrg func, op_to_string (op), srcdesc, maskdesc, dstdesc, 185d514b0f3Smrg uxa_screen->swappedOut ? "swapped out" : "normal"); 186d514b0f3Smrg} 187d514b0f3Smrg 188d514b0f3SmrgBool uxa_op_reads_destination(CARD8 op) 189d514b0f3Smrg{ 190d514b0f3Smrg /* FALSE (does not read destination) is the list of ops in the protocol 191d514b0f3Smrg * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 192d514b0f3Smrg * That's just Clear and Src. ReduceCompositeOp() will already have 193d514b0f3Smrg * converted con/disjoint clear/src to Clear or Src. 194d514b0f3Smrg */ 195d514b0f3Smrg switch (op) { 196d514b0f3Smrg case PictOpClear: 197d514b0f3Smrg case PictOpSrc: 198d514b0f3Smrg return FALSE; 199d514b0f3Smrg default: 200d514b0f3Smrg return TRUE; 201d514b0f3Smrg } 202d514b0f3Smrg} 203d514b0f3Smrg 204d514b0f3Smrgstatic Bool 205d514b0f3Smrguxa_get_pixel_from_rgba(CARD32 * pixel, 206d514b0f3Smrg CARD16 red, 207d514b0f3Smrg CARD16 green, 208d514b0f3Smrg CARD16 blue, 209d514b0f3Smrg CARD16 alpha, 210d514b0f3Smrg CARD32 format) 211d514b0f3Smrg{ 212d514b0f3Smrg int rbits, bbits, gbits, abits; 213d514b0f3Smrg int rshift, bshift, gshift, ashift; 214d514b0f3Smrg 215d514b0f3Smrg rbits = PICT_FORMAT_R(format); 216d514b0f3Smrg gbits = PICT_FORMAT_G(format); 217d514b0f3Smrg bbits = PICT_FORMAT_B(format); 218d514b0f3Smrg abits = PICT_FORMAT_A(format); 219d514b0f3Smrg if (abits == 0) 220d514b0f3Smrg abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 221d514b0f3Smrg 222d514b0f3Smrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 223d514b0f3Smrg *pixel = alpha >> (16 - abits); 224d514b0f3Smrg return TRUE; 225d514b0f3Smrg } 226d514b0f3Smrg 227d514b0f3Smrg if (!PICT_FORMAT_COLOR(format)) 228d514b0f3Smrg return FALSE; 229d514b0f3Smrg 230d514b0f3Smrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 231d514b0f3Smrg bshift = 0; 232d514b0f3Smrg gshift = bbits; 233d514b0f3Smrg rshift = gshift + gbits; 234d514b0f3Smrg ashift = rshift + rbits; 235d514b0f3Smrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 236d514b0f3Smrg rshift = 0; 237d514b0f3Smrg gshift = rbits; 238d514b0f3Smrg bshift = gshift + gbits; 239d514b0f3Smrg ashift = bshift + bbits; 240d514b0f3Smrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 241d514b0f3Smrg ashift = 0; 242d514b0f3Smrg rshift = abits; 243d514b0f3Smrg gshift = rshift + rbits; 244d514b0f3Smrg bshift = gshift + gbits; 245d514b0f3Smrg } else { 246d514b0f3Smrg return FALSE; 247d514b0f3Smrg } 248d514b0f3Smrg 249d514b0f3Smrg *pixel = 0; 250d514b0f3Smrg *pixel |= (blue >> (16 - bbits)) << bshift; 251d514b0f3Smrg *pixel |= (green >> (16 - gbits)) << gshift; 252d514b0f3Smrg *pixel |= (red >> (16 - rbits)) << rshift; 253d514b0f3Smrg *pixel |= (alpha >> (16 - abits)) << ashift; 254d514b0f3Smrg 255d514b0f3Smrg return TRUE; 256d514b0f3Smrg} 257d514b0f3Smrg 258d514b0f3SmrgBool 259d514b0f3Smrguxa_get_rgba_from_pixel(CARD32 pixel, 260d514b0f3Smrg CARD16 * red, 261d514b0f3Smrg CARD16 * green, 262d514b0f3Smrg CARD16 * blue, 263d514b0f3Smrg CARD16 * alpha, 264d514b0f3Smrg CARD32 format) 265d514b0f3Smrg{ 266d514b0f3Smrg int rbits, bbits, gbits, abits; 267d514b0f3Smrg int rshift, bshift, gshift, ashift; 268d514b0f3Smrg 269d514b0f3Smrg rbits = PICT_FORMAT_R(format); 270d514b0f3Smrg gbits = PICT_FORMAT_G(format); 271d514b0f3Smrg bbits = PICT_FORMAT_B(format); 272d514b0f3Smrg abits = PICT_FORMAT_A(format); 273d514b0f3Smrg 274d514b0f3Smrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 275d514b0f3Smrg rshift = gshift = bshift = ashift = 0; 276d514b0f3Smrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 277d514b0f3Smrg bshift = 0; 278d514b0f3Smrg gshift = bbits; 279d514b0f3Smrg rshift = gshift + gbits; 280d514b0f3Smrg ashift = rshift + rbits; 281d514b0f3Smrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 282d514b0f3Smrg rshift = 0; 283d514b0f3Smrg gshift = rbits; 284d514b0f3Smrg bshift = gshift + gbits; 285d514b0f3Smrg ashift = bshift + bbits; 286d514b0f3Smrg } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 287d514b0f3Smrg ashift = 0; 288d514b0f3Smrg rshift = abits; 289d514b0f3Smrg if (abits == 0) 290d514b0f3Smrg rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 291d514b0f3Smrg gshift = rshift + rbits; 292d514b0f3Smrg bshift = gshift + gbits; 293d514b0f3Smrg } else { 294d514b0f3Smrg return FALSE; 295d514b0f3Smrg } 296d514b0f3Smrg 297d514b0f3Smrg if (rbits) { 298d514b0f3Smrg *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 299d514b0f3Smrg while (rbits < 16) { 300d514b0f3Smrg *red |= *red >> rbits; 301d514b0f3Smrg rbits <<= 1; 302d514b0f3Smrg } 303d514b0f3Smrg } else 304d514b0f3Smrg *red = 0; 305d514b0f3Smrg 306d514b0f3Smrg if (gbits) { 307d514b0f3Smrg *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 308d514b0f3Smrg while (gbits < 16) { 309d514b0f3Smrg *green |= *green >> gbits; 310d514b0f3Smrg gbits <<= 1; 311d514b0f3Smrg } 312d514b0f3Smrg } else 313d514b0f3Smrg *green = 0; 314d514b0f3Smrg 315d514b0f3Smrg if (bbits) { 316d514b0f3Smrg *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 317d514b0f3Smrg while (bbits < 16) { 318d514b0f3Smrg *blue |= *blue >> bbits; 319d514b0f3Smrg bbits <<= 1; 320d514b0f3Smrg } 321d514b0f3Smrg } else 322d514b0f3Smrg *blue = 0; 323d514b0f3Smrg 324d514b0f3Smrg if (abits) { 325d514b0f3Smrg *alpha = 326d514b0f3Smrg ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 327d514b0f3Smrg while (abits < 16) { 328d514b0f3Smrg *alpha |= *alpha >> abits; 329d514b0f3Smrg abits <<= 1; 330d514b0f3Smrg } 331d514b0f3Smrg } else 332d514b0f3Smrg *alpha = 0xffff; 333d514b0f3Smrg 334d514b0f3Smrg return TRUE; 335d514b0f3Smrg} 336d514b0f3Smrg 337d514b0f3SmrgBool 338d514b0f3Smrguxa_get_color_for_pixmap (PixmapPtr pixmap, 339d514b0f3Smrg CARD32 src_format, 340d514b0f3Smrg CARD32 dst_format, 341d514b0f3Smrg CARD32 *pixel) 342d514b0f3Smrg{ 343d514b0f3Smrg CARD16 red, green, blue, alpha; 344d514b0f3Smrg 345d514b0f3Smrg *pixel = uxa_get_pixmap_first_pixel(pixmap); 346d514b0f3Smrg 347d514b0f3Smrg if (src_format != dst_format) { 348d514b0f3Smrg if (!uxa_get_rgba_from_pixel(*pixel, 349d514b0f3Smrg &red, &green, &blue, &alpha, 350d514b0f3Smrg src_format)) 351d514b0f3Smrg return FALSE; 352d514b0f3Smrg 353d514b0f3Smrg if (!uxa_get_pixel_from_rgba(pixel, 354d514b0f3Smrg red, green, blue, alpha, 355d514b0f3Smrg dst_format)) 356d514b0f3Smrg return FALSE; 357d514b0f3Smrg } 358d514b0f3Smrg 359d514b0f3Smrg return TRUE; 360d514b0f3Smrg} 361d514b0f3Smrg 362d514b0f3Smrgstatic int 363d514b0f3Smrguxa_try_driver_solid_fill(PicturePtr pSrc, 364d514b0f3Smrg PicturePtr pDst, 365d514b0f3Smrg INT16 xSrc, 366d514b0f3Smrg INT16 ySrc, 367d514b0f3Smrg INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 368d514b0f3Smrg{ 369d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 370d514b0f3Smrg RegionRec region; 371d514b0f3Smrg BoxPtr pbox; 372d514b0f3Smrg int nbox; 373d514b0f3Smrg int dst_off_x, dst_off_y; 374d514b0f3Smrg PixmapPtr pSrcPix = NULL, pDstPix; 375d514b0f3Smrg CARD32 pixel; 376d514b0f3Smrg 377d514b0f3Smrg if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES)) 378d514b0f3Smrg return -1; 379d514b0f3Smrg 380d514b0f3Smrg pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); 381d514b0f3Smrg if (!pDstPix) 382d514b0f3Smrg return -1; 383d514b0f3Smrg 384d514b0f3Smrg xDst += pDst->pDrawable->x; 385d514b0f3Smrg yDst += pDst->pDrawable->y; 386d514b0f3Smrg 387d514b0f3Smrg if (pSrc->pDrawable) { 388d514b0f3Smrg pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); 389d514b0f3Smrg xSrc += pSrc->pDrawable->x; 390d514b0f3Smrg ySrc += pSrc->pDrawable->y; 391d514b0f3Smrg } 392d514b0f3Smrg 393d514b0f3Smrg if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst, 394d514b0f3Smrg xSrc, ySrc, 0, 0, xDst, yDst, 395d514b0f3Smrg width, height)) 396d514b0f3Smrg return 1; 397d514b0f3Smrg 398d514b0f3Smrg if (pSrcPix) { 399d514b0f3Smrg if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) { 400d514b0f3Smrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 401d514b0f3Smrg return -1; 402d514b0f3Smrg } 403d514b0f3Smrg } else { 404d514b0f3Smrg SourcePict *source = pSrc->pSourcePict; 405d514b0f3Smrg PictSolidFill *solid = &source->solidFill; 406d514b0f3Smrg 407d514b0f3Smrg if (source == NULL || source->type != SourcePictTypeSolidFill) { 408d514b0f3Smrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 409d514b0f3Smrg return -1; 410d514b0f3Smrg } 411d514b0f3Smrg 412d514b0f3Smrg if (pDst->format == PICT_a8r8g8b8) { 413d514b0f3Smrg pixel = solid->color; 414d514b0f3Smrg } else if (pDst->format == PICT_x8r8g8b8) { 415d514b0f3Smrg pixel = solid->color | 0xff000000; 416d514b0f3Smrg } else { 417d514b0f3Smrg CARD16 red, green, blue, alpha; 418d514b0f3Smrg 419d514b0f3Smrg if (!uxa_get_rgba_from_pixel(solid->color, 420d514b0f3Smrg &red, &green, &blue, &alpha, 421d514b0f3Smrg PIXMAN_a8r8g8b8) || 422d514b0f3Smrg !uxa_get_pixel_from_rgba(&pixel, 423d514b0f3Smrg red, green, blue, alpha, 424d514b0f3Smrg pDst->format)) { 425d514b0f3Smrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 426d514b0f3Smrg return -1; 427d514b0f3Smrg } 428d514b0f3Smrg } 429d514b0f3Smrg } 430d514b0f3Smrg 431d514b0f3Smrg if (!(*uxa_screen->info->prepare_solid) 432d514b0f3Smrg (pDstPix, GXcopy, FB_ALLONES, pixel)) { 433d514b0f3Smrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 434d514b0f3Smrg return -1; 435d514b0f3Smrg } 436d514b0f3Smrg 437d514b0f3Smrg REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); 438d514b0f3Smrg 439d514b0f3Smrg nbox = REGION_NUM_RECTS(®ion); 440d514b0f3Smrg pbox = REGION_RECTS(®ion); 441d514b0f3Smrg 442d514b0f3Smrg while (nbox--) { 443d514b0f3Smrg (*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1, 444d514b0f3Smrg pbox->x2, pbox->y2); 445d514b0f3Smrg pbox++; 446d514b0f3Smrg } 447d514b0f3Smrg 448d514b0f3Smrg (*uxa_screen->info->done_solid) (pDstPix); 449d514b0f3Smrg 450d514b0f3Smrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 451d514b0f3Smrg return 1; 452d514b0f3Smrg} 453d514b0f3Smrg 454d514b0f3Smrgstatic PicturePtr 455d514b0f3Smrguxa_picture_for_pixman_format(ScreenPtr pScreen, 456d514b0f3Smrg pixman_format_code_t format, 457d514b0f3Smrg int width, int height) 458d514b0f3Smrg{ 459d514b0f3Smrg PicturePtr pPicture; 460d514b0f3Smrg PixmapPtr pPixmap; 461d514b0f3Smrg int error; 462d514b0f3Smrg 463d514b0f3Smrg if (format == PIXMAN_a1) 464d514b0f3Smrg format = PIXMAN_a8; 465d514b0f3Smrg 466d514b0f3Smrg /* fill alpha if unset */ 467d514b0f3Smrg if (PIXMAN_FORMAT_A(format) == 0) 468d514b0f3Smrg format = PIXMAN_a8r8g8b8; 469d514b0f3Smrg 470d514b0f3Smrg pPixmap = (*pScreen->CreatePixmap)(pScreen, width, height, 471d514b0f3Smrg PIXMAN_FORMAT_DEPTH(format), 472d514b0f3Smrg UXA_CREATE_PIXMAP_FOR_MAP); 473d514b0f3Smrg if (!pPixmap) 474d514b0f3Smrg return 0; 475d514b0f3Smrg 476d514b0f3Smrg pPicture = CreatePicture(0, &pPixmap->drawable, 477d514b0f3Smrg PictureMatchFormat(pScreen, 478d514b0f3Smrg PIXMAN_FORMAT_DEPTH(format), 479d514b0f3Smrg format), 480d514b0f3Smrg 0, 0, serverClient, &error); 481d514b0f3Smrg (*pScreen->DestroyPixmap) (pPixmap); 482d514b0f3Smrg if (!pPicture) 483d514b0f3Smrg return 0; 484d514b0f3Smrg 485d514b0f3Smrg ValidatePicture(pPicture); 486d514b0f3Smrg 487d514b0f3Smrg return pPicture; 488d514b0f3Smrg} 489d514b0f3Smrg 490d514b0f3Smrgstatic PicturePtr 491d514b0f3Smrguxa_picture_from_pixman_image(ScreenPtr screen, 492d514b0f3Smrg pixman_image_t * image, 493d514b0f3Smrg pixman_format_code_t format) 494d514b0f3Smrg{ 495d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 496d514b0f3Smrg PicturePtr picture; 497d514b0f3Smrg PixmapPtr pixmap; 498d514b0f3Smrg int width, height; 499d514b0f3Smrg 500d514b0f3Smrg width = pixman_image_get_width(image); 501d514b0f3Smrg height = pixman_image_get_height(image); 502d514b0f3Smrg 503d514b0f3Smrg picture = uxa_picture_for_pixman_format(screen, format, 504d514b0f3Smrg width, height); 505d514b0f3Smrg if (!picture) 506d514b0f3Smrg return 0; 507d514b0f3Smrg 508d514b0f3Smrg if (uxa_screen->info->put_image && 509d514b0f3Smrg ((picture->pDrawable->depth << 24) | picture->format) == format && 510d514b0f3Smrg uxa_screen->info->put_image((PixmapPtr)picture->pDrawable, 511d514b0f3Smrg 0, 0, 512d514b0f3Smrg width, height, 513d514b0f3Smrg (char *)pixman_image_get_data(image), 514d514b0f3Smrg pixman_image_get_stride(image))) 515d514b0f3Smrg return picture; 516d514b0f3Smrg 517d514b0f3Smrg pixmap = GetScratchPixmapHeader(screen, width, height, 518d514b0f3Smrg PIXMAN_FORMAT_DEPTH(format), 519d514b0f3Smrg PIXMAN_FORMAT_BPP(format), 520d514b0f3Smrg pixman_image_get_stride(image), 521d514b0f3Smrg pixman_image_get_data(image)); 522d514b0f3Smrg if (!pixmap) { 523d514b0f3Smrg FreePicture(picture, 0); 524d514b0f3Smrg return 0; 525d514b0f3Smrg } 526d514b0f3Smrg 527d514b0f3Smrg if (((picture->pDrawable->depth << 24) | picture->format) == format) { 528d514b0f3Smrg GCPtr gc; 529d514b0f3Smrg 530d514b0f3Smrg gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen); 531d514b0f3Smrg if (!gc) { 532d514b0f3Smrg FreeScratchPixmapHeader(pixmap); 533d514b0f3Smrg FreePicture(picture, 0); 534d514b0f3Smrg return 0; 535d514b0f3Smrg } 536d514b0f3Smrg ValidateGC(picture->pDrawable, gc); 537d514b0f3Smrg 538d514b0f3Smrg (*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable, 539d514b0f3Smrg gc, 0, 0, width, height, 0, 0); 540d514b0f3Smrg 541d514b0f3Smrg FreeScratchGC(gc); 542d514b0f3Smrg } else { 543d514b0f3Smrg PicturePtr src; 544d514b0f3Smrg int error; 545d514b0f3Smrg 546d514b0f3Smrg src = CreatePicture(0, &pixmap->drawable, 547d514b0f3Smrg PictureMatchFormat(screen, 548d514b0f3Smrg PIXMAN_FORMAT_DEPTH(format), 549d514b0f3Smrg format), 550d514b0f3Smrg 0, 0, serverClient, &error); 551d514b0f3Smrg if (!src) { 552d514b0f3Smrg FreeScratchPixmapHeader(pixmap); 553d514b0f3Smrg FreePicture(picture, 0); 554d514b0f3Smrg return 0; 555d514b0f3Smrg } 556d514b0f3Smrg ValidatePicture(src); 557d514b0f3Smrg 558d514b0f3Smrg if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) { 559d514b0f3Smrg fbComposite(PictOpSrc, src, NULL, picture, 560d514b0f3Smrg 0, 0, 0, 0, 0, 0, width, height); 561d514b0f3Smrg uxa_finish_access(picture->pDrawable); 562d514b0f3Smrg } 563d514b0f3Smrg 564d514b0f3Smrg FreePicture(src, 0); 565d514b0f3Smrg } 566d514b0f3Smrg FreeScratchPixmapHeader(pixmap); 567d514b0f3Smrg 568d514b0f3Smrg return picture; 569d514b0f3Smrg} 570d514b0f3Smrg 571d514b0f3Smrgstatic PicturePtr 572d514b0f3Smrguxa_create_solid(ScreenPtr screen, uint32_t color) 573d514b0f3Smrg{ 574d514b0f3Smrg PixmapPtr pixmap; 575d514b0f3Smrg PicturePtr picture; 576d514b0f3Smrg XID repeat = RepeatNormal; 577d514b0f3Smrg int error = 0; 578d514b0f3Smrg 579d514b0f3Smrg pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32, 580d514b0f3Smrg UXA_CREATE_PIXMAP_FOR_MAP); 581d514b0f3Smrg if (!pixmap) 582d514b0f3Smrg return 0; 583d514b0f3Smrg 584d514b0f3Smrg if (!uxa_prepare_access((DrawablePtr)pixmap, NULL, UXA_ACCESS_RW)) { 585d514b0f3Smrg (*screen->DestroyPixmap)(pixmap); 586d514b0f3Smrg return 0; 587d514b0f3Smrg } 588d514b0f3Smrg *((uint32_t *)pixmap->devPrivate.ptr) = color; 589d514b0f3Smrg uxa_finish_access((DrawablePtr)pixmap); 590d514b0f3Smrg 591d514b0f3Smrg picture = CreatePicture(0, &pixmap->drawable, 592d514b0f3Smrg PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 593d514b0f3Smrg CPRepeat, &repeat, serverClient, &error); 594d514b0f3Smrg (*screen->DestroyPixmap)(pixmap); 595d514b0f3Smrg 596d514b0f3Smrg return picture; 597d514b0f3Smrg} 598d514b0f3Smrg 599d514b0f3Smrgstatic PicturePtr 600d514b0f3Smrguxa_solid_clear(ScreenPtr screen) 601d514b0f3Smrg{ 602d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 603d514b0f3Smrg PicturePtr picture; 604d514b0f3Smrg 605d514b0f3Smrg if (!uxa_screen->solid_clear) { 606d514b0f3Smrg uxa_screen->solid_clear = uxa_create_solid(screen, 0); 607d514b0f3Smrg if (!uxa_screen->solid_clear) 608d514b0f3Smrg return 0; 609d514b0f3Smrg } 610d514b0f3Smrg picture = uxa_screen->solid_clear; 611d514b0f3Smrg return picture; 612d514b0f3Smrg} 613d514b0f3Smrg 614d514b0f3SmrgPicturePtr 615d514b0f3Smrguxa_acquire_solid(ScreenPtr screen, SourcePict *source) 616d514b0f3Smrg{ 617d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 618d514b0f3Smrg PictSolidFill *solid = &source->solidFill; 619d514b0f3Smrg PicturePtr picture; 620d514b0f3Smrg int i; 621d514b0f3Smrg 622d514b0f3Smrg if ((solid->color >> 24) == 0) { 623d514b0f3Smrg picture = uxa_solid_clear(screen); 624d514b0f3Smrg if (!picture) 625d514b0f3Smrg return 0; 626d514b0f3Smrg 627d514b0f3Smrg goto DONE; 628d514b0f3Smrg } else if (solid->color == 0xff000000) { 629d514b0f3Smrg if (!uxa_screen->solid_black) { 630d514b0f3Smrg uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000); 631d514b0f3Smrg if (!uxa_screen->solid_black) 632d514b0f3Smrg return 0; 633d514b0f3Smrg } 634d514b0f3Smrg picture = uxa_screen->solid_black; 635d514b0f3Smrg goto DONE; 636d514b0f3Smrg } else if (solid->color == 0xffffffff) { 637d514b0f3Smrg if (!uxa_screen->solid_white) { 638d514b0f3Smrg uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff); 639d514b0f3Smrg if (!uxa_screen->solid_white) 640d514b0f3Smrg return 0; 641d514b0f3Smrg } 642d514b0f3Smrg picture = uxa_screen->solid_white; 643d514b0f3Smrg goto DONE; 644d514b0f3Smrg } 645d514b0f3Smrg 646d514b0f3Smrg for (i = 0; i < uxa_screen->solid_cache_size; i++) { 647d514b0f3Smrg if (uxa_screen->solid_cache[i].color == solid->color) { 648d514b0f3Smrg picture = uxa_screen->solid_cache[i].picture; 649d514b0f3Smrg goto DONE; 650d514b0f3Smrg } 651d514b0f3Smrg } 652d514b0f3Smrg 653d514b0f3Smrg picture = uxa_create_solid(screen, solid->color); 654d514b0f3Smrg if (!picture) 655d514b0f3Smrg return 0; 656d514b0f3Smrg 657d514b0f3Smrg if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) { 658d514b0f3Smrg i = rand() % UXA_NUM_SOLID_CACHE; 659d514b0f3Smrg FreePicture(uxa_screen->solid_cache[i].picture, 0); 660d514b0f3Smrg } else 661d514b0f3Smrg uxa_screen->solid_cache_size++; 662d514b0f3Smrg 663d514b0f3Smrg uxa_screen->solid_cache[i].picture = picture; 664d514b0f3Smrg uxa_screen->solid_cache[i].color = solid->color; 665d514b0f3Smrg 666d514b0f3SmrgDONE: 667d514b0f3Smrg picture->refcnt++; 668d514b0f3Smrg return picture; 669d514b0f3Smrg} 670d514b0f3Smrg 671d514b0f3SmrgPicturePtr 672d514b0f3Smrguxa_acquire_pattern(ScreenPtr pScreen, 673d514b0f3Smrg PicturePtr pSrc, 674d514b0f3Smrg pixman_format_code_t format, 675d514b0f3Smrg INT16 x, INT16 y, CARD16 width, CARD16 height) 676d514b0f3Smrg{ 677d514b0f3Smrg PicturePtr pDst; 678d514b0f3Smrg 679d514b0f3Smrg if (pSrc->pSourcePict) { 680d514b0f3Smrg SourcePict *source = pSrc->pSourcePict; 681d514b0f3Smrg if (source->type == SourcePictTypeSolidFill) 682d514b0f3Smrg return uxa_acquire_solid (pScreen, source); 683d514b0f3Smrg } 684d514b0f3Smrg 685d514b0f3Smrg pDst = uxa_picture_for_pixman_format(pScreen, format, width, height); 686d514b0f3Smrg if (!pDst) 687d514b0f3Smrg return 0; 688d514b0f3Smrg 689d514b0f3Smrg if (uxa_prepare_access(pDst->pDrawable, NULL, UXA_ACCESS_RW)) { 690d514b0f3Smrg fbComposite(PictOpSrc, pSrc, NULL, pDst, 691d514b0f3Smrg x, y, 0, 0, 0, 0, width, height); 692d514b0f3Smrg uxa_finish_access(pDst->pDrawable); 693d514b0f3Smrg return pDst; 694d514b0f3Smrg } else { 695d514b0f3Smrg FreePicture(pDst, 0); 696d514b0f3Smrg return 0; 697d514b0f3Smrg } 698d514b0f3Smrg} 699d514b0f3Smrg 700d514b0f3Smrgstatic Bool 701d514b0f3Smrgtransform_is_integer_translation(PictTransformPtr t, int *tx, int *ty) 702d514b0f3Smrg{ 703d514b0f3Smrg if (t == NULL) { 704d514b0f3Smrg *tx = *ty = 0; 705d514b0f3Smrg return TRUE; 706d514b0f3Smrg } 707d514b0f3Smrg 708d514b0f3Smrg if (t->matrix[0][0] != IntToxFixed(1) || 709d514b0f3Smrg t->matrix[0][1] != 0 || 710d514b0f3Smrg t->matrix[1][0] != 0 || 711d514b0f3Smrg t->matrix[1][1] != IntToxFixed(1) || 712d514b0f3Smrg t->matrix[2][0] != 0 || 713d514b0f3Smrg t->matrix[2][1] != 0 || 714d514b0f3Smrg t->matrix[2][2] != IntToxFixed(1)) 715d514b0f3Smrg return FALSE; 716d514b0f3Smrg 717d514b0f3Smrg if (xFixedFrac(t->matrix[0][2]) != 0 || 718d514b0f3Smrg xFixedFrac(t->matrix[1][2]) != 0) 719d514b0f3Smrg return FALSE; 720d514b0f3Smrg 721d514b0f3Smrg *tx = xFixedToInt(t->matrix[0][2]); 722d514b0f3Smrg *ty = xFixedToInt(t->matrix[1][2]); 723d514b0f3Smrg return TRUE; 724d514b0f3Smrg} 725d514b0f3Smrg 726d514b0f3Smrgstatic PicturePtr 727d514b0f3Smrguxa_render_picture(ScreenPtr screen, 728d514b0f3Smrg PicturePtr src, 729d514b0f3Smrg pixman_format_code_t format, 730d514b0f3Smrg INT16 x, INT16 y, 731d514b0f3Smrg CARD16 width, CARD16 height) 732d514b0f3Smrg{ 733d514b0f3Smrg PicturePtr picture; 734d514b0f3Smrg int ret = 0; 735d514b0f3Smrg 736d514b0f3Smrg /* XXX we need a mechanism for the card to choose the fallback format */ 737d514b0f3Smrg 738d514b0f3Smrg /* force alpha channel in case source does not entirely cover the extents */ 739d514b0f3Smrg if (PIXMAN_FORMAT_A(format) == 0) 740d514b0f3Smrg format = PIXMAN_a8r8g8b8; /* available on all hardware */ 741d514b0f3Smrg 742d514b0f3Smrg picture = uxa_picture_for_pixman_format(screen, format, width, height); 743d514b0f3Smrg if (!picture) 744d514b0f3Smrg return 0; 745d514b0f3Smrg 746d514b0f3Smrg if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) { 747d514b0f3Smrg if (uxa_prepare_access(src->pDrawable, NULL, UXA_ACCESS_RO)) { 748d514b0f3Smrg ret = 1; 749d514b0f3Smrg fbComposite(PictOpSrc, src, NULL, picture, 750d514b0f3Smrg x, y, 0, 0, 0, 0, width, height); 751d514b0f3Smrg uxa_finish_access(src->pDrawable); 752d514b0f3Smrg } 753d514b0f3Smrg uxa_finish_access(picture->pDrawable); 754d514b0f3Smrg } 755d514b0f3Smrg 756d514b0f3Smrg if (!ret) { 757d514b0f3Smrg FreePicture(picture, 0); 758d514b0f3Smrg return 0; 759d514b0f3Smrg } 760d514b0f3Smrg 761d514b0f3Smrg return picture; 762d514b0f3Smrg} 763d514b0f3Smrg 764d514b0f3SmrgPicturePtr 765d514b0f3Smrguxa_acquire_drawable(ScreenPtr pScreen, 766d514b0f3Smrg PicturePtr pSrc, 767d514b0f3Smrg INT16 x, INT16 y, 768d514b0f3Smrg CARD16 width, CARD16 height, 769d514b0f3Smrg INT16 * out_x, INT16 * out_y) 770d514b0f3Smrg{ 771d514b0f3Smrg PixmapPtr pPixmap; 772d514b0f3Smrg PicturePtr pDst; 773d514b0f3Smrg GCPtr pGC; 774d514b0f3Smrg int depth, error; 775d514b0f3Smrg int tx, ty; 776d514b0f3Smrg 777d514b0f3Smrg depth = pSrc->pDrawable->depth; 778d514b0f3Smrg if (depth == 1 || 779d514b0f3Smrg pSrc->filter == PictFilterConvolution || /* XXX */ 780d514b0f3Smrg !transform_is_integer_translation(pSrc->transform, &tx, &ty)) { 781d514b0f3Smrg /* XXX extract the sample extents and do the transformation on the GPU */ 782d514b0f3Smrg pDst = uxa_render_picture(pScreen, pSrc, 783d514b0f3Smrg pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24), 784d514b0f3Smrg x, y, width, height); 785d514b0f3Smrg 786d514b0f3Smrg goto done; 787d514b0f3Smrg } else { 788d514b0f3Smrg if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->depth) { 789d514b0f3Smrg *out_x = x + pSrc->pDrawable->x; 790d514b0f3Smrg *out_y = y + pSrc->pDrawable->y; 791d514b0f3Smrg return pSrc; 792d514b0f3Smrg } 793d514b0f3Smrg } 794d514b0f3Smrg 795d514b0f3Smrg pPixmap = pScreen->CreatePixmap(pScreen, 796d514b0f3Smrg width, height, depth, 797d514b0f3Smrg CREATE_PIXMAP_USAGE_SCRATCH); 798d514b0f3Smrg if (!pPixmap) 799d514b0f3Smrg return 0; 800d514b0f3Smrg 801d514b0f3Smrg /* Skip the copy if the result remains in memory and not a bo */ 802d514b0f3Smrg if (!uxa_drawable_is_offscreen(&pPixmap->drawable)) { 803d514b0f3Smrg pScreen->DestroyPixmap(pPixmap); 804d514b0f3Smrg return 0; 805d514b0f3Smrg } 806d514b0f3Smrg 807d514b0f3Smrg pGC = GetScratchGC(depth, pScreen); 808d514b0f3Smrg if (!pGC) { 809d514b0f3Smrg pScreen->DestroyPixmap(pPixmap); 810d514b0f3Smrg return 0; 811d514b0f3Smrg } 812d514b0f3Smrg 813d514b0f3Smrg ValidateGC(&pPixmap->drawable, pGC); 814d514b0f3Smrg pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC, 815d514b0f3Smrg x + tx, y + ty, width, height, 0, 0); 816d514b0f3Smrg FreeScratchGC(pGC); 817d514b0f3Smrg 818d514b0f3Smrg pDst = CreatePicture(0, &pPixmap->drawable, 819d514b0f3Smrg PictureMatchFormat(pScreen, depth, pSrc->format), 820d514b0f3Smrg 0, 0, serverClient, &error); 821d514b0f3Smrg pScreen->DestroyPixmap(pPixmap); 822d514b0f3Smrg ValidatePicture(pDst); 823d514b0f3Smrg 824d514b0f3Smrgdone: 825d514b0f3Smrg pDst->componentAlpha = pSrc->componentAlpha; 826d514b0f3Smrg *out_x = x; 827d514b0f3Smrg *out_y = y; 828d514b0f3Smrg return pDst; 829d514b0f3Smrg} 830d514b0f3Smrg 831d514b0f3Smrgstatic PicturePtr 832d514b0f3Smrguxa_acquire_picture(ScreenPtr screen, 833d514b0f3Smrg PicturePtr src, 834d514b0f3Smrg pixman_format_code_t format, 835d514b0f3Smrg INT16 x, INT16 y, 836d514b0f3Smrg CARD16 width, CARD16 height, 837d514b0f3Smrg INT16 * out_x, INT16 * out_y) 838d514b0f3Smrg{ 839d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 840d514b0f3Smrg 841d514b0f3Smrg if (uxa_screen->info->check_composite_texture && 842d514b0f3Smrg uxa_screen->info->check_composite_texture(screen, src)) { 843d514b0f3Smrg if (src->pDrawable) { 844d514b0f3Smrg *out_x = x + src->pDrawable->x; 845d514b0f3Smrg *out_y = y + src->pDrawable->y; 846d514b0f3Smrg } else { 847d514b0f3Smrg *out_x = 0; 848d514b0f3Smrg *out_y = 0; 849d514b0f3Smrg } 850d514b0f3Smrg return src; 851d514b0f3Smrg } 852d514b0f3Smrg 853d514b0f3Smrg if (src->pDrawable) { 854d514b0f3Smrg PicturePtr dst; 855d514b0f3Smrg 856d514b0f3Smrg dst = uxa_acquire_drawable(screen, src, 857d514b0f3Smrg x, y, width, height, 858d514b0f3Smrg out_x, out_y); 859d514b0f3Smrg if (uxa_screen->info->check_composite_texture && 860d514b0f3Smrg !uxa_screen->info->check_composite_texture(screen, dst)) { 861d514b0f3Smrg if (dst != src) 862d514b0f3Smrg FreePicture(dst, 0); 863d514b0f3Smrg return 0; 864d514b0f3Smrg } 865d514b0f3Smrg 866d514b0f3Smrg return dst; 867d514b0f3Smrg } 868d514b0f3Smrg 869d514b0f3Smrg *out_x = 0; 870d514b0f3Smrg *out_y = 0; 871d514b0f3Smrg return uxa_acquire_pattern(screen, src, 872d514b0f3Smrg format, x, y, width, height); 873d514b0f3Smrg} 874d514b0f3Smrg 875d514b0f3Smrgstatic PicturePtr 876d514b0f3Smrguxa_acquire_source(ScreenPtr screen, 877d514b0f3Smrg PicturePtr pict, 878d514b0f3Smrg INT16 x, INT16 y, 879d514b0f3Smrg CARD16 width, CARD16 height, 880d514b0f3Smrg INT16 * out_x, INT16 * out_y) 881d514b0f3Smrg{ 882d514b0f3Smrg return uxa_acquire_picture (screen, pict, 883d514b0f3Smrg PIXMAN_a8r8g8b8, 884d514b0f3Smrg x, y, 885d514b0f3Smrg width, height, 886d514b0f3Smrg out_x, out_y); 887d514b0f3Smrg} 888d514b0f3Smrg 889d514b0f3Smrgstatic PicturePtr 890d514b0f3Smrguxa_acquire_mask(ScreenPtr screen, 891d514b0f3Smrg PicturePtr pict, 892d514b0f3Smrg INT16 x, INT16 y, 893d514b0f3Smrg INT16 width, INT16 height, 894d514b0f3Smrg INT16 * out_x, INT16 * out_y) 895d514b0f3Smrg{ 896d514b0f3Smrg return uxa_acquire_picture (screen, pict, 897d514b0f3Smrg PIXMAN_a8, 898d514b0f3Smrg x, y, 899d514b0f3Smrg width, height, 900d514b0f3Smrg out_x, out_y); 901d514b0f3Smrg} 902d514b0f3Smrg 903d514b0f3Smrgstatic Bool 904d514b0f3Smrg_pixman_region_init_rectangles(pixman_region16_t *region, 905d514b0f3Smrg int num_rects, 906d514b0f3Smrg xRectangle *rects, 907d514b0f3Smrg int tx, int ty) 908d514b0f3Smrg{ 909d514b0f3Smrg pixman_box16_t stack_boxes[64], *boxes = stack_boxes; 910d514b0f3Smrg pixman_bool_t ret; 911d514b0f3Smrg int i; 912d514b0f3Smrg 913d514b0f3Smrg if (num_rects > sizeof(stack_boxes) / sizeof(stack_boxes[0])) { 914d514b0f3Smrg boxes = malloc(sizeof(pixman_box16_t) * num_rects); 915d514b0f3Smrg if (boxes == NULL) 916d514b0f3Smrg return FALSE; 917d514b0f3Smrg } 918d514b0f3Smrg 919d514b0f3Smrg for (i = 0; i < num_rects; i++) { 920d514b0f3Smrg boxes[i].x1 = rects[i].x + tx; 921d514b0f3Smrg boxes[i].y1 = rects[i].y + ty; 922d514b0f3Smrg boxes[i].x2 = rects[i].x + tx + rects[i].width; 923d514b0f3Smrg boxes[i].y2 = rects[i].y + ty + rects[i].height; 924d514b0f3Smrg } 925d514b0f3Smrg 926d514b0f3Smrg ret = pixman_region_init_rects(region, boxes, num_rects); 927d514b0f3Smrg 928d514b0f3Smrg if (boxes != stack_boxes) 929d514b0f3Smrg free(boxes); 930d514b0f3Smrg 931d514b0f3Smrg return ret; 932d514b0f3Smrg} 933d514b0f3Smrg 934d514b0f3Smrgvoid 935d514b0f3Smrguxa_solid_rects (CARD8 op, 936d514b0f3Smrg PicturePtr dst, 937d514b0f3Smrg xRenderColor *color, 938d514b0f3Smrg int num_rects, 939d514b0f3Smrg xRectangle *rects) 940d514b0f3Smrg{ 941d514b0f3Smrg ScreenPtr screen = dst->pDrawable->pScreen; 942d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 943d514b0f3Smrg PixmapPtr dst_pixmap, src_pixmap = NULL; 944d514b0f3Smrg pixman_region16_t region; 945d514b0f3Smrg pixman_box16_t *boxes, *extents; 946d514b0f3Smrg PicturePtr src; 947d514b0f3Smrg int dst_x, dst_y; 948d514b0f3Smrg int num_boxes; 949d514b0f3Smrg 950d514b0f3Smrg if (!pixman_region_not_empty(dst->pCompositeClip)) 951d514b0f3Smrg return; 952d514b0f3Smrg 953d514b0f3Smrg if (dst->alphaMap) 954d514b0f3Smrg goto fallback; 955d514b0f3Smrg 956d514b0f3Smrg dst_pixmap = uxa_get_offscreen_pixmap(dst->pDrawable, &dst_x, &dst_y); 957d514b0f3Smrg if (!dst_pixmap) 958d514b0f3Smrg goto fallback; 959d514b0f3Smrg 960d514b0f3Smrg if (!_pixman_region_init_rectangles(®ion, 961d514b0f3Smrg num_rects, rects, 962d514b0f3Smrg dst->pDrawable->x, dst->pDrawable->y)) 963d514b0f3Smrg goto fallback; 964d514b0f3Smrg 965d514b0f3Smrg if (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip)) { 966d514b0f3Smrg pixman_region_fini(®ion); 967d514b0f3Smrg return; 968d514b0f3Smrg } 969d514b0f3Smrg 970d514b0f3Smrg /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must 971d514b0f3Smrg * manually append the damaged regions ourselves. 972d514b0f3Smrg */ 973d514b0f3Smrg DamageRegionAppend(dst->pDrawable, ®ion); 974d514b0f3Smrg 975d514b0f3Smrg pixman_region_translate(®ion, dst_x, dst_y); 976d514b0f3Smrg boxes = pixman_region_rectangles(®ion, &num_boxes); 977d514b0f3Smrg extents = pixman_region_extents (®ion); 978d514b0f3Smrg 979d514b0f3Smrg if (op == PictOpClear) 980d514b0f3Smrg color->red = color->green = color->blue = color->alpha = 0; 981d514b0f3Smrg if (color->alpha >= 0xff00 && op == PictOpOver) { 982d514b0f3Smrg color->alpha = 0xffff; 983d514b0f3Smrg op = PictOpSrc; 984d514b0f3Smrg } 985d514b0f3Smrg 986d514b0f3Smrg /* Using GEM, the relocation costs outweigh the advantages of the blitter */ 987d514b0f3Smrg if (num_boxes == 1 && (op == PictOpSrc || op == PictOpClear)) { 988d514b0f3Smrg CARD32 pixel; 989d514b0f3Smrg 990d514b0f3Smrgtry_solid: 991d514b0f3Smrg if (uxa_screen->info->check_solid && 992d514b0f3Smrg !uxa_screen->info->check_solid(&dst_pixmap->drawable, GXcopy, FB_ALLONES)) 993d514b0f3Smrg goto err_region; 994d514b0f3Smrg 995d514b0f3Smrg if (!uxa_get_pixel_from_rgba(&pixel, 996d514b0f3Smrg color->red, 997d514b0f3Smrg color->green, 998d514b0f3Smrg color->blue, 999d514b0f3Smrg color->alpha, 1000d514b0f3Smrg dst->format)) 1001d514b0f3Smrg goto err_region; 1002d514b0f3Smrg 1003d514b0f3Smrg if (!uxa_screen->info->prepare_solid(dst_pixmap, GXcopy, FB_ALLONES, pixel)) 1004d514b0f3Smrg goto err_region; 1005d514b0f3Smrg 1006d514b0f3Smrg while (num_boxes--) { 1007d514b0f3Smrg uxa_screen->info->solid(dst_pixmap, 1008d514b0f3Smrg boxes->x1, boxes->y1, 1009d514b0f3Smrg boxes->x2, boxes->y2); 1010d514b0f3Smrg boxes++; 1011d514b0f3Smrg } 1012d514b0f3Smrg 1013d514b0f3Smrg uxa_screen->info->done_solid(dst_pixmap); 1014d514b0f3Smrg } else { 1015d514b0f3Smrg int error; 1016d514b0f3Smrg 1017d514b0f3Smrg src = CreateSolidPicture(0, color, &error); 1018d514b0f3Smrg if (!src) 1019d514b0f3Smrg goto err_region; 1020d514b0f3Smrg 1021d514b0f3Smrg if (!uxa_screen->info->check_composite(op, src, NULL, dst, 1022d514b0f3Smrg extents->x2 - extents->x1, 1023d514b0f3Smrg extents->y2 - extents->y1)) { 1024d514b0f3Smrg if (op == PictOpSrc || op == PictOpClear) { 1025d514b0f3Smrg FreePicture(src, 0); 1026d514b0f3Smrg goto try_solid; 1027d514b0f3Smrg } 1028d514b0f3Smrg 1029d514b0f3Smrg goto err_src; 1030d514b0f3Smrg } 1031d514b0f3Smrg 1032d514b0f3Smrg if (!uxa_screen->info->check_composite_texture || 1033d514b0f3Smrg !uxa_screen->info->check_composite_texture(screen, src)) { 1034d514b0f3Smrg PicturePtr solid; 1035d514b0f3Smrg int src_off_x, src_off_y; 1036d514b0f3Smrg 1037d514b0f3Smrg solid = uxa_acquire_solid(screen, src->pSourcePict); 1038d514b0f3Smrg FreePicture(src, 0); 1039d514b0f3Smrg 1040d514b0f3Smrg src = solid; 1041d514b0f3Smrg src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable, 1042d514b0f3Smrg &src_off_x, &src_off_y); 1043d514b0f3Smrg if (!src_pixmap) 1044d514b0f3Smrg goto err_src; 1045d514b0f3Smrg } 1046d514b0f3Smrg 1047d514b0f3Smrg if (!uxa_screen->info->prepare_composite(op, src, NULL, dst, src_pixmap, NULL, dst_pixmap)) 1048d514b0f3Smrg goto err_src; 1049d514b0f3Smrg 1050d514b0f3Smrg while (num_boxes--) { 1051d514b0f3Smrg uxa_screen->info->composite(dst_pixmap, 1052d514b0f3Smrg 0, 0, 0, 0, 1053d514b0f3Smrg boxes->x1, 1054d514b0f3Smrg boxes->y1, 1055d514b0f3Smrg boxes->x2 - boxes->x1, 1056d514b0f3Smrg boxes->y2 - boxes->y1); 1057d514b0f3Smrg boxes++; 1058d514b0f3Smrg } 1059d514b0f3Smrg 1060d514b0f3Smrg uxa_screen->info->done_composite(dst_pixmap); 1061d514b0f3Smrg FreePicture(src, 0); 1062d514b0f3Smrg } 1063d514b0f3Smrg 1064d514b0f3Smrg pixman_region_fini(®ion); 1065d514b0f3Smrg return; 1066d514b0f3Smrg 1067d514b0f3Smrgerr_src: 1068d514b0f3Smrg FreePicture(src, 0); 1069d514b0f3Smrgerr_region: 1070d514b0f3Smrg pixman_region_fini(®ion); 1071d514b0f3Smrgfallback: 1072d514b0f3Smrg uxa_screen->SavedCompositeRects(op, dst, color, num_rects, rects); 1073d514b0f3Smrg} 1074d514b0f3Smrg 1075d514b0f3Smrgstatic int 1076d514b0f3Smrguxa_try_driver_composite(CARD8 op, 1077d514b0f3Smrg PicturePtr pSrc, 1078d514b0f3Smrg PicturePtr pMask, 1079d514b0f3Smrg PicturePtr pDst, 1080d514b0f3Smrg INT16 xSrc, INT16 ySrc, 1081d514b0f3Smrg INT16 xMask, INT16 yMask, 1082d514b0f3Smrg INT16 xDst, INT16 yDst, 1083d514b0f3Smrg CARD16 width, CARD16 height) 1084d514b0f3Smrg{ 1085d514b0f3Smrg ScreenPtr screen = pDst->pDrawable->pScreen; 1086d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1087d514b0f3Smrg RegionRec region; 1088d514b0f3Smrg BoxPtr pbox; 1089d514b0f3Smrg int nbox; 1090d514b0f3Smrg int xDst_copy = 0, yDst_copy = 0; 1091d514b0f3Smrg int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 1092d514b0f3Smrg PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; 1093d514b0f3Smrg PicturePtr localSrc, localMask = NULL; 1094d514b0f3Smrg PicturePtr localDst = pDst; 1095d514b0f3Smrg 1096d514b0f3Smrg if (uxa_screen->info->check_composite && 1097d514b0f3Smrg !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height)) 1098d514b0f3Smrg return -1; 1099d514b0f3Smrg 1100d514b0f3Smrg if (uxa_screen->info->check_composite_target && 1101d514b0f3Smrg !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 1102d514b0f3Smrg int depth = pDst->pDrawable->depth; 1103d514b0f3Smrg PixmapPtr pixmap; 1104d514b0f3Smrg int error; 1105d514b0f3Smrg GCPtr gc; 1106d514b0f3Smrg 1107d514b0f3Smrg pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 1108d514b0f3Smrg if (uxa_screen->info->check_copy && 1109d514b0f3Smrg !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 1110d514b0f3Smrg return -1; 1111d514b0f3Smrg 1112d514b0f3Smrg pixmap = screen->CreatePixmap(screen, 1113d514b0f3Smrg width, height, depth, 1114d514b0f3Smrg CREATE_PIXMAP_USAGE_SCRATCH); 1115d514b0f3Smrg if (!pixmap) 1116d514b0f3Smrg return 0; 1117d514b0f3Smrg 1118d514b0f3Smrg gc = GetScratchGC(depth, screen); 1119d514b0f3Smrg if (!gc) { 1120d514b0f3Smrg screen->DestroyPixmap(pixmap); 1121d514b0f3Smrg return 0; 1122d514b0f3Smrg } 1123d514b0f3Smrg 1124d514b0f3Smrg ValidateGC(&pixmap->drawable, gc); 1125d514b0f3Smrg gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 1126d514b0f3Smrg xDst, yDst, width, height, 0, 0); 1127d514b0f3Smrg FreeScratchGC(gc); 1128d514b0f3Smrg 1129d514b0f3Smrg xDst_copy = xDst; xDst = 0; 1130d514b0f3Smrg yDst_copy = yDst; yDst = 0; 1131d514b0f3Smrg 1132d514b0f3Smrg localDst = CreatePicture(0, &pixmap->drawable, 1133d514b0f3Smrg PictureMatchFormat(screen, depth, pDst->format), 1134d514b0f3Smrg 0, 0, serverClient, &error); 1135d514b0f3Smrg screen->DestroyPixmap(pixmap); 1136d514b0f3Smrg 1137d514b0f3Smrg if (!localDst) 1138d514b0f3Smrg return 0; 1139d514b0f3Smrg 1140d514b0f3Smrg ValidatePicture(localDst); 1141d514b0f3Smrg } 1142d514b0f3Smrg 1143d514b0f3Smrg pDstPix = 1144d514b0f3Smrg uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y); 1145d514b0f3Smrg if (!pDstPix) { 1146d514b0f3Smrg if (localDst != pDst) 1147d514b0f3Smrg FreePicture(localDst, 0); 1148d514b0f3Smrg return -1; 1149d514b0f3Smrg } 1150d514b0f3Smrg 1151d514b0f3Smrg xDst += localDst->pDrawable->x; 1152d514b0f3Smrg yDst += localDst->pDrawable->y; 1153d514b0f3Smrg 1154d514b0f3Smrg localSrc = uxa_acquire_source(screen, pSrc, 1155d514b0f3Smrg xSrc, ySrc, 1156d514b0f3Smrg width, height, 1157d514b0f3Smrg &xSrc, &ySrc); 1158d514b0f3Smrg if (!localSrc) { 1159d514b0f3Smrg if (localDst != pDst) 1160d514b0f3Smrg FreePicture(localDst, 0); 1161d514b0f3Smrg return 0; 1162d514b0f3Smrg } 1163d514b0f3Smrg 1164d514b0f3Smrg if (pMask) { 1165d514b0f3Smrg localMask = uxa_acquire_mask(screen, pMask, 1166d514b0f3Smrg xMask, yMask, 1167d514b0f3Smrg width, height, 1168d514b0f3Smrg &xMask, &yMask); 1169d514b0f3Smrg if (!localMask) { 1170d514b0f3Smrg if (localSrc != pSrc) 1171d514b0f3Smrg FreePicture(localSrc, 0); 1172d514b0f3Smrg if (localDst != pDst) 1173d514b0f3Smrg FreePicture(localDst, 0); 1174d514b0f3Smrg 1175d514b0f3Smrg return 0; 1176d514b0f3Smrg } 1177d514b0f3Smrg } 1178d514b0f3Smrg 1179d514b0f3Smrg if (!miComputeCompositeRegion(®ion, localSrc, localMask, localDst, 1180d514b0f3Smrg xSrc, ySrc, xMask, yMask, xDst, yDst, 1181d514b0f3Smrg width, height)) { 1182d514b0f3Smrg if (localSrc != pSrc) 1183d514b0f3Smrg FreePicture(localSrc, 0); 1184d514b0f3Smrg if (localMask && localMask != pMask) 1185d514b0f3Smrg FreePicture(localMask, 0); 1186d514b0f3Smrg if (localDst != pDst) 1187d514b0f3Smrg FreePicture(localDst, 0); 1188d514b0f3Smrg 1189d514b0f3Smrg return 1; 1190d514b0f3Smrg } 1191d514b0f3Smrg 1192d514b0f3Smrg if (localSrc->pDrawable) { 1193d514b0f3Smrg pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, 1194d514b0f3Smrg &src_off_x, &src_off_y); 1195d514b0f3Smrg if (!pSrcPix) { 1196d514b0f3Smrg REGION_UNINIT(screen, ®ion); 1197d514b0f3Smrg 1198d514b0f3Smrg if (localSrc != pSrc) 1199d514b0f3Smrg FreePicture(localSrc, 0); 1200d514b0f3Smrg if (localMask && localMask != pMask) 1201d514b0f3Smrg FreePicture(localMask, 0); 1202d514b0f3Smrg if (localDst != pDst) 1203d514b0f3Smrg FreePicture(localDst, 0); 1204d514b0f3Smrg 1205d514b0f3Smrg return 0; 1206d514b0f3Smrg } 1207d514b0f3Smrg } else { 1208d514b0f3Smrg pSrcPix = NULL; 1209d514b0f3Smrg } 1210d514b0f3Smrg 1211d514b0f3Smrg if (localMask) { 1212d514b0f3Smrg if (localMask->pDrawable) { 1213d514b0f3Smrg pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, 1214d514b0f3Smrg &mask_off_x, &mask_off_y); 1215d514b0f3Smrg if (!pMaskPix) { 1216d514b0f3Smrg REGION_UNINIT(screen, ®ion); 1217d514b0f3Smrg 1218d514b0f3Smrg if (localSrc != pSrc) 1219d514b0f3Smrg FreePicture(localSrc, 0); 1220d514b0f3Smrg if (localMask && localMask != pMask) 1221d514b0f3Smrg FreePicture(localMask, 0); 1222d514b0f3Smrg if (localDst != pDst) 1223d514b0f3Smrg FreePicture(localDst, 0); 1224d514b0f3Smrg 1225d514b0f3Smrg return 0; 1226d514b0f3Smrg } 1227d514b0f3Smrg } else { 1228d514b0f3Smrg pMaskPix = NULL; 1229d514b0f3Smrg } 1230d514b0f3Smrg } 1231d514b0f3Smrg 1232d514b0f3Smrg if (!(*uxa_screen->info->prepare_composite) 1233d514b0f3Smrg (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) { 1234d514b0f3Smrg REGION_UNINIT(screen, ®ion); 1235d514b0f3Smrg 1236d514b0f3Smrg if (localSrc != pSrc) 1237d514b0f3Smrg FreePicture(localSrc, 0); 1238d514b0f3Smrg if (localMask && localMask != pMask) 1239d514b0f3Smrg FreePicture(localMask, 0); 1240d514b0f3Smrg if (localDst != pDst) 1241d514b0f3Smrg FreePicture(localDst, 0); 1242d514b0f3Smrg 1243d514b0f3Smrg return -1; 1244d514b0f3Smrg } 1245d514b0f3Smrg 1246d514b0f3Smrg if (pMask) { 1247d514b0f3Smrg xMask = xMask + mask_off_x - xDst; 1248d514b0f3Smrg yMask = yMask + mask_off_y - yDst; 1249d514b0f3Smrg } 1250d514b0f3Smrg 1251d514b0f3Smrg xSrc = xSrc + src_off_x - xDst; 1252d514b0f3Smrg ySrc = ySrc + src_off_y - yDst; 1253d514b0f3Smrg 1254d514b0f3Smrg nbox = REGION_NUM_RECTS(®ion); 1255d514b0f3Smrg pbox = REGION_RECTS(®ion); 1256d514b0f3Smrg while (nbox--) { 1257d514b0f3Smrg (*uxa_screen->info->composite) (pDstPix, 1258d514b0f3Smrg pbox->x1 + xSrc, 1259d514b0f3Smrg pbox->y1 + ySrc, 1260d514b0f3Smrg pbox->x1 + xMask, 1261d514b0f3Smrg pbox->y1 + yMask, 1262d514b0f3Smrg pbox->x1 + dst_off_x, 1263d514b0f3Smrg pbox->y1 + dst_off_y, 1264d514b0f3Smrg pbox->x2 - pbox->x1, 1265d514b0f3Smrg pbox->y2 - pbox->y1); 1266d514b0f3Smrg pbox++; 1267d514b0f3Smrg } 1268d514b0f3Smrg (*uxa_screen->info->done_composite) (pDstPix); 1269d514b0f3Smrg 1270d514b0f3Smrg REGION_UNINIT(screen, ®ion); 1271d514b0f3Smrg 1272d514b0f3Smrg if (localSrc != pSrc) 1273d514b0f3Smrg FreePicture(localSrc, 0); 1274d514b0f3Smrg if (localMask && localMask != pMask) 1275d514b0f3Smrg FreePicture(localMask, 0); 1276d514b0f3Smrg 1277d514b0f3Smrg if (localDst != pDst) { 1278d514b0f3Smrg GCPtr gc; 1279d514b0f3Smrg 1280d514b0f3Smrg gc = GetScratchGC(pDst->pDrawable->depth, screen); 1281d514b0f3Smrg if (gc) { 1282d514b0f3Smrg ValidateGC(pDst->pDrawable, gc); 1283d514b0f3Smrg gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 1284d514b0f3Smrg 0, 0, width, height, xDst_copy, yDst_copy); 1285d514b0f3Smrg FreeScratchGC(gc); 1286d514b0f3Smrg } 1287d514b0f3Smrg 1288d514b0f3Smrg FreePicture(localDst, 0); 1289d514b0f3Smrg } 1290d514b0f3Smrg 1291d514b0f3Smrg return 1; 1292d514b0f3Smrg} 1293d514b0f3Smrg 1294d514b0f3Smrg/** 1295d514b0f3Smrg * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of 1296d514b0f3Smrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 1297d514b0f3Smrg * alpha and limited 1-tmu cards. 1298d514b0f3Smrg * 1299d514b0f3Smrg * From http://anholt.livejournal.com/32058.html: 1300d514b0f3Smrg * 1301d514b0f3Smrg * The trouble is that component-alpha rendering requires two different sources 1302d514b0f3Smrg * for blending: one for the source value to the blender, which is the 1303d514b0f3Smrg * per-channel multiplication of source and mask, and one for the source alpha 1304d514b0f3Smrg * for multiplying with the destination channels, which is the multiplication 1305d514b0f3Smrg * of the source channels by the mask alpha. So the equation for Over is: 1306d514b0f3Smrg * 1307d514b0f3Smrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 1308d514b0f3Smrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 1309d514b0f3Smrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 1310d514b0f3Smrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 1311d514b0f3Smrg * 1312d514b0f3Smrg * But we can do some simpler operations, right? How about PictOpOutReverse, 1313d514b0f3Smrg * which has a source factor of 0 and dest factor of (1 - source alpha). We 1314d514b0f3Smrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 1315d514b0f3Smrg * blenders pretty easily. So we can do a component-alpha OutReverse, which 1316d514b0f3Smrg * gets us: 1317d514b0f3Smrg * 1318d514b0f3Smrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 1319d514b0f3Smrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 1320d514b0f3Smrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 1321d514b0f3Smrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 1322d514b0f3Smrg * 1323d514b0f3Smrg * OK. And if an op doesn't use the source alpha value for the destination 1324d514b0f3Smrg * factor, then we can do the channel multiplication in the texture blenders 1325d514b0f3Smrg * to get the source value, and ignore the source alpha that we wouldn't use. 1326d514b0f3Smrg * We've supported this in the Radeon driver for a long time. An example would 1327d514b0f3Smrg * be PictOpAdd, which does: 1328d514b0f3Smrg * 1329d514b0f3Smrg * dst.A = src.A * mask.A + dst.A 1330d514b0f3Smrg * dst.R = src.R * mask.R + dst.R 1331d514b0f3Smrg * dst.G = src.G * mask.G + dst.G 1332d514b0f3Smrg * dst.B = src.B * mask.B + dst.B 1333d514b0f3Smrg * 1334d514b0f3Smrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 1335d514b0f3Smrg * after it, we get: 1336d514b0f3Smrg * 1337d514b0f3Smrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 1338d514b0f3Smrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 1339d514b0f3Smrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 1340d514b0f3Smrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 1341d514b0f3Smrg */ 1342d514b0f3Smrg 1343d514b0f3Smrgstatic int 1344d514b0f3Smrguxa_try_magic_two_pass_composite_helper(CARD8 op, 1345d514b0f3Smrg PicturePtr pSrc, 1346d514b0f3Smrg PicturePtr pMask, 1347d514b0f3Smrg PicturePtr pDst, 1348d514b0f3Smrg INT16 xSrc, INT16 ySrc, 1349d514b0f3Smrg INT16 xMask, INT16 yMask, 1350d514b0f3Smrg INT16 xDst, INT16 yDst, 1351d514b0f3Smrg CARD16 width, CARD16 height) 1352d514b0f3Smrg{ 1353d514b0f3Smrg ScreenPtr screen = pDst->pDrawable->pScreen; 1354d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1355d514b0f3Smrg PicturePtr localDst = pDst; 1356d514b0f3Smrg int xDst_copy = 0, yDst_copy = 0; 1357d514b0f3Smrg 1358d514b0f3Smrg assert(op == PictOpOver); 1359d514b0f3Smrg 1360d514b0f3Smrg if (uxa_screen->info->check_composite && 1361d514b0f3Smrg (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc, 1362d514b0f3Smrg pMask, pDst, width, height) 1363d514b0f3Smrg || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask, 1364d514b0f3Smrg pDst, width, height))) { 1365d514b0f3Smrg return -1; 1366d514b0f3Smrg } 1367d514b0f3Smrg 1368d514b0f3Smrg if (uxa_screen->info->check_composite_target && 1369d514b0f3Smrg !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 1370d514b0f3Smrg int depth = pDst->pDrawable->depth; 1371d514b0f3Smrg PixmapPtr pixmap; 1372d514b0f3Smrg int error; 1373d514b0f3Smrg GCPtr gc; 1374d514b0f3Smrg 1375d514b0f3Smrg pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 1376d514b0f3Smrg if (uxa_screen->info->check_copy && 1377d514b0f3Smrg !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 1378d514b0f3Smrg return -1; 1379d514b0f3Smrg 1380d514b0f3Smrg pixmap = screen->CreatePixmap(screen, 1381d514b0f3Smrg width, height, depth, 1382d514b0f3Smrg CREATE_PIXMAP_USAGE_SCRATCH); 1383d514b0f3Smrg if (!pixmap) 1384d514b0f3Smrg return 0; 1385d514b0f3Smrg 1386d514b0f3Smrg gc = GetScratchGC(depth, screen); 1387d514b0f3Smrg if (!gc) { 1388d514b0f3Smrg screen->DestroyPixmap(pixmap); 1389d514b0f3Smrg return 0; 1390d514b0f3Smrg } 1391d514b0f3Smrg 1392d514b0f3Smrg ValidateGC(&pixmap->drawable, gc); 1393d514b0f3Smrg gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 1394d514b0f3Smrg xDst, yDst, width, height, 0, 0); 1395d514b0f3Smrg FreeScratchGC(gc); 1396d514b0f3Smrg 1397d514b0f3Smrg xDst_copy = xDst; xDst = 0; 1398d514b0f3Smrg yDst_copy = yDst; yDst = 0; 1399d514b0f3Smrg 1400d514b0f3Smrg localDst = CreatePicture(0, &pixmap->drawable, 1401d514b0f3Smrg PictureMatchFormat(screen, depth, pDst->format), 1402d514b0f3Smrg 0, 0, serverClient, &error); 1403d514b0f3Smrg screen->DestroyPixmap(pixmap); 1404d514b0f3Smrg 1405d514b0f3Smrg if (!localDst) 1406d514b0f3Smrg return 0; 1407d514b0f3Smrg 1408d514b0f3Smrg ValidatePicture(localDst); 1409d514b0f3Smrg } 1410d514b0f3Smrg 1411d514b0f3Smrg /* Now, we think we should be able to accelerate this operation. First, 1412d514b0f3Smrg * composite the destination to be the destination times the source alpha 1413d514b0f3Smrg * factors. 1414d514b0f3Smrg */ 1415d514b0f3Smrg uxa_composite(PictOpOutReverse, pSrc, pMask, localDst, 1416d514b0f3Smrg xSrc, ySrc, 1417d514b0f3Smrg xMask, yMask, 1418d514b0f3Smrg xDst, yDst, 1419d514b0f3Smrg width, height); 1420d514b0f3Smrg 1421d514b0f3Smrg /* Then, add in the source value times the destination alpha factors (1.0). 1422d514b0f3Smrg */ 1423d514b0f3Smrg uxa_composite(PictOpAdd, pSrc, pMask, localDst, 1424d514b0f3Smrg xSrc, ySrc, 1425d514b0f3Smrg xMask, yMask, 1426d514b0f3Smrg xDst, yDst, 1427d514b0f3Smrg width, height); 1428d514b0f3Smrg 1429d514b0f3Smrg if (localDst != pDst) { 1430d514b0f3Smrg GCPtr gc; 1431d514b0f3Smrg 1432d514b0f3Smrg gc = GetScratchGC(pDst->pDrawable->depth, screen); 1433d514b0f3Smrg if (gc) { 1434d514b0f3Smrg ValidateGC(pDst->pDrawable, gc); 1435d514b0f3Smrg gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 1436d514b0f3Smrg 0, 0, width, height, xDst_copy, yDst_copy); 1437d514b0f3Smrg FreeScratchGC(gc); 1438d514b0f3Smrg } 1439d514b0f3Smrg 1440d514b0f3Smrg FreePicture(localDst, 0); 1441d514b0f3Smrg } 1442d514b0f3Smrg 1443d514b0f3Smrg return 1; 1444d514b0f3Smrg} 1445d514b0f3Smrg 1446d514b0f3Smrgstatic int 1447d514b0f3Smrgcompatible_formats (CARD8 op, PicturePtr dst, PicturePtr src) 1448d514b0f3Smrg{ 1449d514b0f3Smrg if (op == PictOpSrc) { 1450d514b0f3Smrg if (src->format == dst->format) 1451d514b0f3Smrg return 1; 1452d514b0f3Smrg 1453d514b0f3Smrg /* Is the destination an alpha-less version of source? */ 1454d514b0f3Smrg if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format), 1455d514b0f3Smrg PICT_FORMAT_TYPE(src->format), 1456d514b0f3Smrg 0, 1457d514b0f3Smrg PICT_FORMAT_R(src->format), 1458d514b0f3Smrg PICT_FORMAT_G(src->format), 1459d514b0f3Smrg PICT_FORMAT_B(src->format))) 1460d514b0f3Smrg return 1; 1461d514b0f3Smrg 1462d514b0f3Smrg /* XXX xrgb is promoted to argb during image upload... */ 1463d514b0f3Smrg#if 0 1464d514b0f3Smrg if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8) 1465d514b0f3Smrg return 1; 1466d514b0f3Smrg#endif 1467d514b0f3Smrg } else if (op == PictOpOver) { 1468d514b0f3Smrg if (PICT_FORMAT_A(src->format)) 1469d514b0f3Smrg return 0; 1470d514b0f3Smrg 1471d514b0f3Smrg return src->format == dst->format; 1472d514b0f3Smrg } 1473d514b0f3Smrg 1474d514b0f3Smrg return 0; 1475d514b0f3Smrg} 1476d514b0f3Smrg 1477d514b0f3Smrgstatic int 1478d514b0f3Smrgdrawable_contains (DrawablePtr drawable, int x, int y, int w, int h) 1479d514b0f3Smrg{ 1480d514b0f3Smrg if (x < 0 || y < 0) 1481d514b0f3Smrg return FALSE; 1482d514b0f3Smrg 1483d514b0f3Smrg if (x + w > drawable->width) 1484d514b0f3Smrg return FALSE; 1485d514b0f3Smrg 1486d514b0f3Smrg if (y + h > drawable->height) 1487d514b0f3Smrg return FALSE; 1488d514b0f3Smrg 1489d514b0f3Smrg return TRUE; 1490d514b0f3Smrg} 1491d514b0f3Smrg 1492d514b0f3Smrgvoid 1493d514b0f3Smrguxa_composite(CARD8 op, 1494d514b0f3Smrg PicturePtr pSrc, 1495d514b0f3Smrg PicturePtr pMask, 1496d514b0f3Smrg PicturePtr pDst, 1497d514b0f3Smrg INT16 xSrc, INT16 ySrc, 1498d514b0f3Smrg INT16 xMask, INT16 yMask, 1499d514b0f3Smrg INT16 xDst, INT16 yDst, 1500d514b0f3Smrg CARD16 width, CARD16 height) 1501d514b0f3Smrg{ 1502d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 1503d514b0f3Smrg int ret = -1; 1504d514b0f3Smrg Bool saveSrcRepeat = pSrc->repeat; 1505d514b0f3Smrg Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 1506d514b0f3Smrg RegionRec region; 1507d514b0f3Smrg int tx, ty; 1508d514b0f3Smrg 1509d514b0f3Smrg if (uxa_screen->swappedOut || uxa_screen->force_fallback) 1510d514b0f3Smrg goto fallback; 1511d514b0f3Smrg 1512d514b0f3Smrg if (!uxa_drawable_is_offscreen(pDst->pDrawable)) 1513d514b0f3Smrg goto fallback; 1514d514b0f3Smrg 1515d514b0f3Smrg if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) 1516d514b0f3Smrg goto fallback; 1517d514b0f3Smrg 1518d514b0f3Smrg /* Remove repeat in source if useless */ 1519d514b0f3Smrg if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution && 1520d514b0f3Smrg transform_is_integer_translation(pSrc->transform, &tx, &ty) && 1521d514b0f3Smrg (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) && 1522d514b0f3Smrg drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height)) 1523d514b0f3Smrg pSrc->repeat = 0; 1524d514b0f3Smrg 1525d514b0f3Smrg if (!pMask) { 1526d514b0f3Smrg if (op == PictOpClear) { 1527d514b0f3Smrg PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen); 1528d514b0f3Smrg if (clear && 1529d514b0f3Smrg uxa_try_driver_solid_fill(clear, pDst, 1530d514b0f3Smrg xSrc, ySrc, 1531d514b0f3Smrg xDst, yDst, 1532d514b0f3Smrg width, height) == 1) 1533d514b0f3Smrg goto done; 1534d514b0f3Smrg } 1535d514b0f3Smrg 1536d514b0f3Smrg if (pSrc->pDrawable == NULL) { 1537d514b0f3Smrg if (pSrc->pSourcePict) { 1538d514b0f3Smrg SourcePict *source = pSrc->pSourcePict; 1539d514b0f3Smrg if (source->type == SourcePictTypeSolidFill) { 1540d514b0f3Smrg if (op == PictOpSrc || 1541d514b0f3Smrg (op == PictOpOver && 1542d514b0f3Smrg (source->solidFill.color & 0xff000000) == 0xff000000)) { 1543d514b0f3Smrg ret = uxa_try_driver_solid_fill(pSrc, pDst, 1544d514b0f3Smrg xSrc, ySrc, 1545d514b0f3Smrg xDst, yDst, 1546d514b0f3Smrg width, height); 1547d514b0f3Smrg if (ret == 1) 1548d514b0f3Smrg goto done; 1549d514b0f3Smrg } 1550d514b0f3Smrg } 1551d514b0f3Smrg } 1552d514b0f3Smrg } else if (pSrc->pDrawable->width == 1 && 1553d514b0f3Smrg pSrc->pDrawable->height == 1 && 1554d514b0f3Smrg pSrc->repeat && 1555d514b0f3Smrg (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) { 1556d514b0f3Smrg ret = uxa_try_driver_solid_fill(pSrc, pDst, 1557d514b0f3Smrg xSrc, ySrc, 1558d514b0f3Smrg xDst, yDst, 1559d514b0f3Smrg width, height); 1560d514b0f3Smrg if (ret == 1) 1561d514b0f3Smrg goto done; 1562d514b0f3Smrg } else if (compatible_formats (op, pDst, pSrc) && 1563d514b0f3Smrg pSrc->filter != PictFilterConvolution && 1564d514b0f3Smrg transform_is_integer_translation(pSrc->transform, &tx, &ty)) { 1565d514b0f3Smrg if (!pSrc->repeat && 1566d514b0f3Smrg drawable_contains(pSrc->pDrawable, 1567d514b0f3Smrg xSrc + tx, ySrc + ty, 1568d514b0f3Smrg width, height)) { 1569d514b0f3Smrg xDst += pDst->pDrawable->x; 1570d514b0f3Smrg yDst += pDst->pDrawable->y; 1571d514b0f3Smrg xSrc += pSrc->pDrawable->x + tx; 1572d514b0f3Smrg ySrc += pSrc->pDrawable->y + ty; 1573d514b0f3Smrg 1574d514b0f3Smrg if (!miComputeCompositeRegion 1575d514b0f3Smrg (®ion, pSrc, pMask, pDst, xSrc, ySrc, 1576d514b0f3Smrg xMask, yMask, xDst, yDst, width, height)) 1577d514b0f3Smrg goto done; 1578d514b0f3Smrg 1579d514b0f3Smrg uxa_copy_n_to_n(pSrc->pDrawable, 1580d514b0f3Smrg pDst->pDrawable, NULL, 1581d514b0f3Smrg REGION_RECTS(®ion), 1582d514b0f3Smrg REGION_NUM_RECTS(®ion), 1583d514b0f3Smrg xSrc - xDst, ySrc - yDst, FALSE, 1584d514b0f3Smrg FALSE, 0, NULL); 1585d514b0f3Smrg REGION_UNINIT(pDst->pDrawable->pScreen, 1586d514b0f3Smrg ®ion); 1587d514b0f3Smrg goto done; 1588d514b0f3Smrg } else if (pSrc->repeat && pSrc->repeatType == RepeatNormal && 1589d514b0f3Smrg pSrc->pDrawable->type == DRAWABLE_PIXMAP) { 1590d514b0f3Smrg DDXPointRec patOrg; 1591d514b0f3Smrg 1592d514b0f3Smrg /* Let's see if the driver can do the repeat 1593d514b0f3Smrg * in one go 1594d514b0f3Smrg */ 1595d514b0f3Smrg if (uxa_screen->info->prepare_composite) { 1596d514b0f3Smrg ret = uxa_try_driver_composite(op, pSrc, 1597d514b0f3Smrg pMask, pDst, 1598d514b0f3Smrg xSrc, ySrc, 1599d514b0f3Smrg xMask, yMask, 1600d514b0f3Smrg xDst, yDst, 1601d514b0f3Smrg width, height); 1602d514b0f3Smrg if (ret == 1) 1603d514b0f3Smrg goto done; 1604d514b0f3Smrg } 1605d514b0f3Smrg 1606d514b0f3Smrg /* Now see if we can use 1607d514b0f3Smrg * uxa_fill_region_tiled() 1608d514b0f3Smrg */ 1609d514b0f3Smrg xDst += pDst->pDrawable->x; 1610d514b0f3Smrg yDst += pDst->pDrawable->y; 1611d514b0f3Smrg xSrc += pSrc->pDrawable->x + tx; 1612d514b0f3Smrg ySrc += pSrc->pDrawable->y + ty; 1613d514b0f3Smrg 1614d514b0f3Smrg if (!miComputeCompositeRegion 1615d514b0f3Smrg (®ion, pSrc, pMask, pDst, xSrc, ySrc, 1616d514b0f3Smrg xMask, yMask, xDst, yDst, width, height)) 1617d514b0f3Smrg goto done; 1618d514b0f3Smrg 1619d514b0f3Smrg /* pattern origin is the point in the 1620d514b0f3Smrg * destination drawable 1621d514b0f3Smrg * corresponding to (0,0) in the source */ 1622d514b0f3Smrg patOrg.x = xDst - xSrc; 1623d514b0f3Smrg patOrg.y = yDst - ySrc; 1624d514b0f3Smrg 1625d514b0f3Smrg ret = uxa_fill_region_tiled(pDst->pDrawable, 1626d514b0f3Smrg ®ion, 1627d514b0f3Smrg (PixmapPtr) pSrc-> 1628d514b0f3Smrg pDrawable, &patOrg, 1629d514b0f3Smrg FB_ALLONES, GXcopy); 1630d514b0f3Smrg 1631d514b0f3Smrg REGION_UNINIT(pDst->pDrawable->pScreen, 1632d514b0f3Smrg ®ion); 1633d514b0f3Smrg 1634d514b0f3Smrg if (ret) 1635d514b0f3Smrg goto done; 1636d514b0f3Smrg } 1637d514b0f3Smrg } 1638d514b0f3Smrg } 1639d514b0f3Smrg 1640d514b0f3Smrg /* Remove repeat in mask if useless */ 1641d514b0f3Smrg if (pMask && pMask->pDrawable && pMask->repeat && 1642d514b0f3Smrg pMask->filter != PictFilterConvolution && 1643d514b0f3Smrg transform_is_integer_translation(pMask->transform, &tx, &ty) && 1644d514b0f3Smrg (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) && 1645d514b0f3Smrg drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height)) 1646d514b0f3Smrg pMask->repeat = 0; 1647d514b0f3Smrg 1648d514b0f3Smrg if (uxa_screen->info->prepare_composite) { 1649d514b0f3Smrg Bool isSrcSolid; 1650d514b0f3Smrg 1651d514b0f3Smrg ret = 1652d514b0f3Smrg uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 1653d514b0f3Smrg xMask, yMask, xDst, yDst, width, 1654d514b0f3Smrg height); 1655d514b0f3Smrg if (ret == 1) 1656d514b0f3Smrg goto done; 1657d514b0f3Smrg 1658d514b0f3Smrg /* For generic masks and solid src pictures, mach64 can do 1659d514b0f3Smrg * Over in two passes, similar to the component-alpha case. 1660d514b0f3Smrg */ 1661d514b0f3Smrg 1662d514b0f3Smrg isSrcSolid = 1663d514b0f3Smrg pSrc->pDrawable ? 1664d514b0f3Smrg pSrc->pDrawable->width == 1 && 1665d514b0f3Smrg pSrc->pDrawable->height == 1 && 1666d514b0f3Smrg pSrc->repeat : 1667d514b0f3Smrg pSrc->pSourcePict ? 1668d514b0f3Smrg pSrc->pSourcePict->type == SourcePictTypeSolidFill : 1669d514b0f3Smrg 0; 1670d514b0f3Smrg 1671d514b0f3Smrg /* If we couldn't do the Composite in a single pass, and it 1672d514b0f3Smrg * was a component-alpha Over, see if we can do it in two 1673d514b0f3Smrg * passes with an OutReverse and then an Add. 1674d514b0f3Smrg */ 1675d514b0f3Smrg if (ret == -1 && op == PictOpOver && pMask && 1676d514b0f3Smrg (pMask->componentAlpha || isSrcSolid)) { 1677d514b0f3Smrg ret = 1678d514b0f3Smrg uxa_try_magic_two_pass_composite_helper(op, pSrc, 1679d514b0f3Smrg pMask, pDst, 1680d514b0f3Smrg xSrc, ySrc, 1681d514b0f3Smrg xMask, yMask, 1682d514b0f3Smrg xDst, yDst, 1683d514b0f3Smrg width, height); 1684d514b0f3Smrg if (ret == 1) 1685d514b0f3Smrg goto done; 1686d514b0f3Smrg } 1687d514b0f3Smrg 1688d514b0f3Smrg } 1689d514b0f3Smrg 1690d514b0f3Smrgfallback: 1691d514b0f3Smrg uxa_print_composite_fallback("uxa_composite", 1692d514b0f3Smrg op, pSrc, pMask, pDst); 1693d514b0f3Smrg 1694d514b0f3Smrg uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 1695d514b0f3Smrg xMask, yMask, xDst, yDst, width, height); 1696d514b0f3Smrg 1697d514b0f3Smrgdone: 1698d514b0f3Smrg pSrc->repeat = saveSrcRepeat; 1699d514b0f3Smrg if (pMask) 1700d514b0f3Smrg pMask->repeat = saveMaskRepeat; 1701d514b0f3Smrg} 1702d514b0f3Smrg#endif 1703d514b0f3Smrg 1704d514b0f3Smrg/** 1705d514b0f3Smrg * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead 1706d514b0f3Smrg * of PolyFillRect to initialize the pixmap after creating it, to prevent 1707d514b0f3Smrg * the pixmap from being migrated. 1708d514b0f3Smrg * 1709d514b0f3Smrg * See the comments about uxa_trapezoids and uxa_triangles. 1710d514b0f3Smrg */ 1711d514b0f3Smrgstatic PicturePtr 1712d514b0f3Smrguxa_create_alpha_picture(ScreenPtr pScreen, 1713d514b0f3Smrg PicturePtr pDst, 1714d514b0f3Smrg PictFormatPtr pPictFormat, CARD16 width, CARD16 height) 1715d514b0f3Smrg{ 1716d514b0f3Smrg PixmapPtr pPixmap; 1717d514b0f3Smrg PicturePtr pPicture; 1718d514b0f3Smrg int error; 1719d514b0f3Smrg 1720d514b0f3Smrg if (width > 32767 || height > 32767) 1721d514b0f3Smrg return 0; 1722d514b0f3Smrg 1723d514b0f3Smrg if (!pPictFormat) { 1724d514b0f3Smrg if (pDst->polyEdge == PolyEdgeSharp) 1725d514b0f3Smrg pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1726d514b0f3Smrg else 1727d514b0f3Smrg pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1728d514b0f3Smrg if (!pPictFormat) 1729d514b0f3Smrg return 0; 1730d514b0f3Smrg } 1731d514b0f3Smrg 1732d514b0f3Smrg pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1733d514b0f3Smrg pPictFormat->depth, 1734d514b0f3Smrg UXA_CREATE_PIXMAP_FOR_MAP); 1735d514b0f3Smrg if (!pPixmap) 1736d514b0f3Smrg return 0; 1737d514b0f3Smrg pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 1738d514b0f3Smrg 0, 0, serverClient, &error); 1739d514b0f3Smrg (*pScreen->DestroyPixmap) (pPixmap); 1740d514b0f3Smrg return pPicture; 1741d514b0f3Smrg} 1742d514b0f3Smrg 1743d514b0f3Smrg/** 1744d514b0f3Smrg * uxa_trapezoids is essentially a copy of miTrapezoids that uses 1745d514b0f3Smrg * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1746d514b0f3Smrg * 1747d514b0f3Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1748d514b0f3Smrg * to initialize the contents after creating the pixmap, which 1749d514b0f3Smrg * causes the pixmap to be moved in for acceleration. The subsequent 1750d514b0f3Smrg * call to RasterizeTrapezoid won't be accelerated however, which 1751d514b0f3Smrg * forces the pixmap to be moved out again. 1752d514b0f3Smrg * 1753d514b0f3Smrg * uxa_create_alpha_picture avoids this roundtrip by using 1754d514b0f3Smrg * uxa_check_poly_fill_rect to initialize the contents. 1755d514b0f3Smrg */ 1756d514b0f3Smrgvoid 1757d514b0f3Smrguxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, 1758d514b0f3Smrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1759d514b0f3Smrg int ntrap, xTrapezoid * traps) 1760d514b0f3Smrg{ 1761d514b0f3Smrg ScreenPtr screen = dst->pDrawable->pScreen; 1762d514b0f3Smrg BoxRec bounds; 1763d514b0f3Smrg Bool direct; 1764d514b0f3Smrg 1765d514b0f3Smrg direct = op == PictOpAdd && miIsSolidAlpha(src); 1766d514b0f3Smrg if (maskFormat || direct) { 1767d514b0f3Smrg miTrapezoidBounds(ntrap, traps, &bounds); 1768d514b0f3Smrg 1769d514b0f3Smrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1770d514b0f3Smrg return; 1771d514b0f3Smrg } 1772d514b0f3Smrg 1773d514b0f3Smrg /* 1774d514b0f3Smrg * Check for solid alpha add 1775d514b0f3Smrg */ 1776d514b0f3Smrg if (direct) { 1777d514b0f3Smrg DrawablePtr pDraw = dst->pDrawable; 1778d514b0f3Smrg PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw); 1779d514b0f3Smrg int xoff, yoff; 1780d514b0f3Smrg 1781d514b0f3Smrg uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff); 1782d514b0f3Smrg 1783d514b0f3Smrg xoff += pDraw->x; 1784d514b0f3Smrg yoff += pDraw->y; 1785d514b0f3Smrg 1786d514b0f3Smrg if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) { 1787d514b0f3Smrg PictureScreenPtr ps = GetPictureScreen(screen); 1788d514b0f3Smrg 1789d514b0f3Smrg for (; ntrap; ntrap--, traps++) 1790d514b0f3Smrg (*ps->RasterizeTrapezoid) (dst, traps, 0, 0); 1791d514b0f3Smrg uxa_finish_access(pDraw); 1792d514b0f3Smrg } 1793d514b0f3Smrg } else if (maskFormat) { 1794d514b0f3Smrg PixmapPtr scratch = NULL; 1795d514b0f3Smrg PicturePtr mask; 1796d514b0f3Smrg INT16 xDst, yDst; 1797d514b0f3Smrg INT16 xRel, yRel; 1798d514b0f3Smrg int width, height; 1799d514b0f3Smrg pixman_image_t *image; 1800d514b0f3Smrg pixman_format_code_t format; 1801d514b0f3Smrg 1802d514b0f3Smrg xDst = traps[0].left.p1.x >> 16; 1803d514b0f3Smrg yDst = traps[0].left.p1.y >> 16; 1804d514b0f3Smrg 1805d514b0f3Smrg width = bounds.x2 - bounds.x1; 1806d514b0f3Smrg height = bounds.y2 - bounds.y1; 1807d514b0f3Smrg 1808d514b0f3Smrg format = maskFormat->format | 1809d514b0f3Smrg (BitsPerPixel(maskFormat->depth) << 24); 1810d514b0f3Smrg image = 1811d514b0f3Smrg pixman_image_create_bits(format, width, height, NULL, 0); 1812d514b0f3Smrg if (!image) 1813d514b0f3Smrg return; 1814d514b0f3Smrg 1815d514b0f3Smrg for (; ntrap; ntrap--, traps++) 1816d514b0f3Smrg pixman_rasterize_trapezoid(image, 1817d514b0f3Smrg (pixman_trapezoid_t *) traps, 1818d514b0f3Smrg -bounds.x1, -bounds.y1); 1819d514b0f3Smrg if (uxa_drawable_is_offscreen(dst->pDrawable)) { 1820d514b0f3Smrg mask = uxa_picture_from_pixman_image(screen, image, format); 1821d514b0f3Smrg } else { 1822d514b0f3Smrg int error; 1823d514b0f3Smrg 1824d514b0f3Smrg scratch = GetScratchPixmapHeader(screen, width, height, 1825d514b0f3Smrg PIXMAN_FORMAT_DEPTH(format), 1826d514b0f3Smrg PIXMAN_FORMAT_BPP(format), 1827d514b0f3Smrg pixman_image_get_stride(image), 1828d514b0f3Smrg pixman_image_get_data(image)); 1829d514b0f3Smrg mask = CreatePicture(0, &scratch->drawable, 1830d514b0f3Smrg PictureMatchFormat(screen, 1831d514b0f3Smrg PIXMAN_FORMAT_DEPTH(format), 1832d514b0f3Smrg format), 1833d514b0f3Smrg 0, 0, serverClient, &error); 1834d514b0f3Smrg } 1835d514b0f3Smrg if (!mask) { 1836d514b0f3Smrg if (scratch) 1837d514b0f3Smrg FreeScratchPixmapHeader(scratch); 1838d514b0f3Smrg pixman_image_unref(image); 1839d514b0f3Smrg return; 1840d514b0f3Smrg } 1841d514b0f3Smrg 1842d514b0f3Smrg xRel = bounds.x1 + xSrc - xDst; 1843d514b0f3Smrg yRel = bounds.y1 + ySrc - yDst; 1844d514b0f3Smrg CompositePicture(op, src, mask, dst, 1845d514b0f3Smrg xRel, yRel, 1846d514b0f3Smrg 0, 0, 1847d514b0f3Smrg bounds.x1, bounds.y1, 1848d514b0f3Smrg width, height); 1849d514b0f3Smrg FreePicture(mask, 0); 1850d514b0f3Smrg 1851d514b0f3Smrg if (scratch) 1852d514b0f3Smrg FreeScratchPixmapHeader(scratch); 1853d514b0f3Smrg pixman_image_unref(image); 1854d514b0f3Smrg } else { 1855d514b0f3Smrg if (dst->polyEdge == PolyEdgeSharp) 1856d514b0f3Smrg maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 1857d514b0f3Smrg else 1858d514b0f3Smrg maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 1859d514b0f3Smrg for (; ntrap; ntrap--, traps++) 1860d514b0f3Smrg uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1861d514b0f3Smrg 1, traps); 1862d514b0f3Smrg } 1863d514b0f3Smrg} 1864d514b0f3Smrg 1865d514b0f3Smrg/** 1866d514b0f3Smrg * uxa_triangles is essentially a copy of miTriangles that uses 1867d514b0f3Smrg * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1868d514b0f3Smrg * 1869d514b0f3Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1870d514b0f3Smrg * to initialize the contents after creating the pixmap, which 1871d514b0f3Smrg * causes the pixmap to be moved in for acceleration. The subsequent 1872d514b0f3Smrg * call to AddTriangles won't be accelerated however, which forces the pixmap 1873d514b0f3Smrg * to be moved out again. 1874d514b0f3Smrg * 1875d514b0f3Smrg * uxa_create_alpha_picture avoids this roundtrip by using 1876d514b0f3Smrg * uxa_check_poly_fill_rect to initialize the contents. 1877d514b0f3Smrg */ 1878d514b0f3Smrgvoid 1879d514b0f3Smrguxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1880d514b0f3Smrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1881d514b0f3Smrg int ntri, xTriangle * tris) 1882d514b0f3Smrg{ 1883d514b0f3Smrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 1884d514b0f3Smrg PictureScreenPtr ps = GetPictureScreen(pScreen); 1885d514b0f3Smrg BoxRec bounds; 1886d514b0f3Smrg Bool direct = op == PictOpAdd && miIsSolidAlpha(pSrc); 1887d514b0f3Smrg 1888d514b0f3Smrg if (maskFormat || direct) { 1889d514b0f3Smrg miTriangleBounds(ntri, tris, &bounds); 1890d514b0f3Smrg 1891d514b0f3Smrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1892d514b0f3Smrg return; 1893d514b0f3Smrg } 1894d514b0f3Smrg 1895d514b0f3Smrg /* 1896d514b0f3Smrg * Check for solid alpha add 1897d514b0f3Smrg */ 1898d514b0f3Smrg if (direct) { 1899d514b0f3Smrg DrawablePtr pDraw = pDst->pDrawable; 1900d514b0f3Smrg if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) { 1901d514b0f3Smrg (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); 1902d514b0f3Smrg uxa_finish_access(pDraw); 1903d514b0f3Smrg } 1904d514b0f3Smrg } else if (maskFormat) { 1905d514b0f3Smrg PicturePtr pPicture; 1906d514b0f3Smrg INT16 xDst, yDst; 1907d514b0f3Smrg INT16 xRel, yRel; 1908d514b0f3Smrg int width = bounds.x2 - bounds.x1; 1909d514b0f3Smrg int height = bounds.y2 - bounds.y1; 1910d514b0f3Smrg GCPtr pGC; 1911d514b0f3Smrg xRectangle rect; 1912d514b0f3Smrg 1913d514b0f3Smrg xDst = tris[0].p1.x >> 16; 1914d514b0f3Smrg yDst = tris[0].p1.y >> 16; 1915d514b0f3Smrg 1916d514b0f3Smrg pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat, 1917d514b0f3Smrg width, height); 1918d514b0f3Smrg if (!pPicture) 1919d514b0f3Smrg return; 1920d514b0f3Smrg 1921d514b0f3Smrg /* Clear the alpha picture to 0. */ 1922d514b0f3Smrg pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen); 1923d514b0f3Smrg if (!pGC) { 1924d514b0f3Smrg FreePicture(pPicture, 0); 1925d514b0f3Smrg return; 1926d514b0f3Smrg } 1927d514b0f3Smrg ValidateGC(pPicture->pDrawable, pGC); 1928d514b0f3Smrg rect.x = 0; 1929d514b0f3Smrg rect.y = 0; 1930d514b0f3Smrg rect.width = width; 1931d514b0f3Smrg rect.height = height; 1932d514b0f3Smrg uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect); 1933d514b0f3Smrg FreeScratchGC(pGC); 1934d514b0f3Smrg 1935d514b0f3Smrg if (uxa_prepare_access(pPicture->pDrawable, NULL, UXA_ACCESS_RW)) { 1936d514b0f3Smrg (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, 1937d514b0f3Smrg ntri, tris); 1938d514b0f3Smrg uxa_finish_access(pPicture->pDrawable); 1939d514b0f3Smrg } 1940d514b0f3Smrg 1941d514b0f3Smrg xRel = bounds.x1 + xSrc - xDst; 1942d514b0f3Smrg yRel = bounds.y1 + ySrc - yDst; 1943d514b0f3Smrg CompositePicture(op, pSrc, pPicture, pDst, 1944d514b0f3Smrg xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1945d514b0f3Smrg bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1946d514b0f3Smrg FreePicture(pPicture, 0); 1947d514b0f3Smrg } else { 1948d514b0f3Smrg if (pDst->polyEdge == PolyEdgeSharp) 1949d514b0f3Smrg maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1950d514b0f3Smrg else 1951d514b0f3Smrg maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1952d514b0f3Smrg 1953d514b0f3Smrg for (; ntri; ntri--, tris++) 1954d514b0f3Smrg uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, 1955d514b0f3Smrg tris); 1956d514b0f3Smrg } 1957d514b0f3Smrg} 1958