1 /* 2 * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, 3 * Precision Insight, Inc., Cedar Park, Texas, and 4 * VA Linux Systems Inc., Fremont, California. 5 * 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining 9 * a copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation on the rights to use, copy, modify, merge, 12 * publish, distribute, sublicense, and/or sell copies of the Software, 13 * and to permit persons to whom the Software is furnished to do so, 14 * subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial 18 * portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX 24 * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 * OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 #include <string.h> 35 #include <stdio.h> 36 37 /* 38 * Authors: 39 * Kevin E. Martin <martin (at) valinux.com> 40 * Rickard E. Faith <faith (at) valinux.com> 41 * Daryll Strauss <daryll (at) valinux.com> 42 * Gareth Hughes <gareth (at) valinux.com> 43 * 44 */ 45 46 /* Driver data structures */ 47 #include "r128.h" 48 #include "r128_dri.h" 49 #include "r128_common.h" 50 #include "r128_reg.h" 51 #include "r128_sarea.h" 52 #include "r128_version.h" 53 54 /* X and server generic header files */ 55 #include "xf86.h" 56 #include "windowstr.h" 57 58 #include "shadowfb.h" 59 /* DRI/DRM definitions */ 60 #define _XF86DRI_SERVER_ 61 #include "sarea.h" 62 63 static size_t r128_drm_page_size; 64 65 static void R128DRITransitionTo2d(ScreenPtr pScreen); 66 static void R128DRITransitionTo3d(ScreenPtr pScreen); 67 static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen); 68 static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen); 69 70 static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox); 71 72 /* Create the Rage 128-specific context information */ 73 static Bool R128CreateContext(ScreenPtr pScreen, VisualPtr visual, 74 drm_context_t hwContext, void *pVisualConfigPriv, 75 DRIContextType contextStore) 76 { 77 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 78 R128InfoPtr info = R128PTR(pScrn); 79 80 info->drmCtx = hwContext; 81 return TRUE; 82 } 83 84 /* Destroy the Rage 128-specific context information */ 85 static void R128DestroyContext(ScreenPtr pScreen, drm_context_t hwContext, 86 DRIContextType contextStore) 87 { 88 /* Nothing yet */ 89 } 90 91 /* Called when the X server is woken up to allow the last client's 92 context to be saved and the X server's context to be loaded. This is 93 not necessary for the Rage 128 since the client detects when it's 94 context is not currently loaded and then load's it itself. Since the 95 registers to start and stop the CCE are privileged, only the X server 96 can start/stop the engine. */ 97 static void R128EnterServer(ScreenPtr pScreen) 98 { 99 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 100 R128InfoPtr info = R128PTR(pScrn); 101 102 #ifdef USE_EXA 103 if (info->ExaDriver) exaMarkSync(pScreen); 104 /* EXA and DRI are fighting over control of the texture hardware. 105 * That means we need to setup compositing when the server wakes 106 * up if a 3D app is running. 107 */ 108 if (info->have3DWindows) info->state_2d.composite_setup = FALSE; 109 #endif 110 } 111 112 /* Called when the X server goes to sleep to allow the X server's 113 context to be saved and the last client's context to be loaded. This 114 is not necessary for the Rage 128 since the client detects when it's 115 context is not currently loaded and then load's it itself. Since the 116 registers to start and stop the CCE are privileged, only the X server 117 can start/stop the engine. */ 118 static void R128LeaveServer(ScreenPtr pScreen) 119 { 120 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 121 R128InfoPtr info = R128PTR(pScrn); 122 unsigned char *R128MMIO = info->MMIO; 123 124 if (!info->directRenderingEnabled) { 125 /* Save all hardware scissors */ 126 info->sc_left = INREG(R128_SC_LEFT); 127 info->sc_right = INREG(R128_SC_RIGHT); 128 info->sc_top = INREG(R128_SC_TOP); 129 info->sc_bottom = INREG(R128_SC_BOTTOM); 130 info->aux_sc_cntl = INREG(R128_SC_BOTTOM); 131 } else if (info->CCEInUse) { 132 R128CCEReleaseIndirect(pScrn); 133 134 info->CCEInUse = FALSE; 135 } 136 } 137 138 /* Contexts can be swapped by the X server if necessary. This callback 139 is currently only used to perform any functions necessary when 140 entering or leaving the X server, and in the future might not be 141 necessary. */ 142 static void R128DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, 143 DRIContextType oldContextType, void *oldContext, 144 DRIContextType newContextType, void *newContext) 145 { 146 if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) && 147 (newContextType==DRI_2D_CONTEXT)) { /* Entering from Wakeup */ 148 R128EnterServer(pScreen); 149 } 150 if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) && 151 (newContextType==DRI_2D_CONTEXT)) { /* Exiting from Block Handler */ 152 R128LeaveServer(pScreen); 153 } 154 } 155 156 /* Initialize the state of the back and depth buffers. */ 157 static void R128DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 indx) 158 { 159 /* FIXME: This routine needs to have acceleration turned on */ 160 ScreenPtr pScreen = pWin->drawable.pScreen; 161 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 162 R128InfoPtr info = R128PTR(pScrn); 163 164 /* FIXME: Use accel when CCE 2D code is written 165 * EA: What is this code kept for? Radeon doesn't have it and 166 * has a comment: "There's no need for the 2d driver to be clearing 167 * buffers for the 3d client. It knows how to do that on its own." 168 */ 169 if (info->directRenderingEnabled) 170 return; 171 } 172 173 /* Copy the back and depth buffers when the X server moves a window. */ 174 static void R128DRIMoveBuffers(WindowPtr pWin, DDXPointRec ptOldOrg, 175 RegionPtr prgnSrc, CARD32 indx) 176 { 177 ScreenPtr pScreen = pWin->drawable.pScreen; 178 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 179 R128InfoPtr info = R128PTR(pScrn); 180 181 /* FIXME: This routine needs to have acceleration turned on */ 182 /* FIXME: Copy XAACopyWindow() and use REGION_TRANSLATE() */ 183 /* FIXME: Only initialize the back and depth buffers for contexts 184 that request them */ 185 186 /* FIXME: Use accel when CCE 2D code is written */ 187 if (info->directRenderingEnabled) 188 return; 189 } 190 191 /* Initialize the AGP state. Request memory for use in AGP space, and 192 initialize the Rage 128 registers to point to that memory. */ 193 static Bool R128DRIAgpInit(R128InfoPtr info, ScreenPtr pScreen) 194 { 195 unsigned char *R128MMIO = info->MMIO; 196 unsigned long mode; 197 unsigned int vendor, device; 198 int ret; 199 unsigned long cntl, chunk; 200 int s, l; 201 int flags; 202 unsigned long agpBase; 203 204 if (drmAgpAcquire(info->drmFD) < 0) { 205 xf86DrvMsg(pScreen->myNum, X_WARNING, "[agp] AGP not available\n"); 206 return FALSE; 207 } 208 209 /* Modify the mode if the default mode is 210 not appropriate for this particular 211 combination of graphics card and AGP 212 chipset. */ 213 214 mode = drmAgpGetMode(info->drmFD); /* Default mode */ 215 vendor = drmAgpVendorId(info->drmFD); 216 device = drmAgpDeviceId(info->drmFD); 217 218 mode &= ~R128_AGP_MODE_MASK; 219 switch (info->agpMode) { 220 case 4: mode |= R128_AGP_4X_MODE; 221 case 2: mode |= R128_AGP_2X_MODE; 222 case 1: default: mode |= R128_AGP_1X_MODE; 223 } 224 225 xf86DrvMsg(pScreen->myNum, X_INFO, 226 "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", 227 mode, vendor, device, 228 PCI_DEV_VENDOR_ID(info->PciInfo), 229 PCI_DEV_DEVICE_ID(info->PciInfo)); 230 231 if (drmAgpEnable(info->drmFD, mode) < 0) { 232 xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n"); 233 drmAgpRelease(info->drmFD); 234 return FALSE; 235 } 236 237 info->agpOffset = 0; 238 239 if ((ret = drmAgpAlloc(info->drmFD, info->agpSize*1024*1024, 0, NULL, 240 &info->agpMemHandle)) < 0) { 241 xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret); 242 drmAgpRelease(info->drmFD); 243 return FALSE; 244 } 245 xf86DrvMsg(pScreen->myNum, X_INFO, 246 "[agp] %d kB allocated with handle 0x%08x\n", 247 info->agpSize*1024, info->agpMemHandle); 248 249 if (drmAgpBind(info->drmFD, info->agpMemHandle, info->agpOffset) < 0) { 250 xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not bind\n"); 251 drmAgpFree(info->drmFD, info->agpMemHandle); 252 drmAgpRelease(info->drmFD); 253 return FALSE; 254 } 255 256 /* Initialize the CCE ring buffer data */ 257 info->ringStart = info->agpOffset; 258 info->ringMapSize = info->ringSize*1024*1024 + r128_drm_page_size; 259 info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; 260 261 info->ringReadOffset = info->ringStart + info->ringMapSize; 262 info->ringReadMapSize = r128_drm_page_size; 263 264 /* Reserve space for vertex/indirect buffers */ 265 info->bufStart = info->ringReadOffset + info->ringReadMapSize; 266 info->bufMapSize = info->bufSize*1024*1024; 267 268 /* Reserve the rest for AGP textures */ 269 info->agpTexStart = info->bufStart + info->bufMapSize; 270 s = (info->agpSize*1024*1024 - info->agpTexStart); 271 l = R128MinBits((s-1) / R128_NR_TEX_REGIONS); 272 if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; 273 info->agpTexMapSize = (s >> l) << l; 274 info->log2AGPTexGran = l; 275 276 if (info->CCESecure) flags = DRM_READ_ONLY; 277 else flags = 0; 278 279 if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize, 280 DRM_AGP, flags, &info->ringHandle) < 0) { 281 xf86DrvMsg(pScreen->myNum, X_ERROR, 282 "[agp] Could not add ring mapping\n"); 283 return FALSE; 284 } 285 xf86DrvMsg(pScreen->myNum, X_INFO, 286 "[agp] ring handle = 0x%08x\n", info->ringHandle); 287 288 if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize, 289 &info->ring) < 0) { 290 xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map ring\n"); 291 return FALSE; 292 } 293 xf86DrvMsg(pScreen->myNum, X_INFO, 294 "[agp] Ring mapped at 0x%08lx\n", 295 (unsigned long)info->ring); 296 297 if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize, 298 DRM_AGP, flags, &info->ringReadPtrHandle) < 0) { 299 xf86DrvMsg(pScreen->myNum, X_ERROR, 300 "[agp] Could not add ring read ptr mapping\n"); 301 return FALSE; 302 } 303 xf86DrvMsg(pScreen->myNum, X_INFO, 304 "[agp] ring read ptr handle = 0x%08x\n", 305 info->ringReadPtrHandle); 306 307 if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, 308 &info->ringReadPtr) < 0) { 309 xf86DrvMsg(pScreen->myNum, X_ERROR, 310 "[agp] Could not map ring read ptr\n"); 311 return FALSE; 312 } 313 xf86DrvMsg(pScreen->myNum, X_INFO, 314 "[agp] Ring read ptr mapped at 0x%08lx\n", 315 (unsigned long)info->ringReadPtr); 316 317 if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize, 318 DRM_AGP, 0, &info->bufHandle) < 0) { 319 xf86DrvMsg(pScreen->myNum, X_ERROR, 320 "[agp] Could not add vertex/indirect buffers mapping\n"); 321 return FALSE; 322 } 323 xf86DrvMsg(pScreen->myNum, X_INFO, 324 "[agp] vertex/indirect buffers handle = 0x%08x\n", 325 info->bufHandle); 326 327 if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize, 328 &info->buf) < 0) { 329 xf86DrvMsg(pScreen->myNum, X_ERROR, 330 "[agp] Could not map vertex/indirect buffers\n"); 331 return FALSE; 332 } 333 xf86DrvMsg(pScreen->myNum, X_INFO, 334 "[agp] Vertex/indirect buffers mapped at 0x%08lx\n", 335 (unsigned long)info->buf); 336 337 if (drmAddMap(info->drmFD, info->agpTexStart, info->agpTexMapSize, 338 DRM_AGP, 0, &info->agpTexHandle) < 0) { 339 xf86DrvMsg(pScreen->myNum, X_ERROR, 340 "[agp] Could not add AGP texture map mapping\n"); 341 return FALSE; 342 } 343 xf86DrvMsg(pScreen->myNum, X_INFO, 344 "[agp] AGP texture map handle = 0x%08x\n", 345 info->agpTexHandle); 346 347 if (drmMap(info->drmFD, info->agpTexHandle, info->agpTexMapSize, 348 &info->agpTex) < 0) { 349 xf86DrvMsg(pScreen->myNum, X_ERROR, 350 "[agp] Could not map AGP texture map\n"); 351 return FALSE; 352 } 353 xf86DrvMsg(pScreen->myNum, X_INFO, 354 "[agp] AGP Texture map mapped at 0x%08lx\n", 355 (unsigned long)info->agpTex); 356 357 /* Initialize Rage 128's AGP registers */ 358 cntl = INREG(R128_AGP_CNTL); 359 cntl &= ~R128_AGP_APER_SIZE_MASK; 360 switch (info->agpSize) { 361 case 256: cntl |= R128_AGP_APER_SIZE_256MB; break; 362 case 128: cntl |= R128_AGP_APER_SIZE_128MB; break; 363 case 64: cntl |= R128_AGP_APER_SIZE_64MB; break; 364 case 32: cntl |= R128_AGP_APER_SIZE_32MB; break; 365 case 16: cntl |= R128_AGP_APER_SIZE_16MB; break; 366 case 8: cntl |= R128_AGP_APER_SIZE_8MB; break; 367 case 4: cntl |= R128_AGP_APER_SIZE_4MB; break; 368 default: 369 xf86DrvMsg(pScreen->myNum, X_ERROR, 370 "[agp] Illegal aperture size %d kB\n", 371 info->agpSize*1024); 372 return FALSE; 373 } 374 agpBase = drmAgpBase(info->drmFD); 375 OUTREG(R128_AGP_BASE, agpBase); 376 OUTREG(R128_AGP_CNTL, cntl); 377 378 /* Disable Rage 128's PCIGART registers */ 379 chunk = INREG(R128_BM_CHUNK_0_VAL); 380 chunk &= ~(R128_BM_PTR_FORCE_TO_PCI | 381 R128_BM_PM4_RD_FORCE_TO_PCI | 382 R128_BM_GLOBAL_FORCE_TO_PCI); 383 OUTREG(R128_BM_CHUNK_0_VAL, chunk); 384 385 OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */ 386 387 return TRUE; 388 } 389 390 static Bool R128DRIPciInit(R128InfoPtr info, ScreenPtr pScreen) 391 { 392 unsigned char *R128MMIO = info->MMIO; 393 uint32_t chunk; 394 int ret; 395 int flags; 396 397 info->agpOffset = 0; 398 399 ret = drmScatterGatherAlloc(info->drmFD, info->agpSize*1024*1024, 400 &info->pciMemHandle); 401 if (ret < 0) { 402 xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Out of memory (%d)\n", ret); 403 return FALSE; 404 } 405 xf86DrvMsg(pScreen->myNum, X_INFO, 406 "[pci] %d kB allocated with handle 0x%08x\n", 407 info->agpSize*1024, info->pciMemHandle); 408 409 /* Initialize the CCE ring buffer data */ 410 info->ringStart = info->agpOffset; 411 info->ringMapSize = info->ringSize*1024*1024 + r128_drm_page_size; 412 info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; 413 414 info->ringReadOffset = info->ringStart + info->ringMapSize; 415 info->ringReadMapSize = r128_drm_page_size; 416 417 /* Reserve space for vertex/indirect buffers */ 418 info->bufStart = info->ringReadOffset + info->ringReadMapSize; 419 info->bufMapSize = info->bufSize*1024*1024; 420 421 flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL; 422 423 if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize, 424 DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) { 425 xf86DrvMsg(pScreen->myNum, X_ERROR, 426 "[pci] Could not add ring mapping\n"); 427 return FALSE; 428 } 429 xf86DrvMsg(pScreen->myNum, X_INFO, 430 "[pci] ring handle = 0x%08x\n", info->ringHandle); 431 432 if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize, 433 &info->ring) < 0) { 434 xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Could not map ring\n"); 435 return FALSE; 436 } 437 xf86DrvMsg(pScreen->myNum, X_INFO, 438 "[pci] Ring mapped at 0x%08lx\n", 439 (unsigned long)info->ring); 440 xf86DrvMsg(pScreen->myNum, X_INFO, 441 "[pci] Ring contents 0x%08lx\n", 442 *(unsigned long *)(pointer)info->ring); 443 444 if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize, 445 DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) { 446 xf86DrvMsg(pScreen->myNum, X_ERROR, 447 "[pci] Could not add ring read ptr mapping\n"); 448 return FALSE; 449 } 450 xf86DrvMsg(pScreen->myNum, X_INFO, 451 "[pci] ring read ptr handle = 0x%08x\n", 452 info->ringReadPtrHandle); 453 454 if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, 455 &info->ringReadPtr) < 0) { 456 xf86DrvMsg(pScreen->myNum, X_ERROR, 457 "[pci] Could not map ring read ptr\n"); 458 return FALSE; 459 } 460 xf86DrvMsg(pScreen->myNum, X_INFO, 461 "[pci] Ring read ptr mapped at 0x%08lx\n", 462 (unsigned long)info->ringReadPtr); 463 xf86DrvMsg(pScreen->myNum, X_INFO, 464 "[pci] Ring read ptr contents 0x%08lx\n", 465 *(unsigned long *)(pointer)info->ringReadPtr); 466 467 if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize, 468 DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) { 469 xf86DrvMsg(pScreen->myNum, X_ERROR, 470 "[pci] Could not add vertex/indirect buffers mapping\n"); 471 return FALSE; 472 } 473 xf86DrvMsg(pScreen->myNum, X_INFO, 474 "[pci] vertex/indirect buffers handle = 0x%08x\n", 475 info->bufHandle); 476 477 if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize, 478 &info->buf) < 0) { 479 xf86DrvMsg(pScreen->myNum, X_ERROR, 480 "[pci] Could not map vertex/indirect buffers\n"); 481 return FALSE; 482 } 483 xf86DrvMsg(pScreen->myNum, X_INFO, 484 "[pci] Vertex/indirect buffers mapped at 0x%08lx\n", 485 (unsigned long)info->buf); 486 xf86DrvMsg(pScreen->myNum, X_INFO, 487 "[pci] Vertex/indirect buffers contents 0x%08lx\n", 488 *(unsigned long *)(pointer)info->buf); 489 490 switch (info->Chipset) { 491 case PCI_CHIP_RAGE128LE: 492 case PCI_CHIP_RAGE128RE: 493 case PCI_CHIP_RAGE128RK: 494 case PCI_CHIP_RAGE128PD: 495 case PCI_CHIP_RAGE128PP: 496 case PCI_CHIP_RAGE128PR: 497 /* This is a PCI card, do nothing */ 498 break; 499 500 case PCI_CHIP_RAGE128LF: 501 case PCI_CHIP_RAGE128MF: 502 case PCI_CHIP_RAGE128ML: 503 case PCI_CHIP_RAGE128RF: 504 case PCI_CHIP_RAGE128RG: 505 case PCI_CHIP_RAGE128RL: 506 case PCI_CHIP_RAGE128SM: 507 case PCI_CHIP_RAGE128PF: 508 case PCI_CHIP_RAGE128TF: 509 case PCI_CHIP_RAGE128TL: 510 case PCI_CHIP_RAGE128TR: 511 /* FIXME: ATI documentation does not specify if the following chips are 512 * AGP or PCI, it just mentions their PCI IDs. I'm assuming they're AGP 513 * until I get more correct information. <mharris (at) redhat.com> 514 */ 515 case PCI_CHIP_RAGE128PA: 516 case PCI_CHIP_RAGE128PB: 517 case PCI_CHIP_RAGE128PC: 518 case PCI_CHIP_RAGE128PE: 519 case PCI_CHIP_RAGE128PG: 520 case PCI_CHIP_RAGE128PH: 521 case PCI_CHIP_RAGE128PI: 522 case PCI_CHIP_RAGE128PJ: 523 case PCI_CHIP_RAGE128PK: 524 case PCI_CHIP_RAGE128PL: 525 case PCI_CHIP_RAGE128PM: 526 case PCI_CHIP_RAGE128PN: 527 case PCI_CHIP_RAGE128PO: 528 case PCI_CHIP_RAGE128PQ: 529 case PCI_CHIP_RAGE128PS: 530 case PCI_CHIP_RAGE128PT: 531 case PCI_CHIP_RAGE128PU: 532 case PCI_CHIP_RAGE128PV: 533 case PCI_CHIP_RAGE128PW: 534 case PCI_CHIP_RAGE128PX: 535 case PCI_CHIP_RAGE128SE: 536 case PCI_CHIP_RAGE128SF: 537 case PCI_CHIP_RAGE128SG: 538 case PCI_CHIP_RAGE128SH: 539 case PCI_CHIP_RAGE128SK: 540 case PCI_CHIP_RAGE128SL: 541 case PCI_CHIP_RAGE128SN: 542 case PCI_CHIP_RAGE128TS: 543 case PCI_CHIP_RAGE128TT: 544 case PCI_CHIP_RAGE128TU: 545 default: 546 /* This is really an AGP card, force PCI GART mode */ 547 chunk = INREG(R128_BM_CHUNK_0_VAL); 548 chunk |= (R128_BM_PTR_FORCE_TO_PCI | 549 R128_BM_PM4_RD_FORCE_TO_PCI | 550 R128_BM_GLOBAL_FORCE_TO_PCI); 551 OUTREG(R128_BM_CHUNK_0_VAL, chunk); 552 OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */ 553 break; 554 } 555 556 return TRUE; 557 } 558 559 /* Add a map for the MMIO registers that will be accessed by any 560 DRI-based clients. */ 561 static Bool R128DRIMapInit(R128InfoPtr info, ScreenPtr pScreen) 562 { 563 int flags; 564 565 if (info->CCESecure) flags = DRM_READ_ONLY; 566 else flags = 0; 567 568 /* Map registers */ 569 info->registerSize = R128_MMIOSIZE; 570 if (drmAddMap(info->drmFD, info->MMIOAddr, info->registerSize, 571 DRM_REGISTERS, flags, &info->registerHandle) < 0) { 572 return FALSE; 573 } 574 xf86DrvMsg(pScreen->myNum, X_INFO, 575 "[drm] register handle = 0x%08x\n", info->registerHandle); 576 577 return TRUE; 578 } 579 580 /* Initialize the kernel data structures. */ 581 static int R128DRIKernelInit(R128InfoPtr info, ScreenPtr pScreen) 582 { 583 drmR128Init drmInfo; 584 585 memset( &drmInfo, 0, sizeof(drmR128Init) ); 586 587 drmInfo.func = DRM_R128_INIT_CCE; 588 drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec); 589 drmInfo.is_pci = info->IsPCI; 590 drmInfo.cce_mode = info->CCEMode; 591 drmInfo.cce_secure = info->CCESecure; 592 drmInfo.ring_size = info->ringSize*1024*1024; 593 drmInfo.usec_timeout = info->CCEusecTimeout; 594 595 drmInfo.fb_bpp = info->CurrentLayout.pixel_code; 596 drmInfo.depth_bpp = info->CurrentLayout.pixel_code; 597 598 drmInfo.front_offset = info->frontOffset; 599 drmInfo.front_pitch = info->frontPitch; 600 601 drmInfo.back_offset = info->backOffset; 602 drmInfo.back_pitch = info->backPitch; 603 604 drmInfo.depth_offset = info->depthOffset; 605 drmInfo.depth_pitch = info->depthPitch; 606 drmInfo.span_offset = info->spanOffset; 607 608 drmInfo.fb_offset = info->fbHandle; 609 drmInfo.mmio_offset = info->registerHandle; 610 drmInfo.ring_offset = info->ringHandle; 611 drmInfo.ring_rptr_offset = info->ringReadPtrHandle; 612 drmInfo.buffers_offset = info->bufHandle; 613 drmInfo.agp_textures_offset = info->agpTexHandle; 614 615 if (drmCommandWrite(info->drmFD, DRM_R128_INIT, 616 &drmInfo, sizeof(drmR128Init)) < 0) 617 return FALSE; 618 619 return TRUE; 620 } 621 622 /* Add a map for the vertex buffers that will be accessed by any 623 DRI-based clients. */ 624 static Bool R128DRIBufInit(R128InfoPtr info, ScreenPtr pScreen) 625 { 626 /* Initialize vertex buffers */ 627 if (info->IsPCI) { 628 info->bufNumBufs = drmAddBufs(info->drmFD, 629 info->bufMapSize / R128_BUFFER_SIZE, 630 R128_BUFFER_SIZE, 631 DRM_SG_BUFFER, 632 info->bufStart); 633 } else { 634 info->bufNumBufs = drmAddBufs(info->drmFD, 635 info->bufMapSize / R128_BUFFER_SIZE, 636 R128_BUFFER_SIZE, 637 DRM_AGP_BUFFER, 638 info->bufStart); 639 } 640 if (info->bufNumBufs <= 0) { 641 xf86DrvMsg(pScreen->myNum, X_ERROR, 642 "[drm] Could not create vertex/indirect buffers list\n"); 643 return FALSE; 644 } 645 xf86DrvMsg(pScreen->myNum, X_INFO, 646 "[drm] Added %d %d byte vertex/indirect buffers\n", 647 info->bufNumBufs, R128_BUFFER_SIZE); 648 649 if (!(info->buffers = drmMapBufs(info->drmFD))) { 650 xf86DrvMsg(pScreen->myNum, X_ERROR, 651 "[drm] Failed to map vertex/indirect buffers list\n"); 652 return FALSE; 653 } 654 xf86DrvMsg(pScreen->myNum, X_INFO, 655 "[drm] Mapped %d vertex/indirect buffers\n", 656 info->buffers->count); 657 658 return TRUE; 659 } 660 661 static void R128DRIIrqInit(R128InfoPtr info, ScreenPtr pScreen) 662 { 663 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 664 665 if (!info->irq) { 666 info->irq = drmGetInterruptFromBusID( 667 info->drmFD, 668 PCI_CFG_BUS(info->PciInfo), 669 PCI_CFG_DEV(info->PciInfo), 670 PCI_CFG_FUNC(info->PciInfo)); 671 672 if((drmCtlInstHandler(info->drmFD, info->irq)) != 0) { 673 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 674 "[drm] failure adding irq handler, " 675 "there is a device already using that irq\n" 676 "[drm] falling back to irq-free operation\n"); 677 info->irq = 0; 678 } else { 679 unsigned char *R128MMIO = info->MMIO; 680 info->gen_int_cntl = INREG( R128_GEN_INT_CNTL ); 681 } 682 } 683 684 if (info->irq) 685 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 686 "[drm] dma control initialized, using IRQ %d\n", 687 info->irq); 688 } 689 690 /* Initialize the CCE state, and start the CCE (if used by the X server) */ 691 static void R128DRICCEInit(ScrnInfoPtr pScrn) 692 { 693 R128InfoPtr info = R128PTR(pScrn); 694 695 /* Turn on bus mastering */ 696 info->BusCntl &= ~R128_BUS_MASTER_DIS; 697 698 /* CCEMode is initialized in r128_driver.c */ 699 switch (info->CCEMode) { 700 case R128_PM4_NONPM4: info->CCEFifoSize = 0; break; 701 case R128_PM4_192PIO: info->CCEFifoSize = 192; break; 702 case R128_PM4_192BM: info->CCEFifoSize = 192; break; 703 case R128_PM4_128PIO_64INDBM: info->CCEFifoSize = 128; break; 704 case R128_PM4_128BM_64INDBM: info->CCEFifoSize = 128; break; 705 case R128_PM4_64PIO_128INDBM: info->CCEFifoSize = 64; break; 706 case R128_PM4_64BM_128INDBM: info->CCEFifoSize = 64; break; 707 case R128_PM4_64PIO_64VCBM_64INDBM: info->CCEFifoSize = 64; break; 708 case R128_PM4_64BM_64VCBM_64INDBM: info->CCEFifoSize = 64; break; 709 case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64; break; 710 } 711 712 if (info->directRenderingEnabled) { 713 /* Make sure the CCE is on for the X server */ 714 R128CCE_START(pScrn, info); 715 } else { 716 /* Make sure the CCE is off for the X server */ 717 R128CCE_STOP(pScrn, info); 718 } 719 } 720 721 /* Initialize the screen-specific data structures for the DRI and the 722 Rage 128. This is the main entry point to the device-specific 723 initialization code. It calls device-independent DRI functions to 724 create the DRI data structures and initialize the DRI state. */ 725 Bool R128DRIScreenInit(ScreenPtr pScreen) 726 { 727 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 728 R128InfoPtr info = R128PTR(pScrn); 729 DRIInfoPtr pDRIInfo; 730 R128DRIPtr pR128DRI; 731 int major, minor, patch; 732 drmVersionPtr version; 733 734 /* Check that the DRI, and DRM modules have been loaded by testing 735 * for known symbols in each module. */ 736 if (!xf86LoaderCheckSymbol("drmAvailable")) return FALSE; 737 if (!xf86LoaderCheckSymbol("DRIQueryVersion")) { 738 xf86DrvMsg(pScreen->myNum, X_ERROR, 739 "[dri] R128DRIScreenInit failed (libdri.a too old)\n"); 740 return FALSE; 741 } 742 743 /* Check the DRI version */ 744 DRIQueryVersion(&major, &minor, &patch); 745 if (major != DRIINFO_MAJOR_VERSION || minor < 0) { 746 xf86DrvMsg(pScreen->myNum, X_ERROR, 747 "[dri] R128DRIScreenInit failed because of a version mismatch.\n" 748 "[dri] libdri version is %d.%d.%d but version %d.%d.x is needed.\n" 749 "[dri] Disabling the DRI.\n", 750 major, minor, patch, 751 DRIINFO_MAJOR_VERSION, 0); 752 return FALSE; 753 } 754 755 switch (info->CurrentLayout.pixel_code) { 756 case 8: 757 /* These modes are not supported (yet). */ 758 case 15: 759 case 24: 760 xf86DrvMsg(pScreen->myNum, X_ERROR, 761 "[dri] R128DRIScreenInit failed (depth %d not supported). " 762 "[dri] Disabling DRI.\n", info->CurrentLayout.pixel_code); 763 return FALSE; 764 765 /* Only 16 and 32 color depths are supports currently. */ 766 case 16: 767 case 32: 768 break; 769 } 770 771 r128_drm_page_size = getpagesize(); 772 773 /* Create the DRI data structure, and fill it in before calling the 774 DRIScreenInit(). */ 775 if (!(pDRIInfo = DRICreateInfoRec())) return FALSE; 776 777 info->pDRIInfo = pDRIInfo; 778 pDRIInfo->drmDriverName = R128_DRIVER_NAME; 779 pDRIInfo->clientDriverName = R128_DRIVER_NAME; 780 if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) { 781 pDRIInfo->busIdString = DRICreatePCIBusID(info->PciInfo); 782 } else { 783 pDRIInfo->busIdString = malloc(64); 784 sprintf(pDRIInfo->busIdString, 785 "PCI:%d:%d:%d", 786 PCI_DEV_BUS(info->PciInfo), 787 PCI_DEV_DEV(info->PciInfo), 788 PCI_DEV_FUNC(info->PciInfo)); 789 } 790 pDRIInfo->ddxDriverMajorVersion = R128_VERSION_MAJOR; 791 pDRIInfo->ddxDriverMinorVersion = R128_VERSION_MINOR; 792 pDRIInfo->ddxDriverPatchVersion = R128_VERSION_PATCH; 793 pDRIInfo->frameBufferPhysicalAddress = (void *)info->LinearAddr; 794 pDRIInfo->frameBufferSize = info->FbMapSize; 795 pDRIInfo->frameBufferStride = (pScrn->displayWidth * 796 info->CurrentLayout.pixel_bytes); 797 pDRIInfo->ddxDrawableTableEntry = R128_MAX_DRAWABLES; 798 pDRIInfo->maxDrawableTableEntry = (SAREA_MAX_DRAWABLES 799 < R128_MAX_DRAWABLES 800 ? SAREA_MAX_DRAWABLES 801 : R128_MAX_DRAWABLES); 802 803 #ifdef NOT_DONE 804 /* FIXME: Need to extend DRI protocol to pass this size back to 805 * client for SAREA mapping that includes a device private record 806 */ 807 pDRIInfo->SAREASize = 808 ((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */ 809 /* + shared memory device private rec */ 810 #else 811 /* For now the mapping works by using a fixed size defined 812 * in the SAREA header 813 */ 814 if (sizeof(XF86DRISAREARec)+sizeof(R128SAREAPriv)>SAREA_MAX) { 815 xf86DrvMsg(pScreen->myNum, X_ERROR, 816 "[dri] Data does not fit in SAREA. Disabling DRI.\n"); 817 return FALSE; 818 } 819 pDRIInfo->SAREASize = SAREA_MAX; 820 #endif 821 822 if (!(pR128DRI = (R128DRIPtr)calloc(1, sizeof(R128DRIRec)))) { 823 DRIDestroyInfoRec(info->pDRIInfo); 824 info->pDRIInfo = NULL; 825 return FALSE; 826 } 827 pDRIInfo->devPrivate = pR128DRI; 828 pDRIInfo->devPrivateSize = sizeof(R128DRIRec); 829 pDRIInfo->contextSize = sizeof(R128DRIContextRec); 830 831 pDRIInfo->CreateContext = R128CreateContext; 832 pDRIInfo->DestroyContext = R128DestroyContext; 833 pDRIInfo->SwapContext = R128DRISwapContext; 834 pDRIInfo->InitBuffers = R128DRIInitBuffers; 835 pDRIInfo->MoveBuffers = R128DRIMoveBuffers; 836 pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; 837 pDRIInfo->TransitionTo2d = R128DRITransitionTo2d; 838 pDRIInfo->TransitionTo3d = R128DRITransitionTo3d; 839 pDRIInfo->TransitionSingleToMulti3D = R128DRITransitionSingleToMulti3d; 840 pDRIInfo->TransitionMultiToSingle3D = R128DRITransitionMultiToSingle3d; 841 842 pDRIInfo->createDummyCtx = TRUE; 843 pDRIInfo->createDummyCtxPriv = FALSE; 844 845 if (!DRIScreenInit(pScreen, pDRIInfo, &info->drmFD)) { 846 xf86DrvMsg(pScreen->myNum, X_ERROR, 847 "[dri] DRIScreenInit failed. Disabling DRI.\n"); 848 free(pDRIInfo->devPrivate); 849 pDRIInfo->devPrivate = NULL; 850 DRIDestroyInfoRec(pDRIInfo); 851 pDRIInfo = NULL; 852 return FALSE; 853 } 854 855 /* Check the DRM lib version. 856 drmGetLibVersion was not supported in version 1.0, so check for 857 symbol first to avoid possible crash or hang. 858 */ 859 if (xf86LoaderCheckSymbol("drmGetLibVersion")) { 860 version = drmGetLibVersion(info->drmFD); 861 } 862 else { 863 /* drmlib version 1.0.0 didn't have the drmGetLibVersion 864 entry point. Fake it by allocating a version record 865 via drmGetVersion and changing it to version 1.0.0 866 */ 867 version = drmGetVersion(info->drmFD); 868 version->version_major = 1; 869 version->version_minor = 0; 870 version->version_patchlevel = 0; 871 } 872 873 if (version) { 874 if (version->version_major != 1 || 875 version->version_minor < 1) { 876 /* incompatible drm library version */ 877 xf86DrvMsg(pScreen->myNum, X_ERROR, 878 "[dri] R128DRIScreenInit failed because of a version mismatch.\n" 879 "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n" 880 "[dri] Disabling DRI.\n", 881 version->version_major, 882 version->version_minor, 883 version->version_patchlevel); 884 drmFreeVersion(version); 885 R128DRICloseScreen(pScreen); 886 return FALSE; 887 } 888 drmFreeVersion(version); 889 } 890 891 /* Check the r128 DRM version */ 892 version = drmGetVersion(info->drmFD); 893 if (version) { 894 if (version->version_major != 2 || 895 version->version_minor < 2) { 896 /* incompatible drm version */ 897 xf86DrvMsg(pScreen->myNum, X_ERROR, 898 "[dri] R128DRIScreenInit failed because of a version mismatch.\n" 899 "[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n" 900 "[dri] Disabling the DRI.\n", 901 version->version_major, 902 version->version_minor, 903 version->version_patchlevel); 904 drmFreeVersion(version); 905 R128DRICloseScreen(pScreen); 906 return FALSE; 907 } 908 info->drmMinor = version->version_minor; 909 drmFreeVersion(version); 910 } 911 912 /* Initialize AGP */ 913 if (!info->IsPCI && !R128DRIAgpInit(info, pScreen)) { 914 info->IsPCI = TRUE; 915 xf86DrvMsg(pScreen->myNum, X_WARNING, 916 "[agp] AGP failed to initialize -- falling back to PCI mode.\n"); 917 xf86DrvMsg(pScreen->myNum, X_WARNING, 918 "[agp] Make sure you have the agpgart kernel module loaded.\n"); 919 } 920 921 /* Initialize PCIGART */ 922 if (info->IsPCI && !R128DRIPciInit(info, pScreen)) { 923 R128DRICloseScreen(pScreen); 924 return FALSE; 925 } 926 927 /* DRIScreenInit doesn't add all the 928 common mappings. Add additional 929 mappings here. */ 930 if (!R128DRIMapInit(info, pScreen)) { 931 R128DRICloseScreen(pScreen); 932 return FALSE; 933 } 934 935 /* DRIScreenInit adds the frame buffer 936 map, but we need it as well */ 937 { 938 void *scratch_ptr; 939 int scratch_int; 940 941 DRIGetDeviceInfo(pScreen, &info->fbHandle, 942 &scratch_int, &scratch_int, 943 &scratch_int, &scratch_int, 944 &scratch_ptr); 945 } 946 947 /* FIXME: When are these mappings unmapped? */ 948 949 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Visual configs initialized\n"); 950 951 return TRUE; 952 } 953 954 /* Finish initializing the device-dependent DRI state, and call 955 DRIFinishScreenInit() to complete the device-independent DRI 956 initialization. */ 957 Bool R128DRIFinishScreenInit(ScreenPtr pScreen) 958 { 959 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 960 R128InfoPtr info = R128PTR(pScrn); 961 R128SAREAPrivPtr pSAREAPriv; 962 R128DRIPtr pR128DRI; 963 964 info->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; 965 /* info->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */ 966 967 /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit 968 because *DRIKernelInit requires that the hardware lock is held by 969 the X server, and the first time the hardware lock is grabbed is 970 in DRIFinishScreenInit. */ 971 if (!DRIFinishScreenInit(pScreen)) { 972 R128DRICloseScreen(pScreen); 973 return FALSE; 974 } 975 976 /* Initialize the kernel data structures */ 977 if (!R128DRIKernelInit(info, pScreen)) { 978 R128DRICloseScreen(pScreen); 979 return FALSE; 980 } 981 982 /* Initialize the vertex buffers list */ 983 if (!R128DRIBufInit(info, pScreen)) { 984 R128DRICloseScreen(pScreen); 985 return FALSE; 986 } 987 988 /* Initialize IRQ */ 989 R128DRIIrqInit(info, pScreen); 990 991 /* Initialize and start the CCE if required */ 992 R128DRICCEInit(pScrn); 993 994 pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen); 995 memset(pSAREAPriv, 0, sizeof(*pSAREAPriv)); 996 997 pR128DRI = (R128DRIPtr)info->pDRIInfo->devPrivate; 998 999 pR128DRI->deviceID = info->Chipset; 1000 pR128DRI->width = pScrn->virtualX; 1001 pR128DRI->height = pScrn->virtualY; 1002 pR128DRI->depth = pScrn->depth; 1003 pR128DRI->bpp = pScrn->bitsPerPixel; 1004 1005 pR128DRI->IsPCI = info->IsPCI; 1006 pR128DRI->AGPMode = info->agpMode; 1007 1008 pR128DRI->frontOffset = info->frontOffset; 1009 pR128DRI->frontPitch = info->frontPitch; 1010 pR128DRI->backOffset = info->backOffset; 1011 pR128DRI->backPitch = info->backPitch; 1012 pR128DRI->depthOffset = info->depthOffset; 1013 pR128DRI->depthPitch = info->depthPitch; 1014 pR128DRI->spanOffset = info->spanOffset; 1015 pR128DRI->textureOffset = info->textureOffset; 1016 pR128DRI->textureSize = info->textureSize; 1017 pR128DRI->log2TexGran = info->log2TexGran; 1018 1019 pR128DRI->registerHandle = info->registerHandle; 1020 pR128DRI->registerSize = info->registerSize; 1021 1022 pR128DRI->agpTexHandle = info->agpTexHandle; 1023 pR128DRI->agpTexMapSize = info->agpTexMapSize; 1024 pR128DRI->log2AGPTexGran = info->log2AGPTexGran; 1025 pR128DRI->agpTexOffset = info->agpTexStart; 1026 pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec); 1027 1028 /* Have shadowfb run only while there is 3d active. */ 1029 if (info->allowPageFlip && info->drmMinor >= 5 ) { 1030 ShadowFBInit( pScreen, R128DRIRefreshArea ); 1031 } else if (info->allowPageFlip) { 1032 xf86DrvMsg(pScreen->myNum, X_WARNING, 1033 "[dri] Kernel module version 2.5.0 or newer is required for pageflipping.\n"); 1034 info->allowPageFlip = 0; 1035 } 1036 1037 return TRUE; 1038 } 1039 1040 /* The screen is being closed, so clean up any state and free any 1041 resources used by the DRI. */ 1042 void R128DRICloseScreen(ScreenPtr pScreen) 1043 { 1044 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1045 R128InfoPtr info = R128PTR(pScrn); 1046 drmR128Init drmInfo; 1047 1048 /* Stop the CCE if it is still in use */ 1049 if (info->directRenderingEnabled) { 1050 R128CCE_STOP(pScrn, info); 1051 } 1052 1053 if (info->irq) { 1054 drmCtlUninstHandler(info->drmFD); 1055 info->irq = 0; 1056 info->gen_int_cntl = 0; 1057 } 1058 1059 /* De-allocate vertex buffers */ 1060 if (info->buffers) { 1061 drmUnmapBufs(info->buffers); 1062 info->buffers = NULL; 1063 } 1064 1065 /* De-allocate all kernel resources */ 1066 memset(&drmInfo, 0, sizeof(drmR128Init)); 1067 drmInfo.func = DRM_R128_CLEANUP_CCE; 1068 drmCommandWrite(info->drmFD, DRM_R128_INIT, 1069 &drmInfo, sizeof(drmR128Init)); 1070 1071 /* De-allocate all AGP resources */ 1072 if (info->agpTex) { 1073 drmUnmap(info->agpTex, info->agpTexMapSize); 1074 info->agpTex = NULL; 1075 } 1076 if (info->buf) { 1077 drmUnmap(info->buf, info->bufMapSize); 1078 info->buf = NULL; 1079 } 1080 if (info->ringReadPtr) { 1081 drmUnmap(info->ringReadPtr, info->ringReadMapSize); 1082 info->ringReadPtr = NULL; 1083 } 1084 if (info->ring) { 1085 drmUnmap(info->ring, info->ringMapSize); 1086 info->ring = NULL; 1087 } 1088 if (info->agpMemHandle != DRM_AGP_NO_HANDLE) { 1089 drmAgpUnbind(info->drmFD, info->agpMemHandle); 1090 drmAgpFree(info->drmFD, info->agpMemHandle); 1091 info->agpMemHandle = DRM_AGP_NO_HANDLE; 1092 drmAgpRelease(info->drmFD); 1093 } 1094 if (info->pciMemHandle) { 1095 drmScatterGatherFree(info->drmFD, info->pciMemHandle); 1096 info->pciMemHandle = 0; 1097 } 1098 1099 /* De-allocate all DRI resources */ 1100 DRICloseScreen(pScreen); 1101 1102 /* De-allocate all DRI data structures */ 1103 if (info->pDRIInfo) { 1104 if (info->pDRIInfo->devPrivate) { 1105 free(info->pDRIInfo->devPrivate); 1106 info->pDRIInfo->devPrivate = NULL; 1107 } 1108 DRIDestroyInfoRec(info->pDRIInfo); 1109 info->pDRIInfo = NULL; 1110 } 1111 } 1112 1113 /* Use callbacks from dri.c to support pageflipping mode for a single 1114 * 3d context without need for any specific full-screen extension. 1115 */ 1116 1117 /* Use the shadowfb module to maintain a list of dirty rectangles. 1118 * These are blitted to the back buffer to keep both buffers clean 1119 * during page-flipping when the 3d application isn't fullscreen. 1120 * 1121 * Unlike most use of the shadowfb code, both buffers are in video memory. 1122 * 1123 * An alternative to this would be to organize for all on-screen drawing 1124 * operations to be duplicated for the two buffers. That might be 1125 * faster, but seems like a lot more work... 1126 */ 1127 1128 1129 static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) 1130 { 1131 R128InfoPtr info = R128PTR(pScrn); 1132 int i; 1133 R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); 1134 PixmapPtr pPix = pScrn->pScreen->GetScreenPixmap(pScrn->pScreen); 1135 1136 /* Don't want to do this when no 3d is active and pages are 1137 * right-way-round 1138 */ 1139 if (!pSAREAPriv->pfAllowPageFlip && pSAREAPriv->pfCurrentPage == 0) 1140 return; 1141 1142 #ifdef USE_EXA 1143 if (info->useEXA) { 1144 uint32_t src_pitch_offset, dst_pitch_offset, datatype; 1145 1146 R128GetPixmapOffsetPitch(pPix, &src_pitch_offset); 1147 dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5); 1148 R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype); 1149 info->xdir = info->ydir = 1; 1150 1151 R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0); 1152 } 1153 #endif 1154 1155 for (i = 0 ; i < num ; i++, pbox++) { 1156 int xa = max(pbox->x1, 0), xb = min(pbox->x2, pScrn->virtualX-1); 1157 int ya = max(pbox->y1, 0), yb = min(pbox->y2, pScrn->virtualY-1); 1158 1159 if (xa <= xb && ya <= yb) { 1160 #ifdef USE_EXA 1161 if (info->useEXA) { 1162 (*info->ExaDriver->Copy)(pPix, xa, ya, xa, ya, xb - xa + 1, yb - ya + 1); 1163 } 1164 #endif 1165 } 1166 } 1167 } 1168 1169 static void R128EnablePageFlip(ScreenPtr pScreen) 1170 { 1171 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1172 R128InfoPtr info = R128PTR(pScrn); 1173 R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); 1174 PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen); 1175 1176 if (info->allowPageFlip) { 1177 /* Duplicate the frontbuffer to the backbuffer */ 1178 #ifdef USE_EXA 1179 if (info->useEXA) { 1180 uint32_t src_pitch_offset, dst_pitch_offset, datatype; 1181 1182 R128GetPixmapOffsetPitch(pPix, &src_pitch_offset); 1183 dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5); 1184 R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype); 1185 info->xdir = info->ydir = 1; 1186 1187 R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0); 1188 1189 (*info->ExaDriver->Copy)(pPix, 0, 0, 0, 0, pScrn->virtualX, pScrn->virtualY); 1190 } 1191 #endif 1192 1193 pSAREAPriv->pfAllowPageFlip = 1; 1194 } 1195 } 1196 1197 static void R128DisablePageFlip(ScreenPtr pScreen) 1198 { 1199 /* Tell the clients not to pageflip. How? 1200 * -- Field in sarea, plus bumping the window counters. 1201 * -- DRM needs to cope with Front-to-Back swapbuffers. 1202 */ 1203 R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); 1204 1205 pSAREAPriv->pfAllowPageFlip = 0; 1206 } 1207 1208 static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen) 1209 { 1210 R128DisablePageFlip(pScreen); 1211 } 1212 1213 static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen) 1214 { 1215 /* Let the remaining 3d app start page flipping again */ 1216 R128EnablePageFlip(pScreen); 1217 } 1218 1219 static void R128DRITransitionTo3d(ScreenPtr pScreen) 1220 { 1221 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1222 R128InfoPtr info = R128PTR(pScrn); 1223 1224 R128EnablePageFlip(pScreen); 1225 1226 info->have3DWindows = 1; 1227 } 1228 1229 static void R128DRITransitionTo2d(ScreenPtr pScreen) 1230 { 1231 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1232 R128InfoPtr info = R128PTR(pScrn); 1233 R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); 1234 1235 /* Try flipping back to the front page if necessary */ 1236 if (pSAREAPriv->pfCurrentPage == 1) 1237 drmCommandNone(info->drmFD, DRM_R128_FLIP); 1238 1239 /* Shut down shadowing if we've made it back to the front page */ 1240 if (pSAREAPriv->pfCurrentPage == 0) { 1241 R128DisablePageFlip(pScreen); 1242 } else { 1243 xf86DrvMsg(pScreen->myNum, X_WARNING, 1244 "[dri] R128DRITransitionTo2d: " 1245 "kernel failed to unflip buffers.\n"); 1246 } 1247 1248 info->have3DWindows = 0; 1249 } 1250