new texture compression infrastructure
[mesa.git] / src / mesa / drivers / glide / fxdd.c
1 /* $Id: fxdd.c,v 1.91 2002/09/27 02:45:38 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 /* update s/w fallback state */
293 _swrast_DrawBuffer(ctx, mode);
294 }
295
296
297
298
299
300 static void
301 fxDDDrawBitmap(GLcontext * ctx, GLint px, GLint py,
302 GLsizei width, GLsizei height,
303 const struct gl_pixelstore_attrib *unpack,
304 const GLubyte * bitmap)
305 {
306 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
307 GrLfbInfo_t info;
308 FxU16 color;
309 const struct gl_pixelstore_attrib *finalUnpack;
310 struct gl_pixelstore_attrib scissoredUnpack;
311
312 /* check if there's any raster operations enabled which we can't handle */
313 if (ctx->Color.AlphaEnabled ||
314 ctx->Color.BlendEnabled ||
315 ctx->Depth.Test ||
316 ctx->Fog.Enabled ||
317 ctx->Color.ColorLogicOpEnabled ||
318 ctx->Stencil.Enabled ||
319 ctx->Scissor.Enabled ||
320 (ctx->DrawBuffer->UseSoftwareAlphaBuffers &&
321 ctx->Color.ColorMask[ACOMP]) ||
322 (ctx->Color._DrawDestMask != FRONT_LEFT_BIT &&
323 ctx->Color._DrawDestMask != BACK_LEFT_BIT)) {
324 _swrast_Bitmap(ctx, px, py, width, height, unpack, bitmap);
325 return;
326 }
327
328
329 if (ctx->Scissor.Enabled) {
330 /* This is a bit tricky, but by carefully adjusting the px, py,
331 * width, height, skipPixels and skipRows values we can do
332 * scissoring without special code in the rendering loop.
333 *
334 * KW: This code is never reached, see the test above.
335 */
336
337 /* we'll construct a new pixelstore struct */
338 finalUnpack = &scissoredUnpack;
339 scissoredUnpack = *unpack;
340 if (scissoredUnpack.RowLength == 0)
341 scissoredUnpack.RowLength = width;
342
343 /* clip left */
344 if (px < ctx->Scissor.X) {
345 scissoredUnpack.SkipPixels += (ctx->Scissor.X - px);
346 width -= (ctx->Scissor.X - px);
347 px = ctx->Scissor.X;
348 }
349 /* clip right */
350 if (px + width >= ctx->Scissor.X + ctx->Scissor.Width) {
351 width -= (px + width - (ctx->Scissor.X + ctx->Scissor.Width));
352 }
353 /* clip bottom */
354 if (py < ctx->Scissor.Y) {
355 scissoredUnpack.SkipRows += (ctx->Scissor.Y - py);
356 height -= (ctx->Scissor.Y - py);
357 py = ctx->Scissor.Y;
358 }
359 /* clip top */
360 if (py + height >= ctx->Scissor.Y + ctx->Scissor.Height) {
361 height -= (py + height - (ctx->Scissor.Y + ctx->Scissor.Height));
362 }
363
364 if (width <= 0 || height <= 0)
365 return;
366 }
367 else {
368 finalUnpack = unpack;
369 }
370
371 /* compute pixel value */
372 {
373 GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0f);
374 GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0f);
375 GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0f);
376 /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f); */
377 if (fxMesa->bgrOrder)
378 color = (FxU16)
379 (((FxU16) 0xf8 & b) << (11 - 3)) |
380 (((FxU16) 0xfc & g) << (5 - 3 + 1)) | (((FxU16) 0xf8 & r) >> 3);
381 else
382 color = (FxU16)
383 (((FxU16) 0xf8 & r) << (11 - 3)) |
384 (((FxU16) 0xfc & g) << (5 - 3 + 1)) | (((FxU16) 0xf8 & b) >> 3);
385 }
386
387 info.size = sizeof(info);
388 if (!FX_grLfbLock(GR_LFB_WRITE_ONLY,
389 fxMesa->currentFB,
390 GR_LFBWRITEMODE_565,
391 GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) {
392 #ifndef FX_SILENT
393 fprintf(stderr, "fx Driver: error locking the linear frame buffer\n");
394 #endif
395 return;
396 }
397
398 {
399 const GLint winX = 0;
400 const GLint winY = fxMesa->height - 1;
401 /* The dest stride depends on the hardware and whether we're drawing
402 * to the front or back buffer. This compile-time test seems to do
403 * the job for now.
404 */
405 const GLint dstStride = info.strideInBytes / 2; /* stride in GLushorts */
406
407 GLint row;
408 /* compute dest address of bottom-left pixel in bitmap */
409 GLushort *dst = (GLushort *) info.lfbPtr
410 + (winY - py) * dstStride + (winX + px);
411
412 for (row = 0; row < height; row++) {
413 const GLubyte *src =
414 (const GLubyte *) _mesa_image_address(finalUnpack,
415 bitmap, width, height,
416 GL_COLOR_INDEX, GL_BITMAP,
417 0, row, 0);
418 if (finalUnpack->LsbFirst) {
419 /* least significan bit first */
420 GLubyte mask = 1U << (finalUnpack->SkipPixels & 0x7);
421 GLint col;
422 for (col = 0; col < width; col++) {
423 if (*src & mask) {
424 dst[col] = color;
425 }
426 if (mask == 128U) {
427 src++;
428 mask = 1U;
429 }
430 else {
431 mask = mask << 1;
432 }
433 }
434 if (mask != 1)
435 src++;
436 }
437 else {
438 /* most significan bit first */
439 GLubyte mask = 128U >> (finalUnpack->SkipPixels & 0x7);
440 GLint col;
441 for (col = 0; col < width; col++) {
442 if (*src & mask) {
443 dst[col] = color;
444 }
445 if (mask == 1U) {
446 src++;
447 mask = 128U;
448 }
449 else {
450 mask = mask >> 1;
451 }
452 }
453 if (mask != 128)
454 src++;
455 }
456 dst -= dstStride;
457 }
458 }
459
460 FX_grLfbUnlock(GR_LFB_WRITE_ONLY, fxMesa->currentFB);
461 }
462
463
464 static void
465 fxDDReadPixels(GLcontext * ctx, GLint x, GLint y,
466 GLsizei width, GLsizei height,
467 GLenum format, GLenum type,
468 const struct gl_pixelstore_attrib *packing, GLvoid * dstImage)
469 {
470 if (ctx->_ImageTransferState) {
471 _swrast_ReadPixels(ctx, x, y, width, height, format, type,
472 packing, dstImage);
473 return;
474 }
475 else {
476 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
477 GrLfbInfo_t info;
478
479 BEGIN_BOARD_LOCK();
480 if (grLfbLock(GR_LFB_READ_ONLY,
481 fxMesa->currentFB,
482 GR_LFBWRITEMODE_ANY,
483 GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) {
484 const GLint winX = 0;
485 const GLint winY = fxMesa->height - 1;
486 const GLint srcStride = info.strideInBytes / 2; /* stride in GLushorts */
487 const GLushort *src = (const GLushort *) info.lfbPtr
488 + (winY - y) * srcStride + (winX + x);
489 GLubyte *dst = (GLubyte *) _mesa_image_address(packing, dstImage,
490 width, height, format,
491 type, 0, 0, 0);
492 GLint dstStride =
493 _mesa_image_row_stride(packing, width, format, type);
494
495 if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
496 /* convert 5R6G5B into 8R8G8B */
497 GLint row, col;
498 const GLint halfWidth = width >> 1;
499 const GLint extraPixel = (width & 1);
500 for (row = 0; row < height; row++) {
501 GLubyte *d = dst;
502 for (col = 0; col < halfWidth; col++) {
503 const GLuint pixel = ((const GLuint *) src)[col];
504 const GLint pixel0 = pixel & 0xffff;
505 const GLint pixel1 = pixel >> 16;
506 *d++ = FX_PixelToR[pixel0];
507 *d++ = FX_PixelToG[pixel0];
508 *d++ = FX_PixelToB[pixel0];
509 *d++ = FX_PixelToR[pixel1];
510 *d++ = FX_PixelToG[pixel1];
511 *d++ = FX_PixelToB[pixel1];
512 }
513 if (extraPixel) {
514 GLushort pixel = src[width - 1];
515 *d++ = FX_PixelToR[pixel];
516 *d++ = FX_PixelToG[pixel];
517 *d++ = FX_PixelToB[pixel];
518 }
519 dst += dstStride;
520 src -= srcStride;
521 }
522 }
523 else if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
524 /* convert 5R6G5B into 8R8G8B8A */
525 GLint row, col;
526 const GLint halfWidth = width >> 1;
527 const GLint extraPixel = (width & 1);
528 for (row = 0; row < height; row++) {
529 GLubyte *d = dst;
530 for (col = 0; col < halfWidth; col++) {
531 const GLuint pixel = ((const GLuint *) src)[col];
532 const GLint pixel0 = pixel & 0xffff;
533 const GLint pixel1 = pixel >> 16;
534 *d++ = FX_PixelToR[pixel0];
535 *d++ = FX_PixelToG[pixel0];
536 *d++ = FX_PixelToB[pixel0];
537 *d++ = 255;
538 *d++ = FX_PixelToR[pixel1];
539 *d++ = FX_PixelToG[pixel1];
540 *d++ = FX_PixelToB[pixel1];
541 *d++ = 255;
542 }
543 if (extraPixel) {
544 const GLushort pixel = src[width - 1];
545 *d++ = FX_PixelToR[pixel];
546 *d++ = FX_PixelToG[pixel];
547 *d++ = FX_PixelToB[pixel];
548 *d++ = 255;
549 }
550 dst += dstStride;
551 src -= srcStride;
552 }
553 }
554 else if (format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5) {
555 /* directly memcpy 5R6G5B pixels into client's buffer */
556 const GLint widthInBytes = width * 2;
557 GLint row;
558 for (row = 0; row < height; row++) {
559 MEMCPY(dst, src, widthInBytes);
560 dst += dstStride;
561 src -= srcStride;
562 }
563 }
564 else {
565 grLfbUnlock(GR_LFB_READ_ONLY, fxMesa->currentFB);
566 END_BOARD_LOCK();
567 _swrast_ReadPixels(ctx, x, y, width, height, format, type,
568 packing, dstImage);
569 return;
570 }
571
572 grLfbUnlock(GR_LFB_READ_ONLY, fxMesa->currentFB);
573 }
574 END_BOARD_LOCK();
575 }
576 }
577
578
579
580 static void
581 fxDDFinish(GLcontext * ctx)
582 {
583 FX_grFlush();
584 }
585
586
587
588
589
590 /* KW: Put the word Mesa in the render string because quakeworld
591 * checks for this rather than doing a glGet(GL_MAX_TEXTURE_SIZE).
592 * Why?
593 */
594 static const GLubyte *
595 fxDDGetString(GLcontext * ctx, GLenum name)
596 {
597 switch (name) {
598 case GL_RENDERER:
599 {
600 static char buf[80];
601
602 if (glbHWConfig.SSTs[glbCurrentBoard].type == GR_SSTTYPE_VOODOO) {
603 GrVoodooConfig_t *vc =
604 &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig;
605
606 sprintf(buf,
607 "Mesa Glide v0.30 Voodoo_Graphics %d "
608 "CARD/%d FB/%d TM/%d TMU/%s",
609 glbCurrentBoard,
610 (vc->sliDetect ? (vc->fbRam * 2) : vc->fbRam),
611 (vc->tmuConfig[GR_TMU0].tmuRam +
612 ((vc->nTexelfx > 1) ? vc->tmuConfig[GR_TMU1].
613 tmuRam : 0)), vc->nTexelfx,
614 (vc->sliDetect ? "SLI" : "NOSLI"));
615 }
616 else if (glbHWConfig.SSTs[glbCurrentBoard].type == GR_SSTTYPE_SST96) {
617 GrSst96Config_t *sc =
618 &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config;
619
620 sprintf(buf,
621 "Glide v0.30 Voodoo_Rush %d "
622 "CARD/%d FB/%d TM/%d TMU/NOSLI",
623 glbCurrentBoard,
624 sc->fbRam, sc->tmuConfig.tmuRam, sc->nTexelfx);
625 }
626 else {
627 strcpy(buf, "Glide v0.30 UNKNOWN");
628 }
629 return (GLubyte *) buf;
630 }
631 default:
632 return NULL;
633 }
634 }
635
636 static const struct gl_pipeline_stage *fx_pipeline[] = {
637 &_tnl_vertex_transform_stage, /* TODO: Add the fastpath here */
638 &_tnl_normal_transform_stage,
639 &_tnl_lighting_stage,
640 &_tnl_fog_coordinate_stage, /* TODO: Omit fog stage */
641 &_tnl_texgen_stage,
642 &_tnl_texture_transform_stage,
643 &_tnl_point_attenuation_stage,
644 &_tnl_render_stage,
645 0,
646 };
647
648
649
650
651 int
652 fxDDInitFxMesaContext(fxMesaContext fxMesa)
653 {
654 int i;
655
656 for (i = 0; i < 256; i++) {
657 gl_ubyte_to_float_255_color_tab[i] = (float) i;
658 }
659
660 FX_setupGrVertexLayout();
661
662 if (getenv("FX_EMULATE_SINGLE_TMU"))
663 fxMesa->haveTwoTMUs = GL_FALSE;
664
665 if (getenv("FX_GLIDE_SWAPINTERVAL"))
666 fxMesa->swapInterval = atoi(getenv("FX_GLIDE_SWAPINTERVAL"));
667 else
668 fxMesa->swapInterval = 1;
669
670 if (getenv("MESA_FX_SWAP_PENDING"))
671 fxMesa->maxPendingSwapBuffers = atoi(getenv("MESA_FX_SWAP_PENDING"));
672 else
673 fxMesa->maxPendingSwapBuffers = 2;
674
675 if (getenv("MESA_FX_INFO"))
676 fxMesa->verbose = GL_TRUE;
677 else
678 fxMesa->verbose = GL_FALSE;
679
680 fxMesa->color = 0xffffffff;
681 fxMesa->clearC = 0;
682 fxMesa->clearA = 0;
683
684 fxMesa->stats.swapBuffer = 0;
685 fxMesa->stats.reqTexUpload = 0;
686 fxMesa->stats.texUpload = 0;
687 fxMesa->stats.memTexUpload = 0;
688
689 fxMesa->tmuSrc = FX_TMU_NONE;
690 fxMesa->lastUnitsMode = FX_UM_NONE;
691 fxTMInit(fxMesa);
692
693 /* FX units setup */
694
695 fxMesa->unitsState.alphaTestEnabled = GL_FALSE;
696 fxMesa->unitsState.alphaTestFunc = GR_CMP_ALWAYS;
697 fxMesa->unitsState.alphaTestRefValue = 0;
698
699 fxMesa->unitsState.blendEnabled = GL_FALSE;
700 fxMesa->unitsState.blendSrcFuncRGB = GR_BLEND_ONE;
701 fxMesa->unitsState.blendDstFuncRGB = GR_BLEND_ZERO;
702 fxMesa->unitsState.blendSrcFuncAlpha = GR_BLEND_ONE;
703 fxMesa->unitsState.blendDstFuncAlpha = GR_BLEND_ZERO;
704
705 fxMesa->unitsState.depthTestEnabled = GL_FALSE;
706 fxMesa->unitsState.depthMask = GL_TRUE;
707 fxMesa->unitsState.depthTestFunc = GR_CMP_LESS;
708
709 FX_grColorMask(FXTRUE, fxMesa->haveAlphaBuffer ? FXTRUE : FXFALSE);
710 if (fxMesa->haveDoubleBuffer) {
711 fxMesa->currentFB = GR_BUFFER_BACKBUFFER;
712 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
713 }
714 else {
715 fxMesa->currentFB = GR_BUFFER_FRONTBUFFER;
716 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
717 }
718
719 fxMesa->state = malloc(FX_grGetInteger(FX_GLIDE_STATE_SIZE));
720 fxMesa->fogTable = malloc(FX_grGetInteger(FX_FOG_TABLE_ENTRIES) *
721 sizeof(GrFog_t));
722
723 if (!fxMesa->state || !fxMesa->fogTable) {
724 if (fxMesa->state)
725 free(fxMesa->state);
726 if (fxMesa->fogTable)
727 free(fxMesa->fogTable);
728 return 0;
729 }
730
731 if (fxMesa->haveZBuffer)
732 FX_grDepthBufferMode(GR_DEPTHBUFFER_ZBUFFER);
733
734 #ifndef FXMESA_USE_ARGB
735 FX_grLfbWriteColorFormat(GR_COLORFORMAT_ABGR); /* Not every Glide has this */
736 #endif
737
738 fxMesa->textureAlign = FX_grGetInteger(FX_TEXTURE_ALIGN);
739 fxMesa->glCtx->Const.MaxTextureLevels = 9;
740 fxMesa->glCtx->Const.MaxTextureUnits = fxMesa->haveTwoTMUs ? 2 : 1;
741 fxMesa->new_state = _NEW_ALL;
742
743 /* Initialize the software rasterizer and helper modules.
744 */
745 _swrast_CreateContext(fxMesa->glCtx);
746 _ac_CreateContext(fxMesa->glCtx);
747 _tnl_CreateContext(fxMesa->glCtx);
748 _swsetup_CreateContext(fxMesa->glCtx);
749
750 _tnl_destroy_pipeline(fxMesa->glCtx);
751 _tnl_install_pipeline(fxMesa->glCtx, fx_pipeline);
752
753 fxAllocVB(fxMesa->glCtx);
754
755 fxSetupDDPointers(fxMesa->glCtx);
756 fxDDInitTriFuncs(fxMesa->glCtx);
757
758 /* Tell the software rasterizer to use pixel fog always.
759 */
760 _swrast_allow_vertex_fog(fxMesa->glCtx, GL_FALSE);
761 _swrast_allow_pixel_fog(fxMesa->glCtx, GL_TRUE);
762
763 /* Tell tnl not to calculate or use vertex fog factors. (Needed to
764 * tell render stage not to clip fog coords).
765 */
766 /* _tnl_calculate_vertex_fog( fxMesa->glCtx, GL_FALSE ); */
767
768 fxDDInitExtensions(fxMesa->glCtx);
769
770 FX_grGlideGetState((GrState *) fxMesa->state);
771
772 return 1;
773 }
774
775 /* Undo the above.
776 */
777 void
778 fxDDDestroyFxMesaContext(fxMesaContext fxMesa)
779 {
780 _swsetup_DestroyContext(fxMesa->glCtx);
781 _tnl_DestroyContext(fxMesa->glCtx);
782 _ac_DestroyContext(fxMesa->glCtx);
783 _swrast_DestroyContext(fxMesa->glCtx);
784
785 if (fxMesa->state)
786 free(fxMesa->state);
787 if (fxMesa->fogTable)
788 free(fxMesa->fogTable);
789 fxTMClose(fxMesa);
790 fxFreeVB(fxMesa->glCtx);
791 }
792
793
794
795
796 void
797 fxDDInitExtensions(GLcontext * ctx)
798 {
799 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
800
801 _mesa_add_extension(ctx, GL_TRUE, "3DFX_set_global_palette", 0);
802 _mesa_enable_extension(ctx, "GL_EXT_point_parameters");
803 _mesa_enable_extension(ctx, "GL_EXT_paletted_texture");
804 _mesa_enable_extension(ctx, "GL_EXT_texture_lod_bias");
805 _mesa_enable_extension(ctx, "GL_EXT_shared_texture_palette");
806
807 if (fxMesa->haveTwoTMUs)
808 _mesa_enable_extension(ctx, "GL_EXT_texture_env_add");
809
810 if (fxMesa->haveTwoTMUs)
811 _mesa_enable_extension(ctx, "GL_ARB_multitexture");
812 }
813
814
815 /************************************************************************/
816 /************************************************************************/
817 /************************************************************************/
818
819 /* Check if the hardware supports the current context
820 *
821 * Performs similar work to fxDDChooseRenderState() - should be merged.
822 */
823 GLboolean
824 fx_check_IsInHardware(GLcontext * ctx)
825 {
826 fxMesaContext fxMesa = (fxMesaContext) ctx->DriverCtx;
827
828 if (ctx->RenderMode != GL_RENDER)
829 return GL_FALSE;
830
831 if (ctx->Stencil.Enabled ||
832 (ctx->Color._DrawDestMask != FRONT_LEFT_BIT &&
833 ctx->Color._DrawDestMask != BACK_LEFT_BIT) ||
834 ((ctx->Color.BlendEnabled)
835 && (ctx->Color.BlendEquation != GL_FUNC_ADD_EXT))
836 || ((ctx->Color.ColorLogicOpEnabled)
837 && (ctx->Color.LogicOp != GL_COPY))
838 || (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
839 ||
840 (!((ctx->
841 Color.ColorMask[RCOMP] == ctx->Color.ColorMask[GCOMP])
842 && (ctx->Color.ColorMask[GCOMP] == ctx->Color.ColorMask[BCOMP])
843 && (ctx->Color.ColorMask[ACOMP] == ctx->Color.ColorMask[ACOMP])))
844 ) {
845 return GL_FALSE;
846 }
847 /* Unsupported texture/multitexture cases */
848
849 if (fxMesa->haveTwoTMUs) {
850 /* we can only do 2D textures */
851 if (ctx->Texture.Unit[0]._ReallyEnabled & ~TEXTURE_2D_BIT)
852 return GL_FALSE;
853 if (ctx->Texture.Unit[1]._ReallyEnabled & ~TEXTURE_2D_BIT)
854 return GL_FALSE;
855
856 if (ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) {
857 if (ctx->Texture.Unit[0].EnvMode == GL_BLEND &&
858 (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT ||
859 ctx->Texture.Unit[0].EnvColor[0] != 0 ||
860 ctx->Texture.Unit[0].EnvColor[1] != 0 ||
861 ctx->Texture.Unit[0].EnvColor[2] != 0 ||
862 ctx->Texture.Unit[0].EnvColor[3] != 1)) {
863 return GL_FALSE;
864 }
865 if (ctx->Texture.Unit[0]._Current->Image[0]->Border > 0)
866 return GL_FALSE;
867 }
868
869 if (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT) {
870 if (ctx->Texture.Unit[1].EnvMode == GL_BLEND)
871 return GL_FALSE;
872 if (ctx->Texture.Unit[1]._Current->Image[0]->Border > 0)
873 return GL_FALSE;
874 }
875
876 if (MESA_VERBOSE & (VERBOSE_DRIVER | VERBOSE_TEXTURE))
877 fprintf(stderr, "fxMesa: fxIsInHardware, envmode is %s/%s\n",
878 _mesa_lookup_enum_by_nr(ctx->Texture.Unit[0].EnvMode),
879 _mesa_lookup_enum_by_nr(ctx->Texture.Unit[1].EnvMode));
880
881 /* KW: This was wrong (I think) and I changed it... which doesn't mean
882 * it is now correct...
883 * BP: The old condition just seemed to test if both texture units
884 * were enabled. That's easy!
885 */
886 if (ctx->Texture._EnabledUnits == 0x3) {
887 /* Can't use multipass to blend a multitextured triangle - fall
888 * back to software.
889 */
890 if (!fxMesa->haveTwoTMUs && ctx->Color.BlendEnabled) {
891 return GL_FALSE;
892 }
893
894 if ((ctx->Texture.Unit[0].EnvMode != ctx->Texture.Unit[1].EnvMode) &&
895 (ctx->Texture.Unit[0].EnvMode != GL_MODULATE) &&
896 (ctx->Texture.Unit[0].EnvMode != GL_REPLACE)) { /* q2, seems ok... */
897 if (MESA_VERBOSE & VERBOSE_DRIVER)
898 fprintf(stderr, "fxMesa: unsupported multitex env mode\n");
899 return GL_FALSE;
900 }
901 }
902 }
903 else {
904 /* we have just one texture unit */
905 if (ctx->Texture._EnabledUnits > 0x1) {
906 return GL_FALSE;
907 }
908
909 if ((ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) &&
910 (ctx->Texture.Unit[0].EnvMode == GL_BLEND)) {
911 return GL_FALSE;
912 }
913 }
914
915 return GL_TRUE;
916 }
917
918
919
920 static void
921 update_texture_scales(GLcontext * ctx)
922 {
923 fxMesaContext fxMesa = FX_CONTEXT(ctx);
924 struct gl_texture_unit *t0 = &ctx->Texture.Unit[fxMesa->tmu_source[0]];
925 struct gl_texture_unit *t1 = &ctx->Texture.Unit[fxMesa->tmu_source[1]];
926
927 if (t0 && t0->_Current && FX_TEXTURE_DATA(t0)) {
928 fxMesa->s0scale = FX_TEXTURE_DATA(t0)->sScale;
929 fxMesa->t0scale = FX_TEXTURE_DATA(t0)->tScale;
930 fxMesa->inv_s0scale = 1.0 / fxMesa->s0scale;
931 fxMesa->inv_t0scale = 1.0 / fxMesa->t0scale;
932 }
933
934 if (t1 && t1->_Current && FX_TEXTURE_DATA(t1)) {
935 fxMesa->s1scale = FX_TEXTURE_DATA(t1)->sScale;
936 fxMesa->t1scale = FX_TEXTURE_DATA(t1)->tScale;
937 fxMesa->inv_s1scale = 1.0 / fxMesa->s1scale;
938 fxMesa->inv_t1scale = 1.0 / fxMesa->t1scale;
939 }
940 }
941
942 static void
943 fxDDUpdateDDPointers(GLcontext * ctx, GLuint new_state)
944 {
945 /* TNLcontext *tnl = TNL_CONTEXT(ctx);*/
946 fxMesaContext fxMesa = FX_CONTEXT(ctx);
947
948 _swrast_InvalidateState(ctx, new_state);
949 _ac_InvalidateState(ctx, new_state);
950 _tnl_InvalidateState(ctx, new_state);
951 _swsetup_InvalidateState(ctx, new_state);
952
953 /* Recalculate fog table on projection matrix changes. This used to
954 * be triggered by the NearFar callback.
955 */
956 if (new_state & _NEW_PROJECTION)
957 fxMesa->new_state |= FX_NEW_FOG;
958
959 if (new_state & (_FX_NEW_IS_IN_HARDWARE |
960 _FX_NEW_RENDERSTATE |
961 _FX_NEW_SETUP_FUNCTION |
962 _NEW_TEXTURE)) {
963
964 if (new_state & _FX_NEW_IS_IN_HARDWARE)
965 fxCheckIsInHardware(ctx);
966
967 if (fxMesa->new_state)
968 fxSetupFXUnits(ctx);
969
970 if (fxMesa->is_in_hardware) {
971 if (new_state & _FX_NEW_RENDERSTATE)
972 fxDDChooseRenderState(ctx);
973
974 if (new_state & _FX_NEW_SETUP_FUNCTION)
975 fxChooseVertexState(ctx);
976 }
977
978 if (new_state & _NEW_TEXTURE)
979 update_texture_scales(ctx);
980 }
981 }
982
983
984
985
986 void
987 fxSetupDDPointers(GLcontext * ctx)
988 {
989 TNLcontext *tnl = TNL_CONTEXT(ctx);
990
991 if (MESA_VERBOSE & VERBOSE_DRIVER) {
992 fprintf(stderr, "fxmesa: fxSetupDDPointers()\n");
993 }
994
995 ctx->Driver.UpdateState = fxDDUpdateDDPointers;
996 ctx->Driver.GetString = fxDDGetString;
997 ctx->Driver.ClearIndex = NULL;
998 ctx->Driver.ClearColor = fxDDClearColor;
999 ctx->Driver.Clear = fxDDClear;
1000 ctx->Driver.DrawBuffer = fxDDSetDrawBuffer;
1001 ctx->Driver.GetBufferSize = fxDDBufferSize;
1002 ctx->Driver.Accum = _swrast_Accum;
1003 ctx->Driver.Bitmap = fxDDDrawBitmap;
1004 ctx->Driver.CopyPixels = _swrast_CopyPixels;
1005 ctx->Driver.DrawPixels = _swrast_DrawPixels;
1006 ctx->Driver.ReadPixels = fxDDReadPixels;
1007 ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
1008 ctx->Driver.Finish = fxDDFinish;
1009 ctx->Driver.Flush = NULL;
1010 ctx->Driver.ChooseTextureFormat = fxDDChooseTextureFormat;
1011 ctx->Driver.TexImage1D = _mesa_store_teximage1d;
1012 ctx->Driver.TexImage2D = fxDDTexImage2D;
1013 ctx->Driver.TexImage3D = _mesa_store_teximage3d;
1014 ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
1015 ctx->Driver.TexSubImage2D = fxDDTexSubImage2D;
1016 ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
1017 ctx->Driver.CompressedTexImage1D = _mesa_store_compressed_teximage1d;
1018 ctx->Driver.CompressedTexImage2D = _mesa_store_compressed_teximage2d;
1019 ctx->Driver.CompressedTexImage3D = _mesa_store_compressed_teximage3d;
1020 ctx->Driver.CompressedTexSubImage1D = _mesa_store_compressed_texsubimage1d;
1021 ctx->Driver.CompressedTexSubImage2D = _mesa_store_compressed_texsubimage2d;
1022 ctx->Driver.CompressedTexSubImage3D = _mesa_store_compressed_texsubimage3d;
1023 ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
1024 ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
1025 ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
1026 ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
1027 ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
1028 ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
1029 ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
1030 ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
1031 ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
1032 ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
1033 ctx->Driver.TexEnv = fxDDTexEnv;
1034 ctx->Driver.TexParameter = fxDDTexParam;
1035 ctx->Driver.BindTexture = fxDDTexBind;
1036 ctx->Driver.DeleteTexture = fxDDTexDel;
1037 ctx->Driver.UpdateTexturePalette = fxDDTexPalette;
1038 ctx->Driver.AlphaFunc = fxDDAlphaFunc;
1039 ctx->Driver.BlendFunc = fxDDBlendFunc;
1040 ctx->Driver.DepthFunc = fxDDDepthFunc;
1041 ctx->Driver.DepthMask = fxDDDepthMask;
1042 ctx->Driver.ColorMask = fxDDColorMask;
1043 ctx->Driver.Fogfv = fxDDFogfv;
1044 ctx->Driver.Scissor = fxDDScissor;
1045 ctx->Driver.FrontFace = fxDDFrontFace;
1046 ctx->Driver.CullFace = fxDDCullFace;
1047 ctx->Driver.ShadeModel = fxDDShadeModel;
1048 ctx->Driver.Enable = fxDDEnable;
1049
1050 tnl->Driver.RunPipeline = _tnl_run_pipeline;
1051
1052 fxSetupDDSpanPointers(ctx);
1053 fxDDUpdateDDPointers(ctx, ~0);
1054 }
1055
1056
1057 #else
1058
1059
1060 /*
1061 * Need this to provide at least one external definition.
1062 */
1063
1064 extern int gl_fx_dummy_function_dd(void);
1065 int
1066 gl_fx_dummy_function_dd(void)
1067 {
1068 return 0;
1069 }
1070
1071 #endif /* FX */