exa.c 35.1 KB
Newer Older
1
/*
Matěj Cepl's avatar
Matěj Cepl committed
2
 * Copyright © 2001 Keith Packard
3
 *
Matěj Cepl's avatar
Matěj Cepl committed
4
 * Partly based on code that is Copyright © The XFree86 Project Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

25 26 27 28 29 30
/** @file
 * This file covers the initialization and teardown of EXA, and has various
 * functions not responsible for performing rendering, pixmap migration, or
 * memory management.
 */

31 32
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
33
#endif
34 35 36

#include <stdlib.h>

37
#include "exa_priv.h"
38 39
#include "exa.h"

40
DevPrivateKeyRec exaScreenPrivateKeyRec;
41

42 43 44 45
#ifdef MITSHM
static ShmFuncs exaShmFuncs = { NULL, NULL };
#endif

46 47 48 49 50 51 52 53 54
/**
 * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
 * the beginning of the given pixmap.
 *
 * Note that drivers are free to, and often do, munge this offset as necessary
 * for handing to the hardware -- for example, translating it into a different
 * aperture.  This function may need to be extended in the future if we grow
 * support for having multiple card-accessible offscreen, such as an AGP memory
 * pool alongside the framebuffer pool.
55
 */
56
unsigned long
57 58
exaGetPixmapOffset(PixmapPtr pPix)
{
59 60
    ExaScreenPriv(pPix->drawable.pScreen);
    ExaPixmapPriv(pPix);
61

62
    return (CARD8 *) pExaPixmap->fb_ptr - pExaScr->info->memoryBase;
63 64
}

65
void *
66 67 68 69 70 71 72
exaGetPixmapDriverPrivate(PixmapPtr pPix)
{
    ExaPixmapPriv(pPix);

    return pExaPixmap->driverPriv;
}

73 74 75 76 77 78
/**
 * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap.
 *
 * This is a helper to make driver code more obvious, due to the rather obscure
 * naming of the pitch field in the pixmap.
 */
79
unsigned long
80 81 82 83
exaGetPixmapPitch(PixmapPtr pPix)
{
    return pPix->devKind;
}
84

85 86 87
/**
 * exaGetPixmapSize() returns the size in bytes of the given pixmap in video
 * memory. Only valid when the pixmap is currently in framebuffer.
88
 */
89
unsigned long
90 91 92 93 94 95
exaGetPixmapSize(PixmapPtr pPix)
{
    ExaPixmapPrivPtr pExaPixmap;

    pExaPixmap = ExaGetPixmapPriv(pPix);
    if (pExaPixmap != NULL)
96
        return pExaPixmap->fb_size;
97 98 99
    return 0;
}

100 101 102 103 104 105 106 107 108 109 110
/**
 * exaGetDrawablePixmap() returns a backing pixmap for a given drawable.
 *
 * @param pDrawable the drawable being requested.
 *
 * This function returns the backing pixmap for a drawable, whether it is a
 * redirected window, unredirected window, or already a pixmap.  Note that
 * coordinate translation is needed when drawing to the backing pixmap of a
 * redirected window, and the translation coordinates are provided by calling
 * exaGetOffscreenPixmap() on the drawable.
 */
111 112 113
PixmapPtr
exaGetDrawablePixmap(DrawablePtr pDrawable)
{
114 115 116 117
    if (pDrawable->type == DRAWABLE_WINDOW)
        return pDrawable->pScreen->GetWindowPixmap((WindowPtr) pDrawable);
    else
        return (PixmapPtr) pDrawable;
Maarten Maathuis's avatar
Maarten Maathuis committed
118
}
119

120
/**
121 122 123 124
 * Sets the offsets to add to coordinates to make them address the same bits in
 * the backing drawable. These coordinates are nonzero only for redirected
 * windows.
 */
125
void
126
exaGetDrawableDeltas(DrawablePtr pDrawable, PixmapPtr pPixmap, int *xp, int *yp)
127 128 129
{
#ifdef COMPOSITE
    if (pDrawable->type == DRAWABLE_WINDOW) {
130 131 132
        *xp = -pPixmap->screen_x;
        *yp = -pPixmap->screen_y;
        return;
133 134 135 136 137 138 139 140 141
    }
#endif

    *xp = 0;
    *yp = 0;
}

/**
 * exaPixmapDirty() marks a pixmap as dirty, allowing for
142 143
 * optimizations in pixmap migration when no changes have occurred.
 */
144
void
145
exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2)
146
{
147
    BoxRec box;
148
    RegionRec region;
149

150 151 152 153 154 155
    box.x1 = max(x1, 0);
    box.y1 = max(y1, 0);
    box.x2 = min(x2, pPix->drawable.width);
    box.y2 = min(y2, pPix->drawable.height);

    if (box.x1 >= box.x2 || box.y1 >= box.y2)
156
        return;
157

158
    RegionInit(&region, &box, 1);
159
    DamageDamageRegion(&pPix->drawable, &region);
160
    RegionUninit(&region);
161 162
}

