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