3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
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:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
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.
26 * Original Mesa / 3Dfx device driver (C) 1999 David Bucciarelli, by the
29 * Thank you for your contribution, David!
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.
37 * Additional Mesa/3Dfx driver developers:
38 * Daryll Strauss <daryll@precisioninsight.com>
39 * Keith Whitwell <keith@precisioninsight.com>
41 * See fxapi.h for more revision/author details.
45 /* fxdd.c - 3Dfx VooDoo Mesa device driver functions */
58 #include "extensions.h"
60 #include "swrast/swrast.h"
61 #include "swrast_setup/swrast_setup.h"
63 #include "tnl/t_pipeline.h"
64 #include "array_cache/acache.h"
68 float gl_ubyte_to_float_255_color_tab
[256];
70 /* These lookup table are used to extract RGB values in [0,255] from
71 * 16-bit pixel values.
73 GLubyte FX_PixelToR
[0x10000];
74 GLubyte FX_PixelToG
[0x10000];
75 GLubyte FX_PixelToB
[0x10000];
79 * Initialize the FX_PixelTo{RGB} arrays.
80 * Input: bgrOrder - if TRUE, pixels are in BGR order, else RGB order.
83 fxInitPixelTables(fxMesaContext fxMesa
, GLboolean bgrOrder
)
87 fxMesa
->bgrOrder
= bgrOrder
;
88 for (pixel
= 0; pixel
<= 0xffff; pixel
++) {
91 r
= (pixel
& 0x001F) << 3;
92 g
= (pixel
& 0x07E0) >> 3;
93 b
= (pixel
& 0xF800) >> 8;
96 r
= (pixel
& 0xF800) >> 8;
97 g
= (pixel
& 0x07E0) >> 3;
98 b
= (pixel
& 0x001F) << 3;
100 r
= r
* 255 / 0xF8; /* fill in low-order bits */
103 FX_PixelToR
[pixel
] = r
;
104 FX_PixelToG
[pixel
] = g
;
105 FX_PixelToB
[pixel
] = b
;
110 /**********************************************************************/
111 /***** Miscellaneous functions *****/
112 /**********************************************************************/
114 /* Return buffer size information */
116 fxDDBufferSize(GLcontext
* ctx
, GLuint
* width
, GLuint
* height
)
118 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
120 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
121 fprintf(stderr
, "fxmesa: fxDDBufferSize(...) Start\n");
124 *width
= fxMesa
->width
;
125 *height
= fxMesa
->height
;
127 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
128 fprintf(stderr
, "fxmesa: fxDDBufferSize(...) End\n");
133 /* Implements glClearColor() */
135 fxDDClearColor(GLcontext
* ctx
, const GLchan color
[4])
137 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
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]);
145 ASSIGN_4V(col
, color
[0], color
[1], color
[2], 255);
146 fxMesa
->clearC
= FXCOLOR4(col
);
147 fxMesa
->clearA
= color
[3];
151 /* Clear the color and/or depth buffers */
153 fxDDClear(GLcontext
* ctx
, GLbitfield mask
, GLboolean all
,
154 GLint x
, GLint y
, GLint width
, GLint height
)
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
);
161 /* we can't clear stencil or accum buffers */
162 mask
&= ~(DD_STENCIL_BIT
| DD_ACCUM_BIT
);
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
);
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
);
176 * This could probably be done fancier but doing each possible case
177 * explicitly is less error prone.
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
);
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/
195 FX_grDepthMask(FXTRUE
);
196 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER
);
197 FX_grColorMask(FXFALSE
, FXFALSE
);
198 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
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
);
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
);
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
);
223 case DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
:
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
);
234 case DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
| DD_DEPTH_BIT
:
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
);
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
);
265 /* Clear any remaining buffers:
268 _swrast_Clear(ctx
, softwareMask
, all
, x
, y
, width
, height
);
272 /* Set the buffer used for drawing */
273 /* XXX support for separate read/draw buffers hasn't been tested */
275 fxDDSetDrawBuffer(GLcontext
* ctx
, GLenum mode
)
277 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
279 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
280 fprintf(stderr
, "fxmesa: fxDDSetBuffer(%x)\n", (int) mode
);
283 if (mode
== GL_FRONT_LEFT
) {
284 fxMesa
->currentFB
= GR_BUFFER_FRONTBUFFER
;
285 FX_grRenderBuffer(fxMesa
->currentFB
);
288 else if (mode
== GL_BACK_LEFT
) {
289 fxMesa
->currentFB
= GR_BUFFER_BACKBUFFER
;
290 FX_grRenderBuffer(fxMesa
->currentFB
);
293 else if (mode
== GL_NONE
) {
294 FX_grColorMask(FXFALSE
, FXFALSE
);
303 /* Set the buffer used for reading */
304 /* XXX support for separate read/draw buffers hasn't been tested */
306 fxDDSetReadBuffer(GLcontext
* ctx
, GLframebuffer
* buffer
, GLenum mode
)
308 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
311 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
312 fprintf(stderr
, "fxmesa: fxDDSetBuffer(%x)\n", (int) mode
);
315 if (mode
== GL_FRONT_LEFT
) {
316 fxMesa
->currentFB
= GR_BUFFER_FRONTBUFFER
;
317 FX_grRenderBuffer(fxMesa
->currentFB
);
319 else if (mode
== GL_BACK_LEFT
) {
320 fxMesa
->currentFB
= GR_BUFFER_BACKBUFFER
;
321 FX_grRenderBuffer(fxMesa
->currentFB
);
328 fxDDDrawBitmap(GLcontext
* ctx
, GLint px
, GLint py
,
329 GLsizei width
, GLsizei height
,
330 const struct gl_pixelstore_attrib
*unpack
,
331 const GLubyte
* bitmap
)
333 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
336 const struct gl_pixelstore_attrib
*finalUnpack
;
337 struct gl_pixelstore_attrib scissoredUnpack
;
339 /* check if there's any raster operations enabled which we can't handle */
340 if (ctx
->Color
.AlphaEnabled
||
341 ctx
->Color
.BlendEnabled
||
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
);
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.
359 * KW: This code is never reached, see the test above.
362 /* we'll construct a new pixelstore struct */
363 finalUnpack
= &scissoredUnpack
;
364 scissoredUnpack
= *unpack
;
365 if (scissoredUnpack
.RowLength
== 0)
366 scissoredUnpack
.RowLength
= width
;
369 if (px
< ctx
->Scissor
.X
) {
370 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
371 width
-= (ctx
->Scissor
.X
- px
);
375 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
376 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
379 if (py
< ctx
->Scissor
.Y
) {
380 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
381 height
-= (ctx
->Scissor
.Y
- py
);
385 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
386 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
389 if (width
<= 0 || height
<= 0)
393 finalUnpack
= unpack
;
396 /* compute pixel value */
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
)
404 (((FxU16
) 0xf8 & b
) << (11 - 3)) |
405 (((FxU16
) 0xfc & g
) << (5 - 3 + 1)) | (((FxU16
) 0xf8 & r
) >> 3);
408 (((FxU16
) 0xf8 & r
) << (11 - 3)) |
409 (((FxU16
) 0xfc & g
) << (5 - 3 + 1)) | (((FxU16
) 0xf8 & b
) >> 3);
412 info
.size
= sizeof(info
);
413 if (!FX_grLfbLock(GR_LFB_WRITE_ONLY
,
416 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
418 fprintf(stderr
, "fx Driver: error locking the linear frame buffer\n");
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
430 const GLint dstStride
= info
.strideInBytes
/ 2; /* stride in GLushorts */
433 /* compute dest address of bottom-left pixel in bitmap */
434 GLushort
*dst
= (GLushort
*) info
.lfbPtr
435 + (winY
- py
) * dstStride
+ (winX
+ px
);
437 for (row
= 0; row
< height
; row
++) {
439 (const GLubyte
*) _mesa_image_address(finalUnpack
,
440 bitmap
, width
, height
,
441 GL_COLOR_INDEX
, GL_BITMAP
,
443 if (finalUnpack
->LsbFirst
) {
444 /* least significan bit first */
445 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
447 for (col
= 0; col
< width
; col
++) {
463 /* most significan bit first */
464 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
466 for (col
= 0; col
< width
; col
++) {
485 FX_grLfbUnlock(GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
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
)
495 if (ctx
->_ImageTransferState
) {
496 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
501 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
505 if (grLfbLock(GR_LFB_READ_ONLY
,
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
,
518 _mesa_image_row_stride(packing
, width
, format
, type
);
520 if (format
== GL_RGB
&& type
== GL_UNSIGNED_BYTE
) {
521 /* convert 5R6G5B into 8R8G8B */
523 const GLint halfWidth
= width
>> 1;
524 const GLint extraPixel
= (width
& 1);
525 for (row
= 0; row
< height
; row
++) {
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
];
539 GLushort pixel
= src
[width
- 1];
540 *d
++ = FX_PixelToR
[pixel
];
541 *d
++ = FX_PixelToG
[pixel
];
542 *d
++ = FX_PixelToB
[pixel
];
548 else if (format
== GL_RGBA
&& type
== GL_UNSIGNED_BYTE
) {
549 /* convert 5R6G5B into 8R8G8B8A */
551 const GLint halfWidth
= width
>> 1;
552 const GLint extraPixel
= (width
& 1);
553 for (row
= 0; row
< height
; row
++) {
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
];
563 *d
++ = FX_PixelToR
[pixel1
];
564 *d
++ = FX_PixelToG
[pixel1
];
565 *d
++ = FX_PixelToB
[pixel1
];
569 const GLushort pixel
= src
[width
- 1];
570 *d
++ = FX_PixelToR
[pixel
];
571 *d
++ = FX_PixelToG
[pixel
];
572 *d
++ = FX_PixelToB
[pixel
];
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;
583 for (row
= 0; row
< height
; row
++) {
584 MEMCPY(dst
, src
, widthInBytes
);
590 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
592 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
597 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
606 fxDDFinish(GLcontext
* ctx
)
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).
619 static const GLubyte
*
620 fxDDGetString(GLcontext
* ctx
, GLenum name
)
627 if (glbHWConfig
.SSTs
[glbCurrentBoard
].type
== GR_SSTTYPE_VOODOO
) {
628 GrVoodooConfig_t
*vc
=
629 &glbHWConfig
.SSTs
[glbCurrentBoard
].sstBoard
.VoodooConfig
;
632 "Mesa Glide v0.30 Voodoo_Graphics %d "
633 "CARD/%d FB/%d TM/%d TMU/%s",
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"));
641 else if (glbHWConfig
.SSTs
[glbCurrentBoard
].type
== GR_SSTTYPE_SST96
) {
642 GrSst96Config_t
*sc
=
643 &glbHWConfig
.SSTs
[glbCurrentBoard
].sstBoard
.SST96Config
;
646 "Glide v0.30 Voodoo_Rush %d "
647 "CARD/%d FB/%d TM/%d TMU/NOSLI",
649 sc
->fbRam
, sc
->tmuConfig
.tmuRam
, sc
->nTexelfx
);
652 strcpy(buf
, "Glide v0.30 UNKNOWN");
654 return (GLubyte
*) buf
;
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 */
667 &_tnl_texture_transform_stage
,
668 &_tnl_point_attenuation_stage
,
677 fxDDInitFxMesaContext(fxMesaContext fxMesa
)
680 static int firsttime
= 1;
682 for (i
= 0; i
< 256; i
++) {
683 gl_ubyte_to_float_255_color_tab
[i
] = (float) i
;
692 FX_setupGrVertexLayout();
694 if (getenv("FX_EMULATE_SINGLE_TMU"))
695 fxMesa
->haveTwoTMUs
= GL_FALSE
;
697 fxMesa
->emulateTwoTMUs
= fxMesa
->haveTwoTMUs
;
699 if (!getenv("FX_DONT_FAKE_MULTITEX"))
700 fxMesa
->emulateTwoTMUs
= GL_TRUE
;
702 if (getenv("FX_GLIDE_SWAPINTERVAL"))
703 fxMesa
->swapInterval
= atoi(getenv("FX_GLIDE_SWAPINTERVAL"));
705 fxMesa
->swapInterval
= 1;
707 if (getenv("MESA_FX_SWAP_PENDING"))
708 fxMesa
->maxPendingSwapBuffers
= atoi(getenv("MESA_FX_SWAP_PENDING"));
710 fxMesa
->maxPendingSwapBuffers
= 2;
712 if (getenv("MESA_FX_INFO"))
713 fxMesa
->verbose
= GL_TRUE
;
715 fxMesa
->verbose
= GL_FALSE
;
717 fxMesa
->color
= 0xffffffff;
721 fxMesa
->stats
.swapBuffer
= 0;
722 fxMesa
->stats
.reqTexUpload
= 0;
723 fxMesa
->stats
.texUpload
= 0;
724 fxMesa
->stats
.memTexUpload
= 0;
726 fxMesa
->tmuSrc
= FX_TMU_NONE
;
727 fxMesa
->lastUnitsMode
= FX_UM_NONE
;
732 fxMesa
->unitsState
.alphaTestEnabled
= GL_FALSE
;
733 fxMesa
->unitsState
.alphaTestFunc
= GR_CMP_ALWAYS
;
734 fxMesa
->unitsState
.alphaTestRefValue
= 0;
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
;
742 fxMesa
->unitsState
.depthTestEnabled
= GL_FALSE
;
743 fxMesa
->unitsState
.depthMask
= GL_TRUE
;
744 fxMesa
->unitsState
.depthTestFunc
= GR_CMP_LESS
;
746 FX_grColorMask(FXTRUE
, fxMesa
->haveAlphaBuffer
? FXTRUE
: FXFALSE
);
747 if (fxMesa
->haveDoubleBuffer
) {
748 fxMesa
->currentFB
= GR_BUFFER_BACKBUFFER
;
749 FX_grRenderBuffer(GR_BUFFER_BACKBUFFER
);
752 fxMesa
->currentFB
= GR_BUFFER_FRONTBUFFER
;
753 FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER
);
756 fxMesa
->state
= malloc(FX_grGetInteger(FX_GLIDE_STATE_SIZE
));
757 fxMesa
->fogTable
= malloc(FX_grGetInteger(FX_FOG_TABLE_ENTRIES
) *
760 if (!fxMesa
->state
|| !fxMesa
->fogTable
) {
763 if (fxMesa
->fogTable
)
764 free(fxMesa
->fogTable
);
768 if (fxMesa
->haveZBuffer
)
769 FX_grDepthBufferMode(GR_DEPTHBUFFER_ZBUFFER
);
771 #if (!FXMESA_USE_ARGB)
772 FX_grLfbWriteColorFormat(GR_COLORFORMAT_ABGR
); /* Not every Glide has this */
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
;
781 /* Initialize the software rasterizer and helper modules.
783 _swrast_CreateContext(fxMesa
->glCtx
);
784 _ac_CreateContext(fxMesa
->glCtx
);
785 _tnl_CreateContext(fxMesa
->glCtx
);
786 _swsetup_CreateContext(fxMesa
->glCtx
);
788 _tnl_destroy_pipeline(fxMesa
->glCtx
);
789 _tnl_install_pipeline(fxMesa
->glCtx
, fx_pipeline
);
791 fxAllocVB(fxMesa
->glCtx
);
793 fxSetupDDPointers(fxMesa
->glCtx
);
795 /* Tell the software rasterizer to use pixel fog always.
797 _swrast_allow_vertex_fog(fxMesa
->glCtx
, GL_FALSE
);
798 _swrast_allow_pixel_fog(fxMesa
->glCtx
, GL_TRUE
);
800 /* Tell tnl not to calculate or use vertex fog factors. (Needed to
801 * tell render stage not to clip fog coords).
803 /* _tnl_calculate_vertex_fog( fxMesa->glCtx, GL_FALSE ); */
805 fxDDInitExtensions(fxMesa
->glCtx
);
808 fxDDInitVtxfmt(fxMesa
->glCtx
);
811 FX_grGlideGetState((GrState
*) fxMesa
->state
);
813 /* Run the config file */
814 _mesa_context_initialize(fxMesa
->glCtx
);
822 fxDDDestroyFxMesaContext(fxMesaContext fxMesa
)
824 _swsetup_DestroyContext(fxMesa
->glCtx
);
825 _tnl_DestroyContext(fxMesa
->glCtx
);
826 _ac_DestroyContext(fxMesa
->glCtx
);
827 _swrast_DestroyContext(fxMesa
->glCtx
);
831 if (fxMesa
->fogTable
)
832 free(fxMesa
->fogTable
);
834 fxFreeVB(fxMesa
->glCtx
);
841 fxDDInitExtensions(GLcontext
* ctx
)
843 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
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");
851 if (fxMesa
->haveTwoTMUs
)
852 _mesa_enable_extension(ctx
, "GL_EXT_texture_env_add");
854 if (fxMesa
->emulateTwoTMUs
)
855 _mesa_enable_extension(ctx
, "GL_ARB_multitexture");
859 /************************************************************************/
860 /************************************************************************/
861 /************************************************************************/
863 /* Check if the hardware supports the current context
865 * Performs similar work to fxDDChooseRenderState() - should be merged.
868 fxIsInHardware(GLcontext
* ctx
)
870 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
872 if (ctx
->RenderMode
!= GL_RENDER
)
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
)
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
])))
890 /* Unsupported texture/multitexture cases */
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 */
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)) {
907 if (ctx
->Texture
.Unit
[0]._Current
->Image
[0]->Border
> 0)
911 if (ctx
->Texture
._ReallyEnabled
& TEXTURE1_2D
) {
912 if (ctx
->Texture
.Unit
[1].EnvMode
== GL_BLEND
)
914 if (ctx
->Texture
.Unit
[0]._Current
->Image
[0]->Border
> 0)
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
));
923 /* KW: This was wrong (I think) and I changed it... which doesn't mean
924 * it is now correct...
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
931 if (!fxMesa
->haveTwoTMUs
&& ctx
->Color
.BlendEnabled
) {
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");
945 if ((ctx
->_Enabled
& (TEXTURE1_1D
| TEXTURE1_2D
| TEXTURE1_3D
)) ||
946 /* Not very well written ... */
947 ((ctx
->_Enabled
& TEXTURE0_1D
) && (!(ctx
->_Enabled
& TEXTURE0_2D
)))
953 if ((ctx
->Texture
._ReallyEnabled
& TEXTURE0_2D
) &&
954 (ctx
->Texture
.Unit
[0].EnvMode
== GL_BLEND
)) {
963 update_texture_scales(GLcontext
* ctx
)
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]];
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
;
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
;
985 fxDDUpdateDDPointers(GLcontext
* ctx
, GLuint new_state
)
987 fxMesaContext fxMesa
= FX_CONTEXT(ctx
);
989 _swrast_InvalidateState(ctx
, new_state
);
990 _ac_InvalidateState(ctx
, new_state
);
991 _tnl_InvalidateState(ctx
, new_state
);
992 _swsetup_InvalidateState(ctx
, new_state
);
994 /* Recalculate fog table on projection matrix changes. This used to
995 * be triggered by the NearFar callback.
997 if (new_state
& _NEW_PROJECTION
)
998 fxMesa
->new_state
|= FX_NEW_FOG
;
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
;
1005 if (new_state
& _FX_NEW_IS_IN_HARDWARE
)
1006 fxMesa
->is_in_hardware
= fxIsInHardware(ctx
);
1008 if (fxMesa
->new_state
)
1009 fxSetupFXUnits(ctx
);
1011 if (new_state
& _FX_NEW_RENDERSTATE
)
1012 fxDDChooseRenderState(ctx
);
1014 if (new_state
& _FX_NEW_SETUP_FUNCTION
)
1015 ctx
->Driver
.BuildProjectedVertices
= fx_validate_BuildProjVerts
;
1017 if (new_state
& _NEW_TEXTURE
)
1018 update_texture_scales(ctx
);
1023 if (fxMesa
->allow_vfmt
) {
1024 if (new_state
& _NEW_LIGHT
)
1025 fx_update_lighting(ctx
);
1027 if (new_state
& _FX_NEW_VTXFMT
)
1028 fxDDCheckVtxfmt(ctx
);
1034 fxDDRenderPrimitive(GLcontext
* ctx
, GLenum mode
)
1036 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
1038 if (!fxMesa
->is_in_hardware
) {
1039 _swsetup_RenderPrimitive(ctx
, mode
);
1042 fxMesa
->render_prim
= mode
;
1048 fxDDRenderStart(GLcontext
* ctx
)
1050 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
1052 _swsetup_RenderStart(ctx
);
1054 if (fxMesa
->new_state
) {
1055 fxSetupFXUnits(ctx
);
1060 fxDDRenderFinish(GLcontext
* ctx
)
1062 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
1064 if (!fxMesa
->is_in_hardware
) {
1065 _swsetup_RenderFinish(ctx
);
1072 fxSetupDDPointers(GLcontext
* ctx
)
1074 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
1075 fprintf(stderr
, "fxmesa: fxSetupDDPointers()\n");
1078 ctx
->Driver
.UpdateState
= fxDDUpdateDDPointers
;
1080 ctx
->Driver
.WriteDepthSpan
= fxDDWriteDepthSpan
;
1081 ctx
->Driver
.WriteDepthPixels
= fxDDWriteDepthPixels
;
1082 ctx
->Driver
.ReadDepthSpan
= fxDDReadDepthSpan
;
1083 ctx
->Driver
.ReadDepthPixels
= fxDDReadDepthPixels
;
1085 ctx
->Driver
.GetString
= fxDDGetString
;
1087 ctx
->Driver
.ClearIndex
= NULL
;
1088 ctx
->Driver
.ClearColor
= fxDDClearColor
;
1089 ctx
->Driver
.Clear
= fxDDClear
;
1091 ctx
->Driver
.SetDrawBuffer
= fxDDSetDrawBuffer
;
1092 ctx
->Driver
.SetReadBuffer
= fxDDSetReadBuffer
;
1093 ctx
->Driver
.GetBufferSize
= fxDDBufferSize
;
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
;
1102 ctx
->Driver
.Finish
= fxDDFinish
;
1103 ctx
->Driver
.Flush
= NULL
;
1105 ctx
->Driver
.RenderStart
= fxDDRenderStart
;
1106 ctx
->Driver
.RenderFinish
= fxDDRenderFinish
;
1107 ctx
->Driver
.ResetLineStipple
= _swrast_ResetLineStipple
;
1108 ctx
->Driver
.RenderPrimitive
= fxDDRenderPrimitive
;
1110 /* Install the oldstyle interp functions:
1112 ctx
->Driver
.RenderInterp
= _swsetup_RenderInterp
;
1113 ctx
->Driver
.RenderCopyPV
= _swsetup_RenderCopyPV
;
1114 ctx
->Driver
.RenderClippedLine
= _swsetup_RenderClippedLine
;
1115 ctx
->Driver
.RenderClippedPolygon
= _swsetup_RenderClippedPolygon
;
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
;
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
;
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
;
1150 fxSetupDDSpanPointers(ctx
);
1151 fxDDUpdateDDPointers(ctx
, ~0);
1159 * Need this to provide at least one external definition.
1162 extern int gl_fx_dummy_function_dd(void);
1164 gl_fx_dummy_function_dd(void)