163 164 165 166 167
static int
exaLog2(int val)
{
    int bits;

168
    if (val <= 0)
169
        return 0;
170
    for (bits = 0; val != 0; bits++)
171
        val >>= 1;
172 173 174
    return bits - 1;
}

175
void
176 177 178 179 180 181
exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
                 int w, int h, int bpp)
{
    pExaPixmap->accel_blocked = 0;

    if (pExaScr->info->maxPitchPixels) {
182
        int max_pitch = pExaScr->info->maxPitchPixels * bits_to_bytes(bpp);
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198

        if (pExaPixmap->fb_pitch > max_pitch)
            pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;
    }

    if (pExaScr->info->maxPitchBytes &&
        pExaPixmap->fb_pitch > pExaScr->info->maxPitchBytes)
        pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;

    if (w > pExaScr->info->maxX)
        pExaPixmap->accel_blocked |= EXA_RANGE_WIDTH;

    if (h > pExaScr->info->maxY)
        pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT;
}

199
void
200 201 202 203
exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
              int w, int h, int bpp)
{
    if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
204
        pExaPixmap->fb_pitch = bits_to_bytes((1 << (exaLog2(w - 1) + 1)) * bpp);
205
    else
206
        pExaPixmap->fb_pitch = bits_to_bytes(w * bpp);
207 208 209 210 211

    pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
                                     pExaScr->info->pixmapPitchAlign);
}

212 213 214 215 216 217
/**
 * Returns TRUE if the pixmap is not movable.  This is the case where it's a
 * pixmap which has no private (almost always bad) or it's a scratch pixmap created by
 * some X Server internal component (the score says it's pinned).
 */
Bool
218
exaPixmapIsPinned(PixmapPtr pPix)
219
{
220
    ExaPixmapPriv(pPix);
221 222

    if (pExaPixmap == NULL)
223
        EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE);
224 225 226 227

    return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
}

228
/**
229
 * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen
230 231 232 233 234 235
 * memory, meaning that acceleration could probably be done to it, and that it
 * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
 * with the CPU.
 *
 * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
 * deal with moving pixmaps in and out of system memory), EXA will give drivers
236
 * pixmaps as arguments for which exaPixmapHasGpuCopy() is TRUE.
237 238 239
 *
 * @return TRUE if the given drawable is in framebuffer memory.
 */
240
Bool
241
exaPixmapHasGpuCopy(PixmapPtr pPixmap)
242
{
243 244
    ScreenPtr pScreen = pPixmap->drawable.pScreen;

245 246
    ExaScreenPriv(pScreen);

247
    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
248
        return FALSE;
249

250
    return (*pExaScr->pixmap_has_gpu_copy) (pPixmap);
251 252
}

253
/**
254
 * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapHasGpuCopy().
255
 */
256
Bool
257
exaDrawableIsOffscreen(DrawablePtr pDrawable)
258
{
259
    return exaPixmapHasGpuCopy(exaGetDrawablePixmap(pDrawable));
260 261
}

262 263 264 265
/**
 * Returns the pixmap which backs a drawable, and the offsets to add to
 * coordinates to make them address the same bits in the backing drawable.
 */
266
PixmapPtr
267
exaGetOffscreenPixmap(DrawablePtr pDrawable, int *xp, int *yp)
268
{
269
    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
270

271
    exaGetDrawableDeltas(pDrawable, pPixmap, xp, yp);
272

273 274
    if (exaPixmapHasGpuCopy(pPixmap))
        return pPixmap;
275
    else
276
        return NULL;
277 278
}

279
/**
280
 * Returns TRUE if the pixmap GPU copy is being accessed.
281 282
 */
Bool
283
ExaDoPrepareAccess(PixmapPtr pPixmap, int index)
284
{
285
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
286 287

    ExaScreenPriv(pScreen);
288
    ExaPixmapPriv(pPixmap);
289
    Bool has_gpu_copy, ret;
290
    int i;
291 292

    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
293
        return FALSE;
294 295

    if (pExaPixmap == NULL)
296
        EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE);
297

298 299
    /* Handle repeated / nested calls. */
    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
300 301 302 303
        if (pExaScr->access[i].pixmap == pPixmap) {
            pExaScr->access[i].count++;
            return pExaScr->access[i].retval;
        }
304 305 306 307
    }

    /* If slot for this index is taken, find an empty slot */
    if (pExaScr->access[index].pixmap) {
308 309 310
        for (index = EXA_NUM_PREPARE_INDICES - 1; index >= 0; index--)
            if (!pExaScr->access[index].pixmap)
                break;
311
    }
312

313 314
    /* Access to this pixmap hasn't been prepared yet, so data pointer should be NULL. */
    if (pPixmap->devPrivate.ptr != NULL) {
315
        EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n", pPixmap->devPrivate.ptr));
316 317
    }

318
    has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
319

320
    if (has_gpu_copy && pExaPixmap->fb_ptr) {
321 322 323 324 325 326
        pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
        ret = TRUE;
    }
    else {
        pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
        ret = FALSE;
327
    }
