patch to import Jon Smirl's work from Bitkeeper
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_screen.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c,v 1.6 2002/12/16 16:18:58 dawes Exp $ */
2 /**************************************************************************
3
4 Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
5 VA Linux Systems Inc., Fremont, California.
6
7 All Rights Reserved.
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 /*
32 * Authors:
33 * Kevin E. Martin <martin@valinux.com>
34 * Gareth Hughes <gareth@valinux.com>
35 *
36 */
37
38 #include "glheader.h"
39 #include "imports.h"
40
41 #include "radeon_context.h"
42 #include "radeon_screen.h"
43 #include "radeon_macros.h"
44
45 #include "utils.h"
46 #include "context.h"
47 #include "vblank.h"
48
49 #ifndef _SOLO
50 #include "glxextensions.h"
51 #endif
52
53 #if 1
54 /* Including xf86PciInfo.h introduces a bunch of errors...
55 */
56 #define PCI_CHIP_RADEON_QD 0x5144
57 #define PCI_CHIP_RADEON_QE 0x5145
58 #define PCI_CHIP_RADEON_QF 0x5146
59 #define PCI_CHIP_RADEON_QG 0x5147
60
61 #define PCI_CHIP_RADEON_QY 0x5159
62 #define PCI_CHIP_RADEON_QZ 0x515A
63
64 #define PCI_CHIP_RADEON_LW 0x4C57 /* mobility 7 - has tcl */
65
66 #define PCI_CHIP_RADEON_LY 0x4C59
67 #define PCI_CHIP_RADEON_LZ 0x4C5A
68
69 #define PCI_CHIP_RV200_QW 0x5157 /* Radeon 7500 - not an R200 at all */
70 #endif
71
72 static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
73
74 /* Create the device specific screen private data struct.
75 */
76 radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv )
77 {
78 radeonScreenPtr screen;
79 RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv;
80
81 if ( ! driCheckDriDdxDrmVersions( sPriv, "Radeon", 4, 0, 4, 0, 1, 3 ) )
82 return NULL;
83
84 /* Allocate the private area */
85 screen = (radeonScreenPtr) CALLOC( sizeof(*screen) );
86 if ( !screen ) {
87 __driUtilMessage("%s: Could not allocate memory for screen structure",
88 __FUNCTION__);
89 return NULL;
90 }
91
92 if ( sPriv->drmMinor < 3 ||
93 getenv("RADEON_COMPAT")) {
94 fprintf( stderr, "Radeon DRI driver:\n\t"
95 "Compatibility mode for DRM driver version %d.%d.%d\n\t"
96 "TCL will be disabled, expect reduced performance\n\t"
97 "(prefer DRM radeon.o 1.3.x or newer)\n\t",
98 sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch );
99 }
100
101
102 /* This is first since which regions we map depends on whether or
103 * not we are using a PCI card.
104 */
105 screen->IsPCI = dri_priv->IsPCI;
106
107 if (sPriv->drmMinor >= 3) {
108 int ret;
109 drmRadeonGetParam gp;
110
111 gp.param = RADEON_PARAM_AGP_BUFFER_OFFSET;
112 gp.value = &screen->agp_buffer_offset;
113
114 ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
115 &gp, sizeof(gp));
116 if (ret) {
117 fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_AGP_BUFFER_OFFSET): %d\n", ret);
118 return NULL;
119 }
120
121 if (sPriv->drmMinor >= 6) {
122 gp.param = RADEON_PARAM_IRQ_NR;
123 gp.value = &screen->irq;
124
125 ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
126 &gp, sizeof(gp));
127 if (ret) {
128 FREE( screen );
129 fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_IRQ_NR): %d\n", ret);
130 return NULL;
131 }
132 }
133 }
134
135 screen->mmio.handle = dri_priv->registerHandle;
136 screen->mmio.size = dri_priv->registerSize;
137 if ( drmMap( sPriv->fd,
138 screen->mmio.handle,
139 screen->mmio.size,
140 &screen->mmio.map ) ) {
141 FREE( screen );
142 __driUtilMessage("%s: drmMap failed\n", __FUNCTION__ );
143 return NULL;
144 }
145
146 screen->status.handle = dri_priv->statusHandle;
147 screen->status.size = dri_priv->statusSize;
148 if ( drmMap( sPriv->fd,
149 screen->status.handle,
150 screen->status.size,
151 &screen->status.map ) ) {
152 drmUnmap( screen->mmio.map, screen->mmio.size );
153 FREE( screen );
154 __driUtilMessage("%s: drmMap (2) failed\n", __FUNCTION__ );
155 return NULL;
156 }
157 screen->scratch = (__volatile__ CARD32 *)
158 ((GLubyte *)screen->status.map + RADEON_SCRATCH_REG_OFFSET);
159
160 screen->buffers = drmMapBufs( sPriv->fd );
161 if ( !screen->buffers ) {
162 drmUnmap( screen->status.map, screen->status.size );
163 drmUnmap( screen->mmio.map, screen->mmio.size );
164 FREE( screen );
165 __driUtilMessage("%s: drmMapBufs failed\n", __FUNCTION__ );
166 return NULL;
167 }
168
169 if ( !screen->IsPCI ) {
170 screen->agpTextures.handle = dri_priv->agpTexHandle;
171 screen->agpTextures.size = dri_priv->agpTexMapSize;
172 if ( drmMap( sPriv->fd,
173 screen->agpTextures.handle,
174 screen->agpTextures.size,
175 (drmAddressPtr)&screen->agpTextures.map ) ) {
176 drmUnmapBufs( screen->buffers );
177 drmUnmap( screen->status.map, screen->status.size );
178 drmUnmap( screen->mmio.map, screen->mmio.size );
179 FREE( screen );
180 __driUtilMessage("%s: IsPCI failed\n", __FUNCTION__);
181 return NULL;
182 }
183 }
184
185 screen->chipset = 0;
186 switch ( dri_priv->deviceID ) {
187 default:
188 fprintf(stderr, "unknown chip id, assuming full radeon support\n");
189 case PCI_CHIP_RADEON_QD:
190 case PCI_CHIP_RADEON_QE:
191 case PCI_CHIP_RADEON_QF:
192 case PCI_CHIP_RADEON_QG:
193 case PCI_CHIP_RV200_QW:
194 case PCI_CHIP_RADEON_LW:
195 screen->chipset |= RADEON_CHIPSET_TCL;
196 case PCI_CHIP_RADEON_QY:
197 case PCI_CHIP_RADEON_QZ:
198 case PCI_CHIP_RADEON_LY:
199 case PCI_CHIP_RADEON_LZ:
200 break;
201 }
202
203 screen->cpp = dri_priv->bpp / 8;
204 screen->AGPMode = dri_priv->AGPMode;
205
206 screen->frontOffset = dri_priv->frontOffset;
207 screen->frontPitch = dri_priv->frontPitch;
208 screen->backOffset = dri_priv->backOffset;
209 screen->backPitch = dri_priv->backPitch;
210 screen->depthOffset = dri_priv->depthOffset;
211 screen->depthPitch = dri_priv->depthPitch;
212
213 screen->texOffset[RADEON_CARD_HEAP] = dri_priv->textureOffset;
214 screen->texSize[RADEON_CARD_HEAP] = dri_priv->textureSize;
215 screen->logTexGranularity[RADEON_CARD_HEAP] =
216 dri_priv->log2TexGran;
217
218 if ( screen->IsPCI
219 || getenv( "RADEON_AGPTEXTURING_FORCE_DISABLE" ) ) {
220 screen->numTexHeaps = RADEON_NR_TEX_HEAPS - 1;
221 screen->texOffset[RADEON_AGP_HEAP] = 0;
222 screen->texSize[RADEON_AGP_HEAP] = 0;
223 screen->logTexGranularity[RADEON_AGP_HEAP] = 0;
224 } else {
225 screen->numTexHeaps = RADEON_NR_TEX_HEAPS;
226 screen->texOffset[RADEON_AGP_HEAP] =
227 dri_priv->agpTexOffset + RADEON_AGP_TEX_OFFSET;
228 screen->texSize[RADEON_AGP_HEAP] = dri_priv->agpTexMapSize;
229 screen->logTexGranularity[RADEON_AGP_HEAP] =
230 dri_priv->log2AGPTexGran;
231 }
232
233 screen->driScreen = sPriv;
234 screen->sarea_priv_offset = dri_priv->sarea_priv_offset;
235 return screen;
236 }
237
238 /* Destroy the device specific screen private data struct.
239 */
240 void radeonDestroyScreen( __DRIscreenPrivate *sPriv )
241 {
242 radeonScreenPtr screen = (radeonScreenPtr)sPriv->private;
243
244 if (!screen)
245 return;
246
247 if ( !screen->IsPCI ) {
248 drmUnmap( screen->agpTextures.map,
249 screen->agpTextures.size );
250 }
251 drmUnmapBufs( screen->buffers );
252 drmUnmap( screen->status.map, screen->status.size );
253 drmUnmap( screen->mmio.map, screen->mmio.size );
254
255 FREE( screen );
256 sPriv->private = NULL;
257 }
258
259
260 /* Initialize the driver specific screen private data.
261 */
262 static GLboolean
263 radeonInitDriver( __DRIscreenPrivate *sPriv )
264 {
265 sPriv->private = (void *) radeonCreateScreen( sPriv );
266 if ( !sPriv->private ) {
267 radeonDestroyScreen( sPriv );
268 return GL_FALSE;
269 }
270
271 return GL_TRUE;
272 }
273
274
275
276 /* Create and initialize the Mesa and driver specific pixmap buffer
277 * data.
278 */
279 static GLboolean
280 radeonCreateBuffer( __DRIscreenPrivate *driScrnPriv,
281 __DRIdrawablePrivate *driDrawPriv,
282 const __GLcontextModes *mesaVis,
283 GLboolean isPixmap )
284 {
285 if (isPixmap) {
286 return GL_FALSE; /* not implemented */
287 }
288 else {
289 const GLboolean swDepth = GL_FALSE;
290 const GLboolean swAlpha = GL_FALSE;
291 const GLboolean swAccum = mesaVis->accumRedBits > 0;
292 const GLboolean swStencil = mesaVis->stencilBits > 0 &&
293 mesaVis->depthBits != 24;
294 driDrawPriv->driverPrivate = (void *)
295 _mesa_create_framebuffer( mesaVis,
296 swDepth,
297 swStencil,
298 swAccum,
299 swAlpha );
300 return (driDrawPriv->driverPrivate != NULL);
301 }
302 }
303
304
305 static void
306 radeonDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
307 {
308 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
309 }
310
311
312
313
314 /* Fullscreen mode isn't used for much -- could be a way to shrink
315 * front/back buffers & get more texture memory if the client has
316 * changed the video resolution.
317 *
318 * Pageflipping is now done automatically whenever there is a single
319 * 3d client.
320 */
321 static GLboolean
322 radeonOpenCloseFullScreen( __DRIcontextPrivate *driContextPriv )
323 {
324 return GL_TRUE;
325 }
326
327 static struct __DriverAPIRec radeonAPI = {
328 .InitDriver = radeonInitDriver,
329 .DestroyScreen = radeonDestroyScreen,
330 .CreateContext = radeonCreateContext,
331 .DestroyContext = radeonDestroyContext,
332 .CreateBuffer = radeonCreateBuffer,
333 .DestroyBuffer = radeonDestroyBuffer,
334 .SwapBuffers = radeonSwapBuffers,
335 .MakeCurrent = radeonMakeCurrent,
336 .UnbindContext = radeonUnbindContext,
337 .OpenFullScreen = radeonOpenCloseFullScreen,
338 .CloseFullScreen = radeonOpenCloseFullScreen,
339 .GetSwapInfo = getSwapInfo,
340 .GetMSC = driGetMSC32,
341 .WaitForMSC = driWaitForMSC32,
342 .WaitForSBC = NULL,
343 .SwapBuffersMSC = NULL
344 };
345
346
347
348 /*
349 * This is the bootstrap function for the driver.
350 * The __driCreateScreen name is the symbol that libGL.so fetches.
351 * Return: pointer to a __DRIscreenPrivate.
352 */
353 #ifndef _SOLO
354 void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
355 int numConfigs, __GLXvisualConfig *config)
356 {
357 __DRIscreenPrivate *psp;
358 psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &radeonAPI);
359 return (void *) psp;
360 }
361 #else
362 void *__driCreateScreen(struct DRIDriverRec *driver,
363 struct DRIDriverContextRec *driverContext)
364 {
365 __DRIscreenPrivate *psp;
366 psp = __driUtilCreateScreen(driver, driverContext, &radeonAPI);
367 return (void *) psp;
368 }
369 #endif
370
371
372 #ifndef _SOLO
373 /* This function is called by libGL.so as soon as libGL.so is loaded.
374 * This is where we'd register new extension functions with the dispatcher.
375 */
376 void
377 __driRegisterExtensions( void )
378 {
379 PFNGLXENABLEEXTENSIONPROC glx_enable_extension;
380
381
382 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
383 glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC)
384 glXGetProcAddress( "__glXEnableExtension" );
385
386 if ( glx_enable_extension != NULL ) {
387 glx_enable_extension( "GLX_SGI_swap_control", GL_FALSE );
388 glx_enable_extension( "GLX_SGI_video_sync", GL_FALSE );
389 glx_enable_extension( "GLX_MESA_swap_control", GL_FALSE );
390 glx_enable_extension( "GLX_MESA_swap_frame_usage", GL_FALSE );
391 }
392 }
393 }
394 #endif
395
396
397 /**
398 * Get information about previous buffer swaps.
399 */
400 static int
401 getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo )
402 {
403 radeonContextPtr rmesa;
404
405 if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL)
406 || (dPriv->driContextPriv->driverPrivate == NULL)
407 || (sInfo == NULL) ) {
408 return -1;
409 }
410
411 rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
412 sInfo->swap_count = rmesa->swap_count;
413 sInfo->swap_ust = rmesa->swap_ust;
414 sInfo->swap_missed_count = rmesa->swap_missed_count;
415
416 sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
417 ? driCalculateSwapUsage( dPriv, 0, rmesa->swap_missed_ust )
418 : 0.0;
419
420 return 0;
421 }