exa.c revision 8223e2f2
105b261ecSmrg/*
205b261ecSmrg * Copyright � 2001 Keith Packard
305b261ecSmrg *
405b261ecSmrg * 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;
416747b715SmrgDevPrivateKeyRec exaPixmapPrivateKeyRec;
426747b715SmrgDevPrivateKeyRec exaGCPrivateKeyRec;
434642e01fSmrg
444642e01fSmrg#ifdef MITSHM
454642e01fSmrgstatic ShmFuncs exaShmFuncs = { NULL, NULL };
464642e01fSmrg#endif
474642e01fSmrg
4805b261ecSmrg/**
4905b261ecSmrg * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
5005b261ecSmrg * the beginning of the given pixmap.
5105b261ecSmrg *
5205b261ecSmrg * Note that drivers are free to, and often do, munge this offset as necessary
5305b261ecSmrg * for handing to the hardware -- for example, translating it into a different
5405b261ecSmrg * aperture.  This function may need to be extended in the future if we grow
5505b261ecSmrg * support for having multiple card-accessible offscreen, such as an AGP memory
5605b261ecSmrg * pool alongside the framebuffer pool.
5705b261ecSmrg */
5805b261ecSmrgunsigned long
5905b261ecSmrgexaGetPixmapOffset(PixmapPtr pPix)
6005b261ecSmrg{
6105b261ecSmrg    ExaScreenPriv (pPix->drawable.pScreen);
626747b715Smrg    ExaPixmapPriv (pPix);
6305b261ecSmrg
646747b715Smrg    return (CARD8 *)pExaPixmap->fb_ptr - pExaScr->info->memoryBase;
654642e01fSmrg}
6605b261ecSmrg
674642e01fSmrgvoid *
684642e01fSmrgexaGetPixmapDriverPrivate(PixmapPtr pPix)
694642e01fSmrg{
704642e01fSmrg    ExaPixmapPriv(pPix);
714642e01fSmrg
724642e01fSmrg    return pExaPixmap->driverPriv;
7305b261ecSmrg}
7405b261ecSmrg
7505b261ecSmrg/**
7605b261ecSmrg * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap.
7705b261ecSmrg *
7805b261ecSmrg * This is a helper to make driver code more obvious, due to the rather obscure
7905b261ecSmrg * naming of the pitch field in the pixmap.
8005b261ecSmrg */
8105b261ecSmrgunsigned long
8205b261ecSmrgexaGetPixmapPitch(PixmapPtr pPix)
8305b261ecSmrg{
8405b261ecSmrg    return pPix->devKind;
8505b261ecSmrg}
8605b261ecSmrg
8705b261ecSmrg/**
8805b261ecSmrg * exaGetPixmapSize() returns the size in bytes of the given pixmap in video
8905b261ecSmrg * memory. Only valid when the pixmap is currently in framebuffer.
9005b261ecSmrg */
9105b261ecSmrgunsigned long
9205b261ecSmrgexaGetPixmapSize(PixmapPtr pPix)
9305b261ecSmrg{
9405b261ecSmrg    ExaPixmapPrivPtr pExaPixmap;
9505b261ecSmrg
9605b261ecSmrg    pExaPixmap = ExaGetPixmapPriv(pPix);
9705b261ecSmrg    if (pExaPixmap != NULL)
9805b261ecSmrg	return pExaPixmap->fb_size;
9905b261ecSmrg    return 0;
10005b261ecSmrg}
10105b261ecSmrg
10205b261ecSmrg/**
10305b261ecSmrg * exaGetDrawablePixmap() returns a backing pixmap for a given drawable.
10405b261ecSmrg *
10505b261ecSmrg * @param pDrawable the drawable being requested.
10605b261ecSmrg *
10705b261ecSmrg * This function returns the backing pixmap for a drawable, whether it is a
10805b261ecSmrg * redirected window, unredirected window, or already a pixmap.  Note that
10905b261ecSmrg * coordinate translation is needed when drawing to the backing pixmap of a
11005b261ecSmrg * redirected window, and the translation coordinates are provided by calling
11105b261ecSmrg * exaGetOffscreenPixmap() on the drawable.
11205b261ecSmrg */
11305b261ecSmrgPixmapPtr
11405b261ecSmrgexaGetDrawablePixmap(DrawablePtr pDrawable)
11505b261ecSmrg{
11605b261ecSmrg     if (pDrawable->type == DRAWABLE_WINDOW)
11705b261ecSmrg	return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
11805b261ecSmrg     else
11905b261ecSmrg	return (PixmapPtr) pDrawable;
1206747b715Smrg}
12105b261ecSmrg
12205b261ecSmrg/**
12305b261ecSmrg * Sets the offsets to add to coordinates to make them address the same bits in
12405b261ecSmrg * the backing drawable. These coordinates are nonzero only for redirected
12505b261ecSmrg * windows.
12605b261ecSmrg */
12705b261ecSmrgvoid
12805b261ecSmrgexaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
12905b261ecSmrg		      int *xp, int *yp)
13005b261ecSmrg{
13105b261ecSmrg#ifdef COMPOSITE
13205b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
13305b261ecSmrg	*xp = -pPixmap->screen_x;
13405b261ecSmrg	*yp = -pPixmap->screen_y;
13505b261ecSmrg	return;
13605b261ecSmrg    }
13705b261ecSmrg#endif
13805b261ecSmrg
13905b261ecSmrg    *xp = 0;
14005b261ecSmrg    *yp = 0;
14105b261ecSmrg}
14205b261ecSmrg
14305b261ecSmrg/**
14405b261ecSmrg * exaPixmapDirty() marks a pixmap as dirty, allowing for
14505b261ecSmrg * optimizations in pixmap migration when no changes have occurred.
14605b261ecSmrg */
14705b261ecSmrgvoid
14805b261ecSmrgexaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
14905b261ecSmrg{
15005b261ecSmrg    BoxRec box;
15105b261ecSmrg    RegionRec region;
15205b261ecSmrg
15305b261ecSmrg    box.x1 = max(x1, 0);
15405b261ecSmrg    box.y1 = max(y1, 0);
15505b261ecSmrg    box.x2 = min(x2, pPix->drawable.width);
15605b261ecSmrg    box.y2 = min(y2, pPix->drawable.height);
15705b261ecSmrg
15805b261ecSmrg    if (box.x1 >= box.x2 || box.y1 >= box.y2)
15905b261ecSmrg	return;
16005b261ecSmrg
1616747b715Smrg    RegionInit(&region, &box, 1);
1628223e2f2Smrg    DamageDamageRegion(&pPix->drawable, &region);
1636747b715Smrg    RegionUninit(&region);
16405b261ecSmrg}
16505b261ecSmrg
16605b261ecSmrgstatic int
16705b261ecSmrgexaLog2(int val)
16805b261ecSmrg{
16905b261ecSmrg    int bits;
17005b261ecSmrg
17105b261ecSmrg    if (val <= 0)
17205b261ecSmrg	return 0;
17305b261ecSmrg    for (bits = 0; val != 0; bits++)
17405b261ecSmrg	val >>= 1;
17505b261ecSmrg    return bits - 1;
17605b261ecSmrg}
17705b261ecSmrg
1786747b715Smrgvoid
1794642e01fSmrgexaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
1804642e01fSmrg                 int w, int h, int bpp)
1814642e01fSmrg{
1824642e01fSmrg    pExaPixmap->accel_blocked = 0;
1834642e01fSmrg
1844642e01fSmrg    if (pExaScr->info->maxPitchPixels) {
1856747b715Smrg        int max_pitch = pExaScr->info->maxPitchPixels * bits_to_bytes(bpp);
1864642e01fSmrg
1874642e01fSmrg        if (pExaPixmap->fb_pitch > max_pitch)
1884642e01fSmrg            pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;
1894642e01fSmrg    }
1904642e01fSmrg
1914642e01fSmrg    if (pExaScr->info->maxPitchBytes &&
1924642e01fSmrg        pExaPixmap->fb_pitch > pExaScr->info->maxPitchBytes)
1934642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;
1944642e01fSmrg
1954642e01fSmrg    if (w > pExaScr->info->maxX)
1964642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_WIDTH;
1974642e01fSmrg
1984642e01fSmrg    if (h > pExaScr->info->maxY)
1994642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT;
2004642e01fSmrg}
2014642e01fSmrg
2026747b715Smrgvoid
2034642e01fSmrgexaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
2044642e01fSmrg              int w, int h, int bpp)
2054642e01fSmrg{
2064642e01fSmrg    if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
2076747b715Smrg        pExaPixmap->fb_pitch = bits_to_bytes((1 << (exaLog2(w - 1) + 1)) * bpp);
2084642e01fSmrg    else
2096747b715Smrg        pExaPixmap->fb_pitch = bits_to_bytes(w * bpp);
2104642e01fSmrg
2114642e01fSmrg    pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
2124642e01fSmrg                                     pExaScr->info->pixmapPitchAlign);
2134642e01fSmrg}
2144642e01fSmrg
21505b261ecSmrg/**
2166747b715Smrg * Returns TRUE if the pixmap is not movable.  This is the case where it's a
2176747b715Smrg * pixmap which has no private (almost always bad) or it's a scratch pixmap created by
2186747b715Smrg * some X Server internal component (the score says it's pinned).
21905b261ecSmrg */
2206747b715SmrgBool
2216747b715SmrgexaPixmapIsPinned (PixmapPtr pPix)
22205b261ecSmrg{
2236747b715Smrg    ExaPixmapPriv (pPix);
22405b261ecSmrg
2256747b715Smrg    if (pExaPixmap == NULL)
2266747b715Smrg	EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE);
22705b261ecSmrg
2286747b715Smrg    return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
2294642e01fSmrg}
2304642e01fSmrg
23105b261ecSmrg/**
2326747b715Smrg * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen
23305b261ecSmrg * memory, meaning that acceleration could probably be done to it, and that it
23405b261ecSmrg * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
23505b261ecSmrg * with the CPU.
23605b261ecSmrg *
23705b261ecSmrg * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
23805b261ecSmrg * deal with moving pixmaps in and out of system memory), EXA will give drivers
2396747b715Smrg * pixmaps as arguments for which exaPixmapHasGpuCopy() is TRUE.
24005b261ecSmrg *
24105b261ecSmrg * @return TRUE if the given drawable is in framebuffer memory.
24205b261ecSmrg */
24305b261ecSmrgBool
2446747b715SmrgexaPixmapHasGpuCopy(PixmapPtr pPixmap)
24505b261ecSmrg{
2466747b715Smrg    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
24705b261ecSmrg    ExaScreenPriv(pScreen);
24805b261ecSmrg
2496747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
2506747b715Smrg	return FALSE;
2514642e01fSmrg
2526747b715Smrg    return (*pExaScr->pixmap_has_gpu_copy)(pPixmap);
25305b261ecSmrg}
25405b261ecSmrg
25505b261ecSmrg/**
2566747b715Smrg * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapHasGpuCopy().
25705b261ecSmrg */
25805b261ecSmrgBool
25905b261ecSmrgexaDrawableIsOffscreen (DrawablePtr pDrawable)
26005b261ecSmrg{
2616747b715Smrg    return exaPixmapHasGpuCopy (exaGetDrawablePixmap (pDrawable));
26205b261ecSmrg}
26305b261ecSmrg
26405b261ecSmrg/**
26505b261ecSmrg * Returns the pixmap which backs a drawable, and the offsets to add to
26605b261ecSmrg * coordinates to make them address the same bits in the backing drawable.
26705b261ecSmrg */
26805b261ecSmrgPixmapPtr
26905b261ecSmrgexaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
27005b261ecSmrg{
27105b261ecSmrg    PixmapPtr	pPixmap = exaGetDrawablePixmap (pDrawable);
27205b261ecSmrg
27305b261ecSmrg    exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp);
27405b261ecSmrg
2756747b715Smrg    if (exaPixmapHasGpuCopy (pPixmap))
27605b261ecSmrg	return pPixmap;
27705b261ecSmrg    else
27805b261ecSmrg	return NULL;
27905b261ecSmrg}
28005b261ecSmrg
2816747b715Smrg/**
2826747b715Smrg * Returns TRUE if the pixmap GPU copy is being accessed.
2836747b715Smrg */
2846747b715SmrgBool
2856747b715SmrgExaDoPrepareAccess(PixmapPtr pPixmap, int index)
28605b261ecSmrg{
2876747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
2886747b715Smrg    ExaScreenPriv (pScreen);
2896747b715Smrg    ExaPixmapPriv(pPixmap);
2906747b715Smrg    Bool has_gpu_copy, ret;
2916747b715Smrg    int i;
29205b261ecSmrg
2936747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
2946747b715Smrg	return FALSE;
2956747b715Smrg
2966747b715Smrg    if (pExaPixmap == NULL)
2976747b715Smrg	EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE);
2986747b715Smrg
2996747b715Smrg    /* Handle repeated / nested calls. */
3006747b715Smrg    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
3016747b715Smrg	if (pExaScr->access[i].pixmap == pPixmap) {
3026747b715Smrg	    pExaScr->access[i].count++;
3036747b715Smrg	    return pExaScr->access[i].retval;
3046747b715Smrg	}
3054642e01fSmrg    }
30605b261ecSmrg
3076747b715Smrg    /* If slot for this index is taken, find an empty slot */
3086747b715Smrg    if (pExaScr->access[index].pixmap) {
3096747b715Smrg	for (index = EXA_NUM_PREPARE_INDICES - 1; index >= 0; index--)
3106747b715Smrg	    if (!pExaScr->access[index].pixmap)
3116747b715Smrg		break;
3126747b715Smrg    }
3136747b715Smrg
3146747b715Smrg    /* Access to this pixmap hasn't been prepared yet, so data pointer should be NULL. */
3156747b715Smrg    if (pPixmap->devPrivate.ptr != NULL) {
3166747b715Smrg	EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n",
3176747b715Smrg			     pPixmap->devPrivate.ptr));
3186747b715Smrg    }
3196747b715Smrg
3206747b715Smrg    has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
3216747b715Smrg
3226747b715Smrg    if (has_gpu_copy && pExaPixmap->fb_ptr) {
3236747b715Smrg	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
3246747b715Smrg	ret = TRUE;
3256747b715Smrg    } else {
3266747b715Smrg	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
3276747b715Smrg	ret = FALSE;
3286747b715Smrg    }
3296747b715Smrg
3306747b715Smrg    /* Store so we can handle repeated / nested calls. */
3316747b715Smrg    pExaScr->access[index].pixmap = pPixmap;
3326747b715Smrg    pExaScr->access[index].count = 1;
3336747b715Smrg
3346747b715Smrg    if (!has_gpu_copy)
3356747b715Smrg	goto out;
33605b261ecSmrg
3376747b715Smrg    exaWaitSync (pScreen);
33805b261ecSmrg
33905b261ecSmrg    if (pExaScr->info->PrepareAccess == NULL)
3406747b715Smrg	goto out;
34105b261ecSmrg
3426747b715Smrg    if (index >= EXA_PREPARE_AUX_DEST &&
3434642e01fSmrg	!(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
3446747b715Smrg	if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
3456747b715Smrg	    FatalError("Unsupported AUX indices used on a pinned pixmap.\n");
3464642e01fSmrg	exaMoveOutPixmap (pPixmap);
3476747b715Smrg	ret = FALSE;
3486747b715Smrg	goto out;
3494642e01fSmrg    }
3504642e01fSmrg
35105b261ecSmrg    if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
3526747b715Smrg	if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED &&
3536747b715Smrg	    !(pExaScr->info->flags & EXA_MIXED_PIXMAPS))
3546747b715Smrg	    FatalError("Driver failed PrepareAccess on a pinned pixmap.\n");
35505b261ecSmrg	exaMoveOutPixmap (pPixmap);
3566747b715Smrg	ret = FALSE;
3576747b715Smrg	goto out;
35805b261ecSmrg    }
3594642e01fSmrg
3606747b715Smrg    ret = TRUE;
3614642e01fSmrg
3626747b715Smrgout:
3636747b715Smrg    pExaScr->access[index].retval = ret;
3646747b715Smrg    return ret;
3654642e01fSmrg}
3664642e01fSmrg
3674642e01fSmrg/**
3684642e01fSmrg * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
3694642e01fSmrg *
3704642e01fSmrg * It deals with waiting for synchronization with the card, determining if
3714642e01fSmrg * PrepareAccess() is necessary, and working around PrepareAccess() failure.
3724642e01fSmrg */
3734642e01fSmrgvoid
3744642e01fSmrgexaPrepareAccess(DrawablePtr pDrawable, int index)
3754642e01fSmrg{
3766747b715Smrg    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
3776747b715Smrg    ExaScreenPriv(pDrawable->pScreen);
3786747b715Smrg
3796747b715Smrg    if (pExaScr->prepare_access_reg)
3806747b715Smrg	pExaScr->prepare_access_reg(pPixmap, index, NULL);
3816747b715Smrg    else
3826747b715Smrg	(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{
39305b261ecSmrg    ScreenPtr	    pScreen = pDrawable->pScreen;
39405b261ecSmrg    ExaScreenPriv  (pScreen);
3954642e01fSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
3964642e01fSmrg    ExaPixmapPriv  (pPixmap);
3976747b715Smrg    int i;
3986747b715Smrg
3996747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
4006747b715Smrg	return;
40105b261ecSmrg
4026747b715Smrg    if (pExaPixmap == NULL)
4036747b715Smrg	EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),);
4046747b715Smrg
4056747b715Smrg    /* Handle repeated / nested calls. */
4066747b715Smrg    for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
4076747b715Smrg	if (pExaScr->access[i].pixmap == pPixmap) {
4086747b715Smrg	    if (--pExaScr->access[i].count > 0)
4096747b715Smrg		return;
4106747b715Smrg	    break;
4116747b715Smrg	}
41205b261ecSmrg    }
41305b261ecSmrg
4146747b715Smrg    /* Catch unbalanced Prepare/FinishAccess calls. */
4156747b715Smrg    if (i == EXA_NUM_PREPARE_INDICES)
4166747b715Smrg      EXA_FatalErrorDebugWithRet(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n",
4176747b715Smrg				  pPixmap),);
4186747b715Smrg
4196747b715Smrg    pExaScr->access[i].pixmap = NULL;
42005b261ecSmrg
4216747b715Smrg    /* We always hide the devPrivate.ptr. */
4226747b715Smrg    pPixmap->devPrivate.ptr = NULL;
4236747b715Smrg
4248223e2f2Smrg    /* Only call FinishAccess if PrepareAccess was called and succeeded. */
4258223e2f2Smrg    if (!pExaScr->info->FinishAccess || !pExaScr->access[i].retval)
42605b261ecSmrg	return;
42705b261ecSmrg
4286747b715Smrg    if (i >= EXA_PREPARE_AUX_DEST &&
4294642e01fSmrg	!(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
4304642e01fSmrg	ErrorF("EXA bug: Trying to call driver FinishAccess hook with "
4314642e01fSmrg	       "unsupported index EXA_PREPARE_AUX*\n");
4324642e01fSmrg	return;
4334642e01fSmrg    }
4344642e01fSmrg
4356747b715Smrg    (*pExaScr->info->FinishAccess) (pPixmap, i);
43605b261ecSmrg}
43705b261ecSmrg
4386747b715Smrg
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++) {
4526747b715Smrg	if (pExaScr->access[i].pixmap == pPixmap) {
4536747b715Smrg	    exaFinishAccess(&pPixmap->drawable, i);
4546747b715Smrg	    pExaScr->access[i].pixmap = NULL;
4556747b715Smrg	    break;
45605b261ecSmrg	}
45705b261ecSmrg    }
4586747b715Smrg}
4596747b715Smrg
4606747b715Smrg
4616747b715Smrg/**
4626747b715Smrg * Here begins EXA's GC code.
4636747b715Smrg * Do not ever access the fb/mi layer directly.
4646747b715Smrg */
4656747b715Smrg
4666747b715Smrgstatic void
4676747b715SmrgexaValidateGC(GCPtr pGC,
4686747b715Smrg		unsigned long changes,
4696747b715Smrg		DrawablePtr pDrawable);
4706747b715Smrg
4716747b715Smrgstatic void
4726747b715SmrgexaDestroyGC(GCPtr pGC);
4736747b715Smrg
4746747b715Smrgstatic void
4756747b715SmrgexaChangeGC (GCPtr pGC,
4766747b715Smrg		unsigned long mask);
4776747b715Smrg
4786747b715Smrgstatic void
4796747b715SmrgexaCopyGC (GCPtr pGCSrc,
4806747b715Smrg	      unsigned long mask,
4816747b715Smrg	      GCPtr	 pGCDst);
4826747b715Smrg
4836747b715Smrgstatic void
4846747b715SmrgexaChangeClip (GCPtr pGC,
4856747b715Smrg		int type,
4866747b715Smrg		pointer pvalue,
4876747b715Smrg		int nrects);
4886747b715Smrg
4896747b715Smrgstatic void
4906747b715SmrgexaCopyClip(GCPtr pGCDst, GCPtr pGCSrc);
4916747b715Smrg
4926747b715Smrgstatic void
4936747b715SmrgexaCopyClip(GCPtr pGCDst, GCPtr pGCSrc);
4946747b715Smrg
4956747b715Smrgstatic void
4966747b715SmrgexaDestroyClip(GCPtr pGC);
4976747b715Smrg
4986747b715Smrgconst GCFuncs exaGCFuncs = {
4996747b715Smrg    exaValidateGC,
5006747b715Smrg    exaChangeGC,
5016747b715Smrg    exaCopyGC,
5026747b715Smrg    exaDestroyGC,
5036747b715Smrg    exaChangeClip,
5046747b715Smrg    exaDestroyClip,
5056747b715Smrg    exaCopyClip
5066747b715Smrg};
5076747b715Smrg
5086747b715Smrgstatic void
5096747b715SmrgexaValidateGC(GCPtr pGC,
5106747b715Smrg		unsigned long changes,
5116747b715Smrg		DrawablePtr pDrawable)
5126747b715Smrg{
5136747b715Smrg    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
5146747b715Smrg     * Do a few smart things so fbValidateGC can do it's work.
5156747b715Smrg     */
5166747b715Smrg
5176747b715Smrg    ScreenPtr pScreen = pDrawable->pScreen;
5186747b715Smrg    ExaScreenPriv(pScreen);
5196747b715Smrg    ExaGCPriv(pGC);
5206747b715Smrg    PixmapPtr pTile = NULL;
5216747b715Smrg    Bool finish_current_tile = FALSE;
5226747b715Smrg
5236747b715Smrg    /* Either of these conditions is enough to trigger access to a tile pixmap. */
5246747b715Smrg    /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */
5256747b715Smrg    if (pGC->fillStyle == FillTiled || ((changes & GCTile) && !pGC->tileIsPixel)) {
5266747b715Smrg	pTile = pGC->tile.pixmap;
5276747b715Smrg
5286747b715Smrg	/* Sometimes tile pixmaps are swapped, you need access to:
5296747b715Smrg	 * - The current tile if it depth matches.
5306747b715Smrg	 * - Or the rotated tile if that one matches depth and !(changes & GCTile).
5316747b715Smrg	 * - Or the current tile pixmap and a newly created one.
53205b261ecSmrg	 */
5336747b715Smrg	if (pTile && pTile->drawable.depth != pDrawable->depth && !(changes & GCTile)) {
5346747b715Smrg	    PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC);
5356747b715Smrg	    if (pRotatedTile && pRotatedTile->drawable.depth == pDrawable->depth)
5366747b715Smrg		pTile = pRotatedTile;
5376747b715Smrg	    else
5386747b715Smrg		finish_current_tile = TRUE; /* CreatePixmap will be called. */
5396747b715Smrg	}
54005b261ecSmrg    }
54105b261ecSmrg
5426747b715Smrg    if (pGC->stipple)
5436747b715Smrg        exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
5446747b715Smrg    if (pTile)
5456747b715Smrg	exaPrepareAccess(&pTile->drawable, EXA_PREPARE_SRC);
5466747b715Smrg
5476747b715Smrg    /* Calls to Create/DestroyPixmap have to be identified as special. */
5486747b715Smrg    pExaScr->fallback_counter++;
5496747b715Smrg    swap(pExaGC, pGC, funcs);
5506747b715Smrg    (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
5516747b715Smrg    swap(pExaGC, pGC, funcs);
5526747b715Smrg    pExaScr->fallback_counter--;
5536747b715Smrg
5546747b715Smrg    if (pTile)
5556747b715Smrg	exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC);
5566747b715Smrg    if (finish_current_tile && pGC->tile.pixmap)
5576747b715Smrg	exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_AUX_DEST);
5586747b715Smrg    if (pGC->stipple)
5596747b715Smrg	exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
5606747b715Smrg}
5616747b715Smrg
5626747b715Smrg/* Is exaPrepareAccessGC() needed? */
5636747b715Smrgstatic void
5646747b715SmrgexaDestroyGC(GCPtr pGC)
5656747b715Smrg{
5666747b715Smrg    ExaGCPriv(pGC);
5676747b715Smrg    swap(pExaGC, pGC, funcs);
5686747b715Smrg    (*pGC->funcs->DestroyGC)(pGC);
5696747b715Smrg    swap(pExaGC, pGC, funcs);
5706747b715Smrg}
57105b261ecSmrg
5726747b715Smrgstatic void
5736747b715SmrgexaChangeGC (GCPtr pGC,
5746747b715Smrg		unsigned long mask)
5756747b715Smrg{
5766747b715Smrg    ExaGCPriv(pGC);
5776747b715Smrg    swap(pExaGC, pGC, funcs);
5786747b715Smrg    (*pGC->funcs->ChangeGC) (pGC, mask);
5796747b715Smrg    swap(pExaGC, pGC, funcs);
58005b261ecSmrg}
58105b261ecSmrg
5826747b715Smrgstatic void
5836747b715SmrgexaCopyGC (GCPtr pGCSrc,
5846747b715Smrg	      unsigned long mask,
5856747b715Smrg	      GCPtr	 pGCDst)
5866747b715Smrg{
5876747b715Smrg    ExaGCPriv(pGCDst);
5886747b715Smrg    swap(pExaGC, pGCDst, funcs);
5896747b715Smrg    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
5906747b715Smrg    swap(pExaGC, pGCDst, funcs);
5916747b715Smrg}
5926747b715Smrg
5936747b715Smrgstatic void
5946747b715SmrgexaChangeClip (GCPtr pGC,
5956747b715Smrg		int type,
5966747b715Smrg		pointer pvalue,
5976747b715Smrg		int nrects)
5986747b715Smrg{
5996747b715Smrg    ExaGCPriv(pGC);
6006747b715Smrg    swap(pExaGC, pGC, funcs);
6016747b715Smrg    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
6026747b715Smrg    swap(pExaGC, pGC, funcs);
6036747b715Smrg}
6046747b715Smrg
6056747b715Smrgstatic void
6066747b715SmrgexaCopyClip(GCPtr pGCDst, GCPtr pGCSrc)
6076747b715Smrg{
6086747b715Smrg    ExaGCPriv(pGCDst);
6096747b715Smrg    swap(pExaGC, pGCDst, funcs);
6106747b715Smrg    (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc);
6116747b715Smrg    swap(pExaGC, pGCDst, funcs);
6126747b715Smrg}
6136747b715Smrg
6146747b715Smrgstatic void
6156747b715SmrgexaDestroyClip(GCPtr pGC)
6166747b715Smrg{
6176747b715Smrg    ExaGCPriv(pGC);
6186747b715Smrg    swap(pExaGC, pGC, funcs);
6196747b715Smrg    (*pGC->funcs->DestroyClip)(pGC);
6206747b715Smrg    swap(pExaGC, pGC, funcs);
6216747b715Smrg}
62205b261ecSmrg
62305b261ecSmrg/**
62405b261ecSmrg * exaCreateGC makes a new GC and hooks up its funcs handler, so that
62505b261ecSmrg * exaValidateGC() will get called.
62605b261ecSmrg */
62705b261ecSmrgstatic int
62805b261ecSmrgexaCreateGC (GCPtr pGC)
62905b261ecSmrg{
6306747b715Smrg    ScreenPtr pScreen = pGC->pScreen;
6316747b715Smrg    ExaScreenPriv(pScreen);
6326747b715Smrg    ExaGCPriv(pGC);
6336747b715Smrg    Bool ret;
63405b261ecSmrg
6356747b715Smrg    swap(pExaScr, pScreen, CreateGC);
6366747b715Smrg    if ((ret = (*pScreen->CreateGC) (pGC))) {
6376747b715Smrg	wrap(pExaGC, pGC, funcs, (GCFuncs *) &exaGCFuncs);
6386747b715Smrg	wrap(pExaGC, pGC, ops, (GCOps *) &exaOps);
6396747b715Smrg    }
6406747b715Smrg    swap(pExaScr, pScreen, CreateGC);
64105b261ecSmrg
6426747b715Smrg    return ret;
64305b261ecSmrg}
64405b261ecSmrg
6454642e01fSmrgstatic Bool
6464642e01fSmrgexaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
6474642e01fSmrg{
6484642e01fSmrg    Bool ret;
6496747b715Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
6506747b715Smrg    ExaScreenPriv(pScreen);
6514642e01fSmrg
6524642e01fSmrg    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
6536747b715Smrg	exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
6544642e01fSmrg
6554642e01fSmrg    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
6566747b715Smrg	exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
6574642e01fSmrg
6586747b715Smrg    pExaScr->fallback_counter++;
6596747b715Smrg    swap(pExaScr, pScreen, ChangeWindowAttributes);
6606747b715Smrg    ret = pScreen->ChangeWindowAttributes(pWin, mask);
6616747b715Smrg    swap(pExaScr, pScreen, ChangeWindowAttributes);
6626747b715Smrg    pExaScr->fallback_counter--;
6634642e01fSmrg
6644642e01fSmrg    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
6656747b715Smrg	exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
6666747b715Smrg    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
6676747b715Smrg	exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
6684642e01fSmrg
6694642e01fSmrg    return ret;
6704642e01fSmrg}
6714642e01fSmrg
6724642e01fSmrgstatic RegionPtr
6734642e01fSmrgexaBitmapToRegion(PixmapPtr pPix)
6744642e01fSmrg{
6756747b715Smrg    RegionPtr ret;
6766747b715Smrg    ScreenPtr pScreen = pPix->drawable.pScreen;
6776747b715Smrg    ExaScreenPriv(pScreen);
6786747b715Smrg
6796747b715Smrg    exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC);
6806747b715Smrg    swap(pExaScr, pScreen, BitmapToRegion);
6816747b715Smrg    ret = (*pScreen->BitmapToRegion)(pPix);
6826747b715Smrg    swap(pExaScr, pScreen, BitmapToRegion);
6836747b715Smrg    exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC);
6846747b715Smrg
6856747b715Smrg    return ret;
6864642e01fSmrg}
6874642e01fSmrg
6884642e01fSmrgstatic Bool
6894642e01fSmrgexaCreateScreenResources(ScreenPtr pScreen)
6904642e01fSmrg{
6914642e01fSmrg    ExaScreenPriv(pScreen);
6924642e01fSmrg    PixmapPtr pScreenPixmap;
6934642e01fSmrg    Bool b;
6944642e01fSmrg
6956747b715Smrg    swap(pExaScr, pScreen, CreateScreenResources);
6964642e01fSmrg    b = pScreen->CreateScreenResources(pScreen);
6976747b715Smrg    swap(pExaScr, pScreen, CreateScreenResources);
6984642e01fSmrg
6994642e01fSmrg    if (!b)
7004642e01fSmrg        return FALSE;
7014642e01fSmrg
7024642e01fSmrg    pScreenPixmap = pScreen->GetScreenPixmap(pScreen);
7034642e01fSmrg
7044642e01fSmrg    if (pScreenPixmap) {
7054642e01fSmrg        ExaPixmapPriv(pScreenPixmap);
7064642e01fSmrg
7074642e01fSmrg        exaSetAccelBlock(pExaScr, pExaPixmap,
7084642e01fSmrg                         pScreenPixmap->drawable.width,
7094642e01fSmrg                         pScreenPixmap->drawable.height,
7104642e01fSmrg                         pScreenPixmap->drawable.bitsPerPixel);
7114642e01fSmrg    }
7124642e01fSmrg
7134642e01fSmrg    return TRUE;
7144642e01fSmrg}
7154642e01fSmrg
7166747b715Smrgstatic void
7176747b715SmrgExaBlockHandler(int screenNum, pointer blockData, pointer pTimeout,
7186747b715Smrg		pointer pReadmask)
7196747b715Smrg{
7206747b715Smrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
7216747b715Smrg    ExaScreenPriv(pScreen);
7226747b715Smrg
7236747b715Smrg    /* Move any deferred results from a software fallback to the driver pixmap */
7246747b715Smrg    if (pExaScr->deferred_mixed_pixmap)
7256747b715Smrg	exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
7266747b715Smrg
7276747b715Smrg    unwrap(pExaScr, pScreen, BlockHandler);
7286747b715Smrg    (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
7296747b715Smrg    wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);
7306747b715Smrg
7316747b715Smrg    /* The rest only applies to classic EXA */
7326747b715Smrg    if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
7336747b715Smrg	return;
7346747b715Smrg
7356747b715Smrg    /* Try and keep the offscreen memory area tidy every now and then (at most
7366747b715Smrg     * once per second) when the server has been idle for at least 100ms.
7376747b715Smrg     */
7386747b715Smrg    if (pExaScr->numOffscreenAvailable > 1) {
7396747b715Smrg	CARD32 now = GetTimeInMillis();
7406747b715Smrg
7416747b715Smrg	pExaScr->nextDefragment = now +
7426747b715Smrg	    max(100, (INT32)(pExaScr->lastDefragment + 1000 - now));
7436747b715Smrg	AdjustWaitForDelay(pTimeout, pExaScr->nextDefragment - now);
7446747b715Smrg    }
7456747b715Smrg}
7466747b715Smrg
7476747b715Smrgstatic void
7486747b715SmrgExaWakeupHandler(int screenNum, pointer wakeupData, unsigned long result,
7496747b715Smrg		 pointer pReadmask)
7506747b715Smrg{
7516747b715Smrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
7526747b715Smrg    ExaScreenPriv(pScreen);
7536747b715Smrg
7546747b715Smrg    unwrap(pExaScr, pScreen, WakeupHandler);
7556747b715Smrg    (*pScreen->WakeupHandler) (screenNum, wakeupData, result, pReadmask);
7566747b715Smrg    wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler);
7576747b715Smrg
7586747b715Smrg    if (result == 0 && pExaScr->numOffscreenAvailable > 1) {
7596747b715Smrg	CARD32 now = GetTimeInMillis();
7606747b715Smrg
7616747b715Smrg	if ((int)(now - pExaScr->nextDefragment) > 0) {
7626747b715Smrg	    ExaOffscreenDefragment(pScreen);
7636747b715Smrg	    pExaScr->lastDefragment = now;
7646747b715Smrg	}
7656747b715Smrg    }
7666747b715Smrg}
7676747b715Smrg
76805b261ecSmrg/**
76905b261ecSmrg * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's
77005b261ecSmrg * screen private, before calling down to the next CloseSccreen.
77105b261ecSmrg */
77205b261ecSmrgstatic Bool
77305b261ecSmrgexaCloseScreen(int i, ScreenPtr pScreen)
77405b261ecSmrg{
77505b261ecSmrg    ExaScreenPriv(pScreen);
77605b261ecSmrg    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
77705b261ecSmrg
7784642e01fSmrg    if (ps->Glyphs == exaGlyphs)
7794642e01fSmrg	exaGlyphsFini(pScreen);
7804642e01fSmrg
7816747b715Smrg    if (pScreen->BlockHandler == ExaBlockHandler)
7826747b715Smrg	unwrap(pExaScr, pScreen, BlockHandler);
7836747b715Smrg    if (pScreen->WakeupHandler == ExaWakeupHandler)
7846747b715Smrg	unwrap(pExaScr, pScreen, WakeupHandler);
7856747b715Smrg    unwrap(pExaScr, pScreen, CreateGC);
7866747b715Smrg    unwrap(pExaScr, pScreen, CloseScreen);
7876747b715Smrg    unwrap(pExaScr, pScreen, GetImage);
7886747b715Smrg    unwrap(pExaScr, pScreen, GetSpans);
7896747b715Smrg    if (pExaScr->SavedCreatePixmap)
7906747b715Smrg	unwrap(pExaScr, pScreen, CreatePixmap);
7916747b715Smrg    if (pExaScr->SavedDestroyPixmap)
7926747b715Smrg	unwrap(pExaScr, pScreen, DestroyPixmap);
7936747b715Smrg    if (pExaScr->SavedModifyPixmapHeader)
7946747b715Smrg	unwrap(pExaScr, pScreen, ModifyPixmapHeader);
7956747b715Smrg    unwrap(pExaScr, pScreen, CopyWindow);
7966747b715Smrg    unwrap(pExaScr, pScreen, ChangeWindowAttributes);
7976747b715Smrg    unwrap(pExaScr, pScreen, BitmapToRegion);
7986747b715Smrg    unwrap(pExaScr, pScreen, CreateScreenResources);
7996747b715Smrg    unwrap(pExaScr, ps, Composite);
8006747b715Smrg    if (pExaScr->SavedGlyphs)
8016747b715Smrg	unwrap(pExaScr, ps, Glyphs);
8026747b715Smrg    unwrap(pExaScr, ps, Trapezoids);
8036747b715Smrg    unwrap(pExaScr, ps, Triangles);
8046747b715Smrg    unwrap(pExaScr, ps, AddTraps);
8056747b715Smrg
8066747b715Smrg    free(pExaScr);
80705b261ecSmrg
80805b261ecSmrg    return (*pScreen->CloseScreen) (i, pScreen);
80905b261ecSmrg}
81005b261ecSmrg
81105b261ecSmrg/**
81205b261ecSmrg * This function allocates a driver structure for EXA drivers to fill in.  By
81305b261ecSmrg * having EXA allocate the structure, the driver structure can be extended
81405b261ecSmrg * without breaking ABI between EXA and the drivers.  The driver's
81505b261ecSmrg * responsibility is to check beforehand that the EXA module has a matching
81605b261ecSmrg * major number and sufficient minor.  Drivers are responsible for freeing the
8176747b715Smrg * driver structure using free().
81805b261ecSmrg *
81905b261ecSmrg * @return a newly allocated, zero-filled driver structure
82005b261ecSmrg */
82105b261ecSmrgExaDriverPtr
82205b261ecSmrgexaDriverAlloc(void)
82305b261ecSmrg{
8246747b715Smrg    return calloc(1, sizeof(ExaDriverRec));
82505b261ecSmrg}
82605b261ecSmrg
82705b261ecSmrg/**
82805b261ecSmrg * @param pScreen screen being initialized
82905b261ecSmrg * @param pScreenInfo EXA driver record
83005b261ecSmrg *
83105b261ecSmrg * exaDriverInit sets up EXA given a driver record filled in by the driver.
83205b261ecSmrg * pScreenInfo should have been allocated by exaDriverAlloc().  See the
83305b261ecSmrg * comments in _ExaDriver for what must be filled in and what is optional.
83405b261ecSmrg *
83505b261ecSmrg * @return TRUE if EXA was successfully initialized.
83605b261ecSmrg */
83705b261ecSmrgBool
83805b261ecSmrgexaDriverInit (ScreenPtr		pScreen,
83905b261ecSmrg               ExaDriverPtr	pScreenInfo)
84005b261ecSmrg{
84105b261ecSmrg    ExaScreenPrivPtr pExaScr;
84205b261ecSmrg    PictureScreenPtr ps;
84305b261ecSmrg
84405b261ecSmrg    if (!pScreenInfo)
84505b261ecSmrg	return FALSE;
84605b261ecSmrg
8474642e01fSmrg    if (pScreenInfo->exa_major != EXA_VERSION_MAJOR ||
8484642e01fSmrg	pScreenInfo->exa_minor > EXA_VERSION_MINOR)
8494642e01fSmrg    {
8504642e01fSmrg	LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements "
8514642e01fSmrg		   "(%d.%d) are incompatible with EXA version (%d.%d)\n",
8524642e01fSmrg		   pScreen->myNum,
8534642e01fSmrg		   pScreenInfo->exa_major, pScreenInfo->exa_minor,
8544642e01fSmrg		   EXA_VERSION_MAJOR, EXA_VERSION_MINOR);
85505b261ecSmrg	return FALSE;
85605b261ecSmrg    }
85705b261ecSmrg
8586747b715Smrg    if (!pScreenInfo->CreatePixmap && !pScreenInfo->CreatePixmap2) {
8594642e01fSmrg	if (!pScreenInfo->memoryBase) {
8604642e01fSmrg	    LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase "
8614642e01fSmrg		       "must be non-zero\n", pScreen->myNum);
8624642e01fSmrg	    return FALSE;
8634642e01fSmrg	}
86405b261ecSmrg
8654642e01fSmrg	if (!pScreenInfo->memorySize) {
8664642e01fSmrg	    LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be "
8674642e01fSmrg		       "non-zero\n", pScreen->myNum);
8684642e01fSmrg	    return FALSE;
8694642e01fSmrg	}
8704642e01fSmrg
8714642e01fSmrg	if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) {
8724642e01fSmrg	    LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must "
8734642e01fSmrg		       "be <= ExaDriverRec::memorySize\n", pScreen->myNum);
8744642e01fSmrg	    return FALSE;
8754642e01fSmrg	}
87605b261ecSmrg    }
87705b261ecSmrg
87805b261ecSmrg    if (!pScreenInfo->PrepareSolid) {
87905b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be "
88005b261ecSmrg		   "non-NULL\n", pScreen->myNum);
88105b261ecSmrg	return FALSE;
88205b261ecSmrg    }
88305b261ecSmrg
88405b261ecSmrg    if (!pScreenInfo->PrepareCopy) {
88505b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be "
88605b261ecSmrg		   "non-NULL\n", pScreen->myNum);
88705b261ecSmrg	return FALSE;
88805b261ecSmrg    }
88905b261ecSmrg
89005b261ecSmrg    if (!pScreenInfo->WaitMarker) {
89105b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be "
89205b261ecSmrg		   "non-NULL\n", pScreen->myNum);
89305b261ecSmrg	return FALSE;
89405b261ecSmrg    }
89505b261ecSmrg
8964642e01fSmrg    /* If the driver doesn't set any max pitch values, we'll just assume
8974642e01fSmrg     * that there's a limitation by pixels, and that it's the same as
8984642e01fSmrg     * maxX.
8994642e01fSmrg     *
9004642e01fSmrg     * We want maxPitchPixels or maxPitchBytes to be set so we can check
9014642e01fSmrg     * pixmaps against the max pitch in exaCreatePixmap() -- it matters
9024642e01fSmrg     * whether a pixmap is rejected because of its pitch or
9034642e01fSmrg     * because of its width.
9044642e01fSmrg     */
9054642e01fSmrg    if (!pScreenInfo->maxPitchPixels && !pScreenInfo->maxPitchBytes)
90605b261ecSmrg    {
9074642e01fSmrg        pScreenInfo->maxPitchPixels = pScreenInfo->maxX;
90805b261ecSmrg    }
90905b261ecSmrg
91005b261ecSmrg    ps = GetPictureScreenIfSet(pScreen);
91105b261ecSmrg
9126747b715Smrg    if (!dixRegisterPrivateKey(&exaScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) {
9136747b715Smrg        LogMessage(X_WARNING, "EXA(%d): Failed to register screen private\n",
9146747b715Smrg		   pScreen->myNum);
9156747b715Smrg	return FALSE;
9166747b715Smrg    }
91705b261ecSmrg
9186747b715Smrg    pExaScr = calloc (sizeof (ExaScreenPrivRec), 1);
91905b261ecSmrg    if (!pExaScr) {
92005b261ecSmrg        LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n",
92105b261ecSmrg		   pScreen->myNum);
92205b261ecSmrg	return FALSE;
92305b261ecSmrg    }
92405b261ecSmrg
92505b261ecSmrg    pExaScr->info = pScreenInfo;
92605b261ecSmrg
9274642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, exaScreenPrivateKey, pExaScr);
92805b261ecSmrg
92905b261ecSmrg    pExaScr->migration = ExaMigrationAlways;
93005b261ecSmrg
93105b261ecSmrg    exaDDXDriverInit(pScreen);
93205b261ecSmrg
9336747b715Smrg    if (!dixRegisterPrivateKey(&exaGCPrivateKeyRec, PRIVATE_GC, sizeof(ExaGCPrivRec))) {
9346747b715Smrg	LogMessage(X_WARNING,
9356747b715Smrg	       "EXA(%d): Failed to allocate GC private\n",
9366747b715Smrg	       pScreen->myNum);
9376747b715Smrg	return FALSE;
9386747b715Smrg    }
9396747b715Smrg
94005b261ecSmrg    /*
94105b261ecSmrg     * Replace various fb screen functions
94205b261ecSmrg     */
9436747b715Smrg    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
9446747b715Smrg	(!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) ||
9456747b715Smrg	 (pExaScr->info->flags & EXA_MIXED_PIXMAPS)))
9466747b715Smrg	wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);
9476747b715Smrg    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
9486747b715Smrg	!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS))
9496747b715Smrg	wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler);
9506747b715Smrg    wrap(pExaScr, pScreen, CreateGC, exaCreateGC);
9516747b715Smrg    wrap(pExaScr, pScreen, CloseScreen, exaCloseScreen);
9526747b715Smrg    wrap(pExaScr, pScreen, GetImage, exaGetImage);
9536747b715Smrg    wrap(pExaScr, pScreen, GetSpans, ExaCheckGetSpans);
9546747b715Smrg    wrap(pExaScr, pScreen, CopyWindow, exaCopyWindow);
9556747b715Smrg    wrap(pExaScr, pScreen, ChangeWindowAttributes, exaChangeWindowAttributes);
9566747b715Smrg    wrap(pExaScr, pScreen, BitmapToRegion, exaBitmapToRegion);
9576747b715Smrg    wrap(pExaScr, pScreen, CreateScreenResources, exaCreateScreenResources);
95805b261ecSmrg
95905b261ecSmrg    if (ps) {
9606747b715Smrg	wrap(pExaScr, ps, Composite, exaComposite);
9614642e01fSmrg	if (pScreenInfo->PrepareComposite) {
9626747b715Smrg	    wrap(pExaScr, ps, Glyphs, exaGlyphs);
9636747b715Smrg	} else {
9646747b715Smrg	    wrap(pExaScr, ps, Glyphs, ExaCheckGlyphs);
9654642e01fSmrg	}
9666747b715Smrg	wrap(pExaScr, ps, Trapezoids, exaTrapezoids);
9676747b715Smrg	wrap(pExaScr, ps, Triangles, exaTriangles);
9686747b715Smrg	wrap(pExaScr, ps, AddTraps, ExaCheckAddTraps);
96905b261ecSmrg    }
97005b261ecSmrg
97105b261ecSmrg#ifdef MITSHM
9724642e01fSmrg    /*
9734642e01fSmrg     * Don't allow shared pixmaps.
97405b261ecSmrg     */
9754642e01fSmrg    ShmRegisterFuncs(pScreen, &exaShmFuncs);
97605b261ecSmrg#endif
97705b261ecSmrg    /*
97805b261ecSmrg     * Hookup offscreen pixmaps
97905b261ecSmrg     */
9804642e01fSmrg    if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)
98105b261ecSmrg    {
9826747b715Smrg	if (!dixRegisterPrivateKey(&exaPixmapPrivateKeyRec, PRIVATE_PIXMAP, sizeof(ExaPixmapPrivRec))) {
98305b261ecSmrg            LogMessage(X_WARNING,
98405b261ecSmrg		       "EXA(%d): Failed to allocate pixmap private\n",
98505b261ecSmrg		       pScreen->myNum);
98605b261ecSmrg	    return FALSE;
98705b261ecSmrg        }
9886747b715Smrg	if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) {
9896747b715Smrg	    if (pExaScr->info->flags & EXA_MIXED_PIXMAPS) {
9906747b715Smrg		wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_mixed);
9916747b715Smrg		wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed);
9926747b715Smrg		wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_mixed);
9936747b715Smrg		pExaScr->do_migration = exaDoMigration_mixed;
9946747b715Smrg		pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_mixed;
9956747b715Smrg		pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed;
9966747b715Smrg		pExaScr->do_move_out_pixmap = NULL;
9976747b715Smrg		pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed;
9986747b715Smrg	    } else {
9996747b715Smrg		wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
10006747b715Smrg		wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
10016747b715Smrg		wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver);
10026747b715Smrg		pExaScr->do_migration = NULL;
10036747b715Smrg		pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_driver;
10046747b715Smrg		pExaScr->do_move_in_pixmap = NULL;
10056747b715Smrg		pExaScr->do_move_out_pixmap = NULL;
10066747b715Smrg		pExaScr->prepare_access_reg = NULL;
10076747b715Smrg	    }
10086747b715Smrg	} else {
10096747b715Smrg	    wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
10106747b715Smrg	    wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic);
10116747b715Smrg	    wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_classic);
10126747b715Smrg	    pExaScr->do_migration = exaDoMigration_classic;
10136747b715Smrg	    pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_classic;
10146747b715Smrg	    pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic;
10156747b715Smrg	    pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic;
10166747b715Smrg	    pExaScr->prepare_access_reg = exaPrepareAccessReg_classic;
10176747b715Smrg	}
10186747b715Smrg	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
10194642e01fSmrg	    LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",
10204642e01fSmrg		       pScreen->myNum,
10214642e01fSmrg		       pExaScr->info->memorySize - pExaScr->info->offScreenBase);
10224642e01fSmrg	} else {
10234642e01fSmrg	    LogMessage(X_INFO, "EXA(%d): Driver allocated offscreen pixmaps\n",
10244642e01fSmrg		       pScreen->myNum);
10254642e01fSmrg
10264642e01fSmrg	}
102705b261ecSmrg    }
102805b261ecSmrg    else
102905b261ecSmrg        LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum);
103005b261ecSmrg
10316747b715Smrg    if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
10324642e01fSmrg	DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase,
10334642e01fSmrg		    pExaScr->info->memorySize));
10344642e01fSmrg	if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
10354642e01fSmrg	    if (!exaOffscreenInit (pScreen)) {
10364642e01fSmrg		LogMessage(X_WARNING, "EXA(%d): Offscreen pixmap setup failed\n",
10374642e01fSmrg			   pScreen->myNum);
10384642e01fSmrg		return FALSE;
10394642e01fSmrg	    }
10404642e01fSmrg	}
104105b261ecSmrg    }
104205b261ecSmrg
10434642e01fSmrg    if (ps->Glyphs == exaGlyphs)
10444642e01fSmrg	exaGlyphsInit(pScreen);
10454642e01fSmrg
104605b261ecSmrg    LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
104705b261ecSmrg	       " operations:\n", pScreen->myNum);
104805b261ecSmrg    assert(pScreenInfo->PrepareSolid != NULL);
104905b261ecSmrg    LogMessage(X_INFO, "        Solid\n");
105005b261ecSmrg    assert(pScreenInfo->PrepareCopy != NULL);
105105b261ecSmrg    LogMessage(X_INFO, "        Copy\n");
105205b261ecSmrg    if (pScreenInfo->PrepareComposite != NULL) {
105305b261ecSmrg	LogMessage(X_INFO, "        Composite (RENDER acceleration)\n");
105405b261ecSmrg    }
105505b261ecSmrg    if (pScreenInfo->UploadToScreen != NULL) {
105605b261ecSmrg	LogMessage(X_INFO, "        UploadToScreen\n");
105705b261ecSmrg    }
105805b261ecSmrg    if (pScreenInfo->DownloadFromScreen != NULL) {
105905b261ecSmrg	LogMessage(X_INFO, "        DownloadFromScreen\n");
106005b261ecSmrg    }
106105b261ecSmrg
106205b261ecSmrg    return TRUE;
106305b261ecSmrg}
106405b261ecSmrg
106505b261ecSmrg/**
106605b261ecSmrg * exaDriverFini tears down EXA on a given screen.
106705b261ecSmrg *
106805b261ecSmrg * @param pScreen screen being torn down.
106905b261ecSmrg */
107005b261ecSmrgvoid
107105b261ecSmrgexaDriverFini (ScreenPtr pScreen)
107205b261ecSmrg{
107305b261ecSmrg    /*right now does nothing*/
107405b261ecSmrg}
107505b261ecSmrg
107605b261ecSmrg/**
107705b261ecSmrg * exaMarkSync() should be called after any asynchronous drawing by the hardware.
107805b261ecSmrg *
107905b261ecSmrg * @param pScreen screen which drawing occurred on
108005b261ecSmrg *
108105b261ecSmrg * exaMarkSync() sets a flag to indicate that some asynchronous drawing has
108205b261ecSmrg * happened and a WaitSync() will be necessary before relying on the contents of
108305b261ecSmrg * offscreen memory from the CPU's perspective.  It also calls an optional
108405b261ecSmrg * driver MarkSync() callback, the return value of which may be used to do partial
108505b261ecSmrg * synchronization with the hardware in the future.
108605b261ecSmrg */
108705b261ecSmrgvoid exaMarkSync(ScreenPtr pScreen)
108805b261ecSmrg{
108905b261ecSmrg    ExaScreenPriv(pScreen);
109005b261ecSmrg
109105b261ecSmrg    pExaScr->info->needsSync = TRUE;
109205b261ecSmrg    if (pExaScr->info->MarkSync != NULL) {
109305b261ecSmrg        pExaScr->info->lastMarker = (*pExaScr->info->MarkSync)(pScreen);
109405b261ecSmrg    }
109505b261ecSmrg}
109605b261ecSmrg
109705b261ecSmrg/**
109805b261ecSmrg * exaWaitSync() ensures that all drawing has been completed.
109905b261ecSmrg *
110005b261ecSmrg * @param pScreen screen being synchronized.
110105b261ecSmrg *
110205b261ecSmrg * Calls down into the driver to ensure that all previous drawing has completed.
110305b261ecSmrg * It should always be called before relying on the framebuffer contents
110405b261ecSmrg * reflecting previous drawing, from a CPU perspective.
110505b261ecSmrg */
110605b261ecSmrgvoid exaWaitSync(ScreenPtr pScreen)
110705b261ecSmrg{
110805b261ecSmrg    ExaScreenPriv(pScreen);
110905b261ecSmrg
111005b261ecSmrg    if (pExaScr->info->needsSync && !pExaScr->swappedOut) {
111105b261ecSmrg        (*pExaScr->info->WaitMarker)(pScreen, pExaScr->info->lastMarker);
111205b261ecSmrg        pExaScr->info->needsSync = FALSE;
111305b261ecSmrg    }
111405b261ecSmrg}
11156747b715Smrg
11166747b715Smrg/**
11176747b715Smrg * Performs migration of the pixmaps according to the operation information
11186747b715Smrg * provided in pixmaps and can_accel and the migration scheme chosen in the
11196747b715Smrg * config file.
11206747b715Smrg */
11216747b715Smrgvoid
11226747b715SmrgexaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
11236747b715Smrg{
11246747b715Smrg    ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
11256747b715Smrg    ExaScreenPriv(pScreen);
11266747b715Smrg
11276747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
11286747b715Smrg	return;
11296747b715Smrg
11306747b715Smrg    if (pExaScr->do_migration)
11316747b715Smrg	(*pExaScr->do_migration)(pixmaps, npixmaps, can_accel);
11326747b715Smrg}
11336747b715Smrg
11346747b715Smrgvoid
11356747b715SmrgexaMoveInPixmap (PixmapPtr pPixmap)
11366747b715Smrg{
11376747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
11386747b715Smrg    ExaScreenPriv(pScreen);
11396747b715Smrg
11406747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
11416747b715Smrg	return;
11426747b715Smrg
11436747b715Smrg    if (pExaScr->do_move_in_pixmap)
11446747b715Smrg	(*pExaScr->do_move_in_pixmap)(pPixmap);
11456747b715Smrg}
11466747b715Smrg
11476747b715Smrgvoid
11486747b715SmrgexaMoveOutPixmap (PixmapPtr pPixmap)
11496747b715Smrg{
11506747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
11516747b715Smrg    ExaScreenPriv(pScreen);
11526747b715Smrg
11536747b715Smrg    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
11546747b715Smrg	return;
11556747b715Smrg
11566747b715Smrg    if (pExaScr->do_move_out_pixmap)
11576747b715Smrg	(*pExaScr->do_move_out_pixmap)(pPixmap);
11586747b715Smrg}
1159