2 * fxDDReadPixels888 does not convert 8A8R8G8B into 5R5G5B
5 /* $Id: fxdd.c,v 1.99 2003/08/19 15:52:53 brianp Exp $ */
8 * Mesa 3-D graphics library
11 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
20 * The above copyright notice and this permission notice shall be included
21 * in all copies or substantial portions of the Software.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
27 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 /* fxdd.c - 3Dfx VooDoo Mesa device driver functions */
53 #include "extensions.h"
57 #include "swrast/swrast.h"
58 #include "swrast_setup/swrast_setup.h"
60 #include "tnl/t_context.h"
61 #include "tnl/t_pipeline.h"
62 #include "array_cache/acache.h"
66 float gl_ubyte_to_float_255_color_tab
[256];
68 /* These lookup table are used to extract RGB values in [0,255] from
69 * 16-bit pixel values.
71 GLubyte FX_PixelToR
[0x10000];
72 GLubyte FX_PixelToG
[0x10000];
73 GLubyte FX_PixelToB
[0x10000];
75 /* lookup table for scaling 5 bit colors up to 8 bits */
76 GLuint FX_rgb_scale_5
[32] = {
77 0, 8, 16, 25, 33, 41, 49, 58,
78 66, 74, 82, 90, 99, 107, 115, 123,
79 132, 140, 148, 156, 165, 173, 181, 189,
80 197, 206, 214, 222, 230, 239, 247, 255
85 * Initialize the FX_PixelTo{RGB} arrays.
86 * Input: bgrOrder - if TRUE, pixels are in BGR order, else RGB order.
89 fxInitPixelTables(fxMesaContext fxMesa
, GLboolean bgrOrder
)
93 fxMesa
->bgrOrder
= bgrOrder
;
94 for (pixel
= 0; pixel
<= 0xffff; pixel
++) {
97 r
= (pixel
& 0x001F) << 3;
98 g
= (pixel
& 0x07E0) >> 3;
99 b
= (pixel
& 0xF800) >> 8;
102 r
= (pixel
& 0xF800) >> 8;
103 g
= (pixel
& 0x07E0) >> 3;
104 b
= (pixel
& 0x001F) << 3;
106 /* fill in low-order bits with proper rounding */
107 r
= (GLuint
)(((double)r
* 255. / 0xF8) + 0.5);
108 g
= (GLuint
)(((double)g
* 255. / 0xFC) + 0.5);
109 b
= (GLuint
)(((double)b
* 255. / 0xF8) + 0.5);
110 FX_PixelToR
[pixel
] = r
;
111 FX_PixelToG
[pixel
] = g
;
112 FX_PixelToB
[pixel
] = b
;
117 /**********************************************************************/
118 /***** Miscellaneous functions *****/
119 /**********************************************************************/
121 /* Return buffer size information */
123 fxDDBufferSize(GLframebuffer
*buffer
, GLuint
* width
, GLuint
* height
)
125 GET_CURRENT_CONTEXT(ctx
);
126 if (ctx
&& ctx
->DriverCtx
) {
127 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
129 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
130 fprintf(stderr
, "fxmesa: fxDDBufferSize(...) Start\n");
133 *width
= fxMesa
->width
;
134 *height
= fxMesa
->height
;
136 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
137 fprintf(stderr
, "fxmesa: fxDDBufferSize(...) End\n");
143 /* Implements glClearColor() */
145 fxDDClearColor(GLcontext
* ctx
, const GLfloat color
[4])
147 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
150 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
151 fprintf(stderr
, "fxmesa: fxDDClearColor(%f,%f,%f,%f)\n",
152 color
[0], color
[1], color
[2], color
[3]);
155 CLAMPED_FLOAT_TO_UBYTE(col
[0], color
[0]);
156 CLAMPED_FLOAT_TO_UBYTE(col
[1], color
[1]);
157 CLAMPED_FLOAT_TO_UBYTE(col
[2], color
[2]);
158 CLAMPED_FLOAT_TO_UBYTE(col
[3], color
[3]);
160 fxMesa
->clearC
= FXCOLOR4(col
);
161 fxMesa
->clearA
= col
[3];
165 /* Clear the color and/or depth buffers */
167 fxDDClear(GLcontext
* ctx
, GLbitfield mask
, GLboolean all
,
168 GLint x
, GLint y
, GLint width
, GLint height
)
170 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
171 const GLuint colorMask
= *((GLuint
*) & ctx
->Color
.ColorMask
);
172 /* [dBorca] should use an adequate scaler for 16 vs 32bit (GR_ZDEPTH_MIN_MAX) */
173 const FxU32 clearD
= (FxU32
) (ctx
->Depth
.Clear
* 0x00ffffff);
174 GLbitfield softwareMask
= mask
& (DD_STENCIL_BIT
| DD_ACCUM_BIT
);
176 /* we can't clear stencil or accum buffers */
177 mask
&= ~(DD_STENCIL_BIT
| DD_ACCUM_BIT
);
179 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
180 fprintf(stderr
, "fxmesa: fxDDClear(%d,%d,%d,%d)\n", (int) x
, (int) y
,
181 (int) width
, (int) height
);
184 if (colorMask
!= 0xffffffff) {
185 /* do masked color buffer clears in software */
186 softwareMask
|= (mask
& (DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
));
187 mask
&= ~(DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
);
191 * This could probably be done fancier but doing each possible case
192 * explicitly is less error prone.
195 case DD_BACK_LEFT_BIT
| DD_DEPTH_BIT
:
196 /* back buffer & depth */
198 grRenderBuffer(GR_BUFFER_BACKBUFFER
);
199 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
200 if (!ctx
->Depth
.Mask
) {
201 grDepthMask(FXFALSE
);
204 case DD_FRONT_LEFT_BIT
| DD_DEPTH_BIT
:
205 /* XXX it appears that the depth buffer isn't cleared when
206 * glRenderBuffer(GR_BUFFER_FRONTBUFFER) is set.
207 * This is a work-around/
211 grRenderBuffer(GR_BUFFER_BACKBUFFER
);
212 grColorMask(FXFALSE
, FXFALSE
);
213 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
215 grColorMask(FXTRUE
, ctx
->Color
.ColorMask
[ACOMP
] && fxMesa
->haveAlphaBuffer
);
216 grRenderBuffer(GR_BUFFER_FRONTBUFFER
);
217 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
219 case DD_BACK_LEFT_BIT
:
220 /* back buffer only */
221 grDepthMask(FXFALSE
);
222 grRenderBuffer(GR_BUFFER_BACKBUFFER
);
223 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
224 if (ctx
->Depth
.Mask
) {
228 case DD_FRONT_LEFT_BIT
:
229 /* front buffer only */
230 grDepthMask(FXFALSE
);
231 grRenderBuffer(GR_BUFFER_FRONTBUFFER
);
232 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
233 if (ctx
->Depth
.Mask
) {
237 case DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
:
239 grDepthMask(FXFALSE
);
240 grRenderBuffer(GR_BUFFER_BACKBUFFER
);
241 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
242 grRenderBuffer(GR_BUFFER_FRONTBUFFER
);
243 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
244 if (ctx
->Depth
.Mask
) {
248 case DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
| DD_DEPTH_BIT
:
250 grDepthMask(FXFALSE
);
251 grRenderBuffer(GR_BUFFER_FRONTBUFFER
);
252 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
253 /* clear back and depth */
255 grRenderBuffer(GR_BUFFER_BACKBUFFER
);
256 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
257 if (!ctx
->Depth
.Mask
) {
258 grDepthMask(FXFALSE
);
262 /* just the depth buffer */
263 grRenderBuffer(GR_BUFFER_BACKBUFFER
);
264 grColorMask(FXFALSE
, FXFALSE
);
266 FX_grBufferClear(fxMesa
->clearC
, fxMesa
->clearA
, clearD
);
267 grColorMask(FXTRUE
, ctx
->Color
.ColorMask
[ACOMP
] && fxMesa
->haveAlphaBuffer
);
268 if (ctx
->Color
._DrawDestMask
& FRONT_LEFT_BIT
)
269 grRenderBuffer(GR_BUFFER_FRONTBUFFER
);
270 if (!ctx
->Depth
.Test
|| !ctx
->Depth
.Mask
)
271 grDepthMask(FXFALSE
);
278 /* Clear any remaining buffers:
281 _swrast_Clear(ctx
, softwareMask
, all
, x
, y
, width
, height
);
285 /* Set the buffer used for drawing */
286 /* XXX support for separate read/draw buffers hasn't been tested */
288 fxDDSetDrawBuffer(GLcontext
* ctx
, GLenum mode
)
290 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
292 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
293 fprintf(stderr
, "fxmesa: fxDDSetBuffer(%x)\n", (int) mode
);
296 if (mode
== GL_FRONT_LEFT
) {
297 fxMesa
->currentFB
= GR_BUFFER_FRONTBUFFER
;
298 grRenderBuffer(fxMesa
->currentFB
);
300 else if (mode
== GL_BACK_LEFT
) {
301 fxMesa
->currentFB
= GR_BUFFER_BACKBUFFER
;
302 grRenderBuffer(fxMesa
->currentFB
);
304 else if (mode
== GL_NONE
) {
305 grColorMask(FXFALSE
, FXFALSE
);
308 /* we'll need a software fallback */
309 /* XXX not implemented */
312 /* update s/w fallback state */
313 _swrast_DrawBuffer(ctx
, mode
);
321 fxDDDrawBitmap(GLcontext
* ctx
, GLint px
, GLint py
,
322 GLsizei width
, GLsizei height
,
323 const struct gl_pixelstore_attrib
*unpack
,
324 const GLubyte
* bitmap
)
326 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
329 const struct gl_pixelstore_attrib
*finalUnpack
;
330 struct gl_pixelstore_attrib scissoredUnpack
;
332 /* check if there's any raster operations enabled which we can't handle */
333 if (ctx
->Color
.AlphaEnabled
||
334 ctx
->Color
.BlendEnabled
||
337 ctx
->Color
.ColorLogicOpEnabled
||
338 ctx
->Stencil
.Enabled
||
339 ctx
->Scissor
.Enabled
||
340 (ctx
->DrawBuffer
->UseSoftwareAlphaBuffers
&&
341 ctx
->Color
.ColorMask
[ACOMP
]) ||
342 (ctx
->Color
._DrawDestMask
!= FRONT_LEFT_BIT
&&
343 ctx
->Color
._DrawDestMask
!= BACK_LEFT_BIT
)) {
344 _swrast_Bitmap(ctx
, px
, py
, width
, height
, unpack
, bitmap
);
349 if (ctx
->Scissor
.Enabled
) {
350 /* This is a bit tricky, but by carefully adjusting the px, py,
351 * width, height, skipPixels and skipRows values we can do
352 * scissoring without special code in the rendering loop.
354 * KW: This code is never reached, see the test above.
357 /* we'll construct a new pixelstore struct */
358 finalUnpack
= &scissoredUnpack
;
359 scissoredUnpack
= *unpack
;
360 if (scissoredUnpack
.RowLength
== 0)
361 scissoredUnpack
.RowLength
= width
;
364 if (px
< ctx
->Scissor
.X
) {
365 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
366 width
-= (ctx
->Scissor
.X
- px
);
370 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
371 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
374 if (py
< ctx
->Scissor
.Y
) {
375 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
376 height
-= (ctx
->Scissor
.Y
- py
);
380 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
381 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
384 if (width
<= 0 || height
<= 0)
388 finalUnpack
= unpack
;
391 /* compute pixel value */
393 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0f
);
394 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0f
);
395 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0f
);
396 /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f); */
397 if (fxMesa
->bgrOrder
)
399 (((FxU16
) 0xf8 & b
) << (11 - 3)) |
400 (((FxU16
) 0xfc & g
) << (5 - 3 + 1)) | (((FxU16
) 0xf8 & r
) >> 3);
403 (((FxU16
) 0xf8 & r
) << (11 - 3)) |
404 (((FxU16
) 0xfc & g
) << (5 - 3 + 1)) | (((FxU16
) 0xf8 & b
) >> 3);
407 info
.size
= sizeof(info
);
408 if (!grLfbLock(GR_LFB_WRITE_ONLY
,
411 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
413 fprintf(stderr
, "fx Driver: error locking the linear frame buffer\n");
419 const GLint winX
= 0;
420 const GLint winY
= fxMesa
->height
- 1;
421 /* The dest stride depends on the hardware and whether we're drawing
422 * to the front or back buffer. This compile-time test seems to do
425 const GLint dstStride
= info
.strideInBytes
/ 2; /* stride in GLushorts */
428 /* compute dest address of bottom-left pixel in bitmap */
429 GLushort
*dst
= (GLushort
*) info
.lfbPtr
430 + (winY
- py
) * dstStride
+ (winX
+ px
);
432 for (row
= 0; row
< height
; row
++) {
434 (const GLubyte
*) _mesa_image_address(finalUnpack
,
435 bitmap
, width
, height
,
436 GL_COLOR_INDEX
, GL_BITMAP
,
438 if (finalUnpack
->LsbFirst
) {
439 /* least significan bit first */
440 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
442 for (col
= 0; col
< width
; col
++) {
458 /* most significan bit first */
459 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
461 for (col
= 0; col
< width
; col
++) {
480 grLfbUnlock(GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
485 fxDDReadPixels(GLcontext
* ctx
, GLint x
, GLint y
,
486 GLsizei width
, GLsizei height
,
487 GLenum format
, GLenum type
,
488 const struct gl_pixelstore_attrib
*packing
, GLvoid
* dstImage
)
490 if (ctx
->_ImageTransferState
) {
491 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
496 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
500 if (grLfbLock(GR_LFB_READ_ONLY
,
503 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
504 const GLint winX
= 0;
505 const GLint winY
= fxMesa
->height
- 1;
506 const GLint srcStride
= info
.strideInBytes
/ 2; /* stride in GLushorts */
507 const GLushort
*src
= (const GLushort
*) info
.lfbPtr
508 + (winY
- y
) * srcStride
+ (winX
+ x
);
509 GLubyte
*dst
= (GLubyte
*) _mesa_image_address(packing
, dstImage
,
510 width
, height
, format
,
513 _mesa_image_row_stride(packing
, width
, format
, type
);
515 if (format
== GL_RGB
&& type
== GL_UNSIGNED_BYTE
) {
516 /* convert 5R6G5B into 8R8G8B */
518 const GLint halfWidth
= width
>> 1;
519 const GLint extraPixel
= (width
& 1);
520 for (row
= 0; row
< height
; row
++) {
522 for (col
= 0; col
< halfWidth
; col
++) {
523 const GLuint pixel
= ((const GLuint
*) src
)[col
];
524 const GLint pixel0
= pixel
& 0xffff;
525 const GLint pixel1
= pixel
>> 16;
526 *d
++ = FX_PixelToR
[pixel0
];
527 *d
++ = FX_PixelToG
[pixel0
];
528 *d
++ = FX_PixelToB
[pixel0
];
529 *d
++ = FX_PixelToR
[pixel1
];
530 *d
++ = FX_PixelToG
[pixel1
];
531 *d
++ = FX_PixelToB
[pixel1
];
534 GLushort pixel
= src
[width
- 1];
535 *d
++ = FX_PixelToR
[pixel
];
536 *d
++ = FX_PixelToG
[pixel
];
537 *d
++ = FX_PixelToB
[pixel
];
543 else if (format
== GL_RGBA
&& type
== GL_UNSIGNED_BYTE
) {
544 /* convert 5R6G5B into 8R8G8B8A */
546 const GLint halfWidth
= width
>> 1;
547 const GLint extraPixel
= (width
& 1);
548 for (row
= 0; row
< height
; row
++) {
550 for (col
= 0; col
< halfWidth
; col
++) {
551 const GLuint pixel
= ((const GLuint
*) src
)[col
];
552 const GLint pixel0
= pixel
& 0xffff;
553 const GLint pixel1
= pixel
>> 16;
554 *d
++ = FX_PixelToR
[pixel0
];
555 *d
++ = FX_PixelToG
[pixel0
];
556 *d
++ = FX_PixelToB
[pixel0
];
558 *d
++ = FX_PixelToR
[pixel1
];
559 *d
++ = FX_PixelToG
[pixel1
];
560 *d
++ = FX_PixelToB
[pixel1
];
564 const GLushort pixel
= src
[width
- 1];
565 *d
++ = FX_PixelToR
[pixel
];
566 *d
++ = FX_PixelToG
[pixel
];
567 *d
++ = FX_PixelToB
[pixel
];
574 else if (format
== GL_RGB
&& type
== GL_UNSIGNED_SHORT_5_6_5
) {
575 /* directly memcpy 5R6G5B pixels into client's buffer */
576 const GLint widthInBytes
= width
* 2;
578 for (row
= 0; row
< height
; row
++) {
579 MEMCPY(dst
, src
, widthInBytes
);
585 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
587 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
592 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
598 static void fxDDReadPixels555 (GLcontext
* ctx
,
600 GLsizei width
, GLsizei height
,
601 GLenum format
, GLenum type
,
602 const struct gl_pixelstore_attrib
*packing
,
605 if (ctx
->_ImageTransferState
) {
606 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
611 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
615 if (grLfbLock(GR_LFB_READ_ONLY
,
618 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
619 const GLint winX
= 0;
620 const GLint winY
= fxMesa
->height
- 1;
621 const GLint srcStride
= info
.strideInBytes
/ 2; /* stride in GLushorts */
622 const GLushort
*src
= (const GLushort
*) info
.lfbPtr
623 + (winY
- y
) * srcStride
+ (winX
+ x
);
624 GLubyte
*dst
= (GLubyte
*) _mesa_image_address(packing
, dstImage
,
625 width
, height
, format
,
628 _mesa_image_row_stride(packing
, width
, format
, type
);
630 if (format
== GL_RGB
&& type
== GL_UNSIGNED_BYTE
) {
631 /* convert 5R5G5B into 8R8G8B */
633 const GLint halfWidth
= width
>> 1;
634 const GLint extraPixel
= (width
& 1);
635 for (row
= 0; row
< height
; row
++) {
637 for (col
= 0; col
< halfWidth
; col
++) {
638 const GLuint pixel
= ((const GLuint
*) src
)[col
];
639 *d
++ = FX_rgb_scale_5
[ pixel
& 0x1f];
640 *d
++ = FX_rgb_scale_5
[(pixel
>> 5) & 0x1f];
641 *d
++ = FX_rgb_scale_5
[(pixel
>> 10) & 0x1f];
642 *d
++ = FX_rgb_scale_5
[(pixel
>> 16) & 0x1f];
643 *d
++ = FX_rgb_scale_5
[(pixel
>> 21) & 0x1f];
644 *d
++ = FX_rgb_scale_5
[(pixel
>> 26) & 0x1f];
647 GLushort pixel
= src
[width
- 1];
648 *d
++ = FX_rgb_scale_5
[ pixel
& 0x1f];
649 *d
++ = FX_rgb_scale_5
[(pixel
>> 5) & 0x1f];
650 *d
++ = FX_rgb_scale_5
[(pixel
>> 10) & 0x1f];
656 else if (format
== GL_RGBA
&& type
== GL_UNSIGNED_BYTE
) {
657 /* convert 5R6G5B into 8R8G8B8A */
659 const GLint halfWidth
= width
>> 1;
660 const GLint extraPixel
= (width
& 1);
661 for (row
= 0; row
< height
; row
++) {
663 for (col
= 0; col
< halfWidth
; col
++) {
664 const GLuint pixel
= ((const GLuint
*) src
)[col
];
665 *d
++ = FX_rgb_scale_5
[ pixel
& 0x1f];
666 *d
++ = FX_rgb_scale_5
[(pixel
>> 5) & 0x1f];
667 *d
++ = FX_rgb_scale_5
[(pixel
>> 10) & 0x1f];
668 *d
++ = (pixel
& 0x8000) ? 255 : 0;
669 *d
++ = FX_rgb_scale_5
[(pixel
>> 16) & 0x1f];
670 *d
++ = FX_rgb_scale_5
[(pixel
>> 21) & 0x1f];
671 *d
++ = FX_rgb_scale_5
[(pixel
>> 26) & 0x1f];
672 *d
++ = (pixel
& 0x80000000) ? 255 : 0;
675 const GLushort pixel
= src
[width
- 1];
676 *d
++ = FX_rgb_scale_5
[ pixel
& 0x1f];
677 *d
++ = FX_rgb_scale_5
[(pixel
>> 5) & 0x1f];
678 *d
++ = FX_rgb_scale_5
[(pixel
>> 10) & 0x1f];
679 *d
++ = (pixel
& 0x8000) ? 255 : 0;
685 else if (format
== GL_RGB
&& type
== GL_UNSIGNED_SHORT_5_6_5
) {
686 /* directly memcpy 5R5G5B pixels into client's buffer */
687 const GLint widthInBytes
= width
* 2;
689 for (row
= 0; row
< height
; row
++) {
690 MEMCPY(dst
, src
, widthInBytes
);
696 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
698 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
703 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
709 static void fxDDReadPixels888 (GLcontext
* ctx
,
711 GLsizei width
, GLsizei height
,
712 GLenum format
, GLenum type
,
713 const struct gl_pixelstore_attrib
*packing
,
716 if (ctx
->_ImageTransferState
) {
717 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
722 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
726 if (grLfbLock(GR_LFB_READ_ONLY
,
729 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
730 const GLint winX
= 0;
731 const GLint winY
= fxMesa
->height
- 1;
732 const GLint srcStride
= info
.strideInBytes
/ 4; /* stride in GLuints */
733 const GLuint
*src
= (const GLuint
*) info
.lfbPtr
734 + (winY
- y
) * srcStride
+ (winX
+ x
);
735 GLubyte
*dst
= (GLubyte
*) _mesa_image_address(packing
, dstImage
,
736 width
, height
, format
,
739 _mesa_image_row_stride(packing
, width
, format
, type
);
741 if (format
== GL_RGB
&& type
== GL_UNSIGNED_BYTE
) {
742 /* convert 8A8R8G8B into 8R8G8B */
744 for (row
= 0; row
< height
; row
++) {
746 for (col
= 0; col
< width
; col
++) {
747 const GLuint pixel
= ((const GLuint
*) src
)[col
];
756 else if (format
== GL_RGBA
&& type
== GL_UNSIGNED_BYTE
) {
757 /* directly memcpy 8A8R8G8B pixels into client's buffer */
758 const GLint widthInBytes
= width
* 4;
760 for (row
= 0; row
< height
; row
++) {
761 MEMCPY(dst
, src
, widthInBytes
);
766 else if (format
== GL_RGB
&& type
== GL_UNSIGNED_SHORT_5_6_5
) {
767 /* convert 8A8R8G8B into 5R5G5B */
770 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
772 _swrast_ReadPixels(ctx
, x
, y
, width
, height
, format
, type
,
777 grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->currentFB
);
785 fxDDFinish(GLcontext
* ctx
)
794 /* KW: Put the word Mesa in the render string because quakeworld
795 * checks for this rather than doing a glGet(GL_MAX_TEXTURE_SIZE).
798 static const GLubyte
*
799 fxDDGetString(GLcontext
* ctx
, GLenum name
)
805 GrVoodooConfig_t
*vc
= &glbHWConfig
.SSTs
[glbCurrentBoard
].VoodooConfig
;
806 sprintf(buf
, "Mesa %s v0.31 %s %dMB FB, %dMB TM, %d TMU, %s",
807 grGetString(GR_RENDERER
),
808 grGetString(GR_HARDWARE
),
810 (vc
->tmuConfig
[GR_TMU0
].tmuRam
+ ((vc
->nTexelfx
> 1) ? vc
->tmuConfig
[GR_TMU1
].tmuRam
: 0)),
811 (vc
->nTexelfx
* vc
->numChips
),
812 (vc
->numChips
> 1) ? "SLI" : "NOSLI");
813 return (GLubyte
*)buf
;
820 static const struct gl_pipeline_stage
*fx_pipeline
[] = {
821 &_tnl_vertex_transform_stage
, /* TODO: Add the fastpath here */
822 &_tnl_normal_transform_stage
,
823 &_tnl_lighting_stage
,
824 &_tnl_fog_coordinate_stage
, /* TODO: Omit fog stage */
826 &_tnl_texture_transform_stage
,
827 &_tnl_point_attenuation_stage
,
836 fxDDInitFxMesaContext(fxMesaContext fxMesa
)
840 for (i
= 0; i
< 256; i
++) {
841 gl_ubyte_to_float_255_color_tab
[i
] = (float) i
;
844 FX_setupGrVertexLayout();
846 if (getenv("FX_EMULATE_SINGLE_TMU"))
847 fxMesa
->haveTwoTMUs
= GL_FALSE
;
849 if (getenv("FX_GLIDE_SWAPINTERVAL"))
850 fxMesa
->swapInterval
= atoi(getenv("FX_GLIDE_SWAPINTERVAL"));
852 fxMesa
->swapInterval
= 1;
854 if (getenv("MESA_FX_SWAP_PENDING"))
855 fxMesa
->maxPendingSwapBuffers
= atoi(getenv("MESA_FX_SWAP_PENDING"));
857 fxMesa
->maxPendingSwapBuffers
= 2;
859 if (getenv("MESA_FX_INFO"))
860 fxMesa
->verbose
= GL_TRUE
;
862 fxMesa
->verbose
= GL_FALSE
;
864 fxMesa
->color
= 0xffffffff;
868 fxMesa
->stats
.swapBuffer
= 0;
869 fxMesa
->stats
.reqTexUpload
= 0;
870 fxMesa
->stats
.texUpload
= 0;
871 fxMesa
->stats
.memTexUpload
= 0;
873 fxMesa
->tmuSrc
= FX_TMU_NONE
;
874 fxMesa
->lastUnitsMode
= FX_UM_NONE
;
879 fxMesa
->unitsState
.alphaTestEnabled
= GL_FALSE
;
880 fxMesa
->unitsState
.alphaTestFunc
= GR_CMP_ALWAYS
;
881 fxMesa
->unitsState
.alphaTestRefValue
= 0.0;
883 fxMesa
->unitsState
.blendEnabled
= GL_FALSE
;
884 fxMesa
->unitsState
.blendSrcFuncRGB
= GR_BLEND_ONE
;
885 fxMesa
->unitsState
.blendDstFuncRGB
= GR_BLEND_ZERO
;
886 fxMesa
->unitsState
.blendSrcFuncAlpha
= GR_BLEND_ONE
;
887 fxMesa
->unitsState
.blendDstFuncAlpha
= GR_BLEND_ZERO
;
889 fxMesa
->unitsState
.depthTestEnabled
= GL_FALSE
;
890 fxMesa
->unitsState
.depthMask
= GL_TRUE
;
891 fxMesa
->unitsState
.depthTestFunc
= GR_CMP_LESS
;
893 grColorMask(FXTRUE
, fxMesa
->haveAlphaBuffer
? FXTRUE
: FXFALSE
);
894 if (fxMesa
->haveDoubleBuffer
) {
895 fxMesa
->currentFB
= GR_BUFFER_BACKBUFFER
;
896 grRenderBuffer(GR_BUFFER_BACKBUFFER
);
899 fxMesa
->currentFB
= GR_BUFFER_FRONTBUFFER
;
900 grRenderBuffer(GR_BUFFER_FRONTBUFFER
);
903 fxMesa
->state
= malloc(FX_grGetInteger(GR_GLIDE_STATE_SIZE
));
904 fxMesa
->fogTable
= (GrFog_t
*) malloc(FX_grGetInteger(GR_FOG_TABLE_ENTRIES
) *
907 if (!fxMesa
->state
|| !fxMesa
->fogTable
) {
910 if (fxMesa
->fogTable
)
911 free(fxMesa
->fogTable
);
915 if (fxMesa
->haveZBuffer
)
916 grDepthBufferMode(GR_DEPTHBUFFER_ZBUFFER
);
918 grLfbWriteColorFormat(GR_COLORFORMAT_ABGR
);
920 fxMesa
->textureAlign
= FX_grGetInteger(GR_TEXTURE_ALIGN
);
923 int textureSize
= ((fxMesa
->maxTextureSize
> 2048) ? 2048 : fxMesa
->maxTextureSize
);
924 fxMesa
->glCtx
->Const
.MaxTextureLevels
= 0;
926 fxMesa
->glCtx
->Const
.MaxTextureLevels
++;
927 } while ((textureSize
>>= 0x1) & 0x7ff);
929 fxMesa
->glCtx
->Const
.MaxTextureUnits
= fxMesa
->haveTwoTMUs
? 2 : 1;
930 fxMesa
->new_state
= _NEW_ALL
;
932 /* Initialize the software rasterizer and helper modules.
934 _swrast_CreateContext(fxMesa
->glCtx
);
935 _ac_CreateContext(fxMesa
->glCtx
);
936 _tnl_CreateContext(fxMesa
->glCtx
);
937 _swsetup_CreateContext(fxMesa
->glCtx
);
939 /* Install customized pipeline */
940 _tnl_destroy_pipeline(fxMesa
->glCtx
);
941 _tnl_install_pipeline(fxMesa
->glCtx
, fx_pipeline
);
943 fxAllocVB(fxMesa
->glCtx
);
945 fxSetupDDPointers(fxMesa
->glCtx
);
946 fxDDInitTriFuncs(fxMesa
->glCtx
);
948 /* Tell the software rasterizer to use pixel fog always.
950 _swrast_allow_vertex_fog(fxMesa
->glCtx
, GL_FALSE
);
951 _swrast_allow_pixel_fog(fxMesa
->glCtx
, GL_TRUE
);
953 /* Tell tnl not to calculate or use vertex fog factors. (Needed to
954 * tell render stage not to clip fog coords).
956 /* _tnl_calculate_vertex_fog( fxMesa->glCtx, GL_FALSE ); */
958 fxDDInitExtensions(fxMesa
->glCtx
);
960 grGlideGetState((GrState
*) fxMesa
->state
);
968 fxDDDestroyFxMesaContext(fxMesaContext fxMesa
)
970 _swsetup_DestroyContext(fxMesa
->glCtx
);
971 _tnl_DestroyContext(fxMesa
->glCtx
);
972 _ac_DestroyContext(fxMesa
->glCtx
);
973 _swrast_DestroyContext(fxMesa
->glCtx
);
977 if (fxMesa
->fogTable
)
978 free(fxMesa
->fogTable
);
980 fxFreeVB(fxMesa
->glCtx
);
987 fxDDInitExtensions(GLcontext
* ctx
)
989 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
991 /*_mesa_add_extension(ctx, GL_TRUE, "3DFX_set_global_palette", 0);*/
992 _mesa_enable_extension(ctx
, "GL_EXT_point_parameters");
993 _mesa_enable_extension(ctx
, "GL_EXT_paletted_texture");
994 _mesa_enable_extension(ctx
, "GL_EXT_texture_lod_bias");
995 _mesa_enable_extension(ctx
, "GL_EXT_shared_texture_palette");
997 if (fxMesa
->haveTwoTMUs
)
998 _mesa_enable_extension(ctx
, "GL_EXT_texture_env_add");
1000 if (fxMesa
->haveTwoTMUs
)
1001 _mesa_enable_extension(ctx
, "GL_ARB_multitexture");
1005 /************************************************************************/
1006 /************************************************************************/
1007 /************************************************************************/
1009 /* Check if the hardware supports the current context
1011 * Performs similar work to fxDDChooseRenderState() - should be merged.
1014 fx_check_IsInHardware(GLcontext
* ctx
)
1016 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
1018 if (ctx
->RenderMode
!= GL_RENDER
)
1021 if (ctx
->Stencil
.Enabled
||
1022 (ctx
->Color
._DrawDestMask
!= FRONT_LEFT_BIT
&&
1023 ctx
->Color
._DrawDestMask
!= BACK_LEFT_BIT
) ||
1024 ((ctx
->Color
.BlendEnabled
)
1025 && (ctx
->Color
.BlendEquation
!= GL_FUNC_ADD_EXT
))
1026 || ((ctx
->Color
.ColorLogicOpEnabled
)
1027 && (ctx
->Color
.LogicOp
!= GL_COPY
))
1028 || (ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
)
1031 Color
.ColorMask
[RCOMP
] == ctx
->Color
.ColorMask
[GCOMP
])
1032 && (ctx
->Color
.ColorMask
[GCOMP
] == ctx
->Color
.ColorMask
[BCOMP
])
1033 && (ctx
->Color
.ColorMask
[ACOMP
] == ctx
->Color
.ColorMask
[ACOMP
])))
1037 /* Unsupported texture/multitexture cases */
1039 if (fxMesa
->haveTwoTMUs
) {
1040 /* we can only do 2D textures */
1041 if (ctx
->Texture
.Unit
[0]._ReallyEnabled
& ~TEXTURE_2D_BIT
)
1043 if (ctx
->Texture
.Unit
[1]._ReallyEnabled
& ~TEXTURE_2D_BIT
)
1046 if (ctx
->Texture
.Unit
[0]._ReallyEnabled
& TEXTURE_2D_BIT
) {
1047 if (ctx
->Texture
.Unit
[0].EnvMode
== GL_BLEND
&&
1048 (ctx
->Texture
.Unit
[1]._ReallyEnabled
& TEXTURE_2D_BIT
||
1049 ctx
->Texture
.Unit
[0].EnvColor
[0] != 0 ||
1050 ctx
->Texture
.Unit
[0].EnvColor
[1] != 0 ||
1051 ctx
->Texture
.Unit
[0].EnvColor
[2] != 0 ||
1052 ctx
->Texture
.Unit
[0].EnvColor
[3] != 1)) {
1055 if (ctx
->Texture
.Unit
[0]._Current
->Image
[0]->Border
> 0)
1059 if (ctx
->Texture
.Unit
[1]._ReallyEnabled
& TEXTURE_2D_BIT
) {
1060 if (ctx
->Texture
.Unit
[1].EnvMode
== GL_BLEND
)
1062 if (ctx
->Texture
.Unit
[1]._Current
->Image
[0]->Border
> 0)
1066 if (MESA_VERBOSE
& (VERBOSE_DRIVER
| VERBOSE_TEXTURE
))
1067 fprintf(stderr
, "fxMesa: fxIsInHardware, envmode is %s/%s\n",
1068 _mesa_lookup_enum_by_nr(ctx
->Texture
.Unit
[0].EnvMode
),
1069 _mesa_lookup_enum_by_nr(ctx
->Texture
.Unit
[1].EnvMode
));
1071 /* KW: This was wrong (I think) and I changed it... which doesn't mean
1072 * it is now correct...
1073 * BP: The old condition just seemed to test if both texture units
1074 * were enabled. That's easy!
1076 if (ctx
->Texture
._EnabledUnits
== 0x3) {
1077 /* Can't use multipass to blend a multitextured triangle - fall
1080 if (!fxMesa
->haveTwoTMUs
&& ctx
->Color
.BlendEnabled
) {
1084 if ((ctx
->Texture
.Unit
[0].EnvMode
!= ctx
->Texture
.Unit
[1].EnvMode
) &&
1085 (ctx
->Texture
.Unit
[0].EnvMode
!= GL_MODULATE
) &&
1086 (ctx
->Texture
.Unit
[0].EnvMode
!= GL_REPLACE
)) { /* q2, seems ok... */
1087 if (MESA_VERBOSE
& VERBOSE_DRIVER
)
1088 fprintf(stderr
, "fxMesa: unsupported multitex env mode\n");
1094 /* we have just one texture unit */
1095 if (ctx
->Texture
._EnabledUnits
> 0x1) {
1099 if ((ctx
->Texture
.Unit
[0]._ReallyEnabled
& TEXTURE_2D_BIT
) &&
1100 (ctx
->Texture
.Unit
[0].EnvMode
== GL_BLEND
)) {
1111 update_texture_scales(GLcontext
* ctx
)
1113 fxMesaContext fxMesa
= FX_CONTEXT(ctx
);
1114 struct gl_texture_unit
*t0
= &ctx
->Texture
.Unit
[fxMesa
->tmu_source
[0]];
1115 struct gl_texture_unit
*t1
= &ctx
->Texture
.Unit
[fxMesa
->tmu_source
[1]];
1117 if (t0
&& t0
->_Current
&& FX_TEXTURE_DATA(t0
)) {
1118 fxMesa
->s0scale
= FX_TEXTURE_DATA(t0
)->sScale
;
1119 fxMesa
->t0scale
= FX_TEXTURE_DATA(t0
)->tScale
;
1120 fxMesa
->inv_s0scale
= 1.0 / fxMesa
->s0scale
;
1121 fxMesa
->inv_t0scale
= 1.0 / fxMesa
->t0scale
;
1124 if (t1
&& t1
->_Current
&& FX_TEXTURE_DATA(t1
)) {
1125 fxMesa
->s1scale
= FX_TEXTURE_DATA(t1
)->sScale
;
1126 fxMesa
->t1scale
= FX_TEXTURE_DATA(t1
)->tScale
;
1127 fxMesa
->inv_s1scale
= 1.0 / fxMesa
->s1scale
;
1128 fxMesa
->inv_t1scale
= 1.0 / fxMesa
->t1scale
;
1133 fxDDUpdateDDPointers(GLcontext
* ctx
, GLuint new_state
)
1135 /* TNLcontext *tnl = TNL_CONTEXT(ctx);*/
1136 fxMesaContext fxMesa
= FX_CONTEXT(ctx
);
1138 _swrast_InvalidateState(ctx
, new_state
);
1139 _ac_InvalidateState(ctx
, new_state
);
1140 _tnl_InvalidateState(ctx
, new_state
);
1141 _swsetup_InvalidateState(ctx
, new_state
);
1143 /* Recalculate fog table on projection matrix changes. This used to
1144 * be triggered by the NearFar callback.
1146 if (new_state
& _NEW_PROJECTION
)
1147 fxMesa
->new_state
|= FX_NEW_FOG
;
1149 if (new_state
& (_FX_NEW_IS_IN_HARDWARE
|
1150 _FX_NEW_RENDERSTATE
|
1151 _FX_NEW_SETUP_FUNCTION
|
1154 if (new_state
& _FX_NEW_IS_IN_HARDWARE
)
1155 fxCheckIsInHardware(ctx
);
1157 if (fxMesa
->new_state
)
1158 fxSetupFXUnits(ctx
);
1160 if (fxMesa
->is_in_hardware
) {
1161 if (new_state
& _FX_NEW_RENDERSTATE
)
1162 fxDDChooseRenderState(ctx
);
1164 if (new_state
& _FX_NEW_SETUP_FUNCTION
)
1165 fxChooseVertexState(ctx
);
1168 if (new_state
& _NEW_TEXTURE
)
1169 update_texture_scales(ctx
);
1177 fxSetupDDPointers(GLcontext
* ctx
)
1179 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1181 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
1182 fprintf(stderr
, "fxmesa: fxSetupDDPointers()\n");
1185 ctx
->Driver
.UpdateState
= fxDDUpdateDDPointers
;
1186 ctx
->Driver
.GetString
= fxDDGetString
;
1187 ctx
->Driver
.ClearIndex
= NULL
;
1188 ctx
->Driver
.ClearColor
= fxDDClearColor
;
1189 ctx
->Driver
.Clear
= fxDDClear
;
1190 ctx
->Driver
.DrawBuffer
= fxDDSetDrawBuffer
;
1191 ctx
->Driver
.GetBufferSize
= fxDDBufferSize
;
1192 ctx
->Driver
.Accum
= _swrast_Accum
;
1193 ctx
->Driver
.Bitmap
= fxDDDrawBitmap
;
1194 ctx
->Driver
.CopyPixels
= _swrast_CopyPixels
;
1195 ctx
->Driver
.DrawPixels
= _swrast_DrawPixels
;
1197 fxMesaContext fxMesa
= (fxMesaContext
) ctx
->DriverCtx
;
1198 switch (fxMesa
->colDepth
) {
1200 ctx
->Driver
.ReadPixels
= fxDDReadPixels555
;
1203 ctx
->Driver
.ReadPixels
= fxDDReadPixels
;
1206 ctx
->Driver
.ReadPixels
= fxDDReadPixels888
;
1210 ctx
->Driver
.ResizeBuffers
= _swrast_alloc_buffers
;
1211 ctx
->Driver
.Finish
= fxDDFinish
;
1212 ctx
->Driver
.Flush
= NULL
;
1213 ctx
->Driver
.ChooseTextureFormat
= fxDDChooseTextureFormat
;
1214 ctx
->Driver
.TexImage1D
= _mesa_store_teximage1d
;
1215 ctx
->Driver
.TexImage2D
= fxDDTexImage2D
;
1216 ctx
->Driver
.TexImage3D
= _mesa_store_teximage3d
;
1217 ctx
->Driver
.TexSubImage1D
= _mesa_store_texsubimage1d
;
1218 ctx
->Driver
.TexSubImage2D
= fxDDTexSubImage2D
;
1219 ctx
->Driver
.TexSubImage3D
= _mesa_store_texsubimage3d
;
1220 ctx
->Driver
.CompressedTexImage1D
= _mesa_store_compressed_teximage1d
;
1221 ctx
->Driver
.CompressedTexImage2D
= _mesa_store_compressed_teximage2d
;
1222 ctx
->Driver
.CompressedTexImage3D
= _mesa_store_compressed_teximage3d
;
1223 ctx
->Driver
.CompressedTexSubImage1D
= _mesa_store_compressed_texsubimage1d
;
1224 ctx
->Driver
.CompressedTexSubImage2D
= _mesa_store_compressed_texsubimage2d
;
1225 ctx
->Driver
.CompressedTexSubImage3D
= _mesa_store_compressed_texsubimage3d
;
1226 ctx
->Driver
.CopyTexImage1D
= _swrast_copy_teximage1d
;
1227 ctx
->Driver
.CopyTexImage2D
= _swrast_copy_teximage2d
;
1228 ctx
->Driver
.CopyTexSubImage1D
= _swrast_copy_texsubimage1d
;
1229 ctx
->Driver
.CopyTexSubImage2D
= _swrast_copy_texsubimage2d
;
1230 ctx
->Driver
.CopyTexSubImage3D
= _swrast_copy_texsubimage3d
;
1231 ctx
->Driver
.TestProxyTexImage
= _mesa_test_proxy_teximage
;
1232 ctx
->Driver
.CopyColorTable
= _swrast_CopyColorTable
;
1233 ctx
->Driver
.CopyColorSubTable
= _swrast_CopyColorSubTable
;
1234 ctx
->Driver
.CopyConvolutionFilter1D
= _swrast_CopyConvolutionFilter1D
;
1235 ctx
->Driver
.CopyConvolutionFilter2D
= _swrast_CopyConvolutionFilter2D
;
1236 ctx
->Driver
.TexEnv
= fxDDTexEnv
;
1237 ctx
->Driver
.TexParameter
= fxDDTexParam
;
1238 ctx
->Driver
.BindTexture
= fxDDTexBind
;
1239 ctx
->Driver
.DeleteTexture
= fxDDTexDel
;
1240 ctx
->Driver
.UpdateTexturePalette
= fxDDTexPalette
;
1241 ctx
->Driver
.AlphaFunc
= fxDDAlphaFunc
;
1242 ctx
->Driver
.BlendFunc
= fxDDBlendFunc
;
1243 ctx
->Driver
.DepthFunc
= fxDDDepthFunc
;
1244 ctx
->Driver
.DepthMask
= fxDDDepthMask
;
1245 ctx
->Driver
.ColorMask
= fxDDColorMask
;
1246 ctx
->Driver
.Fogfv
= fxDDFogfv
;
1247 ctx
->Driver
.Scissor
= fxDDScissor
;
1248 ctx
->Driver
.FrontFace
= fxDDFrontFace
;
1249 ctx
->Driver
.CullFace
= fxDDCullFace
;
1250 ctx
->Driver
.ShadeModel
= fxDDShadeModel
;
1251 ctx
->Driver
.Enable
= fxDDEnable
;
1253 tnl
->Driver
.RunPipeline
= _tnl_run_pipeline
;
1255 fxSetupDDSpanPointers(ctx
);
1256 fxDDUpdateDDPointers(ctx
, ~0);
1264 * Need this to provide at least one external definition.
1267 extern int gl_fx_dummy_function_dd(void);
1269 gl_fx_dummy_function_dd(void)