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