328

329 330 331
    /* Store so we can handle repeated / nested calls. */
    pExaScr->access[index].pixmap = pPixmap;
    pExaScr->access[index].count = 1;
332

333
    if (!has_gpu_copy)
334
        goto out;
335

336
    exaWaitSync(pScreen);
337

338
    if (pExaScr->info->PrepareAccess == NULL)
339
        goto out;
340

341
    if (index >= EXA_PREPARE_AUX_DEST &&
342 343 344 345 346 347
        !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
        if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
            FatalError("Unsupported AUX indices used on a pinned pixmap.\n");
        exaMoveOutPixmap(pPixmap);
        ret = FALSE;
        goto out;
348 349
    }

350
    if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
351 352 353 354 355 356
        if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED &&
            !(pExaScr->info->flags & EXA_MIXED_PIXMAPS))
            FatalError("Driver failed PrepareAccess on a pinned pixmap.\n");
        exaMoveOutPixmap(pPixmap);
        ret = FALSE;
        goto out;
357
    }
358

359 360
    ret = TRUE;

361
 out:
362 363
    pExaScr->access[index].retval = ret;
    return ret;
364 365
}

366 367 368 369 370 371 372 373 374
/**
 * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
 *
 * It deals with waiting for synchronization with the card, determining if
 * PrepareAccess() is necessary, and working around PrepareAccess() failure.
 */
void
exaPrepareAccess(DrawablePtr pDrawable, int index)
{
375
    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
376

377 378 379
    ExaScreenPriv(pDrawable->pScreen);

    if (pExaScr->prepare_access_reg)
380
        pExaScr->prepare_access_reg(pPixmap, index, NULL);
381
    else
382
        (void) ExaDoPrepareAccess(pPixmap, index);
383 384
}

385 386 387
/**
 * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
 *
388
 * It deals with calling the driver's FinishAccess() only if necessary.
389
 */
390 391 392
void
exaFinishAccess(DrawablePtr pDrawable, int index)
{
393 394 395 396 397 398
    ScreenPtr pScreen = pDrawable->pScreen;

    ExaScreenPriv(pScreen);
    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);

    ExaPixmapPriv(pPixmap);
399
    int i;
400

401
    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
402
        return;
403 404

    if (pExaPixmap == NULL)
405
        EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),);
406

407 408
    /* Handle repeated / nested calls. */
    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
409 410 411 412 413
        if (pExaScr->access[i].pixmap == pPixmap) {
            if (--pExaScr->access[i].count > 0)
                return;
            break;
        }
414 415 416 417
    }

    /* Catch unbalanced Prepare/FinishAccess calls. */
    if (i == EXA_NUM_PREPARE_INDICES)
418
        EXA_FatalErrorDebugWithRet(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", pPixmap),);
419

420
    pExaScr->access[i].pixmap = NULL;
421 422 423

    /* We always hide the devPrivate.ptr. */
    pPixmap->devPrivate.ptr = NULL;
424

425 426
    /* Only call FinishAccess if PrepareAccess was called and succeeded. */
    if (!pExaScr->info->FinishAccess || !pExaScr->access[i].retval)
427
        return;
428

429
    if (i >= EXA_PREPARE_AUX_DEST &&
430 431 432 433
        !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
        ErrorF("EXA bug: Trying to call driver FinishAccess hook with "
               "unsupported index EXA_PREPARE_AUX*\n");
        return;
434 435
    }

436
    (*pExaScr->info->FinishAccess) (pPixmap, i);
437 438
}

439 440 441 442 443 444 445 446 447 448 449 450 451
/**
 * Helper for things common to all schemes when a pixmap is destroyed
 */
void
exaDestroyPixmap(PixmapPtr pPixmap)
{
    ExaScreenPriv(pPixmap->drawable.pScreen);
    int i;

    /* Finish access if it was prepared (e.g. pixmap created during
     * software fallback)
     */
    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
452 453 454 455 456
        if (pExaScr->access[i].pixmap == pPixmap) {
            exaFinishAccess(&pPixmap->drawable, i);
            pExaScr->access[i].pixmap = NULL;
            break;
        }
457 458 459
    }
}

460
/**
461 462
 * Here begins EXA's GC code.
 * Do not ever access the fb/mi layer directly.
463
 */
464 465

static void
466
 exaValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable);
467 468

static void
469
 exaDestroyGC(GCPtr pGC);
470 471

static void
472
 exaChangeGC(GCPtr pGC, unsigned long mask);
473 474

static void
475
 exaCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
476 477

static void
478
 exaChangeClip(GCPtr pGC, int type, void *pvalue, int nrects);
479 480

static void
481
 exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc);
482 483

static void
484
 exaDestroyClip(GCPtr pGC);
485 486 487 488 489 490 491 492 493 494 495

const GCFuncs exaGCFuncs = {
    exaValidateGC,
    exaChangeGC,
    exaCopyGC,
    exaDestroyGC,
    exaChangeClip,
    exaDestroyClip,
    exaCopyClip
};

