~ubuntu-branches/ubuntu/precise/xorg-server-lts-saucy/precise-proposed

« back to all changes in this revision

Viewing changes to exa/exa_migration_classic.c

  • Committer: Package Import Robot
  • Author(s): Maarten Lankhorst
  • Date: 2013-12-23 09:04:34 UTC
  • Revision ID: package-import@ubuntu.com-20131223090434-ov0hcp9sdd6szrwa
Tags: upstream-1.14.5
ImportĀ upstreamĀ versionĀ 1.14.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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, (pointer) 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
 
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
 
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
 
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
 
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
 
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
                     (pointer) pPixmap));
 
469
        return;
 
470
    }
 
471
 
 
472
    DBG_MIGRATE(("UseScreen %p score %d\n",
 
473
                 (pointer) 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
 
501
exaMigrateTowardSys(ExaMigrationPtr migrate)
 
502
{
 
503
    PixmapPtr pPixmap = migrate->pPix;
 
504
 
 
505
    ExaPixmapPriv(pPixmap);
 
506
 
 
507
    DBG_MIGRATE(("UseMem: %p score %d\n", (pointer) 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
 
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
 
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
 
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
}