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