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