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