lx_exa.c revision 04007eba
1/* 2 * Copyright (c) 2007-2008 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 * 22 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 23 * contributors may be used to endorse or promote products derived from this 24 * software without specific prior written permission. 25 */ 26 27/* TODO: 28 Support a8 as a source or destination? 29 convert !a8 or !a4 masks? 30 support multiple pass operations? 31*/ 32 33/* To support PictOptAdd with a mask */ 34 35#ifdef HAVE_CONFIG_H 36#include "config.h" 37#endif 38 39#include "xf86.h" 40#include "exa.h" 41 42#include "geode.h" 43#include "cim_defs.h" 44#include "cim_regs.h" 45 46#include "geode_blend.h" 47 48#define F(x) IntToxFixed(x) 49#define I(x) xFixedToInt(x) 50 51#define GEODE_TRACE_FALL 0 52 53#if GEODE_TRACE_FALL 54#define GEODE_FALLBACK(x) \ 55do { \ 56 ErrorF("%s: ", __FUNCTION__); \ 57 ErrorF x; \ 58 return FALSE; \ 59} while (0) 60#else 61#define GEODE_FALLBACK(x) return FALSE 62#endif 63 64static const struct exa_format_t { 65 int exa; 66 int bpp; 67 int fmt; 68 int alphabits; 69} lx_exa_formats[] = { 70 { 71 PICT_a8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}, { 72 PICT_x8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 0}, { 73 PICT_x8b8g8r8, 32, CIMGP_SOURCE_FMT_32BPP_BGR, 0}, { 74 PICT_a4r4g4b4, 16, CIMGP_SOURCE_FMT_4_4_4_4, 4}, { 75 PICT_a1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 1}, { 76 PICT_r5g6b5, 16, CIMGP_SOURCE_FMT_0_5_6_5, 0}, { 77 PICT_b5g6r5, 16, CIMGP_SOURCE_FMT_16BPP_BGR, 0}, { 78 PICT_x1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 0}, { 79 PICT_x1b5g5r5, 16, CIMGP_SOURCE_FMT_15BPP_BGR, 0}, { 80 PICT_r3g3b2, 8, CIMGP_SOURCE_FMT_3_3_2, 0}, { 81 PICT_a8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8} 82}; 83 84/* This is a chunk of memory we use for scratch space */ 85 86#define COMP_TYPE_MASK 0 87#define COMP_TYPE_ONEPASS 1 88#define COMP_TYPE_TWOPASS 3 89#define COMP_TYPE_ROTATE 5 90 91static struct { 92 int type; 93 94 unsigned int srcOffset; 95 unsigned int srcPitch; 96 unsigned int srcBpp; 97 unsigned int srcWidth, srcHeight; 98 99 unsigned int srcColor; 100 int op; 101 int repeat; 102 int maskrepeat; 103 unsigned int fourBpp; 104 unsigned int bufferOffset; 105 struct exa_format_t *srcFormat; 106 struct exa_format_t *dstFormat; 107 108 int rotate; 109 PictTransform *transform; 110 111} exaScratch; 112 113static const int SDfn[16] = { 114 0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE, 115 0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF 116}; 117 118static const int SDfn_PM[16] = { 119 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 120 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA 121}; 122 123/* These functions check to see if we can safely prefetch the memory 124 * for the blt, or if we have to wait the previous blt to complete. 125 * One function is for the fill, and the other is for the copy because 126 * they have different requirements based on ROP 127 */ 128 129static int lx0 = -1, ly0 = -1, lx1 = -1, ly1 = -1; 130 131static int 132lx_fill_flags(int x0, int y0, int w, int h, int rop) 133{ 134 int x1 = x0 + w, y1 = y0 + h; 135 int n = ((rop ^ (rop >> 1)) & 0x55) == 0 || /* no dst */ 136 x0 >= lx1 || y0 >= ly1 || /* rght/below */ 137 x1 <= lx0 || y1 <= ly0 ? /* left/above */ 138 0 : CIMGP_BLTFLAGS_HAZARD; 139 140 lx0 = x0; 141 ly0 = y0; 142 lx1 = x1; 143 ly1 = y1; 144 145 return n; 146} 147 148static int 149lx_copy_flags(int x0, int y0, int x1, int y1, int w, int h, int rop) 150{ 151 int x2 = x1 + w, y2 = y1 + h; 152 153 /* dst not hazzard and src not hazzard */ 154 int n = (((rop ^ (rop >> 1)) & 0x55) == 0 || 155 x1 >= lx1 || y1 >= ly1 || 156 x2 <= lx0 || y2 <= ly0) && 157 (((rop ^ (rop >> 2)) & 0x33) == 0 || 158 x0 >= lx1 || y0 >= ly1 || 159 x0 + w <= lx0 || y0 + h <= ly0) ? 0 : CIMGP_BLTFLAGS_HAZARD; 160 161 lx0 = x1; 162 ly0 = y1; 163 lx1 = x2; 164 ly1 = y2; 165 166 return n; 167} 168 169/* These are borrowed from the exa engine - they should be made global 170 and available to drivers, but until then.... 171*/ 172 173/* exaGetPixelFromRGBA (exa_render.c) */ 174 175static Bool 176_GetPixelFromRGBA(CARD32 *pixel, 177 CARD16 red, CARD16 green, CARD16 blue, CARD16 alpha, 178 CARD32 format) 179{ 180 int rbits, bbits, gbits, abits; 181 int rshift, bshift, gshift, ashift; 182 183 *pixel = 0; 184 185 if (!PICT_FORMAT_COLOR(format)) 186 return FALSE; 187 188 rbits = PICT_FORMAT_R(format); 189 gbits = PICT_FORMAT_G(format); 190 bbits = PICT_FORMAT_B(format); 191 abits = PICT_FORMAT_A(format); 192 193 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 194 bshift = 0; 195 gshift = bbits; 196 rshift = gshift + gbits; 197 ashift = rshift + rbits; 198 } 199 else { /* PICT_TYPE_ABGR */ 200 rshift = 0; 201 gshift = rbits; 202 bshift = gshift + gbits; 203 ashift = bshift + bbits; 204 } 205 206 *pixel |= (blue >> (16 - bbits)) << bshift; 207 *pixel |= (red >> (16 - rbits)) << rshift; 208 *pixel |= (green >> (16 - gbits)) << gshift; 209 *pixel |= (alpha >> (16 - abits)) << ashift; 210 211 return TRUE; 212} 213 214/* exaGetRGBAFromPixel (exa_render.c) */ 215 216static Bool 217_GetRGBAFromPixel(CARD32 pixel, 218 CARD16 *red, 219 CARD16 *green, CARD16 *blue, CARD16 *alpha, CARD32 format) 220{ 221 int rbits, bbits, gbits, abits; 222 int rshift, bshift, gshift, ashift; 223 224 if (!PICT_FORMAT_COLOR(format)) 225 return FALSE; 226 227 rbits = PICT_FORMAT_R(format); 228 gbits = PICT_FORMAT_G(format); 229 bbits = PICT_FORMAT_B(format); 230 abits = PICT_FORMAT_A(format); 231 232 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 233 bshift = 0; 234 gshift = bbits; 235 rshift = gshift + gbits; 236 ashift = rshift + rbits; 237 } 238 else { /* PICT_TYPE_ABGR */ 239 rshift = 0; 240 gshift = rbits; 241 bshift = gshift + gbits; 242 ashift = bshift + bbits; 243 } 244 245 *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 246 while (rbits < 16) { 247 *red |= *red >> rbits; 248 rbits <<= 1; 249 } 250 251 *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 252 while (gbits < 16) { 253 *green |= *green >> gbits; 254 gbits <<= 1; 255 } 256 257 *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 258 while (bbits < 16) { 259 *blue |= *blue >> bbits; 260 bbits <<= 1; 261 } 262 263 if (abits) { 264 *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 265 while (abits < 16) { 266 *alpha |= *alpha >> abits; 267 abits <<= 1; 268 } 269 } 270 else 271 *alpha = 0xffff; 272 273 return TRUE; 274} 275 276static unsigned int 277lx_get_source_color(PixmapPtr pSrc, int srcFormat, int dstFormat) 278{ 279 CARD32 in, out; 280 CARD16 red = 0, green = 0, blue = 0, alpha = 0; 281 282 /* Stall to avoid a race with the upload function */ 283 /* for 1.4 and newer, the problem will be resolved within 284 * exaGetPixmapFirstPixel, so this should be adjusted so 285 * the stall isn't run needlessly 286 */ 287 /* FIXME: xserver-1.4 with a supposed fix for this is really old, so kill the stall? */ 288 289 gp_wait_until_idle(); 290 in = exaGetPixmapFirstPixel(pSrc); 291 292 _GetRGBAFromPixel(in, &red, &blue, &green, &alpha, srcFormat); 293 _GetPixelFromRGBA(&out, red, blue, green, alpha, dstFormat); 294 295 return out; 296} 297 298static Bool 299lx_prepare_solid(PixmapPtr pxMap, int alu, Pixel planemask, Pixel fg) 300{ 301 int pitch = exaGetPixmapPitch(pxMap); 302 int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu]; 303 304 gp_declare_blt(0); 305 gp_set_bpp(pxMap->drawable.bitsPerPixel); 306 307 gp_set_raster_operation(op); 308 309 if (planemask != ~0U) 310 gp_set_solid_pattern(planemask); 311 312 exaScratch.op = op; 313 314 gp_set_solid_source(fg); 315 316 gp_set_strides(pitch, pitch); 317 gp_write_parameters(); 318 return TRUE; 319} 320 321static void 322lx_do_solid(PixmapPtr pxMap, int x1, int y1, int x2, int y2) 323{ 324 int bpp = (pxMap->drawable.bitsPerPixel + 7) / 8; 325 int pitch = exaGetPixmapPitch(pxMap); 326 unsigned int offset = exaGetPixmapOffset(pxMap) + (pitch * y1) + (bpp * x1); 327 328 gp_declare_blt(lx_fill_flags(x1, y1, x2 - x1, y2 - y1, exaScratch.op)); 329 gp_pattern_fill(offset, x2 - x1, y2 - y1); 330} 331 332static Bool 333lx_prepare_copy(PixmapPtr pxSrc, PixmapPtr pxDst, int dx, int dy, 334 int alu, Pixel planemask) 335{ 336 int dpitch = exaGetPixmapPitch(pxDst); 337 int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu]; 338 339 gp_declare_blt(0); 340 gp_set_bpp(pxDst->drawable.bitsPerPixel); 341 342 gp_set_raster_operation(op); 343 344 if (planemask != ~0U) 345 gp_set_solid_pattern(planemask); 346 347 exaScratch.srcOffset = exaGetPixmapOffset(pxSrc); 348 exaScratch.srcPitch = exaGetPixmapPitch(pxSrc); 349 exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8; 350 351 exaScratch.op = op; 352 353 gp_set_strides(dpitch, exaScratch.srcPitch); 354 gp_write_parameters(); 355 return TRUE; 356} 357 358static void 359lx_do_copy(PixmapPtr pxDst, int srcX, int srcY, 360 int dstX, int dstY, int w, int h) 361{ 362 int dstBpp = (pxDst->drawable.bitsPerPixel + 7) / 8; 363 int dstPitch = exaGetPixmapPitch(pxDst); 364 unsigned int srcOffset, dstOffset; 365 int flags = 0; 366 367 gp_declare_blt(lx_copy_flags(srcX, srcY, dstX, dstY, w, h, exaScratch.op)); 368 369 srcOffset = exaScratch.srcOffset + (exaScratch.srcPitch * srcY) + 370 (exaScratch.srcBpp) * srcX; 371 372 dstOffset = exaGetPixmapOffset(pxDst) + (dstPitch * dstY) + (dstBpp * dstX); 373 374 if (dstX > srcX) 375 flags |= CIMGP_NEGXDIR; 376 377 if (dstY > srcY) 378 flags |= CIMGP_NEGYDIR; 379 380 gp_screen_to_screen_blt(dstOffset, srcOffset, w, h, flags); 381} 382 383/* Composite operations 384 385These are the simplest - one pass operations - if there is no format or 386mask, the we can make these happen pretty fast 387 388 Operation Type Channel Alpha 389PictOpClear 0 2 0 3 390PictOpSrc 0 3 0 3 391PictOpDst 0 3 1 3 392PictOpOver 2 0 0 3 393PictOpOverReverse 2 0 1 3 394PictOpIn 0 1 0 3 395PictOpInReverse 0 1 1 3 396PictOpOut 1 0 0 3 397PictOpOutReverse 1 0 1 3 398PictOpAdd 2 2 0 3 399 400The following require multiple passes 401PictOpAtop 402PictOpXor 403*/ 404 405struct blend_ops_t { 406 int operation; 407 int type; 408 int channel; 409} lx_alpha_ops[] = { 410 /* PictOpClear */ 411 { 412 CIMGP_ALPHA_TIMES_A, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 413 }, 414 /* PictOpSrc */ 415 { 416 CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_SOURCE}, { 417 }, 418 /* PictOpDst */ 419 { 420 CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_DEST}, { 421 }, 422 /* PictOpOver */ 423 { 424 CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 425 CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 426 /* PictOpOverReverse */ 427 { 428 CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, { 429 CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 430 /* PictOpIn */ 431 { 432 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 433 CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 434 /* PictOpInReverse */ 435 { 436 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, { 437 CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 438 /* PictOpOut */ 439 { 440 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, { 441 CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 442 /* PictOpOutReverse */ 443 { 444 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 445 CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 446 /* SrcAtop */ 447 { 448 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, { 449 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 450 /* SrcAtopReverse */ 451 { 452 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 453 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, 454 /* Xor */ 455 { 456 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 457 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 458 /* PictOpAdd */ 459 { 460 CIMGP_A_PLUS_BETA_B, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 461 } 462}; 463 464#ifndef ARRAY_SIZE 465#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a)))) 466#endif 467 468static const struct exa_format_t * 469lx_get_format(PicturePtr p) 470{ 471 int i; 472 unsigned int format = p->format; 473 474 for (i = 0; i < ARRAY_SIZE(lx_exa_formats); i++) 475 if (lx_exa_formats[i].exa == format) 476 return (&lx_exa_formats[i]); 477 478 return NULL; 479} 480 481static Bool 482lx_process_transform(PicturePtr pSrc) 483{ 484 PictTransformPtr t = pSrc->transform; 485 xFixed c0 = t->matrix[0][0]; 486 xFixed s0 = t->matrix[0][1]; 487 xFixed s1 = t->matrix[1][0]; 488 xFixed c1 = t->matrix[1][1]; 489 490 /* If the transform doesn't have any rotation 491 * or scaling components, then just grab the 492 * translate coordinates */ 493 494 if (t->matrix[0][0] == 0 && 495 t->matrix[0][1] == 0 && t->matrix[1][0] == 0 && t->matrix[1][1] == 0) { 496 exaScratch.transform = pSrc->transform; 497 return TRUE; 498 } 499 500 /* Otherwise, see if this is a simple 501 * rotate transform - if it isn't, then 502 * we have to punt back to software */ 503 504 if (t->matrix[2][2] != F(1)) 505 return FALSE; 506 507 /* The rotate matrix looks like this: 508 * [ cos X -sin x 509 * sin X cos X ] 510 * 511 * Where X is the angle. We do a simple 512 * check first - if [0,0] != [1,1], then 513 * scaling was specified too, and we can 514 * bail, and if [0,1] != -[1,1] then this 515 * isn't scaling that we can handle. 516 */ 517 518 if ((c0 != c1) || (s0 != -s1)) 519 return FALSE; 520 521 /* Now, figure out what angle we want - we 522 * can only accelerate right angle rotations, 523 * so this turns into an easy set of if statements */ 524 525 if (c0 == F(1) && s1 == F(0)) 526 exaScratch.rotate = RR_Rotate_0; 527 else if (c0 == F(0) && s1 == F(1)) 528 exaScratch.rotate = RR_Rotate_90; 529 else if (c0 == F(-1) && s1 == F(0)) 530 exaScratch.rotate = RR_Rotate_180; 531 else if (c0 == F(0) && s1 == F(-1)) 532 exaScratch.rotate = RR_Rotate_270; 533 else 534 return FALSE; 535 536 exaScratch.transform = pSrc->transform; 537 538 return TRUE; 539} 540 541static Bool 542lx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst) 543{ 544 GeodeRec *pGeode = GEODEPTR_FROM_PICTURE(pDst); 545 const struct exa_format_t *srcFmt, *dstFmt; 546 547 if (op > PictOpAdd) 548 GEODE_FALLBACK(("Operation %d is not supported\n", op)); 549 550 /* XXX - don't know if we can do any hwaccel on solid fills or gradient types in generic cases */ 551 if (pMsk && pMsk->pSourcePict) 552 GEODE_FALLBACK(("%s are not supported as a mask\n", 553 pMsk->pSourcePict->type == 554 SourcePictTypeSolidFill ? "Solid pictures" : 555 "Gradients")); 556 557 if (pSrc->pSourcePict && pSrc->pSourcePict->type != SourcePictTypeSolidFill) 558 GEODE_FALLBACK(("Gradients are not supported as the source\n")); 559 560 if (pMsk && op == PictOpAdd) 561 GEODE_FALLBACK(("PictOpAdd with mask is not supported\n")); 562 563 /* FIXME: Meet this conditions from the debug for PictOpAdd. 564 * Any Other possibilities? Add a judge for the future supplement */ 565 if (op == PictOpAdd && pSrc->format == PICT_a8r8g8b8 && 566 pDst->format == PICT_a8) 567 return TRUE; 568 569 if (op == PictOpAdd && pSrc->format == PICT_x8r8g8b8 && 570 pDst->format == PICT_a8) 571 return TRUE; 572 573 if (op == PictOpAdd && pSrc->format == PICT_r5g6b5 && 574 pDst->format == PICT_a8) 575 return TRUE; 576 577 if (usesPasses(op)) { 578 /* FIXME: Slightly misleading fallback msg when !pMsk */ 579 if (pGeode->exaBfrOffset == 0 || !pMsk) 580 GEODE_FALLBACK(("Multipass operation requires off-screen buffer\n")); 581 } 582 583 /* Check that the filter matches what we support */ 584 585 switch (pSrc->filter) { 586 case PictFilterNearest: 587 case PictFilterFast: 588 case PictFilterGood: 589 case PictFilterBest: 590 break; 591 592 default: 593 GEODE_FALLBACK(("Bilinear or convolution filters are not supported\n")); 594 } 595 596 if (pMsk && pMsk->transform) 597 GEODE_FALLBACK(("Mask transforms are not supported\n")); 598 599 /* Keep an eye out for source rotation transforms - those we can 600 * do something about */ 601 602 exaScratch.rotate = RR_Rotate_0; 603 exaScratch.transform = NULL; 604 605 if (pSrc->transform && !lx_process_transform(pSrc)) 606 GEODE_FALLBACK(("Transform operation is non-trivial\n")); 607 608 /* XXX - I don't understand PICT_a8 enough - so I'm punting */ 609 if ((op != PictOpAdd) && (pSrc->format == PICT_a8 || 610 pDst->format == PICT_a8)) 611 GEODE_FALLBACK(("PICT_a8 as src or dst format is unsupported\n")); 612 613 if (pMsk && op != PictOpClear) { 614 struct blend_ops_t *opPtr = &lx_alpha_ops[op * 2]; 615 int direction = (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1; 616 617 /* Direction 0 indicates src->dst, 1 indicates dst->src */ 618 if (((direction == 0) && 619 (pSrc->pDrawable && pSrc->pDrawable->bitsPerPixel < 16)) || 620 ((direction == 1) && (pDst->pDrawable->bitsPerPixel < 16))) { 621 ErrorF("Mask blending unsupported with <16bpp\n"); 622 return FALSE; 623 } 624 if (pMsk->format != PICT_a8 && pMsk->format != PICT_a4) 625 GEODE_FALLBACK(("Masks can be only done with a 8bpp or 4bpp depth\n")); 626 627 /* The pSrc should be 1x1 pixel if the pMsk is not zero */ 628 if (pSrc->pDrawable && 629 (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1)) 630 GEODE_FALLBACK(("pSrc should be 1x1 pixel if pMsk is not zero\n")); 631 /* FIXME: In lx_prepare_composite, there are no variables to record the 632 * one pixel source's width and height when the mask is not zero. 633 * That will lead to bigger region to render instead of one pixel in lx 634 * _do_composite, so we should fallback currently to avoid this */ 635 /* Not an issue for solid pictures, because we'll treat it as 1x1R too */ 636 if (!pSrc->repeat && 637 !(pSrc->pSourcePict && 638 pSrc->pSourcePict->type == SourcePictTypeSolidFill)) { 639 GEODE_FALLBACK(("FIXME: unzero mask might lead to bigger rendering region than 1x1 pixels\n")); 640 } 641 } 642 else { 643 if (pSrc->pSourcePict) 644 GEODE_FALLBACK(("Solid source pictures without a mask are not supported\n")); 645 } 646 647 /* Get the formats for the source and destination */ 648 649 if ((srcFmt = lx_get_format(pSrc)) == NULL) 650 GEODE_FALLBACK(("Unsupported source format %x\n", pSrc->format)); 651 652 if ((dstFmt = lx_get_format(pDst)) == NULL) 653 GEODE_FALLBACK(("Unsupported destination format %x\n", pDst->format)); 654 655 /* Make sure operations that need alpha bits have them */ 656 /* If a mask is enabled, the alpha will come from there */ 657 658 if (!pMsk && (!srcFmt->alphabits && usesSrcAlpha(op))) 659 GEODE_FALLBACK(("Operation requires src alpha, but alphabits is unset\n")); 660 661 if (!pMsk && (!dstFmt->alphabits && usesDstAlpha(op))) 662 GEODE_FALLBACK(("Operation requires dst alpha, but alphabits is unset\n")); 663 664 /* FIXME: See a way around this! */ 665 if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0) 666 GEODE_FALLBACK(("src_alphabits=0, dst_alphabits!=0\n")); 667 668 /* If this is a rotate operation, then make sure the src and dst 669 * formats are the same */ 670 if (exaScratch.rotate != RR_Rotate_0 && srcFmt != dstFmt) { 671 ErrorF("EXA: Unable to rotate and convert formats at the same time\n"); 672 return FALSE; 673 } 674 return TRUE; 675} 676 677static Bool 678lx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk, 679 PicturePtr pDst, PixmapPtr pxSrc, PixmapPtr pxMsk, 680 PixmapPtr pxDst) 681{ 682 GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst); 683 const struct exa_format_t *srcFmt, *dstFmt; 684 685 /* Get the formats for the source and destination */ 686 687 srcFmt = lx_get_format(pSrc); 688 dstFmt = lx_get_format(pDst); 689 690 /* Set up the scratch buffer with the information we need */ 691 692 exaScratch.srcFormat = (struct exa_format_t *) srcFmt; 693 exaScratch.dstFormat = (struct exa_format_t *) dstFmt; 694 exaScratch.op = op; 695 exaScratch.repeat = pSrc->repeat; 696 exaScratch.bufferOffset = pGeode->exaBfrOffset; 697 698 if (pMsk && op != PictOpClear) { 699 /* Get the source color */ 700 if (pSrc->pSourcePict) { 701 exaScratch.srcColor = pSrc->pSourcePict->solidFill.color; 702 } 703 else { 704 /* If the op is PictOpOver(or PictOpOutReverse, PictOpInReverse, 705 * PictOpIn, PictOpOut, PictOpOverReverse), we should get the 706 * ARGB32 source format */ 707 708 if ((op == PictOpOver || op == PictOpOutReverse || op == 709 PictOpInReverse || op == PictOpIn || op == PictOpOut || 710 op == PictOpOverReverse) && (srcFmt->alphabits != 0)) 711 exaScratch.srcColor = exaGetPixmapFirstPixel(pxSrc); 712 else if ((op == PictOpOver || op == PictOpOutReverse || op == 713 PictOpInReverse || op == PictOpIn || op == PictOpOut || 714 op == PictOpOverReverse) && (srcFmt->alphabits == 0)) 715 exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format, 716 PICT_a8r8g8b8); 717 else 718 exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format, 719 pDst->format); 720 } 721 722 /* Save off the info we need (reuse the source values to save space) */ 723 exaScratch.type = COMP_TYPE_MASK; 724 exaScratch.maskrepeat = pMsk->repeat; 725 726 exaScratch.srcOffset = exaGetPixmapOffset(pxMsk); 727 exaScratch.srcPitch = exaGetPixmapPitch(pxMsk); 728 exaScratch.srcBpp = (pxMsk->drawable.bitsPerPixel + 7) / 8; 729 730 exaScratch.srcWidth = pMsk->pDrawable->width; 731 exaScratch.srcHeight = pMsk->pDrawable->height; 732 733 /* Flag to indicate if this a 8BPP or a 4BPP mask */ 734 exaScratch.fourBpp = (pxMsk->drawable.bitsPerPixel == 4) ? 1 : 0; 735 } 736 else { 737 if (usesPasses(op)) 738 exaScratch.type = COMP_TYPE_TWOPASS; 739 else if (exaScratch.rotate != RR_Rotate_0) 740 exaScratch.type = COMP_TYPE_ROTATE; 741 else 742 exaScratch.type = COMP_TYPE_ONEPASS; 743 744 exaScratch.srcOffset = exaGetPixmapOffset(pxSrc); 745 exaScratch.srcPitch = exaGetPixmapPitch(pxSrc); 746 exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8; 747 748 exaScratch.srcWidth = pSrc->pDrawable->width; 749 exaScratch.srcHeight = pSrc->pDrawable->height; 750 } 751 752 return TRUE; 753} 754 755static int 756lx_get_bpp_from_format(int format) 757{ 758 759 switch (format) { 760 case CIMGP_SOURCE_FMT_8_8_8_8: 761 case CIMGP_SOURCE_FMT_32BPP_BGR: 762 return 32; 763 764 case CIMGP_SOURCE_FMT_4_4_4_4: 765 return 12; 766 767 case CIMGP_SOURCE_FMT_0_5_6_5: 768 case CIMGP_SOURCE_FMT_16BPP_BGR: 769 return 16; 770 771 case CIMGP_SOURCE_FMT_1_5_5_5: 772 case CIMGP_SOURCE_FMT_15BPP_BGR: 773 return 15; 774 775 case CIMGP_SOURCE_FMT_3_3_2: 776 return 8; 777 } 778 779 return 0; 780} 781 782/* BGR needs to be set in the source for it to take - so adjust the source 783 * to enable BGR if the two formats are different, and disable it if they 784 * are the same 785 */ 786 787static void 788lx_set_source_format(int srcFormat, int dstFormat) 789{ 790 if (!(srcFormat & 0x10) && (dstFormat & 0x10)) 791 gp_set_source_format(srcFormat | 0x10); 792 else if ((srcFormat & 0x10) && (dstFormat & 0x10)) 793 gp_set_source_format(srcFormat & ~0x10); 794 else 795 gp_set_source_format(srcFormat); 796} 797 798/* If we are converting colors and we need the channel A alpha, 799 * then use a special alpha type that preserves the alpha before 800 * converting the format 801 */ 802 803static inline int 804get_op_type(struct exa_format_t *src, struct exa_format_t *dst, int type) 805{ 806 return (type == CIMGP_CHANNEL_A_ALPHA && 807 src->alphabits != dst->alphabits) ? CIMGP_CONVERTED_ALPHA : type; 808} 809 810/* Note - this is the preferred onepass method. The other will remain 811 * ifdefed out until such time that we are sure its not needed 812 */ 813 814#define GetPixmapOffset(px, x, y) ( exaGetPixmapOffset((px)) + \ 815 (exaGetPixmapPitch((px)) * (y)) + \ 816 ((((px)->drawable.bitsPerPixel + 7) / 8) * (x)) ) 817 818#define GetSrcOffset(_x, _y) (exaScratch.srcOffset + ((_y) * exaScratch.srcPitch) + \ 819 ((_x) * exaScratch.srcBpp)) 820 821static void 822lx_composite_onepass_add_a8(PixmapPtr pxDst, unsigned long dstOffset, 823 unsigned long srcOffset, int width, int height, 824 int opX, int opY, int srcX, int srcY) 825{ 826 struct blend_ops_t *opPtr; 827 int apply, type; 828 int optempX, optempY; 829 int i, j; 830 unsigned long pixmapOffset, pixmapPitch, calBitsPixel; 831 832 pixmapOffset = exaGetPixmapOffset(pxDst); 833 pixmapPitch = exaGetPixmapPitch(pxDst); 834 calBitsPixel = (pxDst->drawable.bitsPerPixel + 7) / 8; 835 836 /* Keep this GP idle judge here. Otherwise the SW method has chance to 837 * conflict with the HW rendering method */ 838 gp_wait_until_idle(); 839 840 if (opX % 4 == 0 && srcX % 4 == 0) { 841 /* HW acceleration */ 842 opPtr = &lx_alpha_ops[exaScratch.op * 2]; 843 apply = CIMGP_APPLY_BLEND_TO_ALL; 844 gp_declare_blt(0); 845 gp_set_bpp(32); 846 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 847 gp_set_source_format(8); 848 type = opPtr->type; 849 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 850 0); 851 gp_screen_to_screen_convert(dstOffset, srcOffset, width / 4, height, 0); 852 /* Calculate the pixels in the tail of each line */ 853 for (j = srcY; j < srcY + height; j++) 854 for (i = srcX + (width / 4) * 4; i < srcX + width; i++) { 855 srcOffset = GetSrcOffset(i, j); 856 optempX = opX + i - srcX; 857 optempY = opY + j - srcY; 858 dstOffset = pixmapOffset + pixmapPitch * optempY + 859 calBitsPixel * optempX; 860 *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset) 861 + *(cim_fb_ptr + dstOffset) <= 862 0xff) ? *(cim_fb_ptr + srcOffset) + 863 *(cim_fb_ptr + dstOffset) : 0xff; 864 } 865 } 866 else { 867 for (j = srcY; j < srcY + height; j++) 868 for (i = srcX; i < srcX + width; i++) { 869 srcOffset = GetSrcOffset(i, j); 870 optempX = opX + i - srcX; 871 optempY = opY + j - srcY; 872 dstOffset = pixmapOffset + pixmapPitch * optempY + 873 calBitsPixel * optempX; 874 *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset) + 875 *(cim_fb_ptr + dstOffset) <= 876 0xff) ? *(cim_fb_ptr + srcOffset) + 877 *(cim_fb_ptr + dstOffset) : 0xff; 878 } 879 } 880} 881 882static void 883lx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset, 884 unsigned long srcOffset, int width, int height) 885{ 886 struct blend_ops_t *opPtr; 887 int apply, type; 888 889 opPtr = &lx_alpha_ops[exaScratch.op * 2]; 890 891 apply = (exaScratch.dstFormat->alphabits != 0 && 892 exaScratch.srcFormat->alphabits != 0) ? 893 CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB; 894 895 gp_declare_blt(0); 896 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 897 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 898 899 lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt); 900 901 type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type); 902 903 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0); 904 905 gp_screen_to_screen_convert(dstOffset, srcOffset, width, height, 0); 906} 907 908static void 909lx_composite_all_black(unsigned long srcOffset, int width, int height) 910{ 911 struct blend_ops_t *opPtr; 912 int apply, type; 913 914 opPtr = &lx_alpha_ops[0]; 915 apply = (exaScratch.srcFormat->alphabits != 0) ? 916 CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB; 917 gp_declare_blt(0); 918 gp_set_bpp(lx_get_bpp_from_format(exaScratch.srcFormat->fmt)); 919 gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch); 920 lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.srcFormat->fmt); 921 type = get_op_type(exaScratch.srcFormat, exaScratch.srcFormat, opPtr->type); 922 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0); 923 gp_screen_to_screen_convert(srcOffset, srcOffset, width, height, 0); 924 925} 926 927static void 928lx_composite_onepass_special(PixmapPtr pxDst, int width, int height, int opX, 929 int opY, int srcX, int srcY) 930{ 931 struct blend_ops_t *opPtr; 932 int apply, type; 933 int opWidth, opHeight; 934 int optempX, optempY; 935 unsigned int dstOffset, srcOffset = 0; 936 937 optempX = opX; 938 optempY = opY; 939 940 /* Make sure srcX and srcY are in source region */ 941 srcX = ((srcX % (int) exaScratch.srcWidth) + (int) exaScratch.srcWidth) 942 % (int) exaScratch.srcWidth; 943 srcY = ((srcY % (int) exaScratch.srcHeight) + (int) exaScratch.srcHeight) 944 % (int) exaScratch.srcHeight; 945 946 opWidth = exaScratch.srcWidth - srcX; 947 opHeight = exaScratch.srcHeight - srcY; 948 949 srcOffset = GetSrcOffset(srcX, srcY); 950 951 if (width < opWidth) 952 opWidth = width; 953 if (height < opHeight) 954 opHeight = height; 955 956 while (1) { 957 gp_wait_until_idle(); 958 dstOffset = GetPixmapOffset(pxDst, optempX, optempY); 959 opPtr = &lx_alpha_ops[exaScratch.op * 2]; 960 apply = (exaScratch.dstFormat->alphabits != 0 && 961 exaScratch.srcFormat->alphabits != 0) ? 962 CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB; 963 gp_declare_blt(0); 964 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 965 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 966 lx_set_source_format(exaScratch.srcFormat->fmt, 967 exaScratch.dstFormat->fmt); 968 type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, 969 opPtr->type); 970 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, 971 apply, 0); 972 gp_screen_to_screen_convert(dstOffset, srcOffset, opWidth, opHeight, 0); 973 974 optempX += opWidth; 975 if (optempX >= opX + width) { 976 optempX = opX; 977 optempY += opHeight; 978 if (optempY >= opY + height) 979 break; 980 } 981 if (optempX == opX) { 982 srcOffset = GetSrcOffset(srcX, 0); 983 opWidth = ((opX + width) - optempX) > (exaScratch.srcWidth - srcX) 984 ? (exaScratch.srcWidth - srcX) : ((opX + width) - optempX); 985 opHeight = ((opY + height) - optempY) > exaScratch.srcHeight 986 ? exaScratch.srcHeight : ((opY + height) - optempY); 987 } 988 else if (optempY == opY) { 989 srcOffset = GetSrcOffset(0, srcY); 990 opWidth = ((opX + width) - optempX) > exaScratch.srcWidth 991 ? exaScratch.srcWidth : ((opX + width) - optempX); 992 opHeight = ((opY + height) - optempY) > (exaScratch.srcHeight - 993 srcY) 994 ? (exaScratch.srcHeight - srcY) : ((opY + height) 995 - optempY); 996 } 997 else { 998 srcOffset = GetSrcOffset(0, 0); 999 opWidth = ((opX + width) - optempX) > exaScratch.srcWidth 1000 ? exaScratch.srcWidth : ((opX + width) - optempX); 1001 opHeight = ((opY + height) - optempY) > exaScratch.srcHeight 1002 ? exaScratch.srcHeight : ((opY + height) - optempY); 1003 } 1004 } 1005} 1006 1007/* This function handles the multipass blend functions */ 1008 1009static void 1010lx_composite_multipass(PixmapPtr pxDst, unsigned long dstOffset, 1011 unsigned long srcOffset, int width, int height) 1012{ 1013 struct blend_ops_t *opPtr; 1014 int sbpp = lx_get_bpp_from_format(exaScratch.srcFormat->fmt); 1015 int apply, type; 1016 1017 /* Wait until the GP is idle - this will ensure that the scratch buffer 1018 * isn't occupied */ 1019 1020 gp_wait_until_idle(); 1021 1022 /* Copy the destination to the scratch buffer, and convert it to the 1023 * source format */ 1024 1025 gp_declare_blt(0); 1026 1027 gp_set_bpp(sbpp); 1028 gp_set_source_format(exaScratch.dstFormat->fmt); 1029 gp_set_raster_operation(0xCC); 1030 gp_set_strides(exaScratch.srcPitch, exaGetPixmapPitch(pxDst)); 1031 gp_screen_to_screen_convert(exaScratch.bufferOffset, dstOffset, 1032 width, height, 0); 1033 1034 /* Do the first blend from the source to the scratch buffer */ 1035 1036 gp_declare_blt(CIMGP_BLTFLAGS_HAZARD); 1037 gp_set_bpp(sbpp); 1038 gp_set_source_format(exaScratch.srcFormat->fmt); 1039 gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch); 1040 1041 opPtr = &lx_alpha_ops[exaScratch.op * 2]; 1042 1043 apply = (exaScratch.srcFormat->alphabits == 0) ? 1044 CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL; 1045 1046 /* If we're destroying the source alpha bits, then make sure we 1047 * use the alpha before the color conversion 1048 */ 1049 1050 gp_screen_to_screen_blt(exaScratch.bufferOffset, srcOffset, width, height, 1051 0); 1052 1053 /* Finally, do the second blend back to the destination */ 1054 1055 opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1]; 1056 1057 apply = (exaScratch.dstFormat->alphabits == 0) ? 1058 CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL; 1059 1060 gp_declare_blt(CIMGP_BLTFLAGS_HAZARD); 1061 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 1062 1063 lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt); 1064 1065 type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type); 1066 1067 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0); 1068 1069 gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset, 1070 width, height, 0); 1071} 1072 1073static void 1074lx_composite_rotate(PixmapPtr pxDst, unsigned long dstOffset, 1075 unsigned int srcOffset, int width, int height) 1076{ 1077 int degrees = 0; 1078 1079 gp_declare_blt(0); 1080 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 1081 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 1082 1083 lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt); 1084 1085 gp_set_raster_operation(0xCC); 1086 1087 /* RandR rotation is counter-clockwise, our rotation 1088 * is clockwise, so adjust the numbers accordingly */ 1089 1090 switch (exaScratch.rotate) { 1091 case RR_Rotate_90: 1092 degrees = 270; 1093 break; 1094 case RR_Rotate_180: 1095 degrees = 180; 1096 break; 1097 case RR_Rotate_270: 1098 degrees = 90; 1099 break; 1100 } 1101 1102 gp_rotate_blt(dstOffset, srcOffset, width, height, degrees); 1103} 1104 1105static void 1106lx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset, 1107 unsigned int maskOffset, int width, int height) 1108{ 1109 struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2]; 1110 1111 gp_declare_blt(0); 1112 1113 gp_set_source_format(exaScratch.srcFormat->fmt); 1114 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 1115 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 1116 gp_set_solid_source(exaScratch.srcColor); 1117 1118 gp_blend_mask_blt(dstOffset, 0, width, height, maskOffset, 1119 exaScratch.srcPitch, opPtr->operation, 1120 exaScratch.fourBpp); 1121} 1122 1123static void 1124lx_do_composite_mask_two_pass(PixmapPtr pxDst, unsigned long dstOffset, 1125 unsigned int maskOffset, int width, int height, 1126 int opX, int opY, xPointFixed srcPoint) 1127{ 1128 int apply, type; 1129 struct blend_ops_t *opPtr; 1130 int opWidth, opHeight; 1131 int opoverX, opoverY; 1132 1133 opoverX = opX; 1134 opoverY = opY; 1135 1136 /* The rendering region should not be bigger than off-screen memory size 1137 * which equals to DEFAULT_EXA_SCRATCH_BFRSZ. If that happens, we split 1138 * the PictOpOver rendering region into several 256KB chunks. And because 1139 * of the Pitch(stride) parameter, so we use maximun width of mask picture. 1140 * that is to say it is a scanline rendering process */ 1141 if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) { 1142 opWidth = width; 1143 opHeight = DEFAULT_EXA_SCRATCH_BFRSZ / (width * 4); 1144 } 1145 else { 1146 opWidth = width; 1147 opHeight = height; 1148 } 1149 1150 while (1) { 1151 1152 /* Wait until the GP is idle - this will ensure that the scratch buffer 1153 * isn't occupied */ 1154 1155 gp_wait_until_idle(); 1156 1157 /* Copy the source to the scratch buffer, and do a src * mask raster 1158 * operation */ 1159 1160 gp_declare_blt(0); 1161 opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1]; 1162 gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8); 1163 gp_set_strides(opWidth * 4, exaScratch.srcPitch); 1164 gp_set_bpp(lx_get_bpp_from_format(CIMGP_SOURCE_FMT_8_8_8_8)); 1165 gp_set_solid_source(exaScratch.srcColor); 1166 gp_blend_mask_blt(exaScratch.bufferOffset, 0, opWidth, opHeight, 1167 maskOffset, exaScratch.srcPitch, opPtr->operation, 1168 exaScratch.fourBpp); 1169 1170 /* Do a relative operation(refer rendercheck ops.c), and copy the 1171 * operation result to destination */ 1172 1173 gp_declare_blt(CIMGP_BLTFLAGS_HAZARD); 1174 opPtr = &lx_alpha_ops[exaScratch.op * 2]; 1175 apply = (exaScratch.dstFormat->alphabits == 0) ? 1176 CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL; 1177 gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8); 1178 gp_set_strides(exaGetPixmapPitch(pxDst), opWidth * 4); 1179 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 1180 type = CIMGP_CONVERTED_ALPHA; 1181 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, 1182 apply, 0); 1183 gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset, 1184 opWidth, opHeight, 0); 1185 1186 if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) { 1187 /* Finish the rendering */ 1188 if (opoverY + opHeight == opY + height) 1189 break; 1190 /* Recalculate the Dest and Mask rendering start point */ 1191 srcPoint.y = srcPoint.y + F(opHeight); 1192 opoverY = opoverY + opHeight; 1193 if (opoverY + opHeight > opY + height) 1194 opHeight = opY + height - opoverY; 1195 dstOffset = GetPixmapOffset(pxDst, opoverX, opoverY); 1196 maskOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y)); 1197 } 1198 else 1199 break; 1200 } 1201} 1202 1203static void 1204transformPoint(PictTransform * t, xPointFixed * point) 1205{ 1206 PictVector v; 1207 1208 v.vector[0] = point->x; 1209 v.vector[1] = point->y; 1210 v.vector[2] = xFixed1; 1211 1212 if (t != NULL) 1213 PictureTransformPoint(t, &v); 1214 1215 point->x = v.vector[0]; 1216 point->y = v.vector[1]; 1217} 1218 1219static void 1220lx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX, 1221 int maskY, int dstX, int dstY, int width, int height) 1222{ 1223 unsigned int dstOffset, srcOffset = 0; 1224 1225 xPointFixed srcPoint; 1226 1227 int opX = dstX; 1228 int opY = dstY; 1229 int opWidth = width; 1230 int opHeight = height; 1231 1232 /* Transform the source coordinates */ 1233 1234 if (exaScratch.type == COMP_TYPE_MASK) { 1235 srcPoint.x = F(maskX); 1236 srcPoint.y = F(maskY); 1237 } 1238 else { 1239 srcPoint.x = F(srcX); 1240 srcPoint.y = F(srcY); 1241 } 1242 1243 /* srcX, srcY point to the upper right side of the bounding box 1244 * in the unrotated coordinate space. Depending on the orientation, 1245 * we have to translate the coordinates to point to the origin of 1246 * the rectangle in the source pixmap */ 1247 1248 switch (exaScratch.rotate) { 1249 case RR_Rotate_270: 1250 srcPoint.x += F(width); 1251 1252 opWidth = height; 1253 opHeight = width; 1254 break; 1255 1256 case RR_Rotate_180: 1257 srcPoint.x += F(width); 1258 srcPoint.y += F(height); 1259 1260 srcX += width; 1261 srcY += height; 1262 break; 1263 1264 case RR_Rotate_90: 1265 srcPoint.y += F(height); 1266 1267 opWidth = height; 1268 opHeight = width; 1269 break; 1270 } 1271 1272 transformPoint(exaScratch.transform, &srcPoint); 1273 1274 /* Adjust the point to fit into the pixmap */ 1275 1276 if (I(srcPoint.x) < 0) { 1277 opWidth += I(srcPoint.x); 1278 srcPoint.x = F(0); 1279 } 1280 1281 if (I(srcPoint.y) < 0) { 1282 opHeight += I(srcPoint.y); 1283 srcPoint.y = F(0); 1284 } 1285 1286 /* Get the source point offset position */ 1287 1288 srcOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y)); 1289 1290 /* When mask exists, exaScratch.srcWidth and exaScratch.srcHeight are 1291 * the source width and source height; Otherwise, they are mask width 1292 * and mask height */ 1293 /* exaScratch.repeat is the source repeat attribute 1294 * exaScratch.maskrepeat is the mask repeat attribute */ 1295 /* If type is COMP_TYPE_MASK, maskX and maskY are not zero, we should 1296 * subtract them to do the operation in the correct region */ 1297 1298 /* FIXME: Please add the code to handle the condition when the maskX 1299 * and maskY coordinate are negative or greater than 1300 * exaScratch.srcWidth and exaScratch.srcHeight */ 1301 1302 if (exaScratch.type == COMP_TYPE_MASK) { 1303 if ((exaScratch.srcWidth - maskX) < opWidth) 1304 opWidth = exaScratch.srcWidth - maskX; 1305 if ((exaScratch.srcHeight - maskY) < opHeight) 1306 opHeight = exaScratch.srcHeight - maskY; 1307 } 1308 else { 1309 if (exaScratch.type == COMP_TYPE_ONEPASS) { 1310 /* This is the condition srcX or/and srcY is/are out of source 1311 * region */ 1312 if (((srcY >= 0 && srcY >= exaScratch.srcHeight) 1313 || (srcX >= 0 && srcX >= exaScratch.srcWidth)) && 1314 (exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)) { 1315 if (exaScratch.repeat == 1) { 1316 opWidth = width; 1317 opHeight = height; 1318 } 1319 else { 1320 if (exaScratch.op == PictOpOver) 1321 return; 1322 else { 1323 exaScratch.op = PictOpClear; 1324 opWidth = width; 1325 opHeight = height; 1326 } 1327 } 1328 /* This is the condition srcX or/and srcY is/are in the source 1329 * region */ 1330 } 1331 else if (srcX >= 0 && srcY >= 0 && 1332 (exaScratch.op == PictOpOver || 1333 exaScratch.op == PictOpSrc)) { 1334 if (exaScratch.repeat == 1) { 1335 opWidth = width; 1336 opHeight = height; 1337 } 1338 else { 1339 if ((exaScratch.srcWidth - srcX) < opWidth) 1340 opWidth = exaScratch.srcWidth - srcX; 1341 if ((exaScratch.srcHeight - srcY) < opHeight) 1342 opHeight = exaScratch.srcHeight - srcY; 1343 } 1344 /* This is the condition srcX or/and srcY is/are negative */ 1345 } 1346 else if ((srcX < 0 || srcY < 0) && 1347 (exaScratch.op == PictOpOver || 1348 exaScratch.op == PictOpSrc)) { 1349 if (exaScratch.repeat == 1) { 1350 opWidth = width; 1351 opHeight = height; 1352 } 1353 else { 1354 /* FIXME: We can't support negative srcX/Y for all corner cases in 1355 * a sane way without a bit bigger refactoring. So as to avoid 1356 * gross misrenderings (e.g missing tray icons) in current real-world 1357 * applications, just shift destination appropriately for now and 1358 * ignore out of bounds source pixmap zero-vector handling. This is 1359 * actually correct for PictOpOver, but PictOpSrc out of bounds regions 1360 * should be blacked out, but aren't - without this workaround however 1361 * it'd be simply all black instead, which is probably worse till a full 1362 * clean solution solves it for all cases. */ 1363 if (srcX < 0) { 1364 opX -= srcX; 1365 srcX = 0; 1366 } 1367 1368 if (srcY < 0) { 1369 opY -= srcY; 1370 srcY = 0; 1371 } 1372 1373 /* EXA has taken care of adjusting srcWidth if it gets cut on the right */ 1374 width = opWidth = exaScratch.srcWidth; 1375 /* EXA has taken care of adjusting srcHeight if it gets cut on the bottom */ 1376 height = opHeight = exaScratch.srcHeight; 1377 } 1378 } 1379 else { 1380 if (exaScratch.srcWidth < opWidth) 1381 opWidth = exaScratch.srcWidth; 1382 if (exaScratch.srcHeight < opHeight) 1383 opHeight = exaScratch.srcHeight; 1384 } 1385 } 1386 else { 1387 if (exaScratch.rotate == RR_Rotate_180) { 1388 } 1389 else { 1390 if ((exaScratch.srcWidth - srcY) < opWidth) 1391 opWidth = exaScratch.srcWidth - srcY; 1392 if ((exaScratch.srcHeight - srcX) < opHeight) 1393 opHeight = exaScratch.srcHeight - srcX; 1394 } 1395 } 1396 } 1397 1398 while (1) { 1399 1400 dstOffset = GetPixmapOffset(pxDst, opX, opY); 1401 1402 switch (exaScratch.type) { 1403 1404 case COMP_TYPE_MASK:{ 1405 if (exaScratch.op == PictOpOver || exaScratch.op == 1406 PictOpOutReverse || exaScratch.op == PictOpInReverse || 1407 exaScratch.op == PictOpIn || exaScratch.op == PictOpOut || 1408 exaScratch.op == PictOpOverReverse) 1409 lx_do_composite_mask_two_pass(pxDst, dstOffset, 1410 srcOffset, opWidth, opHeight, opX, 1411 opY, srcPoint); 1412 else 1413 lx_do_composite_mask(pxDst, dstOffset, srcOffset, 1414 opWidth, opHeight); 1415 } 1416 break; 1417 1418 case COMP_TYPE_ONEPASS: 1419 if ((exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc) 1420 && (exaScratch.repeat == 1)) { 1421 lx_composite_onepass_special(pxDst, opWidth, opHeight, opX, opY, 1422 srcX, srcY); 1423 return; 1424 } 1425 else if ((exaScratch.op == PictOpAdd) && (exaScratch.srcFormat->exa 1426 == PICT_a8) && 1427 (exaScratch.dstFormat->exa == PICT_a8)) 1428 lx_composite_onepass_add_a8(pxDst, dstOffset, srcOffset, 1429 opWidth, opHeight, opX, opY, srcX, 1430 srcY); 1431 else 1432 lx_composite_onepass(pxDst, dstOffset, srcOffset, opWidth, 1433 opHeight); 1434 break; 1435 1436 case COMP_TYPE_TWOPASS: 1437 lx_composite_multipass(pxDst, dstOffset, srcOffset, opWidth, 1438 opHeight); 1439 1440 case COMP_TYPE_ROTATE: 1441 lx_composite_rotate(pxDst, dstOffset, srcOffset, opWidth, opHeight); 1442 break; 1443 } 1444 1445 opX += opWidth; 1446 1447 if (opX >= dstX + width) { 1448 opX = dstX; 1449 opY += opHeight; 1450 1451 if (opY >= dstY + height) 1452 break; 1453 } 1454 1455 /* FIXME: Please add the code to handle the condition when the maskX 1456 * and maskY coordinate are negative or greater than 1457 * exaScratch.srcWidth and exaScratch.srcHeight */ 1458 1459 if (exaScratch.type == COMP_TYPE_MASK) { 1460 opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - maskX) 1461 ? (exaScratch.srcWidth - maskX) : (dstX + width) - opX; 1462 opHeight = ((dstY + height) - opY) > (exaScratch.srcHeight - maskY) 1463 ? (exaScratch.srcHeight - maskY) : (dstY + height) - opY; 1464 /* All black out of the mask */ 1465 if (!exaScratch.maskrepeat) 1466 exaScratch.srcColor = 0x0; 1467 } 1468 else { 1469 if (exaScratch.type == COMP_TYPE_ONEPASS) { 1470 if (srcX >= 0 && srcY >= 0 && (exaScratch.op == PictOpOver || 1471 exaScratch.op == PictOpSrc || 1472 exaScratch.op == PictOpClear)) { 1473 opWidth = 1474 ((dstX + width) - opX) > 1475 (exaScratch.srcWidth - srcX) ? (exaScratch.srcWidth - 1476 srcX) : (dstX + width) 1477 - opX; 1478 opHeight = ((dstY + height) - opY) > 1479 (exaScratch.srcHeight - srcY) ? 1480 (exaScratch.srcHeight - srcY) : (dstY + height) - opY; 1481 } 1482 else { 1483 opWidth = ((dstX + width) - opX) > exaScratch.srcWidth ? 1484 exaScratch.srcWidth : (dstX + width) - opX; 1485 opHeight = ((dstY + height) - opY) > exaScratch.srcHeight ? 1486 exaScratch.srcHeight : (dstY + height) - opY; 1487 } 1488 } 1489 else { 1490 opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - srcY) 1491 ? (exaScratch.srcWidth - srcY) : (dstX + width) - opX; 1492 opHeight = 1493 ((dstY + height) - opY) > 1494 (exaScratch.srcHeight - srcX) ? (exaScratch.srcHeight - 1495 srcX) : (dstY + height) - 1496 opY; 1497 } 1498 /* All black out of the source */ 1499 if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ONEPASS)) { 1500 /* FIXME: We black out the source here, so that any further regions 1501 * in the loop get handled as a source that's a zero-vector (as 1502 * defined for out-of-bounds from source pixmap for RepeatModeNone), 1503 * but this will likely interfere with cases where srcX and/or srcY 1504 * is negative - as opposed to e.g width being larger than srcWidth, 1505 * which is exercised in rendercheck (always rectangle in top-left 1506 * corner). 1507 * Additionally it forces the drawing into tiles of srcWidth/srcHeight 1508 * for non-repeat modes too, where we don't really need to tile it like 1509 * this and could draw the out of bound regions all at once (or at most 1510 * in 4 operations without the big loop). */ 1511 lx_composite_all_black(srcOffset, exaScratch.srcWidth, 1512 exaScratch.srcHeight); 1513 } 1514 if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ROTATE)) 1515 break; 1516 } 1517 } 1518} 1519 1520static void 1521lx_wait_marker(ScreenPtr PScreen, int marker) 1522{ 1523 gp_wait_until_idle(); 1524} 1525 1526static void 1527lx_done(PixmapPtr ptr) 1528{ 1529} 1530 1531#if 0 1532static void 1533lx_upload_to_screen(PixmapPtr pxDst, int x, int y, int w, int h, 1534 char *src, int src_pitch) 1535{ 1536 GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst); 1537 int dst_pitch = exaGetPixmapPitch(pxDst); 1538 int cpp = (pxDst->drawable.bitsPerPixel + 7) / 8; 1539 1540 char *dst; 1541 int offset = exaGetPixmapOffset(pxDst); 1542 1543 dst = (char *) (pGeode->FBBase + offset + (y * dst_pitch) + (x * cpp)); 1544 int i; 1545 1546 for (i = 0; i < h; i++) { 1547 memcpy(dst, src, w * cpp); 1548 dst += dst_pitch; 1549 src += src_pitch; 1550 } 1551} 1552#endif 1553 1554#if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2) 1555 1556static Bool 1557lx_exa_pixmap_is_offscreen(PixmapPtr pPixmap) 1558{ 1559 ScrnInfoPtr pScrni = xf86ScreenToScrn(pPixmap->drawable.pScreen); 1560 GeodeRec *pGeode = GEODEPTR(pScrni); 1561 void *start = (void *) (pGeode->FBBase); 1562 void *end = 1563 (void *) (pGeode->FBBase + pGeode->offscreenStart + 1564 pGeode->offscreenSize); 1565 1566 if ((void *) pPixmap->devPrivate.ptr >= start && 1567 (void *) pPixmap->devPrivate.ptr < end) 1568 return TRUE; 1569 1570 return FALSE; 1571} 1572 1573#endif 1574 1575Bool 1576LXExaInit(ScreenPtr pScreen) 1577{ 1578 ScrnInfoPtr pScrni = xf86ScreenToScrn(pScreen); 1579 GeodeRec *pGeode = GEODEPTR(pScrni); 1580 ExaDriverPtr pExa = pGeode->pExa; 1581 1582 pExa->exa_major = EXA_VERSION_MAJOR; 1583 pExa->exa_minor = EXA_VERSION_MINOR; 1584 1585 pExa->WaitMarker = lx_wait_marker; 1586 1587 pExa->PrepareSolid = lx_prepare_solid; 1588 pExa->Solid = lx_do_solid; 1589 pExa->DoneSolid = lx_done; 1590 1591 pExa->PrepareCopy = lx_prepare_copy; 1592 pExa->Copy = lx_do_copy; 1593 pExa->DoneCopy = lx_done; 1594 1595 /* Composite */ 1596 pExa->CheckComposite = lx_check_composite; 1597 pExa->PrepareComposite = lx_prepare_composite; 1598 pExa->Composite = lx_do_composite; 1599 pExa->DoneComposite = lx_done; 1600 //pExa->UploadToScreen = lx_upload_to_screen; 1601 1602#if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2) 1603 pExa->PixmapIsOffscreen = lx_exa_pixmap_is_offscreen; 1604#endif 1605 1606 //pExa->flags = EXA_OFFSCREEN_PIXMAPS; 1607 1608 return exaDriverInit(pScreen, pGeode->pExa); 1609} 1610