8ec10ea1101d1dd302a86a28946e33a7a53ea19e
[mesa.git] / src / mesa / drivers / dri / mach64 / mach64_screen.c
1 /* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */
2 /*
3 * Copyright 2000 Gareth Hughes
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * GARETH HUGHES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /*
26 * Authors:
27 * Gareth Hughes <gareth@valinux.com>
28 * Leif Delgass <ldelgass@retinalburn.net>
29 * José Fonseca <j_r_fonseca@yahoo.co.uk>
30 */
31
32 #include "mach64_context.h"
33 #include "mach64_ioctl.h"
34 #include "mach64_tris.h"
35 #include "mach64_vb.h"
36
37 #include "context.h"
38 #include "imports.h"
39
40 #include "utils.h"
41 #include "vblank.h"
42
43 #ifndef _SOLO
44 #include "GL/internal/dri_interface.h"
45 #endif
46
47 /* Mach64 configuration
48 */
49 #include "xmlpool.h"
50
51 const char __driConfigOptions[] =
52 DRI_CONF_BEGIN
53 DRI_CONF_SECTION_PERFORMANCE
54 DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0)
55 DRI_CONF_SECTION_END
56 #if ENABLE_PERF_BOXES
57 DRI_CONF_SECTION_DEBUG
58 DRI_CONF_PERFORMANCE_BOXES(false)
59 DRI_CONF_SECTION_END
60 #endif
61 DRI_CONF_END;
62 #if ENABLE_PERF_BOXES
63 static const GLuint __driNConfigOptions = 2;
64 #else
65 static const GLuint __driNConfigOptions = 1;
66 #endif
67
68 #ifdef USE_NEW_INTERFACE
69 static PFNGLXCREATECONTEXTMODES create_context_modes = NULL;
70 #endif /* USE_NEW_INTERFACE */
71
72 #ifdef USE_NEW_INTERFACE
73 static __GLcontextModes * fill_in_modes( __GLcontextModes * modes,
74 unsigned pixel_bits,
75 unsigned depth_bits,
76 unsigned stencil_bits,
77 const GLenum * db_modes,
78 unsigned num_db_modes,
79 int visType )
80 {
81 static const uint8_t bits[2][4] = {
82 { 5, 6, 5, 0 },
83 { 8, 8, 8, 0 }
84 };
85
86 static const uint32_t masks[2][4] = {
87 { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 },
88 { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }
89 };
90
91 unsigned i;
92 unsigned j;
93 const unsigned index = ((pixel_bits + 15) / 16) - 1;
94
95 for ( i = 0 ; i < num_db_modes ; i++ ) {
96 for ( j = 0 ; j < 2 ; j++ ) {
97
98 modes->redBits = bits[index][0];
99 modes->greenBits = bits[index][1];
100 modes->blueBits = bits[index][2];
101 modes->alphaBits = bits[index][3];
102 modes->redMask = masks[index][0];
103 modes->greenMask = masks[index][1];
104 modes->blueMask = masks[index][2];
105 modes->alphaMask = masks[index][3];
106 modes->rgbBits = modes->redBits + modes->greenBits
107 + modes->blueBits + modes->alphaBits;
108
109 modes->accumRedBits = 16 * j;
110 modes->accumGreenBits = 16 * j;
111 modes->accumBlueBits = 16 * j;
112 modes->accumAlphaBits = 0;
113 modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG;
114 modes->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT;
115 modes->stencilBits = stencil_bits;
116 modes->depthBits = depth_bits;
117
118 modes->visualType = visType;
119 modes->renderType = GLX_RGBA_BIT;
120 modes->rgbMode = GL_TRUE;
121
122 if ( db_modes[i] == GLX_NONE ) {
123
124 modes->doubleBufferMode = GL_FALSE;
125 }
126 else {
127 modes->doubleBufferMode = GL_TRUE;
128 modes->swapMethod = db_modes[i];
129 }
130
131 modes = modes->next;
132 }
133 }
134
135 return modes;
136 }
137 #endif /* USE_NEW_INTERFACE */
138
139
140 #ifdef USE_NEW_INTERFACE
141 static __GLcontextModes *
142 mach64FillInModes( unsigned pixel_bits, unsigned depth_bits,
143 unsigned stencil_bits, GLboolean have_back_buffer )
144 {
145 __GLcontextModes * modes;
146 __GLcontextModes * m;
147 unsigned num_modes;
148 unsigned depth_buffer_factor;
149 unsigned back_buffer_factor;
150 unsigned i;
151
152 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
153 * enough to add support. Basically, if a context is created with an
154 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
155 * will never be used.
156 */
157 static const GLenum back_buffer_modes[] = {
158 GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
159 };
160
161 int depth_buffer_modes[2][2];
162
163
164 depth_buffer_modes[0][0] = depth_bits;
165 depth_buffer_modes[1][0] = depth_bits;
166
167 /* Just like with the accumulation buffer, always provide some modes
168 * with a stencil buffer. It will be a sw fallback, but some apps won't
169 * care about that.
170 */
171 depth_buffer_modes[0][1] = 0;
172 depth_buffer_modes[1][1] = (stencil_bits == 0) ? 8 : stencil_bits;
173
174 depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
175 back_buffer_factor = (have_back_buffer) ? 2 : 1;
176
177 num_modes = depth_buffer_factor * back_buffer_factor * 4;
178
179 modes = (*create_context_modes)( num_modes, sizeof( __GLcontextModes ) );
180 m = modes;
181 for ( i = 0 ; i < depth_buffer_factor ; i++ ) {
182 m = fill_in_modes( m, pixel_bits,
183 depth_buffer_modes[i][0], depth_buffer_modes[i][1],
184 back_buffer_modes, back_buffer_factor,
185 GLX_TRUE_COLOR );
186 }
187
188 for ( i = 0 ; i < depth_buffer_factor ; i++ ) {
189 m = fill_in_modes( m, pixel_bits,
190 depth_buffer_modes[i][0], depth_buffer_modes[i][1],
191 back_buffer_modes, back_buffer_factor,
192 GLX_DIRECT_COLOR );
193 }
194
195 /* Mark the visual as slow if there are "fake" stencil bits.
196 */
197 for ( m = modes ; m != NULL ; m = m->next ) {
198 if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ){
199 m->visualRating = GLX_SLOW_CONFIG;
200 }
201 }
202
203 return modes;
204 }
205 #endif /* USE_NEW_INTERFACE */
206
207
208 /* Create the device specific screen private data struct.
209 */
210 static mach64ScreenRec *
211 mach64CreateScreen( __DRIscreenPrivate *sPriv )
212 {
213 mach64ScreenPtr mach64Screen;
214 ATIDRIPtr serverInfo = (ATIDRIPtr)sPriv->pDevPriv;
215
216 if ( MACH64_DEBUG & DEBUG_VERBOSE_DRI )
217 fprintf( stderr, "%s\n", __FUNCTION__ );
218
219 /* Allocate the private area */
220 mach64Screen = (mach64ScreenPtr) CALLOC( sizeof(*mach64Screen) );
221 if ( !mach64Screen ) return NULL;
222
223 /* parse information in __driConfigOptions */
224 driParseOptionInfo (&mach64Screen->optionCache,
225 __driConfigOptions, __driNConfigOptions);
226
227 mach64Screen->IsPCI = serverInfo->IsPCI;
228
229 {
230 drm_mach64_getparam_t gp;
231 int ret;
232
233 gp.param = MACH64_PARAM_IRQ_NR;
234 gp.value = (void *) &mach64Screen->irq;
235
236 ret = drmCommandWriteRead( sPriv->fd, DRM_MACH64_GETPARAM,
237 &gp, sizeof(gp));
238 if (ret) {
239 fprintf(stderr, "DRM_MACH64_GETPARAM (MACH64_PARAM_IRQ_NR): %d\n", ret);
240 FREE( mach64Screen );
241 return NULL;
242 }
243 }
244
245 mach64Screen->mmio.handle = serverInfo->regs;
246 mach64Screen->mmio.size = serverInfo->regsSize;
247 if ( drmMap( sPriv->fd,
248 mach64Screen->mmio.handle,
249 mach64Screen->mmio.size,
250 (drmAddressPtr)&mach64Screen->mmio.map ) != 0 ) {
251 FREE( mach64Screen );
252 return NULL;
253 }
254
255 mach64Screen->buffers = drmMapBufs( sPriv->fd );
256 if ( !mach64Screen->buffers ) {
257 drmUnmap( (drmAddress)mach64Screen->mmio.map,
258 mach64Screen->mmio.size );
259 FREE( mach64Screen );
260 return NULL;
261 }
262
263 if ( !mach64Screen->IsPCI ) {
264 mach64Screen->agpTextures.handle = serverInfo->agp;
265 mach64Screen->agpTextures.size = serverInfo->agpSize;
266 if ( drmMap( sPriv->fd,
267 mach64Screen->agpTextures.handle,
268 mach64Screen->agpTextures.size,
269 (drmAddressPtr)&mach64Screen->agpTextures.map ) ) {
270 drmUnmapBufs( mach64Screen->buffers );
271 drmUnmap( (drmAddress)mach64Screen->mmio.map, mach64Screen->mmio.size );
272 FREE( mach64Screen );
273 return NULL;
274 }
275 }
276
277 mach64Screen->AGPMode = serverInfo->AGPMode;
278
279 mach64Screen->chipset = serverInfo->chipset;
280 mach64Screen->width = serverInfo->width;
281 mach64Screen->height = serverInfo->height;
282 mach64Screen->mem = serverInfo->mem;
283 mach64Screen->cpp = serverInfo->cpp;
284
285 mach64Screen->frontOffset = serverInfo->frontOffset;
286 mach64Screen->frontPitch = serverInfo->frontPitch;
287 mach64Screen->backOffset = serverInfo->backOffset;
288 mach64Screen->backPitch = serverInfo->backPitch;
289 mach64Screen->depthOffset = serverInfo->depthOffset;
290 mach64Screen->depthPitch = serverInfo->depthPitch;
291
292 mach64Screen->texOffset[MACH64_CARD_HEAP] = serverInfo->textureOffset;
293 mach64Screen->texSize[MACH64_CARD_HEAP] = serverInfo->textureSize;
294 mach64Screen->logTexGranularity[MACH64_CARD_HEAP] =
295 serverInfo->logTextureGranularity;
296
297 if ( mach64Screen->IsPCI ) {
298 mach64Screen->numTexHeaps = MACH64_NR_TEX_HEAPS - 1;
299 mach64Screen->firstTexHeap = MACH64_CARD_HEAP;
300 mach64Screen->texOffset[MACH64_AGP_HEAP] = 0;
301 mach64Screen->texSize[MACH64_AGP_HEAP] = 0;
302 mach64Screen->logTexGranularity[MACH64_AGP_HEAP] = 0;
303 } else {
304 if (mach64Screen->texSize[MACH64_CARD_HEAP] > 0) {
305 mach64Screen->numTexHeaps = MACH64_NR_TEX_HEAPS;
306 mach64Screen->firstTexHeap = MACH64_CARD_HEAP;
307 } else {
308 mach64Screen->numTexHeaps = MACH64_NR_TEX_HEAPS - 1;
309 mach64Screen->firstTexHeap = MACH64_AGP_HEAP;
310 }
311 mach64Screen->texOffset[MACH64_AGP_HEAP] = serverInfo->agpTextureOffset;
312 mach64Screen->texSize[MACH64_AGP_HEAP] = serverInfo->agpSize;
313 mach64Screen->logTexGranularity[MACH64_AGP_HEAP] = serverInfo->logAgpTextureGranularity;
314 }
315
316 mach64Screen->driScreen = sPriv;
317 #ifndef _SOLO
318 if ( driCompareGLXAPIVersion( 20030813 ) >= 0 ) {
319 PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension =
320 (PFNGLXSCRENABLEEXTENSIONPROC) glXGetProcAddress( (const GLubyte *) "__glXScrEnableExtension" );
321 void * const psc = sPriv->psc->screenConfigs;
322
323 if ( glx_enable_extension != NULL ) {
324 if ( mach64Screen->irq != 0 ) {
325 (*glx_enable_extension)( psc, "GLX_SGI_swap_control" );
326 (*glx_enable_extension)( psc, "GLX_SGI_video_sync" );
327 (*glx_enable_extension)( psc, "GLX_MESA_swap_control" );
328 }
329
330 (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" );
331 }
332 }
333 #endif
334 return mach64Screen;
335 }
336
337 /* Destroy the device specific screen private data struct.
338 */
339 static void
340 mach64DestroyScreen( __DRIscreenPrivate *driScreen )
341 {
342 mach64ScreenRec *mach64Screen = (mach64ScreenRec *) driScreen->private;
343
344 if ( !mach64Screen )
345 return;
346
347 if ( MACH64_DEBUG & DEBUG_VERBOSE_DRI )
348 fprintf( stderr, "%s\n", __FUNCTION__ );
349
350 if ( !mach64Screen->IsPCI ) {
351 drmUnmap( (drmAddress)mach64Screen->agpTextures.map,
352 mach64Screen->agpTextures.size );
353 }
354
355 drmUnmapBufs( mach64Screen->buffers );
356 drmUnmap( (drmAddress)mach64Screen->mmio.map, mach64Screen->mmio.size );
357
358 FREE( mach64Screen );
359 driScreen->private = NULL;
360 }
361
362 /* Initialize the fullscreen mode.
363 */
364 static GLboolean
365 mach64OpenFullScreen( __DRIcontextPrivate *driContextPriv )
366 {
367 return GL_TRUE;
368 }
369
370 /* Shut down the fullscreen mode.
371 */
372 static GLboolean
373 mach64CloseFullScreen( __DRIcontextPrivate *driContextPriv )
374 {
375 return GL_TRUE;
376 }
377
378
379 /* Create and initialize the Mesa and driver specific pixmap buffer
380 * data.
381 */
382 static GLboolean
383 mach64CreateBuffer( __DRIscreenPrivate *driScrnPriv,
384 __DRIdrawablePrivate *driDrawPriv,
385 const __GLcontextModes *mesaVis,
386 GLboolean isPixmap )
387 {
388 if (isPixmap) {
389 return GL_FALSE; /* not implemented */
390 }
391 else {
392 driDrawPriv->driverPrivate = (void *)
393 _mesa_create_framebuffer( mesaVis,
394 GL_FALSE, /* software depth buffer? */
395 mesaVis->stencilBits > 0,
396 mesaVis->accumRedBits > 0,
397 mesaVis->alphaBits > 0 );
398 return (driDrawPriv->driverPrivate != NULL);
399 }
400 }
401
402
403 static void
404 mach64DestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
405 {
406 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
407 }
408
409
410 /* Copy the back color buffer to the front color buffer */
411 static void
412 mach64SwapBuffers(__DRIdrawablePrivate *dPriv)
413 {
414 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
415 mach64ContextPtr mmesa;
416 GLcontext *ctx;
417 mmesa = (mach64ContextPtr) dPriv->driContextPriv->driverPrivate;
418 ctx = mmesa->glCtx;
419 if (ctx->Visual.doubleBufferMode) {
420 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
421 mach64CopyBuffer( dPriv );
422 }
423 }
424 else {
425 /* XXX this shouldn't be an error but we can't handle it for now */
426 _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
427 }
428 }
429
430
431 /* Initialize the driver specific screen private data.
432 */
433 static GLboolean
434 mach64InitDriver( __DRIscreenPrivate *driScreen )
435 {
436 driScreen->private = (void *) mach64CreateScreen( driScreen );
437
438 if ( !driScreen->private ) {
439 mach64DestroyScreen( driScreen );
440 return GL_FALSE;
441 }
442
443 return GL_TRUE;
444 }
445
446 #ifndef _SOLO
447 /* This function is called by libGL.so as soon as libGL.so is loaded.
448 * This is where we register new extension functions with the dispatcher.
449 */
450 void __driRegisterExtensions( void )
451 {
452 #if 0
453 /* KW: This is handled differently in the other drivers, not sure
454 * what to do here.
455 */
456 PFNGLXENABLEEXTENSIONPROC glx_enable_extension;
457
458 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
459 glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC)
460 glXGetProcAddress( (const GLubyte *) "__glXEnableExtension" );
461
462 if ( glx_enable_extension != NULL ) {
463 glx_enable_extension( "GLX_SGI_swap_control", GL_FALSE );
464 glx_enable_extension( "GLX_SGI_video_sync", GL_FALSE );
465 glx_enable_extension( "GLX_MESA_swap_control", GL_FALSE );
466 }
467 }
468 #endif
469 }
470 #endif
471
472 static struct __DriverAPIRec mach64API = {
473 .InitDriver = mach64InitDriver,
474 .DestroyScreen = mach64DestroyScreen,
475 .CreateContext = mach64CreateContext,
476 .DestroyContext = mach64DestroyContext,
477 .CreateBuffer = mach64CreateBuffer,
478 .DestroyBuffer = mach64DestroyBuffer,
479 .SwapBuffers = mach64SwapBuffers,
480 .MakeCurrent = mach64MakeCurrent,
481 .UnbindContext = mach64UnbindContext,
482 .OpenFullScreen = mach64OpenFullScreen,
483 .CloseFullScreen = mach64CloseFullScreen,
484 .GetSwapInfo = NULL,
485 .GetMSC = driGetMSC32,
486 .WaitForMSC = driWaitForMSC32,
487 .WaitForSBC = NULL,
488 .SwapBuffersMSC = NULL
489 };
490
491
492 /*
493 * This is the bootstrap function for the driver.
494 * The __driCreateScreen name is the symbol that libGL.so fetches.
495 * Return: pointer to a __DRIscreenPrivate.
496 */
497 #if !defined(DRI_NEW_INTERFACE_ONLY)
498 #ifndef _SOLO
499 void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
500 int numConfigs, __GLXvisualConfig *config)
501 {
502 __DRIscreenPrivate *psp;
503 psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &mach64API);
504 return (void *) psp;
505 }
506 #else
507 void *__driCreateScreen(struct DRIDriverRec *driver,
508 struct DRIDriverContextRec *driverContext)
509 {
510 __DRIscreenPrivate *psp;
511 psp = __driUtilCreateScreen(driver, driverContext, &mach64API);
512 return (void *) psp;
513 }
514 #endif
515 #endif /* !defined(DRI_NEW_INTERFACE_ONLY) */
516
517 /**
518 * This is the bootstrap function for the driver. libGL supplies all of the
519 * requisite information about the system, and the driver initializes itself.
520 * This routine also fills in the linked list pointed to by \c driver_modes
521 * with the \c __GLcontextModes that the driver can support for windows or
522 * pbuffers.
523 *
524 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
525 * failure.
526 */
527 #ifdef USE_NEW_INTERFACE
528 void * __driCreateNewScreen( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
529 const __GLcontextModes * modes,
530 const __DRIversion * ddx_version,
531 const __DRIversion * dri_version,
532 const __DRIversion * drm_version,
533 const __DRIframebuffer * frame_buffer,
534 drmAddress pSAREA, int fd,
535 int internal_api_version,
536 __GLcontextModes ** driver_modes )
537
538 {
539 __DRIscreenPrivate *psp;
540 static const __DRIversion ddx_expected = { 4, 0, 0 };
541 static const __DRIversion dri_expected = { 6, 4, 0 };
542 static const __DRIversion drm_expected = { 1, 0, 0 };
543
544 if ( ! driCheckDriDdxDrmVersions2( "Mach64",
545 dri_version, & dri_expected,
546 ddx_version, & ddx_expected,
547 drm_version, & drm_expected ) ) {
548 return NULL;
549 }
550
551 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
552 ddx_version, dri_version, drm_version,
553 frame_buffer, pSAREA, fd,
554 internal_api_version, &mach64API);
555 if ( psp != NULL ) {
556 create_context_modes = (PFNGLXCREATECONTEXTMODES)
557 glXGetProcAddress( (const GLubyte *) "__glXCreateContextModes" );
558 if ( create_context_modes != NULL ) {
559 ATIDRIPtr dri_priv = (ATIDRIPtr) psp->pDevPriv;
560 *driver_modes = mach64FillInModes( dri_priv->cpp * 8,
561 16,
562 0,
563 1);
564 }
565 }
566
567 return (void *) psp;
568 }
569 #endif /* USE_NEW_INTERFACE */