496
static void
497
exaValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
498
{
499
    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
500
     * Do a few smart things so fbValidateGC can do it's work.
501 502
     */

503
    ScreenPtr pScreen = pDrawable->pScreen;
504

505
    ExaScreenPriv(pScreen);
506
    ExaGCPriv(pGC);
507
    PixmapPtr pTile = NULL;
508
    Bool finish_current_tile = FALSE;
509

510 511
    /* Either of these conditions is enough to trigger access to a tile pixmap. */
    /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    if (pGC->fillStyle == FillTiled ||
        ((changes & GCTile) && !pGC->tileIsPixel)) {
        pTile = pGC->tile.pixmap;

        /* Sometimes tile pixmaps are swapped, you need access to:
         * - The current tile if it depth matches.
         * - Or the rotated tile if that one matches depth and !(changes & GCTile).
         * - Or the current tile pixmap and a newly created one.
         */
        if (pTile && pTile->drawable.depth != pDrawable->depth &&
            !(changes & GCTile)) {
            PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC);

            if (pRotatedTile &&
                pRotatedTile->drawable.depth == pDrawable->depth)
                pTile = pRotatedTile;
            else
                finish_current_tile = TRUE;     /* CreatePixmap will be called. */
        }
531
    }
532 533 534 535

    if (pGC->stipple)
        exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
    if (pTile)
536
        exaPrepareAccess(&pTile->drawable, EXA_PREPARE_SRC);
537

538 539 540
    /* Calls to Create/DestroyPixmap have to be identified as special. */
    pExaScr->fallback_counter++;
    swap(pExaGC, pGC, funcs);
541
    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
542 543
    swap(pExaGC, pGC, funcs);
    pExaScr->fallback_counter--;
544

545
    if (pTile)
546
        exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC);
547
    if (finish_current_tile && pGC->tile.pixmap)
548
        exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_AUX_DEST);
549
    if (pGC->stipple)
550
        exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
551
}
552

553 554 555 556
/* Is exaPrepareAccessGC() needed? */
static void
exaDestroyGC(GCPtr pGC)
{
557 558
    ExaGCPriv(pGC);
    swap(pExaGC, pGC, funcs);
559
    (*pGC->funcs->DestroyGC) (pGC);
560
    swap(pExaGC, pGC, funcs);
561
}
562

563
static void
564
exaChangeGC(GCPtr pGC, unsigned long mask)
565
{
566 567
    ExaGCPriv(pGC);
    swap(pExaGC, pGC, funcs);
568
    (*pGC->funcs->ChangeGC) (pGC, mask);
569
    swap(pExaGC, pGC, funcs);
570 571
}

572
static void
573
exaCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
574
{
575 576
    ExaGCPriv(pGCDst);
    swap(pExaGC, pGCDst, funcs);
577
    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
578
    swap(pExaGC, pGCDst, funcs);
579 580 581
}

static void
582
exaChangeClip(GCPtr pGC, int type, void *pvalue, int nrects)
583
{
584 585
    ExaGCPriv(pGC);
    swap(pExaGC, pGC, funcs);
586
    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
587
    swap(pExaGC, pGC, funcs);
588 589 590 591 592
}

static void
exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc)
{
593 594
    ExaGCPriv(pGCDst);
    swap(pExaGC, pGCDst, funcs);
595
    (*pGCDst->funcs->CopyClip) (pGCDst, pGCSrc);
596
    swap(pExaGC, pGCDst, funcs);
597 598 599 600 601
}

static void
exaDestroyClip(GCPtr pGC)
{
602 603
    ExaGCPriv(pGC);
    swap(pExaGC, pGC, funcs);
604
    (*pGC->funcs->DestroyClip) (pGC);
605
    swap(pExaGC, pGC, funcs);
606
}
607

608 609 610 611
/**
 * exaCreateGC makes a new GC and hooks up its funcs handler, so that
 * exaValidateGC() will get called.
 */
612
static int
613
exaCreateGC(GCPtr pGC)
614
{
615
    ScreenPtr pScreen = pGC->pScreen;
616

617
    ExaScreenPriv(pScreen);
Maarten Maathuis's avatar
Maarten Maathuis committed
618
    ExaGCPriv(pGC);
619
    Bool ret;
Maarten Maathuis's avatar
Maarten Maathuis committed
620

621 622
    swap(pExaScr, pScreen, CreateGC);
    if ((ret = (*pScreen->CreateGC) (pGC))) {
Keith Packard's avatar
Keith Packard committed
623 624
        wrap(pExaGC, pGC, funcs, &exaGCFuncs);
        wrap(pExaGC, pGC, ops, &exaOps);
625 626
    }
    swap(pExaScr, pScreen, CreateGC);
627

628
    return ret;
629 630
}

