Add Egberts fixes for 64bit architectures
[mesa.git] / src / mesa / drivers / dri / r128 / r128_screen.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_screen.c,v 1.9 2003/03/26 20:43:49 tsi Exp $ */
2 /**************************************************************************
3
4 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
5 Cedar Park, Texas.
6 All Rights Reserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
17 Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Gareth Hughes <gareth@valinux.com>
32 * Kevin E. Martin <martin@valinux.com>
33 *
34 */
35
36 #include "r128_dri.h"
37
38 #include "r128_context.h"
39 #include "r128_ioctl.h"
40 #include "r128_span.h"
41 #include "r128_tris.h"
42
43 #include "context.h"
44 #include "imports.h"
45 #include "framebuffer.h"
46 #include "renderbuffer.h"
47
48 #include "utils.h"
49 #include "vblank.h"
50
51 #include "GL/internal/dri_interface.h"
52
53 /* R128 configuration
54 */
55 #include "xmlpool.h"
56
57 PUBLIC const char __driConfigOptions[] =
58 DRI_CONF_BEGIN
59 DRI_CONF_SECTION_PERFORMANCE
60 DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0)
61 DRI_CONF_SECTION_END
62 DRI_CONF_SECTION_QUALITY
63 DRI_CONF_TEXTURE_DEPTH(DRI_CONF_TEXTURE_DEPTH_FB)
64 DRI_CONF_SECTION_END
65 DRI_CONF_SECTION_DEBUG
66 DRI_CONF_NO_RAST(false)
67 #if ENABLE_PERF_BOXES
68 DRI_CONF_PERFORMANCE_BOXES(false)
69 #endif
70 DRI_CONF_SECTION_END
71 DRI_CONF_END;
72 #if ENABLE_PERF_BOXES
73 static const GLuint __driNConfigOptions = 4;
74 #else
75 static const GLuint __driNConfigOptions = 3;
76 #endif
77
78 extern const struct dri_extension card_extensions[];
79
80 #if 1
81 /* Including xf86PciInfo.h introduces a bunch of errors...
82 */
83 #define PCI_CHIP_RAGE128LE 0x4C45
84 #define PCI_CHIP_RAGE128LF 0x4C46
85 #define PCI_CHIP_RAGE128PF 0x5046
86 #define PCI_CHIP_RAGE128PR 0x5052
87 #define PCI_CHIP_RAGE128RE 0x5245
88 #define PCI_CHIP_RAGE128RF 0x5246
89 #define PCI_CHIP_RAGE128RK 0x524B
90 #define PCI_CHIP_RAGE128RL 0x524C
91 #endif
92
93
94 /* Create the device specific screen private data struct.
95 */
96 static r128ScreenPtr
97 r128CreateScreen( __DRIscreenPrivate *sPriv )
98 {
99 r128ScreenPtr r128Screen;
100 R128DRIPtr r128DRIPriv = (R128DRIPtr)sPriv->pDevPriv;
101 PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension =
102 (PFNGLXSCRENABLEEXTENSIONPROC) (*dri_interface->getProcAddress("glxEnableExtension"));
103 void * const psc = sPriv->psc->screenConfigs;
104
105 if (sPriv->devPrivSize != sizeof(R128DRIRec)) {
106 fprintf(stderr,"\nERROR! sizeof(R128DRIRec) does not match passed size from device driver\n");
107 return GL_FALSE;
108 }
109
110 /* Allocate the private area */
111 r128Screen = (r128ScreenPtr) CALLOC( sizeof(*r128Screen) );
112 if ( !r128Screen ) return NULL;
113
114 /* parse information in __driConfigOptions */
115 driParseOptionInfo (&r128Screen->optionCache,
116 __driConfigOptions, __driNConfigOptions);
117
118 /* This is first since which regions we map depends on whether or
119 * not we are using a PCI card.
120 */
121 r128Screen->IsPCI = r128DRIPriv->IsPCI;
122 r128Screen->sarea_priv_offset = r128DRIPriv->sarea_priv_offset;
123
124 if (sPriv->drmMinor >= 3) {
125 drm_r128_getparam_t gp;
126 int ret;
127
128 gp.param = R128_PARAM_IRQ_NR;
129 gp.value = &r128Screen->irq;
130
131 ret = drmCommandWriteRead( sPriv->fd, DRM_R128_GETPARAM,
132 &gp, sizeof(gp));
133 if (ret) {
134 fprintf(stderr, "drmR128GetParam (R128_PARAM_IRQ_NR): %d\n", ret);
135 FREE( r128Screen );
136 return NULL;
137 }
138 }
139
140 r128Screen->mmio.handle = r128DRIPriv->registerHandle;
141 r128Screen->mmio.size = r128DRIPriv->registerSize;
142 if ( drmMap( sPriv->fd,
143 r128Screen->mmio.handle,
144 r128Screen->mmio.size,
145 (drmAddressPtr)&r128Screen->mmio.map ) ) {
146 FREE( r128Screen );
147 return NULL;
148 }
149
150 r128Screen->buffers = drmMapBufs( sPriv->fd );
151 if ( !r128Screen->buffers ) {
152 drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
153 FREE( r128Screen );
154 return NULL;
155 }
156
157 if ( !r128Screen->IsPCI ) {
158 r128Screen->agpTextures.handle = r128DRIPriv->agpTexHandle;
159 r128Screen->agpTextures.size = r128DRIPriv->agpTexMapSize;
160 if ( drmMap( sPriv->fd,
161 r128Screen->agpTextures.handle,
162 r128Screen->agpTextures.size,
163 (drmAddressPtr)&r128Screen->agpTextures.map ) ) {
164 drmUnmapBufs( r128Screen->buffers );
165 drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
166 FREE( r128Screen );
167 return NULL;
168 }
169 }
170
171 switch ( r128DRIPriv->deviceID ) {
172 case PCI_CHIP_RAGE128RE:
173 case PCI_CHIP_RAGE128RF:
174 case PCI_CHIP_RAGE128RK:
175 case PCI_CHIP_RAGE128RL:
176 r128Screen->chipset = R128_CARD_TYPE_R128;
177 break;
178 case PCI_CHIP_RAGE128PF:
179 r128Screen->chipset = R128_CARD_TYPE_R128_PRO;
180 break;
181 case PCI_CHIP_RAGE128LE:
182 case PCI_CHIP_RAGE128LF:
183 r128Screen->chipset = R128_CARD_TYPE_R128_MOBILITY;
184 break;
185 default:
186 r128Screen->chipset = R128_CARD_TYPE_R128;
187 break;
188 }
189
190 r128Screen->cpp = r128DRIPriv->bpp / 8;
191 r128Screen->AGPMode = r128DRIPriv->AGPMode;
192
193 r128Screen->frontOffset = r128DRIPriv->frontOffset;
194 r128Screen->frontPitch = r128DRIPriv->frontPitch;
195 r128Screen->backOffset = r128DRIPriv->backOffset;
196 r128Screen->backPitch = r128DRIPriv->backPitch;
197 r128Screen->depthOffset = r128DRIPriv->depthOffset;
198 r128Screen->depthPitch = r128DRIPriv->depthPitch;
199 r128Screen->spanOffset = r128DRIPriv->spanOffset;
200
201 r128Screen->texOffset[R128_LOCAL_TEX_HEAP] = r128DRIPriv->textureOffset;
202 r128Screen->texSize[R128_LOCAL_TEX_HEAP] = r128DRIPriv->textureSize;
203 r128Screen->logTexGranularity[R128_LOCAL_TEX_HEAP] = r128DRIPriv->log2TexGran;
204
205 if ( r128Screen->IsPCI ) {
206 r128Screen->numTexHeaps = R128_NR_TEX_HEAPS - 1;
207 r128Screen->texOffset[R128_AGP_TEX_HEAP] = 0;
208 r128Screen->texSize[R128_AGP_TEX_HEAP] = 0;
209 r128Screen->logTexGranularity[R128_AGP_TEX_HEAP] = 0;
210 } else {
211 r128Screen->numTexHeaps = R128_NR_TEX_HEAPS;
212 r128Screen->texOffset[R128_AGP_TEX_HEAP] =
213 r128DRIPriv->agpTexOffset + R128_AGP_TEX_OFFSET;
214 r128Screen->texSize[R128_AGP_TEX_HEAP] = r128DRIPriv->agpTexMapSize;
215 r128Screen->logTexGranularity[R128_AGP_TEX_HEAP] =
216 r128DRIPriv->log2AGPTexGran;
217 }
218
219 r128Screen->driScreen = sPriv;
220
221 if ( glx_enable_extension != NULL ) {
222 if ( r128Screen->irq != 0 ) {
223 (*glx_enable_extension)( psc, "GLX_SGI_swap_control" );
224 (*glx_enable_extension)( psc, "GLX_SGI_video_sync" );
225 (*glx_enable_extension)( psc, "GLX_MESA_swap_control" );
226 }
227
228 (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" );
229 }
230
231 return r128Screen;
232 }
233
234 /* Destroy the device specific screen private data struct.
235 */
236 static void
237 r128DestroyScreen( __DRIscreenPrivate *sPriv )
238 {
239 r128ScreenPtr r128Screen = (r128ScreenPtr)sPriv->private;
240
241 if ( !r128Screen )
242 return;
243
244 if ( !r128Screen->IsPCI ) {
245 drmUnmap( (drmAddress)r128Screen->agpTextures.map,
246 r128Screen->agpTextures.size );
247 }
248 drmUnmapBufs( r128Screen->buffers );
249 drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
250
251 /* free all option information */
252 driDestroyOptionInfo (&r128Screen->optionCache);
253
254 FREE( r128Screen );
255 sPriv->private = NULL;
256 }
257
258
259 /* Create and initialize the Mesa and driver specific pixmap buffer
260 * data.
261 */
262 static GLboolean
263 r128CreateBuffer( __DRIscreenPrivate *driScrnPriv,
264 __DRIdrawablePrivate *driDrawPriv,
265 const __GLcontextModes *mesaVis,
266 GLboolean isPixmap )
267 {
268 r128ScreenPtr screen = (r128ScreenPtr) driScrnPriv->private;
269
270 if (isPixmap) {
271 return GL_FALSE; /* not implemented */
272 }
273 else {
274 #if 0
275 driDrawPriv->driverPrivate = (void *)
276 _mesa_create_framebuffer( mesaVis,
277 GL_FALSE, /* software depth buffer? */
278 mesaVis->stencilBits > 0,
279 mesaVis->accumRedBits > 0,
280 mesaVis->alphaBits > 0 );
281 #else
282 struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
283
284 {
285 driRenderbuffer *frontRb
286 = driNewRenderbuffer(GL_RGBA, screen->cpp,
287 screen->frontOffset, screen->frontPitch);
288 r128SetSpanFunctions(frontRb, mesaVis);
289 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
290 }
291
292 if (mesaVis->doubleBufferMode) {
293 driRenderbuffer *backRb
294 = driNewRenderbuffer(GL_RGBA, screen->cpp,
295 screen->backOffset, screen->backPitch);
296 r128SetSpanFunctions(backRb, mesaVis);
297 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
298 }
299
300 if (mesaVis->depthBits == 16) {
301 driRenderbuffer *depthRb
302 = driNewRenderbuffer(GL_DEPTH_COMPONENT16, screen->cpp,
303 screen->depthOffset, screen->depthPitch);
304 r128SetSpanFunctions(depthRb, mesaVis);
305 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
306 }
307 else if (mesaVis->depthBits == 24) {
308 driRenderbuffer *depthRb
309 = driNewRenderbuffer(GL_DEPTH_COMPONENT24, screen->cpp,
310 screen->depthOffset, screen->depthPitch);
311 r128SetSpanFunctions(depthRb, mesaVis);
312 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
313 }
314
315 _mesa_add_soft_renderbuffers(fb,
316 GL_FALSE, /* color */
317 GL_FALSE, /* depth */
318 mesaVis->stencilBits > 0,
319 mesaVis->accumRedBits > 0,
320 GL_FALSE, /* alpha */
321 GL_FALSE /* aux */);
322 driDrawPriv->driverPrivate = (void *) fb;
323 #endif
324 return (driDrawPriv->driverPrivate != NULL);
325 }
326 }
327
328
329 static void
330 r128DestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
331 {
332 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
333 }
334
335
336 /* Copy the back color buffer to the front color buffer */
337 static void
338 r128SwapBuffers(__DRIdrawablePrivate *dPriv)
339 {
340 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
341 r128ContextPtr rmesa;
342 GLcontext *ctx;
343 rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate;
344 ctx = rmesa->glCtx;
345 if (ctx->Visual.doubleBufferMode) {
346 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
347 if ( rmesa->doPageFlip ) {
348 r128PageFlip( dPriv );
349 }
350 else {
351 r128CopyBuffer( dPriv );
352 }
353 }
354 }
355 else {
356 /* XXX this shouldn't be an error but we can't handle it for now */
357 _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
358 }
359 }
360
361
362 /* Initialize the driver specific screen private data.
363 */
364 static GLboolean
365 r128InitDriver( __DRIscreenPrivate *sPriv )
366 {
367 sPriv->private = (void *) r128CreateScreen( sPriv );
368
369 if ( !sPriv->private ) {
370 r128DestroyScreen( sPriv );
371 return GL_FALSE;
372 }
373
374 return GL_TRUE;
375 }
376
377
378 static struct __DriverAPIRec r128API = {
379 .InitDriver = r128InitDriver,
380 .DestroyScreen = r128DestroyScreen,
381 .CreateContext = r128CreateContext,
382 .DestroyContext = r128DestroyContext,
383 .CreateBuffer = r128CreateBuffer,
384 .DestroyBuffer = r128DestroyBuffer,
385 .SwapBuffers = r128SwapBuffers,
386 .MakeCurrent = r128MakeCurrent,
387 .UnbindContext = r128UnbindContext,
388 .GetSwapInfo = NULL,
389 .GetMSC = driGetMSC32,
390 .WaitForMSC = driWaitForMSC32,
391 .WaitForSBC = NULL,
392 .SwapBuffersMSC = NULL
393
394 };
395
396
397 static __GLcontextModes *
398 r128FillInModes( unsigned pixel_bits, unsigned depth_bits,
399 unsigned stencil_bits, GLboolean have_back_buffer )
400 {
401 __GLcontextModes * modes;
402 __GLcontextModes * m;
403 unsigned num_modes;
404 unsigned depth_buffer_factor;
405 unsigned back_buffer_factor;
406 GLenum fb_format;
407 GLenum fb_type;
408
409 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
410 * enough to add support. Basically, if a context is created with an
411 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
412 * will never be used.
413 */
414 static const GLenum back_buffer_modes[] = {
415 GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
416 };
417
418 u_int8_t depth_bits_array[2];
419 u_int8_t stencil_bits_array[2];
420
421
422 depth_bits_array[0] = depth_bits;
423 depth_bits_array[1] = depth_bits;
424
425 /* Just like with the accumulation buffer, always provide some modes
426 * with a stencil buffer. It will be a sw fallback, but some apps won't
427 * care about that.
428 */
429 stencil_bits_array[0] = 0;
430 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
431
432 depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
433 back_buffer_factor = (have_back_buffer) ? 2 : 1;
434
435 num_modes = depth_buffer_factor * back_buffer_factor * 4;
436
437 if ( pixel_bits == 16 ) {
438 fb_format = GL_RGB;
439 fb_type = GL_UNSIGNED_SHORT_5_6_5;
440 }
441 else {
442 fb_format = GL_BGR;
443 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
444 }
445
446 modes = (*dri_interface->createContextModes)( num_modes, sizeof( __GLcontextModes ) );
447 m = modes;
448 if ( ! driFillInModes( & m, fb_format, fb_type,
449 depth_bits_array, stencil_bits_array, depth_buffer_factor,
450 back_buffer_modes, back_buffer_factor,
451 GLX_TRUE_COLOR ) ) {
452 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
453 __func__, __LINE__ );
454 return NULL;
455 }
456
457 if ( ! driFillInModes( & m, fb_format, fb_type,
458 depth_bits_array, stencil_bits_array, depth_buffer_factor,
459 back_buffer_modes, back_buffer_factor,
460 GLX_DIRECT_COLOR ) ) {
461 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
462 __func__, __LINE__ );
463 return NULL;
464 }
465
466 /* Mark the visual as slow if there are "fake" stencil bits.
467 */
468 for ( m = modes ; m != NULL ; m = m->next ) {
469 if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) {
470 m->visualRating = GLX_SLOW_CONFIG;
471 }
472 }
473
474 return modes;
475 }
476
477
478 /**
479 * This is the bootstrap function for the driver. libGL supplies all of the
480 * requisite information about the system, and the driver initializes itself.
481 * This routine also fills in the linked list pointed to by \c driver_modes
482 * with the \c __GLcontextModes that the driver can support for windows or
483 * pbuffers.
484 *
485 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
486 * failure.
487 */
488 PUBLIC
489 void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
490 const __GLcontextModes * modes,
491 const __DRIversion * ddx_version,
492 const __DRIversion * dri_version,
493 const __DRIversion * drm_version,
494 const __DRIframebuffer * frame_buffer,
495 drmAddress pSAREA, int fd,
496 int internal_api_version,
497 const __DRIinterfaceMethods * interface,
498 __GLcontextModes ** driver_modes )
499
500 {
501 __DRIscreenPrivate *psp;
502 static const __DRIversion ddx_expected = { 4, 0, 0 };
503 static const __DRIversion dri_expected = { 4, 0, 0 };
504 static const __DRIversion drm_expected = { 2, 2, 0 };
505
506
507 dri_interface = interface;
508
509 if ( ! driCheckDriDdxDrmVersions2( "Rage128",
510 dri_version, & dri_expected,
511 ddx_version, & ddx_expected,
512 drm_version, & drm_expected ) ) {
513 return NULL;
514 }
515
516 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
517 ddx_version, dri_version, drm_version,
518 frame_buffer, pSAREA, fd,
519 internal_api_version, &r128API);
520 if ( psp != NULL ) {
521 R128DRIPtr dri_priv = (R128DRIPtr) psp->pDevPriv;
522 *driver_modes = r128FillInModes( dri_priv->bpp,
523 (dri_priv->bpp == 16) ? 16 : 24,
524 (dri_priv->bpp == 16) ? 0 : 8,
525 (dri_priv->backOffset != dri_priv->depthOffset) );
526
527 /* Calling driInitExtensions here, with a NULL context pointer, does not actually
528 * enable the extensions. It just makes sure that all the dispatch offsets for all
529 * the extensions that *might* be enables are known. This is needed because the
530 * dispatch offsets need to be known when _mesa_context_create is called, but we can't
531 * enable the extensions until we have a context pointer.
532 *
533 * Hello chicken. Hello egg. How are you two today?
534 */
535 driInitExtensions( NULL, card_extensions, GL_FALSE );
536 }
537
538 return (void *) psp;
539 }