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 | * Authors: | |
25 | * Eric Anholt <eric@anholt.net> | |
26 | * Michel Dänzer <michel@tungstengraphics.com> | |
27 | * | |
28 | */ | |
29 | ||
30 | #ifdef HAVE_DIX_CONFIG_H | |
31 | #include <dix-config.h> | |
32 | #endif | |
33 | #include "exa_priv.h" | |
34 | #include <X11/fonts/fontstruct.h> | |
35 | #include "dixfontstr.h" | |
36 | #include "exa.h" | |
37 | ||
38 | static void | |
39 | exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, | |
40 | DDXPointPtr ppt, int *pwidth, int fSorted) | |
41 | { | |
42 | ScreenPtr pScreen = pDrawable->pScreen; | |
43 | ||
44 | ExaScreenPriv(pScreen); | |
45 | RegionPtr pClip = fbGetCompositeClip(pGC); | |
46 | PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); | |
47 | ||
48 | ExaPixmapPriv(pPixmap); | |
49 | BoxPtr pextent, pbox; | |
50 | int nbox; | |
51 | int extentX1, extentX2, extentY1, extentY2; | |
52 | int fullX1, fullX2, fullY1; | |
53 | int partX1, partX2; | |
54 | int off_x, off_y; | |
55 | ||
56 | if (pExaScr->fallback_counter || | |
57 | pExaScr->swappedOut || | |
58 | pGC->fillStyle != FillSolid || pExaPixmap->accel_blocked) { | |
59 | ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted); | |
60 | return; | |
61 | } | |
62 | ||
63 | if (pExaScr->do_migration) { | |
64 | ExaMigrationRec pixmaps[1]; | |
65 | ||
66 | pixmaps[0].as_dst = TRUE; | |
67 | pixmaps[0].as_src = FALSE; | |
68 | pixmaps[0].pPix = pPixmap; | |
69 | pixmaps[0].pReg = NULL; | |
70 | ||
71 | exaDoMigration(pixmaps, 1, TRUE); | |
72 | } | |
73 | ||
74 | if (!(pPixmap = exaGetOffscreenPixmap(pDrawable, &off_x, &off_y)) || | |
75 | !(*pExaScr->info->PrepareSolid) (pPixmap, | |
76 | pGC->alu, | |
77 | pGC->planemask, pGC->fgPixel)) { | |
78 | ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted); | |
79 | return; | |
80 | } | |
81 | ||
82 | pextent = RegionExtents(pClip); | |
83 | extentX1 = pextent->x1; | |
84 | extentY1 = pextent->y1; | |
85 | extentX2 = pextent->x2; | |
86 | extentY2 = pextent->y2; | |
87 | while (n--) { | |
88 | fullX1 = ppt->x; | |
89 | fullY1 = ppt->y; | |
90 | fullX2 = fullX1 + (int) *pwidth; | |
91 | ppt++; | |
92 | pwidth++; | |
93 | ||
94 | if (fullY1 < extentY1 || extentY2 <= fullY1) | |
95 | continue; | |
96 | ||
97 | if (fullX1 < extentX1) | |
98 | fullX1 = extentX1; | |
99 | ||
100 | if (fullX2 > extentX2) | |
101 | fullX2 = extentX2; | |
102 | ||
103 | if (fullX1 >= fullX2) | |
104 | continue; | |
105 | ||
106 | nbox = RegionNumRects(pClip); | |
107 | if (nbox == 1) { | |
108 | (*pExaScr->info->Solid) (pPixmap, | |
109 | fullX1 + off_x, fullY1 + off_y, | |
110 | fullX2 + off_x, fullY1 + 1 + off_y); | |
111 | } | |
112 | else { | |
113 | pbox = RegionRects(pClip); | |
114 | while (nbox--) { | |
115 | if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) { | |
116 | partX1 = pbox->x1; | |
117 | if (partX1 < fullX1) | |
118 | partX1 = fullX1; | |
119 | partX2 = pbox->x2; | |
120 | if (partX2 > fullX2) | |
121 | partX2 = fullX2; | |
122 | if (partX2 > partX1) { | |
123 | (*pExaScr->info->Solid) (pPixmap, | |
124 | partX1 + off_x, fullY1 + off_y, | |
125 | partX2 + off_x, | |
126 | fullY1 + 1 + off_y); | |
127 | } | |
128 | } | |
129 | pbox++; | |
130 | } | |
131 | } | |
132 | } | |
133 | (*pExaScr->info->DoneSolid) (pPixmap); | |
134 | exaMarkSync(pScreen); | |
135 | } | |
136 | ||
137 | static Bool | |
138 | exaDoPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, | |
139 | int w, int h, int format, char *bits, int src_stride) | |
140 | { | |
141 | ExaScreenPriv(pDrawable->pScreen); | |
142 | PixmapPtr pPix = exaGetDrawablePixmap(pDrawable); | |
143 | ||
144 | ExaPixmapPriv(pPix); | |
145 | RegionPtr pClip; | |
146 | BoxPtr pbox; | |
147 | int nbox; | |
148 | int xoff, yoff; | |
149 | int bpp = pDrawable->bitsPerPixel; | |
150 | Bool ret = TRUE; | |
151 | ||
152 | if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || | |
153 | !pExaScr->info->UploadToScreen) | |
154 | return FALSE; | |
155 | ||
156 | /* If there's a system copy, we want to save the result there */ | |
157 | if (pExaPixmap->pDamage) | |
158 | return FALSE; | |
159 | ||
160 | /* Don't bother with under 8bpp, XYPixmaps. */ | |
161 | if (format != ZPixmap || bpp < 8) | |
162 | return FALSE; | |
163 | ||
164 | /* Only accelerate copies: no rop or planemask. */ | |
165 | if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) | |
166 | return FALSE; | |
167 | ||
168 | if (pExaScr->swappedOut) | |
169 | return FALSE; | |
170 | ||
171 | if (pExaScr->do_migration) { | |
172 | ExaMigrationRec pixmaps[1]; | |
173 | ||
174 | pixmaps[0].as_dst = TRUE; | |
175 | pixmaps[0].as_src = FALSE; | |
176 | pixmaps[0].pPix = pPix; | |
177 | pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); | |
178 | ||
179 | exaDoMigration(pixmaps, 1, TRUE); | |
180 | } | |
181 | ||
182 | pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); | |
183 | ||
184 | if (!pPix) | |
185 | return FALSE; | |
186 | ||
187 | x += pDrawable->x; | |
188 | y += pDrawable->y; | |
189 | ||
190 | pClip = fbGetCompositeClip(pGC); | |
191 | for (nbox = RegionNumRects(pClip), | |
192 | pbox = RegionRects(pClip); nbox--; pbox++) { | |
193 | int x1 = x; | |
194 | int y1 = y; | |
195 | int x2 = x + w; | |
196 | int y2 = y + h; | |
197 | char *src; | |
198 | Bool ok; | |
199 | ||
200 | if (x1 < pbox->x1) | |
201 | x1 = pbox->x1; | |
202 | if (y1 < pbox->y1) | |
203 | y1 = pbox->y1; | |
204 | if (x2 > pbox->x2) | |
205 | x2 = pbox->x2; | |
206 | if (y2 > pbox->y2) | |
207 | y2 = pbox->y2; | |
208 | if (x1 >= x2 || y1 >= y2) | |
209 | continue; | |
210 | ||
211 | src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); | |
212 | ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, | |
213 | x2 - x1, y2 - y1, src, src_stride); | |
214 | /* We have to fall back completely, and ignore what has already been completed. | |
215 | * Messing with the fb layer directly like we used to is completely unacceptable. | |
216 | */ | |
217 | if (!ok) { | |
218 | ret = FALSE; | |
219 | break; | |
220 | } | |
221 | } | |
222 | ||
223 | if (ret) | |
224 | exaMarkSync(pDrawable->pScreen); | |
225 | ||
226 | return ret; | |
227 | } | |
228 | ||
229 | static void | |
230 | exaPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, | |
231 | int w, int h, int leftPad, int format, char *bits) | |
232 | { | |
233 | if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits, | |
234 | PixmapBytePad(w, pDrawable->depth))) | |
235 | ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, | |
236 | bits); | |
237 | } | |
238 | ||
239 | static Bool inline | |
240 | exaCopyNtoNTwoDir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, | |
241 | GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) | |
242 | { | |
243 | ExaScreenPriv(pDstDrawable->pScreen); | |
244 | PixmapPtr pSrcPixmap, pDstPixmap; | |
245 | int src_off_x, src_off_y, dst_off_x, dst_off_y; | |
246 | int dirsetup; | |
247 | ||
248 | /* Need to get both pixmaps to call the driver routines */ | |
249 | pSrcPixmap = exaGetOffscreenPixmap(pSrcDrawable, &src_off_x, &src_off_y); | |
250 | pDstPixmap = exaGetOffscreenPixmap(pDstDrawable, &dst_off_x, &dst_off_y); | |
251 | if (!pSrcPixmap || !pDstPixmap) | |
252 | return FALSE; | |
253 | ||
254 | /* | |
255 | * Now the case of a chip that only supports xdir = ydir = 1 or | |
256 | * xdir = ydir = -1, but we have xdir != ydir. | |
257 | */ | |
258 | dirsetup = 0; /* No direction set up yet. */ | |
259 | for (; nbox; pbox++, nbox--) { | |
260 | if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { | |
261 | /* Do a xdir = ydir = -1 blit instead. */ | |
262 | if (dirsetup != -1) { | |
263 | if (dirsetup != 0) | |
264 | pExaScr->info->DoneCopy(pDstPixmap); | |
265 | dirsetup = -1; | |
266 | if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, | |
267 | pDstPixmap, | |
268 | -1, -1, | |
269 | pGC ? pGC->alu : GXcopy, | |
270 | pGC ? pGC->planemask : | |
271 | FB_ALLONES)) | |
272 | return FALSE; | |
273 | } | |
274 | (*pExaScr->info->Copy) (pDstPixmap, | |
275 | src_off_x + pbox->x1 + dx, | |
276 | src_off_y + pbox->y1 + dy, | |
277 | dst_off_x + pbox->x1, | |
278 | dst_off_y + pbox->y1, | |
279 | pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); | |
280 | } | |
281 | else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { | |
282 | /* Do a xdir = ydir = 1 blit instead. */ | |
283 | if (dirsetup != 1) { | |
284 | if (dirsetup != 0) | |
285 | pExaScr->info->DoneCopy(pDstPixmap); | |
286 | dirsetup = 1; | |
287 | if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, | |
288 | pDstPixmap, | |
289 | 1, 1, | |
290 | pGC ? pGC->alu : GXcopy, | |
291 | pGC ? pGC->planemask : | |
292 | FB_ALLONES)) | |
293 | return FALSE; | |
294 | } | |
295 | (*pExaScr->info->Copy) (pDstPixmap, | |
296 | src_off_x + pbox->x1 + dx, | |
297 | src_off_y + pbox->y1 + dy, | |
298 | dst_off_x + pbox->x1, | |
299 | dst_off_y + pbox->y1, | |
300 | pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); | |
301 | } | |
302 | else if (dx >= 0) { | |
303 | /* | |
304 | * xdir = 1, ydir = -1. | |
305 | * Perform line-by-line xdir = ydir = 1 blits, going up. | |
306 | */ | |
307 | int i; | |
308 | ||
309 | if (dirsetup != 1) { | |
310 | if (dirsetup != 0) | |
311 | pExaScr->info->DoneCopy(pDstPixmap); | |
312 | dirsetup = 1; | |
313 | if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, | |
314 | pDstPixmap, | |
315 | 1, 1, | |
316 | pGC ? pGC->alu : GXcopy, | |
317 | pGC ? pGC->planemask : | |
318 | FB_ALLONES)) | |
319 | return FALSE; | |
320 | } | |
321 | for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) | |
322 | (*pExaScr->info->Copy) (pDstPixmap, | |
323 | src_off_x + pbox->x1 + dx, | |
324 | src_off_y + pbox->y1 + dy + i, | |
325 | dst_off_x + pbox->x1, | |
326 | dst_off_y + pbox->y1 + i, | |
327 | pbox->x2 - pbox->x1, 1); | |
328 | } | |
329 | else { | |
330 | /* | |
331 | * xdir = -1, ydir = 1. | |
332 | * Perform line-by-line xdir = ydir = -1 blits, going down. | |
333 | */ | |
334 | int i; | |
335 | ||
336 | if (dirsetup != -1) { | |
337 | if (dirsetup != 0) | |
338 | pExaScr->info->DoneCopy(pDstPixmap); | |
339 | dirsetup = -1; | |
340 | if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, | |
341 | pDstPixmap, | |
342 | -1, -1, | |
343 | pGC ? pGC->alu : GXcopy, | |
344 | pGC ? pGC->planemask : | |
345 | FB_ALLONES)) | |
346 | return FALSE; | |
347 | } | |
348 | for (i = 0; i < pbox->y2 - pbox->y1; i++) | |
349 | (*pExaScr->info->Copy) (pDstPixmap, | |
350 | src_off_x + pbox->x1 + dx, | |
351 | src_off_y + pbox->y1 + dy + i, | |
352 | dst_off_x + pbox->x1, | |
353 | dst_off_y + pbox->y1 + i, | |
354 | pbox->x2 - pbox->x1, 1); | |
355 | } | |
356 | } | |
357 | if (dirsetup != 0) | |
358 | pExaScr->info->DoneCopy(pDstPixmap); | |
359 | exaMarkSync(pDstDrawable->pScreen); | |
360 | return TRUE; | |
361 | } | |
362 | ||
363 | Bool | |
364 | exaHWCopyNtoN(DrawablePtr pSrcDrawable, | |
365 | DrawablePtr pDstDrawable, | |
366 | GCPtr pGC, | |
367 | BoxPtr pbox, | |
368 | int nbox, int dx, int dy, Bool reverse, Bool upsidedown) | |
369 | { | |
370 | ExaScreenPriv(pDstDrawable->pScreen); | |
371 | PixmapPtr pSrcPixmap, pDstPixmap; | |
372 | ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; | |
373 | int src_off_x, src_off_y; | |
374 | int dst_off_x, dst_off_y; | |
375 | RegionPtr srcregion = NULL, dstregion = NULL; | |
376 | xRectangle *rects; | |
377 | Bool ret = TRUE; | |
378 | ||
379 | /* avoid doing copy operations if no boxes */ | |
380 | if (nbox == 0) | |
381 | return TRUE; | |
382 | ||
383 | pSrcPixmap = exaGetDrawablePixmap(pSrcDrawable); | |
384 | pDstPixmap = exaGetDrawablePixmap(pDstDrawable); | |
385 | ||
386 | exaGetDrawableDeltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); | |
387 | exaGetDrawableDeltas(pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); | |
388 | ||
389 | rects = malloc(nbox * sizeof(xRectangle)); | |
390 | ||
391 | if (rects) { | |
392 | int i; | |
393 | int ordering; | |
394 | ||
395 | for (i = 0; i < nbox; i++) { | |
396 | rects[i].x = pbox[i].x1 + dx + src_off_x; | |
397 | rects[i].y = pbox[i].y1 + dy + src_off_y; | |
398 | rects[i].width = pbox[i].x2 - pbox[i].x1; | |
399 | rects[i].height = pbox[i].y2 - pbox[i].y1; | |
400 | } | |
401 | ||
402 | /* This must match the RegionCopy() logic for reversing rect order */ | |
403 | if (nbox == 1 || (dx > 0 && dy > 0) || | |
404 | (pDstDrawable != pSrcDrawable && | |
405 | (pDstDrawable->type != DRAWABLE_WINDOW || | |
406 | pSrcDrawable->type != DRAWABLE_WINDOW))) | |
407 | ordering = CT_YXBANDED; | |
408 | else | |
409 | ordering = CT_UNSORTED; | |
410 | ||
411 | srcregion = RegionFromRects(nbox, rects, ordering); | |
412 | free(rects); | |
413 | ||
414 | if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, | |
415 | pGC->fillStyle, pGC->alu, | |
416 | pGC->clientClipType)) { | |
417 | dstregion = RegionCreate(NullBox, 0); | |
418 | RegionCopy(dstregion, srcregion); | |
419 | RegionTranslate(dstregion, dst_off_x - dx - src_off_x, | |
420 | dst_off_y - dy - src_off_y); | |
421 | } | |
422 | } | |
423 | ||
424 | pSrcExaPixmap = ExaGetPixmapPriv(pSrcPixmap); | |
425 | pDstExaPixmap = ExaGetPixmapPriv(pDstPixmap); | |
426 | ||
427 | /* Check whether the accelerator can use this pixmap. | |
428 | * If the pitch of the pixmaps is out of range, there's nothing | |
429 | * we can do but fall back to software rendering. | |
430 | */ | |
431 | if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || | |
432 | pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) | |
433 | goto fallback; | |
434 | ||
435 | /* If the width or the height of either of the pixmaps | |
436 | * is out of range, check whether the boxes are actually out of the | |
437 | * addressable range as well. If they aren't, we can still do | |
438 | * the copying in hardware. | |
439 | */ | |
440 | if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { | |
441 | int i; | |
442 | ||
443 | for (i = 0; i < nbox; i++) { | |
444 | /* src */ | |
445 | if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || | |
446 | (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) | |
447 | goto fallback; | |
448 | ||
449 | /* dst */ | |
450 | if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || | |
451 | (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) | |
452 | goto fallback; | |
453 | } | |
454 | } | |
455 | ||
456 | if (pExaScr->do_migration) { | |
457 | ExaMigrationRec pixmaps[2]; | |
458 | ||
459 | pixmaps[0].as_dst = TRUE; | |
460 | pixmaps[0].as_src = FALSE; | |
461 | pixmaps[0].pPix = pDstPixmap; | |
462 | pixmaps[0].pReg = dstregion; | |
463 | pixmaps[1].as_dst = FALSE; | |
464 | pixmaps[1].as_src = TRUE; | |
465 | pixmaps[1].pPix = pSrcPixmap; | |
466 | pixmaps[1].pReg = srcregion; | |
467 | ||
468 | exaDoMigration(pixmaps, 2, TRUE); | |
469 | } | |
470 | ||
471 | /* Mixed directions must be handled specially if the card is lame */ | |
472 | if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && | |
473 | reverse != upsidedown) { | |
474 | if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, | |
475 | dx, dy)) | |
476 | goto out; | |
477 | goto fallback; | |
478 | } | |
479 | ||
480 | if (exaPixmapHasGpuCopy(pDstPixmap)) { | |
481 | /* Normal blitting. */ | |
482 | if (exaPixmapHasGpuCopy(pSrcPixmap)) { | |
483 | if (!(*pExaScr->info->PrepareCopy) | |
484 | (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, upsidedown ? -1 : 1, | |
485 | pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) { | |
486 | goto fallback; | |
487 | } | |
488 | ||
489 | while (nbox--) { | |
490 | (*pExaScr->info->Copy) (pDstPixmap, | |
491 | pbox->x1 + dx + src_off_x, | |
492 | pbox->y1 + dy + src_off_y, | |
493 | pbox->x1 + dst_off_x, | |
494 | pbox->y1 + dst_off_y, | |
495 | pbox->x2 - pbox->x1, | |
496 | pbox->y2 - pbox->y1); | |
497 | pbox++; | |
498 | } | |
499 | ||
500 | (*pExaScr->info->DoneCopy) (pDstPixmap); | |
501 | exaMarkSync(pDstDrawable->pScreen); | |
502 | /* UTS: mainly for SHM PutImage's secondary path. | |
503 | * | |
504 | * Only taking this path for directly accessible pixmaps. | |
505 | */ | |
506 | } | |
507 | else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { | |
508 | int bpp = pSrcDrawable->bitsPerPixel; | |
509 | int src_stride = exaGetPixmapPitch(pSrcPixmap); | |
510 | CARD8 *src = NULL; | |
511 | ||
512 | if (!pExaScr->info->UploadToScreen) | |
513 | goto fallback; | |
514 | ||
515 | if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) | |
516 | goto fallback; | |
517 | ||
518 | if (pSrcDrawable->bitsPerPixel < 8) | |
519 | goto fallback; | |
520 | ||
521 | if (pGC && | |
522 | !(pGC->alu == GXcopy && | |
523 | EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) | |
524 | goto fallback; | |
525 | ||
526 | while (nbox--) { | |
527 | src = | |
528 | pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + | |
529 | src_off_y) * src_stride + | |
530 | (pbox->x1 + dx + src_off_x) * (bpp / 8); | |
531 | if (!pExaScr->info-> | |
532 | UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, | |
533 | pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, | |
534 | pbox->y2 - pbox->y1, (char *) src, | |
535 | src_stride)) | |
536 | goto fallback; | |
537 | ||
538 | pbox++; | |
539 | } | |
540 | } | |
541 | else | |
542 | goto fallback; | |
543 | } | |
544 | else | |
545 | goto fallback; | |
546 | ||
547 | goto out; | |
548 | ||
549 | fallback: | |
550 | ret = FALSE; | |
551 | ||
552 | out: | |
553 | if (dstregion) { | |
554 | RegionUninit(dstregion); | |
555 | RegionDestroy(dstregion); | |
556 | } | |
557 | if (srcregion) { | |
558 | RegionUninit(srcregion); | |
559 | RegionDestroy(srcregion); | |
560 | } | |
561 | ||
562 | return ret; | |
563 | } | |
564 | ||
565 | void | |
566 | exaCopyNtoN(DrawablePtr pSrcDrawable, | |
567 | DrawablePtr pDstDrawable, | |
568 | GCPtr pGC, | |
569 | BoxPtr pbox, | |
570 | int nbox, | |
571 | int dx, | |
572 | int dy, | |
573 | Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) | |
574 | { | |
575 | ExaScreenPriv(pDstDrawable->pScreen); | |
576 | ||
577 | if (pExaScr->fallback_counter || | |
578 | (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW)) | |
579 | return; | |
580 | ||
581 | if (exaHWCopyNtoN | |
582 | (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, | |
583 | upsidedown)) | |
584 | return; | |
585 | ||
586 | /* This is a CopyWindow, it's cleaner to fallback at the original call. */ | |
587 | if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) { | |
588 | pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; | |
589 | return; | |
590 | } | |
591 | ||
592 | /* fallback */ | |
593 | ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, | |
594 | reverse, upsidedown, bitplane, closure); | |
595 | } | |
596 | ||
597 | RegionPtr | |
598 | exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, | |
599 | int srcx, int srcy, int width, int height, int dstx, int dsty) | |
600 | { | |
601 | ExaScreenPriv(pDstDrawable->pScreen); | |
602 | ||
603 | if (pExaScr->fallback_counter || pExaScr->swappedOut) { | |
604 | return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, | |
605 | srcx, srcy, width, height, dstx, dsty); | |
606 | } | |
607 | ||
608 | return miDoCopy(pSrcDrawable, pDstDrawable, pGC, | |
609 | srcx, srcy, width, height, | |
610 | dstx, dsty, exaCopyNtoN, 0, NULL); | |
611 | } | |
612 | ||
613 | static void | |
614 | exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, | |
615 | DDXPointPtr ppt) | |
616 | { | |
617 | ExaScreenPriv(pDrawable->pScreen); | |
618 | int i; | |
619 | xRectangle *prect; | |
620 | ||
621 | /* If we can't reuse the current GC as is, don't bother accelerating the | |
622 | * points. | |
623 | */ | |
624 | if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) { | |
625 | ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); | |
626 | return; | |
627 | } | |
628 | ||
629 | prect = malloc(sizeof(xRectangle) * npt); | |
630 | for (i = 0; i < npt; i++) { | |
631 | prect[i].x = ppt[i].x; | |
632 | prect[i].y = ppt[i].y; | |
633 | if (i > 0 && mode == CoordModePrevious) { | |
634 | prect[i].x += prect[i - 1].x; | |
635 | prect[i].y += prect[i - 1].y; | |
636 | } | |
637 | prect[i].width = 1; | |
638 | prect[i].height = 1; | |
639 | } | |
640 | pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); | |
641 | free(prect); | |
642 | } | |
643 | ||
644 | /** | |
645 | * exaPolylines() checks if it can accelerate the lines as a group of | |
646 | * horizontal or vertical lines (rectangles), and uses existing rectangle fill | |
647 | * acceleration if so. | |
648 | */ | |
649 | static void | |
650 | exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, | |
651 | DDXPointPtr ppt) | |
652 | { | |
653 | ExaScreenPriv(pDrawable->pScreen); | |
654 | xRectangle *prect; | |
655 | int x1, x2, y1, y2; | |
656 | int i; | |
657 | ||
658 | if (pExaScr->fallback_counter) { | |
659 | ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); | |
660 | return; | |
661 | } | |
662 | ||
663 | /* Don't try to do wide lines or non-solid fill style. */ | |
664 | if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || | |
665 | pGC->fillStyle != FillSolid) { | |
666 | ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); | |
667 | return; | |
668 | } | |
669 | ||
670 | prect = malloc(sizeof(xRectangle) * (npt - 1)); | |
671 | x1 = ppt[0].x; | |
672 | y1 = ppt[0].y; | |
673 | /* If we have any non-horizontal/vertical, fall back. */ | |
674 | for (i = 0; i < npt - 1; i++) { | |
675 | if (mode == CoordModePrevious) { | |
676 | x2 = x1 + ppt[i + 1].x; | |
677 | y2 = y1 + ppt[i + 1].y; | |
678 | } | |
679 | else { | |
680 | x2 = ppt[i + 1].x; | |
681 | y2 = ppt[i + 1].y; | |
682 | } | |
683 | ||
684 | if (x1 != x2 && y1 != y2) { | |
685 | free(prect); | |
686 | ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); | |
687 | return; | |
688 | } | |
689 | ||
690 | if (x1 < x2) { | |
691 | prect[i].x = x1; | |
692 | prect[i].width = x2 - x1 + 1; | |
693 | } | |
694 | else { | |
695 | prect[i].x = x2; | |
696 | prect[i].width = x1 - x2 + 1; | |
697 | } | |
698 | if (y1 < y2) { | |
699 | prect[i].y = y1; | |
700 | prect[i].height = y2 - y1 + 1; | |
701 | } | |
702 | else { | |
703 | prect[i].y = y2; | |
704 | prect[i].height = y1 - y2 + 1; | |
705 | } | |
706 | ||
707 | x1 = x2; | |
708 | y1 = y2; | |
709 | } | |
710 | pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); | |
711 | free(prect); | |
712 | } | |
713 | ||
714 | /** | |
715 | * exaPolySegment() checks if it can accelerate the lines as a group of | |
716 | * horizontal or vertical lines (rectangles), and uses existing rectangle fill | |
717 | * acceleration if so. | |
718 | */ | |
719 | static void | |
720 | exaPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg) | |
721 | { | |
722 | ExaScreenPriv(pDrawable->pScreen); | |
723 | xRectangle *prect; | |
724 | int i; | |
725 | ||
726 | /* Don't try to do wide lines or non-solid fill style. */ | |
727 | if (pExaScr->fallback_counter || pGC->lineWidth != 0 || | |
728 | pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) { | |
729 | ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); | |
730 | return; | |
731 | } | |
732 | ||
733 | /* If we have any non-horizontal/vertical, fall back. */ | |
734 | for (i = 0; i < nseg; i++) { | |
735 | if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { | |
736 | ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); | |
737 | return; | |
738 | } | |
739 | } | |
740 | ||
741 | prect = malloc(sizeof(xRectangle) * nseg); | |
742 | for (i = 0; i < nseg; i++) { | |
743 | if (pSeg[i].x1 < pSeg[i].x2) { | |
744 | prect[i].x = pSeg[i].x1; | |
745 | prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; | |
746 | } | |
747 | else { | |
748 | prect[i].x = pSeg[i].x2; | |
749 | prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; | |
750 | } | |
751 | if (pSeg[i].y1 < pSeg[i].y2) { | |
752 | prect[i].y = pSeg[i].y1; | |
753 | prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; | |
754 | } | |
755 | else { | |
756 | prect[i].y = pSeg[i].y2; | |
757 | prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; | |
758 | } | |
759 | ||
760 | /* don't paint last pixel */ | |
761 | if (pGC->capStyle == CapNotLast) { | |
762 | if (prect[i].width == 1) | |
763 | prect[i].height--; | |
764 | else | |
765 | prect[i].width--; | |
766 | } | |
767 | } | |
768 | pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); | |
769 | free(prect); | |
770 | } | |
771 | ||
772 | static Bool exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, | |
773 | Pixel pixel, CARD32 planemask, CARD32 alu, | |
774 | unsigned int clientClipType); | |
775 | ||
776 | static void | |
777 | exaPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect) | |
778 | { | |
779 | ExaScreenPriv(pDrawable->pScreen); | |
780 | RegionPtr pClip = fbGetCompositeClip(pGC); | |
781 | PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); | |
782 | ||
783 | ExaPixmapPriv(pPixmap); | |
784 | register BoxPtr pbox; | |
785 | BoxPtr pextent; | |
786 | int extentX1, extentX2, extentY1, extentY2; | |
787 | int fullX1, fullX2, fullY1, fullY2; | |
788 | int partX1, partX2, partY1, partY2; | |
789 | int xoff, yoff; | |
790 | int xorg, yorg; | |
791 | int n; | |
792 | RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED); | |
793 | ||
794 | /* Compute intersection of rects and clip region */ | |
795 | RegionTranslate(pReg, pDrawable->x, pDrawable->y); | |
796 | RegionIntersect(pReg, pClip, pReg); | |
797 | ||
798 | if (!RegionNumRects(pReg)) { | |
799 | goto out; | |
800 | } | |
801 | ||
802 | exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); | |
803 | ||
804 | if (pExaScr->fallback_counter || pExaScr->swappedOut || | |
805 | pExaPixmap->accel_blocked) { | |
806 | goto fallback; | |
807 | } | |
808 | ||
809 | /* For ROPs where overlaps don't matter, convert rectangles to region and | |
810 | * call exaFillRegion{Solid,Tiled}. | |
811 | */ | |
812 | if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && | |
813 | (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || | |
814 | pGC->alu == GXnoop || pGC->alu == GXcopyInverted || | |
815 | pGC->alu == GXset)) { | |
816 | if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && | |
817 | exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? | |
818 | pGC->fgPixel : pGC->tile.pixel, pGC->planemask, | |
819 | pGC->alu, pGC->clientClipType)) || | |
820 | (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && | |
821 | exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, | |
822 | pGC->planemask, pGC->alu, | |
823 | pGC->clientClipType))) { | |
824 | goto out; | |
825 | } | |
826 | } | |
827 | ||
828 | if (pGC->fillStyle != FillSolid && | |
829 | !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) { | |
830 | goto fallback; | |
831 | } | |
832 | ||
833 | if (pExaScr->do_migration) { | |
834 | ExaMigrationRec pixmaps[1]; | |
835 | ||
836 | pixmaps[0].as_dst = TRUE; | |
837 | pixmaps[0].as_src = FALSE; | |
838 | pixmaps[0].pPix = pPixmap; | |
839 | pixmaps[0].pReg = NULL; | |
840 | ||
841 | exaDoMigration(pixmaps, 1, TRUE); | |
842 | } | |
843 | ||
844 | if (!exaPixmapHasGpuCopy(pPixmap) || | |
845 | !(*pExaScr->info->PrepareSolid) (pPixmap, | |
846 | pGC->alu, | |
847 | pGC->planemask, pGC->fgPixel)) { | |
848 | fallback: | |
849 | ExaCheckPolyFillRect(pDrawable, pGC, nrect, prect); | |
850 | goto out; | |
851 | } | |
852 | ||
853 | xorg = pDrawable->x; | |
854 | yorg = pDrawable->y; | |
855 | ||
856 | pextent = RegionExtents(pClip); | |
857 | extentX1 = pextent->x1; | |
858 | extentY1 = pextent->y1; | |
859 | extentX2 = pextent->x2; | |
860 | extentY2 = pextent->y2; | |
861 | while (nrect--) { | |
862 | fullX1 = prect->x + xorg; | |
863 | fullY1 = prect->y + yorg; | |
864 | fullX2 = fullX1 + (int) prect->width; | |
865 | fullY2 = fullY1 + (int) prect->height; | |
866 | prect++; | |
867 | ||
868 | if (fullX1 < extentX1) | |
869 | fullX1 = extentX1; | |
870 | ||
871 | if (fullY1 < extentY1) | |
872 | fullY1 = extentY1; | |
873 | ||
874 | if (fullX2 > extentX2) | |
875 | fullX2 = extentX2; | |
876 | ||
877 | if (fullY2 > extentY2) | |
878 | fullY2 = extentY2; | |
879 | ||
880 | if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) | |
881 | continue; | |
882 | n = RegionNumRects(pClip); | |
883 | if (n == 1) { | |
884 | (*pExaScr->info->Solid) (pPixmap, | |
885 | fullX1 + xoff, fullY1 + yoff, | |
886 | fullX2 + xoff, fullY2 + yoff); | |
887 | } | |
888 | else { | |
889 | pbox = RegionRects(pClip); | |
890 | /* | |
891 | * clip the rectangle to each box in the clip region | |
892 | * this is logically equivalent to calling Intersect(), | |
893 | * but rectangles may overlap each other here. | |
894 | */ | |
895 | while (n--) { | |
896 | partX1 = pbox->x1; | |
897 | if (partX1 < fullX1) | |
898 | partX1 = fullX1; | |
899 | partY1 = pbox->y1; | |
900 | if (partY1 < fullY1) | |
901 | partY1 = fullY1; | |
902 | partX2 = pbox->x2; | |
903 | if (partX2 > fullX2) | |
904 | partX2 = fullX2; | |
905 | partY2 = pbox->y2; | |
906 | if (partY2 > fullY2) | |
907 | partY2 = fullY2; | |
908 | ||
909 | pbox++; | |
910 | ||
911 | if (partX1 < partX2 && partY1 < partY2) { | |
912 | (*pExaScr->info->Solid) (pPixmap, | |
913 | partX1 + xoff, partY1 + yoff, | |
914 | partX2 + xoff, partY2 + yoff); | |
915 | } | |
916 | } | |
917 | } | |
918 | } | |
919 | (*pExaScr->info->DoneSolid) (pPixmap); | |
920 | exaMarkSync(pDrawable->pScreen); | |
921 | ||
922 | out: | |
923 | RegionUninit(pReg); | |
924 | RegionDestroy(pReg); | |
925 | } | |
926 | ||
927 | const GCOps exaOps = { | |
928 | exaFillSpans, | |
929 | ExaCheckSetSpans, | |
930 | exaPutImage, | |
931 | exaCopyArea, | |
932 | ExaCheckCopyPlane, | |
933 | exaPolyPoint, | |
934 | exaPolylines, | |
935 | exaPolySegment, | |
936 | miPolyRectangle, | |
937 | ExaCheckPolyArc, | |
938 | miFillPolygon, | |
939 | exaPolyFillRect, | |
940 | miPolyFillArc, | |
941 | miPolyText8, | |
942 | miPolyText16, | |
943 | miImageText8, | |
944 | miImageText16, | |
945 | ExaCheckImageGlyphBlt, | |
946 | ExaCheckPolyGlyphBlt, | |
947 | ExaCheckPushPixels, | |
948 | }; | |
949 | ||
950 | void | |
951 | exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) | |
952 | { | |
953 | RegionRec rgnDst; | |
954 | int dx, dy; | |
955 | PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); | |
956 | ||
957 | ExaScreenPriv(pWin->drawable.pScreen); | |
958 | ||
959 | dx = ptOldOrg.x - pWin->drawable.x; | |
960 | dy = ptOldOrg.y - pWin->drawable.y; | |
961 | RegionTranslate(prgnSrc, -dx, -dy); | |
962 | ||
963 | RegionInit(&rgnDst, NullBox, 0); | |
964 | ||
965 | RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); | |
966 | #ifdef COMPOSITE | |
967 | if (pPixmap->screen_x || pPixmap->screen_y) | |
968 | RegionTranslate(&rgnDst, -pPixmap->screen_x, -pPixmap->screen_y); | |
969 | #endif | |
970 | ||
971 | if (pExaScr->fallback_counter) { | |
972 | pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; | |
973 | goto fallback; | |
974 | } | |
975 | ||
976 | pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; | |
977 | miCopyRegion(&pPixmap->drawable, &pPixmap->drawable, | |
978 | NULL, &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); | |
979 | pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; | |
980 | ||
981 | fallback: | |
982 | RegionUninit(&rgnDst); | |
983 | ||
984 | if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { | |
985 | pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; | |
986 | RegionTranslate(prgnSrc, dx, dy); | |
987 | ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); | |
988 | } | |
989 | } | |
990 | ||
991 | static Bool | |
992 | exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, | |
993 | CARD32 planemask, CARD32 alu, unsigned int clientClipType) | |
994 | { | |
995 | ExaScreenPriv(pDrawable->pScreen); | |
996 | PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); | |
997 | ||
998 | ExaPixmapPriv(pPixmap); | |
999 | int xoff, yoff; | |
1000 | Bool ret = FALSE; | |
1001 | ||
1002 | exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); | |
1003 | RegionTranslate(pRegion, xoff, yoff); | |
1004 | ||
1005 | if (pExaScr->fallback_counter || pExaPixmap->accel_blocked) | |
1006 | goto out; | |
1007 | ||
1008 | if (pExaScr->do_migration) { | |
1009 | ExaMigrationRec pixmaps[1]; | |
1010 | ||
1011 | pixmaps[0].as_dst = TRUE; | |
1012 | pixmaps[0].as_src = FALSE; | |
1013 | pixmaps[0].pPix = pPixmap; | |
1014 | pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, | |
1015 | alu, | |
1016 | clientClipType) ? NULL : | |
1017 | pRegion; | |
1018 | ||
1019 | exaDoMigration(pixmaps, 1, TRUE); | |
1020 | } | |
1021 | ||
1022 | if (exaPixmapHasGpuCopy(pPixmap) && | |
1023 | (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) { | |
1024 | int nbox; | |
1025 | BoxPtr pBox; | |
1026 | ||
1027 | nbox = RegionNumRects(pRegion); | |
1028 | pBox = RegionRects(pRegion); | |
1029 | ||
1030 | while (nbox--) { | |
1031 | (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, | |
1032 | pBox->y2); | |
1033 | pBox++; | |
1034 | } | |
1035 | (*pExaScr->info->DoneSolid) (pPixmap); | |
1036 | exaMarkSync(pDrawable->pScreen); | |
1037 | ||
1038 | if (pExaPixmap->pDamage && | |
1039 | pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP && | |
1040 | pDrawable->width == 1 && pDrawable->height == 1 && | |
1041 | pDrawable->bitsPerPixel != 24) { | |
1042 | ExaPixmapPriv(pPixmap); | |
1043 | RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); | |
1044 | ||
1045 | switch (pDrawable->bitsPerPixel) { | |
1046 | case 32: | |
1047 | *(CARD32 *) pExaPixmap->sys_ptr = pixel; | |
1048 | break; | |
1049 | case 16: | |
1050 | *(CARD16 *) pExaPixmap->sys_ptr = pixel; | |
1051 | break; | |
1052 | case 8: | |
1053 | case 4: | |
1054 | case 1: | |
1055 | *(CARD8 *) pExaPixmap->sys_ptr = pixel; | |
1056 | } | |
1057 | ||
1058 | RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, pRegion); | |
1059 | RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, pRegion); | |
1060 | RegionSubtract(pending_damage, pending_damage, pRegion); | |
1061 | } | |
1062 | ||
1063 | ret = TRUE; | |
1064 | } | |
1065 | ||
1066 | out: | |
1067 | RegionTranslate(pRegion, -xoff, -yoff); | |
1068 | ||
1069 | return ret; | |
1070 | } | |
1071 | ||
1072 | /* Try to do an accelerated tile of the pTile into pRegion of pDrawable. | |
1073 | * Based on fbFillRegionTiled(), fbTile(). | |
1074 | */ | |
1075 | Bool | |
1076 | exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, | |
1077 | DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, | |
1078 | unsigned int clientClipType) | |
1079 | { | |
1080 | ExaScreenPriv(pDrawable->pScreen); | |
1081 | PixmapPtr pPixmap; | |
1082 | ExaPixmapPrivPtr pExaPixmap; | |
1083 | ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); | |
1084 | int xoff, yoff; | |
1085 | int tileWidth, tileHeight; | |
1086 | int nbox = RegionNumRects(pRegion); | |
1087 | BoxPtr pBox = RegionRects(pRegion); | |
1088 | Bool ret = FALSE; | |
1089 | int i; | |
1090 | ||
1091 | tileWidth = pTile->drawable.width; | |
1092 | tileHeight = pTile->drawable.height; | |
1093 | ||
1094 | /* If we're filling with a solid color, grab it out and go to | |
1095 | * FillRegionSolid, saving numerous copies. | |
1096 | */ | |
1097 | if (tileWidth == 1 && tileHeight == 1) | |
1098 | return exaFillRegionSolid(pDrawable, pRegion, | |
1099 | exaGetPixmapFirstPixel(pTile), planemask, | |
1100 | alu, clientClipType); | |
1101 | ||
1102 | pPixmap = exaGetDrawablePixmap(pDrawable); | |
1103 | pExaPixmap = ExaGetPixmapPriv(pPixmap); | |
1104 | ||
1105 | if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || | |
1106 | pTileExaPixmap->accel_blocked) | |
1107 | return FALSE; | |
1108 | ||
1109 | if (pExaScr->do_migration) { | |
1110 | ExaMigrationRec pixmaps[2]; | |
1111 | ||
1112 | pixmaps[0].as_dst = TRUE; | |
1113 | pixmaps[0].as_src = FALSE; | |
1114 | pixmaps[0].pPix = pPixmap; | |
1115 | pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, | |
1116 | alu, | |
1117 | clientClipType) ? NULL : | |
1118 | pRegion; | |
1119 | pixmaps[1].as_dst = FALSE; | |
1120 | pixmaps[1].as_src = TRUE; | |
1121 | pixmaps[1].pPix = pTile; | |
1122 | pixmaps[1].pReg = NULL; | |
1123 | ||
1124 | exaDoMigration(pixmaps, 2, TRUE); | |
1125 | } | |
1126 | ||
1127 | pPixmap = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); | |
1128 | ||
1129 | if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) | |
1130 | return FALSE; | |
1131 | ||
1132 | if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) { | |
1133 | if (xoff || yoff) | |
1134 | RegionTranslate(pRegion, xoff, yoff); | |
1135 | ||
1136 | for (i = 0; i < nbox; i++) { | |
1137 | int height = pBox[i].y2 - pBox[i].y1; | |
1138 | int dstY = pBox[i].y1; | |
1139 | int tileY; | |
1140 | ||
1141 | if (alu == GXcopy) | |
1142 | height = min(height, tileHeight); | |
1143 | ||
1144 | modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); | |
1145 | ||
1146 | while (height > 0) { | |
1147 | int width = pBox[i].x2 - pBox[i].x1; | |
1148 | int dstX = pBox[i].x1; | |
1149 | int tileX; | |
1150 | int h = tileHeight - tileY; | |
1151 | ||
1152 | if (alu == GXcopy) | |
1153 | width = min(width, tileWidth); | |
1154 | ||
1155 | if (h > height) | |
1156 | h = height; | |
1157 | height -= h; | |
1158 | ||
1159 | modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, | |
1160 | tileX); | |
1161 | ||
1162 | while (width > 0) { | |
1163 | int w = tileWidth - tileX; | |
1164 | ||
1165 | if (w > width) | |
1166 | w = width; | |
1167 | width -= w; | |
1168 | ||
1169 | (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, | |
1170 | w, h); | |
1171 | dstX += w; | |
1172 | tileX = 0; | |
1173 | } | |
1174 | dstY += h; | |
1175 | tileY = 0; | |
1176 | } | |
1177 | } | |
1178 | (*pExaScr->info->DoneCopy) (pPixmap); | |
1179 | ||
1180 | /* With GXcopy, we only need to do the basic algorithm up to the tile | |
1181 | * size; then, we can just keep doubling the destination in each | |
1182 | * direction until it fills the box. This way, the number of copy | |
1183 | * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where | |
1184 | * rx/ry is the ratio between box and tile width/height. This can make | |
1185 | * a big difference if each driver copy incurs a significant constant | |
1186 | * overhead. | |
1187 | */ | |
1188 | if (alu != GXcopy) | |
1189 | ret = TRUE; | |
1190 | else { | |
1191 | Bool more_copy = FALSE; | |
1192 | ||
1193 | for (i = 0; i < nbox; i++) { | |
1194 | int dstX = pBox[i].x1 + tileWidth; | |
1195 | int dstY = pBox[i].y1 + tileHeight; | |
1196 | ||
1197 | if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { | |
1198 | more_copy = TRUE; | |
1199 | break; | |
1200 | } | |
1201 | } | |
1202 | ||
1203 | if (more_copy == FALSE) | |
1204 | ret = TRUE; | |
1205 | ||
1206 | if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, | |
1207 | 1, 1, alu, | |
1208 | planemask)) { | |
1209 | for (i = 0; i < nbox; i++) { | |
1210 | int dstX = pBox[i].x1 + tileWidth; | |
1211 | int dstY = pBox[i].y1 + tileHeight; | |
1212 | int width = min(pBox[i].x2 - dstX, tileWidth); | |
1213 | int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); | |
1214 | ||
1215 | while (dstX < pBox[i].x2) { | |
1216 | (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, | |
1217 | dstX, pBox[i].y1, width, | |
1218 | height); | |
1219 | dstX += width; | |
1220 | width = min(pBox[i].x2 - dstX, width * 2); | |
1221 | } | |
1222 | ||
1223 | width = pBox[i].x2 - pBox[i].x1; | |
1224 | height = min(pBox[i].y2 - dstY, tileHeight); | |
1225 | ||
1226 | while (dstY < pBox[i].y2) { | |
1227 | (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, | |
1228 | pBox[i].x1, dstY, width, | |
1229 | height); | |
1230 | dstY += height; | |
1231 | height = min(pBox[i].y2 - dstY, height * 2); | |
1232 | } | |
1233 | } | |
1234 | ||
1235 | (*pExaScr->info->DoneCopy) (pPixmap); | |
1236 | ||
1237 | ret = TRUE; | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | exaMarkSync(pDrawable->pScreen); | |
1242 | ||
1243 | if (xoff || yoff) | |
1244 | RegionTranslate(pRegion, -xoff, -yoff); | |
1245 | } | |
1246 | ||
1247 | return ret; | |
1248 | } | |
1249 | ||
1250 | /** | |
1251 | * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. | |
1252 | * | |
1253 | * This is probably the only case we actually care about. The rest fall through | |
1254 | * to migration and fbGetImage, which hopefully will result in migration pushing | |
1255 | * the pixmap out of framebuffer. | |
1256 | */ | |
1257 | void | |
1258 | exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, | |
1259 | unsigned int format, unsigned long planeMask, char *d) | |
1260 | { | |
1261 | ExaScreenPriv(pDrawable->pScreen); | |
1262 | PixmapPtr pPix = exaGetDrawablePixmap(pDrawable); | |
1263 | ||
1264 | ExaPixmapPriv(pPix); | |
1265 | int xoff, yoff; | |
1266 | Bool ok; | |
1267 | ||
1268 | if (pExaScr->fallback_counter || pExaScr->swappedOut) | |
1269 | goto fallback; | |
1270 | ||
1271 | /* If there's a system copy, we want to save the result there */ | |
1272 | if (pExaPixmap->pDamage) | |
1273 | goto fallback; | |
1274 | ||
1275 | pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); | |
1276 | ||
1277 | if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) | |
1278 | goto fallback; | |
1279 | ||
1280 | /* Only cover the ZPixmap, solid copy case. */ | |
1281 | if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) | |
1282 | goto fallback; | |
1283 | ||
1284 | /* Only try to handle the 8bpp and up cases, since we don't want to think | |
1285 | * about <8bpp. | |
1286 | */ | |
1287 | if (pDrawable->bitsPerPixel < 8) | |
1288 | goto fallback; | |
1289 | ||
1290 | ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, | |
1291 | pDrawable->y + y + yoff, w, h, d, | |
1292 | PixmapBytePad(w, pDrawable->depth)); | |
1293 | if (ok) { | |
1294 | exaWaitSync(pDrawable->pScreen); | |
1295 | return; | |
1296 | } | |
1297 | ||
1298 | fallback: | |
1299 | ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); | |
1300 | } |