631 632
static Bool
exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
633
{
634
    Bool ret;
635
    ScreenPtr pScreen = pWin->drawable.pScreen;
636

637
    ExaScreenPriv(pScreen);
638

639 640
    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
        exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
641

642
    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
643
        exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
644

645
    pExaScr->fallback_counter++;
646 647 648
    swap(pExaScr, pScreen, ChangeWindowAttributes);
    ret = pScreen->ChangeWindowAttributes(pWin, mask);
    swap(pExaScr, pScreen, ChangeWindowAttributes);
649
    pExaScr->fallback_counter--;
650

651 652
    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
        exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
653
    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
654
        exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
655 656 657 658 659 660 661

    return ret;
}

static RegionPtr
exaBitmapToRegion(PixmapPtr pPix)
{
Maarten Maathuis's avatar
Maarten Maathuis committed
662
    RegionPtr ret;
663
    ScreenPtr pScreen = pPix->drawable.pScreen;
664

665 666
    ExaScreenPriv(pScreen);

Maarten Maathuis's avatar
Maarten Maathuis committed
667
    exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC);
668
    swap(pExaScr, pScreen, BitmapToRegion);
669
    ret = (*pScreen->BitmapToRegion) (pPix);
670
    swap(pExaScr, pScreen, BitmapToRegion);
Maarten Maathuis's avatar
Maarten Maathuis committed
671
    exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC);
672

Maarten Maathuis's avatar
Maarten Maathuis committed
673
    return ret;
674 675
}

676 677 678 679 680 681 682
static Bool
exaCreateScreenResources(ScreenPtr pScreen)
{
    ExaScreenPriv(pScreen);
    PixmapPtr pScreenPixmap;
    Bool b;

683
    swap(pExaScr, pScreen, CreateScreenResources);
684
    b = pScreen->CreateScreenResources(pScreen);
685
    swap(pExaScr, pScreen, CreateScreenResources);
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703

    if (!b)
        return FALSE;

    pScreenPixmap = pScreen->GetScreenPixmap(pScreen);

    if (pScreenPixmap) {
        ExaPixmapPriv(pScreenPixmap);

        exaSetAccelBlock(pExaScr, pExaPixmap,
                         pScreenPixmap->drawable.width,
                         pScreenPixmap->drawable.height,
                         pScreenPixmap->drawable.bitsPerPixel);
    }

    return TRUE;
}

704
static void
705 706
ExaBlockHandler(ScreenPtr pScreen, void *pTimeout,
                void *pReadmask)
707 708 709
{
    ExaScreenPriv(pScreen);

710 711
    /* Move any deferred results from a software fallback to the driver pixmap */
    if (pExaScr->deferred_mixed_pixmap)
712
        exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
713

714
    unwrap(pExaScr, pScreen, BlockHandler);
715
    (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);
716 717
    wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);

718 719
    /* The rest only applies to classic EXA */
    if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
720
        return;
721

722
    /* Try and keep the offscreen memory area tidy every now and then (at most
723 724 725
     * once per second) when the server has been idle for at least 100ms.
     */
    if (pExaScr->numOffscreenAvailable > 1) {
726
        CARD32 now = GetTimeInMillis();
727

728 729 730
        pExaScr->nextDefragment = now +
            max(100, (INT32) (pExaScr->lastDefragment + 1000 - now));
        AdjustWaitForDelay(pTimeout, pExaScr->nextDefragment - now);
731 732 733 734
    }
}

static void
735
ExaWakeupHandler(ScreenPtr pScreen, unsigned long result,
736
                 void *pReadmask)
737 738 739 740
{
    ExaScreenPriv(pScreen);

    unwrap(pExaScr, pScreen, WakeupHandler);
741
    (*pScreen->WakeupHandler) (pScreen, result, pReadmask);
742 743 744
    wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler);

    if (result == 0 && pExaScr->numOffscreenAvailable > 1) {
745
        CARD32 now = GetTimeInMillis();
746

747 748 749 750
        if ((int) (now - pExaScr->nextDefragment) > 0) {
            ExaOffscreenDefragment(pScreen);
            pExaScr->lastDefragment = now;
        }
751 752 753
    }
}

754 755 756 757
/**
 * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's
 * screen private, before calling down to the next CloseSccreen.
 */
