First import
[xorg_rtime.git] / xorg-server-1.4 / exa / exa_render.c
blob2dd3fc1cee8928b51081e645dd8657631d5b140a
1 /*
2 * Copyright © 2001 Keith Packard
4 * Partly based on code that is Copyright © The XFree86 Project Inc.
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
25 #ifdef HAVE_DIX_CONFIG_H
26 #include <dix-config.h>
27 #endif
29 #include <stdlib.h>
31 #include "exa_priv.h"
33 #ifdef RENDER
34 #include "mipict.h"
36 #if DEBUG_TRACE_FALL
37 static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
39 char format[20];
40 char size[20];
41 char loc;
42 int temp;
44 if (!pict) {
45 snprintf(string, n, "None");
46 return;
49 switch (pict->format)
51 case PICT_a8r8g8b8:
52 snprintf(format, 20, "ARGB8888");
53 break;
54 case PICT_r5g6b5:
55 snprintf(format, 20, "RGB565 ");
56 break;
57 case PICT_x1r5g5b5:
58 snprintf(format, 20, "RGB555 ");
59 break;
60 case PICT_a8:
61 snprintf(format, 20, "A8 ");
62 break;
63 case PICT_a1:
64 snprintf(format, 20, "A1 ");
65 break;
66 default:
67 snprintf(format, 20, "0x%x", (int)pict->format);
68 break;
71 loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
73 snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
74 pict->pDrawable->height, pict->repeat ?
75 " R" : "");
77 snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size);
80 static void
81 exaPrintCompositeFallback(CARD8 op,
82 PicturePtr pSrc,
83 PicturePtr pMask,
84 PicturePtr pDst)
86 char sop[20];
87 char srcdesc[40], maskdesc[40], dstdesc[40];
89 switch(op)
91 case PictOpSrc:
92 sprintf(sop, "Src");
93 break;
94 case PictOpOver:
95 sprintf(sop, "Over");
96 break;
97 default:
98 sprintf(sop, "0x%x", (int)op);
99 break;
102 exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
103 exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
104 exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
106 ErrorF("Composite fallback: op %s, \n"
107 " src %s, \n"
108 " mask %s, \n"
109 " dst %s, \n",
110 sop, srcdesc, maskdesc, dstdesc);
112 #endif /* DEBUG_TRACE_FALL */
114 static Bool
115 exaOpReadsDestination (CARD8 op)
117 /* FALSE (does not read destination) is the list of ops in the protocol
118 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
119 * That's just Clear and Src. ReduceCompositeOp() will already have
120 * converted con/disjoint clear/src to Clear or Src.
122 switch (op) {
123 case PictOpClear:
124 case PictOpSrc:
125 return FALSE;
126 default:
127 return TRUE;
132 static Bool
133 exaGetPixelFromRGBA(CARD32 *pixel,
134 CARD16 red,
135 CARD16 green,
136 CARD16 blue,
137 CARD16 alpha,
138 CARD32 format)
140 int rbits, bbits, gbits, abits;
141 int rshift, bshift, gshift, ashift;
143 *pixel = 0;
145 if (!PICT_FORMAT_COLOR(format))
146 return FALSE;
148 rbits = PICT_FORMAT_R(format);
149 gbits = PICT_FORMAT_G(format);
150 bbits = PICT_FORMAT_B(format);
151 abits = PICT_FORMAT_A(format);
153 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
154 bshift = 0;
155 gshift = bbits;
156 rshift = gshift + gbits;
157 ashift = rshift + rbits;
158 } else { /* PICT_TYPE_ABGR */
159 rshift = 0;
160 gshift = rbits;
161 bshift = gshift + gbits;
162 ashift = bshift + bbits;
165 *pixel |= ( blue >> (16 - bbits)) << bshift;
166 *pixel |= ( red >> (16 - rbits)) << rshift;
167 *pixel |= (green >> (16 - gbits)) << gshift;
168 *pixel |= (alpha >> (16 - abits)) << ashift;
170 return TRUE;
173 static Bool
174 exaGetRGBAFromPixel(CARD32 pixel,
175 CARD16 *red,
176 CARD16 *green,
177 CARD16 *blue,
178 CARD16 *alpha,
179 CARD32 format)
181 int rbits, bbits, gbits, abits;
182 int rshift, bshift, gshift, ashift;
184 if (!PICT_FORMAT_COLOR(format))
185 return FALSE;
187 rbits = PICT_FORMAT_R(format);
188 gbits = PICT_FORMAT_G(format);
189 bbits = PICT_FORMAT_B(format);
190 abits = PICT_FORMAT_A(format);
192 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
193 bshift = 0;
194 gshift = bbits;
195 rshift = gshift + gbits;
196 ashift = rshift + rbits;
197 } else { /* PICT_TYPE_ABGR */
198 rshift = 0;
199 gshift = rbits;
200 bshift = gshift + gbits;
201 ashift = bshift + bbits;
204 *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
205 while (rbits < 16) {
206 *red |= *red >> rbits;
207 rbits <<= 1;
210 *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
211 while (gbits < 16) {
212 *green |= *green >> gbits;
213 gbits <<= 1;
216 *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
217 while (bbits < 16) {
218 *blue |= *blue >> bbits;
219 bbits <<= 1;
222 if (abits) {
223 *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
224 while (abits < 16) {
225 *alpha |= *alpha >> abits;
226 abits <<= 1;
228 } else
229 *alpha = 0xffff;
231 return TRUE;
234 static int
235 exaTryDriverSolidFill(PicturePtr pSrc,
236 PicturePtr pDst,
237 INT16 xSrc,
238 INT16 ySrc,
239 INT16 xDst,
240 INT16 yDst,
241 CARD16 width,
242 CARD16 height)
244 ExaScreenPriv (pDst->pDrawable->pScreen);
245 RegionRec region;
246 BoxPtr pbox;
247 int nbox;
248 int dst_off_x, dst_off_y;
249 PixmapPtr pSrcPix, pDstPix;
250 CARD32 pixel;
251 CARD16 red, green, blue, alpha;
252 ExaMigrationRec pixmaps[1];
254 xDst += pDst->pDrawable->x;
255 yDst += pDst->pDrawable->y;
256 xSrc += pSrc->pDrawable->x;
257 ySrc += pSrc->pDrawable->y;
259 if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
260 xSrc, ySrc, 0, 0, xDst, yDst,
261 width, height))
262 return 1;
264 pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
265 pixel = exaGetPixmapFirstPixel (pSrcPix);
267 pixmaps[0].as_dst = TRUE;
268 pixmaps[0].as_src = FALSE;
269 pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
270 exaDoMigration(pixmaps, 1, TRUE);
272 pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
273 if (!pDstPix) {
274 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
275 return 0;
278 if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
279 pSrc->format))
281 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
282 return -1;
285 if (!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
286 pDst->format))
288 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
289 return -1;
292 if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
294 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
295 return -1;
298 nbox = REGION_NUM_RECTS(&region);
299 pbox = REGION_RECTS(&region);
301 while (nbox--)
303 (*pExaScr->info->Solid) (pDstPix,
304 pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
305 pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
306 pbox++;
309 (*pExaScr->info->DoneSolid) (pDstPix);
310 exaMarkSync(pDst->pDrawable->pScreen);
312 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
313 return 1;
316 static int
317 exaTryDriverComposite(CARD8 op,
318 PicturePtr pSrc,
319 PicturePtr pMask,
320 PicturePtr pDst,
321 INT16 xSrc,
322 INT16 ySrc,
323 INT16 xMask,
324 INT16 yMask,
325 INT16 xDst,
326 INT16 yDst,
327 CARD16 width,
328 CARD16 height)
330 ExaScreenPriv (pDst->pDrawable->pScreen);
331 RegionRec region;
332 BoxPtr pbox;
333 int nbox;
334 int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
335 PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
336 struct _Pixmap scratch;
337 ExaMigrationRec pixmaps[3];
339 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
340 pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
341 if (pMask)
342 pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
344 /* Bail if we might exceed coord limits by rendering from/to these. We
345 * should really be making some scratch pixmaps with offsets and coords
346 * adjusted to deal with this, but it hasn't been done yet.
348 if (pSrcPix->drawable.width > pExaScr->info->maxX ||
349 pSrcPix->drawable.height > pExaScr->info->maxY ||
350 pDstPix->drawable.width > pExaScr->info->maxX ||
351 pDstPix->drawable.height > pExaScr->info->maxY ||
352 (pMask && (pMaskPix->drawable.width > pExaScr->info->maxX ||
353 pMaskPix->drawable.height > pExaScr->info->maxY)))
355 return -1;
358 xDst += pDst->pDrawable->x;
359 yDst += pDst->pDrawable->y;
361 if (pMask) {
362 xMask += pMask->pDrawable->x;
363 yMask += pMask->pDrawable->y;
366 xSrc += pSrc->pDrawable->x;
367 ySrc += pSrc->pDrawable->y;
369 if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
370 xSrc, ySrc, xMask, yMask, xDst, yDst,
371 width, height))
372 return 1;
374 if (pExaScr->info->CheckComposite &&
375 !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
377 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
378 return -1;
381 pixmaps[0].as_dst = TRUE;
382 pixmaps[0].as_src = exaOpReadsDestination(op);
383 pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
384 pixmaps[1].as_dst = FALSE;
385 pixmaps[1].as_src = TRUE;
386 pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
387 if (pMask) {
388 pixmaps[2].as_dst = FALSE;
389 pixmaps[2].as_src = TRUE;
390 pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable);
391 exaDoMigration(pixmaps, 3, TRUE);
392 } else {
393 exaDoMigration(pixmaps, 2, TRUE);
396 pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
397 if (pMask)
398 pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
399 &mask_off_y);
400 pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
402 if (!pDstPix) {
403 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
404 return 0;
407 if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->UploadToScratch) {
408 pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
409 if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch))
410 pSrcPix = &scratch;
411 } else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->UploadToScratch) {
412 pMaskPix = exaGetDrawablePixmap (pMask->pDrawable);
413 if ((*pExaScr->info->UploadToScratch) (pMaskPix, &scratch))
414 pMaskPix = &scratch;
417 if (!pSrcPix || (pMask && !pMaskPix)) {
418 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
419 return 0;
422 if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
423 pMaskPix, pDstPix))
425 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
426 return -1;
429 nbox = REGION_NUM_RECTS(&region);
430 pbox = REGION_RECTS(&region);
432 xMask -= xDst;
433 yMask -= yDst;
435 xSrc -= xDst;
436 ySrc -= yDst;
438 while (nbox--)
440 (*pExaScr->info->Composite) (pDstPix,
441 pbox->x1 + xSrc + src_off_x,
442 pbox->y1 + ySrc + src_off_y,
443 pbox->x1 + xMask + mask_off_x,
444 pbox->y1 + yMask + mask_off_y,
445 pbox->x1 + dst_off_x,
446 pbox->y1 + dst_off_y,
447 pbox->x2 - pbox->x1,
448 pbox->y2 - pbox->y1);
449 pbox++;
451 (*pExaScr->info->DoneComposite) (pDstPix);
452 exaMarkSync(pDst->pDrawable->pScreen);
454 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
455 return 1;
459 * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of
460 * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
461 * alpha and limited 1-tmu cards.
463 * From http://anholt.livejournal.com/32058.html:
465 * The trouble is that component-alpha rendering requires two different sources
466 * for blending: one for the source value to the blender, which is the
467 * per-channel multiplication of source and mask, and one for the source alpha
468 * for multiplying with the destination channels, which is the multiplication
469 * of the source channels by the mask alpha. So the equation for Over is:
471 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
472 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
473 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
474 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
476 * But we can do some simpler operations, right? How about PictOpOutReverse,
477 * which has a source factor of 0 and dest factor of (1 - source alpha). We
478 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
479 * blenders pretty easily. So we can do a component-alpha OutReverse, which
480 * gets us:
482 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
483 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
484 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
485 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
487 * OK. And if an op doesn't use the source alpha value for the destination
488 * factor, then we can do the channel multiplication in the texture blenders
489 * to get the source value, and ignore the source alpha that we wouldn't use.
490 * We've supported this in the Radeon driver for a long time. An example would
491 * be PictOpAdd, which does:
493 * dst.A = src.A * mask.A + dst.A
494 * dst.R = src.R * mask.R + dst.R
495 * dst.G = src.G * mask.G + dst.G
496 * dst.B = src.B * mask.B + dst.B
498 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
499 * after it, we get:
501 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
502 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
503 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
504 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
507 static int
508 exaTryMagicTwoPassCompositeHelper(CARD8 op,
509 PicturePtr pSrc,
510 PicturePtr pMask,
511 PicturePtr pDst,
512 INT16 xSrc,
513 INT16 ySrc,
514 INT16 xMask,
515 INT16 yMask,
516 INT16 xDst,
517 INT16 yDst,
518 CARD16 width,
519 CARD16 height)
521 ExaScreenPriv (pDst->pDrawable->pScreen);
522 DrawablePtr pDstDraw = pDst->pDrawable;
523 PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDstDraw);
524 int xoff, yoff;
526 assert(op == PictOpOver);
528 if (pExaScr->info->CheckComposite &&
529 (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
530 pDst) ||
531 !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))
533 return -1;
536 /* Now, we think we should be able to accelerate this operation. First,
537 * composite the destination to be the destination times the source alpha
538 * factors.
540 exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
541 xDst, yDst, width, height);
543 exaGetDrawableDeltas(pDstDraw, pDstPixmap, &xoff, &yoff);
544 xoff += pDstDraw->x;
545 yoff += pDstDraw->y;
546 exaPixmapDirty(pDstPixmap, xDst + xoff, yDst + yoff, xDst + xoff + width,
547 yDst + yoff + height);
549 /* Then, add in the source value times the destination alpha factors (1.0).
551 exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
552 xDst, yDst, width, height);
554 return 1;
557 void
558 exaComposite(CARD8 op,
559 PicturePtr pSrc,
560 PicturePtr pMask,
561 PicturePtr pDst,
562 INT16 xSrc,
563 INT16 ySrc,
564 INT16 xMask,
565 INT16 yMask,
566 INT16 xDst,
567 INT16 yDst,
568 CARD16 width,
569 CARD16 height)
571 ExaScreenPriv (pDst->pDrawable->pScreen);
572 int ret = -1;
573 Bool saveSrcRepeat = pSrc->repeat;
574 Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
575 ExaMigrationRec pixmaps[3];
576 int npixmaps = 1;
577 PixmapPtr pSrcPixmap = NULL;
579 pixmaps[0].as_dst = TRUE;
580 pixmaps[0].as_src = exaOpReadsDestination(op);
581 pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
583 if (pSrc->pDrawable) {
584 pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable);
585 pixmaps[npixmaps].as_dst = FALSE;
586 pixmaps[npixmaps].as_src = TRUE;
587 pixmaps[npixmaps].pPix = pSrcPixmap;
588 npixmaps++;
591 if (pMask && pMask->pDrawable) {
592 pixmaps[npixmaps].as_dst = FALSE;
593 pixmaps[npixmaps].as_src = TRUE;
594 pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable);
595 npixmaps++;
598 /* We currently don't support acceleration of gradients, or other pictures
599 * with a NULL pDrawable.
601 if (pExaScr->swappedOut ||
602 pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL))
604 goto fallback;
607 /* Remove repeat in source if useless */
608 if (pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
609 (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
610 (ySrc + height) <= pSrc->pDrawable->height)
611 pSrc->repeat = 0;
613 if (!pMask)
615 if ((op == PictOpSrc &&
616 ((pSrc->format == pDst->format) ||
617 (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) ||
618 (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) ||
619 (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap &&
620 pSrc->format == pDst->format &&
621 (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8)))
623 if (pSrc->pDrawable->width == 1 &&
624 pSrc->pDrawable->height == 1 &&
625 pSrc->repeat)
627 ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
628 width, height);
629 if (ret == 1)
630 goto done;
632 else if (pSrcPixmap && !pSrc->repeat && !pSrc->transform)
634 RegionRec region;
636 xDst += pDst->pDrawable->x;
637 yDst += pDst->pDrawable->y;
638 xSrc += pSrc->pDrawable->x;
639 ySrc += pSrc->pDrawable->y;
641 if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
642 xSrc, ySrc, xMask, yMask, xDst,
643 yDst, width, height))
644 goto done;
647 exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, NULL,
648 REGION_RECTS(&region), REGION_NUM_RECTS(&region),
649 xSrc - xDst, ySrc - yDst,
650 FALSE, FALSE, 0, NULL);
651 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
652 goto done;
654 else if (pSrcPixmap && !pSrc->transform &&
655 pSrc->repeatType == RepeatNormal)
657 RegionRec region;
658 DDXPointRec srcOrg;
660 /* Let's see if the driver can do the repeat in one go */
661 if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
662 !pDst->alphaMap)
664 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
665 ySrc, xMask, yMask, xDst, yDst,
666 width, height);
667 if (ret == 1)
668 goto done;
671 /* Now see if we can use exaFillRegionTiled() */
672 xDst += pDst->pDrawable->x;
673 yDst += pDst->pDrawable->y;
674 xSrc += pSrc->pDrawable->x;
675 ySrc += pSrc->pDrawable->y;
677 if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst, xSrc,
678 ySrc, xMask, yMask, xDst, yDst,
679 width, height))
680 goto done;
682 srcOrg.x = (xSrc - xDst) % pSrcPixmap->drawable.width;
683 srcOrg.y = (ySrc - yDst) % pSrcPixmap->drawable.height;
685 ret = exaFillRegionTiled(pDst->pDrawable, &region, pSrcPixmap,
686 &srcOrg, FB_ALLONES, GXcopy);
688 REGION_UNINIT(pDst->pDrawable->pScreen, &region);
690 if (ret)
691 goto done;
696 /* Remove repeat in mask if useless */
697 if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 &&
698 (xMask + width) <= pMask->pDrawable->width && yMask >= 0 &&
699 (yMask + height) <= pMask->pDrawable->height)
700 pMask->repeat = 0;
702 if (pExaScr->info->PrepareComposite &&
703 (!pSrc->repeat || pSrc->repeatType == RepeatNormal) &&
704 (!pMask || !pMask->repeat || pMask->repeatType == RepeatNormal) &&
705 !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
707 Bool isSrcSolid;
709 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
710 yMask, xDst, yDst, width, height);
711 if (ret == 1)
712 goto done;
714 /* For generic masks and solid src pictures, mach64 can do Over in two
715 * passes, similar to the component-alpha case.
717 isSrcSolid = pSrc->pDrawable->width == 1 &&
718 pSrc->pDrawable->height == 1 &&
719 pSrc->repeat;
721 /* If we couldn't do the Composite in a single pass, and it was a
722 * component-alpha Over, see if we can do it in two passes with
723 * an OutReverse and then an Add.
725 if (ret == -1 && op == PictOpOver && pMask &&
726 (pMask->componentAlpha || isSrcSolid)) {
727 ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
728 xSrc, ySrc,
729 xMask, yMask, xDst, yDst,
730 width, height);
731 if (ret == 1)
732 goto done;
736 fallback:
737 #if DEBUG_TRACE_FALL
738 exaPrintCompositeFallback (op, pSrc, pMask, pDst);
739 #endif
741 exaDoMigration(pixmaps, npixmaps, FALSE);
742 ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
743 xMask, yMask, xDst, yDst, width, height);
745 done:
746 pSrc->repeat = saveSrcRepeat;
747 if (pMask)
748 pMask->repeat = saveMaskRepeat;
750 #endif
753 * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead
754 * of PolyFillRect to initialize the pixmap after creating it, to prevent
755 * the pixmap from being migrated.
757 * See the comments about exaTrapezoids.
759 static PicturePtr
760 exaCreateAlphaPicture (ScreenPtr pScreen,
761 PicturePtr pDst,
762 PictFormatPtr pPictFormat,
763 CARD16 width,
764 CARD16 height)
766 PixmapPtr pPixmap;
767 PicturePtr pPicture;
768 GCPtr pGC;
769 int error;
770 xRectangle rect;
772 if (width > 32767 || height > 32767)
773 return 0;
775 if (!pPictFormat)
777 if (pDst->polyEdge == PolyEdgeSharp)
778 pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
779 else
780 pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
781 if (!pPictFormat)
782 return 0;
785 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
786 pPictFormat->depth);
787 if (!pPixmap)
788 return 0;
789 pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
790 if (!pGC)
792 (*pScreen->DestroyPixmap) (pPixmap);
793 return 0;
795 ValidateGC (&pPixmap->drawable, pGC);
796 rect.x = 0;
797 rect.y = 0;
798 rect.width = width;
799 rect.height = height;
800 ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect);
801 exaPixmapDirty (pPixmap, 0, 0, width, height);
802 FreeScratchGC (pGC);
803 pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
804 0, 0, serverClient, &error);
805 (*pScreen->DestroyPixmap) (pPixmap);
806 return pPicture;
810 * exaTrapezoids is essentially a copy of miTrapezoids that uses
811 * exaCreateAlphaPicture instead of miCreateAlphaPicture.
813 * The problem with miCreateAlphaPicture is that it calls PolyFillRect
814 * to initialize the contents after creating the pixmap, which
815 * causes the pixmap to be moved in for acceleration. The subsequent
816 * call to RasterizeTrapezoid won't be accelerated however, which
817 * forces the pixmap to be moved out again.
819 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
820 * to initialize the contents.
822 void
823 exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
824 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
825 int ntrap, xTrapezoid *traps)
827 ScreenPtr pScreen = pDst->pDrawable->pScreen;
828 PictureScreenPtr ps = GetPictureScreen(pScreen);
831 * Check for solid alpha add
833 if (op == PictOpAdd && miIsSolidAlpha (pSrc))
835 for (; ntrap; ntrap--, traps++)
836 (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
838 else if (maskFormat)
840 PicturePtr pPicture;
841 BoxRec bounds;
842 INT16 xDst, yDst;
843 INT16 xRel, yRel;
845 xDst = traps[0].left.p1.x >> 16;
846 yDst = traps[0].left.p1.y >> 16;
848 miTrapezoidBounds (ntrap, traps, &bounds);
849 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
850 return;
851 pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
852 bounds.x2 - bounds.x1,
853 bounds.y2 - bounds.y1);
854 if (!pPicture)
855 return;
856 for (; ntrap; ntrap--, traps++)
857 (*ps->RasterizeTrapezoid) (pPicture, traps,
858 -bounds.x1, -bounds.y1);
859 xRel = bounds.x1 + xSrc - xDst;
860 yRel = bounds.y1 + ySrc - yDst;
861 CompositePicture (op, pSrc, pPicture, pDst,
862 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
863 bounds.x2 - bounds.x1,
864 bounds.y2 - bounds.y1);
865 FreePicture (pPicture, 0);
867 else
869 if (pDst->polyEdge == PolyEdgeSharp)
870 maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
871 else
872 maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
873 for (; ntrap; ntrap--, traps++)
874 exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
878 #define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
881 * exaRasterizeTrapezoid is just a wrapper around the software implementation.
883 * The trapezoid specification is basically too hard to be done in hardware (at
884 * the very least, without programmability), so we just do the appropriate
885 * Prepare/FinishAccess for it before using fbtrap.c.
887 void
888 exaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid *trap,
889 int x_off, int y_off)
891 DrawablePtr pDraw = pPicture->pDrawable;
892 ExaMigrationRec pixmaps[1];
893 int xoff, yoff;
895 pixmaps[0].as_dst = TRUE;
896 pixmaps[0].as_src = TRUE;
897 pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
898 exaDoMigration(pixmaps, 1, FALSE);
900 exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
901 fbRasterizeTrapezoid(pPicture, trap, x_off, y_off);
902 exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
903 exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
904 pDraw->x + xoff + pDraw->width,
905 pDraw->y + yoff + pDraw->height);
906 exaFinishAccess(pDraw, EXA_PREPARE_DEST);
910 * exaAddTriangles does migration and syncing before dumping down to the
911 * software implementation.
913 void
914 exaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri,
915 xTriangle *tris)
917 DrawablePtr pDraw = pPicture->pDrawable;
918 ExaMigrationRec pixmaps[1];
919 int xoff, yoff;
921 pixmaps[0].as_dst = TRUE;
922 pixmaps[0].as_src = TRUE;
923 pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
924 exaDoMigration(pixmaps, 1, FALSE);
926 exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
927 fbAddTriangles(pPicture, x_off, y_off, ntri, tris);
928 exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
929 exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
930 pDraw->x + xoff + pDraw->width,
931 pDraw->y + yoff + pDraw->height);
932 exaFinishAccess(pDraw, EXA_PREPARE_DEST);
936 * Returns TRUE if the glyphs in the lists intersect. Only checks based on
937 * bounding box, which appears to be good enough to catch most cases at least.
939 static Bool
940 exaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs)
942 int x1, x2, y1, y2;
943 int n;
944 GlyphPtr glyph;
945 int x, y;
946 BoxRec extents;
947 Bool first = TRUE;
949 x = 0;
950 y = 0;
951 while (nlist--) {
952 x += list->xOff;
953 y += list->yOff;
954 n = list->len;
955 list++;
956 while (n--) {
957 glyph = *glyphs++;
959 if (glyph->info.width == 0 || glyph->info.height == 0) {
960 x += glyph->info.xOff;
961 y += glyph->info.yOff;
962 continue;
965 x1 = x - glyph->info.x;
966 if (x1 < MINSHORT)
967 x1 = MINSHORT;
968 y1 = y - glyph->info.y;
969 if (y1 < MINSHORT)
970 y1 = MINSHORT;
971 x2 = x1 + glyph->info.width;
972 if (x2 > MAXSHORT)
973 x2 = MAXSHORT;
974 y2 = y1 + glyph->info.height;
975 if (y2 > MAXSHORT)
976 y2 = MAXSHORT;
978 if (first) {
979 extents.x1 = x1;
980 extents.y1 = y1;
981 extents.x2 = x2;
982 extents.y2 = y2;
983 first = FALSE;
984 } else {
985 if (x1 < extents.x2 && x2 > extents.x1 &&
986 y1 < extents.y2 && y2 > extents.y1)
988 return TRUE;
991 if (x1 < extents.x1)
992 extents.x1 = x1;
993 if (x2 > extents.x2)
994 extents.x2 = x2;
995 if (y1 < extents.y1)
996 extents.y1 = y1;
997 if (y2 > extents.y2)
998 extents.y2 = y2;
1000 x += glyph->info.xOff;
1001 y += glyph->info.yOff;
1005 return FALSE;
1008 /* exaGlyphs is a slight variation on miGlyphs, to support acceleration. The
1009 * issue is that miGlyphs' use of ModifyPixmapHeader makes it impossible to
1010 * migrate these pixmaps. So, instead we create a pixmap at the beginning of
1011 * the loop and upload each glyph into the pixmap before compositing.
1013 void
1014 exaGlyphs (CARD8 op,
1015 PicturePtr pSrc,
1016 PicturePtr pDst,
1017 PictFormatPtr maskFormat,
1018 INT16 xSrc,
1019 INT16 ySrc,
1020 int nlist,
1021 GlyphListPtr list,
1022 GlyphPtr *glyphs)
1024 ExaScreenPriv (pDst->pDrawable->pScreen);
1025 PixmapPtr pPixmap = NULL;
1026 PicturePtr pPicture;
1027 PixmapPtr pMaskPixmap = NULL;
1028 PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDst->pDrawable);
1029 PicturePtr pMask;
1030 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1031 int width = 0, height = 0;
1032 int x, y, x1, y1, xoff, yoff;
1033 int xDst = list->xOff, yDst = list->yOff;
1034 int n;
1035 int error;
1036 BoxRec extents;
1037 CARD32 component_alpha;
1039 /* If we have a mask format but it's the same as all the glyphs and
1040 * the glyphs don't intersect, we can avoid accumulating the glyphs in the
1041 * temporary picture.
1043 if (maskFormat != NULL) {
1044 Bool sameFormat = TRUE;
1045 int i;
1047 for (i = 0; i < nlist; i++) {
1048 if (maskFormat->format != list[i].format->format) {
1049 sameFormat = FALSE;
1050 break;
1053 if (sameFormat) {
1054 if (!exaGlyphsIntersect(nlist, list, glyphs)) {
1055 maskFormat = NULL;
1060 /* If the driver doesn't support accelerated composite, there's no point in
1061 * going to this extra work. Assume that any driver that supports Composite
1062 * will be able to support component alpha using the two-pass helper.
1064 if (!pExaScr->info->PrepareComposite)
1066 miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
1067 return;
1070 if (maskFormat)
1072 GCPtr pGC;
1073 xRectangle rect;
1075 miGlyphExtents (nlist, list, glyphs, &extents);
1077 extents.x1 = max(extents.x1, 0);
1078 extents.y1 = max(extents.y1, 0);
1079 extents.x2 = min(extents.x2, pDst->pDrawable->width);
1080 extents.y2 = min(extents.y2, pDst->pDrawable->height);
1082 if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
1083 return;
1084 width = extents.x2 - extents.x1;
1085 height = extents.y2 - extents.y1;
1086 pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1087 maskFormat->depth);
1088 if (!pMaskPixmap)
1089 return;
1090 component_alpha = NeedsComponent(maskFormat->format);
1091 pMask = CreatePicture (0, &pMaskPixmap->drawable,
1092 maskFormat, CPComponentAlpha, &component_alpha,
1093 serverClient, &error);
1094 if (!pMask)
1096 (*pScreen->DestroyPixmap) (pMaskPixmap);
1097 return;
1099 ValidatePicture(pMask);
1100 pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
1101 ValidateGC (&pMaskPixmap->drawable, pGC);
1102 rect.x = 0;
1103 rect.y = 0;
1104 rect.width = width;
1105 rect.height = height;
1106 (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
1107 exaPixmapDirty(pMaskPixmap, 0, 0, width, height);
1108 FreeScratchGC (pGC);
1109 x = -extents.x1;
1110 y = -extents.y1;
1112 else
1114 pMask = pDst;
1115 x = 0;
1116 y = 0;
1119 exaGetDrawableDeltas(pDst->pDrawable, pDstPixmap, &xoff, &yoff);
1121 while (nlist--)
1123 GCPtr pGC = NULL;
1124 int maxwidth = 0, maxheight = 0, i;
1125 ExaMigrationRec pixmaps[1];
1126 PixmapPtr pScratchPixmap = NULL;
1128 x += list->xOff;
1129 y += list->yOff;
1130 n = list->len;
1131 for (i = 0; i < n; i++) {
1132 if (glyphs[i]->info.width > maxwidth)
1133 maxwidth = glyphs[i]->info.width;
1134 if (glyphs[i]->info.height > maxheight)
1135 maxheight = glyphs[i]->info.height;
1137 if (maxwidth == 0 || maxheight == 0) {
1138 while (n--)
1140 GlyphPtr glyph;
1142 glyph = *glyphs++;
1143 x += glyph->info.xOff;
1144 y += glyph->info.yOff;
1146 list++;
1147 continue;
1150 /* Create the (real) temporary pixmap to store the current glyph in */
1151 pPixmap = (*pScreen->CreatePixmap) (pScreen, maxwidth, maxheight,
1152 list->format->depth);
1153 if (!pPixmap)
1154 return;
1156 /* Create a temporary picture to wrap the temporary pixmap, so it can be
1157 * used as a source for Composite.
1159 component_alpha = NeedsComponent(list->format->format);
1160 pPicture = CreatePicture (0, &pPixmap->drawable, list->format,
1161 CPComponentAlpha, &component_alpha,
1162 serverClient, &error);
1163 if (!pPicture) {
1164 (*pScreen->DestroyPixmap) (pPixmap);
1165 return;
1167 ValidatePicture(pPicture);
1169 /* Give the temporary pixmap an initial kick towards the screen, so
1170 * it'll stick there.
1172 pixmaps[0].as_dst = TRUE;
1173 pixmaps[0].as_src = TRUE;
1174 pixmaps[0].pPix = pPixmap;
1175 exaDoMigration (pixmaps, 1, pExaScr->info->PrepareComposite != NULL);
1177 while (n--)
1179 GlyphPtr glyph = *glyphs++;
1180 pointer glyphdata = (pointer) (glyph + 1);
1181 DrawablePtr pCmpDrw = (maskFormat ? pMask : pDst)->pDrawable;
1183 x1 = x - glyph->info.x;
1184 y1 = y - glyph->info.y;
1186 if (x1 >= pCmpDrw->width || y1 >= pCmpDrw->height ||
1187 (x1 + glyph->info.width) <= 0 || (y1 + glyph->info.height) <= 0)
1188 goto nextglyph;
1190 (*pScreen->ModifyPixmapHeader) (pScratchPixmap,
1191 glyph->info.width,
1192 glyph->info.height,
1193 0, 0, -1, glyphdata);
1195 /* Copy the glyph data into the proper pixmap instead of a fake.
1196 * First we try to use UploadToScreen, if we can, then we fall back
1197 * to a plain exaCopyArea in case of failure.
1199 if (pExaScr->info->UploadToScreen &&
1200 exaPixmapIsOffscreen(pPixmap) &&
1201 (*pExaScr->info->UploadToScreen) (pPixmap, 0, 0,
1202 glyph->info.width,
1203 glyph->info.height,
1204 glyphdata,
1205 PixmapBytePad(glyph->info.width,
1206 list->format->depth)))
1208 exaMarkSync (pScreen);
1209 } else {
1210 /* Set up the scratch pixmap/GC for doing a CopyArea. */
1211 if (pScratchPixmap == NULL) {
1212 /* Get a scratch pixmap to wrap the original glyph data */
1213 pScratchPixmap = GetScratchPixmapHeader (pScreen,
1214 glyph->info.width,
1215 glyph->info.height,
1216 list->format->depth,
1217 list->format->depth,
1218 -1, glyphdata);
1219 if (!pScratchPixmap) {
1220 FreePicture(pPicture, 0);
1221 (*pScreen->DestroyPixmap) (pPixmap);
1222 return;
1225 /* Get a scratch GC with which to copy the glyph data from
1226 * scratch to temporary
1228 pGC = GetScratchGC (list->format->depth, pScreen);
1229 ValidateGC (&pPixmap->drawable, pGC);
1230 } else {
1231 (*pScreen->ModifyPixmapHeader) (pScratchPixmap,
1232 glyph->info.width,
1233 glyph->info.height,
1234 0, 0, -1, glyphdata);
1235 pScratchPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1238 exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC,
1239 0, 0, glyph->info.width, glyph->info.height, 0, 0);
1242 exaPixmapDirty (pPixmap, 0, 0,
1243 glyph->info.width, glyph->info.height);
1245 if (maskFormat)
1247 exaComposite (PictOpAdd, pPicture, NULL, pMask, 0, 0, 0, 0,
1248 x1, y1, glyph->info.width, glyph->info.height);
1249 exaPixmapDirty(pMaskPixmap, x1, y1, x1 + glyph->info.width,
1250 y1 + glyph->info.height);
1252 else
1254 exaComposite (op, pSrc, pPicture, pDst,
1255 xSrc + x1 - xDst, ySrc + y1 - yDst,
1256 0, 0, x1, y1, glyph->info.width,
1257 glyph->info.height);
1258 x1 += pDst->pDrawable->x + xoff;
1259 y1 += pDst->pDrawable->y + yoff;
1260 exaPixmapDirty(pDstPixmap, x1, y1, x1 + glyph->info.width,
1261 y1 + glyph->info.height);
1263 nextglyph:
1264 x += glyph->info.xOff;
1265 y += glyph->info.yOff;
1267 list++;
1268 if (pGC != NULL)
1269 FreeScratchGC (pGC);
1270 FreePicture ((pointer) pPicture, 0);
1271 (*pScreen->DestroyPixmap) (pPixmap);
1272 if (pScratchPixmap != NULL)
1273 FreeScratchPixmapHeader (pScratchPixmap);
1275 if (maskFormat)
1277 x = extents.x1;
1278 y = extents.y1;
1279 exaComposite (op, pSrc, pMask, pDst, xSrc + x - xDst, ySrc + y - yDst,
1280 0, 0, x, y, width, height);
1281 FreePicture ((pointer) pMask, (XID) 0);
1282 (*pScreen->DestroyPixmap) (pMaskPixmap);