atimach64exa.c revision 1b12faf6
1/*
2 * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of Marc Aurele La France not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  Marc Aurele La France makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as-is" without express or implied warranty.
13 *
14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22/*
23 * Copyright 1999-2000 Precision Insight, Inc., Cedar Park, Texas.
24 * All Rights Reserved.
25 *
26 * Permission is hereby granted, free of charge, to any person obtaining a copy
27 * of this software and associated documentation files (the "Software"), to
28 * deal in the Software without restriction, including without limitation the
29 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
30 * sell copies of the Software, and to permit persons to whom the Software is
31 * furnished to do so, subject to the following conditions:
32 *
33 * The above copyright notice and this permission notice (including the next
34 * paragraph) shall be included in all copies or substantial portions of the
35 * Software.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
40 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
41 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
42 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
43 * DEALINGS IN THE SOFTWARE.
44 */
45/*
46 * DRI support by:
47 *    Manuel Teira
48 *    Leif Delgass <ldelgass@retinalburn.net>
49 *
50 * EXA support by:
51 *    Jakub Stachowski <qbast@go2.pl>
52 *    George Sapountzis <gsap7@yahoo.gr>
53 */
54
55#ifdef HAVE_CONFIG_H
56#include "config.h"
57#endif
58
59#include <string.h>
60
61#include "ati.h"
62#include "atichip.h"
63#include "atidri.h"
64#include "atimach64accel.h"
65#include "atimach64io.h"
66#include "atipriv.h"
67#include "atiregs.h"
68
69#ifdef XF86DRI_DEVEL
70#include "mach64_dri.h"
71#include "mach64_sarea.h"
72#endif
73
74#ifdef USE_EXA
75extern CARD8 ATIMach64ALU[];
76
77extern void
78ATIMach64ValidateClip
79(
80    ATIPtr pATI,
81    int sc_left,
82    int sc_right,
83    int sc_top,
84    int sc_bottom
85);
86
87#if 0
88#define MACH64_TRACE(x)				\
89do {						\
90    ErrorF("Mach64(%s): ", __FUNCTION__);	\
91    ErrorF x;					\
92} while(0)
93#else
94#define MACH64_TRACE(x) do { } while(0)
95#endif
96
97#if 0
98#define MACH64_FALLBACK(x)			\
99do {						\
100    ErrorF("Fallback(%s): ", __FUNCTION__);	\
101    ErrorF x;					\
102    return FALSE;				\
103} while (0)
104#else
105#define MACH64_FALLBACK(x) return FALSE
106#endif
107
108static void
109Mach64WaitMarker(ScreenPtr pScreenInfo, int Marker)
110{
111    ATIMach64Sync(xf86Screens[pScreenInfo->myNum]);
112}
113
114static Bool
115Mach64GetDatatypeBpp(PixmapPtr pPix, CARD32 *pix_width)
116{
117	int bpp = pPix->drawable.bitsPerPixel;
118
119	switch (bpp) {
120	case 8:
121		*pix_width =
122			SetBits(PIX_WIDTH_8BPP, DP_DST_PIX_WIDTH) |
123			SetBits(PIX_WIDTH_8BPP, DP_SRC_PIX_WIDTH) |
124			SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
125		break;
126	case 16:
127		*pix_width =
128			SetBits(PIX_WIDTH_16BPP, DP_DST_PIX_WIDTH) |
129			SetBits(PIX_WIDTH_16BPP, DP_SRC_PIX_WIDTH) |
130			SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
131		break;
132	case 24:
133		*pix_width =
134			SetBits(PIX_WIDTH_8BPP, DP_DST_PIX_WIDTH) |
135			SetBits(PIX_WIDTH_8BPP, DP_SRC_PIX_WIDTH) |
136			SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
137		break;
138	case 32:
139		*pix_width =
140			SetBits(PIX_WIDTH_32BPP, DP_DST_PIX_WIDTH) |
141			SetBits(PIX_WIDTH_32BPP, DP_SRC_PIX_WIDTH) |
142			SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
143		break;
144	default:
145		MACH64_FALLBACK(("Unsupported bpp: %d\n", bpp));
146	}
147
148#if X_BYTE_ORDER == X_LITTLE_ENDIAN
149
150        *pix_width |= DP_BYTE_PIX_ORDER;
151
152#endif /* X_BYTE_ORDER */
153
154	return TRUE;
155}
156
157static Bool
158Mach64GetOffsetPitch(PixmapPtr pPix, int bpp, CARD32 *pitch_offset,
159		     unsigned int offset, unsigned int pitch)
160{
161#if 0
162    ScrnInfoPtr pScreenInfo = xf86Screens[pPix->drawable.pScreen->myNum];
163    ATIPtr pATI = ATIPTR(pScreenInfo);
164
165    if (pitch % pATI->pExa->pixmapPitchAlign != 0)
166        MACH64_FALLBACK(("Bad pitch 0x%08x\n", pitch));
167
168    if (offset % pATI->pExa->pixmapOffsetAlign != 0)
169        MACH64_FALLBACK(("Bad offset 0x%08x\n", offset));
170#endif
171
172    /* pixels / 8 = ((bytes * 8) / bpp) / 8 = bytes / bpp */
173    pitch = pitch / bpp;
174
175    /* bytes / 8 */
176    offset = offset >> 3;
177
178    *pitch_offset = ((pitch  << 22) | (offset <<  0));
179
180    return TRUE;
181}
182
183static Bool
184Mach64GetPixmapOffsetPitch(PixmapPtr pPix, CARD32 *pitch_offset)
185{
186    CARD32 pitch, offset;
187    int bpp;
188
189    bpp = pPix->drawable.bitsPerPixel;
190    if (bpp == 24)
191        bpp = 8;
192
193    pitch = exaGetPixmapPitch(pPix);
194    offset = exaGetPixmapOffset(pPix);
195
196    return Mach64GetOffsetPitch(pPix, bpp, pitch_offset, offset, pitch);
197}
198
199static Bool
200Mach64PrepareCopy
201(
202    PixmapPtr pSrcPixmap,
203    PixmapPtr pDstPixmap,
204    int       xdir,
205    int       ydir,
206    int       alu,
207    Pixel     planemask
208)
209{
210    ScrnInfoPtr pScreenInfo = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
211    ATIPtr pATI = ATIPTR(pScreenInfo);
212    CARD32 src_pitch_offset, dst_pitch_offset, dp_pix_width;
213
214    ATIDRISync(pScreenInfo);
215
216    if (!Mach64GetDatatypeBpp(pDstPixmap, &dp_pix_width))
217        return FALSE;
218    if (!Mach64GetPixmapOffsetPitch(pSrcPixmap, &src_pitch_offset))
219        return FALSE;
220    if (!Mach64GetPixmapOffsetPitch(pDstPixmap, &dst_pitch_offset))
221        return FALSE;
222
223    ATIMach64WaitForFIFO(pATI, 7);
224    outf(DP_WRITE_MASK, planemask);
225    outf(DP_PIX_WIDTH, dp_pix_width);
226    outf(SRC_OFF_PITCH, src_pitch_offset);
227    outf(DST_OFF_PITCH, dst_pitch_offset);
228
229    outf(DP_SRC, DP_MONO_SRC_ALLONES |
230        SetBits(SRC_BLIT, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC));
231    outf(DP_MIX, SetBits(ATIMach64ALU[alu], DP_FRGD_MIX));
232
233    outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE);
234
235    pATI->dst_cntl = 0;
236
237    if (ydir > 0)
238        pATI->dst_cntl |= DST_Y_DIR;
239    if (xdir > 0)
240        pATI->dst_cntl |= DST_X_DIR;
241
242    if (pATI->XModifier == 1)
243        outf(DST_CNTL, pATI->dst_cntl);
244    else
245        pATI->dst_cntl |= DST_24_ROT_EN;
246
247    return TRUE;
248}
249
250static void
251Mach64Copy
252(
253    PixmapPtr pDstPixmap,
254    int       srcX,
255    int       srcY,
256    int       dstX,
257    int       dstY,
258    int       w,
259    int       h
260)
261{
262    ScrnInfoPtr pScreenInfo = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
263    ATIPtr pATI = ATIPTR(pScreenInfo);
264
265    srcX *= pATI->XModifier;
266    dstY *= pATI->XModifier;
267    w    *= pATI->XModifier;
268
269    ATIDRISync(pScreenInfo);
270
271    /* Disable clipping if it gets in the way */
272    ATIMach64ValidateClip(pATI, dstX, dstX + w - 1, dstY, dstY + h - 1);
273
274    if (!(pATI->dst_cntl & DST_X_DIR))
275    {
276        srcX += w - 1;
277        dstX += w - 1;
278    }
279
280    if (!(pATI->dst_cntl & DST_Y_DIR))
281    {
282        srcY += h - 1;
283        dstY += h - 1;
284    }
285
286    if (pATI->XModifier != 1)
287        outf(DST_CNTL, pATI->dst_cntl | SetBits((dstX / 4) % 6, DST_24_ROT));
288
289    ATIMach64WaitForFIFO(pATI, 4);
290    outf(SRC_Y_X, SetWord(srcX, 1) | SetWord(srcY, 0));
291    outf(SRC_WIDTH1, w);
292    outf(DST_Y_X, SetWord(dstX, 1) | SetWord(dstY, 0));
293    outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0));
294
295    /*
296     * On VTB's and later, the engine will randomly not wait for a copy
297     * operation to commit its results to video memory before starting the next
298     * one.  The probability of such occurrences increases with GUI_WB_FLUSH
299     * (or GUI_WB_FLUSH_P) setting, bitsPerPixel and/or CRTC clock.  This
300     * would point to some kind of video memory bandwidth problem were it noti
301     * for the fact that the problem occurs less often (but still occurs) when
302     * copying larger rectangles.
303     */
304    if ((pATI->Chip >= ATI_CHIP_264VTB) && !pATI->OptionDevel)
305    {
306        exaMarkSync(pScreenInfo->pScreen); /* Force sync. */
307        exaWaitSync(pScreenInfo->pScreen); /* Sync and notify EXA. */
308    }
309}
310
311static void Mach64DoneCopy(PixmapPtr pDstPixmap) { }
312
313static Bool
314Mach64PrepareSolid
315(
316    PixmapPtr pPixmap,
317    int       alu,
318    Pixel     planemask,
319    Pixel     fg
320)
321{
322    ScrnInfoPtr pScreenInfo = xf86Screens[pPixmap->drawable.pScreen->myNum];
323    ATIPtr pATI = ATIPTR(pScreenInfo);
324    CARD32 dst_pitch_offset, dp_pix_width;
325
326    ATIDRISync(pScreenInfo);
327
328    if (!Mach64GetDatatypeBpp(pPixmap, &dp_pix_width))
329        return FALSE;
330    if (!Mach64GetPixmapOffsetPitch(pPixmap, &dst_pitch_offset))
331        return FALSE;
332
333    ATIMach64WaitForFIFO(pATI, 7);
334    outf(DP_WRITE_MASK, planemask);
335    outf(DP_PIX_WIDTH, dp_pix_width);
336    outf(DST_OFF_PITCH, dst_pitch_offset);
337
338    outf(DP_SRC, DP_MONO_SRC_ALLONES |
339        SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC));
340    outf(DP_FRGD_CLR, fg);
341    outf(DP_MIX, SetBits(ATIMach64ALU[alu], DP_FRGD_MIX));
342
343    outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE);
344
345    if (pATI->XModifier == 1)
346        outf(DST_CNTL, DST_X_DIR | DST_Y_DIR);
347
348    return TRUE;
349}
350
351static void
352Mach64Solid
353(
354    PixmapPtr pPixmap,
355    int       x1,
356    int       y1,
357    int       x2,
358    int       y2
359)
360{
361    ScrnInfoPtr pScreenInfo = xf86Screens[pPixmap->drawable.pScreen->myNum];
362    ATIPtr pATI = ATIPTR(pScreenInfo);
363
364    int x = x1;
365    int y = y1;
366    int w = x2-x1;
367    int h = y2-y1;
368
369    ATIDRISync(pScreenInfo);
370
371    if (pATI->XModifier != 1)
372    {
373        x *= pATI->XModifier;
374        w *= pATI->XModifier;
375
376        outf(DST_CNTL, SetBits((x / 4) % 6, DST_24_ROT) |
377            (DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN));
378    }
379
380    /* Disable clipping if it gets in the way */
381    ATIMach64ValidateClip(pATI, x, x + w - 1, y, y + h - 1);
382
383    ATIMach64WaitForFIFO(pATI, 2);
384    outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0));
385    outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0));
386}
387
388static void Mach64DoneSolid(PixmapPtr pPixmap) { }
389
390/*
391 * Memcpy-based UTS.
392 */
393static Bool
394Mach64UploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
395    char *src, int src_pitch)
396{
397    char  *dst        = pDst->devPrivate.ptr;
398    int    dst_pitch  = exaGetPixmapPitch(pDst);
399
400    int bpp    = pDst->drawable.bitsPerPixel;
401    int cpp    = (bpp + 7) / 8;
402    int wBytes = w * cpp;
403
404    exaWaitSync(pDst->drawable.pScreen);
405
406    dst += (x * cpp) + (y * dst_pitch);
407
408    while (h--) {
409        memcpy(dst, src, wBytes);
410        src += src_pitch;
411        dst += dst_pitch;
412    }
413
414    return TRUE;
415}
416
417/*
418 * Memcpy-based DFS.
419 */
420static Bool
421Mach64DownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
422    char *dst, int dst_pitch)
423{
424    char  *src        = pSrc->devPrivate.ptr;
425    int    src_pitch  = exaGetPixmapPitch(pSrc);
426
427    int bpp    = pSrc->drawable.bitsPerPixel;
428    int cpp    = (bpp + 7) / 8;
429    int wBytes = w * cpp;
430
431    exaWaitSync(pSrc->drawable.pScreen);
432
433    src += (x * cpp) + (y * src_pitch);
434
435    while (h--) {
436        memcpy(dst, src, wBytes);
437        src += src_pitch;
438        dst += dst_pitch;
439    }
440
441    return TRUE;
442}
443
444#include "atimach64render.c"
445
446/* Compute log base 2 of val. */
447static __inline__ int Mach64Log2(int val)
448{
449    int bits;
450
451    for (bits = 0; val != 0; val >>= 1, ++bits)
452        ;
453    return bits - 1;
454}
455
456/*
457 * Memory layour for EXA with DRI (no local_textures):
458 * | front  | back   | depth  | textures | pixmaps, xv | c |
459 *
460 * 1024x768@16bpp with 8 MB:
461 * | 1.5 MB | 1.5 MB | 1.5 MB | 0        | ~3.5 MB     | c |
462 *
463 * 1024x768@32bpp with 8 MB:
464 * | 3.0 MB | 3.0 MB | 1.5 MB | 0        | ~0.5 MB     | c |
465 *
466 * "c" is the hw cursor which occupies 1KB
467 */
468static void
469Mach64SetupMemEXA(ScreenPtr pScreen)
470{
471    ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum];
472    ATIPtr pATI = ATIPTR(pScreenInfo);
473
474    int cpp = (pScreenInfo->bitsPerPixel + 7) / 8;
475    /* front and back buffer */
476    int bufferSize = pScreenInfo->virtualY * pScreenInfo->displayWidth * cpp;
477    /* always 16-bit z-buffer */
478    int depthSize  = pScreenInfo->virtualY * pScreenInfo->displayWidth * 2;
479
480    ExaDriverPtr pExa = pATI->pExa;
481
482    pExa->memoryBase = pATI->pMemory;
483    pExa->memorySize = pScreenInfo->videoRam * 1024;
484    pExa->offScreenBase = bufferSize;
485
486#ifdef XF86DRI_DEVEL
487    if (pATI->directRenderingEnabled)
488    {
489	ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
490	Bool is_pci = pATIDRIServer->IsPCI;
491
492	int textureSize = 0;
493	int pixmapCache = 0;
494	int next = 0;
495
496	/* front buffer */
497	pATIDRIServer->frontOffset = 0;
498	pATIDRIServer->frontPitch = pScreenInfo->displayWidth;
499	next += bufferSize;
500
501	/* back buffer */
502	pATIDRIServer->backOffset = next;
503	pATIDRIServer->backPitch = pScreenInfo->displayWidth;
504	next += bufferSize;
505
506	/* depth buffer */
507	pATIDRIServer->depthOffset = next;
508	pATIDRIServer->depthPitch = pScreenInfo->displayWidth;
509	next += depthSize;
510
511	/* ATIScreenInit does check for the this condition. */
512	if (next > pExa->memorySize)
513	{
514	    xf86DrvMsg(pScreen->myNum, X_WARNING,
515		"DRI static buffer allocation failed, disabling DRI --"
516		"need at least %d kB video memory\n", next / 1024 );
517	    ATIDRICloseScreen(pScreen);
518	    pATI->directRenderingEnabled = FALSE;
519	}
520
521	/* local textures */
522
523	/* Reserve approx. half of offscreen memory for local textures */
524	textureSize = (pExa->memorySize - next) / 2;
525
526	/* In case DRI requires more offscreen memory than available,
527	 * should not happen as ATIScreenInit would have not enabled DRI */
528	if (textureSize < 0)
529	    textureSize = 0;
530
531	/* Try for enough pixmap cache for a full viewport */
532	pixmapCache = (pExa->memorySize - next) - textureSize;
533	if (pixmapCache < bufferSize)
534	    textureSize = 0;
535
536	/* Don't allocate a local texture heap for AGP unless requested */
537	if ( !is_pci && !pATI->OptionLocalTextures )
538	    textureSize = 0;
539
540	if (textureSize > 0)
541	{
542	    int l = Mach64Log2(textureSize / MACH64_NR_TEX_REGIONS);
543	    if (l < MACH64_LOG_TEX_GRANULARITY)
544		l = MACH64_LOG_TEX_GRANULARITY;
545	    pATIDRIServer->logTextureGranularity = l;
546
547	    /* Round the texture size down to the nearest whole number of
548	     * texture regions.
549	     */
550	    textureSize = (textureSize >> l) << l;
551	}
552
553	/* Set a minimum usable local texture heap size.  This will fit
554	 * two 256x256 textures.  We check this after any rounding of
555	 * the texture area.
556	 */
557	if (textureSize < 256*256 * cpp * 2)
558	    textureSize = 0;
559
560	/* Disable DRI for PCI if cannot allocate a local texture heap */
561	if ( is_pci && textureSize == 0 )
562	{
563	    xf86DrvMsg(pScreen->myNum, X_WARNING,
564		"Not enough memory for local textures, disabling DRI\n");
565	    ATIDRICloseScreen(pScreen);
566	    pATI->directRenderingEnabled = FALSE;
567	}
568
569	pATIDRIServer->textureOffset = next;
570	pATIDRIServer->textureSize = textureSize;
571	next += textureSize;
572
573	/* pExa->offScreenBase is moved to `next' when DRI gets activated */
574    }
575#endif /* XF86DRI_DEVEL */
576
577    xf86DrvMsg(pScreen->myNum, X_INFO,
578        "EXA memory management initialized\n"
579        "\t base     :  %10p\n"
580        "\t offscreen: +%10lx\n"
581        "\t size     : +%10lx\n"
582        "\t cursor   :  %10p\n",
583        pExa->memoryBase,
584        pExa->offScreenBase,
585        pExa->memorySize,
586        pATI->pCursorImage);
587
588    if (TRUE || xf86GetVerbosity() > 1)
589    {
590        int offscreen = pExa->memorySize - pExa->offScreenBase;
591        int viewport = bufferSize;
592        int dvdframe = 720*480*cpp; /* enough for single-buffered DVD */
593
594        xf86DrvMsg(pScreen->myNum, X_INFO,
595            "Will use %d kB of offscreen memory for EXA\n"
596            "\t\t or %5.2f viewports (composite)\n"
597            "\t\t or %5.2f dvdframes (xvideo)\n",
598            offscreen / 1024,
599            1.0 * offscreen / viewport,
600            1.0 * offscreen / dvdframe);
601    }
602
603#ifdef XF86DRI_DEVEL
604    if (pATI->directRenderingEnabled)
605    {
606        ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
607
608        xf86DrvMsg(pScreen->myNum, X_INFO,
609                   "Will use back  buffer at offset 0x%x\n",
610                   pATIDRIServer->backOffset);
611
612        xf86DrvMsg(pScreen->myNum, X_INFO,
613                   "Will use depth buffer at offset 0x%x\n",
614                   pATIDRIServer->depthOffset);
615
616        if (pATIDRIServer->textureSize > 0)
617        {
618            xf86DrvMsg(pScreen->myNum, X_INFO,
619                   "Will use %d kB for local textures at offset 0x%x\n",
620                   pATIDRIServer->textureSize/1024,
621                   pATIDRIServer->textureOffset);
622        }
623    }
624#endif /* XF86DRI_DEVEL */
625
626    pExa->pixmapOffsetAlign = 64;
627    pExa->pixmapPitchAlign = 64;
628
629    pExa->flags = EXA_OFFSCREEN_PIXMAPS;
630
631    pExa->maxX = ATIMach64MaxX;
632    pExa->maxY = ATIMach64MaxY;
633}
634
635Bool ATIMach64ExaInit(ScreenPtr pScreen)
636{
637    ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum];
638    ATIPtr pATI = ATIPTR(pScreenInfo);
639    ExaDriverPtr pExa;
640
641    pExa = exaDriverAlloc();
642    if (!pExa)
643        return FALSE;
644
645    pATI->pExa = pExa;
646
647    pExa->exa_major = 2;
648    pExa->exa_minor = 0;
649
650    Mach64SetupMemEXA(pScreen);
651
652    pExa->WaitMarker = Mach64WaitMarker;
653
654    pExa->PrepareSolid = Mach64PrepareSolid;
655    pExa->Solid = Mach64Solid;
656    pExa->DoneSolid = Mach64DoneSolid;
657
658    pExa->PrepareCopy = Mach64PrepareCopy;
659    pExa->Copy = Mach64Copy;
660    pExa->DoneCopy = Mach64DoneCopy;
661
662    /* EXA hits more optimized paths when it does not have to fallback because
663     * of missing UTS/DFS, hook memcpy-based UTS/DFS.
664     */
665    pExa->UploadToScreen = Mach64UploadToScreen;
666    pExa->DownloadFromScreen = Mach64DownloadFromScreen;
667
668    if (pATI->RenderAccelEnabled) {
669	if (pATI->Chip >= ATI_CHIP_264GTPRO) {
670	    /* 3D Rage Pro does not support NPOT textures. */
671	    pExa->flags |= EXA_OFFSCREEN_ALIGN_POT;
672
673	    pExa->CheckComposite = Mach64CheckComposite;
674	    pExa->PrepareComposite = Mach64PrepareComposite;
675	    pExa->Composite = Mach64Composite;
676	    pExa->DoneComposite = Mach64DoneComposite;
677	} else {
678	    xf86DrvMsg(pScreen->myNum, X_INFO,
679		       "Render acceleration is not supported for ATI chips "
680		       "earlier than the ATI 3D Rage Pro.\n");
681	    pATI->RenderAccelEnabled = FALSE;
682	}
683    }
684
685    xf86DrvMsg(pScreen->myNum, X_INFO, "Render acceleration %s\n",
686	       pATI->RenderAccelEnabled ? "enabled" : "disabled");
687
688    if (!exaDriverInit(pScreen, pATI->pExa)) {
689	free(pATI->pExa);
690	pATI->pExa = NULL;
691	return FALSE;
692    }
693
694    return TRUE;
695}
696#endif
697