758
static Bool
759
exaCloseScreen(ScreenPtr pScreen)
760 761
{
    ExaScreenPriv(pScreen);
762
    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
763

764
    if (ps->Glyphs == exaGlyphs)
765
        exaGlyphsFini(pScreen);
766

767
    if (pScreen->BlockHandler == ExaBlockHandler)
768
        unwrap(pExaScr, pScreen, BlockHandler);
769
    if (pScreen->WakeupHandler == ExaWakeupHandler)
770
        unwrap(pExaScr, pScreen, WakeupHandler);
771 772 773 774 775
    unwrap(pExaScr, pScreen, CreateGC);
    unwrap(pExaScr, pScreen, CloseScreen);
    unwrap(pExaScr, pScreen, GetImage);
    unwrap(pExaScr, pScreen, GetSpans);
    if (pExaScr->SavedCreatePixmap)
776
        unwrap(pExaScr, pScreen, CreatePixmap);
777
    if (pExaScr->SavedDestroyPixmap)
778
        unwrap(pExaScr, pScreen, DestroyPixmap);
779
    if (pExaScr->SavedModifyPixmapHeader)
780
        unwrap(pExaScr, pScreen, ModifyPixmapHeader);
781 782 783 784
    unwrap(pExaScr, pScreen, CopyWindow);
    unwrap(pExaScr, pScreen, ChangeWindowAttributes);
    unwrap(pExaScr, pScreen, BitmapToRegion);
    unwrap(pExaScr, pScreen, CreateScreenResources);
785 786 787 788
    if (pExaScr->SavedSharePixmapBacking)
        unwrap(pExaScr, pScreen, SharePixmapBacking);
    if (pExaScr->SavedSetSharedPixmapBacking)
        unwrap(pExaScr, pScreen, SetSharedPixmapBacking);
789 790
    unwrap(pExaScr, ps, Composite);
    if (pExaScr->SavedGlyphs)
791
        unwrap(pExaScr, ps, Glyphs);
792 793 794
    unwrap(pExaScr, ps, Trapezoids);
    unwrap(pExaScr, ps, Triangles);
    unwrap(pExaScr, ps, AddTraps);
795

796
    free(pExaScr);
797

798
    return (*pScreen->CloseScreen) (pScreen);
799 800
}

801 802 803 804 805 806
/**
 * This function allocates a driver structure for EXA drivers to fill in.  By
 * having EXA allocate the structure, the driver structure can be extended
 * without breaking ABI between EXA and the drivers.  The driver's
 * responsibility is to check beforehand that the EXA module has a matching
 * major number and sufficient minor.  Drivers are responsible for freeing the
807
 * driver structure using free().
808 809
 *
 * @return a newly allocated, zero-filled driver structure
810
 */
811
ExaDriverPtr
812 813
exaDriverAlloc(void)
{
814
    return calloc(1, sizeof(ExaDriverRec));
815 816 817
}

/**
818 819 820
 * @param pScreen screen being initialized
 * @param pScreenInfo EXA driver record
 *
821
 * exaDriverInit sets up EXA given a driver record filled in by the driver.
822 823 824 825
 * pScreenInfo should have been allocated by exaDriverAlloc().  See the
 * comments in _ExaDriver for what must be filled in and what is optional.
 *
 * @return TRUE if EXA was successfully initialized.
826
 */
827
Bool
828
exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo)
829 830
{
    ExaScreenPrivPtr pExaScr;
831
    PictureScreenPtr ps;
832

833
    if (!pScreenInfo)
834
        return FALSE;
835

836
    if (pScreenInfo->exa_major != EXA_VERSION_MAJOR ||
837 838 839 840 841 842 843
        pScreenInfo->exa_minor > EXA_VERSION_MINOR) {
        LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements "
                   "(%d.%d) are incompatible with EXA version (%d.%d)\n",
                   pScreen->myNum,
                   pScreenInfo->exa_major, pScreenInfo->exa_minor,
                   EXA_VERSION_MAJOR, EXA_VERSION_MINOR);
        return FALSE;
844 845
    }

846
    if (!pScreenInfo->CreatePixmap && !pScreenInfo->CreatePixmap2) {
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
        if (!pScreenInfo->memoryBase) {
            LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase "
                       "must be non-zero\n", pScreen->myNum);
            return FALSE;
        }

        if (!pScreenInfo->memorySize) {
            LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be "
                       "non-zero\n", pScreen->myNum);
            return FALSE;
        }

        if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) {
            LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must "
                       "be <= ExaDriverRec::memorySize\n", pScreen->myNum);
            return FALSE;
        }
864 865 866
    }

    if (!pScreenInfo->PrepareSolid) {
867 868 869
        LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be "
                   "non-NULL\n", pScreen->myNum);
        return FALSE;
870 871 872
    }

    if (!pScreenInfo->PrepareCopy) {
873 874 875
        LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be "
                   "non-NULL\n", pScreen->myNum);
        return FALSE;
876 877 878
    }

    if (!pScreenInfo->WaitMarker) {
879 880 881
        LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be "
                   "non-NULL\n", pScreen->myNum);
        return FALSE;
882 883
    }

884 885 886
    /* If the driver doesn't set any max pitch values, we'll just assume
     * that there's a limitation by pixels, and that it's the same as
     * maxX.
887 888 889 890 891
     *
     * We want maxPitchPixels or maxPitchBytes to be set so we can check
     * pixmaps against the max pitch in exaCreatePixmap() -- it matters
     * whether a pixmap is rejected because of its pitch or
     * because of its width.
892
     */
893
    if (!pScreenInfo->maxPitchPixels && !pScreenInfo->maxPitchBytes) {
894 895 896
        pScreenInfo->maxPitchPixels = pScreenInfo->maxX;
    }

897
    ps = GetPictureScreenIfSet(pScreen);
