52b9b7bcbcc508cea8ee1caf432e7430f9318e18
[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
106 /* Allocate the private area */
107 r128Screen = (r128ScreenPtr) CALLOC( sizeof(*r128Screen) );
108 if ( !r128Screen ) return NULL;
109
110 /* parse information in __driConfigOptions */
111 driParseOptionInfo (&r128Screen->optionCache,
112 __driConfigOptions, __driNConfigOptions);
113
114 /* This is first since which regions we map depends on whether or
115 * not we are using a PCI card.
116 */
117 r128Screen->IsPCI = r128DRIPriv->IsPCI;
118 r128Screen->sarea_priv_offset = r128DRIPriv->sarea_priv_offset;
119
120 if (sPriv->drmMinor >= 3) {
121 drm_r128_getparam_t gp;
122 int ret;
123
124 gp.param = R128_PARAM_IRQ_NR;
125 gp.value = &r128Screen->irq;
126
127 ret = drmCommandWriteRead( sPriv->fd, DRM_R128_GETPARAM,
128 &gp, sizeof(gp));
129 if (ret) {
130 fprintf(stderr, "drmR128GetParam (R128_PARAM_IRQ_NR): %d\n", ret);
131 FREE( r128Screen );
132 return NULL;
133 }
134 }
135
136 r128Screen->mmio.handle = r128DRIPriv->registerHandle;
137 r128Screen->mmio.size = r128DRIPriv->registerSize;
138 if ( drmMap( sPriv->fd,
139 r128Screen->mmio.handle,
140 r128Screen->mmio.size,
141 (drmAddressPtr)&r128Screen->mmio.map ) ) {
142 FREE( r128Screen );
143 return NULL;
144 }
145
146 r128Screen->buffers = drmMapBufs( sPriv->fd );
147 if ( !r128Screen->buffers ) {
148 drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
149 FREE( r128Screen );
150 return NULL;
151 }
152
153 if ( !r128Screen->IsPCI ) {
154 r128Screen->agpTextures.handle = r128DRIPriv->agpTexHandle;
155 r128Screen->agpTextures.size = r128DRIPriv->agpTexMapSize;
156 if ( drmMap( sPriv->fd,
157 r128Screen->agpTextures.handle,
158 r128Screen->agpTextures.size,
159 (drmAddressPtr)&r128Screen->agpTextures.map ) ) {
160 drmUnmapBufs( r128Screen->buffers );
161 drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
162 FREE( r128Screen );
163 return NULL;
164 }
165 }
166
167 switch ( r128DRIPriv->deviceID ) {
168 case PCI_CHIP_RAGE128RE:
169 case PCI_CHIP_RAGE128RF:
170 case PCI_CHIP_RAGE128RK:
171 case PCI_CHIP_RAGE128RL:
172 r128Screen->chipset = R128_CARD_TYPE_R128;
173 break;
174 case PCI_CHIP_RAGE128PF:
175 r128Screen->chipset = R128_CARD_TYPE_R128_PRO;
176 break;
177 case PCI_CHIP_RAGE128LE:
178 case PCI_CHIP_RAGE128LF:
179 r128Screen->chipset = R128_CARD_TYPE_R128_MOBILITY;
180 break;
181 default:
182 r128Screen->chipset = R128_CARD_TYPE_R128;
183 break;
184 }
185
186 r128Screen->cpp = r128DRIPriv->bpp / 8;
187 r128Screen->AGPMode = r128DRIPriv->AGPMode;
188
189 r128Screen->frontOffset = r128DRIPriv->frontOffset;
190 r128Screen->frontPitch = r128DRIPriv->frontPitch;
191 r128Screen->backOffset = r128DRIPriv->backOffset;
192 r128Screen->backPitch = r128DRIPriv->backPitch;
193 r128Screen->depthOffset = r128DRIPriv->depthOffset;
194 r128Screen->depthPitch = r128DRIPriv->depthPitch;
195 r128Screen->spanOffset = r128DRIPriv->spanOffset;
196
197 r128Screen->texOffset[R128_LOCAL_TEX_HEAP] = r128DRIPriv->textureOffset;
198 r128Screen->texSize[R128_LOCAL_TEX_HEAP] = r128DRIPriv->textureSize;
199 r128Screen->logTexGranularity[R128_LOCAL_TEX_HEAP] = r128DRIPriv->log2TexGran;
200
201 if ( r128Screen->IsPCI ) {
202 r128Screen->numTexHeaps = R128_NR_TEX_HEAPS - 1;
203 r128Screen->texOffset[R128_AGP_TEX_HEAP] = 0;
204 r128Screen->texSize[R128_AGP_TEX_HEAP] = 0;
205 r128Screen->logTexGranularity[R128_AGP_TEX_HEAP] = 0;
206 } else {
207 r128Screen->numTexHeaps = R128_NR_TEX_HEAPS;
208 r128Screen->texOffset[R128_AGP_TEX_HEAP] =
209 r128DRIPriv->agpTexOffset + R128_AGP_TEX_OFFSET;
210 r128Screen->texSize[R128_AGP_TEX_HEAP] = r128DRIPriv->agpTexMapSize;
211 r128Screen->logTexGranularity[R128_AGP_TEX_HEAP] =
212 r128DRIPriv->log2AGPTexGran;
213 }
214
215 r128Screen->driScreen = sPriv;
216
217 if ( glx_enable_extension != NULL ) {
218 if ( r128Screen->irq != 0 ) {
219 (*glx_enable_extension)( psc, "GLX_SGI_swap_control" );
220 (*glx_enable_extension)( psc, "GLX_SGI_video_sync" );
221 (*glx_enable_extension)( psc, "GLX_MESA_swap_control" );
222 }
223
224 (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" );
225 }
226
227 return r128Screen;
228 }
229
230 /* Destroy the device specific screen private data struct.
231 */
232 static void
233 r128DestroyScreen( __DRIscreenPrivate *sPriv )
234 {
235 r128ScreenPtr r128Screen = (r128ScreenPtr)sPriv->private;
236
237 if ( !r128Screen )
238 return;
239
240 if ( !r128Screen->IsPCI ) {
241 drmUnmap( (drmAddress)r128Screen->agpTextures.map,
242 r128Screen->agpTextures.size );
243 }
244 drmUnmapBufs( r128Screen->buffers );
245 drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
246
247 /* free all option information */
248 driDestroyOptionInfo (&r128Screen->optionCache);
249
250 FREE( r128Screen );
251 sPriv->private = NULL;
252 }
253
254
255 /* Create and initialize the Mesa and driver specific pixmap buffer
256 * data.
257 */
258 static GLboolean
259 r128CreateBuffer( __DRIscreenPrivate *driScrnPriv,
260 __DRIdrawablePrivate *driDrawPriv,
261 const __GLcontextModes *mesaVis,
262 GLboolean isPixmap )
263 {
264 r128ScreenPtr screen = (r128ScreenPtr) driScrnPriv->private;
265
266 if (isPixmap) {
267 return GL_FALSE; /* not implemented */
268 }
269 else {
270 #if 0
271 driDrawPriv->driverPrivate = (void *)
272 _mesa_create_framebuffer( mesaVis,
273 GL_FALSE, /* software depth buffer? */
274 mesaVis->stencilBits > 0,
275 mesaVis->accumRedBits > 0,
276 mesaVis->alphaBits > 0 );
277 #else
278 struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
279
280 {
281 driRenderbuffer *frontRb
282 = driNewRenderbuffer(GL_RGBA, screen->cpp,
283 screen->frontOffset, screen->frontPitch);
284 r128SetSpanFunctions(frontRb, mesaVis);
285 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
286 }
287
288 if (mesaVis->doubleBufferMode) {
289 driRenderbuffer *backRb
290 = driNewRenderbuffer(GL_RGBA, screen->cpp,
291 screen->backOffset, screen->backPitch);
292 r128SetSpanFunctions(backRb, mesaVis);
293 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
294 }
295
296 if (mesaVis->depthBits == 16) {
297 driRenderbuffer *depthRb
298 = driNewRenderbuffer(GL_DEPTH_COMPONENT16, screen->cpp,
299 screen->depthOffset, screen->depthPitch);
300 r128SetSpanFunctions(depthRb, mesaVis);
301 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
302 }
303 else if (mesaVis->depthBits == 24) {
304 driRenderbuffer *depthRb
305 = driNewRenderbuffer(GL_DEPTH_COMPONENT24, screen->cpp,
306 screen->depthOffset, screen->depthPitch);
307 r128SetSpanFunctions(depthRb, mesaVis);
308 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
309 }
310
311 _mesa_add_soft_renderbuffers(fb,
312 GL_FALSE, /* color */
313 GL_FALSE, /* depth */
314 mesaVis->stencilBits > 0,
315 mesaVis->accumRedBits > 0,
316 GL_FALSE, /* alpha */
317 GL_FALSE /* aux */);
318 driDrawPriv->driverPrivate = (void *) fb;
319 #endif
320 return (driDrawPriv->driverPrivate != NULL);
321 }
322 }
323
324
325 static void
326 r128DestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
327 {
328 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
329 }
330
331
332 /* Copy the back color buffer to the front color buffer */
333 static void
334 r128SwapBuffers(__DRIdrawablePrivate *dPriv)
335 {
336 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
337 r128ContextPtr rmesa;
338 GLcontext *ctx;
339 rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate;
340 ctx = rmesa->glCtx;
341 if (ctx->Visual.doubleBufferMode) {
342 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
343 if ( rmesa->doPageFlip ) {
344 r128PageFlip( dPriv );
345 }
346 else {
347 r128CopyBuffer( dPriv );
348 }
349 }
350 }
351 else {
352 /* XXX this shouldn't be an error but we can't handle it for now */
353 _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
354 }
355 }
356
357
358 /* Initialize the driver specific screen private data.
359 */
360 static GLboolean
361 r128InitDriver( __DRIscreenPrivate *sPriv )
362 {
363 sPriv->private = (void *) r128CreateScreen( sPriv );
364
365 if ( !sPriv->private ) {
366 r128DestroyScreen( sPriv );
367 return GL_FALSE;
368 }
369
370 return GL_TRUE;
371 }
372
373
374 static struct __DriverAPIRec r128API = {
375 .InitDriver = r128InitDriver,
376 .DestroyScreen = r128DestroyScreen,
377 .CreateContext = r128CreateContext,
378 .DestroyContext = r128DestroyContext,
379 .CreateBuffer = r128CreateBuffer,
380 .DestroyBuffer = r128DestroyBuffer,
381 .SwapBuffers = r128SwapBuffers,
382 .MakeCurrent = r128MakeCurrent,
383 .UnbindContext = r128UnbindContext,
384 .GetSwapInfo = NULL,
385 .GetMSC = driGetMSC32,
386 .WaitForMSC = driWaitForMSC32,
387 .WaitForSBC = NULL,
388 .SwapBuffersMSC = NULL
389
390 };
391
392
393 static __GLcontextModes *
394 r128FillInModes( unsigned pixel_bits, unsigned depth_bits,
395 unsigned stencil_bits, GLboolean have_back_buffer )
396 {
397 __GLcontextModes * modes;
398 __GLcontextModes * m;
399 unsigned num_modes;
400 unsigned depth_buffer_factor;
401 unsigned back_buffer_factor;
402 GLenum fb_format;
403 GLenum fb_type;
404
405 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
406 * enough to add support. Basically, if a context is created with an
407 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
408 * will never be used.
409 */
410 static const GLenum back_buffer_modes[] = {
411 GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
412 };
413
414 u_int8_t depth_bits_array[2];
415 u_int8_t stencil_bits_array[2];
416
417
418 depth_bits_array[0] = depth_bits;
419 depth_bits_array[1] = depth_bits;
420
421 /* Just like with the accumulation buffer, always provide some modes
422 * with a stencil buffer. It will be a sw fallback, but some apps won't
423 * care about that.
424 */
425 stencil_bits_array[0] = 0;
426 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
427
428 depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
429 back_buffer_factor = (have_back_buffer) ? 2 : 1;
430
431 num_modes = depth_buffer_factor * back_buffer_factor * 4;
432
433 if ( pixel_bits == 16 ) {
434 fb_format = GL_RGB;
435 fb_type = GL_UNSIGNED_SHORT_5_6_5;
436 }
437 else {
438 fb_format = GL_BGR;
439 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
440 }
441
442 modes = (*dri_interface->createContextModes)( num_modes, sizeof( __GLcontextModes ) );
443 m = modes;
444 if ( ! driFillInModes( & m, fb_format, fb_type,
445 depth_bits_array, stencil_bits_array, depth_buffer_factor,
446 back_buffer_modes, back_buffer_factor,
447 GLX_TRUE_COLOR ) ) {
448 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
449 __func__, __LINE__ );
450 return NULL;
451 }
452
453 if ( ! driFillInModes( & m, fb_format, fb_type,
454 depth_bits_array, stencil_bits_array, depth_buffer_factor,
455 back_buffer_modes, back_buffer_factor,
456 GLX_DIRECT_COLOR ) ) {
457 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
458 __func__, __LINE__ );
459 return NULL;
460 }
461
462 /* Mark the visual as slow if there are "fake" stencil bits.
463 */
464 for ( m = modes ; m != NULL ; m = m->next ) {
465 if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) {
466 m->visualRating = GLX_SLOW_CONFIG;
467 }
468 }
469
470 return modes;
471 }
472
473
474 /**
475 * This is the bootstrap function for the driver. libGL supplies all of the
476 * requisite information about the system, and the driver initializes itself.
477 * This routine also fills in the linked list pointed to by \c driver_modes
478 * with the \c __GLcontextModes that the driver can support for windows or
479 * pbuffers.
480 *
481 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
482 * failure.
483 */
484 PUBLIC
485 void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
486 const __GLcontextModes * modes,
487 const __DRIversion * ddx_version,
488 const __DRIversion * dri_version,
489 const __DRIversion * drm_version,
490 const __DRIframebuffer * frame_buffer,
491 drmAddress pSAREA, int fd,
492 int internal_api_version,
493 const __DRIinterfaceMethods * interface,
494 __GLcontextModes ** driver_modes )
495
496 {
497 __DRIscreenPrivate *psp;
498 static const __DRIversion ddx_expected = { 4, 0, 0 };
499 static const __DRIversion dri_expected = { 4, 0, 0 };
500 static const __DRIversion drm_expected = { 2, 2, 0 };
501
502
503 dri_interface = interface;
504
505 if ( ! driCheckDriDdxDrmVersions2( "Rage128",
506 dri_version, & dri_expected,
507 ddx_version, & ddx_expected,
508 drm_version, & drm_expected ) ) {
509 return NULL;
510 }
511
512 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
513 ddx_version, dri_version, drm_version,
514 frame_buffer, pSAREA, fd,
515 internal_api_version, &r128API);
516 if ( psp != NULL ) {
517 R128DRIPtr dri_priv = (R128DRIPtr) psp->pDevPriv;
518 *driver_modes = r128FillInModes( dri_priv->bpp,
519 (dri_priv->bpp == 16) ? 16 : 24,
520 (dri_priv->bpp == 16) ? 0 : 8,
521 (dri_priv->backOffset != dri_priv->depthOffset) );
522
523 /* Calling driInitExtensions here, with a NULL context pointer, does not actually
524 * enable the extensions. It just makes sure that all the dispatch offsets for all
525 * the extensions that *might* be enables are known. This is needed because the
526 * dispatch offsets need to be known when _mesa_context_create is called, but we can't
527 * enable the extensions until we have a context pointer.
528 *
529 * Hello chicken. Hello egg. How are you two today?
530 */
531 driInitExtensions( NULL, card_extensions, GL_FALSE );
532 }
533
534 return (void *) psp;
535 }