atimach64exa.c revision e35d4d8e
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(xf86ScreenToScrn(pScreenInfo));
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 = xf86ScreenToScrn(pPix->drawable.pScreen);
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 = xf86ScreenToScrn(pDstPixmap->drawable.pScreen);
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 = xf86ScreenToScrn(pDstPixmap->drawable.pScreen);
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 = xf86ScreenToScrn(pPixmap->drawable.pScreen);
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 = xf86ScreenToScrn(pPixmap->drawable.pScreen);
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#include "atimach64render.c"
391
392/* Compute log base 2 of val. */
393static __inline__ int Mach64Log2(int val)
394{
395    int bits;
396
397    for (bits = 0; val != 0; val >>= 1, ++bits)
398        ;
399    return bits - 1;
400}
401
402/*
403 * Memory layour for EXA with DRI (no local_textures):
404 * | front  | back   | depth  | textures | pixmaps, xv | c |
405 *
406 * 1024x768@16bpp with 8 MB:
407 * | 1.5 MB | 1.5 MB | 1.5 MB | 0        | ~3.5 MB     | c |
408 *
409 * 1024x768@32bpp with 8 MB:
410 * | 3.0 MB | 3.0 MB | 1.5 MB | 0        | ~0.5 MB     | c |
411 *
412 * "c" is the hw cursor which occupies 1KB
413 */
414static void
415Mach64SetupMemEXA(ScreenPtr pScreen)
416{
417    ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
418    ATIPtr pATI = ATIPTR(pScreenInfo);
419
420    int cpp = (pScreenInfo->bitsPerPixel + 7) / 8;
421    /* front and back buffer */
422    int bufferSize = pScreenInfo->virtualY * pScreenInfo->displayWidth * cpp;
423    /* always 16-bit z-buffer */
424    int depthSize  = pScreenInfo->virtualY * pScreenInfo->displayWidth * 2;
425
426    ExaDriverPtr pExa = pATI->pExa;
427
428    pExa->memoryBase = pATI->pMemory;
429    pExa->memorySize = pScreenInfo->videoRam * 1024;
430    pExa->offScreenBase = bufferSize;
431
432#ifdef XF86DRI_DEVEL
433    if (pATI->directRenderingEnabled)
434    {
435	ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
436	Bool is_pci = pATIDRIServer->IsPCI;
437
438	int textureSize = 0;
439	int pixmapCache = 0;
440	int next = 0;
441
442	/* front buffer */
443	pATIDRIServer->frontOffset = 0;
444	pATIDRIServer->frontPitch = pScreenInfo->displayWidth;
445	next += bufferSize;
446
447	/* back buffer */
448	pATIDRIServer->backOffset = next;
449	pATIDRIServer->backPitch = pScreenInfo->displayWidth;
450	next += bufferSize;
451
452	/* depth buffer */
453	pATIDRIServer->depthOffset = next;
454	pATIDRIServer->depthPitch = pScreenInfo->displayWidth;
455	next += depthSize;
456
457	/* ATIScreenInit does check for the this condition. */
458	if (next > pExa->memorySize)
459	{
460	    xf86DrvMsg(pScreen->myNum, X_WARNING,
461		"DRI static buffer allocation failed, disabling DRI --"
462		"need at least %d kB video memory\n", next / 1024 );
463	    ATIDRICloseScreen(pScreen);
464	    pATI->directRenderingEnabled = FALSE;
465	}
466
467	/* local textures */
468
469	/* Reserve approx. half of offscreen memory for local textures */
470	textureSize = (pExa->memorySize - next) / 2;
471
472	/* In case DRI requires more offscreen memory than available,
473	 * should not happen as ATIScreenInit would have not enabled DRI */
474	if (textureSize < 0)
475	    textureSize = 0;
476
477	/* Try for enough pixmap cache for a full viewport */
478	pixmapCache = (pExa->memorySize - next) - textureSize;
479	if (pixmapCache < bufferSize)
480	    textureSize = 0;
481
482	/* Don't allocate a local texture heap for AGP unless requested */
483	if ( !is_pci && !pATI->OptionLocalTextures )
484	    textureSize = 0;
485
486	if (textureSize > 0)
487	{
488	    int l = Mach64Log2(textureSize / MACH64_NR_TEX_REGIONS);
489	    if (l < MACH64_LOG_TEX_GRANULARITY)
490		l = MACH64_LOG_TEX_GRANULARITY;
491	    pATIDRIServer->logTextureGranularity = l;
492
493	    /* Round the texture size down to the nearest whole number of
494	     * texture regions.
495	     */
496	    textureSize = (textureSize >> l) << l;
497	}
498
499	/* Set a minimum usable local texture heap size.  This will fit
500	 * two 256x256 textures.  We check this after any rounding of
501	 * the texture area.
502	 */
503	if (textureSize < 256*256 * cpp * 2)
504	    textureSize = 0;
505
506	/* Disable DRI for PCI if cannot allocate a local texture heap */
507	if ( is_pci && textureSize == 0 )
508	{
509	    xf86DrvMsg(pScreen->myNum, X_WARNING,
510		"Not enough memory for local textures, disabling DRI\n");
511	    ATIDRICloseScreen(pScreen);
512	    pATI->directRenderingEnabled = FALSE;
513	}
514
515	pATIDRIServer->textureOffset = next;
516	pATIDRIServer->textureSize = textureSize;
517	next += textureSize;
518
519	/* pExa->offScreenBase is moved to `next' when DRI gets activated */
520    }
521#endif /* XF86DRI_DEVEL */
522
523    xf86DrvMsg(pScreen->myNum, X_INFO,
524        "EXA memory management initialized\n"
525        "\t base     :  %10p\n"
526        "\t offscreen: +%10lx\n"
527        "\t size     : +%10lx\n"
528        "\t cursor   :  %10p\n",
529        pExa->memoryBase,
530        pExa->offScreenBase,
531        pExa->memorySize,
532        pATI->pCursorImage);
533
534    if (TRUE || xf86GetVerbosity() > 1)
535    {
536        int offscreen = pExa->memorySize - pExa->offScreenBase;
537        int viewport = bufferSize;
538        int dvdframe = 720*480*cpp; /* enough for single-buffered DVD */
539
540        xf86DrvMsg(pScreen->myNum, X_INFO,
541            "Will use %d kB of offscreen memory for EXA\n"
542            "\t\t or %5.2f viewports (composite)\n"
543            "\t\t or %5.2f dvdframes (xvideo)\n",
544            offscreen / 1024,
545            1.0 * offscreen / viewport,
546            1.0 * offscreen / dvdframe);
547    }
548
549#ifdef XF86DRI_DEVEL
550    if (pATI->directRenderingEnabled)
551    {
552        ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
553
554        xf86DrvMsg(pScreen->myNum, X_INFO,
555                   "Will use back  buffer at offset 0x%x\n",
556                   pATIDRIServer->backOffset);
557
558        xf86DrvMsg(pScreen->myNum, X_INFO,
559                   "Will use depth buffer at offset 0x%x\n",
560                   pATIDRIServer->depthOffset);
561
562        if (pATIDRIServer->textureSize > 0)
563        {
564            xf86DrvMsg(pScreen->myNum, X_INFO,
565                   "Will use %d kB for local textures at offset 0x%x\n",
566                   pATIDRIServer->textureSize/1024,
567                   pATIDRIServer->textureOffset);
568        }
569    }
570#endif /* XF86DRI_DEVEL */
571
572    pExa->pixmapOffsetAlign = 64;
573    pExa->pixmapPitchAlign = 64;
574
575    pExa->flags = EXA_OFFSCREEN_PIXMAPS;
576
577    pExa->maxX = ATIMach64MaxX;
578    pExa->maxY = ATIMach64MaxY;
579}
580
581Bool ATIMach64ExaInit(ScreenPtr pScreen)
582{
583    ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
584    ATIPtr pATI = ATIPTR(pScreenInfo);
585    ExaDriverPtr pExa;
586
587    pExa = exaDriverAlloc();
588    if (!pExa)
589        return FALSE;
590
591    pATI->pExa = pExa;
592
593    pExa->exa_major = 2;
594    pExa->exa_minor = 0;
595
596    Mach64SetupMemEXA(pScreen);
597
598    pExa->WaitMarker = Mach64WaitMarker;
599
600    pExa->PrepareSolid = Mach64PrepareSolid;
601    pExa->Solid = Mach64Solid;
602    pExa->DoneSolid = Mach64DoneSolid;
603
604    pExa->PrepareCopy = Mach64PrepareCopy;
605    pExa->Copy = Mach64Copy;
606    pExa->DoneCopy = Mach64DoneCopy;
607
608    if (pATI->RenderAccelEnabled) {
609	if (pATI->Chip >= ATI_CHIP_264GTPRO) {
610	    /* 3D Rage Pro does not support NPOT textures. */
611	    pExa->flags |= EXA_OFFSCREEN_ALIGN_POT;
612
613	    pExa->CheckComposite = Mach64CheckComposite;
614	    pExa->PrepareComposite = Mach64PrepareComposite;
615	    pExa->Composite = Mach64Composite;
616	    pExa->DoneComposite = Mach64DoneComposite;
617	} else {
618	    xf86DrvMsg(pScreen->myNum, X_INFO,
619		       "Render acceleration is not supported for ATI chips "
620		       "earlier than the ATI 3D Rage Pro.\n");
621	    pATI->RenderAccelEnabled = FALSE;
622	}
623    }
624
625    xf86DrvMsg(pScreen->myNum, X_INFO, "Render acceleration %s\n",
626	       pATI->RenderAccelEnabled ? "enabled" : "disabled");
627
628    if (!exaDriverInit(pScreen, pATI->pExa)) {
629	free(pATI->pExa);
630	pATI->pExa = NULL;
631	return FALSE;
632    }
633
634    return TRUE;
635}
636#endif
637