exa.c revision 05b261ec
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#ifdef MITSHM
3605b261ecSmrg#include "shmint.h"
3705b261ecSmrg#endif
3805b261ecSmrg
3905b261ecSmrg#include <stdlib.h>
4005b261ecSmrg
4105b261ecSmrg#include "exa_priv.h"
4205b261ecSmrg#include <X11/fonts/fontstruct.h>
4305b261ecSmrg#include "dixfontstr.h"
4405b261ecSmrg#include "exa.h"
4505b261ecSmrg#include "cw.h"
4605b261ecSmrg
4705b261ecSmrgstatic int exaGeneration;
4805b261ecSmrgint exaScreenPrivateIndex;
4905b261ecSmrgint exaPixmapPrivateIndex;
5005b261ecSmrg
5105b261ecSmrg/**
5205b261ecSmrg * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
5305b261ecSmrg * the beginning of the given pixmap.
5405b261ecSmrg *
5505b261ecSmrg * Note that drivers are free to, and often do, munge this offset as necessary
5605b261ecSmrg * for handing to the hardware -- for example, translating it into a different
5705b261ecSmrg * aperture.  This function may need to be extended in the future if we grow
5805b261ecSmrg * support for having multiple card-accessible offscreen, such as an AGP memory
5905b261ecSmrg * pool alongside the framebuffer pool.
6005b261ecSmrg */
6105b261ecSmrgunsigned long
6205b261ecSmrgexaGetPixmapOffset(PixmapPtr pPix)
6305b261ecSmrg{
6405b261ecSmrg    ExaScreenPriv (pPix->drawable.pScreen);
6505b261ecSmrg    ExaPixmapPriv (pPix);
6605b261ecSmrg    void *ptr;
6705b261ecSmrg
6805b261ecSmrg    /* Return the offscreen pointer if we've hidden the data. */
6905b261ecSmrg    if (pPix->devPrivate.ptr == NULL)
7005b261ecSmrg	ptr = pExaPixmap->fb_ptr;
7105b261ecSmrg    else
7205b261ecSmrg	ptr = pPix->devPrivate.ptr;
7305b261ecSmrg
7405b261ecSmrg    return ((unsigned long)ptr - (unsigned long)pExaScr->info->memoryBase);
7505b261ecSmrg}
7605b261ecSmrg
7705b261ecSmrg/**
7805b261ecSmrg * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap.
7905b261ecSmrg *
8005b261ecSmrg * This is a helper to make driver code more obvious, due to the rather obscure
8105b261ecSmrg * naming of the pitch field in the pixmap.
8205b261ecSmrg */
8305b261ecSmrgunsigned long
8405b261ecSmrgexaGetPixmapPitch(PixmapPtr pPix)
8505b261ecSmrg{
8605b261ecSmrg    return pPix->devKind;
8705b261ecSmrg}
8805b261ecSmrg
8905b261ecSmrg/**
9005b261ecSmrg * exaGetPixmapSize() returns the size in bytes of the given pixmap in video
9105b261ecSmrg * memory. Only valid when the pixmap is currently in framebuffer.
9205b261ecSmrg */
9305b261ecSmrgunsigned long
9405b261ecSmrgexaGetPixmapSize(PixmapPtr pPix)
9505b261ecSmrg{
9605b261ecSmrg    ExaPixmapPrivPtr pExaPixmap;
9705b261ecSmrg
9805b261ecSmrg    pExaPixmap = ExaGetPixmapPriv(pPix);
9905b261ecSmrg    if (pExaPixmap != NULL)
10005b261ecSmrg	return pExaPixmap->fb_size;
10105b261ecSmrg    return 0;
10205b261ecSmrg}
10305b261ecSmrg
10405b261ecSmrg/**
10505b261ecSmrg * exaGetDrawablePixmap() returns a backing pixmap for a given drawable.
10605b261ecSmrg *
10705b261ecSmrg * @param pDrawable the drawable being requested.
10805b261ecSmrg *
10905b261ecSmrg * This function returns the backing pixmap for a drawable, whether it is a
11005b261ecSmrg * redirected window, unredirected window, or already a pixmap.  Note that
11105b261ecSmrg * coordinate translation is needed when drawing to the backing pixmap of a
11205b261ecSmrg * redirected window, and the translation coordinates are provided by calling
11305b261ecSmrg * exaGetOffscreenPixmap() on the drawable.
11405b261ecSmrg */
11505b261ecSmrgPixmapPtr
11605b261ecSmrgexaGetDrawablePixmap(DrawablePtr pDrawable)
11705b261ecSmrg{
11805b261ecSmrg     if (pDrawable->type == DRAWABLE_WINDOW)
11905b261ecSmrg	return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
12005b261ecSmrg     else
12105b261ecSmrg	return (PixmapPtr) pDrawable;
12205b261ecSmrg}
12305b261ecSmrg
12405b261ecSmrg/**
12505b261ecSmrg * Sets the offsets to add to coordinates to make them address the same bits in
12605b261ecSmrg * the backing drawable. These coordinates are nonzero only for redirected
12705b261ecSmrg * windows.
12805b261ecSmrg */
12905b261ecSmrgvoid
13005b261ecSmrgexaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
13105b261ecSmrg		      int *xp, int *yp)
13205b261ecSmrg{
13305b261ecSmrg#ifdef COMPOSITE
13405b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
13505b261ecSmrg	*xp = -pPixmap->screen_x;
13605b261ecSmrg	*yp = -pPixmap->screen_y;
13705b261ecSmrg	return;
13805b261ecSmrg    }
13905b261ecSmrg#endif
14005b261ecSmrg
14105b261ecSmrg    *xp = 0;
14205b261ecSmrg    *yp = 0;
14305b261ecSmrg}
14405b261ecSmrg
14505b261ecSmrg/**
14605b261ecSmrg * exaPixmapDirty() marks a pixmap as dirty, allowing for
14705b261ecSmrg * optimizations in pixmap migration when no changes have occurred.
14805b261ecSmrg */
14905b261ecSmrgvoid
15005b261ecSmrgexaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
15105b261ecSmrg{
15205b261ecSmrg    ExaPixmapPriv(pPix);
15305b261ecSmrg    BoxRec box;
15405b261ecSmrg    RegionPtr pDamageReg;
15505b261ecSmrg    RegionRec region;
15605b261ecSmrg
15705b261ecSmrg    if (!pExaPixmap)
15805b261ecSmrg	return;
15905b261ecSmrg
16005b261ecSmrg    box.x1 = max(x1, 0);
16105b261ecSmrg    box.y1 = max(y1, 0);
16205b261ecSmrg    box.x2 = min(x2, pPix->drawable.width);
16305b261ecSmrg    box.y2 = min(y2, pPix->drawable.height);
16405b261ecSmrg
16505b261ecSmrg    if (box.x1 >= box.x2 || box.y1 >= box.y2)
16605b261ecSmrg	return;
16705b261ecSmrg
16805b261ecSmrg    pDamageReg = DamageRegion(pExaPixmap->pDamage);
16905b261ecSmrg
17005b261ecSmrg    REGION_INIT(pScreen, &region, &box, 1);
17105b261ecSmrg    REGION_UNION(pScreen, pDamageReg, pDamageReg, &region);
17205b261ecSmrg    REGION_UNINIT(pScreen, &region);
17305b261ecSmrg}
17405b261ecSmrg
17505b261ecSmrgstatic Bool
17605b261ecSmrgexaDestroyPixmap (PixmapPtr pPixmap)
17705b261ecSmrg{
17805b261ecSmrg    if (pPixmap->refcnt == 1)
17905b261ecSmrg    {
18005b261ecSmrg	ExaPixmapPriv (pPixmap);
18105b261ecSmrg	if (pExaPixmap->area)
18205b261ecSmrg	{
18305b261ecSmrg	    DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
18405b261ecSmrg                        (void*)pPixmap->drawable.id,
18505b261ecSmrg			 ExaGetPixmapPriv(pPixmap)->area->offset,
18605b261ecSmrg			 pPixmap->drawable.width,
18705b261ecSmrg			 pPixmap->drawable.height));
18805b261ecSmrg	    /* Free the offscreen area */
18905b261ecSmrg	    exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
19005b261ecSmrg	    pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
19105b261ecSmrg	    pPixmap->devKind = pExaPixmap->sys_pitch;
19205b261ecSmrg	}
19305b261ecSmrg	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validReg);
19405b261ecSmrg    }
19505b261ecSmrg    return fbDestroyPixmap (pPixmap);
19605b261ecSmrg}
19705b261ecSmrg
19805b261ecSmrgstatic int
19905b261ecSmrgexaLog2(int val)
20005b261ecSmrg{
20105b261ecSmrg    int bits;
20205b261ecSmrg
20305b261ecSmrg    if (val <= 0)
20405b261ecSmrg	return 0;
20505b261ecSmrg    for (bits = 0; val != 0; bits++)
20605b261ecSmrg	val >>= 1;
20705b261ecSmrg    return bits - 1;
20805b261ecSmrg}
20905b261ecSmrg
21005b261ecSmrg/**
21105b261ecSmrg * exaCreatePixmap() creates a new pixmap.
21205b261ecSmrg *
21305b261ecSmrg * If width and height are 0, this won't be a full-fledged pixmap and it will
21405b261ecSmrg * get ModifyPixmapHeader() called on it later.  So, we mark it as pinned, because
21505b261ecSmrg * ModifyPixmapHeader() would break migration.  These types of pixmaps are used
21605b261ecSmrg * for scratch pixmaps, or to represent the visible screen.
21705b261ecSmrg */
21805b261ecSmrgstatic PixmapPtr
21905b261ecSmrgexaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
22005b261ecSmrg{
22105b261ecSmrg    PixmapPtr		pPixmap;
22205b261ecSmrg    ExaPixmapPrivPtr	pExaPixmap;
22305b261ecSmrg    int			bpp;
22405b261ecSmrg    ExaScreenPriv(pScreen);
22505b261ecSmrg
22605b261ecSmrg    if (w > 32767 || h > 32767)
22705b261ecSmrg	return NullPixmap;
22805b261ecSmrg
22905b261ecSmrg    pPixmap = fbCreatePixmap (pScreen, w, h, depth);
23005b261ecSmrg    if (!pPixmap)
23105b261ecSmrg	return NULL;
23205b261ecSmrg    pExaPixmap = ExaGetPixmapPriv(pPixmap);
23305b261ecSmrg
23405b261ecSmrg    bpp = pPixmap->drawable.bitsPerPixel;
23505b261ecSmrg
23605b261ecSmrg    /* Glyphs have w/h equal to zero, and may not be migrated. See exaGlyphs. */
23705b261ecSmrg    if (!w || !h)
23805b261ecSmrg	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
23905b261ecSmrg    else
24005b261ecSmrg	pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
24105b261ecSmrg
24205b261ecSmrg    pExaPixmap->area = NULL;
24305b261ecSmrg
24405b261ecSmrg    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
24505b261ecSmrg    pExaPixmap->sys_pitch = pPixmap->devKind;
24605b261ecSmrg
24705b261ecSmrg    pExaPixmap->fb_ptr = NULL;
24805b261ecSmrg    if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
24905b261ecSmrg	pExaPixmap->fb_pitch = (1 << (exaLog2(w - 1) + 1)) * bpp / 8;
25005b261ecSmrg    else
25105b261ecSmrg	pExaPixmap->fb_pitch = w * bpp / 8;
25205b261ecSmrg    pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
25305b261ecSmrg				     pExaScr->info->pixmapPitchAlign);
25405b261ecSmrg    pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
25505b261ecSmrg
25605b261ecSmrg    if (pExaPixmap->fb_pitch > 131071) {
25705b261ecSmrg	fbDestroyPixmap(pPixmap);
25805b261ecSmrg	return NULL;
25905b261ecSmrg    }
26005b261ecSmrg
26105b261ecSmrg    /* Set up damage tracking */
26205b261ecSmrg    pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE,
26305b261ecSmrg					pScreen, pPixmap);
26405b261ecSmrg
26505b261ecSmrg    if (pExaPixmap->pDamage == NULL) {
26605b261ecSmrg	fbDestroyPixmap (pPixmap);
26705b261ecSmrg	return NULL;
26805b261ecSmrg    }
26905b261ecSmrg
27005b261ecSmrg    DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
27105b261ecSmrg    DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
27205b261ecSmrg
27305b261ecSmrg    /* None of the pixmap bits are valid initially */
27405b261ecSmrg    REGION_NULL(pScreen, &pExaPixmap->validReg);
27505b261ecSmrg
27605b261ecSmrg    return pPixmap;
27705b261ecSmrg}
27805b261ecSmrg
27905b261ecSmrg/**
28005b261ecSmrg * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen
28105b261ecSmrg * memory, meaning that acceleration could probably be done to it, and that it
28205b261ecSmrg * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
28305b261ecSmrg * with the CPU.
28405b261ecSmrg *
28505b261ecSmrg * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
28605b261ecSmrg * deal with moving pixmaps in and out of system memory), EXA will give drivers
28705b261ecSmrg * pixmaps as arguments for which exaPixmapIsOffscreen() is TRUE.
28805b261ecSmrg *
28905b261ecSmrg * @return TRUE if the given drawable is in framebuffer memory.
29005b261ecSmrg */
29105b261ecSmrgBool
29205b261ecSmrgexaPixmapIsOffscreen(PixmapPtr p)
29305b261ecSmrg{
29405b261ecSmrg    ScreenPtr	pScreen = p->drawable.pScreen;
29505b261ecSmrg    ExaScreenPriv(pScreen);
29605b261ecSmrg
29705b261ecSmrg    /* If the devPrivate.ptr is NULL, it's offscreen but we've hidden the data.
29805b261ecSmrg     */
29905b261ecSmrg    if (p->devPrivate.ptr == NULL)
30005b261ecSmrg	return TRUE;
30105b261ecSmrg
30205b261ecSmrg    if (pExaScr->info->PixmapIsOffscreen)
30305b261ecSmrg	return pExaScr->info->PixmapIsOffscreen(p);
30405b261ecSmrg
30505b261ecSmrg    return ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
30605b261ecSmrg			     (CARD8 *) pExaScr->info->memoryBase) <
30705b261ecSmrg	    pExaScr->info->memorySize);
30805b261ecSmrg}
30905b261ecSmrg
31005b261ecSmrg/**
31105b261ecSmrg * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapIsOffscreen().
31205b261ecSmrg */
31305b261ecSmrgBool
31405b261ecSmrgexaDrawableIsOffscreen (DrawablePtr pDrawable)
31505b261ecSmrg{
31605b261ecSmrg    return exaPixmapIsOffscreen (exaGetDrawablePixmap (pDrawable));
31705b261ecSmrg}
31805b261ecSmrg
31905b261ecSmrg/**
32005b261ecSmrg * Returns the pixmap which backs a drawable, and the offsets to add to
32105b261ecSmrg * coordinates to make them address the same bits in the backing drawable.
32205b261ecSmrg */
32305b261ecSmrgPixmapPtr
32405b261ecSmrgexaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
32505b261ecSmrg{
32605b261ecSmrg    PixmapPtr	pPixmap = exaGetDrawablePixmap (pDrawable);
32705b261ecSmrg
32805b261ecSmrg    exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp);
32905b261ecSmrg
33005b261ecSmrg    if (exaPixmapIsOffscreen (pPixmap))
33105b261ecSmrg	return pPixmap;
33205b261ecSmrg    else
33305b261ecSmrg	return NULL;
33405b261ecSmrg}
33505b261ecSmrg
33605b261ecSmrg/**
33705b261ecSmrg * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
33805b261ecSmrg *
33905b261ecSmrg * It deals with waiting for synchronization with the card, determining if
34005b261ecSmrg * PrepareAccess() is necessary, and working around PrepareAccess() failure.
34105b261ecSmrg */
34205b261ecSmrgvoid
34305b261ecSmrgexaPrepareAccess(DrawablePtr pDrawable, int index)
34405b261ecSmrg{
34505b261ecSmrg    ScreenPtr	    pScreen = pDrawable->pScreen;
34605b261ecSmrg    ExaScreenPriv  (pScreen);
34705b261ecSmrg    PixmapPtr	    pPixmap;
34805b261ecSmrg
34905b261ecSmrg    pPixmap = exaGetDrawablePixmap (pDrawable);
35005b261ecSmrg
35105b261ecSmrg    if (exaPixmapIsOffscreen (pPixmap))
35205b261ecSmrg	exaWaitSync (pDrawable->pScreen);
35305b261ecSmrg    else
35405b261ecSmrg	return;
35505b261ecSmrg
35605b261ecSmrg    /* Unhide pixmap pointer */
35705b261ecSmrg    if (pPixmap->devPrivate.ptr == NULL) {
35805b261ecSmrg	ExaPixmapPriv (pPixmap);
35905b261ecSmrg
36005b261ecSmrg	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
36105b261ecSmrg    }
36205b261ecSmrg
36305b261ecSmrg    if (pExaScr->info->PrepareAccess == NULL)
36405b261ecSmrg	return;
36505b261ecSmrg
36605b261ecSmrg    if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
36705b261ecSmrg	ExaPixmapPriv (pPixmap);
36805b261ecSmrg	if (pExaPixmap->score != EXA_PIXMAP_SCORE_PINNED)
36905b261ecSmrg	    FatalError("Driver failed PrepareAccess on a pinned pixmap\n");
37005b261ecSmrg	exaMoveOutPixmap (pPixmap);
37105b261ecSmrg    }
37205b261ecSmrg}
37305b261ecSmrg
37405b261ecSmrg/**
37505b261ecSmrg * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
37605b261ecSmrg *
37705b261ecSmrg * It deals with calling the driver's FinishAccess() only if necessary.
37805b261ecSmrg */
37905b261ecSmrgvoid
38005b261ecSmrgexaFinishAccess(DrawablePtr pDrawable, int index)
38105b261ecSmrg{
38205b261ecSmrg    ScreenPtr	    pScreen = pDrawable->pScreen;
38305b261ecSmrg    ExaScreenPriv  (pScreen);
38405b261ecSmrg    PixmapPtr	    pPixmap;
38505b261ecSmrg    ExaPixmapPrivPtr pExaPixmap;
38605b261ecSmrg
38705b261ecSmrg    pPixmap = exaGetDrawablePixmap (pDrawable);
38805b261ecSmrg
38905b261ecSmrg    pExaPixmap = ExaGetPixmapPriv(pPixmap);
39005b261ecSmrg
39105b261ecSmrg    /* Rehide pixmap pointer if we're doing that. */
39205b261ecSmrg    if (pExaPixmap != NULL && pExaScr->hideOffscreenPixmapData &&
39305b261ecSmrg	pExaPixmap->fb_ptr == pPixmap->devPrivate.ptr)
39405b261ecSmrg    {
39505b261ecSmrg	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
39605b261ecSmrg    }
39705b261ecSmrg
39805b261ecSmrg    if (pExaScr->info->FinishAccess == NULL)
39905b261ecSmrg	return;
40005b261ecSmrg
40105b261ecSmrg    if (!exaPixmapIsOffscreen (pPixmap))
40205b261ecSmrg	return;
40305b261ecSmrg
40405b261ecSmrg    (*pExaScr->info->FinishAccess) (pPixmap, index);
40505b261ecSmrg}
40605b261ecSmrg
40705b261ecSmrg/**
40805b261ecSmrg * exaValidateGC() sets the ops to EXA's implementations, which may be
40905b261ecSmrg * accelerated or may sync the card and fall back to fb.
41005b261ecSmrg */
41105b261ecSmrgstatic void
41205b261ecSmrgexaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
41305b261ecSmrg{
41405b261ecSmrg    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
41505b261ecSmrg     * Preempt fbValidateGC by doing its work and masking the change out, so
41605b261ecSmrg     * that we can do the Prepare/FinishAccess.
41705b261ecSmrg     */
41805b261ecSmrg#ifdef FB_24_32BIT
41905b261ecSmrg    if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
42005b261ecSmrg	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
42105b261ecSmrg	fbGetRotatedPixmap(pGC) = 0;
42205b261ecSmrg    }
42305b261ecSmrg
42405b261ecSmrg    if (pGC->fillStyle == FillTiled) {
42505b261ecSmrg	PixmapPtr	pOldTile, pNewTile;
42605b261ecSmrg
42705b261ecSmrg	pOldTile = pGC->tile.pixmap;
42805b261ecSmrg	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
42905b261ecSmrg	{
43005b261ecSmrg	    pNewTile = fbGetRotatedPixmap(pGC);
43105b261ecSmrg	    if (!pNewTile ||
43205b261ecSmrg		pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
43305b261ecSmrg	    {
43405b261ecSmrg		if (pNewTile)
43505b261ecSmrg		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
43605b261ecSmrg		/* fb24_32ReformatTile will do direct access of a newly-
43705b261ecSmrg		 * allocated pixmap.  This isn't a problem yet, since we don't
43805b261ecSmrg		 * put pixmaps in FB until at least one accelerated EXA op.
43905b261ecSmrg		 */
44005b261ecSmrg		exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
44105b261ecSmrg		pNewTile = fb24_32ReformatTile (pOldTile,
44205b261ecSmrg						pDrawable->bitsPerPixel);
44305b261ecSmrg		exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
44405b261ecSmrg		exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
44505b261ecSmrg	    }
44605b261ecSmrg	    if (pNewTile)
44705b261ecSmrg	    {
44805b261ecSmrg		fbGetRotatedPixmap(pGC) = pOldTile;
44905b261ecSmrg		pGC->tile.pixmap = pNewTile;
45005b261ecSmrg		changes |= GCTile;
45105b261ecSmrg	    }
45205b261ecSmrg	}
45305b261ecSmrg    }
45405b261ecSmrg#endif
45505b261ecSmrg    if (changes & GCTile) {
45605b261ecSmrg	if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
45705b261ecSmrg					     pDrawable->bitsPerPixel))
45805b261ecSmrg	{
45905b261ecSmrg	    /* XXX This fixes corruption with tiled pixmaps, but may just be a
46005b261ecSmrg	     * workaround for broken drivers
46105b261ecSmrg	     */
46205b261ecSmrg	    exaMoveOutPixmap(pGC->tile.pixmap);
46305b261ecSmrg	    fbPadPixmap (pGC->tile.pixmap);
46405b261ecSmrg	    exaPixmapDirty(pGC->tile.pixmap, 0, 0,
46505b261ecSmrg			   pGC->tile.pixmap->drawable.width,
46605b261ecSmrg			   pGC->tile.pixmap->drawable.height);
46705b261ecSmrg	}
46805b261ecSmrg	/* Mask out the GCTile change notification, now that we've done FB's
46905b261ecSmrg	 * job for it.
47005b261ecSmrg	 */
47105b261ecSmrg	changes &= ~GCTile;
47205b261ecSmrg    }
47305b261ecSmrg
47405b261ecSmrg    fbValidateGC (pGC, changes, pDrawable);
47505b261ecSmrg
47605b261ecSmrg    pGC->ops = (GCOps *) &exaOps;
47705b261ecSmrg}
47805b261ecSmrg
47905b261ecSmrgstatic GCFuncs	exaGCFuncs = {
48005b261ecSmrg    exaValidateGC,
48105b261ecSmrg    miChangeGC,
48205b261ecSmrg    miCopyGC,
48305b261ecSmrg    miDestroyGC,
48405b261ecSmrg    miChangeClip,
48505b261ecSmrg    miDestroyClip,
48605b261ecSmrg    miCopyClip
48705b261ecSmrg};
48805b261ecSmrg
48905b261ecSmrg/**
49005b261ecSmrg * exaCreateGC makes a new GC and hooks up its funcs handler, so that
49105b261ecSmrg * exaValidateGC() will get called.
49205b261ecSmrg */
49305b261ecSmrgstatic int
49405b261ecSmrgexaCreateGC (GCPtr pGC)
49505b261ecSmrg{
49605b261ecSmrg    if (!fbCreateGC (pGC))
49705b261ecSmrg	return FALSE;
49805b261ecSmrg
49905b261ecSmrg    pGC->funcs = &exaGCFuncs;
50005b261ecSmrg
50105b261ecSmrg    return TRUE;
50205b261ecSmrg}
50305b261ecSmrg
50405b261ecSmrg/**
50505b261ecSmrg * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's
50605b261ecSmrg * screen private, before calling down to the next CloseSccreen.
50705b261ecSmrg */
50805b261ecSmrgstatic Bool
50905b261ecSmrgexaCloseScreen(int i, ScreenPtr pScreen)
51005b261ecSmrg{
51105b261ecSmrg    ExaScreenPriv(pScreen);
51205b261ecSmrg#ifdef RENDER
51305b261ecSmrg    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
51405b261ecSmrg#endif
51505b261ecSmrg
51605b261ecSmrg    pScreen->CreateGC = pExaScr->SavedCreateGC;
51705b261ecSmrg    pScreen->CloseScreen = pExaScr->SavedCloseScreen;
51805b261ecSmrg    pScreen->GetImage = pExaScr->SavedGetImage;
51905b261ecSmrg    pScreen->GetSpans = pExaScr->SavedGetSpans;
52005b261ecSmrg    pScreen->PaintWindowBackground = pExaScr->SavedPaintWindowBackground;
52105b261ecSmrg    pScreen->PaintWindowBorder = pExaScr->SavedPaintWindowBorder;
52205b261ecSmrg    pScreen->CreatePixmap = pExaScr->SavedCreatePixmap;
52305b261ecSmrg    pScreen->DestroyPixmap = pExaScr->SavedDestroyPixmap;
52405b261ecSmrg    pScreen->CopyWindow = pExaScr->SavedCopyWindow;
52505b261ecSmrg#ifdef RENDER
52605b261ecSmrg    if (ps) {
52705b261ecSmrg	ps->Composite = pExaScr->SavedComposite;
52805b261ecSmrg	ps->Glyphs = pExaScr->SavedGlyphs;
52905b261ecSmrg	ps->Trapezoids = pExaScr->SavedTrapezoids;
53005b261ecSmrg    }
53105b261ecSmrg#endif
53205b261ecSmrg
53305b261ecSmrg    xfree (pExaScr);
53405b261ecSmrg
53505b261ecSmrg    return (*pScreen->CloseScreen) (i, pScreen);
53605b261ecSmrg}
53705b261ecSmrg
53805b261ecSmrg/**
53905b261ecSmrg * This function allocates a driver structure for EXA drivers to fill in.  By
54005b261ecSmrg * having EXA allocate the structure, the driver structure can be extended
54105b261ecSmrg * without breaking ABI between EXA and the drivers.  The driver's
54205b261ecSmrg * responsibility is to check beforehand that the EXA module has a matching
54305b261ecSmrg * major number and sufficient minor.  Drivers are responsible for freeing the
54405b261ecSmrg * driver structure using xfree().
54505b261ecSmrg *
54605b261ecSmrg * @return a newly allocated, zero-filled driver structure
54705b261ecSmrg */
54805b261ecSmrgExaDriverPtr
54905b261ecSmrgexaDriverAlloc(void)
55005b261ecSmrg{
55105b261ecSmrg    return xcalloc(1, sizeof(ExaDriverRec));
55205b261ecSmrg}
55305b261ecSmrg
55405b261ecSmrg/**
55505b261ecSmrg * @param pScreen screen being initialized
55605b261ecSmrg * @param pScreenInfo EXA driver record
55705b261ecSmrg *
55805b261ecSmrg * exaDriverInit sets up EXA given a driver record filled in by the driver.
55905b261ecSmrg * pScreenInfo should have been allocated by exaDriverAlloc().  See the
56005b261ecSmrg * comments in _ExaDriver for what must be filled in and what is optional.
56105b261ecSmrg *
56205b261ecSmrg * @return TRUE if EXA was successfully initialized.
56305b261ecSmrg */
56405b261ecSmrgBool
56505b261ecSmrgexaDriverInit (ScreenPtr		pScreen,
56605b261ecSmrg               ExaDriverPtr	pScreenInfo)
56705b261ecSmrg{
56805b261ecSmrg    ExaScreenPrivPtr pExaScr;
56905b261ecSmrg#ifdef RENDER
57005b261ecSmrg    PictureScreenPtr ps;
57105b261ecSmrg#endif
57205b261ecSmrg
57305b261ecSmrg    if (!pScreenInfo)
57405b261ecSmrg	return FALSE;
57505b261ecSmrg
57605b261ecSmrg    if (!pScreenInfo->memoryBase) {
57705b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase must be "
57805b261ecSmrg		   "non-zero\n", pScreen->myNum);
57905b261ecSmrg	return FALSE;
58005b261ecSmrg    }
58105b261ecSmrg
58205b261ecSmrg    if (!pScreenInfo->memorySize) {
58305b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be "
58405b261ecSmrg		   "non-zero\n", pScreen->myNum);
58505b261ecSmrg	return FALSE;
58605b261ecSmrg    }
58705b261ecSmrg
58805b261ecSmrg    if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) {
58905b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must be <= "
59005b261ecSmrg		   "ExaDriverRec::memorySize\n", pScreen->myNum);
59105b261ecSmrg	return FALSE;
59205b261ecSmrg    }
59305b261ecSmrg
59405b261ecSmrg    if (!pScreenInfo->PrepareSolid) {
59505b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be "
59605b261ecSmrg		   "non-NULL\n", pScreen->myNum);
59705b261ecSmrg	return FALSE;
59805b261ecSmrg    }
59905b261ecSmrg
60005b261ecSmrg    if (!pScreenInfo->PrepareCopy) {
60105b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be "
60205b261ecSmrg		   "non-NULL\n", pScreen->myNum);
60305b261ecSmrg	return FALSE;
60405b261ecSmrg    }
60505b261ecSmrg
60605b261ecSmrg    if (!pScreenInfo->WaitMarker) {
60705b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be "
60805b261ecSmrg		   "non-NULL\n", pScreen->myNum);
60905b261ecSmrg	return FALSE;
61005b261ecSmrg    }
61105b261ecSmrg
61205b261ecSmrg    if (pScreenInfo->exa_major != EXA_VERSION_MAJOR ||
61305b261ecSmrg	pScreenInfo->exa_minor > EXA_VERSION_MINOR)
61405b261ecSmrg    {
61505b261ecSmrg	LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements "
61605b261ecSmrg		   "(%d.%d) are incompatible with EXA version (%d.%d)\n",
61705b261ecSmrg		   pScreen->myNum,
61805b261ecSmrg		   pScreenInfo->exa_major, pScreenInfo->exa_minor,
61905b261ecSmrg		   EXA_VERSION_MAJOR, EXA_VERSION_MINOR);
62005b261ecSmrg	return FALSE;
62105b261ecSmrg    }
62205b261ecSmrg
62305b261ecSmrg#ifdef RENDER
62405b261ecSmrg    ps = GetPictureScreenIfSet(pScreen);
62505b261ecSmrg#endif
62605b261ecSmrg    if (exaGeneration != serverGeneration)
62705b261ecSmrg    {
62805b261ecSmrg	exaScreenPrivateIndex = AllocateScreenPrivateIndex();
62905b261ecSmrg	exaPixmapPrivateIndex = AllocatePixmapPrivateIndex();
63005b261ecSmrg	exaGeneration = serverGeneration;
63105b261ecSmrg    }
63205b261ecSmrg
63305b261ecSmrg    pExaScr = xcalloc (sizeof (ExaScreenPrivRec), 1);
63405b261ecSmrg
63505b261ecSmrg    if (!pExaScr) {
63605b261ecSmrg        LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n",
63705b261ecSmrg		   pScreen->myNum);
63805b261ecSmrg	return FALSE;
63905b261ecSmrg    }
64005b261ecSmrg
64105b261ecSmrg    pExaScr->info = pScreenInfo;
64205b261ecSmrg
64305b261ecSmrg    pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr;
64405b261ecSmrg
64505b261ecSmrg    pExaScr->migration = ExaMigrationAlways;
64605b261ecSmrg
64705b261ecSmrg    exaDDXDriverInit(pScreen);
64805b261ecSmrg
64905b261ecSmrg    /*
65005b261ecSmrg     * Replace various fb screen functions
65105b261ecSmrg     */
65205b261ecSmrg    pExaScr->SavedCloseScreen = pScreen->CloseScreen;
65305b261ecSmrg    pScreen->CloseScreen = exaCloseScreen;
65405b261ecSmrg
65505b261ecSmrg    pExaScr->SavedCreateGC = pScreen->CreateGC;
65605b261ecSmrg    pScreen->CreateGC = exaCreateGC;
65705b261ecSmrg
65805b261ecSmrg    pExaScr->SavedGetImage = pScreen->GetImage;
65905b261ecSmrg    pScreen->GetImage = exaGetImage;
66005b261ecSmrg
66105b261ecSmrg    pExaScr->SavedGetSpans = pScreen->GetSpans;
66205b261ecSmrg    pScreen->GetSpans = exaGetSpans;
66305b261ecSmrg
66405b261ecSmrg    pExaScr->SavedCopyWindow = pScreen->CopyWindow;
66505b261ecSmrg    pScreen->CopyWindow = exaCopyWindow;
66605b261ecSmrg
66705b261ecSmrg    pExaScr->SavedPaintWindowBackground = pScreen->PaintWindowBackground;
66805b261ecSmrg    pScreen->PaintWindowBackground = exaPaintWindow;
66905b261ecSmrg
67005b261ecSmrg    pExaScr->SavedPaintWindowBorder = pScreen->PaintWindowBorder;
67105b261ecSmrg    pScreen->PaintWindowBorder = exaPaintWindow;
67205b261ecSmrg
67305b261ecSmrg    pScreen->BackingStoreFuncs.SaveAreas = ExaCheckSaveAreas;
67405b261ecSmrg    pScreen->BackingStoreFuncs.RestoreAreas = ExaCheckRestoreAreas;
67505b261ecSmrg#ifdef RENDER
67605b261ecSmrg    if (ps) {
67705b261ecSmrg        pExaScr->SavedComposite = ps->Composite;
67805b261ecSmrg	ps->Composite = exaComposite;
67905b261ecSmrg
68005b261ecSmrg	pExaScr->SavedRasterizeTrapezoid = ps->RasterizeTrapezoid;
68105b261ecSmrg	ps->RasterizeTrapezoid = exaRasterizeTrapezoid;
68205b261ecSmrg
68305b261ecSmrg	pExaScr->SavedAddTriangles = ps->AddTriangles;
68405b261ecSmrg	ps->AddTriangles = exaAddTriangles;
68505b261ecSmrg
68605b261ecSmrg	pExaScr->SavedGlyphs = ps->Glyphs;
68705b261ecSmrg	ps->Glyphs = exaGlyphs;
68805b261ecSmrg
68905b261ecSmrg	pExaScr->SavedTrapezoids = ps->Trapezoids;
69005b261ecSmrg	ps->Trapezoids = exaTrapezoids;
69105b261ecSmrg    }
69205b261ecSmrg#endif
69305b261ecSmrg
69405b261ecSmrg#ifdef MITSHM
69505b261ecSmrg    /* Re-register with the MI funcs, which don't allow shared pixmaps.
69605b261ecSmrg     * Shared pixmaps are almost always a performance loss for us, but this
69705b261ecSmrg     * still allows for SHM PutImage.
69805b261ecSmrg     */
69905b261ecSmrg    ShmRegisterFuncs(pScreen, NULL);
70005b261ecSmrg#endif
70105b261ecSmrg    /*
70205b261ecSmrg     * Hookup offscreen pixmaps
70305b261ecSmrg     */
70405b261ecSmrg    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
70505b261ecSmrg	pExaScr->info->offScreenBase < pExaScr->info->memorySize)
70605b261ecSmrg    {
70705b261ecSmrg	if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex,
70805b261ecSmrg				   sizeof (ExaPixmapPrivRec))) {
70905b261ecSmrg            LogMessage(X_WARNING,
71005b261ecSmrg		       "EXA(%d): Failed to allocate pixmap private\n",
71105b261ecSmrg		       pScreen->myNum);
71205b261ecSmrg	    return FALSE;
71305b261ecSmrg        }
71405b261ecSmrg        pExaScr->SavedCreatePixmap = pScreen->CreatePixmap;
71505b261ecSmrg	pScreen->CreatePixmap = exaCreatePixmap;
71605b261ecSmrg
71705b261ecSmrg        pExaScr->SavedDestroyPixmap = pScreen->DestroyPixmap;
71805b261ecSmrg	pScreen->DestroyPixmap = exaDestroyPixmap;
71905b261ecSmrg
72005b261ecSmrg	LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %d bytes\n",
72105b261ecSmrg		   pScreen->myNum,
72205b261ecSmrg		   pExaScr->info->memorySize - pExaScr->info->offScreenBase);
72305b261ecSmrg    }
72405b261ecSmrg    else
72505b261ecSmrg    {
72605b261ecSmrg        LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum);
72705b261ecSmrg	if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex, 0))
72805b261ecSmrg	    return FALSE;
72905b261ecSmrg    }
73005b261ecSmrg
73105b261ecSmrg    DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase,
73205b261ecSmrg                pExaScr->info->memorySize));
73305b261ecSmrg    if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
73405b261ecSmrg	if (!exaOffscreenInit (pScreen)) {
73505b261ecSmrg            LogMessage(X_WARNING, "EXA(%d): Offscreen pixmap setup failed\n",
73605b261ecSmrg                       pScreen->myNum);
73705b261ecSmrg            return FALSE;
73805b261ecSmrg        }
73905b261ecSmrg    }
74005b261ecSmrg
74105b261ecSmrg    LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
74205b261ecSmrg	       " operations:\n", pScreen->myNum);
74305b261ecSmrg    assert(pScreenInfo->PrepareSolid != NULL);
74405b261ecSmrg    LogMessage(X_INFO, "        Solid\n");
74505b261ecSmrg    assert(pScreenInfo->PrepareCopy != NULL);
74605b261ecSmrg    LogMessage(X_INFO, "        Copy\n");
74705b261ecSmrg    if (pScreenInfo->PrepareComposite != NULL) {
74805b261ecSmrg	LogMessage(X_INFO, "        Composite (RENDER acceleration)\n");
74905b261ecSmrg    }
75005b261ecSmrg    if (pScreenInfo->UploadToScreen != NULL) {
75105b261ecSmrg	LogMessage(X_INFO, "        UploadToScreen\n");
75205b261ecSmrg    }
75305b261ecSmrg    if (pScreenInfo->DownloadFromScreen != NULL) {
75405b261ecSmrg	LogMessage(X_INFO, "        DownloadFromScreen\n");
75505b261ecSmrg    }
75605b261ecSmrg
75705b261ecSmrg    return TRUE;
75805b261ecSmrg}
75905b261ecSmrg
76005b261ecSmrg/**
76105b261ecSmrg * exaDriverFini tears down EXA on a given screen.
76205b261ecSmrg *
76305b261ecSmrg * @param pScreen screen being torn down.
76405b261ecSmrg */
76505b261ecSmrgvoid
76605b261ecSmrgexaDriverFini (ScreenPtr pScreen)
76705b261ecSmrg{
76805b261ecSmrg    /*right now does nothing*/
76905b261ecSmrg}
77005b261ecSmrg
77105b261ecSmrg/**
77205b261ecSmrg * exaMarkSync() should be called after any asynchronous drawing by the hardware.
77305b261ecSmrg *
77405b261ecSmrg * @param pScreen screen which drawing occurred on
77505b261ecSmrg *
77605b261ecSmrg * exaMarkSync() sets a flag to indicate that some asynchronous drawing has
77705b261ecSmrg * happened and a WaitSync() will be necessary before relying on the contents of
77805b261ecSmrg * offscreen memory from the CPU's perspective.  It also calls an optional
77905b261ecSmrg * driver MarkSync() callback, the return value of which may be used to do partial
78005b261ecSmrg * synchronization with the hardware in the future.
78105b261ecSmrg */
78205b261ecSmrgvoid exaMarkSync(ScreenPtr pScreen)
78305b261ecSmrg{
78405b261ecSmrg    ExaScreenPriv(pScreen);
78505b261ecSmrg
78605b261ecSmrg    pExaScr->info->needsSync = TRUE;
78705b261ecSmrg    if (pExaScr->info->MarkSync != NULL) {
78805b261ecSmrg        pExaScr->info->lastMarker = (*pExaScr->info->MarkSync)(pScreen);
78905b261ecSmrg    }
79005b261ecSmrg}
79105b261ecSmrg
79205b261ecSmrg/**
79305b261ecSmrg * exaWaitSync() ensures that all drawing has been completed.
79405b261ecSmrg *
79505b261ecSmrg * @param pScreen screen being synchronized.
79605b261ecSmrg *
79705b261ecSmrg * Calls down into the driver to ensure that all previous drawing has completed.
79805b261ecSmrg * It should always be called before relying on the framebuffer contents
79905b261ecSmrg * reflecting previous drawing, from a CPU perspective.
80005b261ecSmrg */
80105b261ecSmrgvoid exaWaitSync(ScreenPtr pScreen)
80205b261ecSmrg{
80305b261ecSmrg    ExaScreenPriv(pScreen);
80405b261ecSmrg
80505b261ecSmrg    if (pExaScr->info->needsSync && !pExaScr->swappedOut) {
80605b261ecSmrg        (*pExaScr->info->WaitMarker)(pScreen, pExaScr->info->lastMarker);
80705b261ecSmrg        pExaScr->info->needsSync = FALSE;
80805b261ecSmrg    }
80905b261ecSmrg}
810