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