105b261ecSmrg/*
235c4bbdfSmrg * Copyright © 2001 Keith Packard
305b261ecSmrg *
435c4bbdfSmrg * Partly based on code that is Copyright © The XFree86 Project Inc.
505b261ecSmrg *
605b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
705b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
805b261ecSmrg * the above copyright notice appear in all copies and that both that
905b261ecSmrg * copyright notice and this permission notice appear in supporting
1005b261ecSmrg * documentation, and that the name of Keith Packard not be used in
1105b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1205b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1305b261ecSmrg * representations about the suitability of this software for any purpose.  It
1405b261ecSmrg * is provided "as is" without express or implied warranty.
1505b261ecSmrg *
1605b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1705b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1805b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1905b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2005b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2105b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2205b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2305b261ecSmrg */
2405b261ecSmrg
2505b261ecSmrg/** @file
2605b261ecSmrg * This file covers the initialization and teardown of EXA, and has various
2705b261ecSmrg * functions not responsible for performing rendering, pixmap migration, or
2805b261ecSmrg * memory management.
2905b261ecSmrg */
3005b261ecSmrg
3105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3205b261ecSmrg#include <dix-config.h>
3305b261ecSmrg#endif
3405b261ecSmrg
3505b261ecSmrg#include <stdlib.h>
3605b261ecSmrg
3705b261ecSmrg#include "exa_priv.h"
3805b261ecSmrg#include "exa.h"
3905b261ecSmrg
406747b715SmrgDevPrivateKeyRec exaScreenPrivateKeyRec;
414642e01fSmrg
424642e01fSmrg#ifdef MITSHM
434642e01fSmrgstatic ShmFuncs exaShmFuncs = { NULL, NULL };
444642e01fSmrg#endif
454642e01fSmrg
4605b261ecSmrg/**
4705b261ecSmrg * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
4805b261ecSmrg * the beginning of the given pixmap.
4905b261ecSmrg *
5005b261ecSmrg * Note that drivers are free to, and often do, munge this offset as necessary
5105b261ecSmrg * for handing to the hardware -- for example, translating it into a different
5205b261ecSmrg * aperture.  This function may need to be extended in the future if we grow
5305b261ecSmrg * support for having multiple card-accessible offscreen, such as an AGP memory
5405b261ecSmrg * pool alongside the framebuffer pool.
5505b261ecSmrg */
5605b261ecSmrgunsigned long
5705b261ecSmrgexaGetPixmapOffset(PixmapPtr pPix)
5805b261ecSmrg{
5935c4bbdfSmrg    ExaScreenPriv(pPix->drawable.pScreen);
6035c4bbdfSmrg    ExaPixmapPriv(pPix);
6105b261ecSmrg
6235c4bbdfSmrg    return (CARD8 *) pExaPixmap->fb_ptr - pExaScr->info->memoryBase;
634642e01fSmrg}
6405b261ecSmrg
654642e01fSmrgvoid *
664642e01fSmrgexaGetPixmapDriverPrivate(PixmapPtr pPix)
674642e01fSmrg{
684642e01fSmrg    ExaPixmapPriv(pPix);
694642e01fSmrg
704642e01fSmrg    return pExaPixmap->driverPriv;
7105b261ecSmrg}
7205b261ecSmrg
7305b261ecSmrg/**
7405b261ecSmrg * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap.
7505b261ecSmrg *
7605b261ecSmrg * This is a helper to make driver code more obvious, due to the rather obscure
7705b261ecSmrg * naming of the pitch field in the pixmap.
7805b261ecSmrg */
7905b261ecSmrgunsigned long
8005b261ecSmrgexaGetPixmapPitch(PixmapPtr pPix)
8105b261ecSmrg{
8205b261ecSmrg    return pPix->devKind;
8305b261ecSmrg}
8405b261ecSmrg
8505b261ecSmrg/**
8605b261ecSmrg * exaGetPixmapSize() returns the size in bytes of the given pixmap in video
8705b261ecSmrg * memory. Only valid when the pixmap is currently in framebuffer.
8805b261ecSmrg */
8905b261ecSmrgunsigned long
9005b261ecSmrgexaGetPixmapSize(PixmapPtr pPix)
9105b261ecSmrg{
9205b261ecSmrg    ExaPixmapPrivPtr pExaPixmap;
9305b261ecSmrg
9405b261ecSmrg    pExaPixmap = ExaGetPixmapPriv(pPix);
9505b261ecSmrg    if (pExaPixmap != NULL)
9635c4bbdfSmrg        return pExaPixmap->fb_size;
9705b261ecSmrg    return 0;
9805b261ecSmrg}
9905b261ecSmrg
10005b261ecSmrg/**
10105b261ecSmrg * exaGetDrawablePixmap() returns a backing pixmap for a given drawable.
10205b261ecSmrg *
10305b261ecSmrg * @param pDrawable the drawable being requested.
10405b261ecSmrg *
10505b261ecSmrg * This function returns the backing pixmap for a drawable, whether it is a
10605b261ecSmrg * redirected window, unredirected window, or already a pixmap.  Note that
10705b261ecSmrg * coordinate translation is needed when drawing to the backing pixmap of a
10805b261ecSmrg * redirected window, and the translation coordinates are provided by calling
10905b261ecSmrg * exaGetOffscreenPixmap() on the drawable.
11005b261ecSmrg */
11105b261ecSmrgPixmapPtr
11205b261ecSmrgexaGetDrawablePixmap(DrawablePtr pDrawable)
11305b261ecSmrg{
11435c4bbdfSmrg    if (pDrawable->type == DRAWABLE_WINDOW)
11535c4bbdfSmrg        return pDrawable->pScreen->GetWindowPixmap((WindowPtr) pDrawable);
11635c4bbdfSmrg    else
11735c4bbdfSmrg        return (PixmapPtr) pDrawable;
1186747b715Smrg}
11905b261ecSmrg
12005b261ecSmrg/**
12105b261ecSmrg * Sets the offsets to add to coordinates to make them address the same bits in
12205b261ecSmrg * the backing drawable. These coordinates are nonzero only for redirected
12305b261ecSmrg * windows.
12405b261ecSmrg */
12505b261ecSmrgvoid
12635c4bbdfSmrgexaGetDrawableDeltas(DrawablePtr pDrawable, PixmapPtr pPixmap, int *xp, int *yp)
12705b261ecSmrg{
12805b261ecSmrg#ifdef COMPOSITE
12905b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
13035c4bbdfSmrg        *xp = -pPixmap->screen_x;
13135c4bbdfSmrg        *yp = -pPixmap->screen_y;
13235c4bbdfSmrg        return;
13305b261ecSmrg    }
13405b261ecSmrg#endif
13505b261ecSmrg
13605b261ecSmrg    *xp = 0;
13705b261ecSmrg    *yp = 0;
13805b261ecSmrg}
13905b261ecSmrg
14005b261ecSmrg/**
14105b261ecSmrg * exaPixmapDirty() marks a pixmap as dirty, allowing for
14205b261ecSmrg * optimizations in pixmap migration when no changes have occurred.
14305b261ecSmrg */
14405b261ecSmrgvoid
14535c4bbdfSmrgexaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2)
14605b261ecSmrg{
14705b261ecSmrg    BoxRec box;
14805b261ecSmrg    RegionRec region;
14905b261ecSmrg
15005b261ecSmrg    box.x1 = max(x1, 0);
15105b261ecSmrg    box.y1 = max(y1, 0);
15205b261ecSmrg    box.x2 = min(x2, pPix->drawable.width);
15305b261ecSmrg    box.y2 = min(y2, pPix->drawable.height);
15405b261ecSmrg
15505b261ecSmrg    if (box.x1 >= box.x2 || box.y1 >= box.y2)
15635c4bbdfSmrg        return;
15705b261ecSmrg
1586747b715Smrg    RegionInit(&region, &box, 1);
1598223e2f2Smrg    DamageDamageRegion(&pPix->drawable, &region);
1606747b715Smrg    RegionUninit(&region);
16105b261ecSmrg}
16205b261ecSmrg
16305b261ecSmrgstatic int
16405b261ecSmrgexaLog2(int val)
16505b261ecSmrg{
16605b261ecSmrg    int bits;
16705b261ecSmrg
16805b261ecSmrg    if (val <= 0)
16935c4bbdfSmrg        return 0;
17005b261ecSmrg    for (bits = 0; val != 0; bits++)
17135c4bbdfSmrg        val >>= 1;
17205b261ecSmrg    return bits - 1;
17305b261ecSmrg}
17405b261ecSmrg
1756747b715Smrgvoid
1764642e01fSmrgexaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
1774642e01fSmrg                 int w, int h, int bpp)
1784642e01fSmrg{
1794642e01fSmrg    pExaPixmap->accel_blocked = 0;
1804642e01fSmrg
1814642e01fSmrg    if (pExaScr->info->maxPitchPixels) {
1826747b715Smrg        int max_pitch = pExaScr->info->maxPitchPixels * bits_to_bytes(bpp);
1834642e01fSmrg
1844642e01fSmrg        if (pExaPixmap->fb_pitch > max_pitch)
1854642e01fSmrg            pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;
1864642e01fSmrg    }
1874642e01fSmrg
1884642e01fSmrg    if (pExaScr->info->maxPitchBytes &&
1894642e01fSmrg        pExaPixmap->fb_pitch > pExaScr->info->maxPitchBytes)
1904642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;
1914642e01fSmrg
1924642e01fSmrg    if (w > pExaScr->info->maxX)
1934642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_WIDTH;
1944642e01fSmrg
1954642e01fSmrg    if (h > pExaScr->info->maxY)
1964642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT;
1974642e01fSmrg}
1984642e01fSmrg
1996747b715Smrgvoid
2004642e01fSmrgexaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
2014642e01fSmrg              int w, int h, int bpp)
2024642e01fSmrg{
2034642e01fSmrg    if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
2046747b715Smrg        pExaPixmap->fb_pitch = bits_to_bytes((1 << (exaLog2(w - 1) + 1)) * bpp);
2054642e01fSmrg    else
2066747b715Smrg        pExaPixmap->fb_pitch = bits_to_bytes(w * bpp);
2074642e01fSmrg
2084642e01fSmrg    pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
2094642e01fSmrg                                     pExaScr->info->pixmapPitchAlign);
2104642e01fSmrg}
2114642e01fSmrg
21205b261ecSmrg/**
2136747b715Smrg * Returns TRUE if the pixmap is not movable.  This is the case where it's a
2146747b715Smrg * pixmap which has no private (almost always bad) or it's a scratch pixmap created by
2156747b715Smrg * some X Server internal component (the score says it's pinned).
21605b261ecSmrg */
2176747b715SmrgBool
21835c4bbdfSmrgexaPixmapIsPinned(PixmapPtr pPix)
21905b261ecSmrg{
22035c4bbdfSmrg    ExaPixmapPriv(pPix);
22105b261ecSmrg
2226747b715Smrg    if (pExaPixmap == NULL)
22335c4bbdfSmrg        EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE);
22405b261ecSmrg
2256747b715Smrg    return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
2264642e01fSmrg}
2274642e01fSmrg
22805b261ecSmrg/**
2296747b715Smrg * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen
23005b261ecSmrg * memory, meaning that acceleration could probably be done to it, and that it
23105b261ecSmrg * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
23205b261ecSmrg * with the CPU.
23305b261ecSmrg *
23405b261ecSmrg * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
23505b261ecSmrg * deal with moving pixmaps in and out of system memory), EXA will give drivers
2366747b715Smrg * pixmaps as arguments for which exaPixmapHasGpuCopy() is TRUE.
23705b261ecSmrg *
23805b261ecSmrg * @return TRUE if the given drawable is in framebuffer memory.
23905b261ecSmrg */
24005b261ecSmrgBool
2416747b715SmrgexaPixmapHasGpuCopy(PixmapPtr pPixmap)
24205b261ecSmrg{
24335c4bbdfSmrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
24435c4bbdfSmrg
24505b261ecSmrg    ExaScreenPriv(pScreen);
24605b261ecSmrg
2476747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
24835c4bbdfSmrg        return FALSE;
2494642e01fSmrg
25035c4bbdfSmrg    return (*pExaScr->pixmap_has_gpu_copy) (pPixmap);
25105b261ecSmrg}
25205b261ecSmrg
25305b261ecSmrg/**
2546747b715Smrg * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapHasGpuCopy().
25505b261ecSmrg */
25605b261ecSmrgBool
25735c4bbdfSmrgexaDrawableIsOffscreen(DrawablePtr pDrawable)
25805b261ecSmrg{
25935c4bbdfSmrg    return exaPixmapHasGpuCopy(exaGetDrawablePixmap(pDrawable));
26005b261ecSmrg}
26105b261ecSmrg
26205b261ecSmrg/**
26305b261ecSmrg * Returns the pixmap which backs a drawable, and the offsets to add to
26405b261ecSmrg * coordinates to make them address the same bits in the backing drawable.
26505b261ecSmrg */
26605b261ecSmrgPixmapPtr
26735c4bbdfSmrgexaGetOffscreenPixmap(DrawablePtr pDrawable, int *xp, int *yp)
26805b261ecSmrg{
26935c4bbdfSmrg    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
27005b261ecSmrg
27135c4bbdfSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, xp, yp);
27205b261ecSmrg
27335c4bbdfSmrg    if (exaPixmapHasGpuCopy(pPixmap))
27435c4bbdfSmrg        return pPixmap;
27505b261ecSmrg    else
27635c4bbdfSmrg        return NULL;
27705b261ecSmrg}
27805b261ecSmrg
2796747b715Smrg/**
2806747b715Smrg * Returns TRUE if the pixmap GPU copy is being accessed.
2816747b715Smrg */
2826747b715SmrgBool
2836747b715SmrgExaDoPrepareAccess(PixmapPtr pPixmap, int index)
28405b261ecSmrg{
2856747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
28635c4bbdfSmrg
28735c4bbdfSmrg    ExaScreenPriv(pScreen);
2886747b715Smrg    ExaPixmapPriv(pPixmap);
2896747b715Smrg    Bool has_gpu_copy, ret;
2906747b715Smrg    int i;
29105b261ecSmrg
2926747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
29335c4bbdfSmrg        return FALSE;
2946747b715Smrg
2956747b715Smrg    if (pExaPixmap == NULL)
29635c4bbdfSmrg        EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE);
2976747b715Smrg
2986747b715Smrg    /* Handle repeated / nested calls. */
2996747b715Smrg    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
30035c4bbdfSmrg        if (pExaScr->access[i].pixmap == pPixmap) {
30135c4bbdfSmrg            pExaScr->access[i].count++;
30235c4bbdfSmrg            return pExaScr->access[i].retval;
30335c4bbdfSmrg        }
3044642e01fSmrg    }
30505b261ecSmrg
3066747b715Smrg    /* If slot for this index is taken, find an empty slot */
3076747b715Smrg    if (pExaScr->access[index].pixmap) {
30835c4bbdfSmrg        for (index = EXA_NUM_PREPARE_INDICES - 1; index >= 0; index--)
30935c4bbdfSmrg            if (!pExaScr->access[index].pixmap)
31035c4bbdfSmrg                break;
3116747b715Smrg    }
3126747b715Smrg
3136747b715Smrg    /* Access to this pixmap hasn't been prepared yet, so data pointer should be NULL. */
3146747b715Smrg    if (pPixmap->devPrivate.ptr != NULL) {
31535c4bbdfSmrg        EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n", pPixmap->devPrivate.ptr));
3166747b715Smrg    }
3176747b715Smrg
3186747b715Smrg    has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
3196747b715Smrg
3206747b715Smrg    if (has_gpu_copy && pExaPixmap->fb_ptr) {
32135c4bbdfSmrg        pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
32235c4bbdfSmrg        ret = TRUE;
32335c4bbdfSmrg    }
32435c4bbdfSmrg    else {
32535c4bbdfSmrg        pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
32635c4bbdfSmrg        ret = FALSE;
3276747b715Smrg    }
3286747b715Smrg
3296747b715Smrg    /* Store so we can handle repeated / nested calls. */
3306747b715Smrg    pExaScr->access[index].pixmap = pPixmap;
3316747b715Smrg    pExaScr->access[index].count = 1;
3326747b715Smrg
3336747b715Smrg    if (!has_gpu_copy)
33435c4bbdfSmrg        goto out;
33505b261ecSmrg
33635c4bbdfSmrg    exaWaitSync(pScreen);
33705b261ecSmrg
33805b261ecSmrg    if (pExaScr->info->PrepareAccess == NULL)
33935c4bbdfSmrg        goto out;
34005b261ecSmrg
3416747b715Smrg    if (index >= EXA_PREPARE_AUX_DEST &&
34235c4bbdfSmrg        !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
34335c4bbdfSmrg        if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
34435c4bbdfSmrg            FatalError("Unsupported AUX indices used on a pinned pixmap.\n");
34535c4bbdfSmrg        exaMoveOutPixmap(pPixmap);
34635c4bbdfSmrg        ret = FALSE;
34735c4bbdfSmrg        goto out;
3484642e01fSmrg    }
3494642e01fSmrg
35005b261ecSmrg    if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
35135c4bbdfSmrg        if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED &&
35235c4bbdfSmrg            !(pExaScr->info->flags & EXA_MIXED_PIXMAPS))
35335c4bbdfSmrg            FatalError("Driver failed PrepareAccess on a pinned pixmap.\n");
35435c4bbdfSmrg        exaMoveOutPixmap(pPixmap);
35535c4bbdfSmrg        ret = FALSE;
35635c4bbdfSmrg        goto out;
35705b261ecSmrg    }
3584642e01fSmrg
3596747b715Smrg    ret = TRUE;
3604642e01fSmrg
36135c4bbdfSmrg out:
3626747b715Smrg    pExaScr->access[index].retval = ret;
3636747b715Smrg    return ret;
3644642e01fSmrg}
3654642e01fSmrg
3664642e01fSmrg/**
3674642e01fSmrg * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
3684642e01fSmrg *
3694642e01fSmrg * It deals with waiting for synchronization with the card, determining if
3704642e01fSmrg * PrepareAccess() is necessary, and working around PrepareAccess() failure.
3714642e01fSmrg */
3724642e01fSmrgvoid
3734642e01fSmrgexaPrepareAccess(DrawablePtr pDrawable, int index)
3744642e01fSmrg{
3756747b715Smrg    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
37635c4bbdfSmrg
3776747b715Smrg    ExaScreenPriv(pDrawable->pScreen);
3786747b715Smrg
3796747b715Smrg    if (pExaScr->prepare_access_reg)
38035c4bbdfSmrg        pExaScr->prepare_access_reg(pPixmap, index, NULL);
3816747b715Smrg    else
38235c4bbdfSmrg        (void) ExaDoPrepareAccess(pPixmap, index);
3834642e01fSmrg}
3844642e01fSmrg
38505b261ecSmrg/**
38605b261ecSmrg * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
38705b261ecSmrg *
38805b261ecSmrg * It deals with calling the driver's FinishAccess() only if necessary.
38905b261ecSmrg */
39005b261ecSmrgvoid
39105b261ecSmrgexaFinishAccess(DrawablePtr pDrawable, int index)
39205b261ecSmrg{
39335c4bbdfSmrg    ScreenPtr pScreen = pDrawable->pScreen;
39435c4bbdfSmrg
39535c4bbdfSmrg    ExaScreenPriv(pScreen);
39635c4bbdfSmrg    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
39735c4bbdfSmrg
39835c4bbdfSmrg    ExaPixmapPriv(pPixmap);
3996747b715Smrg    int i;
4006747b715Smrg
4016747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
40235c4bbdfSmrg        return;
40305b261ecSmrg
4046747b715Smrg    if (pExaPixmap == NULL)
40535c4bbdfSmrg        EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),);
4066747b715Smrg
4076747b715Smrg    /* Handle repeated / nested calls. */
4086747b715Smrg    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
40935c4bbdfSmrg        if (pExaScr->access[i].pixmap == pPixmap) {
41035c4bbdfSmrg            if (--pExaScr->access[i].count > 0)
41135c4bbdfSmrg                return;
41235c4bbdfSmrg            break;
41335c4bbdfSmrg        }
41405b261ecSmrg    }
41505b261ecSmrg
4166747b715Smrg    /* Catch unbalanced Prepare/FinishAccess calls. */
4176747b715Smrg    if (i == EXA_NUM_PREPARE_INDICES)
41835c4bbdfSmrg        EXA_FatalErrorDebugWithRet(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", pPixmap),);
4196747b715Smrg
4206747b715Smrg    pExaScr->access[i].pixmap = NULL;
42105b261ecSmrg
4226747b715Smrg    /* We always hide the devPrivate.ptr. */
4236747b715Smrg    pPixmap->devPrivate.ptr = NULL;
4246747b715Smrg
4258223e2f2Smrg    /* Only call FinishAccess if PrepareAccess was called and succeeded. */
4268223e2f2Smrg    if (!pExaScr->info->FinishAccess || !pExaScr->access[i].retval)
42735c4bbdfSmrg        return;
42805b261ecSmrg
4296747b715Smrg    if (i >= EXA_PREPARE_AUX_DEST &&
43035c4bbdfSmrg        !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
43135c4bbdfSmrg        ErrorF("EXA bug: Trying to call driver FinishAccess hook with "
43235c4bbdfSmrg               "unsupported index EXA_PREPARE_AUX*\n");
43335c4bbdfSmrg        return;
4344642e01fSmrg    }
4354642e01fSmrg
4366747b715Smrg    (*pExaScr->info->FinishAccess) (pPixmap, i);
43705b261ecSmrg}
43805b261ecSmrg
43905b261ecSmrg/**
4406747b715Smrg * Helper for things common to all schemes when a pixmap is destroyed
44105b261ecSmrg */
4426747b715Smrgvoid
4436747b715SmrgexaDestroyPixmap(PixmapPtr pPixmap)
44405b261ecSmrg{
4456747b715Smrg    ExaScreenPriv(pPixmap->drawable.pScreen);
4466747b715Smrg    int i;
4476747b715Smrg
4486747b715Smrg    /* Finish access if it was prepared (e.g. pixmap created during
4496747b715Smrg     * software fallback)
45005b261ecSmrg     */
4516747b715Smrg    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
45235c4bbdfSmrg        if (pExaScr->access[i].pixmap == pPixmap) {
45335c4bbdfSmrg            exaFinishAccess(&pPixmap->drawable, i);
45435c4bbdfSmrg            pExaScr->access[i].pixmap = NULL;
45535c4bbdfSmrg            break;
45635c4bbdfSmrg        }
45705b261ecSmrg    }
4586747b715Smrg}
4596747b715Smrg
4606747b715Smrg/**
4616747b715Smrg * Here begins EXA's GC code.
4626747b715Smrg * Do not ever access the fb/mi layer directly.
4636747b715Smrg */
4646747b715Smrg
4656747b715Smrgstatic void
46635c4bbdfSmrg exaValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable);
4676747b715Smrg
4686747b715Smrgstatic void
46935c4bbdfSmrg exaDestroyGC(GCPtr pGC);
4706747b715Smrg
4716747b715Smrgstatic void
47235c4bbdfSmrg exaChangeGC(GCPtr pGC, unsigned long mask);
4736747b715Smrg
4746747b715Smrgstatic void
47535c4bbdfSmrg exaCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
4766747b715Smrg
4776747b715Smrgstatic void
47835c4bbdfSmrg exaChangeClip(GCPtr pGC, int type, void *pvalue, int nrects);
4796747b715Smrg
4806747b715Smrgstatic void
48135c4bbdfSmrg exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc);
4826747b715Smrg
4836747b715Smrgstatic void
48435c4bbdfSmrg exaDestroyClip(GCPtr pGC);
4856747b715Smrg
4866747b715Smrgconst GCFuncs exaGCFuncs = {
4876747b715Smrg    exaValidateGC,
4886747b715Smrg    exaChangeGC,
4896747b715Smrg    exaCopyGC,
4906747b715Smrg    exaDestroyGC,
4916747b715Smrg    exaChangeClip,
4926747b715Smrg    exaDestroyClip,
4936747b715Smrg    exaCopyClip
4946747b715Smrg};
4956747b715Smrg
4966747b715Smrgstatic void
49735c4bbdfSmrgexaValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
4986747b715Smrg{
4996747b715Smrg    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
500ed6184dfSmrg     * Do a few smart things so fbValidateGC can do its work.
5016747b715Smrg     */
5026747b715Smrg
5036747b715Smrg    ScreenPtr pScreen = pDrawable->pScreen;
50435c4bbdfSmrg
5056747b715Smrg    ExaScreenPriv(pScreen);
5066747b715Smrg    ExaGCPriv(pGC);
5076747b715Smrg    PixmapPtr pTile = NULL;
5086747b715Smrg
5091b5d61b8Smrg    /* Either of these conditions is enough to trigger access to a tile pixmap.
5101b5d61b8Smrg     * With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid
5111b5d61b8Smrg     * tile pixmap pointer.
5121b5d61b8Smrg     */
51335c4bbdfSmrg    if (pGC->fillStyle == FillTiled ||
51435c4bbdfSmrg        ((changes & GCTile) && !pGC->tileIsPixel)) {
51535c4bbdfSmrg        pTile = pGC->tile.pixmap;
51605b261ecSmrg    }
51705b261ecSmrg
5186747b715Smrg    if (pGC->stipple)
5196747b715Smrg        exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
5206747b715Smrg    if (pTile)
52135c4bbdfSmrg        exaPrepareAccess(&pTile->drawable, EXA_PREPARE_SRC);
5226747b715Smrg
5236747b715Smrg    /* Calls to Create/DestroyPixmap have to be identified as special. */
5246747b715Smrg    pExaScr->fallback_counter++;
5256747b715Smrg    swap(pExaGC, pGC, funcs);
52635c4bbdfSmrg    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
5276747b715Smrg    swap(pExaGC, pGC, funcs);
5286747b715Smrg    pExaScr->fallback_counter--;
5296747b715Smrg
5306747b715Smrg    if (pTile)
53135c4bbdfSmrg        exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC);
5326747b715Smrg    if (pGC->stipple)
53335c4bbdfSmrg        exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
5346747b715Smrg}
5356747b715Smrg
5366747b715Smrg/* Is exaPrepareAccessGC() needed? */
5376747b715Smrgstatic void
5386747b715SmrgexaDestroyGC(GCPtr pGC)
5396747b715Smrg{
5406747b715Smrg    ExaGCPriv(pGC);
5416747b715Smrg    swap(pExaGC, pGC, funcs);
54235c4bbdfSmrg    (*pGC->funcs->DestroyGC) (pGC);
5436747b715Smrg    swap(pExaGC, pGC, funcs);
5446747b715Smrg}
54505b261ecSmrg
5466747b715Smrgstatic void
54735c4bbdfSmrgexaChangeGC(GCPtr pGC, unsigned long mask)
5486747b715Smrg{
5496747b715Smrg    ExaGCPriv(pGC);
5506747b715Smrg    swap(pExaGC, pGC, funcs);
5516747b715Smrg    (*pGC->funcs->ChangeGC) (pGC, mask);
5526747b715Smrg    swap(pExaGC, pGC, funcs);
55305b261ecSmrg}
55405b261ecSmrg
5556747b715Smrgstatic void
55635c4bbdfSmrgexaCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
5576747b715Smrg{
5586747b715Smrg    ExaGCPriv(pGCDst);
5596747b715Smrg    swap(pExaGC, pGCDst, funcs);
5606747b715Smrg    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
5616747b715Smrg    swap(pExaGC, pGCDst, funcs);
5626747b715Smrg}
5636747b715Smrg
5646747b715Smrgstatic void
56535c4bbdfSmrgexaChangeClip(GCPtr pGC, int type, void *pvalue, int nrects)
5666747b715Smrg{
5676747b715Smrg    ExaGCPriv(pGC);
5686747b715Smrg    swap(pExaGC, pGC, funcs);
5696747b715Smrg    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
5706747b715Smrg    swap(pExaGC, pGC, funcs);
5716747b715Smrg}
5726747b715Smrg
5736747b715Smrgstatic void
5746747b715SmrgexaCopyClip(GCPtr pGCDst, GCPtr pGCSrc)
5756747b715Smrg{
5766747b715Smrg    ExaGCPriv(pGCDst);
5776747b715Smrg    swap(pExaGC, pGCDst, funcs);
57835c4bbdfSmrg    (*pGCDst->funcs->CopyClip) (pGCDst, pGCSrc);
5796747b715Smrg    swap(pExaGC, pGCDst, funcs);
5806747b715Smrg}
5816747b715Smrg
5826747b715Smrgstatic void
5836747b715SmrgexaDestroyClip(GCPtr pGC)
5846747b715Smrg{
5856747b715Smrg    ExaGCPriv(pGC);
5866747b715Smrg    swap(pExaGC, pGC, funcs);
58735c4bbdfSmrg    (*pGC->funcs->DestroyClip) (pGC);
5886747b715Smrg    swap(pExaGC, pGC, funcs);
5896747b715Smrg}
59005b261ecSmrg
59105b261ecSmrg/**
59205b261ecSmrg * exaCreateGC makes a new GC and hooks up its funcs handler, so that
59305b261ecSmrg * exaValidateGC() will get called.
59405b261ecSmrg */
59505b261ecSmrgstatic int
59635c4bbdfSmrgexaCreateGC(GCPtr pGC)
59705b261ecSmrg{
5986747b715Smrg    ScreenPtr pScreen = pGC->pScreen;
59935c4bbdfSmrg
6006747b715Smrg    ExaScreenPriv(pScreen);
6016747b715Smrg    ExaGCPriv(pGC);
6026747b715Smrg    Bool ret;
60305b261ecSmrg
6046747b715Smrg    swap(pExaScr, pScreen, CreateGC);
6056747b715Smrg    if ((ret = (*pScreen->CreateGC) (pGC))) {
60635c4bbdfSmrg        wrap(pExaGC, pGC, funcs, &exaGCFuncs);
60735c4bbdfSmrg        wrap(pExaGC, pGC, ops, &exaOps);
6086747b715Smrg    }
6096747b715Smrg    swap(pExaScr, pScreen, CreateGC);
61005b261ecSmrg
6116747b715Smrg    return ret;
61205b261ecSmrg}
61305b261ecSmrg
6144642e01fSmrgstatic Bool
6154642e01fSmrgexaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
6164642e01fSmrg{
6174642e01fSmrg    Bool ret;
6186747b715Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
61935c4bbdfSmrg
6206747b715Smrg    ExaScreenPriv(pScreen);
6214642e01fSmrg
62235c4bbdfSmrg    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
62335c4bbdfSmrg        exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
6244642e01fSmrg
6254642e01fSmrg    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
62635c4bbdfSmrg        exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
6274642e01fSmrg
6286747b715Smrg    pExaScr->fallback_counter++;
6296747b715Smrg    swap(pExaScr, pScreen, ChangeWindowAttributes);
6306747b715Smrg    ret = pScreen->ChangeWindowAttributes(pWin, mask);
6316747b715Smrg    swap(pExaScr, pScreen, ChangeWindowAttributes);
6326747b715Smrg    pExaScr->fallback_counter--;
6334642e01fSmrg
63435c4bbdfSmrg    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
63535c4bbdfSmrg        exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
6366747b715Smrg    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
63735c4bbdfSmrg        exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
6384642e01fSmrg
6394642e01fSmrg    return ret;
6404642e01fSmrg}
6414642e01fSmrg
6424642e01fSmrgstatic RegionPtr
6434642e01fSmrgexaBitmapToRegion(PixmapPtr pPix)
6444642e01fSmrg{
6456747b715Smrg    RegionPtr ret;
6466747b715Smrg    ScreenPtr pScreen = pPix->drawable.pScreen;
64735c4bbdfSmrg
6486747b715Smrg    ExaScreenPriv(pScreen);
6496747b715Smrg
6506747b715Smrg    exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC);
6516747b715Smrg    swap(pExaScr, pScreen, BitmapToRegion);
65235c4bbdfSmrg    ret = (*pScreen->BitmapToRegion) (pPix);
6536747b715Smrg    swap(pExaScr, pScreen, BitmapToRegion);
6546747b715Smrg    exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC);
6556747b715Smrg
6566747b715Smrg    return ret;
6574642e01fSmrg}
6584642e01fSmrg
6594642e01fSmrgstatic Bool
6604642e01fSmrgexaCreateScreenResources(ScreenPtr pScreen)
6614642e01fSmrg{
6624642e01fSmrg    ExaScreenPriv(pScreen);
6634642e01fSmrg    PixmapPtr pScreenPixmap;
6644642e01fSmrg    Bool b;
6654642e01fSmrg
6666747b715Smrg    swap(pExaScr, pScreen, CreateScreenResources);
6674642e01fSmrg    b = pScreen->CreateScreenResources(pScreen);
6686747b715Smrg    swap(pExaScr, pScreen, CreateScreenResources);
6694642e01fSmrg
6704642e01fSmrg    if (!b)
6714642e01fSmrg        return FALSE;
6724642e01fSmrg
6734642e01fSmrg    pScreenPixmap = pScreen->GetScreenPixmap(pScreen);
6744642e01fSmrg
6754642e01fSmrg    if (pScreenPixmap) {
6764642e01fSmrg        ExaPixmapPriv(pScreenPixmap);
6774642e01fSmrg
6784642e01fSmrg        exaSetAccelBlock(pExaScr, pExaPixmap,
6794642e01fSmrg                         pScreenPixmap->drawable.width,
6804642e01fSmrg                         pScreenPixmap->drawable.height,
6814642e01fSmrg                         pScreenPixmap->drawable.bitsPerPixel);
6824642e01fSmrg    }
6834642e01fSmrg
6844642e01fSmrg    return TRUE;
6854642e01fSmrg}
6864642e01fSmrg
6876747b715Smrgstatic void
6881b5d61b8SmrgExaBlockHandler(ScreenPtr pScreen, void *pTimeout)
6896747b715Smrg{
6906747b715Smrg    ExaScreenPriv(pScreen);
6916747b715Smrg
6926747b715Smrg    /* Move any deferred results from a software fallback to the driver pixmap */
6936747b715Smrg    if (pExaScr->deferred_mixed_pixmap)
69435c4bbdfSmrg        exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
6956747b715Smrg
6966747b715Smrg    unwrap(pExaScr, pScreen, BlockHandler);
6971b5d61b8Smrg    (*pScreen->BlockHandler) (pScreen, pTimeout);
6986747b715Smrg    wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);
6996747b715Smrg
7006747b715Smrg    /* The rest only applies to classic EXA */
7016747b715Smrg    if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
70235c4bbdfSmrg        return;
7036747b715Smrg
70435c4bbdfSmrg    /* Try and keep the offscreen memory area tidy every now and then (at most
7056747b715Smrg     * once per second) when the server has been idle for at least 100ms.
7066747b715Smrg     */
7076747b715Smrg    if (pExaScr->numOffscreenAvailable > 1) {
70835c4bbdfSmrg        CARD32 now = GetTimeInMillis();
7096747b715Smrg
71035c4bbdfSmrg        pExaScr->nextDefragment = now +
71135c4bbdfSmrg            max(100, (INT32) (pExaScr->lastDefragment + 1000 - now));
71235c4bbdfSmrg        AdjustWaitForDelay(pTimeout, pExaScr->nextDefragment - now);
7136747b715Smrg    }
7146747b715Smrg}
7156747b715Smrg
7166747b715Smrgstatic void
7171b5d61b8SmrgExaWakeupHandler(ScreenPtr pScreen, int result)
7186747b715Smrg{
7196747b715Smrg    ExaScreenPriv(pScreen);
7206747b715Smrg
7216747b715Smrg    unwrap(pExaScr, pScreen, WakeupHandler);
7221b5d61b8Smrg    (*pScreen->WakeupHandler) (pScreen, result);
7236747b715Smrg    wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler);
7246747b715Smrg
7256747b715Smrg    if (result == 0 && pExaScr->numOffscreenAvailable > 1) {
72635c4bbdfSmrg        CARD32 now = GetTimeInMillis();
7276747b715Smrg
72835c4bbdfSmrg        if ((int) (now - pExaScr->nextDefragment) > 0) {
72935c4bbdfSmrg            ExaOffscreenDefragment(pScreen);
73035c4bbdfSmrg            pExaScr->lastDefragment = now;
73135c4bbdfSmrg        }
7326747b715Smrg    }
7336747b715Smrg}
7346747b715Smrg
73505b261ecSmrg/**
73605b261ecSmrg * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's
73705b261ecSmrg * screen private, before calling down to the next CloseSccreen.
73805b261ecSmrg */
73905b261ecSmrgstatic Bool
74035c4bbdfSmrgexaCloseScreen(ScreenPtr pScreen)
74105b261ecSmrg{
74205b261ecSmrg    ExaScreenPriv(pScreen);
74335c4bbdfSmrg    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
74405b261ecSmrg
7454642e01fSmrg    if (ps->Glyphs == exaGlyphs)
74635c4bbdfSmrg        exaGlyphsFini(pScreen);
7474642e01fSmrg
7486747b715Smrg    if (pScreen->BlockHandler == ExaBlockHandler)
74935c4bbdfSmrg        unwrap(pExaScr, pScreen, BlockHandler);
7506747b715Smrg    if (pScreen->WakeupHandler == ExaWakeupHandler)
75135c4bbdfSmrg        unwrap(pExaScr, pScreen, WakeupHandler);
7526747b715Smrg    unwrap(pExaScr, pScreen, CreateGC);
7536747b715Smrg    unwrap(pExaScr, pScreen, CloseScreen);
7546747b715Smrg    unwrap(pExaScr, pScreen, GetImage);
7556747b715Smrg    unwrap(pExaScr, pScreen, GetSpans);
7566747b715Smrg    if (pExaScr->SavedCreatePixmap)
75735c4bbdfSmrg        unwrap(pExaScr, pScreen, CreatePixmap);
7586747b715Smrg    if (pExaScr->SavedDestroyPixmap)
75935c4bbdfSmrg        unwrap(pExaScr, pScreen, DestroyPixmap);
7606747b715Smrg    if (pExaScr->SavedModifyPixmapHeader)
76135c4bbdfSmrg        unwrap(pExaScr, pScreen, ModifyPixmapHeader);
7626747b715Smrg    unwrap(pExaScr, pScreen, CopyWindow);
7636747b715Smrg    unwrap(pExaScr, pScreen, ChangeWindowAttributes);
7646747b715Smrg    unwrap(pExaScr, pScreen, BitmapToRegion);
7656747b715Smrg    unwrap(pExaScr, pScreen, CreateScreenResources);
76635c4bbdfSmrg    if (pExaScr->SavedSharePixmapBacking)
76735c4bbdfSmrg        unwrap(pExaScr, pScreen, SharePixmapBacking);
76835c4bbdfSmrg    if (pExaScr->SavedSetSharedPixmapBacking)
76935c4bbdfSmrg        unwrap(pExaScr, pScreen, SetSharedPixmapBacking);
7706747b715Smrg    unwrap(pExaScr, ps, Composite);
7716747b715Smrg    if (pExaScr->SavedGlyphs)
77235c4bbdfSmrg        unwrap(pExaScr, ps, Glyphs);
7736747b715Smrg    unwrap(pExaScr, ps, Trapezoids);
7746747b715Smrg    unwrap(pExaScr, ps, Triangles);
7756747b715Smrg    unwrap(pExaScr, ps, AddTraps);
7766747b715Smrg
7776747b715Smrg    free(pExaScr);
77805b261ecSmrg
77935c4bbdfSmrg    return (*pScreen->CloseScreen) (pScreen);
78005b261ecSmrg}
78105b261ecSmrg
78205b261ecSmrg/**
78305b261ecSmrg * This function allocates a driver structure for EXA drivers to fill in.  By
78405b261ecSmrg * having EXA allocate the structure, the driver structure can be extended
78505b261ecSmrg * without breaking ABI between EXA and the drivers.  The driver's
78605b261ecSmrg * responsibility is to check beforehand that the EXA module has a matching
78705b261ecSmrg * major number and sufficient minor.  Drivers are responsible for freeing the
7886747b715Smrg * driver structure using free().
78905b261ecSmrg *
79005b261ecSmrg * @return a newly allocated, zero-filled driver structure
79105b261ecSmrg */
79205b261ecSmrgExaDriverPtr
79305b261ecSmrgexaDriverAlloc(void)
79405b261ecSmrg{
7956747b715Smrg    return calloc(1, sizeof(ExaDriverRec));
79605b261ecSmrg}
79705b261ecSmrg
79805b261ecSmrg/**
79905b261ecSmrg * @param pScreen screen being initialized
80005b261ecSmrg * @param pScreenInfo EXA driver record
80105b261ecSmrg *
80205b261ecSmrg * exaDriverInit sets up EXA given a driver record filled in by the driver.
80305b261ecSmrg * pScreenInfo should have been allocated by exaDriverAlloc().  See the
80405b261ecSmrg * comments in _ExaDriver for what must be filled in and what is optional.
80505b261ecSmrg *
80605b261ecSmrg * @return TRUE if EXA was successfully initialized.
80705b261ecSmrg */
80805b261ecSmrgBool
80935c4bbdfSmrgexaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo)
81005b261ecSmrg{
81105b261ecSmrg    ExaScreenPrivPtr pExaScr;
81205b261ecSmrg    PictureScreenPtr ps;
81305b261ecSmrg
81405b261ecSmrg    if (!pScreenInfo)
81535c4bbdfSmrg        return FALSE;
81605b261ecSmrg
8174642e01fSmrg    if (pScreenInfo->exa_major != EXA_VERSION_MAJOR ||
81835c4bbdfSmrg        pScreenInfo->exa_minor > EXA_VERSION_MINOR) {
81935c4bbdfSmrg        LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements "
82035c4bbdfSmrg                   "(%d.%d) are incompatible with EXA version (%d.%d)\n",
82135c4bbdfSmrg                   pScreen->myNum,
82235c4bbdfSmrg                   pScreenInfo->exa_major, pScreenInfo->exa_minor,
82335c4bbdfSmrg                   EXA_VERSION_MAJOR, EXA_VERSION_MINOR);
82435c4bbdfSmrg        return FALSE;
82505b261ecSmrg    }
82605b261ecSmrg
8276747b715Smrg    if (!pScreenInfo->CreatePixmap && !pScreenInfo->CreatePixmap2) {
82835c4bbdfSmrg        if (!pScreenInfo->memoryBase) {
82935c4bbdfSmrg            LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase "
83035c4bbdfSmrg                       "must be non-zero\n", pScreen->myNum);
83135c4bbdfSmrg            return FALSE;
83235c4bbdfSmrg        }
83335c4bbdfSmrg
83435c4bbdfSmrg        if (!pScreenInfo->memorySize) {
83535c4bbdfSmrg            LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be "
83635c4bbdfSmrg                       "non-zero\n", pScreen->myNum);
83735c4bbdfSmrg            return FALSE;
83835c4bbdfSmrg        }
83935c4bbdfSmrg
84035c4bbdfSmrg        if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) {
84135c4bbdfSmrg            LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must "
84235c4bbdfSmrg                       "be <= ExaDriverRec::memorySize\n", pScreen->myNum);
84335c4bbdfSmrg            return FALSE;
84435c4bbdfSmrg        }
84505b261ecSmrg    }
84605b261ecSmrg
84705b261ecSmrg    if (!pScreenInfo->PrepareSolid) {
84835c4bbdfSmrg        LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be "
84935c4bbdfSmrg                   "non-NULL\n", pScreen->myNum);
85035c4bbdfSmrg        return FALSE;
85105b261ecSmrg    }
85205b261ecSmrg
85305b261ecSmrg    if (!pScreenInfo->PrepareCopy) {
85435c4bbdfSmrg        LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be "
85535c4bbdfSmrg                   "non-NULL\n", pScreen->myNum);
85635c4bbdfSmrg        return FALSE;
85705b261ecSmrg    }
85805b261ecSmrg
85905b261ecSmrg    if (!pScreenInfo->WaitMarker) {
86035c4bbdfSmrg        LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be "
86135c4bbdfSmrg                   "non-NULL\n", pScreen->myNum);
86235c4bbdfSmrg        return FALSE;
86305b261ecSmrg    }
86405b261ecSmrg
8654642e01fSmrg    /* If the driver doesn't set any max pitch values, we'll just assume
8664642e01fSmrg     * that there's a limitation by pixels, and that it's the same as
8674642e01fSmrg     * maxX.
8684642e01fSmrg     *
8694642e01fSmrg     * We want maxPitchPixels or maxPitchBytes to be set so we can check
8704642e01fSmrg     * pixmaps against the max pitch in exaCreatePixmap() -- it matters
8714642e01fSmrg     * whether a pixmap is rejected because of its pitch or
8724642e01fSmrg     * because of its width.
8734642e01fSmrg     */
87435c4bbdfSmrg    if (!pScreenInfo->maxPitchPixels && !pScreenInfo->maxPitchBytes) {
8754642e01fSmrg        pScreenInfo->maxPitchPixels = pScreenInfo->maxX;
87605b261ecSmrg    }
87705b261ecSmrg
87805b261ecSmrg    ps = GetPictureScreenIfSet(pScreen);
87905b261ecSmrg
8806747b715Smrg    if (!dixRegisterPrivateKey(&exaScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) {
8816747b715Smrg        LogMessage(X_WARNING, "EXA(%d): Failed to register screen private\n",
88235c4bbdfSmrg                   pScreen->myNum);
88335c4bbdfSmrg        return FALSE;
8846747b715Smrg    }
88505b261ecSmrg
88635c4bbdfSmrg    pExaScr = calloc(sizeof(ExaScreenPrivRec), 1);
88705b261ecSmrg    if (!pExaScr) {
88805b261ecSmrg        LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n",
88935c4bbdfSmrg                   pScreen->myNum);
89035c4bbdfSmrg        return FALSE;
89105b261ecSmrg    }
89205b261ecSmrg
89305b261ecSmrg    pExaScr->info = pScreenInfo;
89405b261ecSmrg
8954642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, exaScreenPrivateKey, pExaScr);
89605b261ecSmrg
89705b261ecSmrg    pExaScr->migration = ExaMigrationAlways;
89805b261ecSmrg
89905b261ecSmrg    exaDDXDriverInit(pScreen);
90005b261ecSmrg
90135c4bbdfSmrg    if (!dixRegisterScreenSpecificPrivateKey
90235c4bbdfSmrg        (pScreen, &pExaScr->gcPrivateKeyRec, PRIVATE_GC, sizeof(ExaGCPrivRec))) {
90335c4bbdfSmrg        LogMessage(X_WARNING, "EXA(%d): Failed to allocate GC private\n",
90435c4bbdfSmrg                   pScreen->myNum);
90535c4bbdfSmrg        return FALSE;
9066747b715Smrg    }
9076747b715Smrg
90805b261ecSmrg    /*
90905b261ecSmrg     * Replace various fb screen functions
91005b261ecSmrg     */
9116747b715Smrg    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
91235c4bbdfSmrg        (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) ||
91335c4bbdfSmrg         (pExaScr->info->flags & EXA_MIXED_PIXMAPS)))
91435c4bbdfSmrg        wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);
9156747b715Smrg    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
91635c4bbdfSmrg        !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS))
91735c4bbdfSmrg        wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler);
9186747b715Smrg    wrap(pExaScr, pScreen, CreateGC, exaCreateGC);
9196747b715Smrg    wrap(pExaScr, pScreen, CloseScreen, exaCloseScreen);
9206747b715Smrg    wrap(pExaScr, pScreen, GetImage, exaGetImage);
9216747b715Smrg    wrap(pExaScr, pScreen, GetSpans, ExaCheckGetSpans);
9226747b715Smrg    wrap(pExaScr, pScreen, CopyWindow, exaCopyWindow);
9236747b715Smrg    wrap(pExaScr, pScreen, ChangeWindowAttributes, exaChangeWindowAttributes);
9246747b715Smrg    wrap(pExaScr, pScreen, BitmapToRegion, exaBitmapToRegion);
9256747b715Smrg    wrap(pExaScr, pScreen, CreateScreenResources, exaCreateScreenResources);
92605b261ecSmrg
92705b261ecSmrg    if (ps) {
92835c4bbdfSmrg        wrap(pExaScr, ps, Composite, exaComposite);
92935c4bbdfSmrg        if (pScreenInfo->PrepareComposite) {
93035c4bbdfSmrg            wrap(pExaScr, ps, Glyphs, exaGlyphs);
93135c4bbdfSmrg        }
93235c4bbdfSmrg        else {
93335c4bbdfSmrg            wrap(pExaScr, ps, Glyphs, ExaCheckGlyphs);
93435c4bbdfSmrg        }
93535c4bbdfSmrg        wrap(pExaScr, ps, Trapezoids, exaTrapezoids);
93635c4bbdfSmrg        wrap(pExaScr, ps, Triangles, exaTriangles);
93735c4bbdfSmrg        wrap(pExaScr, ps, AddTraps, ExaCheckAddTraps);
93805b261ecSmrg    }
93905b261ecSmrg
94005b261ecSmrg#ifdef MITSHM
9414642e01fSmrg    /*
9424642e01fSmrg     * Don't allow shared pixmaps.
94305b261ecSmrg     */
9444642e01fSmrg    ShmRegisterFuncs(pScreen, &exaShmFuncs);
94505b261ecSmrg#endif
94605b261ecSmrg    /*
94705b261ecSmrg     * Hookup offscreen pixmaps
94805b261ecSmrg     */
94935c4bbdfSmrg    if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) {
95035c4bbdfSmrg        if (!dixRegisterScreenSpecificPrivateKey
95135c4bbdfSmrg            (pScreen, &pExaScr->pixmapPrivateKeyRec, PRIVATE_PIXMAP,
95235c4bbdfSmrg             sizeof(ExaPixmapPrivRec))) {
95305b261ecSmrg            LogMessage(X_WARNING,
95435c4bbdfSmrg                       "EXA(%d): Failed to allocate pixmap private\n",
95535c4bbdfSmrg                       pScreen->myNum);
95635c4bbdfSmrg            return FALSE;
95735c4bbdfSmrg        }
95835c4bbdfSmrg        if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) {
95935c4bbdfSmrg            if (pExaScr->info->flags & EXA_MIXED_PIXMAPS) {
96035c4bbdfSmrg                wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_mixed);
96135c4bbdfSmrg                wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed);
96235c4bbdfSmrg                wrap(pExaScr, pScreen, ModifyPixmapHeader,
96335c4bbdfSmrg                     exaModifyPixmapHeader_mixed);
96435c4bbdfSmrg                wrap(pExaScr, pScreen, SharePixmapBacking, exaSharePixmapBacking_mixed);
96535c4bbdfSmrg                wrap(pExaScr, pScreen, SetSharedPixmapBacking, exaSetSharedPixmapBacking_mixed);
96635c4bbdfSmrg
96735c4bbdfSmrg                pExaScr->do_migration = exaDoMigration_mixed;
96835c4bbdfSmrg                pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_mixed;
96935c4bbdfSmrg                pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed;
97035c4bbdfSmrg                pExaScr->do_move_out_pixmap = NULL;
97135c4bbdfSmrg                pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed;
97235c4bbdfSmrg            }
97335c4bbdfSmrg            else {
97435c4bbdfSmrg                wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
97535c4bbdfSmrg                wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
97635c4bbdfSmrg                wrap(pExaScr, pScreen, ModifyPixmapHeader,
97735c4bbdfSmrg                     exaModifyPixmapHeader_driver);
97835c4bbdfSmrg                pExaScr->do_migration = NULL;
97935c4bbdfSmrg                pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_driver;
98035c4bbdfSmrg                pExaScr->do_move_in_pixmap = NULL;
98135c4bbdfSmrg                pExaScr->do_move_out_pixmap = NULL;
98235c4bbdfSmrg                pExaScr->prepare_access_reg = NULL;
98335c4bbdfSmrg            }
98435c4bbdfSmrg        }
98535c4bbdfSmrg        else {
98635c4bbdfSmrg            wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
98735c4bbdfSmrg            wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic);
98835c4bbdfSmrg            wrap(pExaScr, pScreen, ModifyPixmapHeader,
98935c4bbdfSmrg                 exaModifyPixmapHeader_classic);
99035c4bbdfSmrg            pExaScr->do_migration = exaDoMigration_classic;
99135c4bbdfSmrg            pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_classic;
99235c4bbdfSmrg            pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic;
99335c4bbdfSmrg            pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic;
99435c4bbdfSmrg            pExaScr->prepare_access_reg = exaPrepareAccessReg_classic;
99535c4bbdfSmrg        }
99635c4bbdfSmrg        if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
99735c4bbdfSmrg            LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",
99835c4bbdfSmrg                       pScreen->myNum,
99935c4bbdfSmrg                       pExaScr->info->memorySize -
100035c4bbdfSmrg                       pExaScr->info->offScreenBase);
100135c4bbdfSmrg        }
100235c4bbdfSmrg        else {
100335c4bbdfSmrg            LogMessage(X_INFO, "EXA(%d): Driver allocated offscreen pixmaps\n",
100435c4bbdfSmrg                       pScreen->myNum);
100535c4bbdfSmrg
100605b261ecSmrg        }
100705b261ecSmrg    }
100805b261ecSmrg    else
100905b261ecSmrg        LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum);
101005b261ecSmrg
10116747b715Smrg    if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
101235c4bbdfSmrg        DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase,
101335c4bbdfSmrg                    pExaScr->info->memorySize));
101435c4bbdfSmrg        if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
101535c4bbdfSmrg            if (!exaOffscreenInit(pScreen)) {
101635c4bbdfSmrg                LogMessage(X_WARNING,
101735c4bbdfSmrg                           "EXA(%d): Offscreen pixmap setup failed\n",
101835c4bbdfSmrg                           pScreen->myNum);
101935c4bbdfSmrg                return FALSE;
102035c4bbdfSmrg            }
102135c4bbdfSmrg        }
102205b261ecSmrg    }
102305b261ecSmrg
10244642e01fSmrg    if (ps->Glyphs == exaGlyphs)
102535c4bbdfSmrg        exaGlyphsInit(pScreen);
10264642e01fSmrg
102705b261ecSmrg    LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
102835c4bbdfSmrg               " operations:\n", pScreen->myNum);
102905b261ecSmrg    assert(pScreenInfo->PrepareSolid != NULL);
103005b261ecSmrg    LogMessage(X_INFO, "        Solid\n");
103105b261ecSmrg    assert(pScreenInfo->PrepareCopy != NULL);
103205b261ecSmrg    LogMessage(X_INFO, "        Copy\n");
103305b261ecSmrg    if (pScreenInfo->PrepareComposite != NULL) {
103435c4bbdfSmrg        LogMessage(X_INFO, "        Composite (RENDER acceleration)\n");
103505b261ecSmrg    }
103605b261ecSmrg    if (pScreenInfo->UploadToScreen != NULL) {
103735c4bbdfSmrg        LogMessage(X_INFO, "        UploadToScreen\n");
103805b261ecSmrg    }
103905b261ecSmrg    if (pScreenInfo->DownloadFromScreen != NULL) {
104035c4bbdfSmrg        LogMessage(X_INFO, "        DownloadFromScreen\n");
104105b261ecSmrg    }
104205b261ecSmrg
104305b261ecSmrg    return TRUE;
104405b261ecSmrg}
104505b261ecSmrg
104605b261ecSmrg/**
104705b261ecSmrg * exaDriverFini tears down EXA on a given screen.
104805b261ecSmrg *
104905b261ecSmrg * @param pScreen screen being torn down.
105005b261ecSmrg */
105105b261ecSmrgvoid
105235c4bbdfSmrgexaDriverFini(ScreenPtr pScreen)
105305b261ecSmrg{
105435c4bbdfSmrg    /*right now does nothing */
105505b261ecSmrg}
105605b261ecSmrg
105705b261ecSmrg/**
105805b261ecSmrg * exaMarkSync() should be called after any asynchronous drawing by the hardware.
105905b261ecSmrg *
106005b261ecSmrg * @param pScreen screen which drawing occurred on
106105b261ecSmrg *
106205b261ecSmrg * exaMarkSync() sets a flag to indicate that some asynchronous drawing has
106305b261ecSmrg * happened and a WaitSync() will be necessary before relying on the contents of
106405b261ecSmrg * offscreen memory from the CPU's perspective.  It also calls an optional
106505b261ecSmrg * driver MarkSync() callback, the return value of which may be used to do partial
106605b261ecSmrg * synchronization with the hardware in the future.
106705b261ecSmrg */
106835c4bbdfSmrgvoid
106935c4bbdfSmrgexaMarkSync(ScreenPtr pScreen)
107005b261ecSmrg{
107105b261ecSmrg    ExaScreenPriv(pScreen);
107205b261ecSmrg
107305b261ecSmrg    pExaScr->info->needsSync = TRUE;
107405b261ecSmrg    if (pExaScr->info->MarkSync != NULL) {
107535c4bbdfSmrg        pExaScr->info->lastMarker = (*pExaScr->info->MarkSync) (pScreen);
107605b261ecSmrg    }
107705b261ecSmrg}
107805b261ecSmrg
107905b261ecSmrg/**
108005b261ecSmrg * exaWaitSync() ensures that all drawing has been completed.
108105b261ecSmrg *
108205b261ecSmrg * @param pScreen screen being synchronized.
108305b261ecSmrg *
108405b261ecSmrg * Calls down into the driver to ensure that all previous drawing has completed.
108505b261ecSmrg * It should always be called before relying on the framebuffer contents
108605b261ecSmrg * reflecting previous drawing, from a CPU perspective.
108705b261ecSmrg */
108835c4bbdfSmrgvoid
108935c4bbdfSmrgexaWaitSync(ScreenPtr pScreen)
109005b261ecSmrg{
109105b261ecSmrg    ExaScreenPriv(pScreen);
109205b261ecSmrg
109305b261ecSmrg    if (pExaScr->info->needsSync && !pExaScr->swappedOut) {
109435c4bbdfSmrg        (*pExaScr->info->WaitMarker) (pScreen, pExaScr->info->lastMarker);
109505b261ecSmrg        pExaScr->info->needsSync = FALSE;
109605b261ecSmrg    }
109705b261ecSmrg}
10986747b715Smrg
10996747b715Smrg/**
11006747b715Smrg * Performs migration of the pixmaps according to the operation information
11016747b715Smrg * provided in pixmaps and can_accel and the migration scheme chosen in the
11026747b715Smrg * config file.
11036747b715Smrg */
11046747b715Smrgvoid
110535c4bbdfSmrgexaDoMigration(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
11066747b715Smrg{
11076747b715Smrg    ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
110835c4bbdfSmrg
11096747b715Smrg    ExaScreenPriv(pScreen);
11106747b715Smrg
11116747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
111235c4bbdfSmrg        return;
11136747b715Smrg
11146747b715Smrg    if (pExaScr->do_migration)
111535c4bbdfSmrg        (*pExaScr->do_migration) (pixmaps, npixmaps, can_accel);
11166747b715Smrg}
11176747b715Smrg
11186747b715Smrgvoid
111935c4bbdfSmrgexaMoveInPixmap(PixmapPtr pPixmap)
11206747b715Smrg{
11216747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
112235c4bbdfSmrg
11236747b715Smrg    ExaScreenPriv(pScreen);
11246747b715Smrg
11256747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
112635c4bbdfSmrg        return;
11276747b715Smrg
11286747b715Smrg    if (pExaScr->do_move_in_pixmap)
112935c4bbdfSmrg        (*pExaScr->do_move_in_pixmap) (pPixmap);
11306747b715Smrg}
11316747b715Smrg
11326747b715Smrgvoid
113335c4bbdfSmrgexaMoveOutPixmap(PixmapPtr pPixmap)
11346747b715Smrg{
11356747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
113635c4bbdfSmrg
11376747b715Smrg    ExaScreenPriv(pScreen);
11386747b715Smrg
11396747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
114035c4bbdfSmrg        return;
11416747b715Smrg
11426747b715Smrg    if (pExaScr->do_move_out_pixmap)
114335c4bbdfSmrg        (*pExaScr->do_move_out_pixmap) (pPixmap);
11446747b715Smrg}
1145