caff9488512165a57a32487ad88217b34d99ad23
[mesa.git] / src / mesa / drivers / glide / fxdd.c
1 /* $Id: fxdd.c,v 1.87 2002/06/15 02:38:16 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.0
6 *
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /* Authors:
28 * David Bucciarelli
29 * Brian Paul
30 * Daryll Strauss
31 * Keith Whitwell
32 */
33
34 /* fxdd.c - 3Dfx VooDoo Mesa device driver functions */
35
36
37 #ifdef HAVE_CONFIG_H
38 #include "conf.h"
39 #endif
40
41 #if defined(FX)
42
43 #include "image.h"
44 #include "mtypes.h"
45 #include "fxdrv.h"
46 #include "enums.h"
47 #include "extensions.h"
48 #include "texstore.h"
49 #include "swrast/swrast.h"
50 #include "swrast_setup/swrast_setup.h"
51 #include "tnl/tnl.h"
52 #include "tnl/t_context.h"
53 #include "tnl/t_pipeline.h"
54 #include "array_cache/acache.h"
55
56
57
58 float gl_ubyte_to_float_255_color_tab[256];
59
60 /* These lookup table are used to extract RGB values in [0,255] from
61 * 16-bit pixel values.
62 */
63 GLubyte FX_PixelToR[0x10000];
64 GLubyte FX_PixelToG[0x10000];
65 GLubyte FX_PixelToB[0x10000];
66
67
68 /*
69 * Initialize the FX_PixelTo{RGB} arrays.
70 * Input: bgrOrder - if TRUE, pixels are in BGR order, else RGB order.
71 */
72 void
73 fxInitPixelTables(fxMesaContext fxMesa, GLboolean bgrOrder)
74 {
75 GLuint pixel;
76
77 fxMesa->bgrOrder = bgrOrder;
78 for (pixel = 0; pixel <= 0xffff; pixel++) {
79 GLuint r, g, b;
80 if (bgrOrder) {
81 r = (pixel & 0x001F) << 3;
82 g = (pixel & 0x07E0) >> 3;
83 b = (pixel & 0xF800) >> 8;
84 }
85 else {
86 r = (pixel & 0xF800) >> 8;
87 g = (pixel & 0x07E0) >> 3;
88 b = (pixel & 0x001F) << 3;
89 }
90 r = r * 255 / 0xF8; /* fill in low-order bits */
91 g = g * 255 / 0xFC;
92 b = b * 255 / 0xF8;
93 FX_PixelToR[pixel] = r;
94 FX_PixelToG[pixel] = g;
95 FX_PixelToB[pixel] = b;
96 }
97 }
98
99
100 /**********************************************************************/
101 /***** Miscellaneous functions *****/
102 /**********************************************************************/
103
104 /* Return buffer size information */
105 static void
106 fxDDBufferSize(GLframebuffer *buffer, GLuint * width, GLuint * height)
107 {
108 GET_CURRENT_CONTEXT(ctx);
109 if (ctx && ctx->DriverCtx) {
110 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
111
112 if (MESA_VERBOSE & VERBOSE_DRIVER) {
113 fprintf(stderr, "fxmesa: fxDDBufferSize(...) Start\n");
114 }
115
116 *width = fxMesa->width;
117 *height = fxMesa->height;
118
119 if (MESA_VERBOSE & VERBOSE_DRIVER) {
120 fprintf(stderr, "fxmesa: fxDDBufferSize(...) End\n");
121 }
122 }
123 }
124
125
126 /* Implements glClearColor() */
127 static void
128 fxDDClearColor(GLcontext * ctx, const GLchan color[4])
129 {
130 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
131 GLubyte col[4];
132
133 if (MESA_VERBOSE & VERBOSE_DRIVER) {
134 fprintf(stderr, "fxmesa: fxDDClearColor(%d,%d,%d,%d)\n",
135 color[0], color[1], color[2], color[3]);
136 }
137
138 ASSIGN_4V(col, color[0], color[1], color[2], 255);
139 fxMesa->clearC = FXCOLOR4(col);
140 fxMesa->clearA = color[3];
141 }
142
143
144 /* Clear the color and/or depth buffers */
145 static void
146 fxDDClear(GLcontext * ctx, GLbitfield mask, GLboolean all,
147 GLint x, GLint y, GLint width, GLint height)
148 {
149 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
150 const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask);
151 const FxU16 clearD = (FxU16) (ctx->Depth.Clear * 0xffff);
152 GLbitfield softwareMask = mask & (DD_STENCIL_BIT | DD_ACCUM_BIT);
153
154 /* we can't clear stencil or accum buffers */
155 mask &= ~(DD_STENCIL_BIT | DD_ACCUM_BIT);
156
157 if (MESA_VERBOSE & VERBOSE_DRIVER) {
158 fprintf(stderr, "fxmesa: fxDDClear(%d,%d,%d,%d)\n", (int) x, (int) y,
159 (int) width, (int) height);
160 }
161
162 if (colorMask != 0xffffffff) {
163 /* do masked color buffer clears in software */
164 softwareMask |= (mask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT));
165 mask &= ~(DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT);
166 }
167
168 /*
169 * This could probably be done fancier but doing each possible case
170 * explicitly is less error prone.
171 */
172 switch (mask) {
173 case DD_BACK_LEFT_BIT | DD_DEPTH_BIT:
174 /* back buffer & depth */
175 FX_grDepthMask(FXTRUE);
176 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
177 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
178 if (!ctx->Depth.Mask) {
179 FX_grDepthMask(FXFALSE);
180 }
181 break;
182 case DD_FRONT_LEFT_BIT | DD_DEPTH_BIT:
183 /* XXX it appears that the depth buffer isn't cleared when
184 * glRenderBuffer(GR_BUFFER_FRONTBUFFER) is set.
185 * This is a work-around/
186 */
187 /* clear depth */
188 FX_grDepthMask(FXTRUE);
189 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
190 FX_grColorMask(FXFALSE, FXFALSE);
191 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
192 /* clear front */
193 FX_grColorMask(FXTRUE, ctx->Color.ColorMask[ACOMP]
194 && fxMesa->haveAlphaBuffer);
195 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
196 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
197 break;
198 case DD_BACK_LEFT_BIT:
199 /* back buffer only */
200 FX_grDepthMask(FXFALSE);
201 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
202 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
203 if (ctx->Depth.Mask) {
204 FX_grDepthMask(FXTRUE);
205 }
206 break;
207 case DD_FRONT_LEFT_BIT:
208 /* front buffer only */
209 FX_grDepthMask(FXFALSE);
210 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
211 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
212 if (ctx->Depth.Mask) {
213 FX_grDepthMask(FXTRUE);
214 }
215 break;
216 case DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT:
217 /* front and back */
218 FX_grDepthMask(FXFALSE);
219 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
220 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
221 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
222 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
223 if (ctx->Depth.Mask) {
224 FX_grDepthMask(FXTRUE);
225 }
226 break;
227 case DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT | DD_DEPTH_BIT:
228 /* clear front */
229 FX_grDepthMask(FXFALSE);
230 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
231 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
232 /* clear back and depth */
233 FX_grDepthMask(FXTRUE);
234 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
235 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
236 if (!ctx->Depth.Mask) {
237 FX_grDepthMask(FXFALSE);
238 }
239 break;
240 case DD_DEPTH_BIT:
241 /* just the depth buffer */
242 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
243 FX_grColorMask(FXFALSE, FXFALSE);
244 FX_grDepthMask(FXTRUE);
245 FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
246 FX_grColorMask(FXTRUE, ctx->Color.ColorMask[ACOMP]
247 && fxMesa->haveAlphaBuffer);
248 if (ctx->Color.DrawDestMask & FRONT_LEFT_BIT)
249 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
250 if (!ctx->Depth.Test || !ctx->Depth.Mask)
251 FX_grDepthMask(FXFALSE);
252 break;
253 default:
254 /* error */
255 ;
256 }
257
258 /* Clear any remaining buffers:
259 */
260 if (softwareMask)
261 _swrast_Clear(ctx, softwareMask, all, x, y, width, height);
262 }
263
264
265 /* Set the buffer used for drawing */
266 /* XXX support for separate read/draw buffers hasn't been tested */
267 static void
268 fxDDSetDrawBuffer(GLcontext * ctx, GLenum mode)
269 {
270 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
271
272 if (MESA_VERBOSE & VERBOSE_DRIVER) {
273 fprintf(stderr, "fxmesa: fxDDSetBuffer(%x)\n", (int) mode);
274 }
275
276 if (mode == GL_FRONT_LEFT) {
277 fxMesa->currentFB = GR_BUFFER_FRONTBUFFER;
278 FX_grRenderBuffer(fxMesa->currentFB);
279 }
280 else if (mode == GL_BACK_LEFT) {
281 fxMesa->currentFB = GR_BUFFER_BACKBUFFER;
282 FX_grRenderBuffer(fxMesa->currentFB);
283 }
284 else if (mode == GL_NONE) {
285 FX_grColorMask(FXFALSE, FXFALSE);
286 }
287 else {
288 /* we'll need a software fallback */
289 /* XXX not implemented */
290 }
291 }
292
293
294
295
296
297 static void
298 fxDDDrawBitmap(GLcontext * ctx, GLint px, GLint py,
299 GLsizei width, GLsizei height,
300 const struct gl_pixelstore_attrib *unpack,
301 const GLubyte * bitmap)
302 {
303 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
304 GrLfbInfo_t info;
305 FxU16 color;
306 const struct gl_pixelstore_attrib *finalUnpack;
307 struct gl_pixelstore_attrib scissoredUnpack;
308
309 /* check if there's any raster operations enabled which we can't handle */
310 if (ctx->Color.AlphaEnabled ||
311 ctx->Color.BlendEnabled ||
312 ctx->Depth.Test ||
313 ctx->Fog.Enabled ||
314 ctx->Color.ColorLogicOpEnabled ||
315 ctx->Stencil.Enabled ||
316 ctx->Scissor.Enabled ||
317 (ctx->DrawBuffer->UseSoftwareAlphaBuffers &&
318 ctx->Color.ColorMask[ACOMP]) || ctx->Color.MultiDrawBuffer) {
319 _swrast_Bitmap(ctx, px, py, width, height, unpack, bitmap);
320 return;
321 }
322
323
324 if (ctx->Scissor.Enabled) {
325 /* This is a bit tricky, but by carefully adjusting the px, py,
326 * width, height, skipPixels and skipRows values we can do
327 * scissoring without special code in the rendering loop.
328 *
329 * KW: This code is never reached, see the test above.
330 */
331
332 /* we'll construct a new pixelstore struct */
333 finalUnpack = &scissoredUnpack;
334 scissoredUnpack = *unpack;
335 if (scissoredUnpack.RowLength == 0)
336 scissoredUnpack.RowLength = width;
337
338 /* clip left */
339 if (px < ctx->Scissor.X) {
340 scissoredUnpack.SkipPixels += (ctx->Scissor.X - px);
341 width -= (ctx->Scissor.X - px);
342 px = ctx->Scissor.X;
343 }
344 /* clip right */
345 if (px + width >= ctx->Scissor.X + ctx->Scissor.Width) {
346 width -= (px + width - (ctx->Scissor.X + ctx->Scissor.Width));
347 }
348 /* clip bottom */
349 if (py < ctx->Scissor.Y) {
350 scissoredUnpack.SkipRows += (ctx->Scissor.Y - py);
351 height -= (ctx->Scissor.Y - py);
352 py = ctx->Scissor.Y;
353 }
354 /* clip top */
355 if (py + height >= ctx->Scissor.Y + ctx->Scissor.Height) {
356 height -= (py + height - (ctx->Scissor.Y + ctx->Scissor.Height));
357 }
358
359 if (width <= 0 || height <= 0)
360 return;
361 }
362 else {
363 finalUnpack = unpack;
364 }
365
366 /* compute pixel value */
367 {
368 GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0f);
369 GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0f);
370 GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0f);
371 /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f); */
372 if (fxMesa->bgrOrder)
373 color = (FxU16)
374 (((FxU16) 0xf8 & b) << (11 - 3)) |
375 (((FxU16) 0xfc & g) << (5 - 3 + 1)) | (((FxU16) 0xf8 & r) >> 3);
376 else
377 color = (FxU16)
378 (((FxU16) 0xf8 & r) << (11 - 3)) |
379 (((FxU16) 0xfc & g) << (5 - 3 + 1)) | (((FxU16) 0xf8 & b) >> 3);
380 }
381
382 info.size = sizeof(info);
383 if (!FX_grLfbLock(GR_LFB_WRITE_ONLY,
384 fxMesa->currentFB,
385 GR_LFBWRITEMODE_565,
386 GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) {
387 #ifndef FX_SILENT
388 fprintf(stderr, "fx Driver: error locking the linear frame buffer\n");
389 #endif
390 return;
391 }
392
393 {
394 const GLint winX = 0;
395 const GLint winY = fxMesa->height - 1;
396 /* The dest stride depends on the hardware and whether we're drawing
397 * to the front or back buffer. This compile-time test seems to do
398 * the job for now.
399 */
400 const GLint dstStride = info.strideInBytes / 2; /* stride in GLushorts */
401
402 GLint row;
403 /* compute dest address of bottom-left pixel in bitmap */
404 GLushort *dst = (GLushort *) info.lfbPtr
405 + (winY - py) * dstStride + (winX + px);
406
407 for (row = 0; row < height; row++) {
408 const GLubyte *src =
409 (const GLubyte *) _mesa_image_address(finalUnpack,
410 bitmap, width, height,
411 GL_COLOR_INDEX, GL_BITMAP,
412 0, row, 0);
413 if (finalUnpack->LsbFirst) {
414 /* least significan bit first */
415 GLubyte mask = 1U << (finalUnpack->SkipPixels & 0x7);
416 GLint col;
417 for (col = 0; col < width; col++) {
418 if (*src & mask) {
419 dst[col] = color;
420 }
421 if (mask == 128U) {
422 src++;
423 mask = 1U;
424 }
425 else {
426 mask = mask << 1;
427 }
428 }
429 if (mask != 1)
430 src++;
431 }
432 else {
433 /* most significan bit first */
434 GLubyte mask = 128U >> (finalUnpack->SkipPixels & 0x7);
435 GLint col;
436 for (col = 0; col < width; col++) {
437 if (*src & mask) {
438 dst[col] = color;
439 }
440 if (mask == 1U) {
441 src++;
442 mask = 128U;
443 }
444 else {
445 mask = mask >> 1;
446 }
447 }
448 if (mask != 128)
449 src++;
450 }
451 dst -= dstStride;
452 }
453 }
454
455 FX_grLfbUnlock(GR_LFB_WRITE_ONLY, fxMesa->currentFB);
456 }
457
458
459 static void
460 fxDDReadPixels(GLcontext * ctx, GLint x, GLint y,
461 GLsizei width, GLsizei height,
462 GLenum format, GLenum type,
463 const struct gl_pixelstore_attrib *packing, GLvoid * dstImage)
464 {
465 if (ctx->_ImageTransferState) {
466 _swrast_ReadPixels(ctx, x, y, width, height, format, type,
467 packing, dstImage);
468 return;
469 }
470 else {
471 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
472 GrLfbInfo_t info;
473
474 BEGIN_BOARD_LOCK();
475 if (grLfbLock(GR_LFB_READ_ONLY,
476 fxMesa->currentFB,
477 GR_LFBWRITEMODE_ANY,
478 GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) {
479 const GLint winX = 0;
480 const GLint winY = fxMesa->height - 1;
481 const GLint srcStride = info.strideInBytes / 2; /* stride in GLushorts */
482 const GLushort *src = (const GLushort *) info.lfbPtr
483 + (winY - y) * srcStride + (winX + x);
484 GLubyte *dst = (GLubyte *) _mesa_image_address(packing, dstImage,
485 width, height, format,
486 type, 0, 0, 0);
487 GLint dstStride =
488 _mesa_image_row_stride(packing, width, format, type);
489
490 if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
491 /* convert 5R6G5B into 8R8G8B */
492 GLint row, col;
493 const GLint halfWidth = width >> 1;
494 const GLint extraPixel = (width & 1);
495 for (row = 0; row < height; row++) {
496 GLubyte *d = dst;
497 for (col = 0; col < halfWidth; col++) {
498 const GLuint pixel = ((const GLuint *) src)[col];
499 const GLint pixel0 = pixel & 0xffff;
500 const GLint pixel1 = pixel >> 16;
501 *d++ = FX_PixelToR[pixel0];
502 *d++ = FX_PixelToG[pixel0];
503 *d++ = FX_PixelToB[pixel0];
504 *d++ = FX_PixelToR[pixel1];
505 *d++ = FX_PixelToG[pixel1];
506 *d++ = FX_PixelToB[pixel1];
507 }
508 if (extraPixel) {
509 GLushort pixel = src[width - 1];
510 *d++ = FX_PixelToR[pixel];
511 *d++ = FX_PixelToG[pixel];
512 *d++ = FX_PixelToB[pixel];
513 }
514 dst += dstStride;
515 src -= srcStride;
516 }
517 }
518 else if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
519 /* convert 5R6G5B into 8R8G8B8A */
520 GLint row, col;
521 const GLint halfWidth = width >> 1;
522 const GLint extraPixel = (width & 1);
523 for (row = 0; row < height; row++) {
524 GLubyte *d = dst;
525 for (col = 0; col < halfWidth; col++) {
526 const GLuint pixel = ((const GLuint *) src)[col];
527 const GLint pixel0 = pixel & 0xffff;
528 const GLint pixel1 = pixel >> 16;
529 *d++ = FX_PixelToR[pixel0];
530 *d++ = FX_PixelToG[pixel0];
531 *d++ = FX_PixelToB[pixel0];
532 *d++ = 255;
533 *d++ = FX_PixelToR[pixel1];
534 *d++ = FX_PixelToG[pixel1];
535 *d++ = FX_PixelToB[pixel1];
536 *d++ = 255;
537 }
538 if (extraPixel) {
539 const GLushort pixel = src[width - 1];
540 *d++ = FX_PixelToR[pixel];
541 *d++ = FX_PixelToG[pixel];
542 *d++ = FX_PixelToB[pixel];
543 *d++ = 255;
544 }
545 dst += dstStride;
546 src -= srcStride;
547 }
548 }
549 else if (format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5) {
550 /* directly memcpy 5R6G5B pixels into client's buffer */
551 const GLint widthInBytes = width * 2;
552 GLint row;
553 for (row = 0; row < height; row++) {
554 MEMCPY(dst, src, widthInBytes);
555 dst += dstStride;
556 src -= srcStride;
557 }
558 }
559 else {
560 grLfbUnlock(GR_LFB_READ_ONLY, fxMesa->currentFB);
561 END_BOARD_LOCK();
562 _swrast_ReadPixels(ctx, x, y, width, height, format, type,
563 packing, dstImage);
564 return;
565 }
566
567 grLfbUnlock(GR_LFB_READ_ONLY, fxMesa->currentFB);
568 }
569 END_BOARD_LOCK();
570 }
571 }
572
573
574
575 static void
576 fxDDFinish(GLcontext * ctx)
577 {
578 FX_grFlush();
579 }
580
581
582
583
584
585 /* KW: Put the word Mesa in the render string because quakeworld
586 * checks for this rather than doing a glGet(GL_MAX_TEXTURE_SIZE).
587 * Why?
588 */
589 static const GLubyte *
590 fxDDGetString(GLcontext * ctx, GLenum name)
591 {
592 switch (name) {
593 case GL_RENDERER:
594 {
595 static char buf[80];
596
597 if (glbHWConfig.SSTs[glbCurrentBoard].type == GR_SSTTYPE_VOODOO) {
598 GrVoodooConfig_t *vc =
599 &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig;
600
601 sprintf(buf,
602 "Mesa Glide v0.30 Voodoo_Graphics %d "
603 "CARD/%d FB/%d TM/%d TMU/%s",
604 glbCurrentBoard,
605 (vc->sliDetect ? (vc->fbRam * 2) : vc->fbRam),
606 (vc->tmuConfig[GR_TMU0].tmuRam +
607 ((vc->nTexelfx > 1) ? vc->tmuConfig[GR_TMU1].
608 tmuRam : 0)), vc->nTexelfx,
609 (vc->sliDetect ? "SLI" : "NOSLI"));
610 }
611 else if (glbHWConfig.SSTs[glbCurrentBoard].type == GR_SSTTYPE_SST96) {
612 GrSst96Config_t *sc =
613 &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config;
614
615 sprintf(buf,
616 "Glide v0.30 Voodoo_Rush %d "
617 "CARD/%d FB/%d TM/%d TMU/NOSLI",
618 glbCurrentBoard,
619 sc->fbRam, sc->tmuConfig.tmuRam, sc->nTexelfx);
620 }
621 else {
622 strcpy(buf, "Glide v0.30 UNKNOWN");
623 }
624 return (GLubyte *) buf;
625 }
626 default:
627 return NULL;
628 }
629 }
630
631 static const struct gl_pipeline_stage *fx_pipeline[] = {
632 &_tnl_vertex_transform_stage, /* TODO: Add the fastpath here */
633 &_tnl_normal_transform_stage,
634 &_tnl_lighting_stage,
635 &_tnl_fog_coordinate_stage, /* TODO: Omit fog stage */
636 &_tnl_texgen_stage,
637 &_tnl_texture_transform_stage,
638 &_tnl_point_attenuation_stage,
639 &_tnl_render_stage,
640 0,
641 };
642
643
644
645
646 int
647 fxDDInitFxMesaContext(fxMesaContext fxMesa)
648 {
649 int i;
650
651 for (i = 0; i < 256; i++) {
652 gl_ubyte_to_float_255_color_tab[i] = (float) i;
653 }
654
655 FX_setupGrVertexLayout();
656
657 if (getenv("FX_EMULATE_SINGLE_TMU"))
658 fxMesa->haveTwoTMUs = GL_FALSE;
659
660 if (getenv("FX_GLIDE_SWAPINTERVAL"))
661 fxMesa->swapInterval = atoi(getenv("FX_GLIDE_SWAPINTERVAL"));
662 else
663 fxMesa->swapInterval = 1;
664
665 if (getenv("MESA_FX_SWAP_PENDING"))
666 fxMesa->maxPendingSwapBuffers = atoi(getenv("MESA_FX_SWAP_PENDING"));
667 else
668 fxMesa->maxPendingSwapBuffers = 2;
669
670 if (getenv("MESA_FX_INFO"))
671 fxMesa->verbose = GL_TRUE;
672 else
673 fxMesa->verbose = GL_FALSE;
674
675 fxMesa->color = 0xffffffff;
676 fxMesa->clearC = 0;
677 fxMesa->clearA = 0;
678
679 fxMesa->stats.swapBuffer = 0;
680 fxMesa->stats.reqTexUpload = 0;
681 fxMesa->stats.texUpload = 0;
682 fxMesa->stats.memTexUpload = 0;
683
684 fxMesa->tmuSrc = FX_TMU_NONE;
685 fxMesa->lastUnitsMode = FX_UM_NONE;
686 fxTMInit(fxMesa);
687
688 /* FX units setup */
689
690 fxMesa->unitsState.alphaTestEnabled = GL_FALSE;
691 fxMesa->unitsState.alphaTestFunc = GR_CMP_ALWAYS;
692 fxMesa->unitsState.alphaTestRefValue = 0;
693
694 fxMesa->unitsState.blendEnabled = GL_FALSE;
695 fxMesa->unitsState.blendSrcFuncRGB = GR_BLEND_ONE;
696 fxMesa->unitsState.blendDstFuncRGB = GR_BLEND_ZERO;
697 fxMesa->unitsState.blendSrcFuncAlpha = GR_BLEND_ONE;
698 fxMesa->unitsState.blendDstFuncAlpha = GR_BLEND_ZERO;
699
700 fxMesa->unitsState.depthTestEnabled = GL_FALSE;
701 fxMesa->unitsState.depthMask = GL_TRUE;
702 fxMesa->unitsState.depthTestFunc = GR_CMP_LESS;
703
704 FX_grColorMask(FXTRUE, fxMesa->haveAlphaBuffer ? FXTRUE : FXFALSE);
705 if (fxMesa->haveDoubleBuffer) {
706 fxMesa->currentFB = GR_BUFFER_BACKBUFFER;
707 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
708 }
709 else {
710 fxMesa->currentFB = GR_BUFFER_FRONTBUFFER;
711 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
712 }
713
714 fxMesa->state = malloc(FX_grGetInteger(FX_GLIDE_STATE_SIZE));
715 fxMesa->fogTable = malloc(FX_grGetInteger(FX_FOG_TABLE_ENTRIES) *
716 sizeof(GrFog_t));
717
718 if (!fxMesa->state || !fxMesa->fogTable) {
719 if (fxMesa->state)
720 free(fxMesa->state);
721 if (fxMesa->fogTable)
722 free(fxMesa->fogTable);
723 return 0;
724 }
725
726 if (fxMesa->haveZBuffer)
727 FX_grDepthBufferMode(GR_DEPTHBUFFER_ZBUFFER);
728
729 #ifndef FXMESA_USE_ARGB
730 FX_grLfbWriteColorFormat(GR_COLORFORMAT_ABGR); /* Not every Glide has this */
731 #endif
732
733 fxMesa->textureAlign = FX_grGetInteger(FX_TEXTURE_ALIGN);
734 fxMesa->glCtx->Const.MaxTextureLevels = 9;
735 fxMesa->glCtx->Const.MaxTextureUnits = fxMesa->haveTwoTMUs ? 2 : 1;
736 fxMesa->new_state = _NEW_ALL;
737
738 /* Initialize the software rasterizer and helper modules.
739 */
740 _swrast_CreateContext(fxMesa->glCtx);
741 _ac_CreateContext(fxMesa->glCtx);
742 _tnl_CreateContext(fxMesa->glCtx);
743 _swsetup_CreateContext(fxMesa->glCtx);
744
745 _tnl_destroy_pipeline(fxMesa->glCtx);
746 _tnl_install_pipeline(fxMesa->glCtx, fx_pipeline);
747
748 fxAllocVB(fxMesa->glCtx);
749
750 fxSetupDDPointers(fxMesa->glCtx);
751 fxDDInitTriFuncs(fxMesa->glCtx);
752
753 /* Tell the software rasterizer to use pixel fog always.
754 */
755 _swrast_allow_vertex_fog(fxMesa->glCtx, GL_FALSE);
756 _swrast_allow_pixel_fog(fxMesa->glCtx, GL_TRUE);
757
758 /* Tell tnl not to calculate or use vertex fog factors. (Needed to
759 * tell render stage not to clip fog coords).
760 */
761 /* _tnl_calculate_vertex_fog( fxMesa->glCtx, GL_FALSE ); */
762
763 fxDDInitExtensions(fxMesa->glCtx);
764
765 FX_grGlideGetState((GrState *) fxMesa->state);
766
767 return 1;
768 }
769
770 /* Undo the above.
771 */
772 void
773 fxDDDestroyFxMesaContext(fxMesaContext fxMesa)
774 {
775 _swsetup_DestroyContext(fxMesa->glCtx);
776 _tnl_DestroyContext(fxMesa->glCtx);
777 _ac_DestroyContext(fxMesa->glCtx);
778 _swrast_DestroyContext(fxMesa->glCtx);
779
780 if (fxMesa->state)
781 free(fxMesa->state);
782 if (fxMesa->fogTable)
783 free(fxMesa->fogTable);
784 fxTMClose(fxMesa);
785 fxFreeVB(fxMesa->glCtx);
786 }
787
788
789
790
791 void
792 fxDDInitExtensions(GLcontext * ctx)
793 {
794 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
795
796 _mesa_add_extension(ctx, GL_TRUE, "3DFX_set_global_palette", 0);
797 _mesa_enable_extension(ctx, "GL_EXT_point_parameters");
798 _mesa_enable_extension(ctx, "GL_EXT_paletted_texture");
799 _mesa_enable_extension(ctx, "GL_EXT_texture_lod_bias");
800 _mesa_enable_extension(ctx, "GL_EXT_shared_texture_palette");
801
802 if (fxMesa->haveTwoTMUs)
803 _mesa_enable_extension(ctx, "GL_EXT_texture_env_add");
804
805 if (fxMesa->haveTwoTMUs)
806 _mesa_enable_extension(ctx, "GL_ARB_multitexture");
807 }
808
809
810 /************************************************************************/
811 /************************************************************************/
812 /************************************************************************/
813
814 /* Check if the hardware supports the current context
815 *
816 * Performs similar work to fxDDChooseRenderState() - should be merged.
817 */
818 GLboolean
819 fx_check_IsInHardware(GLcontext * ctx)
820 {
821 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
822
823 if (ctx->RenderMode != GL_RENDER)
824 return GL_FALSE;
825
826 if (ctx->Stencil.Enabled ||
827 ctx->Color.MultiDrawBuffer ||
828 ((ctx->Color.BlendEnabled)
829 && (ctx->Color.BlendEquation != GL_FUNC_ADD_EXT))
830 || ((ctx->Color.ColorLogicOpEnabled)
831 && (ctx->Color.LogicOp != GL_COPY))
832 || (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
833 ||
834 (!((ctx->
835 Color.ColorMask[RCOMP] == ctx->Color.ColorMask[GCOMP])
836 && (ctx->Color.ColorMask[GCOMP] == ctx->Color.ColorMask[BCOMP])
837 && (ctx->Color.ColorMask[ACOMP] == ctx->Color.ColorMask[ACOMP])))
838 ) {
839 return GL_FALSE;
840 }
841 /* Unsupported texture/multitexture cases */
842
843 if (fxMesa->haveTwoTMUs) {
844 if (ctx->Texture._ReallyEnabled & (TEXTURE0_3D | TEXTURE1_3D))
845 return GL_FALSE; /* can't do 3D textures */
846 if (ctx->Texture._ReallyEnabled & (TEXTURE0_1D | TEXTURE1_1D))
847 return GL_FALSE; /* can't do 1D textures */
848
849 if (ctx->Texture._ReallyEnabled & TEXTURE0_2D) {
850 if (ctx->Texture.Unit[0].EnvMode == GL_BLEND &&
851 (ctx->Texture._ReallyEnabled & TEXTURE1_2D ||
852 ctx->Texture.Unit[0].EnvColor[0] != 0 ||
853 ctx->Texture.Unit[0].EnvColor[1] != 0 ||
854 ctx->Texture.Unit[0].EnvColor[2] != 0 ||
855 ctx->Texture.Unit[0].EnvColor[3] != 1)) {
856 return GL_FALSE;
857 }
858 if (ctx->Texture.Unit[0]._Current->Image[0]->Border > 0)
859 return GL_FALSE;
860 }
861
862 if (ctx->Texture._ReallyEnabled & TEXTURE1_2D) {
863 if (ctx->Texture.Unit[1].EnvMode == GL_BLEND)
864 return GL_FALSE;
865 if (ctx->Texture.Unit[1]._Current->Image[0]->Border > 0)
866 return GL_FALSE;
867 }
868
869 if (MESA_VERBOSE & (VERBOSE_DRIVER | VERBOSE_TEXTURE))
870 fprintf(stderr, "fxMesa: fxIsInHardware, envmode is %s/%s\n",
871 _mesa_lookup_enum_by_nr(ctx->Texture.Unit[0].EnvMode),
872 _mesa_lookup_enum_by_nr(ctx->Texture.Unit[1].EnvMode));
873
874 /* KW: This was wrong (I think) and I changed it... which doesn't mean
875 * it is now correct...
876 */
877 if ((ctx->Texture._ReallyEnabled & (TEXTURE0_1D | TEXTURE0_2D | TEXTURE0_3D)) &&
878 (ctx->Texture._ReallyEnabled & (TEXTURE1_1D | TEXTURE1_2D | TEXTURE1_3D))) {
879 /* Can't use multipass to blend a multitextured triangle - fall
880 * back to software.
881 */
882 if (!fxMesa->haveTwoTMUs && ctx->Color.BlendEnabled) {
883 return GL_FALSE;
884 }
885
886 if ((ctx->Texture.Unit[0].EnvMode != ctx->Texture.Unit[1].EnvMode) &&
887 (ctx->Texture.Unit[0].EnvMode != GL_MODULATE) &&
888 (ctx->Texture.Unit[0].EnvMode != GL_REPLACE)) { /* q2, seems ok... */
889 if (MESA_VERBOSE & VERBOSE_DRIVER)
890 fprintf(stderr, "fxMesa: unsupported multitex env mode\n");
891 return GL_FALSE;
892 }
893 }
894 }
895 else {
896 if ((ctx->Texture._ReallyEnabled & (TEXTURE1_1D | TEXTURE1_2D | TEXTURE1_3D)) ||
897 /* Not very well written ... */
898 ((ctx->Texture._ReallyEnabled & TEXTURE0_1D) &&
899 (!(ctx->Texture._ReallyEnabled & TEXTURE0_2D)))
900 ) {
901 return GL_FALSE;
902 }
903
904
905 if ((ctx->Texture._ReallyEnabled & TEXTURE0_2D) &&
906 (ctx->Texture.Unit[0].EnvMode == GL_BLEND)) {
907 return GL_FALSE;
908 }
909 }
910
911 return GL_TRUE;
912 }
913
914
915
916 static void
917 update_texture_scales(GLcontext * ctx)
918 {
919 fxMesaContext fxMesa = FX_CONTEXT(ctx);
920 struct gl_texture_unit *t0 = &ctx->Texture.Unit[fxMesa->tmu_source[0]];
921 struct gl_texture_unit *t1 = &ctx->Texture.Unit[fxMesa->tmu_source[1]];
922
923 if (t0 && t0->_Current && FX_TEXTURE_DATA(t0)) {
924 fxMesa->s0scale = FX_TEXTURE_DATA(t0)->sScale;
925 fxMesa->t0scale = FX_TEXTURE_DATA(t0)->tScale;
926 fxMesa->inv_s0scale = 1.0 / fxMesa->s0scale;
927 fxMesa->inv_t0scale = 1.0 / fxMesa->t0scale;
928 }
929
930 if (t1 && t1->_Current && FX_TEXTURE_DATA(t1)) {
931 fxMesa->s1scale = FX_TEXTURE_DATA(t1)->sScale;
932 fxMesa->t1scale = FX_TEXTURE_DATA(t1)->tScale;
933 fxMesa->inv_s1scale = 1.0 / fxMesa->s1scale;
934 fxMesa->inv_t1scale = 1.0 / fxMesa->t1scale;
935 }
936 }
937
938 static void
939 fxDDUpdateDDPointers(GLcontext * ctx, GLuint new_state)
940 {
941 /* TNLcontext *tnl = TNL_CONTEXT(ctx);*/
942 fxMesaContext fxMesa = FX_CONTEXT(ctx);
943
944 _swrast_InvalidateState(ctx, new_state);
945 _ac_InvalidateState(ctx, new_state);
946 _tnl_InvalidateState(ctx, new_state);
947 _swsetup_InvalidateState(ctx, new_state);
948
949 /* Recalculate fog table on projection matrix changes. This used to
950 * be triggered by the NearFar callback.
951 */
952 if (new_state & _NEW_PROJECTION)
953 fxMesa->new_state |= FX_NEW_FOG;
954
955 if (new_state & (_FX_NEW_IS_IN_HARDWARE |
956 _FX_NEW_RENDERSTATE |
957 _FX_NEW_SETUP_FUNCTION |
958 _NEW_TEXTURE)) {
959
960 if (new_state & _FX_NEW_IS_IN_HARDWARE)
961 fxCheckIsInHardware(ctx);
962
963 if (fxMesa->new_state)
964 fxSetupFXUnits(ctx);
965
966 if (fxMesa->is_in_hardware) {
967 if (new_state & _FX_NEW_RENDERSTATE)
968 fxDDChooseRenderState(ctx);
969
970 if (new_state & _FX_NEW_SETUP_FUNCTION)
971 fxChooseVertexState(ctx);
972 }
973
974 if (new_state & _NEW_TEXTURE)
975 update_texture_scales(ctx);
976 }
977 }
978
979
980
981
982 void
983 fxSetupDDPointers(GLcontext * ctx)
984 {
985 TNLcontext *tnl = TNL_CONTEXT(ctx);
986
987 if (MESA_VERBOSE & VERBOSE_DRIVER) {
988 fprintf(stderr, "fxmesa: fxSetupDDPointers()\n");
989 }
990
991 ctx->Driver.UpdateState = fxDDUpdateDDPointers;
992 ctx->Driver.GetString = fxDDGetString;
993 ctx->Driver.ClearIndex = NULL;
994 ctx->Driver.ClearColor = fxDDClearColor;
995 ctx->Driver.Clear = fxDDClear;
996 ctx->Driver.SetDrawBuffer = fxDDSetDrawBuffer;
997 ctx->Driver.GetBufferSize = fxDDBufferSize;
998 ctx->Driver.Accum = _swrast_Accum;
999 ctx->Driver.Bitmap = fxDDDrawBitmap;
1000 ctx->Driver.CopyPixels = _swrast_CopyPixels;
1001 ctx->Driver.DrawPixels = _swrast_DrawPixels;
1002 ctx->Driver.ReadPixels = fxDDReadPixels;
1003 ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
1004 ctx->Driver.Finish = fxDDFinish;
1005 ctx->Driver.Flush = NULL;
1006 ctx->Driver.ChooseTextureFormat = fxDDChooseTextureFormat;
1007 ctx->Driver.TexImage1D = _mesa_store_teximage1d;
1008 ctx->Driver.TexImage2D = fxDDTexImage2D;
1009 ctx->Driver.TexImage3D = _mesa_store_teximage3d;
1010 ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
1011 ctx->Driver.TexSubImage2D = fxDDTexSubImage2D;
1012 ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
1013 ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
1014 ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
1015 ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
1016 ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
1017 ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
1018 ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
1019 ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
1020 ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
1021 ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
1022 ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
1023 ctx->Driver.TexEnv = fxDDTexEnv;
1024 ctx->Driver.TexParameter = fxDDTexParam;
1025 ctx->Driver.BindTexture = fxDDTexBind;
1026 ctx->Driver.DeleteTexture = fxDDTexDel;
1027 ctx->Driver.UpdateTexturePalette = fxDDTexPalette;
1028 ctx->Driver.AlphaFunc = fxDDAlphaFunc;
1029 ctx->Driver.BlendFunc = fxDDBlendFunc;
1030 ctx->Driver.DepthFunc = fxDDDepthFunc;
1031 ctx->Driver.DepthMask = fxDDDepthMask;
1032 ctx->Driver.ColorMask = fxDDColorMask;
1033 ctx->Driver.Fogfv = fxDDFogfv;
1034 ctx->Driver.Scissor = fxDDScissor;
1035 ctx->Driver.FrontFace = fxDDFrontFace;
1036 ctx->Driver.CullFace = fxDDCullFace;
1037 ctx->Driver.ShadeModel = fxDDShadeModel;
1038 ctx->Driver.Enable = fxDDEnable;
1039
1040 tnl->Driver.RunPipeline = _tnl_run_pipeline;
1041
1042 fxSetupDDSpanPointers(ctx);
1043 fxDDUpdateDDPointers(ctx, ~0);
1044 }
1045
1046
1047 #else
1048
1049
1050 /*
1051 * Need this to provide at least one external definition.
1052 */
1053
1054 extern int gl_fx_dummy_function_dd(void);
1055 int
1056 gl_fx_dummy_function_dd(void)
1057 {
1058 return 0;
1059 }
1060
1061 #endif /* FX */