1 /*
2 * Copyright © 2001 Keith Packard
3 *
4 * Partly based on code that is Copyright © The XFree86 Project Inc.
5 *
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.
15 *
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.
23 */
24
25 #ifdef HAVE_DIX_CONFIG_H
26 #include <dix-config.h>
27 #endif
28
29 #include <stdlib.h>
30
31 #include "exa_priv.h"
32
33 #include "mipict.h"
34
35 #if DEBUG_TRACE_FALL
36 static void
exaCompositeFallbackPictDesc(PicturePtr pict,char * string,int n)37 exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
38 {
39 char format[20];
40 char size[20];
41 char loc;
42 int temp;
43
44 if (!pict) {
45 snprintf(string, n, "None");
46 return;
47 }
48
49 switch (pict->format) {
50 case PICT_a8r8g8b8:
51 snprintf(format, 20, "ARGB8888");
52 break;
53 case PICT_x8r8g8b8:
54 snprintf(format, 20, "XRGB8888");
55 break;
56 case PICT_b8g8r8a8:
57 snprintf(format, 20, "BGRA8888");
58 break;
59 case PICT_b8g8r8x8:
60 snprintf(format, 20, "BGRX8888");
61 break;
62 case PICT_r5g6b5:
63 snprintf(format, 20, "RGB565 ");
64 break;
65 case PICT_x1r5g5b5:
66 snprintf(format, 20, "RGB555 ");
67 break;
68 case PICT_a8:
69 snprintf(format, 20, "A8 ");
70 break;
71 case PICT_a1:
72 snprintf(format, 20, "A1 ");
73 break;
74 default:
75 snprintf(format, 20, "0x%x", (int) pict->format);
76 break;
77 }
78
79 if (pict->pDrawable) {
80 loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
81
82 snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
83 pict->pDrawable->height, pict->repeat ? " R" : "");
84 }
85 else {
86 loc = '-';
87
88 snprintf(size, 20, "%s", pict->repeat ? " R" : "");
89 }
90
91 snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format,
92 size);
93 }
94
95 static void
exaPrintCompositeFallback(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst)96 exaPrintCompositeFallback(CARD8 op,
97 PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
98 {
99 char sop[20];
100 char srcdesc[40], maskdesc[40], dstdesc[40];
101
102 switch (op) {
103 case PictOpSrc:
104 snprintf(sop, sizeof(sop), "Src");
105 break;
106 case PictOpOver:
107 snprintf(sop, sizeof(sop), "Over");
108 break;
109 default:
110 snprintf(sop, sizeof(sop), "0x%x", (int) op);
111 break;
112 }
113
114 exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
115 exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
116 exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
117
118 ErrorF("Composite fallback: op %s, \n"
119 " src %s, \n"
120 " mask %s, \n"
121 " dst %s, \n", sop, srcdesc, maskdesc, dstdesc);
122 }
123 #endif /* DEBUG_TRACE_FALL */
124
125 Bool
exaOpReadsDestination(CARD8 op)126 exaOpReadsDestination(CARD8 op)
127 {
128 /* FALSE (does not read destination) is the list of ops in the protocol
129 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
130 * That's just Clear and Src. ReduceCompositeOp() will already have
131 * converted con/disjoint clear/src to Clear or Src.
132 */
133 switch (op) {
134 case PictOpClear:
135 case PictOpSrc:
136 return FALSE;
137 default:
138 return TRUE;
139 }
140 }
141
142 static Bool
exaGetPixelFromRGBA(CARD32 * pixel,CARD16 red,CARD16 green,CARD16 blue,CARD16 alpha,PictFormatPtr pFormat)143 exaGetPixelFromRGBA(CARD32 *pixel,
144 CARD16 red,
145 CARD16 green,
146 CARD16 blue, CARD16 alpha, PictFormatPtr pFormat)
147 {
148 int rbits, bbits, gbits, abits;
149 int rshift, bshift, gshift, ashift;
150
151 *pixel = 0;
152
153 if (!PICT_FORMAT_COLOR(pFormat->format) &&
154 PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A)
155 return FALSE;
156
157 rbits = PICT_FORMAT_R(pFormat->format);
158 gbits = PICT_FORMAT_G(pFormat->format);
159 bbits = PICT_FORMAT_B(pFormat->format);
160 abits = PICT_FORMAT_A(pFormat->format);
161
162 rshift = pFormat->direct.red;
163 gshift = pFormat->direct.green;
164 bshift = pFormat->direct.blue;
165 ashift = pFormat->direct.alpha;
166
167 *pixel |= (blue >> (16 - bbits)) << bshift;
168 *pixel |= (red >> (16 - rbits)) << rshift;
169 *pixel |= (green >> (16 - gbits)) << gshift;
170 *pixel |= (alpha >> (16 - abits)) << ashift;
171
172 return TRUE;
173 }
174
175 static Bool
exaGetRGBAFromPixel(CARD32 pixel,CARD16 * red,CARD16 * green,CARD16 * blue,CARD16 * alpha,PictFormatPtr pFormat,PictFormatShort format)176 exaGetRGBAFromPixel(CARD32 pixel,
177 CARD16 *red,
178 CARD16 *green,
179 CARD16 *blue,
180 CARD16 *alpha,
181 PictFormatPtr pFormat, PictFormatShort format)
182 {
183 int rbits, bbits, gbits, abits;
184 int rshift, bshift, gshift, ashift;
185
186 if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A)
187 return FALSE;
188
189 rbits = PICT_FORMAT_R(format);
190 gbits = PICT_FORMAT_G(format);
191 bbits = PICT_FORMAT_B(format);
192 abits = PICT_FORMAT_A(format);
193
194 if (pFormat) {
195 rshift = pFormat->direct.red;
196 gshift = pFormat->direct.green;
197 bshift = pFormat->direct.blue;
198 ashift = pFormat->direct.alpha;
199 }
200 else if (format == PICT_a8r8g8b8) {
201 rshift = 16;
202 gshift = 8;
203 bshift = 0;
204 ashift = 24;
205 }
206 else
207 FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match "
208 "createSourcePicture()\n");
209
210 if (rbits) {
211 *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
212 while (rbits < 16) {
213 *red |= *red >> rbits;
214 rbits <<= 1;
215 }
216
217 *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
218 while (gbits < 16) {
219 *green |= *green >> gbits;
220 gbits <<= 1;
221 }
222
223 *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
224 while (bbits < 16) {
225 *blue |= *blue >> bbits;
226 bbits <<= 1;
227 }
228 }
229 else {
230 *red = 0x0000;
231 *green = 0x0000;
232 *blue = 0x0000;
233 }
234
235 if (abits) {
236 *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
237 while (abits < 16) {
238 *alpha |= *alpha >> abits;
239 abits <<= 1;
240 }
241 }
242 else
243 *alpha = 0xffff;
244
245 return TRUE;
246 }
247
248 static int
exaTryDriverSolidFill(PicturePtr pSrc,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)249 exaTryDriverSolidFill(PicturePtr pSrc,
250 PicturePtr pDst,
251 INT16 xSrc,
252 INT16 ySrc,
253 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
254 {
255 ExaScreenPriv(pDst->pDrawable->pScreen);
256 RegionRec region;
257 BoxPtr pbox;
258 int nbox;
259 int dst_off_x, dst_off_y;
260 PixmapPtr pSrcPix, pDstPix;
261 ExaPixmapPrivPtr pDstExaPix;
262 CARD32 pixel;
263 CARD16 red, green, blue, alpha;
264
265 pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
266 pDstExaPix = ExaGetPixmapPriv(pDstPix);
267
268 /* Check whether the accelerator can use the destination pixmap.
269 */
270 if (pDstExaPix->accel_blocked) {
271 return -1;
272 }
273
274 xDst += pDst->pDrawable->x;
275 yDst += pDst->pDrawable->y;
276 if (pSrc->pDrawable) {
277 xSrc += pSrc->pDrawable->x;
278 ySrc += pSrc->pDrawable->y;
279 }
280
281 if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst,
282 xSrc, ySrc, 0, 0, xDst, yDst, width, height))
283 return 1;
284
285 exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
286
287 RegionTranslate(®ion, dst_off_x, dst_off_y);
288
289 if (pSrc->pDrawable) {
290 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
291 pixel = exaGetPixmapFirstPixel(pSrcPix);
292 }
293 else
294 miRenderColorToPixel(PictureMatchFormat(pDst->pDrawable->pScreen, 32,
295 pSrc->format),
296 &pSrc->pSourcePict->solidFill.fullcolor,
297 &pixel);
298
299 if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
300 pSrc->pFormat, pSrc->format) ||
301 !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, pDst->pFormat)) {
302 RegionUninit(®ion);
303 return -1;
304 }
305
306 if (pExaScr->do_migration) {
307 ExaMigrationRec pixmaps[1];
308
309 pixmaps[0].as_dst = TRUE;
310 pixmaps[0].as_src = FALSE;
311 pixmaps[0].pPix = pDstPix;
312 pixmaps[0].pReg = ®ion;
313 exaDoMigration(pixmaps, 1, TRUE);
314 }
315
316 if (!exaPixmapHasGpuCopy(pDstPix)) {
317 RegionUninit(®ion);
318 return 0;
319 }
320
321 if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) {
322 RegionUninit(®ion);
323 return -1;
324 }
325
326 nbox = RegionNumRects(®ion);
327 pbox = RegionRects(®ion);
328
329 while (nbox--) {
330 (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2,
331 pbox->y2);
332 pbox++;
333 }
334
335 (*pExaScr->info->DoneSolid) (pDstPix);
336 exaMarkSync(pDst->pDrawable->pScreen);
337
338 RegionUninit(®ion);
339 return 1;
340 }
341
342 static int
exaTryDriverCompositeRects(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,int nrect,ExaCompositeRectPtr rects)343 exaTryDriverCompositeRects(CARD8 op,
344 PicturePtr pSrc,
345 PicturePtr pMask,
346 PicturePtr pDst,
347 int nrect, ExaCompositeRectPtr rects)
348 {
349 ExaScreenPriv(pDst->pDrawable->pScreen);
350 int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0;
351 int dst_off_x, dst_off_y;
352 PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
353 ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
354
355 if (!pExaScr->info->PrepareComposite)
356 return -1;
357
358 if (pSrc->pDrawable) {
359 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
360 pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
361 }
362
363 if (pMask && pMask->pDrawable) {
364 pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
365 pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
366 }
367
368 pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
369 pDstExaPix = ExaGetPixmapPriv(pDstPix);
370
371 /* Check whether the accelerator can use these pixmaps.
372 * FIXME: If it cannot, use temporary pixmaps so that the drawing
373 * happens within limits.
374 */
375 if (pDstExaPix->accel_blocked ||
376 (pSrcExaPix && pSrcExaPix->accel_blocked) ||
377 (pMaskExaPix && pMaskExaPix->accel_blocked)) {
378 return -1;
379 }
380
381 if (pExaScr->info->CheckComposite &&
382 !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) {
383 return -1;
384 }
385
386 if (pExaScr->do_migration) {
387 ExaMigrationRec pixmaps[3];
388 int i = 0;
389
390 pixmaps[i].as_dst = TRUE;
391 pixmaps[i].as_src = exaOpReadsDestination(op);
392 pixmaps[i].pPix = pDstPix;
393 pixmaps[i].pReg = NULL;
394 i++;
395
396 if (pSrcPix) {
397 pixmaps[i].as_dst = FALSE;
398 pixmaps[i].as_src = TRUE;
399 pixmaps[i].pPix = pSrcPix;
400 pixmaps[i].pReg = NULL;
401 i++;
402 }
403
404 if (pMaskPix) {
405 pixmaps[i].as_dst = FALSE;
406 pixmaps[i].as_src = TRUE;
407 pixmaps[i].pPix = pMaskPix;
408 pixmaps[i].pReg = NULL;
409 i++;
410 }
411
412 exaDoMigration(pixmaps, i, TRUE);
413 }
414
415 pDstPix = exaGetOffscreenPixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
416 if (!pDstPix)
417 return 0;
418
419 if (pSrcPix) {
420 pSrcPix =
421 exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
422 if (!pSrcPix)
423 return 0;
424 }
425
426 if (pMaskPix) {
427 pMaskPix =
428 exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x, &mask_off_y);
429 if (!pMaskPix)
430 return 0;
431 }
432
433 if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
434 pMaskPix, pDstPix))
435 return -1;
436
437 while (nrect--) {
438 INT16 xDst = rects->xDst + pDst->pDrawable->x;
439 INT16 yDst = rects->yDst + pDst->pDrawable->y;
440 INT16 xMask = rects->xMask;
441 INT16 yMask = rects->yMask;
442 INT16 xSrc = rects->xSrc;
443 INT16 ySrc = rects->ySrc;
444 RegionRec region;
445 BoxPtr pbox;
446 int nbox;
447
448 if (pMaskPix) {
449 xMask += pMask->pDrawable->x;
450 yMask += pMask->pDrawable->y;
451 }
452
453 if (pSrcPix) {
454 xSrc += pSrc->pDrawable->x;
455 ySrc += pSrc->pDrawable->y;
456 }
457
458 if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst,
459 xSrc, ySrc, xMask, yMask, xDst, yDst,
460 rects->width, rects->height))
461 goto next_rect;
462
463 RegionTranslate(®ion, dst_off_x, dst_off_y);
464
465 nbox = RegionNumRects(®ion);
466 pbox = RegionRects(®ion);
467
468 xMask = xMask + mask_off_x - xDst - dst_off_x;
469 yMask = yMask + mask_off_y - yDst - dst_off_y;
470 xSrc = xSrc + src_off_x - xDst - dst_off_x;
471 ySrc = ySrc + src_off_y - yDst - dst_off_y;
472
473 while (nbox--) {
474 (*pExaScr->info->Composite) (pDstPix,
475 pbox->x1 + xSrc,
476 pbox->y1 + ySrc,
477 pbox->x1 + xMask,
478 pbox->y1 + yMask,
479 pbox->x1,
480 pbox->y1,
481 pbox->x2 - pbox->x1,
482 pbox->y2 - pbox->y1);
483 pbox++;
484 }
485
486 next_rect:
487 RegionUninit(®ion);
488
489 rects++;
490 }
491
492 (*pExaScr->info->DoneComposite) (pDstPix);
493 exaMarkSync(pDst->pDrawable->pScreen);
494
495 return 1;
496 }
497
498 /**
499 * Copy a number of rectangles from source to destination in a single
500 * operation. This is specialized for glyph rendering: we don't have the
501 * special-case fallbacks found in exaComposite() - if the driver can support
502 * it, we use the driver functionality, otherwise we fall back straight to
503 * software.
504 */
505 void
exaCompositeRects(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,int nrect,ExaCompositeRectPtr rects)506 exaCompositeRects(CARD8 op,
507 PicturePtr pSrc,
508 PicturePtr pMask,
509 PicturePtr pDst, int nrect, ExaCompositeRectPtr rects)
510 {
511 ExaScreenPriv(pDst->pDrawable->pScreen);
512 int n;
513 ExaCompositeRectPtr r;
514 int ret;
515
516 /* If we get a mask, that means we're rendering to the exaGlyphs
517 * destination directly, so the damage layer takes care of this.
518 */
519 if (!pMask) {
520 RegionRec region;
521 int x1 = MAXSHORT;
522 int y1 = MAXSHORT;
523 int x2 = MINSHORT;
524 int y2 = MINSHORT;
525 BoxRec box;
526
527 /* We have to manage the damage ourselves, since CompositeRects isn't
528 * something in the screen that can be managed by the damage extension,
529 * and EXA depends on damage to track what needs to be migrated between
530 * the gpu and the cpu.
531 */
532
533 /* Compute the overall extents of the composited region - we're making
534 * the assumption here that we are compositing a bunch of glyphs that
535 * cluster closely together and damaging each glyph individually would
536 * be a loss compared to damaging the bounding box.
537 */
538 n = nrect;
539 r = rects;
540 while (n--) {
541 int rect_x2 = r->xDst + r->width;
542 int rect_y2 = r->yDst + r->height;
543
544 if (r->xDst < x1)
545 x1 = r->xDst;
546 if (r->yDst < y1)
547 y1 = r->yDst;
548 if (rect_x2 > x2)
549 x2 = rect_x2;
550 if (rect_y2 > y2)
551 y2 = rect_y2;
552
553 r++;
554 }
555
556 if (x2 <= x1 || y2 <= y1)
557 return;
558
559 box.x1 = x1;
560 box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
561 box.y1 = y1;
562 box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
563
564 /* The pixmap migration code relies on pendingDamage indicating
565 * the bounds of the current rendering, so we need to force
566 * the actual damage into that region before we do anything, and
567 * (see use of DamagePendingRegion in exaCopyDirty)
568 */
569
570 RegionInit(®ion, &box, 1);
571
572 DamageRegionAppend(pDst->pDrawable, ®ion);
573
574 RegionUninit(®ion);
575 }
576
577 /************************************************************/
578
579 ValidatePicture(pSrc);
580 if (pMask)
581 ValidatePicture(pMask);
582 ValidatePicture(pDst);
583
584 ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects);
585
586 if (ret != 1) {
587 if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha &&
588 (!pExaScr->info->CheckComposite ||
589 ((*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask,
590 pDst) &&
591 (*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask,
592 pDst)))) {
593 ret =
594 exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, pDst,
595 nrect, rects);
596 if (ret == 1) {
597 op = PictOpAdd;
598 ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect,
599 rects);
600 }
601 }
602
603 if (ret != 1) {
604 n = nrect;
605 r = rects;
606 while (n--) {
607 ExaCheckComposite(op, pSrc, pMask, pDst,
608 r->xSrc, r->ySrc,
609 r->xMask, r->yMask,
610 r->xDst, r->yDst, r->width, r->height);
611 r++;
612 }
613 }
614 }
615
616 /************************************************************/
617
618 if (!pMask) {
619 /* Now we have to flush the damage out from pendingDamage => damage
620 * Calling DamageRegionProcessPending has that effect.
621 */
622
623 DamageRegionProcessPending(pDst->pDrawable);
624 }
625 }
626
627 static int
exaTryDriverComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)628 exaTryDriverComposite(CARD8 op,
629 PicturePtr pSrc,
630 PicturePtr pMask,
631 PicturePtr pDst,
632 INT16 xSrc,
633 INT16 ySrc,
634 INT16 xMask,
635 INT16 yMask,
636 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
637 {
638 ExaScreenPriv(pDst->pDrawable->pScreen);
639 RegionRec region;
640 BoxPtr pbox;
641 int nbox;
642 int src_off_x, src_off_y, mask_off_x = 0, mask_off_y = 0, dst_off_x, dst_off_y;
643 PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
644 ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
645
646 if (pSrc->pDrawable) {
647 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
648 pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
649 }
650
651 pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
652 pDstExaPix = ExaGetPixmapPriv(pDstPix);
653
654 if (pMask && pMask->pDrawable) {
655 pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
656 pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
657 }
658
659 /* Check whether the accelerator can use these pixmaps.
660 * FIXME: If it cannot, use temporary pixmaps so that the drawing
661 * happens within limits.
662 */
663 if (pDstExaPix->accel_blocked ||
664 (pSrcExaPix && pSrcExaPix->accel_blocked) ||
665 (pMaskExaPix && (pMaskExaPix->accel_blocked))) {
666 return -1;
667 }
668
669 xDst += pDst->pDrawable->x;
670 yDst += pDst->pDrawable->y;
671
672 if (pMaskPix) {
673 xMask += pMask->pDrawable->x;
674 yMask += pMask->pDrawable->y;
675 }
676
677 if (pSrcPix) {
678 xSrc += pSrc->pDrawable->x;
679 ySrc += pSrc->pDrawable->y;
680 }
681
682 if (pExaScr->info->CheckComposite &&
683 !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) {
684 return -1;
685 }
686
687 if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst,
688 xSrc, ySrc, xMask, yMask, xDst, yDst,
689 width, height))
690 return 1;
691
692 exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
693
694 RegionTranslate(®ion, dst_off_x, dst_off_y);
695
696 if (pExaScr->do_migration) {
697 ExaMigrationRec pixmaps[3];
698 int i = 0;
699
700 pixmaps[i].as_dst = TRUE;
701 pixmaps[i].as_src = exaOpReadsDestination(op);
702 pixmaps[i].pPix = pDstPix;
703 pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion;
704 i++;
705
706 if (pSrcPix) {
707 pixmaps[i].as_dst = FALSE;
708 pixmaps[i].as_src = TRUE;
709 pixmaps[i].pPix = pSrcPix;
710 pixmaps[i].pReg = NULL;
711 i++;
712 }
713
714 if (pMaskPix) {
715 pixmaps[i].as_dst = FALSE;
716 pixmaps[i].as_src = TRUE;
717 pixmaps[i].pPix = pMaskPix;
718 pixmaps[i].pReg = NULL;
719 i++;
720 }
721
722 exaDoMigration(pixmaps, i, TRUE);
723 }
724
725 if (pSrcPix) {
726 pSrcPix =
727 exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
728 if (!pSrcPix) {
729 RegionUninit(®ion);
730 return 0;
731 }
732 }
733
734 if (pMaskPix) {
735 pMaskPix = exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x,
736 &mask_off_y);
737 if (!pMaskPix) {
738 RegionUninit(®ion);
739 return 0;
740 }
741 }
742
743 if (!exaPixmapHasGpuCopy(pDstPix)) {
744 RegionUninit(®ion);
745 return 0;
746 }
747
748 if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
749 pMaskPix, pDstPix)) {
750 RegionUninit(®ion);
751 return -1;
752 }
753
754 nbox = RegionNumRects(®ion);
755 pbox = RegionRects(®ion);
756
757 xMask = xMask + mask_off_x - xDst - dst_off_x;
758 yMask = yMask + mask_off_y - yDst - dst_off_y;
759
760 xSrc = xSrc + src_off_x - xDst - dst_off_x;
761 ySrc = ySrc + src_off_y - yDst - dst_off_y;
762
763 while (nbox--) {
764 (*pExaScr->info->Composite) (pDstPix,
765 pbox->x1 + xSrc,
766 pbox->y1 + ySrc,
767 pbox->x1 + xMask,
768 pbox->y1 + yMask,
769 pbox->x1,
770 pbox->y1,
771 pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
772 pbox++;
773 }
774 (*pExaScr->info->DoneComposite) (pDstPix);
775 exaMarkSync(pDst->pDrawable->pScreen);
776
777 RegionUninit(®ion);
778 return 1;
779 }
780
781 /**
782 * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of
783 * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
784 * alpha and limited 1-tmu cards.
785 *
786 * From http://anholt.livejournal.com/32058.html:
787 *
788 * The trouble is that component-alpha rendering requires two different sources
789 * for blending: one for the source value to the blender, which is the
790 * per-channel multiplication of source and mask, and one for the source alpha
791 * for multiplying with the destination channels, which is the multiplication
792 * of the source channels by the mask alpha. So the equation for Over is:
793 *
794 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
795 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
796 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
797 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
798 *
799 * But we can do some simpler operations, right? How about PictOpOutReverse,
800 * which has a source factor of 0 and dest factor of (1 - source alpha). We
801 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
802 * blenders pretty easily. So we can do a component-alpha OutReverse, which
803 * gets us:
804 *
805 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
806 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
807 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
808 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
809 *
810 * OK. And if an op doesn't use the source alpha value for the destination
811 * factor, then we can do the channel multiplication in the texture blenders
812 * to get the source value, and ignore the source alpha that we wouldn't use.
813 * We've supported this in the Radeon driver for a long time. An example would
814 * be PictOpAdd, which does:
815 *
816 * dst.A = src.A * mask.A + dst.A
817 * dst.R = src.R * mask.R + dst.R
818 * dst.G = src.G * mask.G + dst.G
819 * dst.B = src.B * mask.B + dst.B
820 *
821 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
822 * after it, we get:
823 *
824 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
825 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
826 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
827 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
828 */
829
830 static int
exaTryMagicTwoPassCompositeHelper(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)831 exaTryMagicTwoPassCompositeHelper(CARD8 op,
832 PicturePtr pSrc,
833 PicturePtr pMask,
834 PicturePtr pDst,
835 INT16 xSrc,
836 INT16 ySrc,
837 INT16 xMask,
838 INT16 yMask,
839 INT16 xDst,
840 INT16 yDst, CARD16 width, CARD16 height)
841 {
842 ExaScreenPriv(pDst->pDrawable->pScreen);
843
844 assert(op == PictOpOver);
845
846 if (pExaScr->info->CheckComposite &&
847 (!(*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask,
848 pDst) ||
849 !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask, pDst))) {
850 return -1;
851 }
852
853 /* Now, we think we should be able to accelerate this operation. First,
854 * composite the destination to be the destination times the source alpha
855 * factors.
856 */
857 exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
858 xDst, yDst, width, height);
859
860 /* Then, add in the source value times the destination alpha factors (1.0).
861 */
862 exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
863 xDst, yDst, width, height);
864
865 return 1;
866 }
867
868 void
exaComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)869 exaComposite(CARD8 op,
870 PicturePtr pSrc,
871 PicturePtr pMask,
872 PicturePtr pDst,
873 INT16 xSrc,
874 INT16 ySrc,
875 INT16 xMask,
876 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
877 {
878 ExaScreenPriv(pDst->pDrawable->pScreen);
879 int ret = -1;
880 Bool saveSrcRepeat = pSrc->repeat;
881 Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
882 RegionRec region;
883
884 if (pExaScr->swappedOut)
885 goto fallback;
886
887 /* Remove repeat in source if useless */
888 if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
889 (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
890 (ySrc + height) <= pSrc->pDrawable->height)
891 pSrc->repeat = 0;
892
893 if (!pMask && !pSrc->alphaMap && !pDst->alphaMap &&
894 (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format))))
895 {
896 if (pSrc->pDrawable ?
897 (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
898 pSrc->repeat) :
899 (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) {
900 ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
901 width, height);
902 if (ret == 1)
903 goto done;
904 }
905 else if (pSrc->pDrawable && !pSrc->transform &&
906 ((op == PictOpSrc &&
907 (pSrc->format == pDst->format ||
908 (PICT_FORMAT_COLOR(pDst->format) &&
909 PICT_FORMAT_COLOR(pSrc->format) &&
910 pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format),
911 PICT_FORMAT_TYPE(pSrc->format),
912 0,
913 PICT_FORMAT_R(pSrc->format),
914 PICT_FORMAT_G(pSrc->format),
915 PICT_FORMAT_B(pSrc->format)))))
916 || (op == PictOpOver && pSrc->format == pDst->format &&
917 !PICT_FORMAT_A(pSrc->format)))) {
918 if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 &&
919 (xSrc + width <= pSrc->pDrawable->width) &&
920 (ySrc + height <= pSrc->pDrawable->height)) {
921 Bool suc;
922
923 xDst += pDst->pDrawable->x;
924 yDst += pDst->pDrawable->y;
925 xSrc += pSrc->pDrawable->x;
926 ySrc += pSrc->pDrawable->y;
927
928 if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst,
929 xSrc, ySrc, xMask, yMask, xDst,
930 yDst, width, height))
931 goto done;
932
933 suc = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL,
934 RegionRects(®ion),
935 RegionNumRects(®ion), xSrc - xDst,
936 ySrc - yDst, FALSE, FALSE);
937 RegionUninit(®ion);
938
939 /* Reset values to their original values. */
940 xDst -= pDst->pDrawable->x;
941 yDst -= pDst->pDrawable->y;
942 xSrc -= pSrc->pDrawable->x;
943 ySrc -= pSrc->pDrawable->y;
944
945 if (!suc)
946 goto fallback;
947
948 goto done;
949 }
950
951 if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
952 pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
953 DDXPointRec patOrg;
954
955 /* Let's see if the driver can do the repeat in one go */
956 if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
957 !pDst->alphaMap) {
958 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
959 ySrc, xMask, yMask, xDst, yDst,
960 width, height);
961 if (ret == 1)
962 goto done;
963 }
964
965 /* Now see if we can use exaFillRegionTiled() */
966 xDst += pDst->pDrawable->x;
967 yDst += pDst->pDrawable->y;
968 xSrc += pSrc->pDrawable->x;
969 ySrc += pSrc->pDrawable->y;
970
971 if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, xSrc,
972 ySrc, xMask, yMask, xDst, yDst,
973 width, height))
974 goto done;
975
976 /* pattern origin is the point in the destination drawable
977 * corresponding to (0,0) in the source */
978 patOrg.x = xDst - xSrc;
979 patOrg.y = yDst - ySrc;
980
981 ret = exaFillRegionTiled(pDst->pDrawable, ®ion,
982 (PixmapPtr) pSrc->pDrawable,
983 &patOrg, FB_ALLONES, GXcopy, CT_NONE);
984
985 RegionUninit(®ion);
986
987 if (ret)
988 goto done;
989
990 /* Let's be correct and restore the variables to their original state. */
991 xDst -= pDst->pDrawable->x;
992 yDst -= pDst->pDrawable->y;
993 xSrc -= pSrc->pDrawable->x;
994 ySrc -= pSrc->pDrawable->y;
995 }
996 }
997 }
998
999 /* Remove repeat in mask if useless */
1000 if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform &&
1001 xMask >= 0 && (xMask + width) <= pMask->pDrawable->width &&
1002 yMask >= 0 && (yMask + height) <= pMask->pDrawable->height)
1003 pMask->repeat = 0;
1004
1005 if (pExaScr->info->PrepareComposite &&
1006 !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) {
1007 Bool isSrcSolid;
1008
1009 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
1010 yMask, xDst, yDst, width, height);
1011 if (ret == 1)
1012 goto done;
1013
1014 /* For generic masks and solid src pictures, mach64 can do Over in two
1015 * passes, similar to the component-alpha case.
1016 */
1017 isSrcSolid = pSrc->pDrawable ?
1018 (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
1019 pSrc->repeat) :
1020 (pSrc->pSourcePict->type == SourcePictTypeSolidFill);
1021
1022 /* If we couldn't do the Composite in a single pass, and it was a
1023 * component-alpha Over, see if we can do it in two passes with
1024 * an OutReverse and then an Add.
1025 */
1026 if (ret == -1 && op == PictOpOver && pMask &&
1027 (pMask->componentAlpha || isSrcSolid)) {
1028 ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
1029 xSrc, ySrc,
1030 xMask, yMask, xDst, yDst,
1031 width, height);
1032 if (ret == 1)
1033 goto done;
1034 }
1035 }
1036
1037 fallback:
1038 #if DEBUG_TRACE_FALL
1039 exaPrintCompositeFallback(op, pSrc, pMask, pDst);
1040 #endif
1041
1042 ExaCheckComposite(op, pSrc, pMask, pDst, xSrc, ySrc,
1043 xMask, yMask, xDst, yDst, width, height);
1044
1045 done:
1046 pSrc->repeat = saveSrcRepeat;
1047 if (pMask)
1048 pMask->repeat = saveMaskRepeat;
1049 }
1050
1051 /**
1052 * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead
1053 * of PolyFillRect to initialize the pixmap after creating it, to prevent
1054 * the pixmap from being migrated.
1055 *
1056 * See the comments about exaTrapezoids and exaTriangles.
1057 */
1058 static PicturePtr
exaCreateAlphaPicture(ScreenPtr pScreen,PicturePtr pDst,PictFormatPtr pPictFormat,CARD16 width,CARD16 height)1059 exaCreateAlphaPicture(ScreenPtr pScreen,
1060 PicturePtr pDst,
1061 PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
1062 {
1063 PixmapPtr pPixmap;
1064 PicturePtr pPicture;
1065 GCPtr pGC;
1066 int error;
1067 xRectangle rect;
1068
1069 if (width > 32767 || height > 32767)
1070 return 0;
1071
1072 if (!pPictFormat) {
1073 if (pDst->polyEdge == PolyEdgeSharp)
1074 pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1075 else
1076 pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1077 if (!pPictFormat)
1078 return 0;
1079 }
1080
1081 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1082 pPictFormat->depth, 0);
1083 if (!pPixmap)
1084 return 0;
1085 pGC = GetScratchGC(pPixmap->drawable.depth, pScreen);
1086 if (!pGC) {
1087 (*pScreen->DestroyPixmap) (pPixmap);
1088 return 0;
1089 }
1090 ValidateGC(&pPixmap->drawable, pGC);
1091 rect.x = 0;
1092 rect.y = 0;
1093 rect.width = width;
1094 rect.height = height;
1095 ExaCheckPolyFillRect(&pPixmap->drawable, pGC, 1, &rect);
1096 exaPixmapDirty(pPixmap, 0, 0, width, height);
1097 FreeScratchGC(pGC);
1098 pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
1099 0, 0, serverClient, &error);
1100 (*pScreen->DestroyPixmap) (pPixmap);
1101 return pPicture;
1102 }
1103
1104 /**
1105 * exaTrapezoids is essentially a copy of miTrapezoids that uses
1106 * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1107 *
1108 * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1109 * to initialize the contents after creating the pixmap, which
1110 * causes the pixmap to be moved in for acceleration. The subsequent
1111 * call to RasterizeTrapezoid won't be accelerated however, which
1112 * forces the pixmap to be moved out again.
1113 *
1114 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1115 * to initialize the contents.
1116 */
1117 void
exaTrapezoids(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int ntrap,xTrapezoid * traps)1118 exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1119 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1120 int ntrap, xTrapezoid * traps)
1121 {
1122 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1123 PictureScreenPtr ps = GetPictureScreen(pScreen);
1124 BoxRec bounds;
1125
1126 if (maskFormat) {
1127 PicturePtr pPicture;
1128 INT16 xDst, yDst;
1129 INT16 xRel, yRel;
1130
1131 miTrapezoidBounds(ntrap, traps, &bounds);
1132
1133 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1134 return;
1135
1136 xDst = traps[0].left.p1.x >> 16;
1137 yDst = traps[0].left.p1.y >> 16;
1138
1139 pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat,
1140 bounds.x2 - bounds.x1,
1141 bounds.y2 - bounds.y1);
1142 if (!pPicture)
1143 return;
1144
1145 exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1146 for (; ntrap; ntrap--, traps++)
1147 if (xTrapezoidValid(traps))
1148 (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1);
1149 exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1150
1151 xRel = bounds.x1 + xSrc - xDst;
1152 yRel = bounds.y1 + ySrc - yDst;
1153 CompositePicture(op, pSrc, pPicture, pDst,
1154 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1155 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1156 FreePicture(pPicture, 0);
1157 }
1158 else {
1159 if (pDst->polyEdge == PolyEdgeSharp)
1160 maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1161 else
1162 maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1163 for (; ntrap; ntrap--, traps++)
1164 exaTrapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
1165 }
1166 }
1167
1168 /**
1169 * exaTriangles is essentially a copy of miTriangles that uses
1170 * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1171 *
1172 * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1173 * to initialize the contents after creating the pixmap, which
1174 * causes the pixmap to be moved in for acceleration. The subsequent
1175 * call to AddTriangles won't be accelerated however, which forces the pixmap
1176 * to be moved out again.
1177 *
1178 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1179 * to initialize the contents.
1180 */
1181 void
exaTriangles(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int ntri,xTriangle * tris)1182 exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1183 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1184 int ntri, xTriangle * tris)
1185 {
1186 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1187 PictureScreenPtr ps = GetPictureScreen(pScreen);
1188 BoxRec bounds;
1189
1190 if (maskFormat) {
1191 PicturePtr pPicture;
1192 INT16 xDst, yDst;
1193 INT16 xRel, yRel;
1194
1195 miTriangleBounds(ntri, tris, &bounds);
1196
1197 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1198 return;
1199
1200 xDst = tris[0].p1.x >> 16;
1201 yDst = tris[0].p1.y >> 16;
1202
1203 pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat,
1204 bounds.x2 - bounds.x1,
1205 bounds.y2 - bounds.y1);
1206 if (!pPicture)
1207 return;
1208
1209 exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1210 (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
1211 exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1212
1213 xRel = bounds.x1 + xSrc - xDst;
1214 yRel = bounds.y1 + ySrc - yDst;
1215 CompositePicture(op, pSrc, pPicture, pDst,
1216 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1217 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1218 FreePicture(pPicture, 0);
1219 }
1220 else {
1221 if (pDst->polyEdge == PolyEdgeSharp)
1222 maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1223 else
1224 maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1225
1226 for (; ntri; ntri--, tris++)
1227 exaTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
1228 }
1229 }
1230