exa.c revision 4642e01f
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
404642e01fSmrgstatic int exaScreenPrivateKeyIndex;
414642e01fSmrgDevPrivateKey exaScreenPrivateKey = &exaScreenPrivateKeyIndex;
424642e01fSmrgstatic int exaPixmapPrivateKeyIndex;
434642e01fSmrgDevPrivateKey exaPixmapPrivateKey = &exaPixmapPrivateKeyIndex;
444642e01fSmrg
454642e01fSmrg#ifdef MITSHM
464642e01fSmrgstatic ShmFuncs exaShmFuncs = { NULL, NULL };
474642e01fSmrg#endif
484642e01fSmrg
494642e01fSmrgstatic _X_INLINE void*
504642e01fSmrgExaGetPixmapAddress(PixmapPtr p)
514642e01fSmrg{
524642e01fSmrg    ExaPixmapPriv(p);
534642e01fSmrg
544642e01fSmrg    if (pExaPixmap->offscreen && pExaPixmap->fb_ptr)
554642e01fSmrg	return pExaPixmap->fb_ptr;
564642e01fSmrg    else
574642e01fSmrg	return pExaPixmap->sys_ptr;
584642e01fSmrg}
5905b261ecSmrg
6005b261ecSmrg/**
6105b261ecSmrg * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
6205b261ecSmrg * the beginning of the given pixmap.
6305b261ecSmrg *
6405b261ecSmrg * Note that drivers are free to, and often do, munge this offset as necessary
6505b261ecSmrg * for handing to the hardware -- for example, translating it into a different
6605b261ecSmrg * aperture.  This function may need to be extended in the future if we grow
6705b261ecSmrg * support for having multiple card-accessible offscreen, such as an AGP memory
6805b261ecSmrg * pool alongside the framebuffer pool.
6905b261ecSmrg */
7005b261ecSmrgunsigned long
7105b261ecSmrgexaGetPixmapOffset(PixmapPtr pPix)
7205b261ecSmrg{
7305b261ecSmrg    ExaScreenPriv (pPix->drawable.pScreen);
7405b261ecSmrg
754642e01fSmrg    return ((unsigned long)ExaGetPixmapAddress(pPix) -
764642e01fSmrg	    (unsigned long)pExaScr->info->memoryBase);
774642e01fSmrg}
7805b261ecSmrg
794642e01fSmrgvoid *
804642e01fSmrgexaGetPixmapDriverPrivate(PixmapPtr pPix)
814642e01fSmrg{
824642e01fSmrg    ExaPixmapPriv(pPix);
834642e01fSmrg
844642e01fSmrg    return pExaPixmap->driverPriv;
8505b261ecSmrg}
8605b261ecSmrg
8705b261ecSmrg/**
8805b261ecSmrg * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap.
8905b261ecSmrg *
9005b261ecSmrg * This is a helper to make driver code more obvious, due to the rather obscure
9105b261ecSmrg * naming of the pitch field in the pixmap.
9205b261ecSmrg */
9305b261ecSmrgunsigned long
9405b261ecSmrgexaGetPixmapPitch(PixmapPtr pPix)
9505b261ecSmrg{
9605b261ecSmrg    return pPix->devKind;
9705b261ecSmrg}
9805b261ecSmrg
9905b261ecSmrg/**
10005b261ecSmrg * exaGetPixmapSize() returns the size in bytes of the given pixmap in video
10105b261ecSmrg * memory. Only valid when the pixmap is currently in framebuffer.
10205b261ecSmrg */
10305b261ecSmrgunsigned long
10405b261ecSmrgexaGetPixmapSize(PixmapPtr pPix)
10505b261ecSmrg{
10605b261ecSmrg    ExaPixmapPrivPtr pExaPixmap;
10705b261ecSmrg
10805b261ecSmrg    pExaPixmap = ExaGetPixmapPriv(pPix);
10905b261ecSmrg    if (pExaPixmap != NULL)
11005b261ecSmrg	return pExaPixmap->fb_size;
11105b261ecSmrg    return 0;
11205b261ecSmrg}
11305b261ecSmrg
11405b261ecSmrg/**
11505b261ecSmrg * exaGetDrawablePixmap() returns a backing pixmap for a given drawable.
11605b261ecSmrg *
11705b261ecSmrg * @param pDrawable the drawable being requested.
11805b261ecSmrg *
11905b261ecSmrg * This function returns the backing pixmap for a drawable, whether it is a
12005b261ecSmrg * redirected window, unredirected window, or already a pixmap.  Note that
12105b261ecSmrg * coordinate translation is needed when drawing to the backing pixmap of a
12205b261ecSmrg * redirected window, and the translation coordinates are provided by calling
12305b261ecSmrg * exaGetOffscreenPixmap() on the drawable.
12405b261ecSmrg */
12505b261ecSmrgPixmapPtr
12605b261ecSmrgexaGetDrawablePixmap(DrawablePtr pDrawable)
12705b261ecSmrg{
12805b261ecSmrg     if (pDrawable->type == DRAWABLE_WINDOW)
12905b261ecSmrg	return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
13005b261ecSmrg     else
13105b261ecSmrg	return (PixmapPtr) pDrawable;
13205b261ecSmrg}
13305b261ecSmrg
13405b261ecSmrg/**
13505b261ecSmrg * Sets the offsets to add to coordinates to make them address the same bits in
13605b261ecSmrg * the backing drawable. These coordinates are nonzero only for redirected
13705b261ecSmrg * windows.
13805b261ecSmrg */
13905b261ecSmrgvoid
14005b261ecSmrgexaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
14105b261ecSmrg		      int *xp, int *yp)
14205b261ecSmrg{
14305b261ecSmrg#ifdef COMPOSITE
14405b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
14505b261ecSmrg	*xp = -pPixmap->screen_x;
14605b261ecSmrg	*yp = -pPixmap->screen_y;
14705b261ecSmrg	return;
14805b261ecSmrg    }
14905b261ecSmrg#endif
15005b261ecSmrg
15105b261ecSmrg    *xp = 0;
15205b261ecSmrg    *yp = 0;
15305b261ecSmrg}
15405b261ecSmrg
15505b261ecSmrg/**
15605b261ecSmrg * exaPixmapDirty() marks a pixmap as dirty, allowing for
15705b261ecSmrg * optimizations in pixmap migration when no changes have occurred.
15805b261ecSmrg */
15905b261ecSmrgvoid
16005b261ecSmrgexaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
16105b261ecSmrg{
16205b261ecSmrg    ExaPixmapPriv(pPix);
16305b261ecSmrg    BoxRec box;
16405b261ecSmrg    RegionPtr pDamageReg;
16505b261ecSmrg    RegionRec region;
16605b261ecSmrg
1674642e01fSmrg    if (!pExaPixmap || !pExaPixmap->pDamage)
16805b261ecSmrg	return;
16905b261ecSmrg
17005b261ecSmrg    box.x1 = max(x1, 0);
17105b261ecSmrg    box.y1 = max(y1, 0);
17205b261ecSmrg    box.x2 = min(x2, pPix->drawable.width);
17305b261ecSmrg    box.y2 = min(y2, pPix->drawable.height);
17405b261ecSmrg
17505b261ecSmrg    if (box.x1 >= box.x2 || box.y1 >= box.y2)
17605b261ecSmrg	return;
17705b261ecSmrg
17805b261ecSmrg    pDamageReg = DamageRegion(pExaPixmap->pDamage);
17905b261ecSmrg
18005b261ecSmrg    REGION_INIT(pScreen, &region, &box, 1);
18105b261ecSmrg    REGION_UNION(pScreen, pDamageReg, pDamageReg, &region);
18205b261ecSmrg    REGION_UNINIT(pScreen, &region);
18305b261ecSmrg}
18405b261ecSmrg
18505b261ecSmrgstatic Bool
18605b261ecSmrgexaDestroyPixmap (PixmapPtr pPixmap)
18705b261ecSmrg{
1884642e01fSmrg    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
1894642e01fSmrg    ExaScreenPriv(pScreen);
1904642e01fSmrg
19105b261ecSmrg    if (pPixmap->refcnt == 1)
19205b261ecSmrg    {
19305b261ecSmrg	ExaPixmapPriv (pPixmap);
1944642e01fSmrg
1954642e01fSmrg	if (pExaPixmap->driverPriv) {
1964642e01fSmrg	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
1974642e01fSmrg	    pExaPixmap->driverPriv = NULL;
1984642e01fSmrg	}
1994642e01fSmrg
20005b261ecSmrg	if (pExaPixmap->area)
20105b261ecSmrg	{
20205b261ecSmrg	    DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
20305b261ecSmrg                        (void*)pPixmap->drawable.id,
20405b261ecSmrg			 ExaGetPixmapPriv(pPixmap)->area->offset,
20505b261ecSmrg			 pPixmap->drawable.width,
20605b261ecSmrg			 pPixmap->drawable.height));
20705b261ecSmrg	    /* Free the offscreen area */
20805b261ecSmrg	    exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
20905b261ecSmrg	    pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
21005b261ecSmrg	    pPixmap->devKind = pExaPixmap->sys_pitch;
21105b261ecSmrg	}
2124642e01fSmrg	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validSys);
2134642e01fSmrg	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
21405b261ecSmrg    }
21505b261ecSmrg    return fbDestroyPixmap (pPixmap);
21605b261ecSmrg}
21705b261ecSmrg
21805b261ecSmrgstatic int
21905b261ecSmrgexaLog2(int val)
22005b261ecSmrg{
22105b261ecSmrg    int bits;
22205b261ecSmrg
22305b261ecSmrg    if (val <= 0)
22405b261ecSmrg	return 0;
22505b261ecSmrg    for (bits = 0; val != 0; bits++)
22605b261ecSmrg	val >>= 1;
22705b261ecSmrg    return bits - 1;
22805b261ecSmrg}
22905b261ecSmrg
2304642e01fSmrgstatic void
2314642e01fSmrgexaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
2324642e01fSmrg                 int w, int h, int bpp)
2334642e01fSmrg{
2344642e01fSmrg    pExaPixmap->accel_blocked = 0;
2354642e01fSmrg
2364642e01fSmrg    if (pExaScr->info->maxPitchPixels) {
2374642e01fSmrg        int max_pitch = pExaScr->info->maxPitchPixels * (bpp + 7) / 8;
2384642e01fSmrg
2394642e01fSmrg        if (pExaPixmap->fb_pitch > max_pitch)
2404642e01fSmrg            pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;
2414642e01fSmrg    }
2424642e01fSmrg
2434642e01fSmrg    if (pExaScr->info->maxPitchBytes &&
2444642e01fSmrg        pExaPixmap->fb_pitch > pExaScr->info->maxPitchBytes)
2454642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_PITCH;
2464642e01fSmrg
2474642e01fSmrg    if (w > pExaScr->info->maxX)
2484642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_WIDTH;
2494642e01fSmrg
2504642e01fSmrg    if (h > pExaScr->info->maxY)
2514642e01fSmrg        pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT;
2524642e01fSmrg}
2534642e01fSmrg
2544642e01fSmrgstatic void
2554642e01fSmrgexaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
2564642e01fSmrg              int w, int h, int bpp)
2574642e01fSmrg{
2584642e01fSmrg    if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
2594642e01fSmrg        pExaPixmap->fb_pitch = (1 << (exaLog2(w - 1) + 1)) * bpp / 8;
2604642e01fSmrg    else
2614642e01fSmrg        pExaPixmap->fb_pitch = w * bpp / 8;
2624642e01fSmrg
2634642e01fSmrg    pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
2644642e01fSmrg                                     pExaScr->info->pixmapPitchAlign);
2654642e01fSmrg}
2664642e01fSmrg
26705b261ecSmrg/**
26805b261ecSmrg * exaCreatePixmap() creates a new pixmap.
26905b261ecSmrg *
27005b261ecSmrg * If width and height are 0, this won't be a full-fledged pixmap and it will
27105b261ecSmrg * get ModifyPixmapHeader() called on it later.  So, we mark it as pinned, because
27205b261ecSmrg * ModifyPixmapHeader() would break migration.  These types of pixmaps are used
27305b261ecSmrg * for scratch pixmaps, or to represent the visible screen.
27405b261ecSmrg */
27505b261ecSmrgstatic PixmapPtr
2764642e01fSmrgexaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth,
2774642e01fSmrg		unsigned usage_hint)
27805b261ecSmrg{
27905b261ecSmrg    PixmapPtr		pPixmap;
28005b261ecSmrg    ExaPixmapPrivPtr	pExaPixmap;
2814642e01fSmrg    int                 driver_alloc = 0;
28205b261ecSmrg    int			bpp;
28305b261ecSmrg    ExaScreenPriv(pScreen);
28405b261ecSmrg
28505b261ecSmrg    if (w > 32767 || h > 32767)
28605b261ecSmrg	return NullPixmap;
28705b261ecSmrg
2884642e01fSmrg    if (!pExaScr->info->CreatePixmap) {
2894642e01fSmrg        pPixmap = fbCreatePixmap (pScreen, w, h, depth, usage_hint);
2904642e01fSmrg    } else {
2914642e01fSmrg        driver_alloc = 1;
2924642e01fSmrg        pPixmap = fbCreatePixmap(pScreen, 0, 0, depth, usage_hint);
2934642e01fSmrg    }
2944642e01fSmrg
29505b261ecSmrg    if (!pPixmap)
2964642e01fSmrg        return NULL;
2974642e01fSmrg
29805b261ecSmrg    pExaPixmap = ExaGetPixmapPriv(pPixmap);
2994642e01fSmrg    pExaPixmap->driverPriv = NULL;
30005b261ecSmrg
30105b261ecSmrg    bpp = pPixmap->drawable.bitsPerPixel;
30205b261ecSmrg
3034642e01fSmrg    if (driver_alloc) {
3044642e01fSmrg        size_t paddedWidth, datasize;
30505b261ecSmrg
3064642e01fSmrg	paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
3074642e01fSmrg        if (paddedWidth / 4 > 32767 || h > 32767)
3084642e01fSmrg            return NullPixmap;
30905b261ecSmrg
3104642e01fSmrg        exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
31105b261ecSmrg
3124642e01fSmrg        if (paddedWidth < pExaPixmap->fb_pitch)
3134642e01fSmrg            paddedWidth = pExaPixmap->fb_pitch;
31405b261ecSmrg
3154642e01fSmrg        datasize = h * paddedWidth;
31605b261ecSmrg
3174642e01fSmrg	/* Set this before driver hooks, to allow for !offscreen pixmaps.
3184642e01fSmrg	 * !offscreen pixmaps have a valid pointer at all times.
3194642e01fSmrg	 */
3204642e01fSmrg	pPixmap->devPrivate.ptr = NULL;
32105b261ecSmrg
3224642e01fSmrg        pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0);
3234642e01fSmrg        if (!pExaPixmap->driverPriv) {
3244642e01fSmrg             fbDestroyPixmap(pPixmap);
3254642e01fSmrg             return NULL;
3264642e01fSmrg        }
3274642e01fSmrg
3284642e01fSmrg        (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
3294642e01fSmrg                                       paddedWidth, NULL);
3304642e01fSmrg        pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
3314642e01fSmrg        pExaPixmap->fb_ptr = NULL;
3324642e01fSmrg        pExaPixmap->pDamage = NULL;
3334642e01fSmrg        pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
3344642e01fSmrg
3354642e01fSmrg    } else {
3364642e01fSmrg        pExaPixmap->driverPriv = NULL;
3374642e01fSmrg        /* Scratch pixmaps may have w/h equal to zero, and may not be
3384642e01fSmrg	 * migrated.
3394642e01fSmrg	 */
3404642e01fSmrg        if (!w || !h)
3414642e01fSmrg	    pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
3424642e01fSmrg        else
3434642e01fSmrg            pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
3444642e01fSmrg
3454642e01fSmrg        pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
3464642e01fSmrg        pExaPixmap->sys_pitch = pPixmap->devKind;
34705b261ecSmrg
3484642e01fSmrg        pPixmap->devPrivate.ptr = NULL;
3494642e01fSmrg        pExaPixmap->offscreen = FALSE;
3504642e01fSmrg
3514642e01fSmrg        pExaPixmap->fb_ptr = NULL;
3524642e01fSmrg        exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
3534642e01fSmrg        pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
3544642e01fSmrg
3554642e01fSmrg        if (pExaPixmap->fb_pitch > 131071) {
3564642e01fSmrg	     fbDestroyPixmap(pPixmap);
3574642e01fSmrg	     return NULL;
3584642e01fSmrg        }
3594642e01fSmrg
3604642e01fSmrg	/* Set up damage tracking */
3614642e01fSmrg	pExaPixmap->pDamage = DamageCreate (NULL, NULL,
3624642e01fSmrg					    DamageReportNone, TRUE,
3634642e01fSmrg					    pScreen, pPixmap);
3644642e01fSmrg
3654642e01fSmrg	if (pExaPixmap->pDamage == NULL) {
3664642e01fSmrg	    fbDestroyPixmap (pPixmap);
3674642e01fSmrg	    return NULL;
3684642e01fSmrg	}
3694642e01fSmrg
3704642e01fSmrg	DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
3714642e01fSmrg	/* This ensures that pending damage reflects the current operation. */
3724642e01fSmrg	/* This is used by exa to optimize migration. */
3734642e01fSmrg	DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
3744642e01fSmrg    }
3754642e01fSmrg
3764642e01fSmrg    pExaPixmap->area = NULL;
37705b261ecSmrg
37805b261ecSmrg    /* None of the pixmap bits are valid initially */
3794642e01fSmrg    REGION_NULL(pScreen, &pExaPixmap->validSys);
3804642e01fSmrg    REGION_NULL(pScreen, &pExaPixmap->validFB);
3814642e01fSmrg
3824642e01fSmrg    exaSetAccelBlock(pExaScr, pExaPixmap,
3834642e01fSmrg                     w, h, bpp);
38405b261ecSmrg
38505b261ecSmrg    return pPixmap;
38605b261ecSmrg}
38705b261ecSmrg
3884642e01fSmrgstatic Bool
3894642e01fSmrgexaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
3904642e01fSmrg		      int bitsPerPixel, int devKind, pointer pPixData)
3914642e01fSmrg{
3924642e01fSmrg    ExaScreenPrivPtr pExaScr;
3934642e01fSmrg    ExaPixmapPrivPtr pExaPixmap;
3944642e01fSmrg    Bool ret;
3954642e01fSmrg
3964642e01fSmrg    if (!pPixmap)
3974642e01fSmrg        return FALSE;
3984642e01fSmrg
3994642e01fSmrg    pExaScr = ExaGetScreenPriv(pPixmap->drawable.pScreen);
4004642e01fSmrg    pExaPixmap = ExaGetPixmapPriv(pPixmap);
4014642e01fSmrg
4024642e01fSmrg    if (pExaPixmap) {
4034642e01fSmrg        if (pPixData)
4044642e01fSmrg            pExaPixmap->sys_ptr = pPixData;
4054642e01fSmrg
4064642e01fSmrg        if (devKind > 0)
4074642e01fSmrg            pExaPixmap->sys_pitch = devKind;
4084642e01fSmrg
4094642e01fSmrg        if (width > 0 && height > 0 && bitsPerPixel > 0) {
4104642e01fSmrg            exaSetFbPitch(pExaScr, pExaPixmap,
4114642e01fSmrg                          width, height, bitsPerPixel);
4124642e01fSmrg
4134642e01fSmrg            exaSetAccelBlock(pExaScr, pExaPixmap,
4144642e01fSmrg                             width, height, bitsPerPixel);
4154642e01fSmrg        }
4164642e01fSmrg    }
4174642e01fSmrg
4184642e01fSmrg
4194642e01fSmrg    if (pExaScr->info->ModifyPixmapHeader) {
4204642e01fSmrg	ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
4214642e01fSmrg						bitsPerPixel, devKind, pPixData);
4224642e01fSmrg	if (ret == TRUE)
4234642e01fSmrg	    return ret;
4244642e01fSmrg    }
4254642e01fSmrg    return pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth,
4264642e01fSmrg					    bitsPerPixel, devKind, pPixData);
4274642e01fSmrg}
4284642e01fSmrg
42905b261ecSmrg/**
43005b261ecSmrg * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen
43105b261ecSmrg * memory, meaning that acceleration could probably be done to it, and that it
43205b261ecSmrg * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
43305b261ecSmrg * with the CPU.
43405b261ecSmrg *
43505b261ecSmrg * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
43605b261ecSmrg * deal with moving pixmaps in and out of system memory), EXA will give drivers
43705b261ecSmrg * pixmaps as arguments for which exaPixmapIsOffscreen() is TRUE.
43805b261ecSmrg *
43905b261ecSmrg * @return TRUE if the given drawable is in framebuffer memory.
44005b261ecSmrg */
44105b261ecSmrgBool
44205b261ecSmrgexaPixmapIsOffscreen(PixmapPtr p)
44305b261ecSmrg{
44405b261ecSmrg    ScreenPtr	pScreen = p->drawable.pScreen;
44505b261ecSmrg    ExaScreenPriv(pScreen);
4464642e01fSmrg    ExaPixmapPriv(p);
4474642e01fSmrg    void *save_ptr;
4484642e01fSmrg    Bool ret;
44905b261ecSmrg
4504642e01fSmrg    save_ptr = p->devPrivate.ptr;
4514642e01fSmrg
4524642e01fSmrg    if (!save_ptr && pExaPixmap && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS))
4534642e01fSmrg	p->devPrivate.ptr = ExaGetPixmapAddress(p);
45405b261ecSmrg
45505b261ecSmrg    if (pExaScr->info->PixmapIsOffscreen)
4564642e01fSmrg	ret = pExaScr->info->PixmapIsOffscreen(p);
4574642e01fSmrg    else
4584642e01fSmrg       ret = ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
4594642e01fSmrg			       (CARD8 *) pExaScr->info->memoryBase) <
4604642e01fSmrg	      pExaScr->info->memorySize);
46105b261ecSmrg
4624642e01fSmrg    p->devPrivate.ptr = save_ptr;
4634642e01fSmrg
4644642e01fSmrg    return ret;
46505b261ecSmrg}
46605b261ecSmrg
46705b261ecSmrg/**
46805b261ecSmrg * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapIsOffscreen().
46905b261ecSmrg */
47005b261ecSmrgBool
47105b261ecSmrgexaDrawableIsOffscreen (DrawablePtr pDrawable)
47205b261ecSmrg{
47305b261ecSmrg    return exaPixmapIsOffscreen (exaGetDrawablePixmap (pDrawable));
47405b261ecSmrg}
47505b261ecSmrg
47605b261ecSmrg/**
47705b261ecSmrg * Returns the pixmap which backs a drawable, and the offsets to add to
47805b261ecSmrg * coordinates to make them address the same bits in the backing drawable.
47905b261ecSmrg */
48005b261ecSmrgPixmapPtr
48105b261ecSmrgexaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
48205b261ecSmrg{
48305b261ecSmrg    PixmapPtr	pPixmap = exaGetDrawablePixmap (pDrawable);
48405b261ecSmrg
48505b261ecSmrg    exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp);
48605b261ecSmrg
48705b261ecSmrg    if (exaPixmapIsOffscreen (pPixmap))
48805b261ecSmrg	return pPixmap;
48905b261ecSmrg    else
49005b261ecSmrg	return NULL;
49105b261ecSmrg}
49205b261ecSmrg
49305b261ecSmrgvoid
4944642e01fSmrgExaDoPrepareAccess(DrawablePtr pDrawable, int index)
49505b261ecSmrg{
49605b261ecSmrg    ScreenPtr	    pScreen = pDrawable->pScreen;
49705b261ecSmrg    ExaScreenPriv  (pScreen);
4984642e01fSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
4994642e01fSmrg    Bool	    offscreen = exaPixmapIsOffscreen(pPixmap);
50005b261ecSmrg
5014642e01fSmrg    /* Unhide pixmap pointer */
5024642e01fSmrg    if (pPixmap->devPrivate.ptr == NULL && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
5034642e01fSmrg	pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
5044642e01fSmrg    }
50505b261ecSmrg
5064642e01fSmrg    if (!offscreen)
50705b261ecSmrg	return;
50805b261ecSmrg
5094642e01fSmrg    exaWaitSync (pDrawable->pScreen);
51005b261ecSmrg
51105b261ecSmrg    if (pExaScr->info->PrepareAccess == NULL)
51205b261ecSmrg	return;
51305b261ecSmrg
5144642e01fSmrg    if (index >= EXA_PREPARE_AUX0 &&
5154642e01fSmrg	!(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
5164642e01fSmrg	exaMoveOutPixmap (pPixmap);
5174642e01fSmrg	return;
5184642e01fSmrg    }
5194642e01fSmrg
52005b261ecSmrg    if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
52105b261ecSmrg	ExaPixmapPriv (pPixmap);
5224642e01fSmrg	if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
52305b261ecSmrg	    FatalError("Driver failed PrepareAccess on a pinned pixmap\n");
52405b261ecSmrg	exaMoveOutPixmap (pPixmap);
52505b261ecSmrg    }
52605b261ecSmrg}
52705b261ecSmrg
5284642e01fSmrgvoid
5294642e01fSmrgexaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg)
5304642e01fSmrg{
5314642e01fSmrg    ExaMigrationRec pixmaps[1];
5324642e01fSmrg
5334642e01fSmrg    pixmaps[0].as_dst = index == EXA_PREPARE_DEST;
5344642e01fSmrg    pixmaps[0].as_src = index != EXA_PREPARE_DEST;
5354642e01fSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
5364642e01fSmrg    pixmaps[0].pReg = pReg;
5374642e01fSmrg
5384642e01fSmrg    exaDoMigration(pixmaps, 1, FALSE);
5394642e01fSmrg
5404642e01fSmrg    ExaDoPrepareAccess(pDrawable, index);
5414642e01fSmrg}
5424642e01fSmrg
5434642e01fSmrg/**
5444642e01fSmrg * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
5454642e01fSmrg *
5464642e01fSmrg * It deals with waiting for synchronization with the card, determining if
5474642e01fSmrg * PrepareAccess() is necessary, and working around PrepareAccess() failure.
5484642e01fSmrg */
5494642e01fSmrgvoid
5504642e01fSmrgexaPrepareAccess(DrawablePtr pDrawable, int index)
5514642e01fSmrg{
5524642e01fSmrg    exaPrepareAccessReg(pDrawable, index, NULL);
5534642e01fSmrg}
5544642e01fSmrg
55505b261ecSmrg/**
55605b261ecSmrg * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
55705b261ecSmrg *
55805b261ecSmrg * It deals with calling the driver's FinishAccess() only if necessary.
55905b261ecSmrg */
56005b261ecSmrgvoid
56105b261ecSmrgexaFinishAccess(DrawablePtr pDrawable, int index)
56205b261ecSmrg{
56305b261ecSmrg    ScreenPtr	    pScreen = pDrawable->pScreen;
56405b261ecSmrg    ExaScreenPriv  (pScreen);
5654642e01fSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
5664642e01fSmrg    ExaPixmapPriv  (pPixmap);
56705b261ecSmrg
56805b261ecSmrg    /* Rehide pixmap pointer if we're doing that. */
5694642e01fSmrg    if (pExaPixmap && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
5704642e01fSmrg	pPixmap->devPrivate.ptr = NULL;
57105b261ecSmrg    }
57205b261ecSmrg
57305b261ecSmrg    if (pExaScr->info->FinishAccess == NULL)
57405b261ecSmrg	return;
57505b261ecSmrg
57605b261ecSmrg    if (!exaPixmapIsOffscreen (pPixmap))
57705b261ecSmrg	return;
57805b261ecSmrg
5794642e01fSmrg    if (index >= EXA_PREPARE_AUX0 &&
5804642e01fSmrg	!(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
5814642e01fSmrg	ErrorF("EXA bug: Trying to call driver FinishAccess hook with "
5824642e01fSmrg	       "unsupported index EXA_PREPARE_AUX*\n");
5834642e01fSmrg	return;
5844642e01fSmrg    }
5854642e01fSmrg
58605b261ecSmrg    (*pExaScr->info->FinishAccess) (pPixmap, index);
58705b261ecSmrg}
58805b261ecSmrg
58905b261ecSmrg/**
59005b261ecSmrg * exaValidateGC() sets the ops to EXA's implementations, which may be
59105b261ecSmrg * accelerated or may sync the card and fall back to fb.
59205b261ecSmrg */
59305b261ecSmrgstatic void
59405b261ecSmrgexaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
59505b261ecSmrg{
59605b261ecSmrg    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
59705b261ecSmrg     * Preempt fbValidateGC by doing its work and masking the change out, so
59805b261ecSmrg     * that we can do the Prepare/FinishAccess.
59905b261ecSmrg     */
60005b261ecSmrg#ifdef FB_24_32BIT
60105b261ecSmrg    if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
60205b261ecSmrg	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
60305b261ecSmrg	fbGetRotatedPixmap(pGC) = 0;
60405b261ecSmrg    }
60505b261ecSmrg
60605b261ecSmrg    if (pGC->fillStyle == FillTiled) {
60705b261ecSmrg	PixmapPtr	pOldTile, pNewTile;
60805b261ecSmrg
60905b261ecSmrg	pOldTile = pGC->tile.pixmap;
61005b261ecSmrg	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
61105b261ecSmrg	{
61205b261ecSmrg	    pNewTile = fbGetRotatedPixmap(pGC);
61305b261ecSmrg	    if (!pNewTile ||
61405b261ecSmrg		pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
61505b261ecSmrg	    {
61605b261ecSmrg		if (pNewTile)
61705b261ecSmrg		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
61805b261ecSmrg		/* fb24_32ReformatTile will do direct access of a newly-
61905b261ecSmrg		 * allocated pixmap.  This isn't a problem yet, since we don't
62005b261ecSmrg		 * put pixmaps in FB until at least one accelerated EXA op.
62105b261ecSmrg		 */
62205b261ecSmrg		exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
62305b261ecSmrg		pNewTile = fb24_32ReformatTile (pOldTile,
62405b261ecSmrg						pDrawable->bitsPerPixel);
62505b261ecSmrg		exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
62605b261ecSmrg		exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
62705b261ecSmrg	    }
62805b261ecSmrg	    if (pNewTile)
62905b261ecSmrg	    {
63005b261ecSmrg		fbGetRotatedPixmap(pGC) = pOldTile;
63105b261ecSmrg		pGC->tile.pixmap = pNewTile;
63205b261ecSmrg		changes |= GCTile;
63305b261ecSmrg	    }
63405b261ecSmrg	}
63505b261ecSmrg    }
63605b261ecSmrg#endif
63705b261ecSmrg    if (changes & GCTile) {
63805b261ecSmrg	if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
63905b261ecSmrg					     pDrawable->bitsPerPixel))
64005b261ecSmrg	{
6414642e01fSmrg	    exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
64205b261ecSmrg	    fbPadPixmap (pGC->tile.pixmap);
6434642e01fSmrg	    exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
64405b261ecSmrg	    exaPixmapDirty(pGC->tile.pixmap, 0, 0,
64505b261ecSmrg			   pGC->tile.pixmap->drawable.width,
64605b261ecSmrg			   pGC->tile.pixmap->drawable.height);
64705b261ecSmrg	}
64805b261ecSmrg	/* Mask out the GCTile change notification, now that we've done FB's
64905b261ecSmrg	 * job for it.
65005b261ecSmrg	 */
65105b261ecSmrg	changes &= ~GCTile;
65205b261ecSmrg    }
65305b261ecSmrg
6544642e01fSmrg    exaPrepareAccessGC(pGC);
65505b261ecSmrg    fbValidateGC (pGC, changes, pDrawable);
6564642e01fSmrg    exaFinishAccessGC(pGC);
65705b261ecSmrg
65805b261ecSmrg    pGC->ops = (GCOps *) &exaOps;
65905b261ecSmrg}
66005b261ecSmrg
66105b261ecSmrgstatic GCFuncs	exaGCFuncs = {
66205b261ecSmrg    exaValidateGC,
66305b261ecSmrg    miChangeGC,
66405b261ecSmrg    miCopyGC,
66505b261ecSmrg    miDestroyGC,
66605b261ecSmrg    miChangeClip,
66705b261ecSmrg    miDestroyClip,
66805b261ecSmrg    miCopyClip
66905b261ecSmrg};
67005b261ecSmrg
67105b261ecSmrg/**
67205b261ecSmrg * exaCreateGC makes a new GC and hooks up its funcs handler, so that
67305b261ecSmrg * exaValidateGC() will get called.
67405b261ecSmrg */
67505b261ecSmrgstatic int
67605b261ecSmrgexaCreateGC (GCPtr pGC)
67705b261ecSmrg{
67805b261ecSmrg    if (!fbCreateGC (pGC))
67905b261ecSmrg	return FALSE;
68005b261ecSmrg
68105b261ecSmrg    pGC->funcs = &exaGCFuncs;
68205b261ecSmrg
68305b261ecSmrg    return TRUE;
68405b261ecSmrg}
68505b261ecSmrg
6864642e01fSmrgstatic Bool
6874642e01fSmrgexaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
6884642e01fSmrg{
6894642e01fSmrg    Bool ret;
6904642e01fSmrg
6914642e01fSmrg    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
6924642e01fSmrg        exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
6934642e01fSmrg
6944642e01fSmrg    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
6954642e01fSmrg        exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
6964642e01fSmrg
6974642e01fSmrg    ret = fbChangeWindowAttributes(pWin, mask);
6984642e01fSmrg
6994642e01fSmrg    if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
7004642e01fSmrg        exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
7014642e01fSmrg
7024642e01fSmrg    if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
7034642e01fSmrg        exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
7044642e01fSmrg
7054642e01fSmrg    return ret;
7064642e01fSmrg}
7074642e01fSmrg
7084642e01fSmrgstatic RegionPtr
7094642e01fSmrgexaBitmapToRegion(PixmapPtr pPix)
7104642e01fSmrg{
7114642e01fSmrg  RegionPtr ret;
7124642e01fSmrg  exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC);
7134642e01fSmrg  ret = fbPixmapToRegion(pPix);
7144642e01fSmrg  exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC);
7154642e01fSmrg  return ret;
7164642e01fSmrg}
7174642e01fSmrg
7184642e01fSmrgstatic Bool
7194642e01fSmrgexaCreateScreenResources(ScreenPtr pScreen)
7204642e01fSmrg{
7214642e01fSmrg    ExaScreenPriv(pScreen);
7224642e01fSmrg    PixmapPtr pScreenPixmap;
7234642e01fSmrg    Bool b;
7244642e01fSmrg
7254642e01fSmrg    pScreen->CreateScreenResources = pExaScr->SavedCreateScreenResources;
7264642e01fSmrg    b = pScreen->CreateScreenResources(pScreen);
7274642e01fSmrg    pScreen->CreateScreenResources = exaCreateScreenResources;
7284642e01fSmrg
7294642e01fSmrg    if (!b)
7304642e01fSmrg        return FALSE;
7314642e01fSmrg
7324642e01fSmrg    pScreenPixmap = pScreen->GetScreenPixmap(pScreen);
7334642e01fSmrg
7344642e01fSmrg    if (pScreenPixmap) {
7354642e01fSmrg        ExaPixmapPriv(pScreenPixmap);
7364642e01fSmrg
7374642e01fSmrg        exaSetAccelBlock(pExaScr, pExaPixmap,
7384642e01fSmrg                         pScreenPixmap->drawable.width,
7394642e01fSmrg                         pScreenPixmap->drawable.height,
7404642e01fSmrg                         pScreenPixmap->drawable.bitsPerPixel);
7414642e01fSmrg    }
7424642e01fSmrg
7434642e01fSmrg    return TRUE;
7444642e01fSmrg}
7454642e01fSmrg
74605b261ecSmrg/**
74705b261ecSmrg * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's
74805b261ecSmrg * screen private, before calling down to the next CloseSccreen.
74905b261ecSmrg */
75005b261ecSmrgstatic Bool
75105b261ecSmrgexaCloseScreen(int i, ScreenPtr pScreen)
75205b261ecSmrg{
75305b261ecSmrg    ExaScreenPriv(pScreen);
75405b261ecSmrg#ifdef RENDER
75505b261ecSmrg    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
75605b261ecSmrg#endif
75705b261ecSmrg
7584642e01fSmrg    if (ps->Glyphs == exaGlyphs)
7594642e01fSmrg	exaGlyphsFini(pScreen);
7604642e01fSmrg
76105b261ecSmrg    pScreen->CreateGC = pExaScr->SavedCreateGC;
76205b261ecSmrg    pScreen->CloseScreen = pExaScr->SavedCloseScreen;
76305b261ecSmrg    pScreen->GetImage = pExaScr->SavedGetImage;
76405b261ecSmrg    pScreen->GetSpans = pExaScr->SavedGetSpans;
76505b261ecSmrg    pScreen->CreatePixmap = pExaScr->SavedCreatePixmap;
76605b261ecSmrg    pScreen->DestroyPixmap = pExaScr->SavedDestroyPixmap;
76705b261ecSmrg    pScreen->CopyWindow = pExaScr->SavedCopyWindow;
7684642e01fSmrg    pScreen->ChangeWindowAttributes = pExaScr->SavedChangeWindowAttributes;
7694642e01fSmrg    pScreen->BitmapToRegion = pExaScr->SavedBitmapToRegion;
7704642e01fSmrg    pScreen->CreateScreenResources = pExaScr->SavedCreateScreenResources;
77105b261ecSmrg#ifdef RENDER
77205b261ecSmrg    if (ps) {
77305b261ecSmrg	ps->Composite = pExaScr->SavedComposite;
77405b261ecSmrg	ps->Glyphs = pExaScr->SavedGlyphs;
77505b261ecSmrg	ps->Trapezoids = pExaScr->SavedTrapezoids;
7764642e01fSmrg	ps->Triangles = pExaScr->SavedTriangles;
7774642e01fSmrg	ps->AddTraps = pExaScr->SavedAddTraps;
77805b261ecSmrg    }
77905b261ecSmrg#endif
78005b261ecSmrg
78105b261ecSmrg    xfree (pExaScr);
78205b261ecSmrg
78305b261ecSmrg    return (*pScreen->CloseScreen) (i, pScreen);
78405b261ecSmrg}
78505b261ecSmrg
78605b261ecSmrg/**
78705b261ecSmrg * This function allocates a driver structure for EXA drivers to fill in.  By
78805b261ecSmrg * having EXA allocate the structure, the driver structure can be extended
78905b261ecSmrg * without breaking ABI between EXA and the drivers.  The driver's
79005b261ecSmrg * responsibility is to check beforehand that the EXA module has a matching
79105b261ecSmrg * major number and sufficient minor.  Drivers are responsible for freeing the
79205b261ecSmrg * driver structure using xfree().
79305b261ecSmrg *
79405b261ecSmrg * @return a newly allocated, zero-filled driver structure
79505b261ecSmrg */
79605b261ecSmrgExaDriverPtr
79705b261ecSmrgexaDriverAlloc(void)
79805b261ecSmrg{
79905b261ecSmrg    return xcalloc(1, sizeof(ExaDriverRec));
80005b261ecSmrg}
80105b261ecSmrg
80205b261ecSmrg/**
80305b261ecSmrg * @param pScreen screen being initialized
80405b261ecSmrg * @param pScreenInfo EXA driver record
80505b261ecSmrg *
80605b261ecSmrg * exaDriverInit sets up EXA given a driver record filled in by the driver.
80705b261ecSmrg * pScreenInfo should have been allocated by exaDriverAlloc().  See the
80805b261ecSmrg * comments in _ExaDriver for what must be filled in and what is optional.
80905b261ecSmrg *
81005b261ecSmrg * @return TRUE if EXA was successfully initialized.
81105b261ecSmrg */
81205b261ecSmrgBool
81305b261ecSmrgexaDriverInit (ScreenPtr		pScreen,
81405b261ecSmrg               ExaDriverPtr	pScreenInfo)
81505b261ecSmrg{
81605b261ecSmrg    ExaScreenPrivPtr pExaScr;
81705b261ecSmrg#ifdef RENDER
81805b261ecSmrg    PictureScreenPtr ps;
81905b261ecSmrg#endif
82005b261ecSmrg
82105b261ecSmrg    if (!pScreenInfo)
82205b261ecSmrg	return FALSE;
82305b261ecSmrg
8244642e01fSmrg    if (pScreenInfo->exa_major != EXA_VERSION_MAJOR ||
8254642e01fSmrg	pScreenInfo->exa_minor > EXA_VERSION_MINOR)
8264642e01fSmrg    {
8274642e01fSmrg	LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements "
8284642e01fSmrg		   "(%d.%d) are incompatible with EXA version (%d.%d)\n",
8294642e01fSmrg		   pScreen->myNum,
8304642e01fSmrg		   pScreenInfo->exa_major, pScreenInfo->exa_minor,
8314642e01fSmrg		   EXA_VERSION_MAJOR, EXA_VERSION_MINOR);
83205b261ecSmrg	return FALSE;
83305b261ecSmrg    }
83405b261ecSmrg
8354642e01fSmrg    if (!pScreenInfo->CreatePixmap) {
8364642e01fSmrg	if (!pScreenInfo->memoryBase) {
8374642e01fSmrg	    LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase "
8384642e01fSmrg		       "must be non-zero\n", pScreen->myNum);
8394642e01fSmrg	    return FALSE;
8404642e01fSmrg	}
84105b261ecSmrg
8424642e01fSmrg	if (!pScreenInfo->memorySize) {
8434642e01fSmrg	    LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be "
8444642e01fSmrg		       "non-zero\n", pScreen->myNum);
8454642e01fSmrg	    return FALSE;
8464642e01fSmrg	}
8474642e01fSmrg
8484642e01fSmrg	if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) {
8494642e01fSmrg	    LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must "
8504642e01fSmrg		       "be <= ExaDriverRec::memorySize\n", pScreen->myNum);
8514642e01fSmrg	    return FALSE;
8524642e01fSmrg	}
85305b261ecSmrg    }
85405b261ecSmrg
85505b261ecSmrg    if (!pScreenInfo->PrepareSolid) {
85605b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be "
85705b261ecSmrg		   "non-NULL\n", pScreen->myNum);
85805b261ecSmrg	return FALSE;
85905b261ecSmrg    }
86005b261ecSmrg
86105b261ecSmrg    if (!pScreenInfo->PrepareCopy) {
86205b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be "
86305b261ecSmrg		   "non-NULL\n", pScreen->myNum);
86405b261ecSmrg	return FALSE;
86505b261ecSmrg    }
86605b261ecSmrg
86705b261ecSmrg    if (!pScreenInfo->WaitMarker) {
86805b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be "
86905b261ecSmrg		   "non-NULL\n", pScreen->myNum);
87005b261ecSmrg	return FALSE;
87105b261ecSmrg    }
87205b261ecSmrg
8734642e01fSmrg    /* If the driver doesn't set any max pitch values, we'll just assume
8744642e01fSmrg     * that there's a limitation by pixels, and that it's the same as
8754642e01fSmrg     * maxX.
8764642e01fSmrg     *
8774642e01fSmrg     * We want maxPitchPixels or maxPitchBytes to be set so we can check
8784642e01fSmrg     * pixmaps against the max pitch in exaCreatePixmap() -- it matters
8794642e01fSmrg     * whether a pixmap is rejected because of its pitch or
8804642e01fSmrg     * because of its width.
8814642e01fSmrg     */
8824642e01fSmrg    if (!pScreenInfo->maxPitchPixels && !pScreenInfo->maxPitchBytes)
88305b261ecSmrg    {
8844642e01fSmrg        pScreenInfo->maxPitchPixels = pScreenInfo->maxX;
88505b261ecSmrg    }
88605b261ecSmrg
88705b261ecSmrg#ifdef RENDER
88805b261ecSmrg    ps = GetPictureScreenIfSet(pScreen);
88905b261ecSmrg#endif
89005b261ecSmrg
89105b261ecSmrg    pExaScr = xcalloc (sizeof (ExaScreenPrivRec), 1);
89205b261ecSmrg
89305b261ecSmrg    if (!pExaScr) {
89405b261ecSmrg        LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n",
89505b261ecSmrg		   pScreen->myNum);
89605b261ecSmrg	return FALSE;
89705b261ecSmrg    }
89805b261ecSmrg
89905b261ecSmrg    pExaScr->info = pScreenInfo;
90005b261ecSmrg
9014642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, exaScreenPrivateKey, pExaScr);
90205b261ecSmrg
90305b261ecSmrg    pExaScr->migration = ExaMigrationAlways;
90405b261ecSmrg
90505b261ecSmrg    exaDDXDriverInit(pScreen);
90605b261ecSmrg
90705b261ecSmrg    /*
90805b261ecSmrg     * Replace various fb screen functions
90905b261ecSmrg     */
91005b261ecSmrg    pExaScr->SavedCloseScreen = pScreen->CloseScreen;
91105b261ecSmrg    pScreen->CloseScreen = exaCloseScreen;
91205b261ecSmrg
91305b261ecSmrg    pExaScr->SavedCreateGC = pScreen->CreateGC;
91405b261ecSmrg    pScreen->CreateGC = exaCreateGC;
91505b261ecSmrg
91605b261ecSmrg    pExaScr->SavedGetImage = pScreen->GetImage;
91705b261ecSmrg    pScreen->GetImage = exaGetImage;
91805b261ecSmrg
91905b261ecSmrg    pExaScr->SavedGetSpans = pScreen->GetSpans;
9204642e01fSmrg    pScreen->GetSpans = ExaCheckGetSpans;
92105b261ecSmrg
92205b261ecSmrg    pExaScr->SavedCopyWindow = pScreen->CopyWindow;
92305b261ecSmrg    pScreen->CopyWindow = exaCopyWindow;
92405b261ecSmrg
9254642e01fSmrg    pExaScr->SavedChangeWindowAttributes = pScreen->ChangeWindowAttributes;
9264642e01fSmrg    pScreen->ChangeWindowAttributes = exaChangeWindowAttributes;
9274642e01fSmrg
9284642e01fSmrg    pExaScr->SavedBitmapToRegion = pScreen->BitmapToRegion;
9294642e01fSmrg    pScreen->BitmapToRegion = exaBitmapToRegion;
93005b261ecSmrg
9314642e01fSmrg    pExaScr->SavedCreateScreenResources = pScreen->CreateScreenResources;
9324642e01fSmrg    pScreen->CreateScreenResources = exaCreateScreenResources;
93305b261ecSmrg
93405b261ecSmrg#ifdef RENDER
93505b261ecSmrg    if (ps) {
93605b261ecSmrg        pExaScr->SavedComposite = ps->Composite;
93705b261ecSmrg	ps->Composite = exaComposite;
93805b261ecSmrg
9394642e01fSmrg	if (pScreenInfo->PrepareComposite) {
9404642e01fSmrg	    pExaScr->SavedGlyphs = ps->Glyphs;
9414642e01fSmrg	    ps->Glyphs = exaGlyphs;
9424642e01fSmrg	}
9434642e01fSmrg
9444642e01fSmrg	pExaScr->SavedTriangles = ps->Triangles;
9454642e01fSmrg	ps->Triangles = exaTriangles;
94605b261ecSmrg
94705b261ecSmrg	pExaScr->SavedTrapezoids = ps->Trapezoids;
94805b261ecSmrg	ps->Trapezoids = exaTrapezoids;
9494642e01fSmrg
9504642e01fSmrg	pExaScr->SavedAddTraps = ps->AddTraps;
9514642e01fSmrg	ps->AddTraps = ExaCheckAddTraps;
95205b261ecSmrg    }
95305b261ecSmrg#endif
95405b261ecSmrg
95505b261ecSmrg#ifdef MITSHM
9564642e01fSmrg    /*
9574642e01fSmrg     * Don't allow shared pixmaps.
95805b261ecSmrg     */
9594642e01fSmrg    ShmRegisterFuncs(pScreen, &exaShmFuncs);
96005b261ecSmrg#endif
96105b261ecSmrg    /*
96205b261ecSmrg     * Hookup offscreen pixmaps
96305b261ecSmrg     */
9644642e01fSmrg    if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)
96505b261ecSmrg    {
9664642e01fSmrg	if (!dixRequestPrivate(exaPixmapPrivateKey, sizeof(ExaPixmapPrivRec))) {
96705b261ecSmrg            LogMessage(X_WARNING,
96805b261ecSmrg		       "EXA(%d): Failed to allocate pixmap private\n",
96905b261ecSmrg		       pScreen->myNum);
97005b261ecSmrg	    return FALSE;
97105b261ecSmrg        }
97205b261ecSmrg        pExaScr->SavedCreatePixmap = pScreen->CreatePixmap;
97305b261ecSmrg	pScreen->CreatePixmap = exaCreatePixmap;
97405b261ecSmrg
97505b261ecSmrg        pExaScr->SavedDestroyPixmap = pScreen->DestroyPixmap;
97605b261ecSmrg	pScreen->DestroyPixmap = exaDestroyPixmap;
97705b261ecSmrg
9784642e01fSmrg	pExaScr->SavedModifyPixmapHeader = pScreen->ModifyPixmapHeader;
9794642e01fSmrg	pScreen->ModifyPixmapHeader = exaModifyPixmapHeader;
9804642e01fSmrg	if (!pExaScr->info->CreatePixmap) {
9814642e01fSmrg	    LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",
9824642e01fSmrg		       pScreen->myNum,
9834642e01fSmrg		       pExaScr->info->memorySize - pExaScr->info->offScreenBase);
9844642e01fSmrg	} else {
9854642e01fSmrg	    LogMessage(X_INFO, "EXA(%d): Driver allocated offscreen pixmaps\n",
9864642e01fSmrg		       pScreen->myNum);
9874642e01fSmrg
9884642e01fSmrg	}
98905b261ecSmrg    }
99005b261ecSmrg    else
99105b261ecSmrg        LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum);
99205b261ecSmrg
9934642e01fSmrg    if (!pExaScr->info->CreatePixmap) {
9944642e01fSmrg	DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase,
9954642e01fSmrg		    pExaScr->info->memorySize));
9964642e01fSmrg	if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
9974642e01fSmrg	    if (!exaOffscreenInit (pScreen)) {
9984642e01fSmrg		LogMessage(X_WARNING, "EXA(%d): Offscreen pixmap setup failed\n",
9994642e01fSmrg			   pScreen->myNum);
10004642e01fSmrg		return FALSE;
10014642e01fSmrg	    }
10024642e01fSmrg	}
100305b261ecSmrg    }
100405b261ecSmrg
10054642e01fSmrg    if (ps->Glyphs == exaGlyphs)
10064642e01fSmrg	exaGlyphsInit(pScreen);
10074642e01fSmrg
100805b261ecSmrg    LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
100905b261ecSmrg	       " operations:\n", pScreen->myNum);
101005b261ecSmrg    assert(pScreenInfo->PrepareSolid != NULL);
101105b261ecSmrg    LogMessage(X_INFO, "        Solid\n");
101205b261ecSmrg    assert(pScreenInfo->PrepareCopy != NULL);
101305b261ecSmrg    LogMessage(X_INFO, "        Copy\n");
101405b261ecSmrg    if (pScreenInfo->PrepareComposite != NULL) {
101505b261ecSmrg	LogMessage(X_INFO, "        Composite (RENDER acceleration)\n");
101605b261ecSmrg    }
101705b261ecSmrg    if (pScreenInfo->UploadToScreen != NULL) {
101805b261ecSmrg	LogMessage(X_INFO, "        UploadToScreen\n");
101905b261ecSmrg    }
102005b261ecSmrg    if (pScreenInfo->DownloadFromScreen != NULL) {
102105b261ecSmrg	LogMessage(X_INFO, "        DownloadFromScreen\n");
102205b261ecSmrg    }
102305b261ecSmrg
102405b261ecSmrg    return TRUE;
102505b261ecSmrg}
102605b261ecSmrg
102705b261ecSmrg/**
102805b261ecSmrg * exaDriverFini tears down EXA on a given screen.
102905b261ecSmrg *
103005b261ecSmrg * @param pScreen screen being torn down.
103105b261ecSmrg */
103205b261ecSmrgvoid
103305b261ecSmrgexaDriverFini (ScreenPtr pScreen)
103405b261ecSmrg{
103505b261ecSmrg    /*right now does nothing*/
103605b261ecSmrg}
103705b261ecSmrg
103805b261ecSmrg/**
103905b261ecSmrg * exaMarkSync() should be called after any asynchronous drawing by the hardware.
104005b261ecSmrg *
104105b261ecSmrg * @param pScreen screen which drawing occurred on
104205b261ecSmrg *
104305b261ecSmrg * exaMarkSync() sets a flag to indicate that some asynchronous drawing has
104405b261ecSmrg * happened and a WaitSync() will be necessary before relying on the contents of
104505b261ecSmrg * offscreen memory from the CPU's perspective.  It also calls an optional
104605b261ecSmrg * driver MarkSync() callback, the return value of which may be used to do partial
104705b261ecSmrg * synchronization with the hardware in the future.
104805b261ecSmrg */
104905b261ecSmrgvoid exaMarkSync(ScreenPtr pScreen)
105005b261ecSmrg{
105105b261ecSmrg    ExaScreenPriv(pScreen);
105205b261ecSmrg
105305b261ecSmrg    pExaScr->info->needsSync = TRUE;
105405b261ecSmrg    if (pExaScr->info->MarkSync != NULL) {
105505b261ecSmrg        pExaScr->info->lastMarker = (*pExaScr->info->MarkSync)(pScreen);
105605b261ecSmrg    }
105705b261ecSmrg}
105805b261ecSmrg
105905b261ecSmrg/**
106005b261ecSmrg * exaWaitSync() ensures that all drawing has been completed.
106105b261ecSmrg *
106205b261ecSmrg * @param pScreen screen being synchronized.
106305b261ecSmrg *
106405b261ecSmrg * Calls down into the driver to ensure that all previous drawing has completed.
106505b261ecSmrg * It should always be called before relying on the framebuffer contents
106605b261ecSmrg * reflecting previous drawing, from a CPU perspective.
106705b261ecSmrg */
106805b261ecSmrgvoid exaWaitSync(ScreenPtr pScreen)
106905b261ecSmrg{
107005b261ecSmrg    ExaScreenPriv(pScreen);
107105b261ecSmrg
107205b261ecSmrg    if (pExaScr->info->needsSync && !pExaScr->swappedOut) {
107305b261ecSmrg        (*pExaScr->info->WaitMarker)(pScreen, pExaScr->info->lastMarker);
107405b261ecSmrg        pExaScr->info->needsSync = FALSE;
107505b261ecSmrg    }
107605b261ecSmrg}
1077