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