1 /*
2 * Copyright © 2006 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 * Michel Dänzer <michel@tungstengraphics.com>
26 *
27 */
28
29 #ifdef HAVE_DIX_CONFIG_H
30 #include <dix-config.h>
31 #endif
32
33 #include <string.h>
34
35 #include "exa_priv.h"
36 #include "exa.h"
37
38 #if DEBUG_MIGRATE
39 #define DBG_MIGRATE(a) ErrorF a
40 #else
41 #define DBG_MIGRATE(a)
42 #endif
43
44 /**
45 * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys
46 * and exaCopyDirtyToFb both needed to do this loop.
47 */
48 static void
exaMemcpyBox(PixmapPtr pPixmap,BoxPtr pbox,CARD8 * src,int src_pitch,CARD8 * dst,int dst_pitch)49 exaMemcpyBox(PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
50 CARD8 *dst, int dst_pitch)
51 {
52 int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
53 int bytes = (pbox->x2 - pbox->x1) * cpp;
54
55 src += pbox->y1 * src_pitch + pbox->x1 * cpp;
56 dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
57
58 for (i = pbox->y2 - pbox->y1; i; i--) {
59 memcpy(dst, src, bytes);
60 src += src_pitch;
61 dst += dst_pitch;
62 }
63 }
64
65 /**
66 * Returns TRUE if the pixmap is dirty (has been modified in its current
67 * location compared to the other), or lacks a private for tracking
68 * dirtiness.
69 */
70 static Bool
exaPixmapIsDirty(PixmapPtr pPix)71 exaPixmapIsDirty(PixmapPtr pPix)
72 {
73 ExaPixmapPriv(pPix);
74
75 if (pExaPixmap == NULL)
76 EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
77
78 if (!pExaPixmap->pDamage)
79 return FALSE;
80
81 return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) ||
82 !RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB);
83 }
84
85 /**
86 * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
87 * to be considered "should be in framebuffer". That's just anything that has
88 * had more acceleration than fallbacks, or has no score yet.
89 *
90 * Only valid if using a migration scheme that tracks score.
91 */
92 static Bool
exaPixmapShouldBeInFB(PixmapPtr pPix)93 exaPixmapShouldBeInFB(PixmapPtr pPix)
94 {
95 ExaPixmapPriv(pPix);
96
97 if (exaPixmapIsPinned(pPix))
98 return TRUE;
99
100 return pExaPixmap->score >= 0;
101 }
102
103 /**
104 * If the pixmap is currently dirty, this copies at least the dirty area from
105 * FB to system or vice versa. Both areas must be allocated.
106 */
107 static void
exaCopyDirty(ExaMigrationPtr migrate,RegionPtr pValidDst,RegionPtr pValidSrc,Bool (* transfer)(PixmapPtr pPix,int x,int y,int w,int h,char * sys,int sys_pitch),int fallback_index,void (* sync)(ScreenPtr pScreen))108 exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
109 Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
110 char *sys, int sys_pitch), int fallback_index,
111 void (*sync) (ScreenPtr pScreen))
112 {
113 PixmapPtr pPixmap = migrate->pPix;
114
115 ExaPixmapPriv(pPixmap);
116 RegionPtr damage = DamageRegion(pExaPixmap->pDamage);
117 RegionRec CopyReg;
118 Bool save_use_gpu_copy;
119 int save_pitch;
120 BoxPtr pBox;
121 int nbox;
122 Bool access_prepared = FALSE;
123 Bool need_sync = FALSE;
124
125 /* Damaged bits are valid in current copy but invalid in other one */
126 if (pExaPixmap->use_gpu_copy) {
127 RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
128 RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
129 }
130 else {
131 RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
132 RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
133 }
134
135 RegionEmpty(damage);
136
137 /* Copy bits valid in source but not in destination */
138 RegionNull(&CopyReg);
139 RegionSubtract(&CopyReg, pValidSrc, pValidDst);
140
141 if (migrate->as_dst) {
142 ExaScreenPriv(pPixmap->drawable.pScreen);
143
144 /* XXX: The pending damage region will be marked as damaged after the
145 * operation, so it should serve as an upper bound for the region that
146 * needs to be synchronized for the operation. Unfortunately, this
147 * causes corruption in some cases, e.g. when starting compiz. See
148 * https://bugs.freedesktop.org/show_bug.cgi?id=12916 .
149 */
150 if (pExaScr->optimize_migration) {
151 RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
152
153 #if DEBUG_MIGRATE
154 if (RegionNil(pending_damage)) {
155 static Bool firsttime = TRUE;
156
157 if (firsttime) {
158 ErrorF("%s: Pending damage region empty!\n", __func__);
159 firsttime = FALSE;
160 }
161 }
162 #endif
163
164 /* Try to prevent destination valid region from growing too many
165 * rects by filling it up to the extents of the union of the
166 * destination valid region and the pending damage region.
167 */
168 if (RegionNumRects(pValidDst) > 10) {
169 BoxRec box;
170 BoxPtr pValidExt, pDamageExt;
171 RegionRec closure;
172
173 pValidExt = RegionExtents(pValidDst);
174 pDamageExt = RegionExtents(pending_damage);
175
176 box.x1 = min(pValidExt->x1, pDamageExt->x1);
177 box.y1 = min(pValidExt->y1, pDamageExt->y1);
178 box.x2 = max(pValidExt->x2, pDamageExt->x2);
179 box.y2 = max(pValidExt->y2, pDamageExt->y2);
180
181 RegionInit(&closure, &box, 0);
182 RegionIntersect(&CopyReg, &CopyReg, &closure);
183 }
184 else
185 RegionIntersect(&CopyReg, &CopyReg, pending_damage);
186 }
187
188 /* The caller may provide a region to be subtracted from the calculated
189 * dirty region. This is to avoid migration of bits that don't
190 * contribute to the result of the operation.
191 */
192 if (migrate->pReg)
193 RegionSubtract(&CopyReg, &CopyReg, migrate->pReg);
194 }
195 else {
196 /* The caller may restrict the region to be migrated for source pixmaps
197 * to what's relevant for the operation.
198 */
199 if (migrate->pReg)
200 RegionIntersect(&CopyReg, &CopyReg, migrate->pReg);
201 }
202
203 pBox = RegionRects(&CopyReg);
204 nbox = RegionNumRects(&CopyReg);
205
206 save_use_gpu_copy = pExaPixmap->use_gpu_copy;
207 save_pitch = pPixmap->devKind;
208 pExaPixmap->use_gpu_copy = TRUE;
209 pPixmap->devKind = pExaPixmap->fb_pitch;
210
211 while (nbox--) {
212 pBox->x1 = max(pBox->x1, 0);
213 pBox->y1 = max(pBox->y1, 0);
214 pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
215 pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
216
217 if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
218 continue;
219
220 if (!transfer || !transfer(pPixmap,
221 pBox->x1, pBox->y1,
222 pBox->x2 - pBox->x1,
223 pBox->y2 - pBox->y1,
224 (char *) (pExaPixmap->sys_ptr
225 + pBox->y1 * pExaPixmap->sys_pitch
226 +
227 pBox->x1 *
228 pPixmap->drawable.bitsPerPixel /
229 8), pExaPixmap->sys_pitch)) {
230 if (!access_prepared) {
231 ExaDoPrepareAccess(pPixmap, fallback_index);
232 access_prepared = TRUE;
233 }
234 if (fallback_index == EXA_PREPARE_DEST) {
235 exaMemcpyBox(pPixmap, pBox,
236 pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
237 pPixmap->devPrivate.ptr, pPixmap->devKind);
238 }
239 else {
240 exaMemcpyBox(pPixmap, pBox,
241 pPixmap->devPrivate.ptr, pPixmap->devKind,
242 pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
243 }
244 }
245 else
246 need_sync = TRUE;
247
248 pBox++;
249 }
250
251 pExaPixmap->use_gpu_copy = save_use_gpu_copy;
252 pPixmap->devKind = save_pitch;
253
254 /* Try to prevent source valid region from growing too many rects by
255 * removing parts of it which are also in the destination valid region.
256 * Removing anything beyond that would lead to data loss.
257 */
258 if (RegionNumRects(pValidSrc) > 20)
259 RegionSubtract(pValidSrc, pValidSrc, pValidDst);
260
261 /* The copied bits are now valid in destination */
262 RegionUnion(pValidDst, pValidDst, &CopyReg);
263
264 RegionUninit(&CopyReg);
265
266 if (access_prepared)
267 exaFinishAccess(&pPixmap->drawable, fallback_index);
268 else if (need_sync && sync)
269 sync(pPixmap->drawable.pScreen);
270 }
271
272 /**
273 * If the pixmap is currently dirty, this copies at least the dirty area from
274 * the framebuffer memory copy to the system memory copy. Both areas must be
275 * allocated.
276 */
277 void
exaCopyDirtyToSys(ExaMigrationPtr migrate)278 exaCopyDirtyToSys(ExaMigrationPtr migrate)
279 {
280 PixmapPtr pPixmap = migrate->pPix;
281
282 ExaScreenPriv(pPixmap->drawable.pScreen);
283 ExaPixmapPriv(pPixmap);
284
285 exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
286 pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC,
287 exaWaitSync);
288 }
289
290 /**
291 * If the pixmap is currently dirty, this copies at least the dirty area from
292 * the system memory copy to the framebuffer memory copy. Both areas must be
293 * allocated.
294 */
295 void
exaCopyDirtyToFb(ExaMigrationPtr migrate)296 exaCopyDirtyToFb(ExaMigrationPtr migrate)
297 {
298 PixmapPtr pPixmap = migrate->pPix;
299
300 ExaScreenPriv(pPixmap->drawable.pScreen);
301 ExaPixmapPriv(pPixmap);
302
303 exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
304 pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL);
305 }
306
307 /**
308 * Allocates a framebuffer copy of the pixmap if necessary, and then copies
309 * any necessary pixmap data into the framebuffer copy and points the pixmap at
310 * it.
311 *
312 * Note that when first allocated, a pixmap will have FALSE dirty flag.
313 * This is intentional because pixmap data starts out undefined. So if we move
314 * it in due to the first operation against it being accelerated, it will have
315 * undefined framebuffer contents that we didn't have to upload. If we do
316 * moveouts (and moveins) after the first movein, then we will only have to copy
317 * back and forth if the pixmap was written to after the last synchronization of
318 * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
319 * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
320 * all the data, since it's almost surely all valid now.
321 */
322 static void
exaDoMoveInPixmap(ExaMigrationPtr migrate)323 exaDoMoveInPixmap(ExaMigrationPtr migrate)
324 {
325 PixmapPtr pPixmap = migrate->pPix;
326 ScreenPtr pScreen = pPixmap->drawable.pScreen;
327
328 ExaScreenPriv(pScreen);
329 ExaPixmapPriv(pPixmap);
330
331 /* If we're VT-switched away, no touching card memory allowed. */
332 if (pExaScr->swappedOut)
333 return;
334
335 /* If we're not allowed to move, then fail. */
336 if (exaPixmapIsPinned(pPixmap))
337 return;
338
339 /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
340 * fragility in EXA, and <8bpp is probably not used enough any more to care
341 * (at least, not in acceleratd paths).
342 */
343 if (pPixmap->drawable.bitsPerPixel < 8)
344 return;
345
346 if (pExaPixmap->accel_blocked)
347 return;
348
349 if (pExaPixmap->area == NULL) {
350 pExaPixmap->area =
351 exaOffscreenAlloc(pScreen, pExaPixmap->fb_size,
352 pExaScr->info->pixmapOffsetAlign, FALSE,
353 exaPixmapSave, (void *) pPixmap);
354 if (pExaPixmap->area == NULL)
355 return;
356
357 pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
358 pExaPixmap->area->offset;
359 }
360
361 exaCopyDirtyToFb(migrate);
362
363 if (exaPixmapHasGpuCopy(pPixmap))
364 return;
365
366 DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
367 (ExaGetPixmapPriv(pPixmap)->area ?
368 ExaGetPixmapPriv(pPixmap)->area->offset : 0),
369 pPixmap->drawable.width,
370 pPixmap->drawable.height,
371 exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
372
373 pExaPixmap->use_gpu_copy = TRUE;
374
375 pPixmap->devKind = pExaPixmap->fb_pitch;
376 pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
377 }
378
379 void
exaMoveInPixmap_classic(PixmapPtr pPixmap)380 exaMoveInPixmap_classic(PixmapPtr pPixmap)
381 {
382 static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
383 .pReg = NULL
384 };
385
386 migrate.pPix = pPixmap;
387 exaDoMoveInPixmap(&migrate);
388 }
389
390 /**
391 * Switches the current active location of the pixmap to system memory, copying
392 * updated data out if necessary.
393 */
394 static void
exaDoMoveOutPixmap(ExaMigrationPtr migrate)395 exaDoMoveOutPixmap(ExaMigrationPtr migrate)
396 {
397 PixmapPtr pPixmap = migrate->pPix;
398
399 ExaPixmapPriv(pPixmap);
400
401 if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
402 return;
403
404 exaCopyDirtyToSys(migrate);
405
406 if (exaPixmapHasGpuCopy(pPixmap)) {
407
408 DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
409 (void *) (ExaGetPixmapPriv(pPixmap)->area ?
410 ExaGetPixmapPriv(pPixmap)->area->offset : 0),
411 pPixmap->drawable.width,
412 pPixmap->drawable.height,
413 exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
414
415 pExaPixmap->use_gpu_copy = FALSE;
416
417 pPixmap->devKind = pExaPixmap->sys_pitch;
418 pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
419 }
420 }
421
422 void
exaMoveOutPixmap_classic(PixmapPtr pPixmap)423 exaMoveOutPixmap_classic(PixmapPtr pPixmap)
424 {
425 static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
426 .pReg = NULL
427 };
428
429 migrate.pPix = pPixmap;
430 exaDoMoveOutPixmap(&migrate);
431 }
432
433 /**
434 * Copies out important pixmap data and removes references to framebuffer area.
435 * Called when the memory manager decides it's time to kick the pixmap out of
436 * framebuffer entirely.
437 */
438 void
exaPixmapSave(ScreenPtr pScreen,ExaOffscreenArea * area)439 exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area)
440 {
441 PixmapPtr pPixmap = area->privData;
442
443 ExaPixmapPriv(pPixmap);
444
445 exaMoveOutPixmap(pPixmap);
446
447 pExaPixmap->fb_ptr = NULL;
448 pExaPixmap->area = NULL;
449
450 /* Mark all FB bits as invalid, so all valid system bits get copied to FB
451 * next time */
452 RegionEmpty(&pExaPixmap->validFB);
453 }
454
455 /**
456 * For the "greedy" migration scheme, pushes the pixmap toward being located in
457 * framebuffer memory.
458 */
459 static void
exaMigrateTowardFb(ExaMigrationPtr migrate)460 exaMigrateTowardFb(ExaMigrationPtr migrate)
461 {
462 PixmapPtr pPixmap = migrate->pPix;
463
464 ExaPixmapPriv(pPixmap);
465
466 if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
467 DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
468 (void *) pPixmap));
469 return;
470 }
471
472 DBG_MIGRATE(("UseScreen %p score %d\n",
473 (void *) pPixmap, pExaPixmap->score));
474
475 if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
476 exaDoMoveInPixmap(migrate);
477 pExaPixmap->score = 0;
478 }
479
480 if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
481 pExaPixmap->score++;
482
483 if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
484 !exaPixmapHasGpuCopy(pPixmap)) {
485 exaDoMoveInPixmap(migrate);
486 }
487
488 if (exaPixmapHasGpuCopy(pPixmap)) {
489 exaCopyDirtyToFb(migrate);
490 ExaOffscreenMarkUsed(pPixmap);
491 }
492 else
493 exaCopyDirtyToSys(migrate);
494 }
495
496 /**
497 * For the "greedy" migration scheme, pushes the pixmap toward being located in
498 * system memory.
499 */
500 static void
exaMigrateTowardSys(ExaMigrationPtr migrate)501 exaMigrateTowardSys(ExaMigrationPtr migrate)
502 {
503 PixmapPtr pPixmap = migrate->pPix;
504
505 ExaPixmapPriv(pPixmap);
506
507 DBG_MIGRATE(("UseMem: %p score %d\n", (void *) pPixmap,
508 pExaPixmap->score));
509
510 if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
511 return;
512
513 if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
514 pExaPixmap->score = 0;
515
516 if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
517 pExaPixmap->score--;
518
519 if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
520 exaDoMoveOutPixmap(migrate);
521
522 if (exaPixmapHasGpuCopy(pPixmap)) {
523 exaCopyDirtyToFb(migrate);
524 ExaOffscreenMarkUsed(pPixmap);
525 }
526 else
527 exaCopyDirtyToSys(migrate);
528 }
529
530 /**
531 * If the pixmap has both a framebuffer and system memory copy, this function
532 * asserts that both of them are the same.
533 */
534 static Bool
exaAssertNotDirty(PixmapPtr pPixmap)535 exaAssertNotDirty(PixmapPtr pPixmap)
536 {
537 ExaPixmapPriv(pPixmap);
538 CARD8 *dst, *src;
539 RegionRec ValidReg;
540 int dst_pitch, src_pitch, cpp, y, nbox, save_pitch;
541 BoxPtr pBox;
542 Bool ret = TRUE, save_use_gpu_copy;
543
544 if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
545 return ret;
546
547 RegionNull(&ValidReg);
548 RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys);
549 nbox = RegionNumRects(&ValidReg);
550
551 if (!nbox)
552 goto out;
553
554 pBox = RegionRects(&ValidReg);
555
556 dst_pitch = pExaPixmap->sys_pitch;
557 src_pitch = pExaPixmap->fb_pitch;
558 cpp = pPixmap->drawable.bitsPerPixel / 8;
559
560 save_use_gpu_copy = pExaPixmap->use_gpu_copy;
561 save_pitch = pPixmap->devKind;
562 pExaPixmap->use_gpu_copy = TRUE;
563 pPixmap->devKind = pExaPixmap->fb_pitch;
564
565 if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
566 goto skip;
567
568 while (nbox--) {
569 int rowbytes;
570
571 pBox->x1 = max(pBox->x1, 0);
572 pBox->y1 = max(pBox->y1, 0);
573 pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
574 pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
575
576 if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
577 continue;
578
579 rowbytes = (pBox->x2 - pBox->x1) * cpp;
580 src =
581 (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch +
582 pBox->x1 * cpp;
583 dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
584
585 for (y = pBox->y1; y < pBox->y2;
586 y++, src += src_pitch, dst += dst_pitch) {
587 if (memcmp(dst, src, rowbytes) != 0) {
588 ret = FALSE;
589 exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
590 break;
591 }
592 }
593 }
594
595 skip:
596 exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
597
598 pExaPixmap->use_gpu_copy = save_use_gpu_copy;
599 pPixmap->devKind = save_pitch;
600
601 out:
602 RegionUninit(&ValidReg);
603 return ret;
604 }
605
606 /**
607 * Performs migration of the pixmaps according to the operation information
608 * provided in pixmaps and can_accel and the migration scheme chosen in the
609 * config file.
610 */
611 void
exaDoMigration_classic(ExaMigrationPtr pixmaps,int npixmaps,Bool can_accel)612 exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
613 {
614 ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
615
616 ExaScreenPriv(pScreen);
617 int i, j;
618
619 /* If this debugging flag is set, check each pixmap for whether it is marked
620 * as clean, and if so, actually check if that's the case. This should help
621 * catch issues with failing to mark a drawable as dirty. While it will
622 * catch them late (after the operation happened), it at least explains what
623 * went wrong, and instrumenting the code to find what operation happened
624 * to the pixmap last shouldn't be hard.
625 */
626 if (pExaScr->checkDirtyCorrectness) {
627 for (i = 0; i < npixmaps; i++) {
628 if (!exaPixmapIsDirty(pixmaps[i].pPix) &&
629 !exaAssertNotDirty(pixmaps[i].pPix))
630 ErrorF("%s: Pixmap %d dirty but not marked as such!\n",
631 __func__, i);
632 }
633 }
634 /* If anything is pinned in system memory, we won't be able to
635 * accelerate.
636 */
637 for (i = 0; i < npixmaps; i++) {
638 if (exaPixmapIsPinned(pixmaps[i].pPix) &&
639 !exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
640 EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
641 pixmaps[i].pPix->drawable.width,
642 pixmaps[i].pPix->drawable.height));
643 can_accel = FALSE;
644 break;
645 }
646 }
647
648 if (pExaScr->migration == ExaMigrationSmart) {
649 /* If we've got something as a destination that we shouldn't cause to
650 * become newly dirtied, take the unaccelerated route.
651 */
652 for (i = 0; i < npixmaps; i++) {
653 if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB(pixmaps[i].pPix) &&
654 !exaPixmapIsDirty(pixmaps[i].pPix)) {
655 for (i = 0; i < npixmaps; i++) {
656 if (!exaPixmapIsDirty(pixmaps[i].pPix))
657 exaDoMoveOutPixmap(pixmaps + i);
658 }
659 return;
660 }
661 }
662
663 /* If we aren't going to accelerate, then we migrate everybody toward
664 * system memory, and kick out if it's free.
665 */
666 if (!can_accel) {
667 for (i = 0; i < npixmaps; i++) {
668 exaMigrateTowardSys(pixmaps + i);
669 if (!exaPixmapIsDirty(pixmaps[i].pPix))
670 exaDoMoveOutPixmap(pixmaps + i);
671 }
672 return;
673 }
674
675 /* Finally, the acceleration path. Move them all in. */
676 for (i = 0; i < npixmaps; i++) {
677 exaMigrateTowardFb(pixmaps + i);
678 exaDoMoveInPixmap(pixmaps + i);
679 }
680 }
681 else if (pExaScr->migration == ExaMigrationGreedy) {
682 /* If we can't accelerate, either because the driver can't or because one of
683 * the pixmaps is pinned in system memory, then we migrate everybody toward
684 * system memory.
685 *
686 * We also migrate toward system if all pixmaps involved are currently in
687 * system memory -- this can mitigate thrashing when there are significantly
688 * more pixmaps active than would fit in memory.
689 *
690 * If not, then we migrate toward FB so that hopefully acceleration can
691 * happen.
692 */
693 if (!can_accel) {
694 for (i = 0; i < npixmaps; i++)
695 exaMigrateTowardSys(pixmaps + i);
696 return;
697 }
698
699 for (i = 0; i < npixmaps; i++) {
700 if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
701 /* Found one in FB, so move all to FB. */
702 for (j = 0; j < npixmaps; j++)
703 exaMigrateTowardFb(pixmaps + i);
704 return;
705 }
706 }
707
708 /* Nobody's in FB, so move all away from FB. */
709 for (i = 0; i < npixmaps; i++)
710 exaMigrateTowardSys(pixmaps + i);
711 }
712 else if (pExaScr->migration == ExaMigrationAlways) {
713 /* Always move the pixmaps out if we can't accelerate. If we can
714 * accelerate, try to move them all in. If that fails, then move them
715 * back out.
716 */
717 if (!can_accel) {
718 for (i = 0; i < npixmaps; i++)
719 exaDoMoveOutPixmap(pixmaps + i);
720 return;
721 }
722
723 /* Now, try to move them all into FB */
724 for (i = 0; i < npixmaps; i++) {
725 exaDoMoveInPixmap(pixmaps + i);
726 }
727
728 /* If we couldn't fit everything in, abort */
729 for (i = 0; i < npixmaps; i++) {
730 if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
731 return;
732 }
733 }
734
735 /* Yay, everything has a gpu copy, mark memory as used */
736 for (i = 0; i < npixmaps; i++) {
737 ExaOffscreenMarkUsed(pixmaps[i].pPix);
738 }
739 }
740 }
741
742 void
exaPrepareAccessReg_classic(PixmapPtr pPixmap,int index,RegionPtr pReg)743 exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
744 {
745 ExaMigrationRec pixmaps[1];
746
747 if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
748 pixmaps[0].as_dst = TRUE;
749 pixmaps[0].as_src = FALSE;
750 }
751 else {
752 pixmaps[0].as_dst = FALSE;
753 pixmaps[0].as_src = TRUE;
754 }
755 pixmaps[0].pPix = pPixmap;
756 pixmaps[0].pReg = pReg;
757
758 exaDoMigration(pixmaps, 1, FALSE);
759
760 (void) ExaDoPrepareAccess(pPixmap, index);
761 }
762