898

899 900
    if (!dixRegisterPrivateKey(&exaScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) {
        LogMessage(X_WARNING, "EXA(%d): Failed to register screen private\n",
901 902
                   pScreen->myNum);
        return FALSE;
903 904
    }

905
    pExaScr = calloc(sizeof(ExaScreenPrivRec), 1);
906
    if (!pExaScr) {
907
        LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n",
908 909
                   pScreen->myNum);
        return FALSE;
910
    }
911 912 913

    pExaScr->info = pScreenInfo;

914
    dixSetPrivate(&pScreen->devPrivates, exaScreenPrivateKey, pExaScr);
915

916
    pExaScr->migration = ExaMigrationAlways;
917

918 919
    exaDDXDriverInit(pScreen);

920 921
    if (!dixRegisterScreenSpecificPrivateKey
        (pScreen, &pExaScr->gcPrivateKeyRec, PRIVATE_GC, sizeof(ExaGCPrivRec))) {
922 923 924
        LogMessage(X_WARNING, "EXA(%d): Failed to allocate GC private\n",
                   pScreen->myNum);
        return FALSE;
Maarten Maathuis's avatar
Maarten Maathuis committed
925 926
    }

927 928 929
    /*
     * Replace various fb screen functions
     */
930
    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
931 932 933
        (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) ||
         (pExaScr->info->flags & EXA_MIXED_PIXMAPS)))
        wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);
934
    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
935 936
        !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS))
        wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler);
937 938 939 940 941 942 943 944
    wrap(pExaScr, pScreen, CreateGC, exaCreateGC);
    wrap(pExaScr, pScreen, CloseScreen, exaCloseScreen);
    wrap(pExaScr, pScreen, GetImage, exaGetImage);
    wrap(pExaScr, pScreen, GetSpans, ExaCheckGetSpans);
    wrap(pExaScr, pScreen, CopyWindow, exaCopyWindow);
    wrap(pExaScr, pScreen, ChangeWindowAttributes, exaChangeWindowAttributes);
    wrap(pExaScr, pScreen, BitmapToRegion, exaBitmapToRegion);
    wrap(pExaScr, pScreen, CreateScreenResources, exaCreateScreenResources);
945

946
    if (ps) {
947 948 949 950 951 952 953 954 955 956
        wrap(pExaScr, ps, Composite, exaComposite);
        if (pScreenInfo->PrepareComposite) {
            wrap(pExaScr, ps, Glyphs, exaGlyphs);
        }
        else {
            wrap(pExaScr, ps, Glyphs, ExaCheckGlyphs);
        }
        wrap(pExaScr, ps, Trapezoids, exaTrapezoids);
        wrap(pExaScr, ps, Triangles, exaTriangles);
        wrap(pExaScr, ps, AddTraps, ExaCheckAddTraps);
957 958
    }

959 960 961 962 963 964
#ifdef MITSHM
    /*
     * Don't allow shared pixmaps.
     */
    ShmRegisterFuncs(pScreen, &exaShmFuncs);
#endif
965 966 967
    /*
     * Hookup offscreen pixmaps
     */
968
    if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) {
969 970
        if (!dixRegisterScreenSpecificPrivateKey
            (pScreen, &pExaScr->pixmapPrivateKeyRec, PRIVATE_PIXMAP,
971
             sizeof(ExaPixmapPrivRec))) {
972
            LogMessage(X_WARNING,
973 974 975 976 977 978 979 980 981 982
                       "EXA(%d): Failed to allocate pixmap private\n",
                       pScreen->myNum);
            return FALSE;
        }
        if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) {
            if (pExaScr->info->flags & EXA_MIXED_PIXMAPS) {
                wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_mixed);
                wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed);
                wrap(pExaScr, pScreen, ModifyPixmapHeader,
                     exaModifyPixmapHeader_mixed);
983 984 985
                wrap(pExaScr, pScreen, SharePixmapBacking, exaSharePixmapBacking_mixed);
                wrap(pExaScr, pScreen, SetSharedPixmapBacking, exaSetSharedPixmapBacking_mixed);

986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
                pExaScr->do_migration = exaDoMigration_mixed;
                pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_mixed;
                pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed;
                pExaScr->do_move_out_pixmap = NULL;
                pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed;
            }
            else {
                wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
                wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
                wrap(pExaScr, pScreen, ModifyPixmapHeader,
                     exaModifyPixmapHeader_driver);
                pExaScr->do_migration = NULL;
                pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_driver;
                pExaScr->do_move_in_pixmap = NULL;
                pExaScr->do_move_out_pixmap = NULL;
                pExaScr->prepare_access_reg = NULL;
            }
        }
        else {
            wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
            wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic);
            wrap(pExaScr, pScreen, ModifyPixmapHeader,
                 exaModifyPixmapHeader_classic);
            pExaScr->do_migration = exaDoMigration_classic;
            pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_classic;
            pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic;
            pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic;
            pExaScr->prepare_access_reg = exaPrepareAccessReg_classic;
        }
        if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
            LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",
                       pScreen->myNum,
                       pExaScr->info->memorySize -
                       pExaScr->info->offScreenBase);
        }
        else {
            LogMessage(X_INFO, "EXA(%d): Driver allocated offscreen pixmaps\n",
                       pScreen->myNum);

1025
        }
