lx_exa.c revision f29dbc25
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 51static const struct exa_format_t 52{ 53 int exa; 54 int bpp; 55 int fmt; 56 int alphabits; 57} lx_exa_formats[] = { 58 { 59 PICT_a8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}, { 60 PICT_x8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 0}, { 61 PICT_x8b8g8r8, 32, CIMGP_SOURCE_FMT_32BPP_BGR, 0}, { 62 PICT_a4r4g4b4, 16, CIMGP_SOURCE_FMT_4_4_4_4, 4}, { 63 PICT_a1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 1}, { 64 PICT_r5g6b5, 16, CIMGP_SOURCE_FMT_0_5_6_5, 0}, { 65 PICT_b5g6r5, 16, CIMGP_SOURCE_FMT_16BPP_BGR, 0}, { 66 PICT_x1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 0}, { 67 PICT_x1b5g5r5, 16, CIMGP_SOURCE_FMT_15BPP_BGR, 0}, { 68 PICT_r3g3b2, 8, CIMGP_SOURCE_FMT_3_3_2, 0} 69}; 70 71/* This is a chunk of memory we use for scratch space */ 72 73#define COMP_TYPE_MASK 0 74#define COMP_TYPE_ONEPASS 1 75#define COMP_TYPE_TWOPASS 3 76#define COMP_TYPE_ROTATE 5 77 78static struct 79{ 80 int type; 81 82 unsigned int srcOffset; 83 unsigned int srcPitch; 84 unsigned int srcBpp; 85 unsigned int srcWidth, srcHeight; 86 PixmapPtr srcPixmap; 87 88 unsigned int srcColor; 89 int op; 90 int repeat; 91 unsigned int fourBpp; 92 unsigned int bufferOffset; 93 struct exa_format_t *srcFormat; 94 struct exa_format_t *dstFormat; 95 96 int rotate; 97 PictTransform *transform; 98 99} exaScratch; 100 101static const int SDfn[16] = { 102 0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE, 103 0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF 104}; 105 106static const int SDfn_PM[16] = { 107 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 108 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA 109}; 110 111/* These functions check to see if we can safely prefetch the memory 112 * for the blt, or if we have to wait the previous blt to complete. 113 * One function is for the fill, and the other is for the copy because 114 * they have different requirements based on ROP 115 */ 116 117static int lx0 = -1, ly0 = -1, lx1 = -1, ly1 = -1; 118 119static int 120lx_fill_flags(int x0, int y0, int w, int h, int rop) 121{ 122 int x1 = x0 + w, y1 = y0 + h; 123 int n = ((rop ^ (rop >> 1)) & 0x55) == 0 || /* no dst */ 124 x0 >= lx1 || y0 >= ly1 || /* rght/below */ 125 x1 <= lx0 || y1 <= ly0 ? /* left/above */ 126 0 : CIMGP_BLTFLAGS_HAZARD; 127 128 lx0 = x0; 129 ly0 = y0; 130 lx1 = x1; 131 ly1 = y1; 132 133 return n; 134} 135 136static int 137lx_copy_flags(int x0, int y0, int x1, int y1, int w, int h, int rop) 138{ 139 int x2 = x1 + w, y2 = y1 + h; 140 141 /* dst not hazzard and src not hazzard */ 142 int n = (((rop ^ (rop >> 1)) & 0x55) == 0 || 143 x1 >= lx1 || y1 >= ly1 || 144 x2 <= lx0 || y2 <= ly0) && 145 (((rop ^ (rop >> 2)) & 0x33) == 0 || 146 x0 >= lx1 || y0 >= ly1 || 147 x0 + w <= lx0 || y0 + h <= ly0) ? 0 : CIMGP_BLTFLAGS_HAZARD; 148 149 lx0 = x1; 150 ly0 = y1; 151 lx1 = x2; 152 ly1 = y2; 153 154 return n; 155} 156 157/* These are borrowed from the exa engine - they should be made global 158 and available to drivers, but until then.... 159*/ 160 161/* exaGetPixelFromRGBA (exa_render.c) */ 162 163static Bool 164_GetPixelFromRGBA(CARD32 * pixel, 165 CARD16 red, CARD16 green, CARD16 blue, CARD16 alpha, CARD32 format) 166{ 167 int rbits, bbits, gbits, abits; 168 int rshift, bshift, gshift, ashift; 169 170 *pixel = 0; 171 172 if (!PICT_FORMAT_COLOR(format)) 173 return FALSE; 174 175 rbits = PICT_FORMAT_R(format); 176 gbits = PICT_FORMAT_G(format); 177 bbits = PICT_FORMAT_B(format); 178 abits = PICT_FORMAT_A(format); 179 180 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 181 bshift = 0; 182 gshift = bbits; 183 rshift = gshift + gbits; 184 ashift = rshift + rbits; 185 } else { /* PICT_TYPE_ABGR */ 186 rshift = 0; 187 gshift = rbits; 188 bshift = gshift + gbits; 189 ashift = bshift + bbits; 190 } 191 192 *pixel |= (blue >> (16 - bbits)) << bshift; 193 *pixel |= (red >> (16 - rbits)) << rshift; 194 *pixel |= (green >> (16 - gbits)) << gshift; 195 *pixel |= (alpha >> (16 - abits)) << ashift; 196 197 return TRUE; 198} 199 200/* exaGetRGBAFromPixel (exa_render.c) */ 201 202static Bool 203_GetRGBAFromPixel(CARD32 pixel, 204 CARD16 * red, 205 CARD16 * green, CARD16 * blue, CARD16 * alpha, CARD32 format) 206{ 207 int rbits, bbits, gbits, abits; 208 int rshift, bshift, gshift, ashift; 209 210 if (!PICT_FORMAT_COLOR(format)) 211 return FALSE; 212 213 rbits = PICT_FORMAT_R(format); 214 gbits = PICT_FORMAT_G(format); 215 bbits = PICT_FORMAT_B(format); 216 abits = PICT_FORMAT_A(format); 217 218 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 219 bshift = 0; 220 gshift = bbits; 221 rshift = gshift + gbits; 222 ashift = rshift + rbits; 223 } else { /* PICT_TYPE_ABGR */ 224 rshift = 0; 225 gshift = rbits; 226 bshift = gshift + gbits; 227 ashift = bshift + bbits; 228 } 229 230 *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 231 while (rbits < 16) { 232 *red |= *red >> rbits; 233 rbits <<= 1; 234 } 235 236 *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 237 while (gbits < 16) { 238 *green |= *green >> gbits; 239 gbits <<= 1; 240 } 241 242 *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 243 while (bbits < 16) { 244 *blue |= *blue >> bbits; 245 bbits <<= 1; 246 } 247 248 if (abits) { 249 *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 250 while (abits < 16) { 251 *alpha |= *alpha >> abits; 252 abits <<= 1; 253 } 254 } else 255 *alpha = 0xffff; 256 257 return TRUE; 258} 259 260static unsigned int 261lx_get_source_color(PixmapPtr pSrc, int srcFormat, int dstFormat) 262{ 263 CARD32 in, out; 264 CARD16 red = 0, green = 0, blue = 0, alpha = 0; 265 266 /* Stall to avoid a race with the upload function */ 267 /* for 1.4 and newer, the problem will be resolved within 268 * exaGetPixmapFirstPixel, so this should be adjusted so 269 * the stall isn't run needlessly 270 */ 271 272 gp_wait_until_idle(); 273 in = exaGetPixmapFirstPixel(pSrc); 274 275 _GetRGBAFromPixel(in, &red, &blue, &green, &alpha, srcFormat); 276 _GetPixelFromRGBA(&out, red, blue, green, alpha, dstFormat); 277 278 return out; 279} 280 281static Bool 282lx_prepare_solid(PixmapPtr pxMap, int alu, Pixel planemask, Pixel fg) 283{ 284 int pitch = exaGetPixmapPitch(pxMap); 285 int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu]; 286 287 gp_declare_blt(0); 288 gp_set_bpp(pxMap->drawable.bitsPerPixel); 289 290 gp_set_raster_operation(op); 291 292 if (planemask != ~0U) 293 gp_set_solid_pattern(planemask); 294 295 exaScratch.op = op; 296 297 gp_set_solid_source(fg); 298 299 gp_set_strides(pitch, pitch); 300 gp_write_parameters(); 301 return TRUE; 302} 303 304static void 305lx_do_solid(PixmapPtr pxMap, int x1, int y1, int x2, int y2) 306{ 307 int bpp = (pxMap->drawable.bitsPerPixel + 7) / 8; 308 int pitch = exaGetPixmapPitch(pxMap); 309 unsigned int offset = 310 exaGetPixmapOffset(pxMap) + (pitch * y1) + (bpp * x1); 311 312 gp_declare_blt(lx_fill_flags(x1, y1, x2 - x1, y2 - y1, exaScratch.op)); 313 gp_pattern_fill(offset, x2 - x1, y2 - y1); 314} 315 316static Bool 317lx_prepare_copy(PixmapPtr pxSrc, PixmapPtr pxDst, int dx, int dy, 318 int alu, Pixel planemask) 319{ 320 int dpitch = exaGetPixmapPitch(pxDst); 321 int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu]; 322 323 gp_declare_blt(0); 324 gp_set_bpp(pxDst->drawable.bitsPerPixel); 325 326 gp_set_raster_operation(op); 327 328 if (planemask != ~0U) 329 gp_set_solid_pattern(planemask); 330 331 exaScratch.srcOffset = exaGetPixmapOffset(pxSrc); 332 exaScratch.srcPitch = exaGetPixmapPitch(pxSrc); 333 exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8; 334 335 exaScratch.op = op; 336 337 gp_set_strides(dpitch, exaScratch.srcPitch); 338 gp_write_parameters(); 339 return TRUE; 340} 341 342static void 343lx_do_copy(PixmapPtr pxDst, int srcX, int srcY, 344 int dstX, int dstY, int w, int h) 345{ 346 int dstBpp = (pxDst->drawable.bitsPerPixel + 7) / 8; 347 int dstPitch = exaGetPixmapPitch(pxDst); 348 unsigned int srcOffset, dstOffset; 349 int flags = 0; 350 351 gp_declare_blt(lx_copy_flags(srcX, srcY, dstX, dstY, w, h, 352 exaScratch.op)); 353 354 srcOffset = exaScratch.srcOffset + (exaScratch.srcPitch * srcY) + 355 (exaScratch.srcBpp) * srcX; 356 357 dstOffset = exaGetPixmapOffset(pxDst) + 358 (dstPitch * dstY) + (dstBpp * dstX); 359 360 if (dstX > srcX) 361 flags |= CIMGP_NEGXDIR; 362 363 if (dstY > srcY) 364 flags |= CIMGP_NEGYDIR; 365 366 gp_screen_to_screen_blt(dstOffset, srcOffset, w, h, flags); 367} 368 369/* Composite operations 370 371These are the simplest - one pass operations - if there is no format or 372mask, the we can make these happen pretty fast 373 374 Operation Type Channel Alpha 375PictOpClear 0 2 0 3 376PictOpSrc 0 3 0 3 377PictOpDst 0 3 1 3 378PictOpOver 2 0 0 3 379PictOpOverReverse 2 0 1 3 380PictOpIn 0 1 0 3 381PictOpInReverse 0 1 1 3 382PictOpOut 1 0 0 3 383PictOpOutReverse 1 0 1 3 384PictOpAdd 2 2 0 3 385 386The following require multiple passes 387PictOpAtop 388PictOpXor 389*/ 390 391struct blend_ops_t 392{ 393 int operation; 394 int type; 395 int channel; 396} lx_alpha_ops[] = { 397 /* PictOpClear */ 398 { 399 CIMGP_ALPHA_TIMES_A, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 400 }, 401 /* PictOpSrc */ 402 { 403 CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_SOURCE}, { 404 }, 405 /* PictOpDst */ 406 { 407 CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_DEST}, { 408 }, 409 /* PictOpOver */ 410 { 411 CIMGP_ALPHA_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 412 { 413 }, 414 /* PictOpOverReverse */ 415 { 416 CIMGP_ALPHA_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, { 417 }, 418 /* PictOpIn */ 419 { 420 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 421 }, 422 /* PictOpInReverse */ 423 { 424 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, { 425 }, 426 /* PictOpOut */ 427 { 428 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 429 }, 430 /* PictOpOutReverse */ 431 { 432 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, { 433 }, 434 /* SrcAtop */ 435 { 436 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, { 437 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 438 /* SrcAtopReverse */ 439 { 440 CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 441 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, 442 /* Xor */ 443 { 444 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 445 CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, 446 /* PictOpAdd */ 447 { 448 CIMGP_A_PLUS_BETA_B, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, { 449 } 450}; 451 452#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a)))) 453 454static const struct exa_format_t * 455lx_get_format(PicturePtr p) 456{ 457 int i; 458 unsigned int format = p->format; 459 460 for (i = 0; i < ARRAY_SIZE(lx_exa_formats); i++) { 461 462 if (lx_exa_formats[i].bpp < PICT_FORMAT_BPP(format)) 463 break; 464 else if (lx_exa_formats[i].bpp != PICT_FORMAT_BPP(format)) 465 continue; 466 467 if (lx_exa_formats[i].exa == format) 468 return (&lx_exa_formats[i]); 469 } 470 471 return NULL; 472} 473 474static Bool 475lx_process_transform(PicturePtr pSrc) 476{ 477 PictTransformPtr t = pSrc->transform; 478 xFixed c0 = t->matrix[0][0]; 479 xFixed s0 = t->matrix[0][1]; 480 xFixed s1 = t->matrix[1][0]; 481 xFixed c1 = t->matrix[1][1]; 482 483 /* If the transform doesn't have any rotation 484 * or scaling components, then just grab the 485 * translate coordinates */ 486 487 if (t->matrix[0][0] == 0 && 488 t->matrix[0][1] == 0 && 489 t->matrix[1][0] == 0 && t->matrix[1][1] == 0) { 490 exaScratch.transform = pSrc->transform; 491 return TRUE; 492 } 493 494 /* Otherwise, see if this is a simple 495 * rotate transform - if it isn't, then 496 * we have to punt back to software */ 497 498 if (t->matrix[2][2] != F(1)) 499 return FALSE; 500 501 /* The rotate matrix looks like this: 502 * [ cos X -sin x 503 * sin X cos X ] 504 * 505 * Where X is the angle. We do a simple 506 * check first - if [0,0] != [1,1], then 507 * scaling was specified too, and we can 508 * bail, and if [0,1] != -[1,1] then this 509 * isn't scaling that we can handle. 510 */ 511 512 if ((c0 != c1) || (s0 != -s1)) 513 return FALSE; 514 515 /* Now, figure out what angle we want - we 516 * can only accelerate right angle rotations, 517 * so this turns into an easy set of if statements */ 518 519 if (c0 == F(1) && s1 == F(0)) 520 exaScratch.rotate = RR_Rotate_0; 521 else if (c0 == F(0) && s1 == F(1)) 522 exaScratch.rotate = RR_Rotate_90; 523 else if (c0 == F(-1) && s1 == F(0)) 524 exaScratch.rotate = RR_Rotate_180; 525 else if (c0 == F(0) && s1 == F(-1)) 526 exaScratch.rotate = RR_Rotate_270; 527 else 528 return FALSE; 529 530 exaScratch.transform = pSrc->transform; 531 532 return TRUE; 533} 534 535static Bool 536lx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst) 537{ 538 GeodeRec *pGeode = GEODEPTR_FROM_PICTURE(pDst); 539 540 /* Check that the operation is supported */ 541 542 if (op > PictOpAdd) 543 return FALSE; 544 545 if (usesPasses(op)) { 546 if (pGeode->exaBfrOffset == 0 || !pMsk) 547 return FALSE; 548 } 549 550 if (pMsk && op == PictOpAdd) 551 return FALSE; 552 553 /* Check that the filter matches what we support */ 554 555 switch (pSrc->filter) { 556 case PictFilterNearest: 557 case PictFilterFast: 558 case PictFilterGood: 559 case PictFilterBest: 560 break; 561 562 default: 563 /* WE don't support bilinear or convolution filters */ 564 return FALSE; 565 } 566 567 /* We don't support any mask transforms */ 568 if (pMsk && pMsk->transform) 569 return FALSE; 570 571 /* Keep an eye out for source rotation transforms - those we can 572 * do something about */ 573 574 exaScratch.rotate = RR_Rotate_0; 575 exaScratch.transform = NULL; 576 577 if (pSrc->transform && !lx_process_transform(pSrc)) 578 return FALSE; 579 580 /* XXX - I don't understand PICT_a8 enough - so I'm punting */ 581 582 if (pSrc->format == PICT_a8 || pDst->format == PICT_a8) 583 return FALSE; 584 585 if (pMsk && op != PictOpClear) { 586 /* We can only do masks with a 8bpp or a 4bpp mask */ 587 if (pMsk->format != PICT_a8 && pMsk->format != PICT_a4) 588 return FALSE; 589 } 590 591 return TRUE; 592} 593 594static Bool 595lx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk, 596 PicturePtr pDst, PixmapPtr pxSrc, PixmapPtr pxMsk, PixmapPtr pxDst) 597{ 598 GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst); 599 const struct exa_format_t *srcFmt, *dstFmt; 600 601 /* Get the formats for the source and destination */ 602 603 if ((srcFmt = lx_get_format(pSrc)) == NULL) { 604 ErrorF("EXA: Invalid source format %x\n", pSrc->format); 605 return FALSE; 606 } 607 608 if ((dstFmt = lx_get_format(pDst)) == NULL) { 609 ErrorF("EXA: Invalid destination format %x\n", pDst->format); 610 return FALSE; 611 } 612 613 /* Make sure operations that need alpha bits have them */ 614 /* If a mask is enabled, the alpha will come from there */ 615 616 if (!pMsk && (!srcFmt->alphabits && usesSrcAlpha(op))) 617 return FALSE; 618 619 if (!pMsk && (!dstFmt->alphabits && usesDstAlpha(op))) 620 return FALSE; 621 622 /* FIXME: See a way around this! */ 623 624 if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0) 625 return FALSE; 626 627 /* If this is a rotate operation, then make sure the src and dst 628 * formats are the same */ 629 630 if (exaScratch.rotate != RR_Rotate_0 && srcFmt != dstFmt) { 631 ErrorF("EXA: Can't rotate and convert formats at the same time\n"); 632 return FALSE; 633 } 634 635 /* Set up the scratch buffer with the information we need */ 636 637 exaScratch.srcFormat = (struct exa_format_t *)srcFmt; 638 exaScratch.dstFormat = (struct exa_format_t *)dstFmt; 639 exaScratch.op = op; 640 exaScratch.repeat = pSrc->repeat; 641 exaScratch.bufferOffset = pGeode->exaBfrOffset; 642 643 if (pMsk && op != PictOpClear) { 644 struct blend_ops_t *opPtr = &lx_alpha_ops[op * 2]; 645 int direction = (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1; 646 647 /* Direction 0 indicates src->dst, 1 indiates dst->src */ 648 649 if (((direction == 0) && (pxSrc->drawable.bitsPerPixel < 16)) || 650 ((direction == 1) && (pxDst->drawable.bitsPerPixel < 16))) { 651 ErrorF("Can't do mask blending with less then 16bpp\n"); 652 return FALSE; 653 } 654 655 /* Get the source color */ 656 657 if (direction == 0) 658 exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format, 659 pDst->format); 660 else 661 exaScratch.srcColor = lx_get_source_color(pxDst, pDst->format, 662 pSrc->format); 663 664 /* FIXME: What to do here? */ 665 666 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) 667 return FALSE; 668 669 /* Save off the info we need (reuse the source values to save space) */ 670 671 exaScratch.type = COMP_TYPE_MASK; 672 673 exaScratch.srcOffset = exaGetPixmapOffset(pxMsk); 674 exaScratch.srcPitch = exaGetPixmapPitch(pxMsk); 675 exaScratch.srcBpp = (pxMsk->drawable.bitsPerPixel + 7) / 8; 676 677 exaScratch.srcWidth = pMsk->pDrawable->width; 678 exaScratch.srcHeight = pMsk->pDrawable->height; 679 680 /* Flag to indicate if this a 8BPP or a 4BPP mask */ 681 exaScratch.fourBpp = (pxMsk->drawable.bitsPerPixel == 4) ? 1 : 0; 682 683 /* If the direction is reversed, then remember the source */ 684 685 if (direction == 1) 686 exaScratch.srcPixmap = pxSrc; 687 } else { 688 if (usesPasses(op)) 689 exaScratch.type = COMP_TYPE_TWOPASS; 690 else if (exaScratch.rotate != RR_Rotate_0) 691 exaScratch.type = COMP_TYPE_ROTATE; 692 else 693 exaScratch.type = COMP_TYPE_ONEPASS; 694 695 exaScratch.srcOffset = exaGetPixmapOffset(pxSrc); 696 exaScratch.srcPitch = exaGetPixmapPitch(pxSrc); 697 exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8; 698 699 exaScratch.srcWidth = pSrc->pDrawable->width; 700 exaScratch.srcHeight = pSrc->pDrawable->height; 701 } 702 703 return TRUE; 704} 705 706static int 707lx_get_bpp_from_format(int format) 708{ 709 710 switch (format) { 711 case CIMGP_SOURCE_FMT_8_8_8_8: 712 case CIMGP_SOURCE_FMT_32BPP_BGR: 713 return 32; 714 715 case CIMGP_SOURCE_FMT_4_4_4_4: 716 return 12; 717 718 case CIMGP_SOURCE_FMT_0_5_6_5: 719 case CIMGP_SOURCE_FMT_16BPP_BGR: 720 return 16; 721 722 case CIMGP_SOURCE_FMT_1_5_5_5: 723 case CIMGP_SOURCE_FMT_15BPP_BGR: 724 return 15; 725 726 case CIMGP_SOURCE_FMT_3_3_2: 727 return 8; 728 } 729 730 return 0; 731} 732 733/* BGR needs to be set in the source for it to take - so adjust the source 734 * to enable BGR if the two formats are different, and disable it if they 735 * are the same 736 */ 737 738static void 739lx_set_source_format(int srcFormat, int dstFormat) 740{ 741 if (!(srcFormat & 0x10) && (dstFormat & 0x10)) 742 gp_set_source_format(srcFormat | 0x10); 743 else if ((srcFormat & 0x10) && (dstFormat & 0x10)) 744 gp_set_source_format(srcFormat & ~0x10); 745 else 746 gp_set_source_format(srcFormat); 747} 748 749/* If we are converting colors and we need the channel A alpha, 750 * then use a special alpha type that preserves the alpha before 751 * converting the format 752 */ 753 754static inline int 755get_op_type(struct exa_format_t *src, struct exa_format_t *dst, int type) 756{ 757 return (type == CIMGP_CHANNEL_A_ALPHA && 758 src->alphabits != dst->alphabits) ? CIMGP_CONVERTED_ALPHA : type; 759} 760 761/* Note - this is the preferred onepass method. The other will remain 762 * ifdefed out until such time that we are sure its not needed 763 */ 764 765static void 766lx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset, 767 unsigned long srcOffset, int width, int height) 768{ 769 struct blend_ops_t *opPtr; 770 int apply, type; 771 772 opPtr = &lx_alpha_ops[exaScratch.op * 2]; 773 774 apply = (exaScratch.dstFormat->alphabits != 0 && 775 exaScratch.srcFormat->alphabits != 0) ? 776 CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB; 777 778 gp_declare_blt(0); 779 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 780 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 781 782 lx_set_source_format(exaScratch.srcFormat->fmt, 783 exaScratch.dstFormat->fmt); 784 785 type = 786 get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type); 787 788 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0); 789 790 gp_screen_to_screen_convert(dstOffset, srcOffset, width, height, 0); 791} 792 793/* This function handles the multipass blend functions */ 794 795static void 796lx_composite_multipass(PixmapPtr pxDst, unsigned long dstOffset, 797 unsigned long srcOffset, int width, int height) 798{ 799 struct blend_ops_t *opPtr; 800 int sbpp = lx_get_bpp_from_format(exaScratch.srcFormat->fmt); 801 int apply, type; 802 803 /* Wait until the GP is idle - this will ensure that the scratch buffer 804 * isn't occupied */ 805 806 gp_wait_until_idle(); 807 808 /* Copy the destination to the scratch buffer, and convert it to the 809 * source format */ 810 811 gp_declare_blt(0); 812 813 gp_set_bpp(sbpp); 814 gp_set_source_format(exaScratch.dstFormat->fmt); 815 gp_set_raster_operation(0xCC); 816 gp_set_strides(exaScratch.srcPitch, exaGetPixmapPitch(pxDst)); 817 gp_screen_to_screen_convert(exaScratch.bufferOffset, dstOffset, 818 width, height, 0); 819 820 /* Do the first blend from the source to the scratch buffer */ 821 822 gp_declare_blt(CIMGP_BLTFLAGS_HAZARD); 823 gp_set_bpp(sbpp); 824 gp_set_source_format(exaScratch.srcFormat->fmt); 825 gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch); 826 827 opPtr = &lx_alpha_ops[exaScratch.op * 2]; 828 829 apply = (exaScratch.srcFormat->alphabits == 0) ? 830 CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL; 831 832 /* If we're destroying the source alpha bits, then make sure we 833 * use the alpha before the color conversion 834 */ 835 836 gp_screen_to_screen_blt(exaScratch.bufferOffset, srcOffset, width, height, 837 0); 838 839 /* Finally, do the second blend back to the destination */ 840 841 opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1]; 842 843 apply = (exaScratch.dstFormat->alphabits == 0) ? 844 CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL; 845 846 gp_declare_blt(CIMGP_BLTFLAGS_HAZARD); 847 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 848 849 lx_set_source_format(exaScratch.srcFormat->fmt, 850 exaScratch.dstFormat->fmt); 851 852 type = 853 get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type); 854 855 gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0); 856 857 gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset, 858 width, height, 0); 859} 860 861static void 862lx_composite_rotate(PixmapPtr pxDst, unsigned long dstOffset, 863 unsigned int srcOffset, int width, int height) 864{ 865 int degrees = 0; 866 867 gp_declare_blt(0); 868 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 869 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 870 871 lx_set_source_format(exaScratch.srcFormat->fmt, 872 exaScratch.dstFormat->fmt); 873 874 gp_set_raster_operation(0xCC); 875 876 /* RandR rotation is counter-clockwise, our rotation 877 * is clockwise, so adjust the numbers accordingly */ 878 879 switch (exaScratch.rotate) { 880 case RR_Rotate_90: 881 degrees = 270; 882 break; 883 case RR_Rotate_180: 884 degrees = 180; 885 break; 886 case RR_Rotate_270: 887 degrees = 90; 888 break; 889 } 890 891 gp_rotate_blt(dstOffset, srcOffset, width, height, degrees); 892} 893 894static void 895lx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset, 896 unsigned int maskOffset, int width, int height) 897{ 898 struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2]; 899 900 gp_declare_blt(0); 901 902 gp_set_source_format(exaScratch.srcFormat->fmt); 903 gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch); 904 gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt)); 905 gp_set_solid_source(exaScratch.srcColor); 906 907 gp_blend_mask_blt(dstOffset, 0, width, height, maskOffset, 908 exaScratch.srcPitch, opPtr->operation, exaScratch.fourBpp); 909} 910 911#define GetPixmapOffset(px, x, y) ( exaGetPixmapOffset((px)) + \ 912 (exaGetPixmapPitch((px)) * (y)) + \ 913 ((((px)->drawable.bitsPerPixel + 7) / 8) * (x)) ) 914 915#define GetSrcOffset(_x, _y) (exaScratch.srcOffset + ((_y) * exaScratch.srcPitch) + \ 916 ((_x) * exaScratch.srcBpp)) 917 918static void 919transformPoint(PictTransform * t, xPointFixed * point) 920{ 921 PictVector v; 922 923 v.vector[0] = point->x; 924 v.vector[1] = point->y; 925 v.vector[2] = xFixed1; 926 927 if (t != NULL) 928 PictureTransformPoint(t, &v); 929 930 point->x = v.vector[0]; 931 point->y = v.vector[1]; 932} 933 934static void 935lx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX, 936 int maskY, int dstX, int dstY, int width, int height) 937{ 938 struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2]; 939 940 unsigned int dstOffset, srcOffset = 0; 941 942 xPointFixed srcPoint; 943 944 int opX = dstX; 945 int opY = dstY; 946 int opWidth = width; 947 int opHeight = height; 948 949 /* Transform the source coordinates */ 950 951 if (exaScratch.type == COMP_TYPE_MASK) { 952 srcPoint.x = F(maskX); 953 srcPoint.y = F(maskY); 954 } else { 955 srcPoint.x = F(srcX); 956 srcPoint.y = F(srcY); 957 } 958 959 /* srcX, srcY point to the upper right side of the bounding box 960 * in the unrotated coordinate space. Depending on the orientation, 961 * we have to translate the coordinates to point to the origin of 962 * the rectangle in the source pixmap */ 963 964 switch (exaScratch.rotate) { 965 case RR_Rotate_270: 966 srcPoint.x += F(width); 967 968 opWidth = height; 969 opHeight = width; 970 break; 971 972 case RR_Rotate_180: 973 srcPoint.x += F(width); 974 srcPoint.y += F(height); 975 976 srcX += width; 977 srcY += height; 978 break; 979 980 case RR_Rotate_90: 981 srcPoint.y += F(height); 982 983 opWidth = height; 984 opHeight = width; 985 break; 986 } 987 988 transformPoint(exaScratch.transform, &srcPoint); 989 990 /* Adjust the point to fit into the pixmap */ 991 992 if (I(srcPoint.x) < 0) { 993 opWidth += I(srcPoint.x); 994 srcPoint.x = F(0); 995 } 996 997 if (I(srcPoint.y) < 0) { 998 opHeight += I(srcPoint.y); 999 srcPoint.y = F(0); 1000 } 1001 1002 srcOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y)); 1003 1004 if (exaScratch.srcWidth < opWidth) 1005 opWidth = exaScratch.srcWidth; 1006 1007 if (exaScratch.srcHeight < opHeight) 1008 opHeight = exaScratch.srcHeight; 1009 1010 while (1) { 1011 1012 dstOffset = GetPixmapOffset(pxDst, opX, opY); 1013 1014 switch (exaScratch.type) { 1015 1016 case COMP_TYPE_MASK:{ 1017 int direction = 1018 (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1; 1019 1020 if (direction == 1) { 1021 dstOffset = 1022 GetPixmapOffset(exaScratch.srcPixmap, opX, opY); 1023 lx_do_composite_mask(exaScratch.srcPixmap, dstOffset, 1024 srcOffset, opWidth, opHeight); 1025 } else { 1026 lx_do_composite_mask(pxDst, dstOffset, srcOffset, opWidth, 1027 opHeight); 1028 } 1029 } 1030 break; 1031 1032 case COMP_TYPE_ONEPASS: 1033 lx_composite_onepass(pxDst, dstOffset, srcOffset, opWidth, 1034 opHeight); 1035 break; 1036 1037 case COMP_TYPE_TWOPASS: 1038 lx_composite_multipass(pxDst, dstOffset, srcOffset, opWidth, 1039 opHeight); 1040 1041 case COMP_TYPE_ROTATE: 1042 lx_composite_rotate(pxDst, dstOffset, srcOffset, opWidth, 1043 opHeight); 1044 break; 1045 } 1046 1047 if (!exaScratch.repeat) 1048 break; 1049 1050 opX += opWidth; 1051 1052 if (opX >= dstX + width) { 1053 opX = dstX; 1054 opY += opHeight; 1055 1056 if (opY >= dstY + height) 1057 break; 1058 } 1059 1060 opWidth = ((dstX + width) - opX) > exaScratch.srcWidth ? 1061 exaScratch.srcWidth : (dstX + width) - opX; 1062 opHeight = ((dstY + height) - opY) > exaScratch.srcHeight ? 1063 exaScratch.srcHeight : (dstY + height) - opY; 1064 } 1065} 1066 1067static void 1068lx_wait_marker(ScreenPtr PScreen, int marker) 1069{ 1070 gp_wait_until_idle(); 1071} 1072 1073static void 1074lx_done(PixmapPtr ptr) 1075{ 1076} 1077 1078#if 0 1079static void 1080lx_upload_to_screen(PixmapPtr pxDst, int x, int y, int w, int h, 1081 char *src, int src_pitch) 1082{ 1083 GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst); 1084 int dst_pitch = exaGetPixmapPitch(pxDst); 1085 int cpp = (pxDst->drawable.bitsPerPixel + 7) / 8; 1086 1087 char *dst; 1088 int offset = exaGetPixmapOffset(pxDst); 1089 1090 dst = (char *)(pGeode->FBBase + offset + (y * dst_pitch) + (x * cpp)); 1091 int i; 1092 1093 for (i = 0; i < h; i++) { 1094 memcpy(dst, src, w * cpp); 1095 dst += dst_pitch; 1096 src += src_pitch; 1097 } 1098} 1099#endif 1100 1101#if EXA_VERSION_MINOR >= 2 1102 1103static Bool 1104lx_exa_pixmap_is_offscreen(PixmapPtr pPixmap) 1105{ 1106 ScrnInfoPtr pScrni = xf86Screens[pPixmap->drawable.pScreen->myNum]; 1107 GeodeRec *pGeode = GEODEPTR(pScrni); 1108 void *start = (void *)(pGeode->FBBase); 1109 void *end = 1110 (void *)(pGeode->FBBase + pGeode->offscreenStart + 1111 pGeode->offscreenSize); 1112 1113 if ((void *)pPixmap->devPrivate.ptr >= start && 1114 (void *)pPixmap->devPrivate.ptr < end) 1115 return TRUE; 1116 1117 return FALSE; 1118} 1119 1120#endif 1121 1122Bool 1123LXExaInit(ScreenPtr pScreen) 1124{ 1125 ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum]; 1126 GeodeRec *pGeode = GEODEPTR(pScrni); 1127 ExaDriverPtr pExa = pGeode->pExa; 1128 1129 pExa->exa_major = EXA_VERSION_MAJOR; 1130 pExa->exa_minor = EXA_VERSION_MINOR; 1131 1132 pExa->WaitMarker = lx_wait_marker; 1133 1134 pExa->PrepareSolid = lx_prepare_solid; 1135 pExa->Solid = lx_do_solid; 1136 pExa->DoneSolid = lx_done; 1137 1138 pExa->PrepareCopy = lx_prepare_copy; 1139 pExa->Copy = lx_do_copy; 1140 pExa->DoneCopy = lx_done; 1141 1142 /* Composite */ 1143 pExa->CheckComposite = lx_check_composite; 1144 pExa->PrepareComposite = lx_prepare_composite; 1145 pExa->Composite = lx_do_composite; 1146 pExa->DoneComposite = lx_done; 1147 //pExa->UploadToScreen = lx_upload_to_screen; 1148 1149#if EXA_VERSION_MINOR >= 2 1150 pExa->PixmapIsOffscreen = lx_exa_pixmap_is_offscreen; 1151#endif 1152 1153 //pExa->flags = EXA_OFFSCREEN_PIXMAPS; 1154 1155 return exaDriverInit(pScreen, pGeode->pExa); 1156} 1157