Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / drivers / glide / fxapi.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 4.0
4 *
5 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * 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 /* Authors:
26 * David Bucciarelli
27 * Brian Paul
28 * Daryll Strauss
29 * Keith Whitwell
30 * Daniel Borca
31 * Hiroshi Morii
32 */
33
34
35 /* fxapi.c - public interface to FX/Mesa functions (fxmesa.h) */
36
37
38 #ifdef HAVE_CONFIG_H
39 #include "conf.h"
40 #endif
41
42 #if defined(FX)
43 #include "fxdrv.h"
44
45 #include "drivers/common/driverfuncs.h"
46 #include "main/framebuffer.h"
47
48 #ifndef TDFX_DEBUG
49 int TDFX_DEBUG = (0
50 /* | VERBOSE_VARRAY */
51 /* | VERBOSE_TEXTURE */
52 /* | VERBOSE_IMMEDIATE */
53 /* | VERBOSE_PIPELINE */
54 /* | VERBOSE_DRIVER */
55 /* | VERBOSE_STATE */
56 /* | VERBOSE_API */
57 /* | VERBOSE_DISPLAY_LIST */
58 /* | VERBOSE_LIGHTING */
59 /* | VERBOSE_PRIMS */
60 /* | VERBOSE_VERTS */
61 );
62 #endif
63
64 static fxMesaContext fxMesaCurrentCtx = NULL;
65
66 /*
67 * Status of 3Dfx hardware initialization
68 */
69
70 static int glbGlideInitialized = 0;
71 static int glb3DfxPresent = 0;
72 static int glbTotNumCtx = 0;
73
74 static GrHwConfiguration glbHWConfig;
75 static int glbCurrentBoard = 0;
76
77
78 #if defined(__WIN32__)
79 static int
80 cleangraphics(void)
81 {
82 glbTotNumCtx = 1;
83 fxMesaDestroyContext(fxMesaCurrentCtx);
84
85 return 0;
86 }
87 #elif defined(__linux__)
88 static void
89 cleangraphics(void)
90 {
91 glbTotNumCtx = 1;
92 fxMesaDestroyContext(fxMesaCurrentCtx);
93 }
94
95 static void
96 cleangraphics_handler(int s)
97 {
98 fprintf(stderr, "fxmesa: ERROR: received a not handled signal %d\n", s);
99
100 cleangraphics();
101 /* abort(); */
102 exit(1);
103 }
104 #endif
105
106
107 /*
108 * Query 3Dfx hardware presence/kind
109 */
110 static GLboolean GLAPIENTRY fxQueryHardware (void)
111 {
112 if (TDFX_DEBUG & VERBOSE_DRIVER) {
113 fprintf(stderr, "fxQueryHardware()\n");
114 }
115
116 if (!glbGlideInitialized) {
117 grGlideInit();
118 glb3DfxPresent = FX_grSstQueryHardware(&glbHWConfig);
119
120 glbGlideInitialized = 1;
121
122 #if defined(__WIN32__)
123 _onexit((_onexit_t) cleangraphics);
124 #elif defined(__linux__)
125 /* Only register handler if environment variable is not defined. */
126 if (!getenv("MESA_FX_NO_SIGNALS")) {
127 atexit(cleangraphics);
128 }
129 #endif
130 }
131
132 return glb3DfxPresent;
133 }
134
135
136 /*
137 * Select the Voodoo board to use when creating
138 * a new context.
139 */
140 GLint GLAPIENTRY fxMesaSelectCurrentBoard (int n)
141 {
142 fxQueryHardware();
143
144 if ((n < 0) || (n >= glbHWConfig.num_sst))
145 return -1;
146
147 return glbHWConfig.SSTs[glbCurrentBoard = n].type;
148 }
149
150
151 fxMesaContext GLAPIENTRY fxMesaGetCurrentContext (void)
152 {
153 return fxMesaCurrentCtx;
154 }
155
156
157 void GLAPIENTRY fxGetScreenGeometry (GLint *w, GLint *h)
158 {
159 GLint width = 0;
160 GLint height = 0;
161
162 if (fxMesaCurrentCtx != NULL) {
163 width = fxMesaCurrentCtx->screen_width;
164 height = fxMesaCurrentCtx->screen_height;
165 }
166
167 if (w != NULL) {
168 *w = width;
169 }
170 if (h != NULL) {
171 *h = height;
172 }
173 }
174
175
176 /*
177 * The 3Dfx Global Palette extension for GLQuake.
178 * More a trick than a real extesion, use the shared global
179 * palette extension.
180 */
181 extern void GLAPIENTRY gl3DfxSetPaletteEXT(GLuint * pal); /* silence warning */
182 void GLAPIENTRY
183 gl3DfxSetPaletteEXT(GLuint * pal)
184 {
185 fxMesaContext fxMesa = fxMesaCurrentCtx;
186
187 if (TDFX_DEBUG & VERBOSE_DRIVER) {
188 int i;
189
190 fprintf(stderr, "gl3DfxSetPaletteEXT(...)\n");
191
192 for (i = 0; i < 256; i++) {
193 fprintf(stderr, "\t%x\n", pal[i]);
194 }
195 }
196
197 if (fxMesa) {
198 fxMesa->haveGlobalPaletteTexture = 1;
199
200 grTexDownloadTable(GR_TEXTABLE_PALETTE, (GuTexPalette *) pal);
201 }
202 }
203
204
205 static GrScreenResolution_t fxBestResolution (int width, int height)
206 {
207 static int resolutions[][3] = {
208 { GR_RESOLUTION_320x200, 320, 200 },
209 { GR_RESOLUTION_320x240, 320, 240 },
210 { GR_RESOLUTION_400x256, 400, 256 },
211 { GR_RESOLUTION_512x384, 512, 384 },
212 { GR_RESOLUTION_640x200, 640, 200 },
213 { GR_RESOLUTION_640x350, 640, 350 },
214 { GR_RESOLUTION_640x400, 640, 400 },
215 { GR_RESOLUTION_640x480, 640, 480 },
216 { GR_RESOLUTION_800x600, 800, 600 },
217 { GR_RESOLUTION_960x720, 960, 720 },
218 { GR_RESOLUTION_856x480, 856, 480 },
219 { GR_RESOLUTION_512x256, 512, 256 },
220 { GR_RESOLUTION_1024x768, 1024, 768 },
221 { GR_RESOLUTION_1280x1024, 1280, 1024 },
222 { GR_RESOLUTION_1600x1200, 1600, 1200 },
223 { GR_RESOLUTION_400x300, 400, 300 },
224 { GR_RESOLUTION_1152x864, 1152, 864 },
225 { GR_RESOLUTION_1280x960, 1280, 960 },
226 { GR_RESOLUTION_1600x1024, 1600, 1024 },
227 { GR_RESOLUTION_1792x1344, 1792, 1344 },
228 { GR_RESOLUTION_1856x1392, 1856, 1392 },
229 { GR_RESOLUTION_1920x1440, 1920, 1440 },
230 { GR_RESOLUTION_2048x1536, 2048, 1536 },
231 { GR_RESOLUTION_2048x2048, 2048, 2048 }
232 };
233
234 int i, size;
235 int lastvalidres = GR_RESOLUTION_640x480;
236 int min = 2048 * 2048; /* max is GR_RESOLUTION_2048x2048 */
237 GrResolution resTemplate = {
238 GR_QUERY_ANY,
239 GR_QUERY_ANY,
240 2 /*GR_QUERY_ANY */,
241 GR_QUERY_ANY
242 };
243 GrResolution *presSupported;
244
245 fxQueryHardware();
246
247 size = grQueryResolutions(&resTemplate, NULL);
248 presSupported = malloc(size);
249
250 size /= sizeof(GrResolution);
251 grQueryResolutions(&resTemplate, presSupported);
252
253 for (i = 0; i < size; i++) {
254 int r = presSupported[i].resolution;
255 if ((width <= resolutions[r][1]) && (height <= resolutions[r][2])) {
256 if (min > (resolutions[r][1] * resolutions[r][2])) {
257 min = resolutions[r][1] * resolutions[r][2];
258 lastvalidres = r;
259 }
260 }
261 }
262
263 free(presSupported);
264
265 return resolutions[lastvalidres][0];
266 }
267
268
269 fxMesaContext GLAPIENTRY
270 fxMesaCreateBestContext(GLuint win, GLint width, GLint height,
271 const GLint attribList[])
272 {
273 int res = fxBestResolution(width, height);
274
275 if (res == -1) {
276 return NULL;
277 }
278
279 return fxMesaCreateContext(win, res, GR_REFRESH_60Hz, attribList);
280 }
281
282
283 /*
284 * Create a new FX/Mesa context and return a handle to it.
285 */
286 fxMesaContext GLAPIENTRY
287 fxMesaCreateContext(GLuint win,
288 GrScreenResolution_t res,
289 GrScreenRefresh_t ref, const GLint attribList[])
290 {
291 fxMesaContext fxMesa = NULL;
292 GLcontext *ctx = NULL, *shareCtx = NULL;
293 struct dd_function_table functions;
294
295 int i;
296 const char *str;
297 int sliaa, numSLI, samplesPerChip;
298 struct SstCard_St *voodoo;
299 struct tdfx_glide *Glide;
300
301 GLboolean aux;
302 GLboolean doubleBuffer;
303 GLuint colDepth;
304 GLuint depthSize, alphaSize, stencilSize, accumSize;
305 GLuint redBits, greenBits, blueBits, alphaBits;
306 GrPixelFormat_t pixFmt;
307
308 if (TDFX_DEBUG & VERBOSE_DRIVER) {
309 fprintf(stderr, "fxMesaCreateContext(...)\n");
310 }
311
312 /* Okay, first process the user flags */
313 aux = GL_FALSE;
314 doubleBuffer = GL_FALSE;
315 colDepth = 16;
316 depthSize = alphaSize = stencilSize = accumSize = 0;
317
318 i = 0;
319 while (attribList[i] != FXMESA_NONE) {
320 switch (attribList[i]) {
321 case FXMESA_COLORDEPTH:
322 colDepth = attribList[++i];
323 break;
324 case FXMESA_DOUBLEBUFFER:
325 doubleBuffer = GL_TRUE;
326 break;
327 case FXMESA_ALPHA_SIZE:
328 if ((alphaSize = attribList[++i])) {
329 aux = GL_TRUE;
330 }
331 break;
332 case FXMESA_DEPTH_SIZE:
333 if ((depthSize = attribList[++i])) {
334 aux = GL_TRUE;
335 }
336 break;
337 case FXMESA_STENCIL_SIZE:
338 stencilSize = attribList[++i];
339 break;
340 case FXMESA_ACCUM_SIZE:
341 accumSize = attribList[++i];
342 break;
343 /* XXX ugly hack here for sharing display lists */
344 case FXMESA_SHARE_CONTEXT:
345 shareCtx = (GLcontext *)attribList[++i];
346 break;
347 default:
348 fprintf(stderr, "fxMesaCreateContext: ERROR: wrong parameter (%d) passed\n", attribList[i]);
349 return NULL;
350 }
351 i++;
352 }
353
354 if (!fxQueryHardware()) {
355 str = "no Voodoo hardware!";
356 goto errorhandler;
357 }
358
359 grSstSelect(glbCurrentBoard);
360 /*grEnable(GR_OPENGL_MODE_EXT);*/ /* [koolsmoky] */
361 voodoo = &glbHWConfig.SSTs[glbCurrentBoard];
362
363 fxMesa = (fxMesaContext)CALLOC_STRUCT(tfxMesaContext);
364 if (!fxMesa) {
365 str = "private context";
366 goto errorhandler;
367 }
368
369 if (getenv("MESA_FX_INFO")) {
370 fxMesa->verbose = GL_TRUE;
371 }
372
373 fxMesa->type = voodoo->type;
374 fxMesa->HavePalExt = voodoo->HavePalExt && !getenv("MESA_FX_IGNORE_PALEXT");
375 fxMesa->HavePixExt = voodoo->HavePixExt && !getenv("MESA_FX_IGNORE_PIXEXT");
376 fxMesa->HaveTexFmt = voodoo->HaveTexFmt && !getenv("MESA_FX_IGNORE_TEXFMT");
377 fxMesa->HaveCmbExt = voodoo->HaveCmbExt && !getenv("MESA_FX_IGNORE_CMBEXT");
378 fxMesa->HaveMirExt = voodoo->HaveMirExt && !getenv("MESA_FX_IGNORE_MIREXT");
379 fxMesa->HaveTexUma = voodoo->HaveTexUma && !getenv("MESA_FX_IGNORE_TEXUMA");
380 fxMesa->Glide = glbHWConfig.Glide;
381 Glide = &fxMesa->Glide;
382 fxMesa->HaveTexus2 = Glide->txImgQuantize &&
383 Glide->txMipQuantize &&
384 Glide->txPalToNcc && !getenv("MESA_FX_IGNORE_TEXUS2");
385
386 /* Determine if we need vertex swapping, RGB order and SLI/AA */
387 sliaa = 0;
388 switch (fxMesa->type) {
389 case GR_SSTTYPE_VOODOO:
390 case GR_SSTTYPE_SST96:
391 case GR_SSTTYPE_Banshee:
392 fxMesa->bgrOrder = GL_TRUE;
393 fxMesa->snapVertices = (getenv("MESA_FX_NOSNAP") == NULL);
394 break;
395 case GR_SSTTYPE_Voodoo2:
396 fxMesa->bgrOrder = GL_TRUE;
397 fxMesa->snapVertices = GL_FALSE;
398 break;
399 case GR_SSTTYPE_Voodoo4:
400 case GR_SSTTYPE_Voodoo5:
401 /* number of SLI units and AA Samples per chip */
402 if ((str = Glide->grGetRegistryOrEnvironmentStringExt("SSTH3_SLI_AA_CONFIGURATION")) != NULL) {
403 sliaa = atoi(str);
404 }
405 case GR_SSTTYPE_Voodoo3:
406 default:
407 fxMesa->bgrOrder = GL_FALSE;
408 fxMesa->snapVertices = GL_FALSE;
409 break;
410 }
411 /* XXX todo - Add the old SLI/AA settings for Napalm. */
412 switch(voodoo->numChips) {
413 case 4: /* 4 chips */
414 switch(sliaa) {
415 case 8: /* 8 Sample AA */
416 numSLI = 1;
417 samplesPerChip = 2;
418 break;
419 case 7: /* 4 Sample AA */
420 numSLI = 1;
421 samplesPerChip = 1;
422 break;
423 case 6: /* 2 Sample AA */
424 numSLI = 2;
425 samplesPerChip = 1;
426 break;
427 default:
428 numSLI = 4;
429 samplesPerChip = 1;
430 }
431 break;
432 case 2: /* 2 chips */
433 switch(sliaa) {
434 case 4: /* 4 Sample AA */
435 numSLI = 1;
436 samplesPerChip = 2;
437 break;
438 case 3: /* 2 Sample AA */
439 numSLI = 1;
440 samplesPerChip = 1;
441 break;
442 default:
443 numSLI = 2;
444 samplesPerChip = 1;
445 }
446 break;
447 default: /* 1 chip */
448 switch(sliaa) {
449 case 1: /* 2 Sample AA */
450 numSLI = 1;
451 samplesPerChip = 2;
452 break;
453 default:
454 numSLI = 1;
455 samplesPerChip = 1;
456 }
457 }
458
459 fxMesa->fsaa = samplesPerChip * voodoo->numChips / numSLI; /* 1:noFSAA, 2:2xFSAA, 4:4xFSAA, 8:8xFSAA */
460
461 switch (fxMesa->colDepth = colDepth) {
462 case 15:
463 redBits = 5;
464 greenBits = 5;
465 blueBits = 5;
466 alphaBits = depthSize ? 1 : 8;
467 switch(fxMesa->fsaa) {
468 case 8:
469 pixFmt = GR_PIXFMT_AA_8_ARGB_1555;
470 break;
471 case 4:
472 pixFmt = GR_PIXFMT_AA_4_ARGB_1555;
473 break;
474 case 2:
475 pixFmt = GR_PIXFMT_AA_2_ARGB_1555;
476 break;
477 default:
478 pixFmt = GR_PIXFMT_ARGB_1555;
479 }
480 break;
481 case 16:
482 redBits = 5;
483 greenBits = 6;
484 blueBits = 5;
485 alphaBits = depthSize ? 0 : 8;
486 switch(fxMesa->fsaa) {
487 case 8:
488 pixFmt = GR_PIXFMT_AA_8_RGB_565;
489 break;
490 case 4:
491 pixFmt = GR_PIXFMT_AA_4_RGB_565;
492 break;
493 case 2:
494 pixFmt = GR_PIXFMT_AA_2_RGB_565;
495 break;
496 default:
497 pixFmt = GR_PIXFMT_RGB_565;
498 }
499 break;
500 case 24:
501 fxMesa->colDepth = 32;
502 case 32:
503 redBits = 8;
504 greenBits = 8;
505 blueBits = 8;
506 alphaBits = 8;
507 switch(fxMesa->fsaa) {
508 case 8:
509 pixFmt = GR_PIXFMT_AA_8_ARGB_8888;
510 break;
511 case 4:
512 pixFmt = GR_PIXFMT_AA_4_ARGB_8888;
513 break;
514 case 2:
515 pixFmt = GR_PIXFMT_AA_2_ARGB_8888;
516 break;
517 default:
518 pixFmt = GR_PIXFMT_ARGB_8888;
519 }
520 break;
521 default:
522 str = "pixelFormat";
523 goto errorhandler;
524 }
525
526 /* Tips:
527 * 1. we don't bother setting/checking AUX for stencil, because we'll decide
528 * later whether we have HW stencil, based on depth buffer (thus AUX is
529 * properly set)
530 * 2. when both DEPTH and ALPHA are enabled, depth should win. However, it is
531 * not clear whether 15bpp and 32bpp require AUX alpha buffer. Furthermore,
532 * alpha buffering is required only if destination alpha is used in alpha
533 * blending; alpha blending modes that do not use destination alpha can be
534 * used w/o alpha buffer.
535 * 3. `alphaBits' is what we can provide
536 * `alphaSize' is what app requests
537 * if we cannot provide enough bits for alpha buffer, we should fallback to
538 * SW alpha. However, setting `alphaBits' to `alphaSize' might confuse some
539 * of the span functions...
540 */
541
542 fxMesa->haveHwAlpha = GL_FALSE;
543 if (alphaSize && (alphaSize <= alphaBits)) {
544 alphaSize = alphaBits;
545 fxMesa->haveHwAlpha = GL_TRUE;
546 }
547
548 fxMesa->haveHwStencil = (fxMesa->HavePixExt && stencilSize && depthSize == 24);
549
550 fxMesa->haveZBuffer = depthSize > 0;
551 fxMesa->haveDoubleBuffer = doubleBuffer;
552 fxMesa->haveGlobalPaletteTexture = GL_FALSE;
553 fxMesa->board = glbCurrentBoard;
554
555 fxMesa->haveTwoTMUs = (voodoo->nTexelfx > 1);
556
557 if ((str = Glide->grGetRegistryOrEnvironmentStringExt("FX_GLIDE_NUM_TMU"))) {
558 if (atoi(str) <= 1) {
559 fxMesa->haveTwoTMUs = GL_FALSE;
560 }
561 }
562
563 if ((str = Glide->grGetRegistryOrEnvironmentStringExt("FX_GLIDE_SWAPPENDINGCOUNT"))) {
564 fxMesa->maxPendingSwapBuffers = atoi(str);
565 if (fxMesa->maxPendingSwapBuffers > 6) {
566 fxMesa->maxPendingSwapBuffers = 6;
567 } else if (fxMesa->maxPendingSwapBuffers < 0) {
568 fxMesa->maxPendingSwapBuffers = 0;
569 }
570 } else {
571 fxMesa->maxPendingSwapBuffers = 2;
572 }
573
574 if ((str = Glide->grGetRegistryOrEnvironmentStringExt("FX_GLIDE_SWAPINTERVAL"))) {
575 fxMesa->swapInterval = atoi(str);
576 } else {
577 fxMesa->swapInterval = 0;
578 }
579
580 BEGIN_BOARD_LOCK();
581 if (fxMesa->HavePixExt) {
582 fxMesa->glideContext = Glide->grSstWinOpenExt((FxU32)win, res, ref,
583 GR_COLORFORMAT_ABGR, GR_ORIGIN_LOWER_LEFT,
584 pixFmt,
585 2, aux);
586 } else if (pixFmt == GR_PIXFMT_RGB_565) {
587 fxMesa->glideContext = grSstWinOpen((FxU32)win, res, ref,
588 GR_COLORFORMAT_ABGR, GR_ORIGIN_LOWER_LEFT,
589 2, aux);
590 } else {
591 fxMesa->glideContext = 0;
592 }
593 END_BOARD_LOCK();
594 if (!fxMesa->glideContext) {
595 str = "grSstWinOpen";
596 goto errorhandler;
597 }
598
599 /* screen */
600 fxMesa->screen_width = FX_grSstScreenWidth();
601 fxMesa->screen_height = FX_grSstScreenHeight();
602
603 /* window inside screen */
604 fxMesa->width = fxMesa->screen_width;
605 fxMesa->height = fxMesa->screen_height;
606
607 /* scissor inside window */
608 fxMesa->clipMinX = 0;
609 fxMesa->clipMaxX = fxMesa->width;
610 fxMesa->clipMinY = 0;
611 fxMesa->clipMaxY = fxMesa->height;
612
613 if (fxMesa->verbose) {
614 FxI32 tmuRam, fbRam;
615
616 /* Not that it matters, but tmuRam and fbRam change after grSstWinOpen. */
617 tmuRam = voodoo->tmuConfig[GR_TMU0].tmuRam;
618 fbRam = voodoo->fbRam;
619 BEGIN_BOARD_LOCK();
620 grGet(GR_MEMORY_TMU, 4, &tmuRam);
621 grGet(GR_MEMORY_FB, 4, &fbRam);
622 END_BOARD_LOCK();
623
624 fprintf(stderr, "Voodoo Using Glide %s\n", grGetString(GR_VERSION));
625 fprintf(stderr, "Voodoo Board: %d/%d, %s, %d GPU\n",
626 fxMesa->board + 1,
627 glbHWConfig.num_sst,
628 grGetString(GR_HARDWARE),
629 voodoo->numChips);
630 fprintf(stderr, "Voodoo Memory: FB = %ld, TM = %d x %ld\n",
631 fbRam,
632 voodoo->nTexelfx,
633 tmuRam);
634 fprintf(stderr, "Voodoo Screen: %dx%d:%d %s, %svertex snapping\n",
635 fxMesa->screen_width,
636 fxMesa->screen_height,
637 colDepth,
638 fxMesa->bgrOrder ? "BGR" : "RGB",
639 fxMesa->snapVertices ? "" : "no ");
640 }
641
642 sprintf(fxMesa->rendererString, "Mesa %s v0.63 %s%s",
643 grGetString(GR_RENDERER),
644 grGetString(GR_HARDWARE),
645 ((fxMesa->type < GR_SSTTYPE_Voodoo4) && (voodoo->numChips > 1)) ? " SLI" : "");
646
647 fxMesa->glVis = _mesa_create_visual(GL_TRUE, /* RGB mode */
648 doubleBuffer,
649 GL_FALSE, /* stereo */
650 redBits, /* RGBA.R bits */
651 greenBits, /* RGBA.G bits */
652 blueBits, /* RGBA.B bits */
653 alphaSize, /* RGBA.A bits */
654 0, /* index bits */
655 depthSize, /* depth_size */
656 stencilSize, /* stencil_size */
657 accumSize,
658 accumSize,
659 accumSize,
660 alphaSize ? accumSize : 0,
661 1);
662 if (!fxMesa->glVis) {
663 str = "_mesa_create_visual";
664 goto errorhandler;
665 }
666
667 _mesa_init_driver_functions(&functions);
668 ctx = fxMesa->glCtx = _mesa_create_context(fxMesa->glVis, shareCtx,
669 &functions, (void *) fxMesa);
670 if (!ctx) {
671 str = "_mesa_create_context";
672 goto errorhandler;
673 }
674
675
676 if (!fxDDInitFxMesaContext(fxMesa)) {
677 str = "fxDDInitFxMesaContext";
678 goto errorhandler;
679 }
680
681
682 fxMesa->glBuffer = _mesa_create_framebuffer(fxMesa->glVis);
683 #if 0
684 /* XXX this is a complete mess :(
685 * _mesa_add_soft_renderbuffers
686 * driNewRenderbuffer
687 */
688 GL_FALSE, /* no software depth */
689 stencilSize && !fxMesa->haveHwStencil,
690 fxMesa->glVis->accumRedBits > 0,
691 alphaSize && !fxMesa->haveHwAlpha);
692 #endif
693 if (!fxMesa->glBuffer) {
694 str = "_mesa_create_framebuffer";
695 goto errorhandler;
696 }
697
698 glbTotNumCtx++;
699
700 /* install signal handlers */
701 #if defined(__linux__)
702 /* Only install if environment var. is not set. */
703 if (!getenv("MESA_FX_NO_SIGNALS")) {
704 signal(SIGINT, cleangraphics_handler);
705 signal(SIGHUP, cleangraphics_handler);
706 signal(SIGPIPE, cleangraphics_handler);
707 signal(SIGFPE, cleangraphics_handler);
708 signal(SIGBUS, cleangraphics_handler);
709 signal(SIGILL, cleangraphics_handler);
710 signal(SIGSEGV, cleangraphics_handler);
711 signal(SIGTERM, cleangraphics_handler);
712 }
713 #endif
714
715 return fxMesa;
716
717 errorhandler:
718 if (fxMesa) {
719 if (fxMesa->glideContext) {
720 grSstWinClose(fxMesa->glideContext);
721 fxMesa->glideContext = 0;
722 }
723
724 if (fxMesa->state) {
725 FREE(fxMesa->state);
726 }
727 if (fxMesa->fogTable) {
728 FREE(fxMesa->fogTable);
729 }
730 if (fxMesa->glBuffer) {
731 _mesa_reference_framebuffer(&fxMesa->glBuffer, NULL);
732 }
733 if (fxMesa->glVis) {
734 _mesa_destroy_visual(fxMesa->glVis);
735 }
736 if (fxMesa->glCtx) {
737 _mesa_destroy_context(fxMesa->glCtx);
738 }
739 FREE(fxMesa);
740 }
741
742 fprintf(stderr, "fxMesaCreateContext: ERROR: %s\n", str);
743 return NULL;
744 }
745
746
747 /*
748 * Function to set the new window size in the context (mainly for the Voodoo Rush)
749 */
750 void GLAPIENTRY
751 fxMesaUpdateScreenSize(fxMesaContext fxMesa)
752 {
753 fxMesa->width = FX_grSstScreenWidth();
754 fxMesa->height = FX_grSstScreenHeight();
755 }
756
757
758 /*
759 * Destroy the given FX/Mesa context.
760 */
761 void GLAPIENTRY
762 fxMesaDestroyContext(fxMesaContext fxMesa)
763 {
764 if (TDFX_DEBUG & VERBOSE_DRIVER) {
765 fprintf(stderr, "fxMesaDestroyContext(...)\n");
766 }
767
768 if (!fxMesa)
769 return;
770
771 if (fxMesa->verbose) {
772 fprintf(stderr, "Misc Stats:\n");
773 fprintf(stderr, " # swap buffer: %u\n", fxMesa->stats.swapBuffer);
774
775 if (!fxMesa->stats.swapBuffer)
776 fxMesa->stats.swapBuffer = 1;
777
778 fprintf(stderr, "Textures Stats:\n");
779 fprintf(stderr, " Free texture memory on TMU0: %d\n",
780 fxMesa->freeTexMem[FX_TMU0]);
781 if (fxMesa->haveTwoTMUs)
782 fprintf(stderr, " Free texture memory on TMU1: %d\n",
783 fxMesa->freeTexMem[FX_TMU1]);
784 fprintf(stderr, " # request to TMM to upload a texture objects: %u\n",
785 fxMesa->stats.reqTexUpload);
786 fprintf(stderr,
787 " # request to TMM to upload a texture objects per swapbuffer: %.2f\n",
788 fxMesa->stats.reqTexUpload / (float) fxMesa->stats.swapBuffer);
789 fprintf(stderr, " # texture objects uploaded: %u\n",
790 fxMesa->stats.texUpload);
791 fprintf(stderr, " # texture objects uploaded per swapbuffer: %.2f\n",
792 fxMesa->stats.texUpload / (float) fxMesa->stats.swapBuffer);
793 fprintf(stderr, " # MBs uploaded to texture memory: %.2f\n",
794 fxMesa->stats.memTexUpload / (float) (1 << 20));
795 fprintf(stderr,
796 " # MBs uploaded to texture memory per swapbuffer: %.2f\n",
797 (fxMesa->stats.memTexUpload /
798 (float) fxMesa->stats.swapBuffer) / (float) (1 << 20));
799 }
800
801 glbTotNumCtx--;
802
803 if (!glbTotNumCtx && getenv("MESA_FX_INFO")) {
804 GrSstPerfStats_t st;
805
806 FX_grSstPerfStats(&st);
807
808 fprintf(stderr, "Pixels Stats:\n");
809 fprintf(stderr, " # pixels processed (minus buffer clears): %u\n",
810 (unsigned) st.pixelsIn);
811 fprintf(stderr, " # pixels not drawn due to chroma key test failure: %u\n",
812 (unsigned) st.chromaFail);
813 fprintf(stderr, " # pixels not drawn due to depth test failure: %u\n",
814 (unsigned) st.zFuncFail);
815 fprintf(stderr,
816 " # pixels not drawn due to alpha test failure: %u\n",
817 (unsigned) st.aFuncFail);
818 fprintf(stderr, " # pixels drawn (including buffer clears and LFB writes): %u\n",
819 (unsigned) st.pixelsOut);
820 }
821
822 /* close the hardware first,
823 * so we can debug atexit problems (memory leaks, etc).
824 */
825 grSstWinClose(fxMesa->glideContext);
826 fxCloseHardware();
827
828 fxDDDestroyFxMesaContext(fxMesa); /* must be before _mesa_destroy_context */
829 _mesa_destroy_visual(fxMesa->glVis);
830 _mesa_destroy_context(fxMesa->glCtx);
831 _mesa_reference_framebuffer(&fxMesa->glBuffer, NULL);
832 fxTMClose(fxMesa); /* must be after _mesa_destroy_context */
833
834 FREE(fxMesa);
835
836 if (fxMesa == fxMesaCurrentCtx)
837 fxMesaCurrentCtx = NULL;
838 }
839
840
841 /*
842 * Make the specified FX/Mesa context the current one.
843 */
844 void GLAPIENTRY
845 fxMesaMakeCurrent(fxMesaContext fxMesa)
846 {
847 if (!fxMesa) {
848 _mesa_make_current(NULL, NULL, NULL);
849 fxMesaCurrentCtx = NULL;
850
851 if (TDFX_DEBUG & VERBOSE_DRIVER) {
852 fprintf(stderr, "fxMesaMakeCurrent(NULL)\n");
853 }
854
855 return;
856 }
857
858 /* if this context is already the current one, we can return early */
859 if (fxMesaCurrentCtx == fxMesa
860 && fxMesaCurrentCtx->glCtx == _mesa_get_current_context()) {
861 if (TDFX_DEBUG & VERBOSE_DRIVER) {
862 fprintf(stderr, "fxMesaMakeCurrent(NOP)\n");
863 }
864
865 return;
866 }
867
868 if (TDFX_DEBUG & VERBOSE_DRIVER) {
869 fprintf(stderr, "fxMesaMakeCurrent(...)\n");
870 }
871
872 if (fxMesaCurrentCtx)
873 grGlideGetState((GrState *) fxMesaCurrentCtx->state);
874
875 fxMesaCurrentCtx = fxMesa;
876
877 grSstSelect(fxMesa->board);
878 grGlideSetState((GrState *) fxMesa->state);
879
880 _mesa_make_current(fxMesa->glCtx, fxMesa->glBuffer, fxMesa->glBuffer);
881
882 fxSetupDDPointers(fxMesa->glCtx);
883 }
884
885
886 /*
887 * Swap front/back buffers for current context if double buffered.
888 */
889 void GLAPIENTRY
890 fxMesaSwapBuffers(void)
891 {
892 if (TDFX_DEBUG & VERBOSE_DRIVER) {
893 fprintf(stderr, "fxMesaSwapBuffers()\n");
894 }
895
896 if (fxMesaCurrentCtx) {
897 _mesa_notifySwapBuffers(fxMesaCurrentCtx->glCtx);
898
899 if (fxMesaCurrentCtx->haveDoubleBuffer) {
900
901 grBufferSwap(fxMesaCurrentCtx->swapInterval);
902
903 #if 0
904 /*
905 * Don't allow swap buffer commands to build up!
906 */
907 while (FX_grGetInteger(GR_PENDING_BUFFERSWAPS) >
908 fxMesaCurrentCtx->maxPendingSwapBuffers)
909 /* The driver is able to sleep when waiting for the completation
910 of multiple swapbuffer operations instead of wasting
911 CPU time (NOTE: you must uncomment the following line in the
912 in order to enable this option) */
913 /* usleep(10000); */
914 ;
915 #endif
916
917 fxMesaCurrentCtx->stats.swapBuffer++;
918 }
919 }
920 }
921
922
923 /*
924 * Shutdown Glide library
925 */
926 void GLAPIENTRY
927 fxCloseHardware(void)
928 {
929 if (glbGlideInitialized) {
930 if (glbTotNumCtx == 0) {
931 grGlideShutdown();
932 glbGlideInitialized = 0;
933 }
934 }
935 }
936
937
938 #else
939
940
941 /*
942 * Need this to provide at least one external definition.
943 */
944 extern int gl_fx_dummy_function_api(void);
945 int
946 gl_fx_dummy_function_api(void)
947 {
948 return 0;
949 }
950
951 #endif /* FX */