1026 1027
    }
    else
1028
        LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum);
1029

1030
    if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
        DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase,
                    pExaScr->info->memorySize));
        if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
            if (!exaOffscreenInit(pScreen)) {
                LogMessage(X_WARNING,
                           "EXA(%d): Offscreen pixmap setup failed\n",
                           pScreen->myNum);
                return FALSE;
            }
        }
1041 1042
    }

1043
    if (ps->Glyphs == exaGlyphs)
1044
        exaGlyphsInit(pScreen);
1045

1046
    LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
1047
               " operations:\n", pScreen->myNum);
1048 1049 1050 1051 1052
    assert(pScreenInfo->PrepareSolid != NULL);
    LogMessage(X_INFO, "        Solid\n");
    assert(pScreenInfo->PrepareCopy != NULL);
    LogMessage(X_INFO, "        Copy\n");
    if (pScreenInfo->PrepareComposite != NULL) {
1053
        LogMessage(X_INFO, "        Composite (RENDER acceleration)\n");
1054 1055
    }
    if (pScreenInfo->UploadToScreen != NULL) {
1056
        LogMessage(X_INFO, "        UploadToScreen\n");
1057 1058
    }
    if (pScreenInfo->DownloadFromScreen != NULL) {
1059
        LogMessage(X_INFO, "        DownloadFromScreen\n");
1060 1061
    }

1062 1063 1064
    return TRUE;
}

1065 1066 1067 1068 1069
/**
 * exaDriverFini tears down EXA on a given screen.
 *
 * @param pScreen screen being torn down.
 */
1070
void
1071
exaDriverFini(ScreenPtr pScreen)
1072
{
1073
    /*right now does nothing */
1074 1075
}

1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
/**
 * exaMarkSync() should be called after any asynchronous drawing by the hardware.
 *
 * @param pScreen screen which drawing occurred on
 *
 * exaMarkSync() sets a flag to indicate that some asynchronous drawing has
 * happened and a WaitSync() will be necessary before relying on the contents of
 * offscreen memory from the CPU's perspective.  It also calls an optional
 * driver MarkSync() callback, the return value of which may be used to do partial
 * synchronization with the hardware in the future.
 */
1087 1088
void
exaMarkSync(ScreenPtr pScreen)
1089 1090 1091
{
    ExaScreenPriv(pScreen);

1092 1093
    pExaScr->info->needsSync = TRUE;
    if (pExaScr->info->MarkSync != NULL) {
1094
        pExaScr->info->lastMarker = (*pExaScr->info->MarkSync) (pScreen);
1095 1096 1097
    }
}

1098 1099 1100 1101 1102 1103 1104 1105 1106
/**
 * exaWaitSync() ensures that all drawing has been completed.
 *
 * @param pScreen screen being synchronized.
 *
 * Calls down into the driver to ensure that all previous drawing has completed.
 * It should always be called before relying on the framebuffer contents
 * reflecting previous drawing, from a CPU perspective.
 */
1107 1108
void
exaWaitSync(ScreenPtr pScreen)
1109 1110 1111
{
    ExaScreenPriv(pScreen);

1112
    if (pExaScr->info->needsSync && !pExaScr->swappedOut) {
1113
        (*pExaScr->info->WaitMarker) (pScreen, pExaScr->info->lastMarker);
1114
        pExaScr->info->needsSync = FALSE;
1115 1116
    }
}
1117 1118 1119 1120 1121 1122 1123

/**
 * Performs migration of the pixmaps according to the operation information
 * provided in pixmaps and can_accel and the migration scheme chosen in the
 * config file.
 */
void
1124
exaDoMigration(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
1125 1126
{
    ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
1127

1128 1129 1130
    ExaScreenPriv(pScreen);

    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
1131
        return;
1132 1133

    if (pExaScr->do_migration)
1134
        (*pExaScr->do_migration) (pixmaps, npixmaps, can_accel);
1135
}
1136 1137

void
1138
exaMoveInPixmap(PixmapPtr pPixmap)
1139 1140
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
1141

1142 1143 1144
    ExaScreenPriv(pScreen);

    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
1145
        return;
1146 1147

    if (pExaScr->do_move_in_pixmap)
1148
        (*pExaScr->do_move_in_pixmap) (pPixmap);
1149 1150 1151
}

void
1152
exaMoveOutPixmap(PixmapPtr pPixmap)
1153 1154
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
1155

1156 1157 1158
    ExaScreenPriv(pScreen);

    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
1159
        return;
1160 1161

    if (pExaScr->do_move_out_pixmap)
1162
        (*pExaScr->do_move_out_pixmap) (pPixmap);
1163
}