radeon_screen.c revision effc73931f86c7961b4eb296d2d4c5d91624a9e3
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 * 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/* 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_COLOR_REDUCTION(DRI_CONF_COLOR_REDUCTION_DITHER)
69        DRI_CONF_ROUND_MODE(DRI_CONF_ROUND_TRUNC)
70        DRI_CONF_DITHER_MODE(DRI_CONF_DITHER_XERRORDIFF)
71    DRI_CONF_SECTION_END
72    DRI_CONF_SECTION_DEBUG
73        DRI_CONF_NO_RAST(false)
74    DRI_CONF_SECTION_END
75DRI_CONF_END;
76static const GLuint __driNConfigOptions = 10;
77
78#if 1
79/* Including xf86PciInfo.h introduces a bunch of errors...
80 */
81#define PCI_CHIP_RADEON_QD	0x5144
82#define PCI_CHIP_RADEON_QE	0x5145
83#define PCI_CHIP_RADEON_QF	0x5146
84#define PCI_CHIP_RADEON_QG	0x5147
85
86#define PCI_CHIP_RADEON_QY	0x5159
87#define PCI_CHIP_RADEON_QZ	0x515A
88
89#define PCI_CHIP_RADEON_LW	0x4C57 /* mobility 7 - has tcl */
90
91#define PCI_CHIP_RADEON_LY	0x4C59
92#define PCI_CHIP_RADEON_LZ	0x4C5A
93
94#define PCI_CHIP_RV200_QW	0x5157 /* Radeon 7500 - not an R200 at all */
95#endif
96
97static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
98
99/* Create the device specific screen private data struct.
100 */
101radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv )
102{
103   radeonScreenPtr screen;
104   RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv;
105   unsigned char *RADEONMMIO;
106
107   if ( ! driCheckDriDdxDrmVersions( sPriv, "Radeon", 4, 0, 4, 0, 1, 3 ) )
108      return NULL;
109
110   /* Allocate the private area */
111   screen = (radeonScreenPtr) CALLOC( sizeof(*screen) );
112   if ( !screen ) {
113      __driUtilMessage("%s: Could not allocate memory for screen structure",
114		       __FUNCTION__);
115      return NULL;
116   }
117
118   /* parse information in __driConfigOptions */
119   driParseOptionInfo (&screen->optionCache,
120		       __driConfigOptions, __driNConfigOptions);
121
122   /* This is first since which regions we map depends on whether or
123    * not we are using a PCI card.
124    */
125   screen->IsPCI = dri_priv->IsPCI;
126
127   {
128      int ret;
129      drmRadeonGetParam gp;
130
131      gp.param = RADEON_PARAM_GART_BUFFER_OFFSET;
132      gp.value = &screen->gart_buffer_offset;
133
134      ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
135				 &gp, sizeof(gp));
136      if (ret) {
137	 FREE( screen );
138	 fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_GART_BUFFER_OFFSET): %d\n", ret);
139	 return NULL;
140      }
141
142      if (sPriv->drmMinor >= 6) {
143	 gp.param = RADEON_PARAM_IRQ_NR;
144	 gp.value = &screen->irq;
145
146	 ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
147				    &gp, sizeof(gp));
148	 if (ret) {
149	    FREE( screen );
150	    fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_IRQ_NR): %d\n", ret);
151	    return NULL;
152	 }
153      }
154   }
155
156   screen->mmio.handle = dri_priv->registerHandle;
157   screen->mmio.size   = dri_priv->registerSize;
158   if ( drmMap( sPriv->fd,
159		screen->mmio.handle,
160		screen->mmio.size,
161		&screen->mmio.map ) ) {
162      FREE( screen );
163      __driUtilMessage("%s: drmMap failed\n", __FUNCTION__ );
164      return NULL;
165   }
166
167   RADEONMMIO = screen->mmio.map;
168
169   screen->status.handle = dri_priv->statusHandle;
170   screen->status.size   = dri_priv->statusSize;
171   if ( drmMap( sPriv->fd,
172		screen->status.handle,
173		screen->status.size,
174		&screen->status.map ) ) {
175      drmUnmap( screen->mmio.map, screen->mmio.size );
176      FREE( screen );
177      __driUtilMessage("%s: drmMap (2) failed\n", __FUNCTION__ );
178      return NULL;
179   }
180   screen->scratch = (__volatile__ CARD32 *)
181      ((GLubyte *)screen->status.map + RADEON_SCRATCH_REG_OFFSET);
182
183   screen->buffers = drmMapBufs( sPriv->fd );
184   if ( !screen->buffers ) {
185      drmUnmap( screen->status.map, screen->status.size );
186      drmUnmap( screen->mmio.map, screen->mmio.size );
187      FREE( screen );
188      __driUtilMessage("%s: drmMapBufs failed\n", __FUNCTION__ );
189      return NULL;
190   }
191
192   if ( dri_priv->gartTexHandle && dri_priv->gartTexMapSize ) {
193      screen->gartTextures.handle = dri_priv->gartTexHandle;
194      screen->gartTextures.size   = dri_priv->gartTexMapSize;
195      if ( drmMap( sPriv->fd,
196		   screen->gartTextures.handle,
197		   screen->gartTextures.size,
198		   (drmAddressPtr)&screen->gartTextures.map ) ) {
199	 drmUnmapBufs( screen->buffers );
200	 drmUnmap( screen->status.map, screen->status.size );
201	 drmUnmap( screen->mmio.map, screen->mmio.size );
202	 FREE( screen );
203	 __driUtilMessage("%s: drmMap failed for GART texture area\n", __FUNCTION__);
204	 return NULL;
205      }
206
207      screen->gart_texture_offset = dri_priv->gartTexOffset + ( screen->IsPCI
208		? INREG( RADEON_AIC_LO_ADDR )
209		: ( ( INREG( RADEON_MC_AGP_LOCATION ) & 0x0ffffU ) << 16 ) );
210   }
211
212   screen->chipset = 0;
213   switch ( dri_priv->deviceID ) {
214   default:
215      fprintf(stderr, "unknown chip id, assuming full radeon support\n");
216   case PCI_CHIP_RADEON_QD:
217   case PCI_CHIP_RADEON_QE:
218   case PCI_CHIP_RADEON_QF:
219   case PCI_CHIP_RADEON_QG:
220   case PCI_CHIP_RV200_QW:
221   case PCI_CHIP_RADEON_LW:
222      screen->chipset |= RADEON_CHIPSET_TCL;
223   case PCI_CHIP_RADEON_QY:
224   case PCI_CHIP_RADEON_QZ:
225   case PCI_CHIP_RADEON_LY:
226   case PCI_CHIP_RADEON_LZ:
227      break;
228   }
229
230   screen->cpp = dri_priv->bpp / 8;
231   screen->AGPMode = dri_priv->AGPMode;
232
233   screen->fbLocation	= ( INREG( RADEON_MC_FB_LOCATION ) & 0xffff ) << 16;
234
235   if ( sPriv->drmMinor >= 10 ) {
236      drmRadeonSetParam sp;
237
238      sp.param = RADEON_SETPARAM_FB_LOCATION;
239      sp.value = screen->fbLocation;
240
241      drmCommandWrite( sPriv->fd, DRM_RADEON_SETPARAM,
242		       &sp, sizeof( sp ) );
243   }
244
245   screen->frontOffset	= dri_priv->frontOffset;
246   screen->frontPitch	= dri_priv->frontPitch;
247   screen->backOffset	= dri_priv->backOffset;
248   screen->backPitch	= dri_priv->backPitch;
249   screen->depthOffset	= dri_priv->depthOffset;
250   screen->depthPitch	= dri_priv->depthPitch;
251
252   screen->texOffset[RADEON_CARD_HEAP] = dri_priv->textureOffset
253				       + screen->fbLocation;
254   screen->texSize[RADEON_CARD_HEAP] = dri_priv->textureSize;
255   screen->logTexGranularity[RADEON_CARD_HEAP] =
256      dri_priv->log2TexGran;
257
258   if ( !screen->gartTextures.map
259	|| getenv( "RADEON_GARTTEXTURING_FORCE_DISABLE" ) ) {
260      screen->numTexHeaps = RADEON_NR_TEX_HEAPS - 1;
261      screen->texOffset[RADEON_GART_HEAP] = 0;
262      screen->texSize[RADEON_GART_HEAP] = 0;
263      screen->logTexGranularity[RADEON_GART_HEAP] = 0;
264   } else {
265      screen->numTexHeaps = RADEON_NR_TEX_HEAPS;
266      screen->texOffset[RADEON_GART_HEAP] = screen->gart_texture_offset;
267      screen->texSize[RADEON_GART_HEAP] = dri_priv->gartTexMapSize;
268      screen->logTexGranularity[RADEON_GART_HEAP] =
269	 dri_priv->log2GARTTexGran;
270   }
271#ifndef _SOLO
272   if ( driCompareGLXAPIVersion( 20030813 ) >= 0 ) {
273      PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension =
274          (PFNGLXSCRENABLEEXTENSIONPROC) glXGetProcAddress( (const GLubyte *) "__glXScrEnableExtension" );
275      void * const psc = sPriv->psc->screenConfigs;
276
277      if ( glx_enable_extension != NULL ) {
278	 if ( screen->irq != 0 ) {
279	    (*glx_enable_extension)( psc, "GLX_SGI_swap_control" );
280	    (*glx_enable_extension)( psc, "GLX_SGI_video_sync" );
281	    (*glx_enable_extension)( psc, "GLX_MESA_swap_control" );
282	 }
283
284	 (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" );
285      }
286   }
287#endif
288   screen->driScreen = sPriv;
289   screen->sarea_priv_offset = dri_priv->sarea_priv_offset;
290   return screen;
291}
292
293/* Destroy the device specific screen private data struct.
294 */
295void radeonDestroyScreen( __DRIscreenPrivate *sPriv )
296{
297   radeonScreenPtr screen = (radeonScreenPtr)sPriv->private;
298
299   if (!screen)
300      return;
301
302   if ( screen->gartTextures.map ) {
303      drmUnmap( screen->gartTextures.map, screen->gartTextures.size );
304   }
305   drmUnmapBufs( screen->buffers );
306   drmUnmap( screen->status.map, screen->status.size );
307   drmUnmap( screen->mmio.map, screen->mmio.size );
308
309   /* free all option information */
310   driDestroyOptionInfo (&screen->optionCache);
311
312   FREE( screen );
313   sPriv->private = NULL;
314}
315
316
317/* Initialize the driver specific screen private data.
318 */
319static GLboolean
320radeonInitDriver( __DRIscreenPrivate *sPriv )
321{
322   sPriv->private = (void *) radeonCreateScreen( sPriv );
323   if ( !sPriv->private ) {
324      radeonDestroyScreen( sPriv );
325      return GL_FALSE;
326   }
327
328   return GL_TRUE;
329}
330
331
332
333/* Create and initialize the Mesa and driver specific pixmap buffer
334 * data.
335 */
336static GLboolean
337radeonCreateBuffer( __DRIscreenPrivate *driScrnPriv,
338                    __DRIdrawablePrivate *driDrawPriv,
339                    const __GLcontextModes *mesaVis,
340                    GLboolean isPixmap )
341{
342   if (isPixmap) {
343      return GL_FALSE; /* not implemented */
344   }
345   else {
346      const GLboolean swDepth = GL_FALSE;
347      const GLboolean swAlpha = GL_FALSE;
348      const GLboolean swAccum = mesaVis->accumRedBits > 0;
349      const GLboolean swStencil = mesaVis->stencilBits > 0 &&
350         mesaVis->depthBits != 24;
351      driDrawPriv->driverPrivate = (void *)
352         _mesa_create_framebuffer( mesaVis,
353                                   swDepth,
354                                   swStencil,
355                                   swAccum,
356                                   swAlpha );
357      return (driDrawPriv->driverPrivate != NULL);
358   }
359}
360
361
362static void
363radeonDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
364{
365   _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
366}
367
368
369
370
371/* Fullscreen mode isn't used for much -- could be a way to shrink
372 * front/back buffers & get more texture memory if the client has
373 * changed the video resolution.
374 *
375 * Pageflipping is now done automatically whenever there is a single
376 * 3d client.
377 */
378static GLboolean
379radeonOpenCloseFullScreen( __DRIcontextPrivate *driContextPriv )
380{
381   return GL_TRUE;
382}
383
384static struct __DriverAPIRec radeonAPI = {
385   .InitDriver      = radeonInitDriver,
386   .DestroyScreen   = radeonDestroyScreen,
387   .CreateContext   = radeonCreateContext,
388   .DestroyContext  = radeonDestroyContext,
389   .CreateBuffer    = radeonCreateBuffer,
390   .DestroyBuffer   = radeonDestroyBuffer,
391   .SwapBuffers     = radeonSwapBuffers,
392   .MakeCurrent     = radeonMakeCurrent,
393   .UnbindContext   = radeonUnbindContext,
394   .OpenFullScreen  = radeonOpenCloseFullScreen,
395   .CloseFullScreen = radeonOpenCloseFullScreen,
396   .GetSwapInfo     = getSwapInfo,
397   .GetMSC          = driGetMSC32,
398   .WaitForMSC      = driWaitForMSC32,
399   .WaitForSBC      = NULL,
400   .SwapBuffersMSC  = NULL
401};
402
403
404
405/*
406 * This is the bootstrap function for the driver.
407 * The __driCreateScreen name is the symbol that libGL.so fetches.
408 * Return:  pointer to a __DRIscreenPrivate.
409 */
410#ifndef _SOLO
411void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
412                        int numConfigs, __GLXvisualConfig *config)
413{
414   __DRIscreenPrivate *psp;
415   psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &radeonAPI);
416   return (void *) psp;
417}
418#else
419void *__driCreateScreen(struct DRIDriverRec *driver,
420                        struct DRIDriverContextRec *driverContext)
421{
422   __DRIscreenPrivate *psp;
423   psp = __driUtilCreateScreen(driver, driverContext, &radeonAPI);
424   return (void *) psp;
425}
426#endif
427
428#ifndef _SOLO
429/**
430 * This function is called by libGL.so as soon as libGL.so is loaded.
431 * This is where we'd register new extension functions with the dispatcher.
432 *
433 * \todo This interface has been deprecated, so we should probably remove
434 *       this function before the next XFree86 release.
435 */
436void
437__driRegisterExtensions( void )
438{
439   PFNGLXENABLEEXTENSIONPROC glx_enable_extension;
440
441
442   if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
443      glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC)
444	  glXGetProcAddress( (const GLubyte *) "__glXEnableExtension" );
445
446      if ( glx_enable_extension != NULL ) {
447	 (*glx_enable_extension)( "GLX_SGI_swap_control", GL_FALSE );
448	 (*glx_enable_extension)( "GLX_SGI_video_sync", GL_FALSE );
449	 (*glx_enable_extension)( "GLX_MESA_swap_control", GL_FALSE );
450	 (*glx_enable_extension)( "GLX_MESA_swap_frame_usage", GL_FALSE );
451      }
452   }
453}
454#endif
455
456/**
457 * Get information about previous buffer swaps.
458 */
459static int
460getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo )
461{
462   radeonContextPtr  rmesa;
463
464   if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL)
465	|| (dPriv->driContextPriv->driverPrivate == NULL)
466	|| (sInfo == NULL) ) {
467      return -1;
468   }
469
470   rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
471   sInfo->swap_count = rmesa->swap_count;
472   sInfo->swap_ust = rmesa->swap_ust;
473   sInfo->swap_missed_count = rmesa->swap_missed_count;
474
475   sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
476       ? driCalculateSwapUsage( dPriv, 0, rmesa->swap_missed_ust )
477       : 0.0;
478
479   return 0;
480}
481