atiscreen.c revision 32b578d3
1/*
2 * Copyright 1999 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 * DRI support by:
23 *    Gareth Hughes <gareth@valinux.com>
24 *    José Fonseca <j_r_fonseca@yahoo.co.uk>
25 *    Leif Delgass <ldelgass@retinalburn.net>
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <string.h>
33
34#include "ati.h"
35#include "atibus.h"
36#include "atichip.h"
37#include "aticonsole.h"
38#include "aticursor.h"
39#include "atidac.h"
40#include "atidga.h"
41#include "atidri.h"
42#include "atimach64.h"
43#include "atimode.h"
44#include "atiscreen.h"
45#include "atistruct.h"
46#include "atixv.h"
47#include "atimach64accel.h"
48
49#ifdef XF86DRI_DEVEL
50#include "mach64_dri.h"
51#include "mach64_sarea.h"
52#endif
53
54#ifdef TV_OUT
55
56#include "atichip.h"
57
58#endif /* TV_OUT */
59
60#include "shadowfb.h"
61#include "xf86cmap.h"
62
63#include "fb.h"
64
65#include "micmap.h"
66#include "mipointer.h"
67
68/*
69 * ATIRefreshArea --
70 *
71 * This function is called by the shadow frame buffer code to refresh the
72 * hardware frame buffer.
73 */
74static void
75ATIRefreshArea
76(
77    ScrnInfoPtr pScreenInfo,
78    int         nBox,
79    BoxPtr      pBox
80)
81{
82    ATIPtr  pATI = ATIPTR(pScreenInfo);
83    pointer pSrc, pDst;
84    int     offset, w, h;
85
86    while (nBox-- > 0)
87    {
88        w = (pBox->x2 - pBox->x1) * pATI->AdjustDepth;
89        h = pBox->y2 - pBox->y1;
90        offset = (pBox->y1 * pATI->FBPitch) + (pBox->x1 * pATI->AdjustDepth);
91        pSrc = (char *)pATI->pShadow + offset;
92        pDst = (char *)pATI->pMemory + offset;
93
94        while (h-- > 0)
95        {
96            (void)memcpy(pDst, pSrc, w);
97            pSrc = (char *)pSrc + pATI->FBPitch;
98            pDst = (char *)pDst + pATI->FBPitch;
99        }
100
101        pBox++;
102    }
103}
104
105/*
106 * ATIMinBits --
107 *
108 * Compute log base 2 of val.
109 */
110static int
111ATIMinBits
112(
113    int val
114)
115{
116    int bits;
117
118    if (!val) return 1;
119    for (bits = 0; val; val >>= 1, ++bits);
120    return bits;
121}
122
123#ifdef USE_XAA
124static Bool
125ATIMach64SetupMemXAA_NoDRI
126(
127    int       iScreen,
128    ScreenPtr pScreen
129)
130{
131    ScrnInfoPtr  pScreenInfo = xf86Screens[iScreen];
132    ATIPtr       pATI        = ATIPTR(pScreenInfo);
133
134    int maxScanlines = ATIMach64MaxY;
135    int maxPixelArea, PixelArea;
136
137    {
138        /*
139         * Note:  If PixelArea exceeds the engine's maximum, the excess is
140         *        never used, even though it would be useful for such things
141         *        as XVideo buffers.
142         */
143        maxPixelArea = maxScanlines * pScreenInfo->displayWidth;
144        PixelArea = pScreenInfo->videoRam * 1024 * 8 / pATI->bitsPerPixel;
145        if (PixelArea > maxPixelArea)
146            PixelArea = maxPixelArea;
147        xf86InitFBManagerArea(pScreen, PixelArea, 2);
148    }
149
150    return TRUE;
151}
152
153#ifdef XF86DRI_DEVEL
154/*
155 * Memory layour for XAA with DRI (no local_textures):
156 * | front  | pixmaps, xv | back   | depth  | textures | c |
157 *
158 * 1024x768@16bpp with 8 MB:
159 * | 1.5 MB | ~3.5 MB     | 1.5 MB | 1.5 MB | 0        | c |
160 *
161 * 1024x768@32bpp with 8 MB:
162 * | 3.0 MB | ~0.5 MB     | 3.0 MB | 1.5 MB | 0        | c |
163 *
164 * "c" is the hw cursor which occupies 1KB
165 */
166static Bool
167ATIMach64SetupMemXAA
168(
169    int       iScreen,
170    ScreenPtr pScreen
171)
172{
173	ScrnInfoPtr  pScreenInfo = xf86Screens[iScreen];
174	ATIPtr       pATI        = ATIPTR(pScreenInfo);
175
176	ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
177	int cpp = pATI->bitsPerPixel >> 3;
178	int widthBytes = pScreenInfo->displayWidth * cpp;
179	int zWidthBytes = pScreenInfo->displayWidth * 2; /* always 16-bit z-buffer */
180	int fbSize = pScreenInfo->videoRam * 1024;
181	int bufferSize = pScreenInfo->virtualY * widthBytes;
182	int zBufferSize = pScreenInfo->virtualY * zWidthBytes;
183	int offscreenBytes, total, scanlines;
184
185	pATIDRIServer->fbX = 0;
186	pATIDRIServer->fbY = 0;
187	pATIDRIServer->frontOffset = 0;
188	pATIDRIServer->frontPitch = pScreenInfo->displayWidth;
189
190	/* Calculate memory remaining for pixcache and textures after
191	 * front, back, and depth buffers
192	 */
193	offscreenBytes = fbSize - ( 2 * bufferSize + zBufferSize );
194
195	if ( !pATIDRIServer->IsPCI && !pATI->OptionLocalTextures ) {
196	    /* Don't allocate a local texture heap for AGP unless requested */
197	    pATIDRIServer->textureSize = 0;
198	} else {
199	    int l, maxPixcache;
200
201#ifdef XvExtension
202
203	    int xvBytes;
204
205	    /* Try for enough pixmap cache for DVD and a full viewport
206	     */
207	    xvBytes = 720*480*cpp; /* enough for single-buffered DVD */
208	    maxPixcache = xvBytes > bufferSize ? xvBytes : bufferSize;
209
210#else /* XvExtension */
211
212	    /* Try for one viewport */
213	    maxPixcache = bufferSize;
214
215#endif /* XvExtension */
216
217	    pATIDRIServer->textureSize = offscreenBytes - maxPixcache;
218
219	    /* If that gives us less than half the offscreen mem available for textures, split
220	     * the available mem between textures and pixmap cache
221	     */
222	    if (pATIDRIServer->textureSize < (offscreenBytes/2)) {
223		pATIDRIServer->textureSize = offscreenBytes/2;
224	    }
225
226	    if (pATIDRIServer->textureSize <= 0)
227		pATIDRIServer->textureSize = 0;
228
229	    l = ATIMinBits((pATIDRIServer->textureSize-1) / MACH64_NR_TEX_REGIONS);
230	    if (l < MACH64_LOG_TEX_GRANULARITY) l = MACH64_LOG_TEX_GRANULARITY;
231
232	    /* Round the texture size up to the nearest whole number of
233	     * texture regions.  Again, be greedy about this, don't round
234	     * down.
235	     */
236	    pATIDRIServer->logTextureGranularity = l;
237	    pATIDRIServer->textureSize =
238		(pATIDRIServer->textureSize >> l) << l;
239	}
240
241	total = fbSize - pATIDRIServer->textureSize;
242	scanlines = total / widthBytes;
243	if (scanlines > ATIMach64MaxY) scanlines = ATIMach64MaxY;
244
245	/* Recalculate the texture offset and size to accomodate any
246	 * rounding to a whole number of scanlines.
247	 * FIXME: Is this actually needed?
248	 */
249	pATIDRIServer->textureOffset = scanlines * widthBytes;
250	pATIDRIServer->textureSize = fbSize - pATIDRIServer->textureOffset;
251
252	/* Set a minimum usable local texture heap size.  This will fit
253	 * two 256x256 textures.  We check this after any rounding of
254	 * the texture area.
255	 */
256	if (pATIDRIServer->textureSize < 256*256 * cpp * 2) {
257	    pATIDRIServer->textureOffset = 0;
258	    pATIDRIServer->textureSize = 0;
259	    scanlines = fbSize / widthBytes;
260	    if (scanlines > ATIMach64MaxY) scanlines = ATIMach64MaxY;
261	}
262
263	pATIDRIServer->depthOffset = scanlines * widthBytes - zBufferSize;
264	pATIDRIServer->depthPitch = pScreenInfo->displayWidth;
265	pATIDRIServer->depthY = pATIDRIServer->depthOffset/widthBytes;
266	pATIDRIServer->depthX =  (pATIDRIServer->depthOffset -
267				  (pATIDRIServer->depthY * widthBytes)) / cpp;
268
269	pATIDRIServer->backOffset = pATIDRIServer->depthOffset - bufferSize;
270	pATIDRIServer->backPitch = pScreenInfo->displayWidth;
271	pATIDRIServer->backY = pATIDRIServer->backOffset/widthBytes;
272	pATIDRIServer->backX =  (pATIDRIServer->backOffset -
273				  (pATIDRIServer->backY * widthBytes)) / cpp;
274
275	scanlines = fbSize / widthBytes;
276	if (scanlines > ATIMach64MaxY) scanlines = ATIMach64MaxY;
277
278	if ( pATIDRIServer->IsPCI && pATIDRIServer->textureSize == 0 ) {
279	    xf86DrvMsg(iScreen, X_WARNING,
280		       "Not enough memory for local textures, disabling DRI\n");
281	    ATIDRICloseScreen(pScreen);
282	    pATI->directRenderingEnabled = FALSE;
283	} else {
284	    BoxRec ScreenArea;
285
286	    ScreenArea.x1 = 0;
287	    ScreenArea.y1 = 0;
288	    ScreenArea.x2 = pATI->displayWidth;
289	    ScreenArea.y2 = scanlines;
290
291	    if (!xf86InitFBManager(pScreen, &ScreenArea)) {
292		xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
293			   "Memory manager initialization to (%d,%d) (%d,%d) failed\n",
294			   ScreenArea.x1, ScreenArea.y1,
295			   ScreenArea.x2, ScreenArea.y2);
296		return FALSE;
297	    } else {
298		int width, height;
299
300		xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
301			   "Memory manager initialized to (%d,%d) (%d,%d)\n",
302			   ScreenArea.x1, ScreenArea.y1, ScreenArea.x2, ScreenArea.y2);
303
304		if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0)) {
305		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
306			       "Largest offscreen area available: %d x %d\n",
307			       width, height);
308
309		    /* lines in offscreen area needed for depth buffer and textures */
310		    pATI->depthTexLines = scanlines
311			- pATIDRIServer->depthOffset / widthBytes;
312		    pATI->backLines     = scanlines
313			- pATIDRIServer->backOffset / widthBytes
314			- pATI->depthTexLines;
315		    pATI->depthTexArea  = NULL;
316		    pATI->backArea      = NULL;
317		} else {
318		    xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
319			       "Unable to determine largest offscreen area available\n");
320		    return FALSE;
321		}
322
323	    }
324
325	    xf86DrvMsg(iScreen, X_INFO, "Will use %d kB of offscreen memory for XAA\n",
326		       (offscreenBytes - pATIDRIServer->textureSize)/1024);
327
328	    xf86DrvMsg(iScreen, X_INFO, "Will use back buffer at offset 0x%x\n",
329		       pATIDRIServer->backOffset);
330
331	    xf86DrvMsg(iScreen, X_INFO, "Will use depth buffer at offset 0x%x\n",
332		       pATIDRIServer->depthOffset);
333
334	    if (pATIDRIServer->textureSize > 0) {
335		xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
336			   "Will use %d kB for local textures at offset 0x%x\n",
337			   pATIDRIServer->textureSize/1024,
338			   pATIDRIServer->textureOffset);
339	    }
340	}
341
342	return TRUE;
343}
344#endif /* XF86DRI_DEVEL */
345#endif /* USE_XAA */
346
347/*
348 * ATIScreenInit --
349 *
350 * This function is called by DIX to initialise the screen.
351 */
352Bool
353ATIScreenInit
354(
355    int       iScreen,
356    ScreenPtr pScreen,
357    int       argc,
358    char      **argv
359)
360{
361    ScrnInfoPtr  pScreenInfo = xf86Screens[iScreen];
362    ATIPtr       pATI        = ATIPTR(pScreenInfo);
363    pointer      pFB;
364    int          VisualMask;
365
366    /* Set video hardware state */
367    if (!ATIEnterGraphics(pScreen, pScreenInfo, pATI))
368        return FALSE;
369
370    /* Re-initialise mi's visual list */
371    miClearVisualTypes();
372
373    if ((pATI->depth > 8) && (pATI->DAC == ATI_DAC_INTERNAL))
374        VisualMask = TrueColorMask;
375    else
376        VisualMask = miGetDefaultVisualMask(pATI->depth);
377
378    if (!miSetVisualTypes(pATI->depth, VisualMask, pATI->rgbBits,
379                          pScreenInfo->defaultVisual))
380        return FALSE;
381
382    if (!miSetPixmapDepths())
383        return FALSE;
384
385    pFB = pATI->pMemory;
386    pATI->FBPitch = PixmapBytePad(pATI->displayWidth, pATI->depth);
387    if (pATI->OptionShadowFB)
388    {
389        pATI->FBBytesPerPixel = pATI->bitsPerPixel >> 3;
390        pATI->FBPitch = PixmapBytePad(pATI->displayWidth, pATI->depth);
391        if ((pATI->pShadow = xalloc(pATI->FBPitch * pScreenInfo->virtualY)))
392        {
393            pFB = pATI->pShadow;
394        }
395        else
396        {
397            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
398                "Insufficient virtual memory for shadow frame buffer.\n");
399            pATI->OptionShadowFB = FALSE;
400        }
401    }
402
403#ifdef XF86DRI_DEVEL
404
405    /* Setup DRI after visuals have been established, but before
406     * fbScreenInit is called.  fbScreenInit will eventually call the
407     * driver's InitGLXVisuals call back.
408     */
409
410    /* According to atiregs.h, GTPro (3D Rage Pro) is the first chip type with
411     * 3D triangle setup (the VERTEX_* registers)
412     */
413    if (pATI->Chip < ATI_CHIP_264GTPRO) {
414	xf86DrvMsg(iScreen, X_WARNING,
415		   "Direct rendering is not supported for ATI chips earlier than "
416		   "the ATI 3D Rage Pro.\n");
417	pATI->directRenderingEnabled = FALSE;
418    } else {
419	/* FIXME: When we move to dynamic allocation of back and depth
420	 * buffers, we will want to revisit the following check for 3
421	 * times the virtual size (or 2.5 times for 24-bit depth) of the screen below.
422	 */
423	int cpp = pATI->bitsPerPixel >> 3;
424	int maxY = pScreenInfo->videoRam * 1024 / (pATI->displayWidth * cpp);
425	int requiredY;
426
427	requiredY = pScreenInfo->virtualY * 2     /* front, back buffers */
428	    + (pScreenInfo->virtualY * 2 / cpp);  /* depth buffer (always 16-bit) */
429
430	if (!pATI->OptionAccel) {
431	    xf86DrvMsg(iScreen, X_WARNING,
432		       "Acceleration disabled, not initializing the DRI\n");
433	    pATI->directRenderingEnabled = FALSE;
434	} else if ( maxY > requiredY ) {
435	    pATI->directRenderingEnabled = ATIDRIScreenInit(pScreen);
436	} else {
437	    xf86DrvMsg(iScreen, X_WARNING,
438		       "DRI static buffer allocation failed -- "
439		       "need at least %d kB video memory\n",
440		       (pScreenInfo->displayWidth * requiredY * cpp ) / 1024);
441	    pATI->directRenderingEnabled = FALSE;
442	}
443    }
444
445#endif /* XF86DRI_DEVEL */
446
447    /* Initialise framebuffer layer */
448    switch (pATI->bitsPerPixel)
449    {
450        case 8:
451        case 16:
452        case 24:
453        case 32:
454            pATI->Closeable = fbScreenInit(pScreen, pFB,
455                pScreenInfo->virtualX, pScreenInfo->virtualY,
456                pScreenInfo->xDpi, pScreenInfo->yDpi, pATI->displayWidth,
457                pATI->bitsPerPixel);
458            break;
459
460        default:
461            return FALSE;
462    }
463
464    if (!pATI->Closeable)
465        return FALSE;
466
467    /* Fixup RGB ordering */
468    if (pATI->depth > 8)
469    {
470        VisualPtr pVisual = pScreen->visuals + pScreen->numVisuals;
471
472        while (--pVisual >= pScreen->visuals)
473        {
474            if ((pVisual->class | DynamicClass) != DirectColor)
475                continue;
476
477            pVisual->offsetRed = pScreenInfo->offset.red;
478            pVisual->offsetGreen = pScreenInfo->offset.green;
479            pVisual->offsetBlue = pScreenInfo->offset.blue;
480
481            pVisual->redMask = pScreenInfo->mask.red;
482            pVisual->greenMask = pScreenInfo->mask.green;
483            pVisual->blueMask = pScreenInfo->mask.blue;
484        }
485    }
486
487    /* If applicable, initialise RENDER extension */
488    {
489        if (pATI->OptionShadowFB)
490        {
491            if (serverGeneration == 1)
492                xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
493                    "RENDER extension not supported with a shadowed"
494                    " framebuffer.\n");
495        }
496        else if (!fbPictureInit(pScreen, NULL, 0) &&
497                 (serverGeneration == 1))
498        {
499            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
500                "RENDER extension initialisation failed.\n");
501        }
502    }
503
504    xf86SetBlackWhitePixels(pScreen);
505
506#ifdef USE_XAA
507
508    if (!pATI->useEXA) {
509
510    /* Memory manager setup */
511
512#ifdef XF86DRI_DEVEL
513    if (pATI->directRenderingEnabled)
514    {
515        if (!ATIMach64SetupMemXAA(iScreen, pScreen))
516            return FALSE;
517    }
518    else
519#endif /* XF86DRI_DEVEL */
520    {
521        if (!ATIMach64SetupMemXAA_NoDRI(iScreen, pScreen))
522            return FALSE;
523    }
524
525    /* Setup acceleration */
526
527    if (pATI->OptionAccel && !ATIMach64AccelInit(pScreen))
528        return FALSE;
529
530    }
531
532#endif /* USE_XAA */
533
534#ifdef USE_EXA
535
536    if (pATI->useEXA) {
537        /* EXA setups both memory manager and acceleration here */
538
539        if (pATI->OptionAccel && !ATIMach64ExaInit(pScreen))
540            return FALSE;
541    }
542
543#endif /* USE_EXA */
544
545#ifndef AVOID_DGA
546
547    /* Initialise DGA support */
548    (void)ATIDGAInit(pScreen, pScreenInfo, pATI);
549
550#endif /* AVOID_DGA */
551
552    /* Initialise backing store */
553    miInitializeBackingStore(pScreen);
554    xf86SetBackingStore(pScreen);
555
556    /* Initialise cursor */
557    if (!ATIMach64CursorInit(pScreen))
558        return FALSE;
559
560    /* Create default colourmap */
561    if (!miCreateDefColormap(pScreen))
562        return FALSE;
563
564    if (!xf86HandleColormaps(pScreen, 256, pATI->rgbBits, ATILoadPalette, NULL,
565                             CMAP_PALETTED_TRUECOLOR |
566                             CMAP_LOAD_EVEN_IF_OFFSCREEN))
567            return FALSE;
568
569    /* Initialise shadow framebuffer */
570    if (pATI->OptionShadowFB &&
571        !ShadowFBInit(pScreen, ATIRefreshArea))
572        return FALSE;
573
574    /* Initialise DPMS support */
575    (void)xf86DPMSInit(pScreen, ATISetDPMSMode, 0);
576
577    /* Initialise XVideo support */
578    (void)ATIInitializeXVideo(pScreen, pScreenInfo, pATI);
579
580    /* Set pScreen->SaveScreen and wrap CloseScreen vector */
581    pScreen->SaveScreen = ATISaveScreen;
582    pATI->CloseScreen = pScreen->CloseScreen;
583    pScreen->CloseScreen = ATICloseScreen;
584
585    if (serverGeneration == 1)
586        xf86ShowUnusedOptions(pScreenInfo->scrnIndex, pScreenInfo->options);
587
588#ifdef TV_OUT
589    /* Fix-up TV out after ImpacTV probe */
590    if (pATI->OptionTvOut && pATI->Chip < ATI_CHIP_264GTPRO)
591        ATISwitchMode(0, pScreenInfo->currentMode, 0);
592#endif /* TV_OUT */
593
594#ifdef XF86DRI_DEVEL
595
596    /* DRI finalization */
597    if (pATI->directRenderingEnabled) {
598	/* Now that mi, fb, drm and others have done their thing,
599	 * complete the DRI setup.
600	 */
601	pATI->directRenderingEnabled = ATIDRIFinishScreenInit(pScreen);
602    }
603    if (pATI->directRenderingEnabled) {
604	xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
605		   "Direct rendering enabled\n");
606    } else {
607        /* FIXME: Release unused offscreen mem here? */
608	xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
609		   "Direct rendering disabled\n");
610    }
611
612#endif /* XF86DRI_DEVEL */
613
614    return TRUE;
615}
616
617/*
618 * ATICloseScreen --
619 *
620 * This function is called by DIX to close the screen.
621 */
622Bool
623ATICloseScreen
624(
625    int       iScreen,
626    ScreenPtr pScreen
627)
628{
629    ScrnInfoPtr pScreenInfo = xf86Screens[iScreen];
630    ATIPtr      pATI        = ATIPTR(pScreenInfo);
631    Bool        Closed      = TRUE;
632
633#ifdef XF86DRI_DEVEL
634
635    /* Disable direct rendering */
636    if (pATI->directRenderingEnabled)
637    {
638	ATIDRICloseScreen(pScreen);
639	pATI->directRenderingEnabled = FALSE;
640    }
641
642#endif /* XF86DRI_DEVEL */
643
644    ATICloseXVideo(pScreen, pScreenInfo, pATI);
645
646#ifdef USE_EXA
647    if (pATI->pExa)
648    {
649        exaDriverFini(pScreen);
650        xfree(pATI->pExa);
651        pATI->pExa = NULL;
652    }
653#endif
654#ifdef USE_XAA
655    if (pATI->pXAAInfo)
656    {
657        XAADestroyInfoRec(pATI->pXAAInfo);
658        pATI->pXAAInfo = NULL;
659    }
660#endif
661
662    if ((pScreen->CloseScreen = pATI->CloseScreen))
663    {
664        pATI->CloseScreen = NULL;
665        Closed = (*pScreen->CloseScreen)(iScreen, pScreen);
666    }
667
668    pATI->Closeable = FALSE;
669
670    if (pATI->pCursorInfo)
671    {
672        xf86DestroyCursorInfoRec(pATI->pCursorInfo);
673        pATI->pCursorInfo = NULL;
674    }
675
676    ATILeaveGraphics(pScreenInfo, pATI);
677
678#ifdef USE_XAA
679    if (!pATI->useEXA)
680    {
681        xfree(pATI->ExpansionBitmapScanlinePtr[1]);
682        pATI->ExpansionBitmapScanlinePtr[0] = NULL;
683        pATI->ExpansionBitmapScanlinePtr[1] = NULL;
684    }
685#endif
686
687    xfree(pATI->pShadow);
688    pATI->pShadow = NULL;
689    pScreenInfo->pScreen = NULL;
690
691    return Closed;
692}
693