Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | pixel = pSrc->pSourcePict->solidFill.color; | |
295 | ||
296 | if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, | |
297 | pSrc->pFormat, pSrc->format) || | |
298 | !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, pDst->pFormat)) { | |
299 | RegionUninit(®ion); | |
300 | return -1; | |
301 | } | |
302 | ||
303 | if (pExaScr->do_migration) { | |
304 | ExaMigrationRec pixmaps[1]; | |
305 | ||
306 | pixmaps[0].as_dst = TRUE; | |
307 | pixmaps[0].as_src = FALSE; | |
308 | pixmaps[0].pPix = pDstPix; | |
309 | pixmaps[0].pReg = ®ion; | |
310 | exaDoMigration(pixmaps, 1, TRUE); | |
311 | } | |
312 | ||
313 | if (!exaPixmapHasGpuCopy(pDstPix)) { | |
314 | RegionUninit(®ion); | |
315 | return 0; | |
316 | } | |
317 | ||
318 | if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) { | |
319 | RegionUninit(®ion); | |
320 | return -1; | |
321 | } | |
322 | ||
323 | nbox = RegionNumRects(®ion); | |
324 | pbox = RegionRects(®ion); | |
325 | ||
326 | while (nbox--) { | |
327 | (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, | |
328 | pbox->y2); | |
329 | pbox++; | |
330 | } | |
331 | ||
332 | (*pExaScr->info->DoneSolid) (pDstPix); | |
333 | exaMarkSync(pDst->pDrawable->pScreen); | |
334 | ||
335 | RegionUninit(®ion); | |
336 | return 1; | |
337 | } | |
338 | ||
339 | static int | |
340 | exaTryDriverCompositeRects(CARD8 op, | |
341 | PicturePtr pSrc, | |
342 | PicturePtr pMask, | |
343 | PicturePtr pDst, | |
344 | int nrect, ExaCompositeRectPtr rects) | |
345 | { | |
346 | ExaScreenPriv(pDst->pDrawable->pScreen); | |
347 | int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; | |
348 | int dst_off_x, dst_off_y; | |
349 | PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; | |
350 | ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; | |
351 | ||
352 | if (!pExaScr->info->PrepareComposite) | |
353 | return -1; | |
354 | ||
355 | if (pSrc->pDrawable) { | |
356 | pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); | |
357 | pSrcExaPix = ExaGetPixmapPriv(pSrcPix); | |
358 | } | |
359 | ||
360 | if (pMask && pMask->pDrawable) { | |
361 | pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); | |
362 | pMaskExaPix = ExaGetPixmapPriv(pMaskPix); | |
363 | } | |
364 | ||
365 | pDstPix = exaGetDrawablePixmap(pDst->pDrawable); | |
366 | pDstExaPix = ExaGetPixmapPriv(pDstPix); | |
367 | ||
368 | /* Check whether the accelerator can use these pixmaps. | |
369 | * FIXME: If it cannot, use temporary pixmaps so that the drawing | |
370 | * happens within limits. | |
371 | */ | |
372 | if (pDstExaPix->accel_blocked || | |
373 | (pSrcExaPix && pSrcExaPix->accel_blocked) || | |
374 | (pMaskExaPix && pMaskExaPix->accel_blocked)) { | |
375 | return -1; | |
376 | } | |
377 | ||
378 | if (pExaScr->info->CheckComposite && | |
379 | !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) { | |
380 | return -1; | |
381 | } | |
382 | ||
383 | if (pExaScr->do_migration) { | |
384 | ExaMigrationRec pixmaps[3]; | |
385 | int i = 0; | |
386 | ||
387 | pixmaps[i].as_dst = TRUE; | |
388 | pixmaps[i].as_src = exaOpReadsDestination(op); | |
389 | pixmaps[i].pPix = pDstPix; | |
390 | pixmaps[i].pReg = NULL; | |
391 | i++; | |
392 | ||
393 | if (pSrcPix) { | |
394 | pixmaps[i].as_dst = FALSE; | |
395 | pixmaps[i].as_src = TRUE; | |
396 | pixmaps[i].pPix = pSrcPix; | |
397 | pixmaps[i].pReg = NULL; | |
398 | i++; | |
399 | } | |
400 | ||
401 | if (pMaskPix) { | |
402 | pixmaps[i].as_dst = FALSE; | |
403 | pixmaps[i].as_src = TRUE; | |
404 | pixmaps[i].pPix = pMaskPix; | |
405 | pixmaps[i].pReg = NULL; | |
406 | i++; | |
407 | } | |
408 | ||
409 | exaDoMigration(pixmaps, i, TRUE); | |
410 | } | |
411 | ||
412 | pDstPix = exaGetOffscreenPixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); | |
413 | if (!pDstPix) | |
414 | return 0; | |
415 | ||
416 | if (pSrcPix) { | |
417 | pSrcPix = | |
418 | exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y); | |
419 | if (!pSrcPix) | |
420 | return 0; | |
421 | } | |
422 | ||
423 | if (pMaskPix) { | |
424 | pMaskPix = | |
425 | exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x, &mask_off_y); | |
426 | if (!pMaskPix) | |
427 | return 0; | |
428 | } | |
429 | ||
430 | if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, | |
431 | pMaskPix, pDstPix)) | |
432 | return -1; | |
433 | ||
434 | while (nrect--) { | |
435 | INT16 xDst = rects->xDst + pDst->pDrawable->x; | |
436 | INT16 yDst = rects->yDst + pDst->pDrawable->y; | |
437 | INT16 xMask = rects->xMask; | |
438 | INT16 yMask = rects->yMask; | |
439 | INT16 xSrc = rects->xSrc; | |
440 | INT16 ySrc = rects->ySrc; | |
441 | RegionRec region; | |
442 | BoxPtr pbox; | |
443 | int nbox; | |
444 | ||
445 | if (pMaskPix) { | |
446 | xMask += pMask->pDrawable->x; | |
447 | yMask += pMask->pDrawable->y; | |
448 | } | |
449 | ||
450 | if (pSrcPix) { | |
451 | xSrc += pSrc->pDrawable->x; | |
452 | ySrc += pSrc->pDrawable->y; | |
453 | } | |
454 | ||
455 | if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, | |
456 | xSrc, ySrc, xMask, yMask, xDst, yDst, | |
457 | rects->width, rects->height)) | |
458 | goto next_rect; | |
459 | ||
460 | RegionTranslate(®ion, dst_off_x, dst_off_y); | |
461 | ||
462 | nbox = RegionNumRects(®ion); | |
463 | pbox = RegionRects(®ion); | |
464 | ||
465 | xMask = xMask + mask_off_x - xDst - dst_off_x; | |
466 | yMask = yMask + mask_off_y - yDst - dst_off_y; | |
467 | xSrc = xSrc + src_off_x - xDst - dst_off_x; | |
468 | ySrc = ySrc + src_off_y - yDst - dst_off_y; | |
469 | ||
470 | while (nbox--) { | |
471 | (*pExaScr->info->Composite) (pDstPix, | |
472 | pbox->x1 + xSrc, | |
473 | pbox->y1 + ySrc, | |
474 | pbox->x1 + xMask, | |
475 | pbox->y1 + yMask, | |
476 | pbox->x1, | |
477 | pbox->y1, | |
478 | pbox->x2 - pbox->x1, | |
479 | pbox->y2 - pbox->y1); | |
480 | pbox++; | |
481 | } | |
482 | ||
483 | next_rect: | |
484 | RegionUninit(®ion); | |
485 | ||
486 | rects++; | |
487 | } | |
488 | ||
489 | (*pExaScr->info->DoneComposite) (pDstPix); | |
490 | exaMarkSync(pDst->pDrawable->pScreen); | |
491 | ||
492 | return 1; | |
493 | } | |
494 | ||
495 | /** | |
496 | * Copy a number of rectangles from source to destination in a single | |
497 | * operation. This is specialized for glyph rendering: we don't have the | |
498 | * special-case fallbacks found in exaComposite() - if the driver can support | |
499 | * it, we use the driver functionality, otherwise we fall back straight to | |
500 | * software. | |
501 | */ | |
502 | void | |
503 | exaCompositeRects(CARD8 op, | |
504 | PicturePtr pSrc, | |
505 | PicturePtr pMask, | |
506 | PicturePtr pDst, int nrect, ExaCompositeRectPtr rects) | |
507 | { | |
508 | ExaScreenPriv(pDst->pDrawable->pScreen); | |
509 | int n; | |
510 | ExaCompositeRectPtr r; | |
511 | int ret; | |
512 | ||
513 | /* If we get a mask, that means we're rendering to the exaGlyphs | |
514 | * destination directly, so the damage layer takes care of this. | |
515 | */ | |
516 | if (!pMask) { | |
517 | RegionRec region; | |
518 | int x1 = MAXSHORT; | |
519 | int y1 = MAXSHORT; | |
520 | int x2 = MINSHORT; | |
521 | int y2 = MINSHORT; | |
522 | BoxRec box; | |
523 | ||
524 | /* We have to manage the damage ourselves, since CompositeRects isn't | |
525 | * something in the screen that can be managed by the damage extension, | |
526 | * and EXA depends on damage to track what needs to be migrated between | |
527 | * the gpu and the cpu. | |
528 | */ | |
529 | ||
530 | /* Compute the overall extents of the composited region - we're making | |
531 | * the assumption here that we are compositing a bunch of glyphs that | |
532 | * cluster closely together and damaging each glyph individually would | |
533 | * be a loss compared to damaging the bounding box. | |
534 | */ | |
535 | n = nrect; | |
536 | r = rects; | |
537 | while (n--) { | |
538 | int rect_x2 = r->xDst + r->width; | |
539 | int rect_y2 = r->yDst + r->height; | |
540 | ||
541 | if (r->xDst < x1) | |
542 | x1 = r->xDst; | |
543 | if (r->yDst < y1) | |
544 | y1 = r->yDst; | |
545 | if (rect_x2 > x2) | |
546 | x2 = rect_x2; | |
547 | if (rect_y2 > y2) | |
548 | y2 = rect_y2; | |
549 | ||
550 | r++; | |
551 | } | |
552 | ||
553 | if (x2 <= x1 || y2 <= y1) | |
554 | return; | |
555 | ||
556 | box.x1 = x1; | |
557 | box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; | |
558 | box.y1 = y1; | |
559 | box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; | |
560 | ||
561 | /* The pixmap migration code relies on pendingDamage indicating | |
562 | * the bounds of the current rendering, so we need to force | |
563 | * the actual damage into that region before we do anything, and | |
564 | * (see use of DamagePendingRegion in exaCopyDirty) | |
565 | */ | |
566 | ||
567 | RegionInit(®ion, &box, 1); | |
568 | ||
569 | DamageRegionAppend(pDst->pDrawable, ®ion); | |
570 | ||
571 | RegionUninit(®ion); | |
572 | } | |
573 | ||
574 | /************************************************************/ | |
575 | ||
576 | ValidatePicture(pSrc); | |
577 | if (pMask) | |
578 | ValidatePicture(pMask); | |
579 | ValidatePicture(pDst); | |
580 | ||
581 | ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); | |
582 | ||
583 | if (ret != 1) { | |
584 | if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && | |
585 | (!pExaScr->info->CheckComposite || | |
586 | ((*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask, | |
587 | pDst) && | |
588 | (*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask, | |
589 | pDst)))) { | |
590 | ret = | |
591 | exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, pDst, | |
592 | nrect, rects); | |
593 | if (ret == 1) { | |
594 | op = PictOpAdd; | |
595 | ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, | |
596 | rects); | |
597 | } | |
598 | } | |
599 | ||
600 | if (ret != 1) { | |
601 | n = nrect; | |
602 | r = rects; | |
603 | while (n--) { | |
604 | ExaCheckComposite(op, pSrc, pMask, pDst, | |
605 | r->xSrc, r->ySrc, | |
606 | r->xMask, r->yMask, | |
607 | r->xDst, r->yDst, r->width, r->height); | |
608 | r++; | |
609 | } | |
610 | } | |
611 | } | |
612 | ||
613 | /************************************************************/ | |
614 | ||
615 | if (!pMask) { | |
616 | /* Now we have to flush the damage out from pendingDamage => damage | |
617 | * Calling DamageRegionProcessPending has that effect. | |
618 | */ | |
619 | ||
620 | DamageRegionProcessPending(pDst->pDrawable); | |
621 | } | |
622 | } | |
623 | ||
624 | static int | |
625 | exaTryDriverComposite(CARD8 op, | |
626 | PicturePtr pSrc, | |
627 | PicturePtr pMask, | |
628 | PicturePtr pDst, | |
629 | INT16 xSrc, | |
630 | INT16 ySrc, | |
631 | INT16 xMask, | |
632 | INT16 yMask, | |
633 | INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) | |
634 | { | |
635 | ExaScreenPriv(pDst->pDrawable->pScreen); | |
636 | RegionRec region; | |
637 | BoxPtr pbox; | |
638 | int nbox; | |
639 | int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; | |
640 | PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; | |
641 | ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; | |
642 | ||
643 | if (pSrc->pDrawable) { | |
644 | pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); | |
645 | pSrcExaPix = ExaGetPixmapPriv(pSrcPix); | |
646 | } | |
647 | ||
648 | pDstPix = exaGetDrawablePixmap(pDst->pDrawable); | |
649 | pDstExaPix = ExaGetPixmapPriv(pDstPix); | |
650 | ||
651 | if (pMask && pMask->pDrawable) { | |
652 | pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); | |
653 | pMaskExaPix = ExaGetPixmapPriv(pMaskPix); | |
654 | } | |
655 | ||
656 | /* Check whether the accelerator can use these pixmaps. | |
657 | * FIXME: If it cannot, use temporary pixmaps so that the drawing | |
658 | * happens within limits. | |
659 | */ | |
660 | if (pDstExaPix->accel_blocked || | |
661 | (pSrcExaPix && pSrcExaPix->accel_blocked) || | |
662 | (pMaskExaPix && (pMaskExaPix->accel_blocked))) { | |
663 | return -1; | |
664 | } | |
665 | ||
666 | xDst += pDst->pDrawable->x; | |
667 | yDst += pDst->pDrawable->y; | |
668 | ||
669 | if (pMaskPix) { | |
670 | xMask += pMask->pDrawable->x; | |
671 | yMask += pMask->pDrawable->y; | |
672 | } | |
673 | ||
674 | if (pSrcPix) { | |
675 | xSrc += pSrc->pDrawable->x; | |
676 | ySrc += pSrc->pDrawable->y; | |
677 | } | |
678 | ||
679 | if (pExaScr->info->CheckComposite && | |
680 | !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) { | |
681 | return -1; | |
682 | } | |
683 | ||
684 | if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, | |
685 | xSrc, ySrc, xMask, yMask, xDst, yDst, | |
686 | width, height)) | |
687 | return 1; | |
688 | ||
689 | exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); | |
690 | ||
691 | RegionTranslate(®ion, dst_off_x, dst_off_y); | |
692 | ||
693 | if (pExaScr->do_migration) { | |
694 | ExaMigrationRec pixmaps[3]; | |
695 | int i = 0; | |
696 | ||
697 | pixmaps[i].as_dst = TRUE; | |
698 | pixmaps[i].as_src = exaOpReadsDestination(op); | |
699 | pixmaps[i].pPix = pDstPix; | |
700 | pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; | |
701 | i++; | |
702 | ||
703 | if (pSrcPix) { | |
704 | pixmaps[i].as_dst = FALSE; | |
705 | pixmaps[i].as_src = TRUE; | |
706 | pixmaps[i].pPix = pSrcPix; | |
707 | pixmaps[i].pReg = NULL; | |
708 | i++; | |
709 | } | |
710 | ||
711 | if (pMaskPix) { | |
712 | pixmaps[i].as_dst = FALSE; | |
713 | pixmaps[i].as_src = TRUE; | |
714 | pixmaps[i].pPix = pMaskPix; | |
715 | pixmaps[i].pReg = NULL; | |
716 | i++; | |
717 | } | |
718 | ||
719 | exaDoMigration(pixmaps, i, TRUE); | |
720 | } | |
721 | ||
722 | if (pSrcPix) { | |
723 | pSrcPix = | |
724 | exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y); | |
725 | if (!pSrcPix) { | |
726 | RegionUninit(®ion); | |
727 | return 0; | |
728 | } | |
729 | } | |
730 | ||
731 | if (pMaskPix) { | |
732 | pMaskPix = exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x, | |
733 | &mask_off_y); | |
734 | if (!pMaskPix) { | |
735 | RegionUninit(®ion); | |
736 | return 0; | |
737 | } | |
738 | } | |
739 | ||
740 | if (!exaPixmapHasGpuCopy(pDstPix)) { | |
741 | RegionUninit(®ion); | |
742 | return 0; | |
743 | } | |
744 | ||
745 | if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, | |
746 | pMaskPix, pDstPix)) { | |
747 | RegionUninit(®ion); | |
748 | return -1; | |
749 | } | |
750 | ||
751 | nbox = RegionNumRects(®ion); | |
752 | pbox = RegionRects(®ion); | |
753 | ||
754 | xMask = xMask + mask_off_x - xDst - dst_off_x; | |
755 | yMask = yMask + mask_off_y - yDst - dst_off_y; | |
756 | ||
757 | xSrc = xSrc + src_off_x - xDst - dst_off_x; | |
758 | ySrc = ySrc + src_off_y - yDst - dst_off_y; | |
759 | ||
760 | while (nbox--) { | |
761 | (*pExaScr->info->Composite) (pDstPix, | |
762 | pbox->x1 + xSrc, | |
763 | pbox->y1 + ySrc, | |
764 | pbox->x1 + xMask, | |
765 | pbox->y1 + yMask, | |
766 | pbox->x1, | |
767 | pbox->y1, | |
768 | pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); | |
769 | pbox++; | |
770 | } | |
771 | (*pExaScr->info->DoneComposite) (pDstPix); | |
772 | exaMarkSync(pDst->pDrawable->pScreen); | |
773 | ||
774 | RegionUninit(®ion); | |
775 | return 1; | |
776 | } | |
777 | ||
778 | /** | |
779 | * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of | |
780 | * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component | |
781 | * alpha and limited 1-tmu cards. | |
782 | * | |
783 | * From http://anholt.livejournal.com/32058.html: | |
784 | * | |
785 | * The trouble is that component-alpha rendering requires two different sources | |
786 | * for blending: one for the source value to the blender, which is the | |
787 | * per-channel multiplication of source and mask, and one for the source alpha | |
788 | * for multiplying with the destination channels, which is the multiplication | |
789 | * of the source channels by the mask alpha. So the equation for Over is: | |
790 | * | |
791 | * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A | |
792 | * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R | |
793 | * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G | |
794 | * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B | |
795 | * | |
796 | * But we can do some simpler operations, right? How about PictOpOutReverse, | |
797 | * which has a source factor of 0 and dest factor of (1 - source alpha). We | |
798 | * can get the source alpha value (srca.X = src.A * mask.X) out of the texture | |
799 | * blenders pretty easily. So we can do a component-alpha OutReverse, which | |
800 | * gets us: | |
801 | * | |
802 | * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A | |
803 | * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R | |
804 | * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G | |
805 | * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B | |
806 | * | |
807 | * OK. And if an op doesn't use the source alpha value for the destination | |
808 | * factor, then we can do the channel multiplication in the texture blenders | |
809 | * to get the source value, and ignore the source alpha that we wouldn't use. | |
810 | * We've supported this in the Radeon driver for a long time. An example would | |
811 | * be PictOpAdd, which does: | |
812 | * | |
813 | * dst.A = src.A * mask.A + dst.A | |
814 | * dst.R = src.R * mask.R + dst.R | |
815 | * dst.G = src.G * mask.G + dst.G | |
816 | * dst.B = src.B * mask.B + dst.B | |
817 | * | |
818 | * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right | |
819 | * after it, we get: | |
820 | * | |
821 | * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) | |
822 | * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) | |
823 | * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) | |
824 | * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) | |
825 | */ | |
826 | ||
827 | static int | |
828 | exaTryMagicTwoPassCompositeHelper(CARD8 op, | |
829 | PicturePtr pSrc, | |
830 | PicturePtr pMask, | |
831 | PicturePtr pDst, | |
832 | INT16 xSrc, | |
833 | INT16 ySrc, | |
834 | INT16 xMask, | |
835 | INT16 yMask, | |
836 | INT16 xDst, | |
837 | INT16 yDst, CARD16 width, CARD16 height) | |
838 | { | |
839 | ExaScreenPriv(pDst->pDrawable->pScreen); | |
840 | ||
841 | assert(op == PictOpOver); | |
842 | ||
843 | if (pExaScr->info->CheckComposite && | |
844 | (!(*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask, | |
845 | pDst) || | |
846 | !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask, pDst))) { | |
847 | return -1; | |
848 | } | |
849 | ||
850 | /* Now, we think we should be able to accelerate this operation. First, | |
851 | * composite the destination to be the destination times the source alpha | |
852 | * factors. | |
853 | */ | |
854 | exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, | |
855 | xDst, yDst, width, height); | |
856 | ||
857 | /* Then, add in the source value times the destination alpha factors (1.0). | |
858 | */ | |
859 | exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, | |
860 | xDst, yDst, width, height); | |
861 | ||
862 | return 1; | |
863 | } | |
864 | ||
865 | void | |
866 | exaComposite(CARD8 op, | |
867 | PicturePtr pSrc, | |
868 | PicturePtr pMask, | |
869 | PicturePtr pDst, | |
870 | INT16 xSrc, | |
871 | INT16 ySrc, | |
872 | INT16 xMask, | |
873 | INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) | |
874 | { | |
875 | ExaScreenPriv(pDst->pDrawable->pScreen); | |
876 | int ret = -1; | |
877 | Bool saveSrcRepeat = pSrc->repeat; | |
878 | Bool saveMaskRepeat = pMask ? pMask->repeat : 0; | |
879 | RegionRec region; | |
880 | ||
881 | if (pExaScr->swappedOut) | |
882 | goto fallback; | |
883 | ||
884 | /* Remove repeat in source if useless */ | |
885 | if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && | |
886 | (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && | |
887 | (ySrc + height) <= pSrc->pDrawable->height) | |
888 | pSrc->repeat = 0; | |
889 | ||
890 | if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && | |
891 | (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) | |
892 | { | |
893 | if (pSrc->pDrawable ? | |
894 | (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && | |
895 | pSrc->repeat) : | |
896 | (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) { | |
897 | ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, | |
898 | width, height); | |
899 | if (ret == 1) | |
900 | goto done; | |
901 | } | |
902 | else if (pSrc->pDrawable && !pSrc->transform && | |
903 | ((op == PictOpSrc && | |
904 | (pSrc->format == pDst->format || | |
905 | (PICT_FORMAT_COLOR(pDst->format) && | |
906 | PICT_FORMAT_COLOR(pSrc->format) && | |
907 | pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), | |
908 | PICT_FORMAT_TYPE(pSrc->format), | |
909 | 0, | |
910 | PICT_FORMAT_R(pSrc->format), | |
911 | PICT_FORMAT_G(pSrc->format), | |
912 | PICT_FORMAT_B(pSrc->format))))) | |
913 | || (op == PictOpOver && pSrc->format == pDst->format && | |
914 | !PICT_FORMAT_A(pSrc->format)))) { | |
915 | if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && | |
916 | (xSrc + width <= pSrc->pDrawable->width) && | |
917 | (ySrc + height <= pSrc->pDrawable->height)) { | |
918 | Bool ret; | |
919 | ||
920 | xDst += pDst->pDrawable->x; | |
921 | yDst += pDst->pDrawable->y; | |
922 | xSrc += pSrc->pDrawable->x; | |
923 | ySrc += pSrc->pDrawable->y; | |
924 | ||
925 | if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, | |
926 | xSrc, ySrc, xMask, yMask, xDst, | |
927 | yDst, width, height)) | |
928 | goto done; | |
929 | ||
930 | ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, | |
931 | RegionRects(®ion), | |
932 | RegionNumRects(®ion), xSrc - xDst, | |
933 | ySrc - yDst, FALSE, FALSE); | |
934 | RegionUninit(®ion); | |
935 | ||
936 | /* Reset values to their original values. */ | |
937 | xDst -= pDst->pDrawable->x; | |
938 | yDst -= pDst->pDrawable->y; | |
939 | xSrc -= pSrc->pDrawable->x; | |
940 | ySrc -= pSrc->pDrawable->y; | |
941 | ||
942 | if (!ret) | |
943 | goto fallback; | |
944 | ||
945 | goto done; | |
946 | } | |
947 | ||
948 | if (pSrc->repeat && pSrc->repeatType == RepeatNormal && | |
949 | pSrc->pDrawable->type == DRAWABLE_PIXMAP) { | |
950 | DDXPointRec patOrg; | |
951 | ||
952 | /* Let's see if the driver can do the repeat in one go */ | |
953 | if (pExaScr->info->PrepareComposite && !pSrc->alphaMap && | |
954 | !pDst->alphaMap) { | |
955 | ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, | |
956 | ySrc, xMask, yMask, xDst, yDst, | |
957 | width, height); | |
958 | if (ret == 1) | |
959 | goto done; | |
960 | } | |
961 | ||
962 | /* Now see if we can use exaFillRegionTiled() */ | |
963 | xDst += pDst->pDrawable->x; | |
964 | yDst += pDst->pDrawable->y; | |
965 | xSrc += pSrc->pDrawable->x; | |
966 | ySrc += pSrc->pDrawable->y; | |
967 | ||
968 | if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, xSrc, | |
969 | ySrc, xMask, yMask, xDst, yDst, | |
970 | width, height)) | |
971 | goto done; | |
972 | ||
973 | /* pattern origin is the point in the destination drawable | |
974 | * corresponding to (0,0) in the source */ | |
975 | patOrg.x = xDst - xSrc; | |
976 | patOrg.y = yDst - ySrc; | |
977 | ||
978 | ret = exaFillRegionTiled(pDst->pDrawable, ®ion, | |
979 | (PixmapPtr) pSrc->pDrawable, | |
980 | &patOrg, FB_ALLONES, GXcopy, CT_NONE); | |
981 | ||
982 | RegionUninit(®ion); | |
983 | ||
984 | if (ret) | |
985 | goto done; | |
986 | ||
987 | /* Let's be correct and restore the variables to their original state. */ | |
988 | xDst -= pDst->pDrawable->x; | |
989 | yDst -= pDst->pDrawable->y; | |
990 | xSrc -= pSrc->pDrawable->x; | |
991 | ySrc -= pSrc->pDrawable->y; | |
992 | } | |
993 | } | |
994 | } | |
995 | ||
996 | /* Remove repeat in mask if useless */ | |
997 | if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && | |
998 | xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && | |
999 | yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) | |
1000 | pMask->repeat = 0; | |
1001 | ||
1002 | if (pExaScr->info->PrepareComposite && | |
1003 | !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) { | |
1004 | Bool isSrcSolid; | |
1005 | ||
1006 | ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, | |
1007 | yMask, xDst, yDst, width, height); | |
1008 | if (ret == 1) | |
1009 | goto done; | |
1010 | ||
1011 | /* For generic masks and solid src pictures, mach64 can do Over in two | |
1012 | * passes, similar to the component-alpha case. | |
1013 | */ | |
1014 | isSrcSolid = pSrc->pDrawable ? | |
1015 | (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && | |
1016 | pSrc->repeat) : | |
1017 | (pSrc->pSourcePict->type == SourcePictTypeSolidFill); | |
1018 | ||
1019 | /* If we couldn't do the Composite in a single pass, and it was a | |
1020 | * component-alpha Over, see if we can do it in two passes with | |
1021 | * an OutReverse and then an Add. | |
1022 | */ | |
1023 | if (ret == -1 && op == PictOpOver && pMask && | |
1024 | (pMask->componentAlpha || isSrcSolid)) { | |
1025 | ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, | |
1026 | xSrc, ySrc, | |
1027 | xMask, yMask, xDst, yDst, | |
1028 | width, height); | |
1029 | if (ret == 1) | |
1030 | goto done; | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | fallback: | |
1035 | #if DEBUG_TRACE_FALL | |
1036 | exaPrintCompositeFallback(op, pSrc, pMask, pDst); | |
1037 | #endif | |
1038 | ||
1039 | ExaCheckComposite(op, pSrc, pMask, pDst, xSrc, ySrc, | |
1040 | xMask, yMask, xDst, yDst, width, height); | |
1041 | ||
1042 | done: | |
1043 | pSrc->repeat = saveSrcRepeat; | |
1044 | if (pMask) | |
1045 | pMask->repeat = saveMaskRepeat; | |
1046 | } | |
1047 | ||
1048 | /** | |
1049 | * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead | |
1050 | * of PolyFillRect to initialize the pixmap after creating it, to prevent | |
1051 | * the pixmap from being migrated. | |
1052 | * | |
1053 | * See the comments about exaTrapezoids and exaTriangles. | |
1054 | */ | |
1055 | static PicturePtr | |
1056 | exaCreateAlphaPicture(ScreenPtr pScreen, | |
1057 | PicturePtr pDst, | |
1058 | PictFormatPtr pPictFormat, CARD16 width, CARD16 height) | |
1059 | { | |
1060 | PixmapPtr pPixmap; | |
1061 | PicturePtr pPicture; | |
1062 | GCPtr pGC; | |
1063 | int error; | |
1064 | xRectangle rect; | |
1065 | ||
1066 | if (width > 32767 || height > 32767) | |
1067 | return 0; | |
1068 | ||
1069 | if (!pPictFormat) { | |
1070 | if (pDst->polyEdge == PolyEdgeSharp) | |
1071 | pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); | |
1072 | else | |
1073 | pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); | |
1074 | if (!pPictFormat) | |
1075 | return 0; | |
1076 | } | |
1077 | ||
1078 | pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, | |
1079 | pPictFormat->depth, 0); | |
1080 | if (!pPixmap) | |
1081 | return 0; | |
1082 | pGC = GetScratchGC(pPixmap->drawable.depth, pScreen); | |
1083 | if (!pGC) { | |
1084 | (*pScreen->DestroyPixmap) (pPixmap); | |
1085 | return 0; | |
1086 | } | |
1087 | ValidateGC(&pPixmap->drawable, pGC); | |
1088 | rect.x = 0; | |
1089 | rect.y = 0; | |
1090 | rect.width = width; | |
1091 | rect.height = height; | |
1092 | ExaCheckPolyFillRect(&pPixmap->drawable, pGC, 1, &rect); | |
1093 | exaPixmapDirty(pPixmap, 0, 0, width, height); | |
1094 | FreeScratchGC(pGC); | |
1095 | pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, | |
1096 | 0, 0, serverClient, &error); | |
1097 | (*pScreen->DestroyPixmap) (pPixmap); | |
1098 | return pPicture; | |
1099 | } | |
1100 | ||
1101 | /** | |
1102 | * exaTrapezoids is essentially a copy of miTrapezoids that uses | |
1103 | * exaCreateAlphaPicture instead of miCreateAlphaPicture. | |
1104 | * | |
1105 | * The problem with miCreateAlphaPicture is that it calls PolyFillRect | |
1106 | * to initialize the contents after creating the pixmap, which | |
1107 | * causes the pixmap to be moved in for acceleration. The subsequent | |
1108 | * call to RasterizeTrapezoid won't be accelerated however, which | |
1109 | * forces the pixmap to be moved out again. | |
1110 | * | |
1111 | * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect | |
1112 | * to initialize the contents. | |
1113 | */ | |
1114 | void | |
1115 | exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, | |
1116 | PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, | |
1117 | int ntrap, xTrapezoid * traps) | |
1118 | { | |
1119 | ScreenPtr pScreen = pDst->pDrawable->pScreen; | |
1120 | PictureScreenPtr ps = GetPictureScreen(pScreen); | |
1121 | BoxRec bounds; | |
1122 | ||
1123 | if (maskFormat) { | |
1124 | PicturePtr pPicture; | |
1125 | INT16 xDst, yDst; | |
1126 | INT16 xRel, yRel; | |
1127 | ||
1128 | miTrapezoidBounds(ntrap, traps, &bounds); | |
1129 | ||
1130 | if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) | |
1131 | return; | |
1132 | ||
1133 | xDst = traps[0].left.p1.x >> 16; | |
1134 | yDst = traps[0].left.p1.y >> 16; | |
1135 | ||
1136 | pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat, | |
1137 | bounds.x2 - bounds.x1, | |
1138 | bounds.y2 - bounds.y1); | |
1139 | if (!pPicture) | |
1140 | return; | |
1141 | ||
1142 | exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); | |
1143 | for (; ntrap; ntrap--, traps++) | |
1144 | (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1); | |
1145 | exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); | |
1146 | ||
1147 | xRel = bounds.x1 + xSrc - xDst; | |
1148 | yRel = bounds.y1 + ySrc - yDst; | |
1149 | CompositePicture(op, pSrc, pPicture, pDst, | |
1150 | xRel, yRel, 0, 0, bounds.x1, bounds.y1, | |
1151 | bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); | |
1152 | FreePicture(pPicture, 0); | |
1153 | } | |
1154 | else { | |
1155 | if (pDst->polyEdge == PolyEdgeSharp) | |
1156 | maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); | |
1157 | else | |
1158 | maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); | |
1159 | for (; ntrap; ntrap--, traps++) | |
1160 | exaTrapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); | |
1161 | } | |
1162 | } | |
1163 | ||
1164 | /** | |
1165 | * exaTriangles is essentially a copy of miTriangles that uses | |
1166 | * exaCreateAlphaPicture instead of miCreateAlphaPicture. | |
1167 | * | |
1168 | * The problem with miCreateAlphaPicture is that it calls PolyFillRect | |
1169 | * to initialize the contents after creating the pixmap, which | |
1170 | * causes the pixmap to be moved in for acceleration. The subsequent | |
1171 | * call to AddTriangles won't be accelerated however, which forces the pixmap | |
1172 | * to be moved out again. | |
1173 | * | |
1174 | * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect | |
1175 | * to initialize the contents. | |
1176 | */ | |
1177 | void | |
1178 | exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, | |
1179 | PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, | |
1180 | int ntri, xTriangle * tris) | |
1181 | { | |
1182 | ScreenPtr pScreen = pDst->pDrawable->pScreen; | |
1183 | PictureScreenPtr ps = GetPictureScreen(pScreen); | |
1184 | BoxRec bounds; | |
1185 | ||
1186 | if (maskFormat) { | |
1187 | PicturePtr pPicture; | |
1188 | INT16 xDst, yDst; | |
1189 | INT16 xRel, yRel; | |
1190 | ||
1191 | miTriangleBounds(ntri, tris, &bounds); | |
1192 | ||
1193 | if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) | |
1194 | return; | |
1195 | ||
1196 | xDst = tris[0].p1.x >> 16; | |
1197 | yDst = tris[0].p1.y >> 16; | |
1198 | ||
1199 | pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat, | |
1200 | bounds.x2 - bounds.x1, | |
1201 | bounds.y2 - bounds.y1); | |
1202 | if (!pPicture) | |
1203 | return; | |
1204 | ||
1205 | exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); | |
1206 | (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); | |
1207 | exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); | |
1208 | ||
1209 | xRel = bounds.x1 + xSrc - xDst; | |
1210 | yRel = bounds.y1 + ySrc - yDst; | |
1211 | CompositePicture(op, pSrc, pPicture, pDst, | |
1212 | xRel, yRel, 0, 0, bounds.x1, bounds.y1, | |
1213 | bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); | |
1214 | FreePicture(pPicture, 0); | |
1215 | } | |
1216 | else { | |
1217 | if (pDst->polyEdge == PolyEdgeSharp) | |
1218 | maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); | |
1219 | else | |
1220 | maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); | |
1221 | ||
1222 | for (; ntri; ntri--, tris++) | |
1223 | exaTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); | |
1224 | } | |
1225 | } |