r200 driver, brought over by Jon Smirl
[mesa.git] / src / mesa / drivers / dri / r200 / r200_screen.c
1 /* $XFree86$ */
2 /**************************************************************************
3
4 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
5
6 The Weather Channel (TM) funded Tungsten Graphics to develop the
7 initial release of the Radeon 8500 driver under the XFree86 license.
8 This notice must be preserved.
9
10 Permission is hereby granted, free of charge, to any person obtaining
11 a copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sublicense, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial
20 portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 /*
33 * Authors:
34 * Keith Whitwell <keith@tungstengraphics.com>
35 */
36
37 #include <dlfcn.h>
38
39 #include "glheader.h"
40 #include "imports.h"
41 #include "context.h"
42
43 #include "r200_screen.h"
44 #include "r200_context.h"
45 #include "r200_ioctl.h"
46
47 #include "utils.h"
48 #include "vblank.h"
49
50 #ifndef _SOLO
51 #include "glxextensions.h"
52 #endif
53
54 #if 1
55 /* Including xf86PciInfo.h introduces a bunch of errors...
56 */
57 #define PCI_CHIP_R200_QD 0x5144
58 #define PCI_CHIP_R200_QE 0x5145
59 #define PCI_CHIP_R200_QF 0x5146
60 #define PCI_CHIP_R200_QG 0x5147
61 #define PCI_CHIP_R200_QY 0x5159
62 #define PCI_CHIP_R200_QZ 0x515A
63 #define PCI_CHIP_R200_LW 0x4C57
64 #define PCI_CHIP_R200_LY 0x4C59
65 #define PCI_CHIP_R200_LZ 0x4C5A
66 #define PCI_CHIP_RV200_QW 0x5157 /* Radeon 7500 - not an R200 at all */
67 #endif
68
69 static r200ScreenPtr __r200Screen;
70
71 static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
72
73 /* Create the device specific screen private data struct.
74 */
75 static r200ScreenPtr
76 r200CreateScreen( __DRIscreenPrivate *sPriv )
77 {
78 r200ScreenPtr screen;
79 RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv;
80
81 if ( ! driCheckDriDdxDrmVersions( sPriv, "R200", 4, 0, 4, 0, 1, 5 ) )
82 return NULL;
83
84 /* Allocate the private area */
85 screen = (r200ScreenPtr) CALLOC( sizeof(*screen) );
86 if ( !screen ) {
87 __driUtilMessage("%s: Could not allocate memory for screen structure",
88 __FUNCTION__);
89 return NULL;
90 }
91
92 switch ( dri_priv->deviceID ) {
93 case PCI_CHIP_R200_QD:
94 case PCI_CHIP_R200_QE:
95 case PCI_CHIP_R200_QF:
96 case PCI_CHIP_R200_QG:
97 case PCI_CHIP_R200_QY:
98 case PCI_CHIP_R200_QZ:
99 case PCI_CHIP_RV200_QW:
100 case PCI_CHIP_R200_LW:
101 case PCI_CHIP_R200_LY:
102 case PCI_CHIP_R200_LZ:
103 __driUtilMessage("r200CreateScreen(): Device isn't an r200!\n");
104 FREE( screen );
105 return NULL;
106 default:
107 screen->chipset = R200_CHIPSET_R200;
108 break;
109 }
110
111
112 /* This is first since which regions we map depends on whether or
113 * not we are using a PCI card.
114 */
115 screen->IsPCI = dri_priv->IsPCI;
116
117 {
118 int ret;
119 drmRadeonGetParam gp;
120
121 gp.param = RADEON_PARAM_AGP_BUFFER_OFFSET;
122 gp.value = &screen->agp_buffer_offset;
123
124 ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
125 &gp, sizeof(gp));
126 if (ret) {
127 FREE( screen );
128 fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_AGP_BUFFER_OFFSET): %d\n", ret);
129 return NULL;
130 }
131
132 screen->agp_texture_offset =
133 screen->agp_buffer_offset + 2*1024*1024;
134
135
136 if (sPriv->drmMinor >= 6) {
137 gp.param = RADEON_PARAM_AGP_BASE;
138 gp.value = &screen->agp_base;
139
140 ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
141 &gp, sizeof(gp));
142 if (ret) {
143 FREE( screen );
144 fprintf(stderr, "drmR200GetParam (RADEON_PARAM_AGP_BASE): %d\n", ret);
145 return NULL;
146 }
147
148
149 gp.param = RADEON_PARAM_IRQ_NR;
150 gp.value = &screen->irq;
151
152 ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
153 &gp, sizeof(gp));
154 if (ret) {
155 FREE( screen );
156 fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_IRQ_NR): %d\n", ret);
157 return NULL;
158 }
159
160 /* Check if kernel module is new enough to support cube maps */
161 screen->drmSupportsCubeMaps = (sPriv->drmMinor >= 7);
162 }
163 }
164
165 screen->mmio.handle = dri_priv->registerHandle;
166 screen->mmio.size = dri_priv->registerSize;
167 if ( drmMap( sPriv->fd,
168 screen->mmio.handle,
169 screen->mmio.size,
170 &screen->mmio.map ) ) {
171 FREE( screen );
172 __driUtilMessage("%s: drmMap failed\n", __FUNCTION__ );
173 return NULL;
174 }
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 ( !screen->IsPCI ) {
200 screen->agpTextures.handle = dri_priv->agpTexHandle;
201 screen->agpTextures.size = dri_priv->agpTexMapSize;
202 if ( drmMap( sPriv->fd,
203 screen->agpTextures.handle,
204 screen->agpTextures.size,
205 (drmAddressPtr)&screen->agpTextures.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: IsPCI failed\n", __FUNCTION__);
211 return NULL;
212 }
213 }
214
215
216
217 screen->cpp = dri_priv->bpp / 8;
218 screen->AGPMode = dri_priv->AGPMode;
219
220 screen->frontOffset = dri_priv->frontOffset;
221 screen->frontPitch = dri_priv->frontPitch;
222 screen->backOffset = dri_priv->backOffset;
223 screen->backPitch = dri_priv->backPitch;
224 screen->depthOffset = dri_priv->depthOffset;
225 screen->depthPitch = dri_priv->depthPitch;
226
227 screen->texOffset[RADEON_CARD_HEAP] = dri_priv->textureOffset;
228 screen->texSize[RADEON_CARD_HEAP] = dri_priv->textureSize;
229 screen->logTexGranularity[RADEON_CARD_HEAP] =
230 dri_priv->log2TexGran;
231
232 if ( screen->IsPCI ) {
233 screen->numTexHeaps = RADEON_NR_TEX_HEAPS - 1;
234 screen->texOffset[RADEON_AGP_HEAP] = 0;
235 screen->texSize[RADEON_AGP_HEAP] = 0;
236 screen->logTexGranularity[RADEON_AGP_HEAP] = 0;
237 } else {
238 screen->numTexHeaps = RADEON_NR_TEX_HEAPS;
239 screen->texOffset[RADEON_AGP_HEAP] =
240 dri_priv->agpTexOffset + R200_AGP_TEX_OFFSET;
241 screen->texSize[RADEON_AGP_HEAP] = dri_priv->agpTexMapSize;
242 screen->logTexGranularity[RADEON_AGP_HEAP] =
243 dri_priv->log2AGPTexGran;
244 }
245
246 screen->driScreen = sPriv;
247 screen->sarea_priv_offset = dri_priv->sarea_priv_offset;
248 return screen;
249 }
250
251 /* Destroy the device specific screen private data struct.
252 */
253 static void
254 r200DestroyScreen( __DRIscreenPrivate *sPriv )
255 {
256 r200ScreenPtr screen = (r200ScreenPtr)sPriv->private;
257
258 if (!screen)
259 return;
260
261 if ( !screen->IsPCI ) {
262 drmUnmap( screen->agpTextures.map,
263 screen->agpTextures.size );
264 }
265 drmUnmapBufs( screen->buffers );
266 drmUnmap( screen->status.map, screen->status.size );
267 drmUnmap( screen->mmio.map, screen->mmio.size );
268
269 FREE( screen );
270 sPriv->private = NULL;
271 }
272
273
274 /* Initialize the driver specific screen private data.
275 */
276 static GLboolean
277 r200InitDriver( __DRIscreenPrivate *sPriv )
278 {
279 __r200Screen = r200CreateScreen( sPriv );
280
281 sPriv->private = (void *) __r200Screen;
282
283 return sPriv->private ? GL_TRUE : GL_FALSE;
284 }
285
286
287
288 /* Create and initialize the Mesa and driver specific pixmap buffer
289 * data.
290 */
291 static GLboolean
292 r200CreateBuffer( __DRIscreenPrivate *driScrnPriv,
293 __DRIdrawablePrivate *driDrawPriv,
294 const __GLcontextModes *mesaVis,
295 GLboolean isPixmap )
296 {
297 if (isPixmap) {
298 return GL_FALSE; /* not implemented */
299 }
300 else {
301 const GLboolean swDepth = GL_FALSE;
302 const GLboolean swAlpha = GL_FALSE;
303 const GLboolean swAccum = mesaVis->accumRedBits > 0;
304 const GLboolean swStencil = mesaVis->stencilBits > 0 &&
305 mesaVis->depthBits != 24;
306 driDrawPriv->driverPrivate = (void *)
307 _mesa_create_framebuffer( mesaVis,
308 swDepth,
309 swStencil,
310 swAccum,
311 swAlpha );
312 return (driDrawPriv->driverPrivate != NULL);
313 }
314 }
315
316
317 static void
318 r200DestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
319 {
320 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
321 }
322
323
324
325
326 /* Fullscreen mode isn't used for much -- could be a way to shrink
327 * front/back buffers & get more texture memory if the client has
328 * changed the video resolution.
329 *
330 * Pageflipping is now done automatically whenever there is a single
331 * 3d client.
332 */
333 static GLboolean
334 r200OpenCloseFullScreen( __DRIcontextPrivate *driContextPriv )
335 {
336 return GL_TRUE;
337 }
338
339 static struct __DriverAPIRec r200API = {
340 .InitDriver = r200InitDriver,
341 .DestroyScreen = r200DestroyScreen,
342 .CreateContext = r200CreateContext,
343 .DestroyContext = r200DestroyContext,
344 .CreateBuffer = r200CreateBuffer,
345 .DestroyBuffer = r200DestroyBuffer,
346 .SwapBuffers = r200SwapBuffers,
347 .MakeCurrent = r200MakeCurrent,
348 .UnbindContext = r200UnbindContext,
349 .OpenFullScreen = r200OpenCloseFullScreen,
350 .CloseFullScreen = r200OpenCloseFullScreen,
351 .GetSwapInfo = getSwapInfo,
352 .GetMSC = driGetMSC32,
353 .WaitForMSC = driWaitForMSC32,
354 .WaitForSBC = NULL,
355 .SwapBuffersMSC = NULL
356 };
357
358
359 /*
360 * This is the bootstrap function for the driver.
361 * The __driCreateScreen name is the symbol that libGL.so fetches.
362 * Return: pointer to a __DRIscreenPrivate.
363 *
364 */
365 #ifndef _SOLO
366 void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
367 int numConfigs, __GLXvisualConfig *config)
368 {
369 __DRIscreenPrivate *psp;
370 psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &r200API);
371 return (void *) psp;
372 }
373 #else
374 void *__driCreateScreen(struct DRIDriverRec *driver,
375 struct DRIDriverContextRec *driverContext)
376 {
377 __DRIscreenPrivate *psp;
378 psp = __driUtilCreateScreen(driver, driverContext, &r200API);
379 return (void *) psp;
380 }
381 #endif
382
383
384
385 #ifndef _SOLO
386 /* This function is called by libGL.so to allow the driver to dynamically
387 * extend libGL. We can add new GLX functions and/or new GL functions.
388 * Note that _mesa_create_context() will probably add most of the newer
389 * OpenGL extension functions into the dispatcher.
390 */
391 void
392 __driRegisterExtensions( void )
393 {
394 PFNGLXENABLEEXTENSIONPROC glx_enable_extension;
395 typedef void *(*registerFunc)(const char *funcName, void *funcAddr);
396 registerFunc regFunc;
397
398
399 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
400 glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC)
401 glXGetProcAddress( "__glXEnableExtension" );
402
403 if ( glx_enable_extension != NULL ) {
404 glx_enable_extension( "GLX_SGI_swap_control", GL_FALSE );
405 glx_enable_extension( "GLX_SGI_video_sync", GL_FALSE );
406 glx_enable_extension( "GLX_MESA_swap_control", GL_FALSE );
407 glx_enable_extension( "GLX_MESA_swap_frame_usage", GL_FALSE );
408
409
410 /* Get pointers to libGL's __glXRegisterGLXFunction
411 * and __glXRegisterGLXExtensionString, if they exist.
412 */
413 regFunc = (registerFunc) glXGetProcAddress( "__glXRegisterGLXFunction" );
414
415 if (regFunc) {
416 /* register our GLX extensions with libGL */
417 void *p;
418 p = regFunc("glXAllocateMemoryNV", (void *) r200AllocateMemoryNV);
419 if (p)
420 ; /* XXX already registered - what to do, wrap? */
421
422 p = regFunc("glXFreeMemoryNV", (void *) r200FreeMemoryNV);
423 if (p)
424 ; /* XXX already registered - what to do, wrap? */
425
426 p = regFunc("glXGetAGPOffsetMESA", (void *) r200GetAGPOffset);
427 if (p)
428 ; /* XXX already registered - what to do, wrap? */
429
430 glx_enable_extension( "GLX_NV_vertex_array_range", GL_TRUE );
431 glx_enable_extension( "GLX_MESA_agp_offset", GL_TRUE );
432 }
433 }
434 }
435 }
436 #endif
437
438 /**
439 * Get information about previous buffer swaps.
440 */
441 static int
442 getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo )
443 {
444 r200ContextPtr rmesa;
445
446 if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL)
447 || (dPriv->driContextPriv->driverPrivate == NULL)
448 || (sInfo == NULL) ) {
449 return -1;
450 }
451
452 rmesa = (r200ContextPtr) dPriv->driContextPriv->driverPrivate;
453 sInfo->swap_count = rmesa->swap_count;
454 sInfo->swap_ust = rmesa->swap_ust;
455 sInfo->swap_missed_count = rmesa->swap_missed_count;
456
457 sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
458 ? driCalculateSwapUsage( dPriv, 0, rmesa->swap_missed_ust )
459 : 0.0;
460
461 return 0;
462 }