radeon_screen.c revision de7b071b5534fc423a056abd521de8bf9120f89e
1/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c,v 1.7 2003/03/26 20:43:51 tsi Exp $ */
2/**************************************************************************
3
4Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
5                     VA Linux Systems Inc., Fremont, California.
6
7All Rights Reserved.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice (including the
18next paragraph) shall be included in all copies or substantial
19portions of the Software.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29**************************************************************************/
30
31/**
32 * \file radeon_screen.c
33 * Screen initialization functions for the Radeon driver.
34 *
35 * \author Kevin E. Martin <martin@valinux.com>
36 * \author  Gareth Hughes <gareth@valinux.com>
37 */
38
39#include "glheader.h"
40#include "imports.h"
41
42#define STANDALONE_MMIO
43#include "radeon_context.h"
44#include "radeon_screen.h"
45#include "radeon_macros.h"
46
47#include "utils.h"
48#include "context.h"
49#include "vblank.h"
50
51#include "GL/internal/dri_interface.h"
52
53/* Radeon configuration
54 */
55#include "xmlpool.h"
56
57const char __driConfigOptions[] =
58DRI_CONF_BEGIN
59    DRI_CONF_SECTION_PERFORMANCE
60        DRI_CONF_TCL_MODE(DRI_CONF_TCL_CODEGEN)
61        DRI_CONF_FTHROTTLE_MODE(DRI_CONF_FTHROTTLE_IRQS)
62        DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0)
63    DRI_CONF_SECTION_END
64    DRI_CONF_SECTION_QUALITY
65        DRI_CONF_TEXTURE_DEPTH(DRI_CONF_TEXTURE_DEPTH_FB)
66        DRI_CONF_DEF_MAX_ANISOTROPY(1.0,"1.0,2.0,4.0,8.0,16.0")
67        DRI_CONF_NO_NEG_LOD_BIAS(false)
68        DRI_CONF_FORCE_S3TC_ENABLE(false)
69        DRI_CONF_COLOR_REDUCTION(DRI_CONF_COLOR_REDUCTION_DITHER)
70        DRI_CONF_ROUND_MODE(DRI_CONF_ROUND_TRUNC)
71        DRI_CONF_DITHER_MODE(DRI_CONF_DITHER_XERRORDIFF)
72    DRI_CONF_SECTION_END
73    DRI_CONF_SECTION_DEBUG
74        DRI_CONF_NO_RAST(false)
75    DRI_CONF_SECTION_END
76DRI_CONF_END;
77static const GLuint __driNConfigOptions = 11;
78
79#if 1
80/* Including xf86PciInfo.h introduces a bunch of errors...
81 */
82#define PCI_CHIP_RADEON_QD	0x5144
83#define PCI_CHIP_RADEON_QE	0x5145
84#define PCI_CHIP_RADEON_QF	0x5146
85#define PCI_CHIP_RADEON_QG	0x5147
86
87#define PCI_CHIP_RADEON_QY	0x5159
88#define PCI_CHIP_RADEON_QZ	0x515A
89
90#define PCI_CHIP_RADEON_LW	0x4C57 /* mobility 7 - has tcl */
91#define PCI_CHIP_RADEON_LX	0x4C58 /* mobility FireGL 7800 m7 */
92
93#define PCI_CHIP_RADEON_LY	0x4C59
94#define PCI_CHIP_RADEON_LZ	0x4C5A
95
96#define PCI_CHIP_RV200_QW	0x5157 /* Radeon 7500 - not an R200 at all */
97#define PCI_CHIP_RV200_QX	0x5158
98
99/* IGP Chipsets */
100#define PCI_CHIP_RS100_4136     0x4136
101#define PCI_CHIP_RS200_4137     0x4137
102#define PCI_CHIP_RS250_4237     0x4237
103#define PCI_CHIP_RS100_4336     0x4336
104#define PCI_CHIP_RS200_4337     0x4337
105#define PCI_CHIP_RS250_4437     0x4437
106#endif
107
108#ifdef USE_NEW_INTERFACE
109static PFNGLXCREATECONTEXTMODES create_context_modes = NULL;
110#endif /* USE_NEW_INTERFACE */
111
112static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
113
114#ifdef USE_NEW_INTERFACE
115static __GLcontextModes *
116radeonFillInModes( unsigned pixel_bits, unsigned depth_bits,
117		 unsigned stencil_bits, GLboolean have_back_buffer )
118{
119    __GLcontextModes * modes;
120    __GLcontextModes * m;
121    unsigned num_modes;
122    unsigned depth_buffer_factor;
123    unsigned back_buffer_factor;
124    GLenum fb_format;
125    GLenum fb_type;
126
127    /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
128     * enough to add support.  Basically, if a context is created with an
129     * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
130     * will never be used.
131     */
132    static const GLenum back_buffer_modes[] = {
133	GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
134    };
135
136    uint8_t depth_bits_array[2];
137    uint8_t stencil_bits_array[2];
138
139
140    depth_bits_array[0] = depth_bits;
141    depth_bits_array[1] = depth_bits;
142
143    /* Just like with the accumulation buffer, always provide some modes
144     * with a stencil buffer.  It will be a sw fallback, but some apps won't
145     * care about that.
146     */
147    stencil_bits_array[0] = 0;
148    stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
149
150    depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
151    back_buffer_factor  = (have_back_buffer) ? 2 : 1;
152
153    num_modes = depth_buffer_factor * back_buffer_factor * 4;
154
155    if ( pixel_bits == 16 ) {
156        fb_format = GL_RGB;
157        fb_type = GL_UNSIGNED_SHORT_5_6_5;
158    }
159    else {
160        fb_format = GL_BGRA;
161        fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
162    }
163
164    modes = (*create_context_modes)( num_modes, sizeof( __GLcontextModes ) );
165    m = modes;
166    if ( ! driFillInModes( & m, fb_format, fb_type,
167			   depth_bits_array, stencil_bits_array, depth_buffer_factor,
168			   back_buffer_modes, back_buffer_factor,
169			   GLX_TRUE_COLOR ) ) {
170	fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
171		 __func__, __LINE__ );
172	return NULL;
173    }
174
175    if ( ! driFillInModes( & m, fb_format, fb_type,
176			   depth_bits_array, stencil_bits_array, depth_buffer_factor,
177			   back_buffer_modes, back_buffer_factor,
178			   GLX_DIRECT_COLOR ) ) {
179	fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
180		 __func__, __LINE__ );
181	return NULL;
182    }
183
184    /* Mark the visual as slow if there are "fake" stencil bits.
185     */
186    for ( m = modes ; m != NULL ; m = m->next ) {
187	if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) {
188	    m->visualRating = GLX_SLOW_CONFIG;
189	}
190    }
191
192    return modes;
193}
194#endif /* USE_NEW_INTERFACE */
195
196/* Create the device specific screen private data struct.
197 */
198radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv )
199{
200   radeonScreenPtr screen;
201   RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv;
202   unsigned char *RADEONMMIO;
203
204
205   /* Allocate the private area */
206   screen = (radeonScreenPtr) CALLOC( sizeof(*screen) );
207   if ( !screen ) {
208      __driUtilMessage("%s: Could not allocate memory for screen structure",
209		       __FUNCTION__);
210      return NULL;
211   }
212
213   /* parse information in __driConfigOptions */
214   driParseOptionInfo (&screen->optionCache,
215		       __driConfigOptions, __driNConfigOptions);
216
217   /* This is first since which regions we map depends on whether or
218    * not we are using a PCI card.
219    */
220   screen->IsPCI = dri_priv->IsPCI;
221
222   {
223      int ret;
224      drm_radeon_getparam_t gp;
225
226      gp.param = RADEON_PARAM_GART_BUFFER_OFFSET;
227      gp.value = &screen->gart_buffer_offset;
228
229      ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
230				 &gp, sizeof(gp));
231      if (ret) {
232	 FREE( screen );
233	 fprintf(stderr, "drm_radeon_getparam_t (RADEON_PARAM_GART_BUFFER_OFFSET): %d\n", ret);
234	 return NULL;
235      }
236
237      if (sPriv->drmMinor >= 6) {
238	 gp.param = RADEON_PARAM_IRQ_NR;
239	 gp.value = &screen->irq;
240
241	 ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
242				    &gp, sizeof(gp));
243	 if (ret) {
244	    FREE( screen );
245	    fprintf(stderr, "drm_radeon_getparam_t (RADEON_PARAM_IRQ_NR): %d\n", ret);
246	    return NULL;
247	 }
248      }
249   }
250
251   screen->mmio.handle = dri_priv->registerHandle;
252   screen->mmio.size   = dri_priv->registerSize;
253   if ( drmMap( sPriv->fd,
254		screen->mmio.handle,
255		screen->mmio.size,
256		&screen->mmio.map ) ) {
257      FREE( screen );
258      __driUtilMessage("%s: drmMap failed\n", __FUNCTION__ );
259      return NULL;
260   }
261
262   RADEONMMIO = screen->mmio.map;
263
264   screen->status.handle = dri_priv->statusHandle;
265   screen->status.size   = dri_priv->statusSize;
266   if ( drmMap( sPriv->fd,
267		screen->status.handle,
268		screen->status.size,
269		&screen->status.map ) ) {
270      drmUnmap( screen->mmio.map, screen->mmio.size );
271      FREE( screen );
272      __driUtilMessage("%s: drmMap (2) failed\n", __FUNCTION__ );
273      return NULL;
274   }
275   screen->scratch = (__volatile__ uint32_t *)
276      ((GLubyte *)screen->status.map + RADEON_SCRATCH_REG_OFFSET);
277
278   screen->buffers = drmMapBufs( sPriv->fd );
279   if ( !screen->buffers ) {
280      drmUnmap( screen->status.map, screen->status.size );
281      drmUnmap( screen->mmio.map, screen->mmio.size );
282      FREE( screen );
283      __driUtilMessage("%s: drmMapBufs failed\n", __FUNCTION__ );
284      return NULL;
285   }
286
287   if ( dri_priv->gartTexHandle && dri_priv->gartTexMapSize ) {
288      screen->gartTextures.handle = dri_priv->gartTexHandle;
289      screen->gartTextures.size   = dri_priv->gartTexMapSize;
290      if ( drmMap( sPriv->fd,
291		   screen->gartTextures.handle,
292		   screen->gartTextures.size,
293		   (drmAddressPtr)&screen->gartTextures.map ) ) {
294	 drmUnmapBufs( screen->buffers );
295	 drmUnmap( screen->status.map, screen->status.size );
296	 drmUnmap( screen->mmio.map, screen->mmio.size );
297	 FREE( screen );
298	 __driUtilMessage("%s: drmMap failed for GART texture area\n", __FUNCTION__);
299	 return NULL;
300      }
301
302      screen->gart_texture_offset = dri_priv->gartTexOffset + ( screen->IsPCI
303		? INREG( RADEON_AIC_LO_ADDR )
304		: ( ( INREG( RADEON_MC_AGP_LOCATION ) & 0x0ffffU ) << 16 ) );
305   }
306
307   screen->chipset = 0;
308   switch ( dri_priv->deviceID ) {
309   default:
310      fprintf(stderr, "unknown chip id, assuming full radeon support\n");
311   case PCI_CHIP_RADEON_QD:
312   case PCI_CHIP_RADEON_QE:
313   case PCI_CHIP_RADEON_QF:
314   case PCI_CHIP_RADEON_QG:
315      /* all original radeons (7200) presumably have a stencil op bug */
316      screen->chipset |= RADEON_CHIPSET_BROKEN_STENCIL;
317   case PCI_CHIP_RV200_QW:
318   case PCI_CHIP_RV200_QX:
319   case PCI_CHIP_RADEON_LW:
320   case PCI_CHIP_RADEON_LX:
321      screen->chipset |= RADEON_CHIPSET_TCL;
322   case PCI_CHIP_RADEON_QY:
323   case PCI_CHIP_RADEON_QZ:
324   case PCI_CHIP_RADEON_LY:
325   case PCI_CHIP_RADEON_LZ:
326   case PCI_CHIP_RS100_4136: /* IGPs don't have TCL */
327   case PCI_CHIP_RS200_4137:
328   case PCI_CHIP_RS250_4237:
329   case PCI_CHIP_RS100_4336:
330   case PCI_CHIP_RS200_4337:
331   case PCI_CHIP_RS250_4437:
332      break;
333   }
334
335   screen->cpp = dri_priv->bpp / 8;
336   screen->AGPMode = dri_priv->AGPMode;
337
338   screen->fbLocation	= ( INREG( RADEON_MC_FB_LOCATION ) & 0xffff ) << 16;
339
340   if ( sPriv->drmMinor >= 10 ) {
341      drm_radeon_setparam_t sp;
342
343      sp.param = RADEON_SETPARAM_FB_LOCATION;
344      sp.value = screen->fbLocation;
345
346      drmCommandWrite( sPriv->fd, DRM_RADEON_SETPARAM,
347		       &sp, sizeof( sp ) );
348   }
349
350   screen->frontOffset	= dri_priv->frontOffset;
351   screen->frontPitch	= dri_priv->frontPitch;
352   screen->backOffset	= dri_priv->backOffset;
353   screen->backPitch	= dri_priv->backPitch;
354   screen->depthOffset	= dri_priv->depthOffset;
355   screen->depthPitch	= dri_priv->depthPitch;
356
357   screen->texOffset[RADEON_LOCAL_TEX_HEAP] = dri_priv->textureOffset
358				       + screen->fbLocation;
359   screen->texSize[RADEON_LOCAL_TEX_HEAP] = dri_priv->textureSize;
360   screen->logTexGranularity[RADEON_LOCAL_TEX_HEAP] =
361      dri_priv->log2TexGran;
362
363   if ( !screen->gartTextures.map
364	|| getenv( "RADEON_GARTTEXTURING_FORCE_DISABLE" ) ) {
365      screen->numTexHeaps = RADEON_NR_TEX_HEAPS - 1;
366      screen->texOffset[RADEON_GART_TEX_HEAP] = 0;
367      screen->texSize[RADEON_GART_TEX_HEAP] = 0;
368      screen->logTexGranularity[RADEON_GART_TEX_HEAP] = 0;
369   } else {
370      screen->numTexHeaps = RADEON_NR_TEX_HEAPS;
371      screen->texOffset[RADEON_GART_TEX_HEAP] = screen->gart_texture_offset;
372      screen->texSize[RADEON_GART_TEX_HEAP] = dri_priv->gartTexMapSize;
373      screen->logTexGranularity[RADEON_GART_TEX_HEAP] =
374	 dri_priv->log2GARTTexGran;
375   }
376
377   if ( driCompareGLXAPIVersion( 20030813 ) >= 0 ) {
378      PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension =
379          (PFNGLXSCRENABLEEXTENSIONPROC) glXGetProcAddress( (const GLubyte *) "__glXScrEnableExtension" );
380      void * const psc = sPriv->psc->screenConfigs;
381
382      if ( glx_enable_extension != NULL ) {
383	 if ( screen->irq != 0 ) {
384	    (*glx_enable_extension)( psc, "GLX_SGI_swap_control" );
385	    (*glx_enable_extension)( psc, "GLX_SGI_video_sync" );
386	    (*glx_enable_extension)( psc, "GLX_MESA_swap_control" );
387	 }
388
389	 (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" );
390
391         if ( driCompareGLXAPIVersion( 20030915 ) >= 0 ) {
392	    (*glx_enable_extension)( psc, "GLX_SGIX_fbconfig" );
393	    (*glx_enable_extension)( psc, "GLX_OML_swap_method" );
394	 }
395
396      }
397   }
398
399   screen->driScreen = sPriv;
400   screen->sarea_priv_offset = dri_priv->sarea_priv_offset;
401   return screen;
402}
403
404/* Destroy the device specific screen private data struct.
405 */
406void radeonDestroyScreen( __DRIscreenPrivate *sPriv )
407{
408   radeonScreenPtr screen = (radeonScreenPtr)sPriv->private;
409
410   if (!screen)
411      return;
412
413   if ( screen->gartTextures.map ) {
414      drmUnmap( screen->gartTextures.map, screen->gartTextures.size );
415   }
416   drmUnmapBufs( screen->buffers );
417   drmUnmap( screen->status.map, screen->status.size );
418   drmUnmap( screen->mmio.map, screen->mmio.size );
419
420   /* free all option information */
421   driDestroyOptionInfo (&screen->optionCache);
422
423   FREE( screen );
424   sPriv->private = NULL;
425}
426
427
428/* Initialize the driver specific screen private data.
429 */
430static GLboolean
431radeonInitDriver( __DRIscreenPrivate *sPriv )
432{
433   sPriv->private = (void *) radeonCreateScreen( sPriv );
434   if ( !sPriv->private ) {
435      radeonDestroyScreen( sPriv );
436      return GL_FALSE;
437   }
438
439   return GL_TRUE;
440}
441
442
443
444/**
445 * Create and initialize the Mesa and driver specific pixmap buffer
446 * data.
447 *
448 * \todo This function (and its interface) will need to be updated to support
449 * pbuffers.
450 */
451static GLboolean
452radeonCreateBuffer( __DRIscreenPrivate *driScrnPriv,
453                    __DRIdrawablePrivate *driDrawPriv,
454                    const __GLcontextModes *mesaVis,
455                    GLboolean isPixmap )
456{
457   if (isPixmap) {
458      return GL_FALSE; /* not implemented */
459   }
460   else {
461      const GLboolean swDepth = GL_FALSE;
462      const GLboolean swAlpha = GL_FALSE;
463      const GLboolean swAccum = mesaVis->accumRedBits > 0;
464      const GLboolean swStencil = mesaVis->stencilBits > 0 &&
465         mesaVis->depthBits != 24;
466      driDrawPriv->driverPrivate = (void *)
467         _mesa_create_framebuffer( mesaVis,
468                                   swDepth,
469                                   swStencil,
470                                   swAccum,
471                                   swAlpha );
472      return (driDrawPriv->driverPrivate != NULL);
473   }
474}
475
476
477static void
478radeonDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
479{
480   _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
481}
482
483static struct __DriverAPIRec radeonAPI = {
484   .InitDriver      = radeonInitDriver,
485   .DestroyScreen   = radeonDestroyScreen,
486   .CreateContext   = radeonCreateContext,
487   .DestroyContext  = radeonDestroyContext,
488   .CreateBuffer    = radeonCreateBuffer,
489   .DestroyBuffer   = radeonDestroyBuffer,
490   .SwapBuffers     = radeonSwapBuffers,
491   .MakeCurrent     = radeonMakeCurrent,
492   .UnbindContext   = radeonUnbindContext,
493   .GetSwapInfo     = getSwapInfo,
494   .GetMSC          = driGetMSC32,
495   .WaitForMSC      = driWaitForMSC32,
496   .WaitForSBC      = NULL,
497   .SwapBuffersMSC  = NULL
498};
499
500
501/*
502 * This is the bootstrap function for the driver.
503 * The __driCreateScreen name is the symbol that libGL.so fetches.
504 * Return:  pointer to a __DRIscreenPrivate.
505 */
506#if !defined(DRI_NEW_INTERFACE_ONLY)
507void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
508                        int numConfigs, __GLXvisualConfig *config)
509{
510   __DRIscreenPrivate *psp;
511   psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &radeonAPI);
512   return (void *) psp;
513}
514#endif /* !defined(DRI_NEW_INTERFACE_ONLY) */
515
516/**
517 * This is the bootstrap function for the driver.  libGL supplies all of the
518 * requisite information about the system, and the driver initializes itself.
519 * This routine also fills in the linked list pointed to by \c driver_modes
520 * with the \c __GLcontextModes that the driver can support for windows or
521 * pbuffers.
522 *
523 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
524 *         failure.
525 */
526#ifdef USE_NEW_INTERFACE
527void * __driCreateNewScreen( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
528			     const __GLcontextModes * modes,
529			     const __DRIversion * ddx_version,
530			     const __DRIversion * dri_version,
531			     const __DRIversion * drm_version,
532			     const __DRIframebuffer * frame_buffer,
533			     drmAddress pSAREA, int fd,
534			     int internal_api_version,
535			     __GLcontextModes ** driver_modes )
536
537{
538   __DRIscreenPrivate *psp;
539   static const __DRIversion ddx_expected = { 4, 0, 0 };
540   static const __DRIversion dri_expected = { 4, 0, 0 };
541   static const __DRIversion drm_expected = { 1, 3, 0 };
542
543   if ( ! driCheckDriDdxDrmVersions2( "Radeon",
544				      dri_version, & dri_expected,
545				      ddx_version, & ddx_expected,
546				      drm_version, & drm_expected ) ) {
547      return NULL;
548   }
549
550   psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
551				  ddx_version, dri_version, drm_version,
552				  frame_buffer, pSAREA, fd,
553				  internal_api_version, &radeonAPI);
554   if ( psp != NULL ) {
555      create_context_modes = (PFNGLXCREATECONTEXTMODES)
556	  glXGetProcAddress( (const GLubyte *) "__glXCreateContextModes" );
557      if ( create_context_modes != NULL ) {
558	 RADEONDRIPtr dri_priv = (RADEONDRIPtr) psp->pDevPriv;
559	 *driver_modes = radeonFillInModes( dri_priv->bpp,
560					    (dri_priv->bpp == 16) ? 16 : 24,
561					    (dri_priv->bpp == 16) ? 0  : 8,
562					    (dri_priv->backOffset != dri_priv->depthOffset) );
563      }
564   }
565
566   return (void *) psp;
567}
568#endif /* USE_NEW_INTERFACE */
569
570/**
571 * Get information about previous buffer swaps.
572 */
573static int
574getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo )
575{
576   radeonContextPtr  rmesa;
577
578   if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL)
579	|| (dPriv->driContextPriv->driverPrivate == NULL)
580	|| (sInfo == NULL) ) {
581      return -1;
582   }
583
584   rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
585   sInfo->swap_count = rmesa->swap_count;
586   sInfo->swap_ust = rmesa->swap_ust;
587   sInfo->swap_missed_count = rmesa->swap_missed_count;
588
589   sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
590       ? driCalculateSwapUsage( dPriv, 0, rmesa->swap_missed_ust )
591       : 0.0;
592
593   return 0;
594}
595