OSDN Git Service

add tdfx DRI driver
authorAlan Hourihane <alanh@tungstengraphics.com>
Thu, 4 Dec 2003 13:27:05 +0000 (13:27 +0000)
committerAlan Hourihane <alanh@tungstengraphics.com>
Thu, 4 Dec 2003 13:27:05 +0000 (13:27 +0000)
33 files changed:
src/mesa/drivers/dri/tdfx/BUGS [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/Makefile.X11 [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fastpath.S [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fasttmp.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/dri_glide.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_context.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_context.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_dd.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_dd.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_glide.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_lock.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_lock.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_pixels.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_pixels.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_render.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_render.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_screen.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_screen.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_span.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_span.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_state.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_state.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_tex.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_tex.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_texman.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_texman.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_texstate.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_texstate.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_tris.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_tris.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_vb.c [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_vb.h [new file with mode: 0644]
src/mesa/drivers/dri/tdfx/tdfx_vbtmp.h [new file with mode: 0644]

diff --git a/src/mesa/drivers/dri/tdfx/BUGS b/src/mesa/drivers/dri/tdfx/BUGS
new file mode 100644 (file)
index 0000000..b15f6a9
--- /dev/null
@@ -0,0 +1,64 @@
+REMOVE THIS FILE BEFORE MERGING WITH TRUNK
+------------------------------------------
+
+OUTSTANDING BUGS
+
+demos/reflect - reading back Z on Voodoo3, image offset to right
+       Fixed in latest Glide.
+
+Q3 - some polygons drawn as vertical strips, similar to bug that was
+       seen in demos/fire.  Voodoo3 only.  May be related to glDepthMask
+       or glColorMask.
+
+book/fog - not fogging
+       Fog in orthograph mode still not implemented.  Checking with
+       3dfx engineers for ideas.
+
+Q3 demo crashes after changing display settings
+       but the full Q3 game version seems OK.
+
+
+
+MORE OUTSTANDING BUGS
+
+private context was NULL! causing immediate failure of any glx prog. cant
+reproduce after restarting the X server. putting it down as halluc.
+
+texture object image was NULL, causing segmentation failure. happens with
+prboom. ive put a check in tdfx_texstate.c but this isn't a fix.
+
+prboom, wall textures near first chainsaw aren't bound properly. sideways
+movements causes the wall textures to move with you. prboom busted?
+
+16bpp mode, quake3, windowed, q3dm1, floor under rocketlauncher bands. it
+looks like multitexturing gone wrong. i'll disable a tmu and test.
+
+sof, polygons appear at wrong x,y,z positions, intermittent, have not yet
+found reliable way of reproducing. culling? sometimes polys disappear.
+
+descent3 is all black in 16bpp mode - FIXED (palette problems)
+
+smeared pixels in quake3 - FIXED (texture memory overlapped FB)
+
+
+
+PERFORMANCE COMPARISON  (Brian / Alan)
+
+  V3/16  is Voodoo3 in 16bpp on a P3/500
+  V5/16  is Voodoo5 in 16bpp on a P3/600
+  V5/32  is Voodoo5 in 32bpp on a P3/600
+  V5A/16 is Voodoo5 in 16bpp on an Alpha AXP/600
+  V5A/32 is Voodoo5 in 32bpp on an Alpha AXP/600
+
+                  tdfx-2-1-branch               tdfx-3-0-0-branch
+demo             V3/16 V5/16 V5/32       V3/16 V5/16 V5/32 V5A/16 V5A/32
+------------------------------------------------------------------------
+gloss             257   183   174         320    308  177   313    167
+fire               42                      39                52     41
+fire (no help)     98    80    50         106    113   73   124     80
+tunnel             61                      50                70     58
+tunnel (no help)  167   142    57         138    152  113   171    122
+gears             663   554   540         881   1232  776  1484    830
+teapot             20                      21                37     36
+teapot (no help)   22    14    14          24     30   30    43     42
+
diff --git a/src/mesa/drivers/dri/tdfx/Makefile.X11 b/src/mesa/drivers/dri/tdfx/Makefile.X11
new file mode 100644 (file)
index 0000000..b05717f
--- /dev/null
@@ -0,0 +1,128 @@
+
+# Mesa 3-D graphics library
+# Version:  5.0
+# Copyright (C) 1995-2002  Brian Paul
+
+TOP = ../../../../..
+
+default: linux-solo
+
+SHARED_INCLUDES = $(INCLUDE_DIRS) -I. -I../common -Iserver
+MINIGLX_INCLUDES = -I$(TOP)/src/glx/mini
+
+DEFINES += \
+       -D_HAVE_SWRAST=1 \
+       -D_HAVE_SWTNL=1 \
+       -D_HAVE_SANITY=1 \
+       -D_HAVE_CODEGEN=1 \
+       -D_HAVE_LIGHTING=1 \
+       -D_HAVE_TEXGEN=1 \
+       -D_HAVE_USERCLIP=1 \
+       -DGLX_DIRECT_RENDERING 
+
+# not yet
+# MINIGLX_SOURCES = server/tdfx_dri.c 
+
+DRIVER_SOURCES = tdfx_context.c \
+                ../common/mm.c \
+                ../common/utils.c \
+                ../common/texmem.c \
+                ../common/vblank.c \
+                ../common/xmlconfig.c \
+                tdfx_dd.c \
+                tdfx_lock.c \
+                tdfx_pixels.c \
+                tdfx_render.c \
+                tdfx_screen.c \
+                tdfx_span.c \
+                tdfx_state.c \
+                tdfx_tex.c \
+                tdfx_texman.c \
+                tdfx_texstate.c \
+                tdfx_tris.c \
+                tdfx_vb.c
+
+INCLUDES = $(MINIGLX_INCLUDES) \
+          $(SHARED_INCLUDES)
+
+
+C_SOURCES = $(DRIVER_SOURCES) \
+           $(MINIGLX_SOURCES) 
+
+MESA_MODULES = $(TOP)/src/mesa/mesa.a
+
+
+ifeq ($(WINDOW_SYSTEM),dri)
+WINOBJ=$(MESABUILDDIR)/dri/dri.a
+WINLIB=
+else
+WINOBJ=
+WINLIB=-L$(MESA)/src/glx/mini
+endif
+
+ASM_SOURCES = 
+OBJECTS = $(C_SOURCES:.c=.o) \
+         $(ASM_SOURCES:.S=.o) 
+
+$(SYMLINKS):
+       mkdir -p server
+       cd server
+       rm -f $@ && ln -s ../../radeon/$@ $@
+
+
+### Include directories
+
+INCLUDE_DIRS = \
+       -I$(TOP)/include \
+       -I$(TOP)/src/mesa \
+       -I$(TOP)/src/mesa/main \
+       -I$(TOP)/src/mesa/glapi \
+       -I$(TOP)/src/mesa/math \
+       -I$(TOP)/src/mesa/transform \
+       -I$(TOP)/src/mesa/swrast \
+       -I$(TOP)/src/mesa/swrast_setup
+
+
+##### RULES #####
+
+.c.o:
+       $(CC) -c $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+.S.o:
+       $(CC) -c $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) $(CFLAGS) $(DEFINES)  $< -o $@
+
+
+##### TARGETS #####
+
+targets: depend tdfx_dri.so
+
+tdfx_dri.so:  $(SYMLINKS) $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11
+       rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc $(GL_LIB_DEPS)
+       rm -f $(TOP)/lib/tdfx_dri.so && \
+       install tdfx_dri.so $(TOP)/lib/tdfx_dri.so
+
+$(TOP)/lib/tdfx_dri.so:        tdfx_dri.so
+       rm -f $(TOP)/lib/tdfx_dri.so && \
+       install tdfx_dri.so $(TOP)/lib/tdfx_dri.so
+
+# Run 'make -f Makefile.X11 dep' to update the dependencies if you change
+# what's included by any source file.
+depend: $(C_SOURCES) $(ASM_SOURCES)
+       makedepend -fdepend -Y $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) \
+               $(C_SOURCES) $(ASM_SOURCES)
+
+
+# Emacs tags
+tags:
+       etags `find . -name \*.[ch]` `find ../include`
+
+
+# Remove .o and backup files
+clean:
+       -rm -f *.o */*.o *~ *.o *~ *.so server/*.o
+       -rm -f $(SYMLINKS)
+
+
+include $(TOP)/Make-config
+
+include depend
diff --git a/src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fastpath.S b/src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fastpath.S
new file mode 100644 (file)
index 0000000..0f4cc45
--- /dev/null
@@ -0,0 +1,84 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/X86/fx_3dnow_fastpath.S,v 1.2 2000/09/26 15:56:51 tsi Exp $ */
+
+#include "../../X86/assyntax.h"
+
+#define SETUP_RGBA  0x1
+#define SETUP_TMU0  0x2
+#define SETUP_TMU1  0x4
+
+
+/* Pack either rgba or texture into the remaining half of a 32 byte vertex.
+ */
+#define CLIP_R  24
+#define CLIP_G  16
+#define CLIP_B  20
+#define CLIP_A  28                      /*  defined inf fxdrv.h              */
+
+#define CLIP_S0 16
+#define CLIP_T0 20
+#define CLIP_S1 24
+#define CLIP_T1 28
+
+#define SIZE 4
+#define TYPE (0)
+#define TAG(x) x
+#include "fx_3dnow_fasttmp.h"
+
+#define SIZE 8
+#define TYPE (SETUP_RGBA)
+#define TAG(x) x##_RGBA
+#include "fx_3dnow_fasttmp.h"
+
+#define SIZE 6
+#define TYPE (SETUP_TMU0)
+#define TAG(x) x##_TMU0
+#include "fx_3dnow_fasttmp.h"
+
+#define SIZE 8
+#define TYPE (SETUP_TMU0|SETUP_TMU1)
+#define TAG(x) x##_TMU0_TMU1
+#include "fx_3dnow_fasttmp.h"
+
+#undef CLIP_S1
+#undef CLIP_T1
+#define CLIP_S1 16
+#define CLIP_T1 20
+
+#define SIZE 6
+#define TYPE (SETUP_TMU1)
+#define TAG(x) x##_TMU1
+#include "fx_3dnow_fasttmp.h"
+
+/* These three need to use a full 64 byte clip-space vertex.
+ */
+#undef CLIP_S0
+#undef CLIP_T0
+#undef CLIP_S1
+#undef CLIP_T1
+
+#define CLIP_S0 32
+#define CLIP_T0 36
+#define CLIP_S1 40
+#define CLIP_T1 44
+
+#define SIZE 10
+#define TYPE (SETUP_RGBA|SETUP_TMU0)
+#define TAG(x) x##_RGBA_TMU0
+#include "fx_3dnow_fasttmp.h"
+
+#define SIZE 12
+#define TYPE (SETUP_RGBA|SETUP_TMU0|SETUP_TMU1)
+#define TAG(x) x##_RGBA_TMU0_TMU1
+#include "fx_3dnow_fasttmp.h"
+
+#undef CLIP_S1
+#undef CLIP_T1
+#define CLIP_S1 32
+#define CLIP_T1 36
+
+#define SIZE 10
+#define TYPE (SETUP_RGBA|SETUP_TMU1)
+#define TAG(x) x##_RGBA_TMU1
+#include "fx_3dnow_fasttmp.h"
+
+
diff --git a/src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fasttmp.h b/src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fasttmp.h
new file mode 100644 (file)
index 0000000..9ec4935
--- /dev/null
@@ -0,0 +1,314 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/X86/fx_3dnow_fasttmp.h,v 1.2 2000/09/26 15:56:51 tsi Exp $ */
+
+#if !defined(NASM_ASSEMBLER) && !defined(MASM_ASSEMBLER)
+#define TAGLLBL(a) TAG(.L##a)
+#else
+#define TAGLLBL(a) TAG(a)
+#endif
+
+#if !GLIDE3
+
+#define GR_VERTEX_X_OFFSET              0
+#define GR_VERTEX_Y_OFFSET              4
+#define GR_VERTEX_Z_OFFSET              8
+#define GR_VERTEX_R_OFFSET              12
+#define GR_VERTEX_G_OFFSET              16
+#define GR_VERTEX_B_OFFSET              20
+#define GR_VERTEX_OOZ_OFFSET            24
+#define GR_VERTEX_A_OFFSET              28
+#define GR_VERTEX_OOW_OFFSET            32
+
+#else /* GLIDE3 */
+
+#define GR_VERTEX_X_OFFSET              0
+#define GR_VERTEX_Y_OFFSET              4
+#define GR_VERTEX_OOZ_OFFSET            8
+#define GR_VERTEX_OOW_OFFSET            12
+#define GR_VERTEX_R_OFFSET              16
+#define GR_VERTEX_G_OFFSET              20
+#define GR_VERTEX_B_OFFSET              24
+#define GR_VERTEX_A_OFFSET              28
+#define GR_VERTEX_Z_OFFSET              32
+
+#endif /* GLIDE3 */
+
+#define GR_VERTEX_SOW_TMU0_OFFSET       36
+#define GR_VERTEX_TOW_TMU0_OFFSET       40
+#define GR_VERTEX_OOW_TMU0_OFFSET       44
+#define GR_VERTEX_SOW_TMU1_OFFSET       48
+#define GR_VERTEX_TOW_TMU1_OFFSET       52
+#define GR_VERTEX_OOW_TMU1_OFFSET       56
+
+
+
+
+/*#define MAT_SX 0        /*  accessed by REGIND !! */
+#define MAT_SY 20
+#define MAT_SZ 40
+#define MAT_TX 48
+#define MAT_TY 52
+#define MAT_TZ 56
+
+
+
+
+/* Do viewport map, device scale and perspective projection.
+ *
+ * void project_verts( GLfloat *first,
+ *                    GLfloat *last,
+ *                    const GLfloat *m,
+ *                    GLuint stride )
+ *
+ *
+ * Rearrange fxVertices to look like grVertices.
+ */
+
+GLOBL GLNAME( TAG(fx_3dnow_project_vertices) )
+GLNAME( TAG(fx_3dnow_project_vertices) ):
+
+    PUSH_L    ( EBP )
+
+    MOV_L     ( REGOFF(8, ESP), ECX )    /* first_vert */
+    MOV_L     ( REGOFF(12, ESP), EDX )     /* last_vert */
+
+    CMP_L     ( ECX, EDX )
+    JE        ( TAGLLBL(FXPV_end) )
+
+    FEMMS
+
+    PREFETCH  ( REGIND(ECX) )         /* fetch the first vertex */
+
+    MOV_L     ( REGOFF(16, ESP), EBP )     /* matrix */
+    MOV_L     ( REGOFF(20, ESP), EAX )     /* stride */
+
+    MOVD      ( REGOFF(MAT_TX, EBP), MM6 )      /*             | tx           */
+    PUNPCKLDQ ( REGOFF(MAT_TY, EBP), MM6 )      /*  ty         | tx           */
+
+#if !defined(FX_V2)
+    MOV_L     ( CONST(0x49400000), REGOFF(-8, ESP) )    /*  snapper           */
+    MOV_L     ( CONST(0x49400000), REGOFF(-4, ESP) )    /*  snapper           */
+#endif
+
+    MOVQ      ( REGOFF(-8, ESP), MM4 )          /*  snapper    | snapper      */
+    PFADD     ( MM4, MM6 )                      /*  ty+snapper | tx+snapper   */
+
+    MOVD      ( REGIND(EBP), MM5 )
+    PUNPCKLDQ ( REGOFF(MAT_SY, EBP), MM5 )      /*  vsy        | vsx          */
+
+    MOVD      ( REGOFF(MAT_SZ, EBP), MM1 )      /*             | vsz          */
+
+
+ALIGNTEXT32
+TAGLLBL(FXPV_loop_start):
+
+    PREFETCH  ( REGOFF(64, ECX) )               /* fetch the next-ish vertex */
+
+
+    MOVD      ( REGOFF(12, ECX), MM0 )          /*              | f[3]        */
+    PFRCP     ( MM0, MM0 )                      /*  oow = 1/f[3]              */
+
+    MOVD      ( REGOFF(12, ECX), MM7 )          /*              | f[3]        */
+    PFRCPIT1  ( MM0, MM7 )
+    PFRCPIT2  ( MM0, MM7 )                      /*  oow         | oow         */
+
+    PUNPCKLDQ ( MM7, MM7 )
+
+
+#if (TYPE & SETUP_RGBA)
+    MOVD      ( REGOFF(CLIP_R, ECX ), MM0 )     /*  f[RCOORD] = f[CLIP_R];    */
+    MOVD      ( MM0, REGOFF(GR_VERTEX_R_OFFSET, ECX) )
+#endif
+
+#if (TYPE & SETUP_TMU1)
+    MOVQ      ( REGOFF(CLIP_S1, ECX), MM0 ) /* f[S1COORD] = f[CLIP_S1] * oow  */
+    PFMUL     ( MM7, MM0 )                  /* f[T1COORD] = f[CLIP_T1] * oow  */
+    MOVQ      ( MM0, REGOFF(GR_VERTEX_SOW_TMU1_OFFSET, ECX) )
+#endif
+
+
+#if (TYPE & SETUP_TMU0)
+    MOVQ      ( REGOFF(CLIP_S0, ECX), MM0 ) /* f[S0COORD] = f[CLIP_S0] * oow  */
+    PFMUL     ( MM7, MM0 )                  /* f[T0COORD] = f[CLIP_T0] * oow  */
+    MOVQ      ( MM0, REGOFF(GR_VERTEX_SOW_TMU0_OFFSET, ECX) )
+#endif
+
+
+
+
+
+/*  DO_SETUP_XYZ */
+
+    MOVQ      ( REGIND(ECX), MM2 )              /*  f[1]        | f[0]        */
+    PFMUL     ( MM7, MM2 )                      /*  f[1] * oow  | f[0] * oow  */
+
+    MOVD      ( REGOFF(8, ECX), MM3 )           /*              | f[2]        */
+    PFMUL     ( MM7, MM3 )                      /*              | f[2] * oow  */
+
+    MOVD      ( REGOFF(MAT_TZ, EBP), MM0 )      /*              | vtz         */
+    PFMUL     ( MM1, MM3 )                      /*              | f[2] *= vsz */
+
+    PFADD     ( MM0, MM3 )                      /*              | f[2] += vtz */
+    PFMUL     ( MM5, MM2 )                      /*  f[1] *= vsy | f[0] *= vsx */
+
+    PFADD     ( MM6, MM2 )                      /*  f[1] += vty | f[0] += vtx */
+
+#if !defined(FX_V2)
+    PFSUB     ( MM4, MM2 )                      /*  f[0,1] -= snapper         */
+#endif
+
+    MOVQ      ( MM2, REGOFF(GR_VERTEX_X_OFFSET, ECX) )
+    MOVD      ( MM3, REGOFF(GR_VERTEX_OOZ_OFFSET, ECX) )
+
+
+/* end of DO_SETUP_XYZ   */
+
+    MOVD      ( MM7, REGOFF(GR_VERTEX_OOW_OFFSET, ECX) ) /* f[OOWCOORD] = oow */
+    ADD_L     ( EAX, ECX )        /* f += stride */
+
+    CMP_L     ( ECX, EDX )     /* stall??? */
+    JA        ( TAGLLBL(FXPV_loop_start) )
+
+TAGLLBL(FXPV_end):
+    FEMMS
+    POP_L     ( EBP )
+    RET
+
+
+
+
+
+
+
+/* void project_verts( GLfloat *first,
+ *                    GLfloat *last,
+ *                    const GLfloat *m,
+ *                    GLuint stride,
+ *                     const GLubyte *mask )
+ *
+ */
+
+GLOBL GLNAME( TAG(fx_3dnow_project_clipped_vertices) )
+GLNAME( TAG(fx_3dnow_project_clipped_vertices) ):
+
+    PUSH_L    ( EBP )
+
+    MOV_L     ( REGOFF(8, ESP), ECX ) /* first FXDRIVER(VB)->verts*/
+    MOV_L     ( REGOFF(12, ESP), EDX ) /* last FXDRIVER(VB)->last_vert  */
+
+    FEMMS
+
+    PUSH_L    ( EDI )
+    PUSH_L    ( ESI )
+
+    PREFETCH  ( REGIND(ECX) )         /* fetch the first vertex */
+
+    MOV_L     ( REGOFF(24, ESP), EBP ) /* mat ctx->Viewport.WindowMap.M */
+    MOV_L     ( REGOFF(28, ESP), EAX )     /* stride */
+    MOV_L     ( REGOFF(32, ESP), ESI ) /* VB->ClipMask       */
+
+    MOVD      ( REGOFF(MAT_TX, EBP), MM6 )      /*             | tx           */
+    PUNPCKLDQ ( REGOFF(MAT_TY, EBP), MM6 )      /*  ty         | tx           */
+
+#if !defined(FX_V2)
+    MOV_L     ( CONST(0x49400000), REGOFF(-8, ESP) )    /*  snapper           */
+    MOV_L     ( CONST(0x49400000), REGOFF(-4, ESP) )    /*  snapper           */
+#endif
+
+    MOVQ      ( REGOFF(-8, ESP), MM4 )          /*  snapper    | snapper      */
+    PFADD     ( MM4, MM6 )                      /*  ty+snapper | tx+snapper   */
+
+    MOVD      ( REGIND(EBP), MM5 )
+    PUNPCKLDQ ( REGOFF(MAT_SY, EBP), MM5 )      /*  vsy        | vsx          */
+
+    MOVD      ( REGOFF(MAT_SZ, EBP), MM1 )      /*             | vsz          */
+
+
+
+ALIGNTEXT32
+TAGLLBL(FXPCV_loop_start):
+
+    PREFETCH  ( REGOFF(64, ECX) )         /* fetch the next-ish vertex */
+
+    CMP_B     ( CONST(0), REGIND(ESI) )
+    JNE       ( TAGLLBL(FXPCV_skip) )
+
+    MOVD      ( REGOFF(12, ECX), MM0)           /*              | f[3]        */
+    PFRCP     ( MM0, MM0 )                      /*  oow = 1/f[3]              */
+
+    MOVD      ( REGOFF(12, ECX), MM7)           /*              | f[3]        */
+    PFRCPIT1  ( MM0, MM7 )
+    PFRCPIT2  ( MM0, MM7 )                      /*  oow         | oow         */
+
+    PUNPCKLDQ ( MM7, MM7 )
+
+
+#if (TYPE & SETUP_RGBA)
+    MOVD      ( REGOFF(CLIP_R, ECX ), MM0 )     /*  f[RCOORD] = f[CLIP_R];    */
+    MOVD      ( MM0, REGOFF(GR_VERTEX_R_OFFSET, ECX) )
+#endif
+
+#if (TYPE & SETUP_TMU1)
+    MOVQ      ( REGOFF(CLIP_S1, ECX), MM0 ) /* f[S1COORD] = f[CLIP_S1] * oow  */
+    PFMUL     ( MM7, MM0 )                  /* f[T1COORD] = f[CLIP_T1] * oow  */
+    MOVQ      ( MM0, REGOFF(GR_VERTEX_SOW_TMU1_OFFSET, ECX) )
+#endif
+
+
+#if (TYPE & SETUP_TMU0)
+    MOVQ      ( REGOFF(CLIP_S0, ECX), MM0 ) /* f[S0COORD] = f[CLIP_S0] * oow  */
+    PFMUL     ( MM7, MM0 )                  /* f[T0COORD] = f[CLIP_T0] * oow  */
+    MOVQ      ( MM0, REGOFF(GR_VERTEX_SOW_TMU0_OFFSET, ECX) )
+#endif
+
+
+
+
+/*  DO_SETUP_XYZ */
+
+    MOVQ      ( REGIND(ECX), MM2 )              /*  f[1]        | f[0]        */
+    PFMUL     ( MM7, MM2 )                      /*  f[1] * oow  | f[0] * oow  */
+
+    MOVD      ( REGOFF(8, ECX), MM3 )           /*              | f[2]        */
+    PFMUL     ( MM7, MM3 )                      /*              | f[2] * oow  */
+
+    MOVD      ( REGOFF(MAT_TZ, EBP), MM0 )      /*              | vtz         */
+    PFMUL     ( MM1, MM3 )                      /*              | f[2] *= vsz */
+
+    PFADD     ( MM0, MM3 )                      /*              | f[2] += vtz */
+    PFMUL     ( MM5, MM2 )                      /*  f[1] *= vsy | f[0] *= vsx */
+
+    PFADD     ( MM6, MM2 )                      /*  f[1] += vty | f[0] += vtx */
+
+#if !defined(FX_V2)
+    PFSUB     ( MM4, MM2 )                      /*  f[0,1] -= snapper         */
+#endif
+
+    MOVQ      ( MM2, REGOFF(GR_VERTEX_X_OFFSET, ECX) )
+    MOVD      ( MM3, REGOFF(GR_VERTEX_OOZ_OFFSET, ECX) )
+
+
+/* end of DO_SETUP_XYZ   */
+
+    MOVD      ( MM7, REGOFF(GR_VERTEX_OOW_OFFSET, ECX) ) /* f[OOWCOORD] = oow */
+
+TAGLLBL(FXPCV_skip):
+    ADD_L     ( EAX, ECX )    /* f += stride     */
+
+    INC_L     ( ESI )                           /*  next ClipMask             */
+    CMP_L     ( ECX, EDX )
+    JA        ( TAGLLBL(FXPCV_loop_start) )
+
+    POP_L     ( ESI )
+    POP_L     ( EDI )
+
+TAGLLBL(FXPCV_end):
+    FEMMS
+    POP_L     ( EBP )
+    RET
+
+
+
+#undef TYPE
+#undef TAG
+#undef SIZE
+
diff --git a/src/mesa/drivers/dri/tdfx/dri_glide.h b/src/mesa/drivers/dri/tdfx/dri_glide.h
new file mode 100644 (file)
index 0000000..0af5601
--- /dev/null
@@ -0,0 +1,63 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/dri_glide.h,v 1.1 2001/03/21 16:14:26 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __DRI_GLIDE_H__
+#define __DRI_GLIDE_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <glide.h>
+#include "dri_mesaint.h"
+
+/*
+ * This is the private interface between Glide and the DRI.
+ */
+extern void grDRIOpen( char *pFB, char *pRegs, int deviceID,
+                      int width, int height,
+                      int mem, int cpp, int stride,
+                      int fifoOffset, int fifoSize,
+                      int fbOffset, int backOffset, int depthOffset,
+                      int textureOffset, int textureSize,
+                      volatile int *fifoPtr, volatile int *fifoRead );
+extern void grDRIPosition( int x, int y, int w, int h,
+                          int numClip, XF86DRIClipRectPtr pClip );
+extern void grDRILostContext( void );
+extern void grDRIImportFifo( int fifoPtr, int fifoRead );
+extern void grDRIInvalidateAll( void );
+extern void grDRIResetSAREA( void );
+extern void grDRIBufferSwap( FxU32 swapInterval );
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_context.c b/src/mesa/drivers/dri/tdfx/tdfx_context.c
new file mode 100644 (file)
index 0000000..f3a7191
--- /dev/null
@@ -0,0 +1,897 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_context.c,v 1.12 2003/05/08 09:25:35 herrb Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#include <dlfcn.h>
+#include "tdfx_context.h"
+#include "tdfx_dd.h"
+#include "tdfx_state.h"
+#include "tdfx_vb.h"
+#include "tdfx_tris.h"
+#include "tdfx_render.h"
+#include "tdfx_span.h"
+#include "tdfx_texman.h"
+#include "extensions.h"
+
+
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "array_cache/acache.h"
+
+#include "tnl/tnl.h"
+#include "tnl/t_pipeline.h"
+
+
+/*
+ * Enable/Disable the extensions for this context.
+ */
+static void tdfxDDInitExtensions( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   _mesa_enable_extension( ctx, "GL_HP_occlusion_test" );
+   _mesa_enable_extension( ctx, "GL_EXT_paletted_texture" );
+   _mesa_enable_extension( ctx, "GL_EXT_texture_lod_bias" );
+
+   if ( fxMesa->haveTwoTMUs ) {
+      _mesa_enable_extension( ctx, "GL_EXT_texture_env_add" );
+      _mesa_enable_extension( ctx, "GL_ARB_multitexture" );
+   }
+
+   if ( TDFX_IS_NAPALM( fxMesa ) ) {
+#if 0
+      _mesa_enable_extension( ctx, "GL_ARB_texture_compression" );
+      _mesa_enable_extension( ctx, "GL_3DFX_texture_compression_FXT1" );
+#endif
+      _mesa_enable_extension( ctx, "GL_EXT_texture_env_combine" );
+   }
+
+#if 0
+   _mesa_enable_extension( ctx, "GL_ARB_texture_cube_map");
+   _mesa_enable_extension( ctx, "GL_NV_texture_rectangle");
+#endif
+
+   if (fxMesa->haveHwStencil) {
+      _mesa_enable_extension( ctx, "GL_EXT_stencil_wrap" );
+   }
+}
+
+
+
+static const struct gl_pipeline_stage *tdfx_pipeline[] = {
+   &_tnl_vertex_transform_stage, 
+   &_tnl_normal_transform_stage, 
+   &_tnl_lighting_stage,       /* REMOVE: fog coord stage */
+   &_tnl_texgen_stage, 
+   &_tnl_texture_transform_stage, 
+                               /* REMOVE: point attenuation stage */
+   &_tnl_render_stage,         
+   0,
+};
+
+
+GLboolean tdfxCreateContext( const __GLcontextModes *mesaVis,
+                            __DRIcontextPrivate *driContextPriv,
+                             void *sharedContextPrivate )
+{
+   tdfxContextPtr fxMesa;
+   GLcontext *ctx, *shareCtx;
+   __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
+   tdfxScreenPrivate *fxScreen = (tdfxScreenPrivate *) sPriv->private;
+   TDFXSAREAPriv *saPriv = (TDFXSAREAPriv *) ((char *) sPriv->pSAREA +
+                                             sizeof(XF86DRISAREARec));
+
+   /* Allocate tdfx context */
+   fxMesa = (tdfxContextPtr) CALLOC( sizeof(tdfxContextRec) );
+   if (!fxMesa)
+      return GL_FALSE;
+
+   /* Allocate the Mesa context */
+   if (sharedContextPrivate)
+      shareCtx = ((tdfxContextPtr) sharedContextPrivate)->glCtx;
+   else 
+      shareCtx = NULL;
+
+   fxMesa->glCtx = _mesa_create_context(mesaVis, shareCtx, (void *) fxMesa, GL_TRUE);
+   if (!fxMesa->glCtx) {
+      FREE(fxMesa);
+      return GL_FALSE;
+   }
+   driContextPriv->driverPrivate = fxMesa;
+
+   /* Mirror some important DRI state
+    */
+   fxMesa->hHWContext = driContextPriv->hHWContext;
+   fxMesa->driHwLock = &sPriv->pSAREA->lock;
+   fxMesa->driFd = sPriv->fd;
+
+   fxMesa->driScreen = sPriv;
+   fxMesa->driContext = driContextPriv;
+   fxMesa->fxScreen = fxScreen;
+   fxMesa->sarea = saPriv;
+
+   fxMesa->haveHwStencil = ( TDFX_IS_NAPALM( fxMesa ) &&
+                            mesaVis->stencilBits &&
+                            mesaVis->depthBits == 24 );
+
+   fxMesa->screen_width = fxScreen->width;
+   fxMesa->screen_height = fxScreen->height;
+
+   fxMesa->new_gl_state = ~0;
+   fxMesa->new_state = ~0;
+   fxMesa->dirty = ~0;
+
+   /* NOTE: This must be here before any Glide calls! */
+   if (!tdfxInitGlide( fxMesa )) {
+      FREE(fxMesa);
+      return GL_FALSE;
+   }
+
+   fxMesa->Glide.grDRIOpen( (char*) sPriv->pFB, fxScreen->regs.map, fxScreen->deviceID,
+             fxScreen->width, fxScreen->height, fxScreen->mem, fxScreen->cpp,
+             fxScreen->stride, fxScreen->fifoOffset, fxScreen->fifoSize,
+             fxScreen->fbOffset, fxScreen->backOffset, fxScreen->depthOffset,
+             fxScreen->textureOffset, fxScreen->textureSize, &saPriv->fifoPtr,
+             &saPriv->fifoRead );
+
+   if ( getenv( "FX_GLIDE_SWAPINTERVAL" ) ) {
+      fxMesa->Glide.SwapInterval = atoi( getenv( "FX_GLIDE_SWAPINTERVAL" ) );
+   } else {
+      fxMesa->Glide.SwapInterval = 0;
+   }
+   if ( getenv( "FX_MAX_PENDING_SWAPS" ) ) {
+      fxMesa->Glide.MaxPendingSwaps = atoi( getenv( "FX_MAX_PENDING_SWAPS" ) );
+   } else {
+      fxMesa->Glide.MaxPendingSwaps = 2;
+   }
+
+   fxMesa->Glide.Initialized = GL_FALSE;
+   fxMesa->Glide.Board = 0;
+
+
+   if (getenv("FX_EMULATE_SINGLE_TMU")) {
+      fxMesa->haveTwoTMUs = GL_FALSE;
+   }
+   else {
+      if ( TDFX_IS_BANSHEE( fxMesa ) ) {
+         fxMesa->haveTwoTMUs = GL_FALSE;
+      } else {
+         fxMesa->haveTwoTMUs = GL_TRUE;
+      }
+   }
+
+   fxMesa->stats.swapBuffer = 0;
+   fxMesa->stats.reqTexUpload = 0;
+   fxMesa->stats.texUpload = 0;
+   fxMesa->stats.memTexUpload = 0;
+
+   fxMesa->tmuSrc = TDFX_TMU_NONE;
+
+   ctx = fxMesa->glCtx;
+   if ( TDFX_IS_NAPALM( fxMesa ) ) {
+      ctx->Const.MaxTextureLevels = 12;
+   } else {
+      ctx->Const.MaxTextureLevels = 9;
+   }
+   ctx->Const.MaxTextureUnits = TDFX_IS_BANSHEE( fxMesa ) ? 1 : 2;
+
+   /* No wide points.
+    */
+   ctx->Const.MinPointSize = 1.0;
+   ctx->Const.MinPointSizeAA = 1.0;
+   ctx->Const.MaxPointSize = 1.0;
+   ctx->Const.MaxPointSizeAA = 1.0;
+
+   /* Disable wide lines as we can't antialias them correctly in
+    * hardware.
+    */
+   ctx->Const.MinLineWidth = 1.0;
+   ctx->Const.MinLineWidthAA = 1.0;
+   ctx->Const.MaxLineWidth = 1.0;
+   ctx->Const.MaxLineWidthAA = 1.0;
+   ctx->Const.LineWidthGranularity = 1.0;
+
+   /* Initialize the software rasterizer and helper modules.
+    */
+   _swrast_CreateContext( ctx );
+   _ac_CreateContext( ctx );
+   _tnl_CreateContext( ctx );
+   _swsetup_CreateContext( ctx );
+
+   /* Install the customized pipeline:
+    */
+   _tnl_destroy_pipeline( ctx );
+   _tnl_install_pipeline( ctx, tdfx_pipeline );
+
+   /* Configure swrast to match hardware characteristics:
+    */
+   _swrast_allow_pixel_fog( ctx, GL_TRUE );
+   _swrast_allow_vertex_fog( ctx, GL_FALSE );
+
+   tdfxDDInitExtensions( ctx );
+   tdfxDDInitDriverFuncs( ctx );
+   tdfxDDInitStateFuncs( ctx );
+   tdfxDDInitRenderFuncs( ctx );
+   tdfxDDInitSpanFuncs( ctx ); 
+   tdfxDDInitTriFuncs( ctx );
+   tdfxInitVB( ctx );
+   tdfxInitState( fxMesa );
+
+   return GL_TRUE;
+}
+
+
+static GLboolean tdfxInitVertexFormats( tdfxContextPtr fxMesa )
+{
+   FxI32 result;
+   int i;
+
+   LOCK_HARDWARE( fxMesa );
+
+   fxMesa->Glide.grGet( GR_GLIDE_VERTEXLAYOUT_SIZE, sizeof(FxI32), &result );
+   for ( i = 0 ; i < TDFX_NUM_LAYOUTS ; i++ ) {
+      fxMesa->layout[i] = MALLOC( result );
+      if ( !fxMesa->layout[i] ) {
+        UNLOCK_HARDWARE( fxMesa );
+        return GL_FALSE;
+      }
+   }
+
+   /* Tiny vertex format - 16 bytes.
+    */
+   fxMesa->Glide.grReset( GR_VERTEX_PARAMETER );
+   fxMesa->Glide.grCoordinateSpace( GR_WINDOW_COORDS );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_XY,  TDFX_XY_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Z, TDFX_Z_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_PARGB, TDFX_Q_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grGlideGetVertexLayout( fxMesa->layout[TDFX_LAYOUT_TINY] );
+
+   /* Non textured vertex format - 24 bytes (Need w for table fog)
+    */
+   fxMesa->Glide.grReset( GR_VERTEX_PARAMETER );
+   fxMesa->Glide.grCoordinateSpace( GR_WINDOW_COORDS );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_XY,  TDFX_XY_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Z, TDFX_Z_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Q, TDFX_Q_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_PARGB, TDFX_ARGB_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grGlideGetVertexLayout( fxMesa->layout[TDFX_LAYOUT_NOTEX] );
+
+   /* Single textured vertex format - 32 bytes.
+    */
+   fxMesa->Glide.grReset( GR_VERTEX_PARAMETER );
+   fxMesa->Glide.grCoordinateSpace( GR_WINDOW_COORDS );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_XY,  TDFX_XY_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Z, TDFX_Z_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Q, TDFX_Q_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_PARGB, TDFX_ARGB_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_ST0, TDFX_ST0_OFFSET, GR_PARAM_ENABLE );
+   /*grVertexLayout( GR_PARAM_FOG_EXT, TDFX_FOG_OFFSET, GR_PARAM_ENABLE );*/
+   fxMesa->Glide.grGlideGetVertexLayout( fxMesa->layout[TDFX_LAYOUT_SINGLE] );
+
+   /* Multitextured vertex format - 40 bytes.
+    */
+   fxMesa->Glide.grReset( GR_VERTEX_PARAMETER );
+   fxMesa->Glide.grCoordinateSpace( GR_WINDOW_COORDS );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_XY, TDFX_XY_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Z, TDFX_Z_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Q, TDFX_Q_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_PARGB, TDFX_ARGB_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_ST0, TDFX_ST0_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_ST1, TDFX_ST1_OFFSET, GR_PARAM_ENABLE );
+   /*fxMesa->Glide.grVertexLayout( GR_PARAM_FOG_EXT, TDFX_FOG_OFFSET, GR_PARAM_ENABLE );*/
+   fxMesa->Glide.grGlideGetVertexLayout( fxMesa->layout[TDFX_LAYOUT_MULTI] );
+
+   /* Projected texture vertex format - 48 bytes.
+    */
+   fxMesa->Glide.grReset( GR_VERTEX_PARAMETER );
+   fxMesa->Glide.grCoordinateSpace( GR_WINDOW_COORDS );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_XY, TDFX_XY_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Z, TDFX_Z_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Q, TDFX_Q_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_PARGB, TDFX_ARGB_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_ST0, TDFX_ST0_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Q0, TDFX_Q0_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_ST1, TDFX_ST1_OFFSET, GR_PARAM_ENABLE );
+   fxMesa->Glide.grVertexLayout( GR_PARAM_Q1, TDFX_Q1_OFFSET, GR_PARAM_ENABLE );
+   /*fxMesa->Glide.grVertexLayout( GR_PARAM_FOG_EXT, TDFX_FOG_OFFSET, GR_PARAM_ENABLE );*/
+   fxMesa->Glide.grGlideGetVertexLayout( fxMesa->layout[TDFX_LAYOUT_PROJECT] );
+
+   UNLOCK_HARDWARE( fxMesa );
+
+   return GL_TRUE;
+}
+
+
+/*
+ * Initialize the state in an tdfxContextPtr struct.
+ */
+static GLboolean
+tdfxInitContext( __DRIdrawablePrivate *driDrawPriv, tdfxContextPtr fxMesa )
+{
+   /* KW: Would be nice to make one of these a member of the other.
+    */
+   FxI32 result[2];
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
+      fprintf( stderr, "%s( %p )\n", __FUNCTION__, fxMesa );
+   }
+
+#if DEBUG_LOCKING
+   fprintf(stderr, "Debug locking enabled\n");
+#endif
+
+   if ( fxMesa->Glide.Initialized )
+      return GL_TRUE;
+
+   fxMesa->width = driDrawPriv->w;
+   fxMesa->height = driDrawPriv->h;
+
+   /* We have to use a light lock here, because we can't do any glide
+    * operations yet. No use of FX_* functions in this function.
+    */
+   DRM_LIGHT_LOCK( fxMesa->driFd, fxMesa->driHwLock, fxMesa->hHWContext );
+
+   fxMesa->Glide.grGlideInit();
+   fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
+
+   fxMesa->Glide.Context = fxMesa->Glide.grSstWinOpen( (FxU32) -1,
+                                        GR_RESOLUTION_NONE,
+                                        GR_REFRESH_NONE,
+                                        fxMesa->Glide.ColorFormat,
+                                        fxMesa->Glide.Origin,
+                                        2, 1 );
+
+   fxMesa->Glide.grDRIResetSAREA();
+
+   DRM_UNLOCK( fxMesa->driFd, fxMesa->driHwLock, fxMesa->hHWContext );
+
+   if ( !fxMesa->Glide.Context )
+      return GL_FALSE;
+
+
+   /* Perform the Glide-dependant part of the context initialization.
+    */
+   FX_grColorMaskv( fxMesa->glCtx, true4 );
+
+   tdfxTMInit( fxMesa );
+
+   LOCK_HARDWARE( fxMesa );
+
+   if ( fxMesa->glCtx->Visual.depthBits > 0 ) {
+      fxMesa->Glide.grDepthBufferMode(GR_DEPTHBUFFER_ZBUFFER);
+   } else {
+      fxMesa->Glide.grDepthBufferMode(GR_DEPTHBUFFER_DISABLE);
+   }
+
+   fxMesa->Glide.grLfbWriteColorFormat( GR_COLORFORMAT_ABGR );
+
+   fxMesa->Glide.grGet( GR_TEXTURE_ALIGN, sizeof(FxI32), result );
+   fxMesa->Glide.TextureAlign = result[0];
+
+   fxMesa->Glide.State = NULL;
+   fxMesa->Glide.grGet( GR_GLIDE_STATE_SIZE, sizeof(FxI32), result );
+   fxMesa->Glide.State = MALLOC( result[0] );
+
+   fxMesa->Fog.Table = NULL;
+   fxMesa->Glide.grGet( GR_FOG_TABLE_ENTRIES, sizeof(FxI32), result );
+   fxMesa->Fog.Table = MALLOC( result[0] * sizeof(GrFog_t) );
+
+   UNLOCK_HARDWARE( fxMesa );
+
+   if ( !fxMesa->Glide.State || !fxMesa->Fog.Table ) {
+      if ( fxMesa->Glide.State )
+        FREE( fxMesa->Glide.State );
+      if ( fxMesa->Fog.Table )
+        FREE( fxMesa->Fog.Table );
+      return GL_FALSE;
+   }
+
+   if ( !tdfxInitVertexFormats( fxMesa ) ) {
+      return GL_FALSE;
+   }
+
+   LOCK_HARDWARE( fxMesa );
+
+   fxMesa->Glide.grGlideGetState( fxMesa->Glide.State );
+
+   if ( getenv( "FX_GLIDE_INFO" ) ) {
+      printf( "GR_RENDERER  = %s\n", (char *) fxMesa->Glide.grGetString( GR_RENDERER ) );
+      printf( "GR_VERSION   = %s\n", (char *) fxMesa->Glide.grGetString( GR_VERSION ) );
+      printf( "GR_VENDOR    = %s\n", (char *) fxMesa->Glide.grGetString( GR_VENDOR ) );
+      printf( "GR_HARDWARE  = %s\n", (char *) fxMesa->Glide.grGetString( GR_HARDWARE ) );
+      printf( "GR_EXTENSION = %s\n", (char *) fxMesa->Glide.grGetString( GR_EXTENSION ) );
+   }
+
+   UNLOCK_HARDWARE( fxMesa );
+
+   {
+      const char *debug = getenv("LIBGL_DEBUG");
+      if (debug && strstr(debug, "fallbacks")) {
+         fxMesa->debugFallbacks = GL_TRUE;
+      }
+   }
+
+
+   fxMesa->numClipRects = 0;
+   fxMesa->pClipRects = NULL;
+   fxMesa->scissoredClipRects = GL_FALSE;
+
+   fxMesa->Glide.Initialized = GL_TRUE;
+
+   return GL_TRUE;
+}
+
+
+void
+tdfxDestroyContext( __DRIcontextPrivate *driContextPriv )
+{
+   tdfxContextPtr fxMesa = (tdfxContextPtr) driContextPriv->driverPrivate;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
+      fprintf( stderr, "%s( %p )\n", __FUNCTION__, fxMesa );
+   }
+
+   if ( fxMesa ) {
+      if (fxMesa->glCtx->Shared->RefCount == 1 && fxMesa->driDrawable) {
+         /* This share group is about to go away, free our private
+          * texture object data.
+          */
+         struct gl_texture_object *tObj;
+         tObj = fxMesa->glCtx->Shared->TexObjectList;
+         while (tObj) {
+            tdfxTMFreeTexture(fxMesa, tObj);
+            tObj = tObj->Next;
+         }
+      }
+
+      tdfxTMClose(fxMesa);  /* free texture memory */
+
+      _swsetup_DestroyContext( fxMesa->glCtx );
+      _tnl_DestroyContext( fxMesa->glCtx );
+      _ac_DestroyContext( fxMesa->glCtx );
+      _swrast_DestroyContext( fxMesa->glCtx );
+
+      tdfxFreeVB( fxMesa->glCtx );
+
+      /* Free Mesa context */
+      fxMesa->glCtx->DriverCtx = NULL;
+      _mesa_destroy_context(fxMesa->glCtx);
+
+      /* free the tdfx context */
+      XFree( fxMesa );
+   }
+}
+
+
+GLboolean
+tdfxUnbindContext( __DRIcontextPrivate *driContextPriv )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
+      fprintf( stderr, "%s( %p )\n", __FUNCTION__, driContextPriv );
+   }
+
+   if ( driContextPriv && (tdfxContextPtr) driContextPriv == fxMesa ) {
+      LOCK_HARDWARE(fxMesa);
+      fxMesa->Glide.grGlideGetState(fxMesa->Glide.State);
+      UNLOCK_HARDWARE(fxMesa);
+   }
+   return GL_TRUE;
+}
+
+
+GLboolean
+tdfxMakeCurrent( __DRIcontextPrivate *driContextPriv,
+                 __DRIdrawablePrivate *driDrawPriv,
+                 __DRIdrawablePrivate *driReadPriv )
+{
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
+      fprintf( stderr, "%s( %p )\n", __FUNCTION__, driContextPriv );
+   }
+
+   if ( driContextPriv ) {
+      tdfxContextPtr newFx = (tdfxContextPtr) driContextPriv->driverPrivate;
+      GLcontext *newCtx = newFx->glCtx;
+      GET_CURRENT_CONTEXT(curCtx);
+
+      if ( newFx->driDrawable != driDrawPriv ) {
+        newFx->driDrawable = driDrawPriv;
+        newFx->dirty = ~0;
+      }
+      else if (curCtx == newCtx) {
+         /* same drawable, same context -> no-op */
+         /* Need to call _mesa_make_current2() in order to make sure API
+          * dispatch is set correctly.
+          */
+         _mesa_make_current2( newCtx,
+                              (GLframebuffer *) driDrawPriv->driverPrivate,
+                              (GLframebuffer *) driReadPriv->driverPrivate );
+         return GL_TRUE;
+      }
+
+      if ( !newFx->Glide.Initialized ) {
+        if ( !tdfxInitContext( driDrawPriv, newFx ) )
+           return GL_FALSE;
+
+        LOCK_HARDWARE( newFx );
+
+        /* FIXME: Force loading of window information */
+        newFx->width = 0;
+         tdfxUpdateClipping(newCtx);
+         tdfxUploadClipping(newFx);
+
+        UNLOCK_HARDWARE( newFx );
+      } else {
+        LOCK_HARDWARE( newFx );
+
+        newFx->Glide.grSstSelect( newFx->Glide.Board );
+        newFx->Glide.grGlideSetState( newFx->Glide.State );
+
+         tdfxUpdateClipping(newCtx);
+         tdfxUploadClipping(newFx);
+
+        UNLOCK_HARDWARE( newFx );
+      }
+
+      _mesa_make_current2( newCtx,
+                           (GLframebuffer *) driDrawPriv->driverPrivate,
+                           (GLframebuffer *) driReadPriv->driverPrivate );
+
+      if ( !newCtx->Viewport.Width ) {
+        _mesa_set_viewport( newCtx, 0, 0, driDrawPriv->w, driDrawPriv->h );
+      }
+   } else {
+      _mesa_make_current( 0, 0 );
+   }
+
+   return GL_TRUE;
+}
+
+
+/*
+ * Enable this to trace calls to various Glide functions.
+ */
+/*#define DEBUG_TRAP*/
+#ifdef DEBUG_TRAP
+static void (*real_grDrawTriangle)( const void *a, const void *b, const void *c );
+static void (*real_grDrawPoint)( const void *a );
+static void (*real_grDrawVertexArray)(FxU32 mode, FxU32 Count, void *pointers);
+static void (*real_grDrawVertexArrayContiguous)(FxU32 mode, FxU32 Count,
+                                       void *pointers, FxU32 stride);
+static void (*real_grClipWindow)( FxU32 minx, FxU32 miny, FxU32 maxx, FxU32 maxy );
+
+static void (*real_grVertexLayout)(FxU32 param, FxI32 offset, FxU32 mode);
+static void (*real_grGlideGetVertexLayout)( void *layout );
+static void (*real_grGlideSetVertexLayout)( const void *layout );
+
+static void (*real_grTexDownloadMipMapLevel)( GrChipID_t        tmu,
+                                     FxU32             startAddress,
+                                     GrLOD_t           thisLod,
+                                     GrLOD_t           largeLod,
+                                     GrAspectRatio_t   aspectRatio,
+                                     GrTextureFormat_t format,
+                                     FxU32             evenOdd,
+                                              void              *data );
+
+
+static void debug_grDrawTriangle( const void *a, const void *b, const void *c )
+{
+   printf("%s\n", __FUNCTION__);
+   (*real_grDrawTriangle)(a, b, c);
+}
+
+static void debug_grDrawPoint( const void *a )
+{
+   const float *f = (const float *) a;
+   printf("%s %g %g\n", __FUNCTION__, f[0], f[1]);
+   (*real_grDrawPoint)(a);
+}
+
+static void debug_grDrawVertexArray(FxU32 mode, FxU32 Count, void *pointers)
+{
+   printf("%s count=%d\n", __FUNCTION__, (int) Count);
+   (*real_grDrawVertexArray)(mode, Count, pointers);
+}
+
+static void debug_grDrawVertexArrayContiguous(FxU32 mode, FxU32 Count,
+                                       void *pointers, FxU32 stride)
+{
+   printf("%s mode=0x%x count=%d\n", __FUNCTION__, (int) mode, (int) Count);
+   (*real_grDrawVertexArrayContiguous)(mode, Count, pointers, stride);
+}
+
+static void debug_grClipWindow( FxU32 minx, FxU32 miny, FxU32 maxx, FxU32 maxy )
+{
+   printf("%s %d,%d .. %d,%d\n", __FUNCTION__,
+          (int) minx, (int) miny, (int) maxx, (int) maxy);
+   (*real_grClipWindow)(minx, miny, maxx, maxy);
+}
+
+static void debug_grVertexLayout(FxU32 param, FxI32 offset, FxU32 mode)
+{
+   (*real_grVertexLayout)(param, offset, mode);
+}
+
+static void debug_grGlideGetVertexLayout( void *layout )
+{
+   (*real_grGlideGetVertexLayout)(layout);
+}
+
+static void debug_grGlideSetVertexLayout( const void *layout )
+{
+   (*real_grGlideSetVertexLayout)(layout);
+}
+
+static void debug_grTexDownloadMipMapLevel( GrChipID_t        tmu,
+                                     FxU32             startAddress,
+                                     GrLOD_t           thisLod,
+                                     GrLOD_t           largeLod,
+                                     GrAspectRatio_t   aspectRatio,
+                                     GrTextureFormat_t format,
+                                     FxU32             evenOdd,
+                                     void              *data )
+{
+   (*real_grTexDownloadMipMapLevel)(tmu, startAddress, thisLod, largeLod,
+                                    aspectRatio, format, evenOdd, data);
+}
+
+#endif
+
+
+/*
+ * Examine the context's deviceID to determine what kind of 3dfx hardware
+ * is installed.  dlopen() the appropriate Glide library and initialize
+ * this context's Glide function pointers.
+ * Return:  true/false = success/failure
+ */
+GLboolean tdfxInitGlide(tdfxContextPtr tmesa)
+{
+   static const char *defaultGlide = "libglide3.so";
+   const char *libName;
+   void *libHandle;
+
+   /*
+    * XXX this code which selects a Glide library filename given the
+    * deviceID may need to be cleaned up a bit.
+    * Non-Linux systems may have different filenames, for example.
+    */
+   switch (tmesa->fxScreen->deviceID) {
+   case PCI_CHIP_BANSHEE:
+   case PCI_CHIP_VOODOO3:
+      libName = "libglide3-v3.so";
+      break;
+   case PCI_CHIP_VOODOO5:   /* same as PCI_CHIP_VOODOO4 */
+      libName = "libglide3-v5.so";
+      break;
+   default:
+      {
+         __driUtilMessage("unrecognized 3dfx deviceID: 0x%x",
+                 tmesa->fxScreen->deviceID);
+      }
+      return GL_FALSE;
+   }
+
+   libHandle = dlopen(libName, RTLD_NOW);
+   if (!libHandle) {
+      /* The device-specific Glide library filename didn't work, try the
+       * old, generic libglide3.so library.
+       */
+      libHandle = dlopen(defaultGlide, RTLD_NOW); 
+      if (!libHandle) {
+         __driUtilMessage(
+            "can't find Glide library, dlopen(%s) and dlopen(%s) both failed.",
+            libName, defaultGlide);
+         __driUtilMessage("dlerror() message: %s", dlerror());
+         return GL_FALSE;
+      }
+      libName = defaultGlide;
+   }
+
+   {
+      const char *env = getenv("LIBGL_DEBUG");
+      if (env && strstr(env, "verbose")) {
+         fprintf(stderr, "libGL: using Glide library %s\n", libName);
+      }
+   }         
+
+#define GET_FUNCTION(PTR, NAME)                                                \
+   tmesa->Glide.PTR = dlsym(libHandle, NAME);                          \
+   if (!tmesa->Glide.PTR) {                                            \
+      __driUtilMessage("couldn't find Glide function %s in %s.",       \
+              NAME, libName);                                          \
+   }
+
+   GET_FUNCTION(grDrawPoint, "grDrawPoint");
+   GET_FUNCTION(grDrawLine, "grDrawLine");
+   GET_FUNCTION(grDrawTriangle, "grDrawTriangle");
+   GET_FUNCTION(grVertexLayout, "grVertexLayout");
+   GET_FUNCTION(grDrawVertexArray, "grDrawVertexArray");
+   GET_FUNCTION(grDrawVertexArrayContiguous, "grDrawVertexArrayContiguous");
+   GET_FUNCTION(grBufferClear, "grBufferClear");
+   /*GET_FUNCTION(grBufferSwap, "grBufferSwap");*/
+   GET_FUNCTION(grRenderBuffer, "grRenderBuffer");
+   GET_FUNCTION(grErrorSetCallback, "grErrorSetCallback");
+   GET_FUNCTION(grFinish, "grFinish");
+   GET_FUNCTION(grFlush, "grFlush");
+   GET_FUNCTION(grSstWinOpen, "grSstWinOpen");
+   GET_FUNCTION(grSstWinClose, "grSstWinClose");
+#if 0
+   /* Not in V3 lib, and not used anyway. */
+   GET_FUNCTION(grSetNumPendingBuffers, "grSetNumPendingBuffers");
+#endif
+   GET_FUNCTION(grSelectContext, "grSelectContext");
+   GET_FUNCTION(grSstOrigin, "grSstOrigin");
+   GET_FUNCTION(grSstSelect, "grSstSelect");
+   GET_FUNCTION(grAlphaBlendFunction, "grAlphaBlendFunction");
+   GET_FUNCTION(grAlphaCombine, "grAlphaCombine");
+   GET_FUNCTION(grAlphaControlsITRGBLighting, "grAlphaControlsITRGBLighting");
+   GET_FUNCTION(grAlphaTestFunction, "grAlphaTestFunction");
+   GET_FUNCTION(grAlphaTestReferenceValue, "grAlphaTestReferenceValue");
+   GET_FUNCTION(grChromakeyMode, "grChromakeyMode");
+   GET_FUNCTION(grChromakeyValue, "grChromakeyValue");
+   GET_FUNCTION(grClipWindow, "grClipWindow");
+   GET_FUNCTION(grColorCombine, "grColorCombine");
+   GET_FUNCTION(grColorMask, "grColorMask");
+   GET_FUNCTION(grCullMode, "grCullMode");
+   GET_FUNCTION(grConstantColorValue, "grConstantColorValue");
+   GET_FUNCTION(grDepthBiasLevel, "grDepthBiasLevel");
+   GET_FUNCTION(grDepthBufferFunction, "grDepthBufferFunction");
+   GET_FUNCTION(grDepthBufferMode, "grDepthBufferMode");
+   GET_FUNCTION(grDepthMask, "grDepthMask");
+   GET_FUNCTION(grDisableAllEffects, "grDisableAllEffects");
+   GET_FUNCTION(grDitherMode, "grDitherMode");
+   GET_FUNCTION(grFogColorValue, "grFogColorValue");
+   GET_FUNCTION(grFogMode, "grFogMode");
+   GET_FUNCTION(grFogTable, "grFogTable");
+   GET_FUNCTION(grLoadGammaTable, "grLoadGammaTable");
+   GET_FUNCTION(grSplash, "grSplash");
+   GET_FUNCTION(grGet, "grGet");
+   GET_FUNCTION(grGetString, "grGetString");
+   GET_FUNCTION(grQueryResolutions, "grQueryResolutions");
+   GET_FUNCTION(grReset, "grReset");
+   GET_FUNCTION(grGetProcAddress, "grGetProcAddress");
+   GET_FUNCTION(grEnable, "grEnable");
+   GET_FUNCTION(grDisable, "grDisable");
+   GET_FUNCTION(grCoordinateSpace, "grCoordinateSpace");
+   GET_FUNCTION(grDepthRange, "grDepthRange");
+   GET_FUNCTION(grStippleMode, "grStippleMode");
+   GET_FUNCTION(grStipplePattern, "grStipplePattern");
+   GET_FUNCTION(grViewport, "grViewport");
+   GET_FUNCTION(grTexCalcMemRequired, "grTexCalcMemRequired");
+   GET_FUNCTION(grTexTextureMemRequired, "grTexTextureMemRequired");
+   GET_FUNCTION(grTexMinAddress, "grTexMinAddress");
+   GET_FUNCTION(grTexMaxAddress, "grTexMaxAddress");
+   GET_FUNCTION(grTexNCCTable, "grTexNCCTable");
+   GET_FUNCTION(grTexSource, "grTexSource");
+   GET_FUNCTION(grTexClampMode, "grTexClampMode");
+   GET_FUNCTION(grTexCombine, "grTexCombine");
+   GET_FUNCTION(grTexDetailControl, "grTexDetailControl");
+   GET_FUNCTION(grTexFilterMode, "grTexFilterMode");
+   GET_FUNCTION(grTexLodBiasValue, "grTexLodBiasValue");
+   GET_FUNCTION(grTexDownloadMipMap, "grTexDownloadMipMap");
+   GET_FUNCTION(grTexDownloadMipMapLevel, "grTexDownloadMipMapLevel");
+   GET_FUNCTION(grTexDownloadMipMapLevelPartial, "grTexDownloadMipMapLevelPartial");
+   GET_FUNCTION(grTexDownloadTable, "grTexDownloadTable");
+   GET_FUNCTION(grTexDownloadTablePartial, "grTexDownloadTablePartial");
+   GET_FUNCTION(grTexMipMapMode, "grTexMipMapMode");
+   GET_FUNCTION(grTexMultibase, "grTexMultibase");
+   GET_FUNCTION(grTexMultibaseAddress, "grTexMultibaseAddress");
+   GET_FUNCTION(grLfbLock, "grLfbLock");
+   GET_FUNCTION(grLfbUnlock, "grLfbUnlock");
+   GET_FUNCTION(grLfbConstantAlpha, "grLfbConstantAlpha");
+   GET_FUNCTION(grLfbConstantDepth, "grLfbConstantDepth");
+   GET_FUNCTION(grLfbWriteColorSwizzle, "grLfbWriteColorSwizzle");
+   GET_FUNCTION(grLfbWriteColorFormat, "grLfbWriteColorFormat");
+   GET_FUNCTION(grLfbWriteRegion, "grLfbWriteRegion");
+   GET_FUNCTION(grLfbReadRegion, "grLfbReadRegion");
+   GET_FUNCTION(grGlideInit, "grGlideInit");
+   GET_FUNCTION(grGlideShutdown, "grGlideShutdown");
+   GET_FUNCTION(grGlideGetState, "grGlideGetState");
+   GET_FUNCTION(grGlideSetState, "grGlideSetState");
+   GET_FUNCTION(grGlideGetVertexLayout, "grGlideGetVertexLayout");
+   GET_FUNCTION(grGlideSetVertexLayout, "grGlideSetVertexLayout");
+
+   /* Glide utility functions */
+   GET_FUNCTION(guFogGenerateExp, "guFogGenerateExp");
+   GET_FUNCTION(guFogGenerateExp2, "guFogGenerateExp2");
+   GET_FUNCTION(guFogGenerateLinear, "guFogGenerateLinear");
+
+   /* DRI functions */
+   GET_FUNCTION(grDRIOpen, "grDRIOpen");
+   GET_FUNCTION(grDRIPosition, "grDRIPosition");
+   /*GET_FUNCTION(grDRILostContext, "grDRILostContext");*/
+   GET_FUNCTION(grDRIImportFifo, "grDRIImportFifo");
+   GET_FUNCTION(grDRIInvalidateAll, "grDRIInvalidateAll");
+   GET_FUNCTION(grDRIResetSAREA, "grDRIResetSAREA");
+   GET_FUNCTION(grDRIBufferSwap, "grDRIBufferSwap");
+
+   /*
+    * Extension functions:
+    * Just use dlysm() because we want a NULL pointer if the function is
+    * not found.
+    */
+   /* PIXEXT extension */
+   tmesa->Glide.grStencilFunc = dlsym(libHandle, "grStencilFunc");
+   tmesa->Glide.grStencilMask = dlsym(libHandle, "grStencilMask");
+   tmesa->Glide.grStencilOp = dlsym(libHandle, "grStencilOp");
+   tmesa->Glide.grBufferClearExt = dlsym(libHandle, "grBufferClearExt");
+   tmesa->Glide.grColorMaskExt = dlsym(libHandle, "grColorMaskExt");
+   /* COMBINE extension */
+   tmesa->Glide.grColorCombineExt = dlsym(libHandle, "grColorCombineExt");
+   tmesa->Glide.grTexColorCombineExt = dlsym(libHandle, "grTexColorCombineExt");
+   tmesa->Glide.grAlphaCombineExt = dlsym(libHandle, "grAlphaCombineExt");
+   tmesa->Glide.grTexAlphaCombineExt = dlsym(libHandle, "grTexAlphaCombineExt");
+   tmesa->Glide.grAlphaBlendFunctionExt = dlsym(libHandle, "grAlphaBlendFunctionExt");
+   tmesa->Glide.grConstantColorValueExt = dlsym(libHandle, "grConstantColorValueExt");
+   /* Texus 2 */
+   tmesa->Glide.txImgQuantize = dlsym(libHandle, "txImgQuantize");
+   tmesa->Glide.txImgDequantizeFXT1 = dlsym(libHandle, "_txImgDequantizeFXT1");
+   tmesa->Glide.txErrorSetCallback = dlsym(libHandle, "txErrorSetCallback");
+   
+#ifdef DEBUG_TRAP
+   /* wrap the drawing functions so we can trap them */
+   real_grDrawTriangle = tmesa->Glide.grDrawTriangle;
+   tmesa->Glide.grDrawTriangle = debug_grDrawTriangle;
+
+   real_grDrawPoint = tmesa->Glide.grDrawPoint;
+   tmesa->Glide.grDrawPoint = debug_grDrawPoint;
+
+   real_grDrawVertexArray = tmesa->Glide.grDrawVertexArray;
+   tmesa->Glide.grDrawVertexArray = debug_grDrawVertexArray;
+
+   real_grDrawVertexArrayContiguous = tmesa->Glide.grDrawVertexArrayContiguous;
+   tmesa->Glide.grDrawVertexArrayContiguous = debug_grDrawVertexArrayContiguous;
+
+   real_grClipWindow = tmesa->Glide.grClipWindow;
+   tmesa->Glide.grClipWindow = debug_grClipWindow;
+
+   real_grVertexLayout = tmesa->Glide.grVertexLayout;
+   tmesa->Glide.grVertexLayout = debug_grVertexLayout;
+
+   real_grGlideGetVertexLayout = tmesa->Glide.grGlideGetVertexLayout;
+   tmesa->Glide.grGlideGetVertexLayout = debug_grGlideGetVertexLayout;
+
+   real_grGlideSetVertexLayout = tmesa->Glide.grGlideSetVertexLayout;
+   tmesa->Glide.grGlideSetVertexLayout = debug_grGlideSetVertexLayout;
+
+   real_grTexDownloadMipMapLevel = tmesa->Glide.grTexDownloadMipMapLevel;
+   tmesa->Glide.grTexDownloadMipMapLevel = debug_grTexDownloadMipMapLevel;
+
+#endif
+   return GL_TRUE;
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_context.h b/src/mesa/drivers/dri/tdfx/tdfx_context.h
new file mode 100644 (file)
index 0000000..9b0c912
--- /dev/null
@@ -0,0 +1,1027 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_context.h,v 1.5 2002/02/24 21:51:10 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_CONTEXT_H__
+#define __TDFX_CONTEXT_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <sys/time.h>
+#include "dri_util.h"
+#ifdef XFree86Server
+#include "GL/xf86glx.h"
+#else
+#include "glheader.h"
+#endif
+#if defined(__linux__)
+#include <signal.h>
+#endif
+
+#include "tdfx_glide.h"
+
+#include "clip.h"
+#include "context.h"
+#include "macros.h"
+#include "matrix.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "tdfx_screen.h"
+
+
+
+
+#define TDFX_TMU0              GR_TMU0
+#define TDFX_TMU1              GR_TMU1
+#define TDFX_TMU_SPLIT         98
+#define TDFX_TMU_BOTH          99
+#define TDFX_TMU_NONE          100
+
+
+
+/* Flags for fxMesa->new_state
+ */
+#define TDFX_NEW_COLOR         0x0001
+#define TDFX_NEW_ALPHA         0x0002
+#define TDFX_NEW_DEPTH         0x0004
+#define TDFX_NEW_FOG           0x0008
+#define TDFX_NEW_STENCIL       0x0010
+#define TDFX_NEW_CLIP          0x0020
+#define TDFX_NEW_VIEWPORT      0x0040
+#define TDFX_NEW_CULL          0x0080
+#define TDFX_NEW_GLIDE         0x0100
+#define TDFX_NEW_TEXTURE       0x0200
+#define TDFX_NEW_CONTEXT       0x0400
+#define TDFX_NEW_LINE          0x0800
+#define TDFX_NEW_RENDER         0x1000
+#define TDFX_NEW_STIPPLE       0x2000
+#define TDFX_NEW_TEXTURE_BIND   0x4000 /* experimental */
+
+
+/* Flags for fxMesa->dirty
+ */
+#define TDFX_UPLOAD_COLOR_COMBINE      0x00000001
+#define TDFX_UPLOAD_ALPHA_COMBINE      0x00000002
+#define TDFX_UPLOAD_RENDER_BUFFER      0x00000004
+#define TDFX_UPLOAD_ALPHA_TEST         0x00000008
+#define TDFX_UPLOAD_ALPHA_REF          0x00000010
+#define TDFX_UPLOAD_BLEND_FUNC         0x00000020
+#define TDFX_UPLOAD_DEPTH_MODE         0x00000040
+#define TDFX_UPLOAD_DEPTH_BIAS         0x00000080
+#define TDFX_UPLOAD_DEPTH_FUNC         0x00000100
+#define TDFX_UPLOAD_DEPTH_MASK         0x00000200
+#define TDFX_UPLOAD_FOG_MODE           0x00000400
+#define TDFX_UPLOAD_FOG_COLOR          0x00000800
+#define TDFX_UPLOAD_FOG_TABLE          0x00001000
+
+#define TDFX_UPLOAD_CLIP               0x00002000
+#define TDFX_UPLOAD_CULL               0x00004000
+#define TDFX_UPLOAD_VERTEX_LAYOUT      0x00008000
+#define TDFX_UPLOAD_COLOR_MASK         0x00010000
+#define TDFX_UPLOAD_DITHER             0x00040000
+#define TDFX_UPLOAD_STENCIL            0x00080000
+
+#define TDFX_UPLOAD_TEXTURE_SOURCE     0x00100000
+#define TDFX_UPLOAD_TEXTURE_PARAMS     0x00200000
+#define TDFX_UPLOAD_TEXTURE_PALETTE    0x00400000
+#define TDFX_UPLOAD_TEXTURE_ENV                0x00800000
+#define TDFX_UPLOAD_TEXTURE_IMAGES     0x01000000
+
+#define TDFX_UPLOAD_LINE               0x02000000
+
+#define TDFX_UPLOAD_STIPPLE            0x04000000
+
+/* Flags for software fallback cases */
+/* See correponding strings in tdfx_tris.c */
+#define TDFX_FALLBACK_TEXTURE_1D_3D    0x0001
+#define TDFX_FALLBACK_DRAW_BUFFER      0x0002
+#define TDFX_FALLBACK_SPECULAR         0x0004
+#define TDFX_FALLBACK_STENCIL          0x0008
+#define TDFX_FALLBACK_RENDER_MODE      0x0010
+#define TDFX_FALLBACK_LOGICOP          0x0020
+#define TDFX_FALLBACK_TEXTURE_ENV      0x0040
+#define TDFX_FALLBACK_TEXTURE_BORDER   0x0080
+#define TDFX_FALLBACK_COLORMASK                0x0100
+#define TDFX_FALLBACK_BLEND            0x0200
+#define TDFX_FALLBACK_LINE_STIPPLE     0x0400
+
+/* Different Glide vertex layouts
+ */
+#define TDFX_LAYOUT_TINY       0
+#define TDFX_LAYOUT_NOTEX      1
+#define TDFX_LAYOUT_SINGLE     2
+#define TDFX_LAYOUT_MULTI      3
+#define TDFX_LAYOUT_PROJECT    4
+#define TDFX_NUM_LAYOUTS       5
+
+#define TDFX_XY_OFFSET         0
+#define TDFX_Z_OFFSET          8
+#define TDFX_Q_OFFSET          12
+#define TDFX_ARGB_OFFSET       16
+#define TDFX_PAD_OFFSET                20
+#define TDFX_FOG_OFFSET         20 /* experimental */
+#define TDFX_ST0_OFFSET                24
+#define TDFX_ST1_OFFSET                32
+#define TDFX_Q0_OFFSET         40
+#define TDFX_Q1_OFFSET         44
+
+
+/* Flags for buffer clears
+ */
+#define TDFX_FRONT             0x1
+#define TDFX_BACK              0x2
+#define TDFX_DEPTH             0x4
+#define TDFX_STENCIL           0x8
+
+/*
+ * Subpixel offsets to adjust Mesa's (true) window coordinates to
+ * Glide coordinates.  We need these to ensure precise rasterization.
+ * Otherwise, we'll fail a bunch of conformance tests.
+ */
+#define TRI_X_OFFSET    ( 0.0F)
+#define TRI_Y_OFFSET    ( 0.0F)
+#define LINE_X_OFFSET   ( 0.0F)
+#define LINE_Y_OFFSET   ( 0.125F)
+#define PNT_X_OFFSET    ( 0.375F)
+#define PNT_Y_OFFSET    ( 0.375F)
+
+
+#define TDFX_DEPTH_BIAS_SCALE  128
+
+/* Including xf86PciInfo.h causes a bunch of errors
+ */
+#ifndef PCI_CHIP_BANSHEE
+#define PCI_CHIP_BANSHEE       0x0003
+#define PCI_CHIP_VOODOO3       0x0005
+#define PCI_CHIP_VOODOO4       0x0009
+#define PCI_CHIP_VOODOO5       0x0009
+#endif
+
+#define TDFX_IS_BANSHEE( fxMesa ) \
+               ( fxMesa->fxScreen->deviceID == PCI_CHIP_BANSHEE )
+#define TDFX_IS_VOODOO3( fxMesa ) \
+               ( fxMesa->fxScreen->deviceID == PCI_CHIP_VOODOO3 )
+#define TDFX_IS_VOODOO4( fxMesa ) \
+               ( fxMesa->fxScreen->deviceID == PCI_CHIP_VOODOO4 )
+#define TDFX_IS_VOODOO5( fxMesa ) \
+               ( fxMesa->fxScreen->deviceID == PCI_CHIP_VOODOO5 )
+#define TDFX_IS_NAPALM( fxMesa ) \
+                ( (fxMesa->fxScreen->deviceID == PCI_CHIP_VOODOO4) || \
+                  (fxMesa->fxScreen->deviceID == PCI_CHIP_VOODOO5) )
+
+
+#define PACK_BGRA32(R, G, B, A)  \
+    ( (((GLuint) (R)) << 16) | \
+      (((GLuint) (G)) <<  8) | \
+      (((GLuint) (B))      ) | \
+      (((GLuint) (A)) << 24) )
+
+#define PACK_RGBA32(R, G, B, A)  \
+    ( (((GLuint) (R))      ) | \
+      (((GLuint) (G)) <<  8) | \
+      (((GLuint) (B)) << 16) | \
+      (((GLuint) (A)) << 24) )
+
+/*
+ * The first two macros are to pack 8 bit color
+ * channel values into a 565 format.
+ */
+#define PACK_RGB16(R, G, B)         \
+    ((((GLuint) (R) & 0xF8) << 8) | \
+     (((GLuint) (G) & 0xFC) << 3) | \
+      (((GLuint) (B) & 0xFF)         >> 3))
+#define PACK_BGR16(R, G, B)         \
+    ((((GLuint) (B) & 0xF8) << 8) | \
+     (((GLuint) (G) & 0xFC) << 3) | \
+     (((GLuint) (R) & 0xFF) >> 3))
+/*
+ * The second two macros pack 8 bit color channel values
+ * into 1555 values.
+ */
+#define PACK_RGBA16(R, G, B, A)       \
+    (((((GLuint) (A) & 0xFF) > 0) << 15)| \
+     (((GLuint) (R)  & 0xF8)      << 7) | \
+     (((GLuint) (G)  & 0xF8)      << 2) | \
+     (((GLuint) (B)  & 0xF8)      >> 3))
+#define PACK_BGRA16(R, G, B, A) \
+    (((((GLuint) (A) & 0xFF) > 0) << 15)| \
+      (((GLuint) (B) & 0xF8)     << 7)  | \
+      (((GLuint) (G) & 0xF8)     << 2)  | \
+      (((GLuint) (R) & 0xF8)     >> 3))
+
+/* Used in calls to grColorMaskv()...
+ */
+extern const GLboolean false4[4];
+extern const GLboolean true4[4];
+
+
+typedef struct tdfx_context tdfxContextRec;
+typedef struct tdfx_context *tdfxContextPtr;
+
+
+typedef struct {
+   volatile int fifoPtr;
+   volatile int fifoRead;
+   volatile int fifoOwner;
+   volatile int ctxOwner;
+   volatile int texOwner;
+}
+TDFXSAREAPriv;
+
+
+typedef struct {
+   GLuint swapBuffer;
+   GLuint reqTexUpload;
+   GLuint texUpload;
+   GLuint memTexUpload;
+   GLuint texSwaps;
+} tdfxStats;
+
+
+
+/*
+ *  Memory range from startAddr to endAddr-1
+ */
+typedef struct mem_range {
+   struct mem_range *next;
+   FxU32 startAddr, endAddr;
+}
+tdfxMemRange;
+
+
+typedef struct {
+    GLsizei            width, height;  /* image size */
+    GLint              wScale, hScale; /* scale factors */
+    GrTextureFormat_t  glideFormat;    /* Glide image format */
+}
+tdfxMipMapLevel;
+
+
+#define TDFX_NUM_TMU           2
+
+
+typedef struct tdfxTexInfo_t
+{
+   GLboolean isInTM;
+   GLboolean reloadImages;  /* if true, resend images to Glide */
+   GLuint lastTimeUsed;
+   FxU32 whichTMU;
+
+   GrTexInfo info;
+   GrAspectRatio_t aspectRatio;
+   tdfxMemRange *tm[TDFX_NUM_TMU];
+
+   GLint minLevel, maxLevel;
+   GrTextureFilterMode_t minFilt;
+   GrTextureFilterMode_t magFilt;
+   GrTextureClampMode_t sClamp;
+   GrTextureClampMode_t tClamp;
+   FxBool LODblend;
+   GrMipMapMode_t mmMode;
+
+   GLfloat sScale, tScale;  /* texcoord scale factor */
+
+   GuTexPalette palette;
+}
+tdfxTexInfo;
+
+
+#define TDFX_TEXTURE_DATA(mesaObj) ((tdfxTexInfo *)((mesaObj)->DriverData))
+
+#define TDFX_TEXIMAGE_DATA(mesaImg) ((tdfxMipMapLevel *)((mesaImg)->DriverData))
+
+
+
+/*
+ * This is state which may be shared by several tdfx contexts.
+ * It hangs off of Mesa's gl_shared_state object (ctx->Shared->DriverData).
+ */
+struct tdfxSharedState {
+   GLboolean umaTexMemory;
+   GLuint totalTexMem[TDFX_NUM_TMU]; /* constant */
+   GLuint freeTexMem[TDFX_NUM_TMU]; /* changes as we go */
+   tdfxMemRange *tmPool;
+   tdfxMemRange *tmFree[TDFX_NUM_TMU];
+};
+
+
+
+/* ================================================================
+ * The vertex structures.
+ */
+typedef struct {
+   GLubyte     blue;
+   GLubyte     green;
+   GLubyte     red;
+   GLubyte     alpha;
+} tdfx_color_t;
+
+typedef struct {
+   GLfloat x, y, z;                    /* Coordinates in screen space */
+   GLfloat rhw;                                /* Reciprocal homogeneous w */
+   tdfx_color_t color;         /* Diffuse color */
+   GLuint pad;                 
+   GLfloat tu0, tv0;                   /* Texture 0 coordinates */
+   GLfloat tu1, tv1;                   /* Texture 1 coordinates */
+} tdfx_vertex;
+
+typedef struct {
+   GLfloat x, y, z;                    /* Coordinates in screen space */
+   GLfloat rhw;                                /* Reciprocal homogeneous w */
+   tdfx_color_t color;         /* Diffuse color */
+   GLuint pad;                 
+   GLfloat tu0, tv0;           /* Texture 0 coordinates */
+   GLfloat tu1, tv1;           /* Texture 1 coordinates */
+   GLfloat tq0, tq1;           /* Texture 0/1 q coords */
+} tdfx_ptex_vertex;
+
+typedef struct {
+   GLfloat x, y, z;                    /* Coordinates in screen space */
+   tdfx_color_t color;         /* Diffuse color */
+} tdfx_tiny_vertex;
+
+/* The size of this union is not of relevence:
+ */
+union tdfx_vertex_t {
+   tdfx_vertex v;
+   tdfx_tiny_vertex tv;
+   tdfx_ptex_vertex pv;
+   GLfloat f[16];
+   GLuint ui[16];
+   GLubyte ub4[16][4];
+};
+
+typedef union tdfx_vertex_t tdfxVertex, *tdfxVertexPtr;
+
+
+/* ================================================================
+ *
+ * We want to keep a mirror of the Glide function call parameters so we
+ * can avoid updating our state too often.
+ *
+ * Each of these broad groups will typically have a new state flag
+ * associated with it, and will be updated together.  The individual
+ * Glide function calls each have a dirty flag and will only be called
+ * when absolutely necessary.
+ */
+
+/* for grTexSource() */
+struct tdfx_texsource {
+   FxU32 StartAddress;
+   FxU32 EvenOdd;
+   GrTexInfo *Info;
+};
+
+/* Texture object params */
+struct tdfx_texparams {
+   GrTextureClampMode_t sClamp;
+   GrTextureClampMode_t tClamp;
+   GrTextureFilterMode_t minFilt;
+   GrTextureFilterMode_t magFilt;
+   GrMipMapMode_t mmMode;
+   FxBool LODblend;
+   GLfloat LodBias;
+};
+
+/* for grTexDownloadTable() texture palettes */
+struct tdfx_texpalette {
+   GrTexTable_t Type;
+   void *Data;
+};
+
+/* for Voodoo3/Banshee's grColorCombine() and grAlphaCombine() */
+struct tdfx_combine {
+   GrCombineFunction_t Function;       /* Combine function */
+   GrCombineFactor_t Factor;           /* Combine scale factor */
+   GrCombineLocal_t Local;             /* Local combine source */
+   GrCombineOther_t Other;             /* Other combine source */
+   FxBool Invert;                      /* Combine result inversion flag */
+};
+
+/* for Voodoo3's grTexCombine() */
+struct tdfx_texcombine {
+   GrCombineFunction_t FunctionRGB;
+   GrCombineFactor_t FactorRGB;
+   GrCombineFunction_t FunctionAlpha;
+   GrCombineFactor_t FactorAlpha;
+   FxBool InvertRGB;
+   FxBool InvertAlpha;
+};
+
+
+/* for Voodoo5's grColorCombineExt() */
+struct tdfx_combine_color_ext {
+   GrCCUColor_t SourceA;
+   GrCombineMode_t ModeA;
+   GrCCUColor_t SourceB;
+   GrCombineMode_t ModeB;
+   GrCCUColor_t SourceC;
+   FxBool InvertC;
+   GrCCUColor_t SourceD;
+   FxBool InvertD;
+   FxU32 Shift;
+   FxBool Invert;
+};
+
+/* for Voodoo5's grAlphaCombineExt() */
+struct tdfx_combine_alpha_ext {
+   GrACUColor_t SourceA;
+   GrCombineMode_t ModeA;
+   GrACUColor_t SourceB;
+   GrCombineMode_t ModeB;
+   GrACUColor_t SourceC;
+   FxBool InvertC;
+   GrACUColor_t SourceD;
+   FxBool InvertD;
+   FxU32 Shift;
+   FxBool Invert;
+};
+
+/* for Voodoo5's grTexColorCombineExt() */
+struct tdfx_color_texenv {
+   GrTCCUColor_t SourceA;
+   GrCombineMode_t ModeA;
+   GrTCCUColor_t SourceB;
+   GrCombineMode_t ModeB;
+   GrTCCUColor_t SourceC;
+   FxBool InvertC;
+   GrTCCUColor_t SourceD;
+   FxBool InvertD;
+   FxU32 Shift;
+   FxBool Invert;
+};
+
+/* for Voodoo5's grTexAlphaCombineExt() */
+struct tdfx_alpha_texenv {
+   GrTACUColor_t SourceA;
+   GrCombineMode_t ModeA;
+   GrTACUColor_t SourceB;
+   GrCombineMode_t ModeB;
+   GrTACUColor_t SourceC;
+   FxBool InvertC;
+   GrTCCUColor_t SourceD;
+   FxBool InvertD;
+   FxU32 Shift;
+   FxBool Invert;
+};
+
+/* Voodoo5's texture combine environment */
+struct tdfx_texcombine_ext {
+   struct tdfx_alpha_texenv Alpha;
+   struct tdfx_color_texenv Color;
+   GrColor_t EnvColor;
+};
+
+/* Used to track changes between Glide's state and Mesa's */
+struct tdfx_texstate {
+   GLuint Enabled[2];              /* values ala ctx->Texture.Unit[i]._ReallyEnabled */
+   GLenum EnvMode[TDFX_NUM_TMU];   /* index is Glide index, not OpenGL */
+   GLenum TexFormat[TDFX_NUM_TMU]; /* index is Glide index, not OpenGL */
+};
+
+struct tdfx_color {
+   GrColor_t ClearColor;               /* Buffer clear color value */
+   GrAlpha_t ClearAlpha;               /* Buffer clear alpha value */
+   FxBool ColorMask[4];                        /* Per-channel write enable flags */
+
+   GrColor_t MonoColor;                        /* Constant color value */
+
+   /* Alpha testing */
+   GrCmpFnc_t AlphaFunc;               /* Alpha test function */
+   GrAlpha_t AlphaRef;                 /* Alpha ref value in range [0,255] */
+
+   /* Blending */
+   GrAlphaBlendFnc_t BlendSrcRGB;      /* Blend source RGB factor */
+   GrAlphaBlendFnc_t BlendDstRGB;      /* Blend destination RGB factor */
+   GrAlphaBlendFnc_t BlendSrcA;                /* Blend source alpha factor */
+   GrAlphaBlendFnc_t BlendDstA;                /* Blend destination alpha factor */
+
+   GrDitherMode_t Dither;              /* Dither enable */
+};
+
+struct tdfx_depth {
+   GrDepthBufferMode_t Mode;           /* Fixed-point Z or floating-point W */
+   FxI32 Bias;                         /* Polygon offset factor */
+   GrCmpFnc_t Func;                    /* Depth test function */
+   FxU32 Clear;                                /* Buffer clear value */
+   FxBool Mask;                                /* Write enable flag */
+};
+
+struct tdfx_stipple {
+   GrStippleMode_t Mode;               /* Stipple enable/disable */
+   FxU32 Pattern;                      /* 8x4 Stipple Pattern */
+};
+
+struct tdfx_fog {
+   GrFogMode_t Mode;                   /* Glide fog mode */
+   GrColor_t Color;                    /* Fog color value */
+   GLenum TableMode;                   /* GL fog mode currently in table */
+   GrFog_t *Table;                     /* Fog value table */
+   FxFloat Density;                    /* Density >= 0 */
+   FxFloat Near;                       /* Start distance in eye coords */
+   FxFloat Far;                                /* End distance in eye coords */
+};
+
+struct tdfx_stencil {
+   GrCmpFnc_t Function;                        /* Stencil function */
+   GrStencil_t RefValue;               /* Stencil reference value */
+   GrStencil_t ValueMask;              /* Value mask */
+   GrStencil_t WriteMask;              /* Write mask */
+   GrStencil_t FailFunc;               /* Stencil fail function */
+   GrStencil_t ZFailFunc;              /* Stencil pass, depth fail function */
+   GrStencil_t ZPassFunc;              /* Stencil pass, depth pass function */
+   GrStencil_t Clear;                  /* Buffer clear value */
+};
+
+struct tdfx_scissor {
+   FxU32 minX, minY;                   /* Lower left corner */
+   FxU32 maxX, maxY;                   /* Upper right corner */
+};
+
+struct tdfx_viewport {
+   GrCoordinateSpaceMode_t Mode;       /* Coordinate space */
+   FxI32 X, Y;                         /* Position */
+   FxI32 Width, Height;                        /* Size */
+   FxFloat Near, Far;                  /* Depth buffer range */
+};
+
+struct tdfx_glide {
+   void *State;                                /* Mirror of internal Glide state */
+   GrContext_t Context;                        /* Glide context identifier */
+   FxI32 Board;                                /* Current graphics subsystem */
+   GrColorFormat_t ColorFormat;                /* Framebuffer format */
+   GrOriginLocation_t Origin;          /* Location of screen space origin */
+
+   FxBool Initialized;                 /* Glide initialization done? */
+
+   FxI32 SwapInterval;                 /* SwapBuffers interval */
+   FxI32 MaxPendingSwaps;              /* Maximum outstanding SwapBuffers */
+   FxI32 TextureAlign;
+
+   /* Extensions */
+   FxBool HaveCombineExt;              /* COMBINE */
+   FxBool HaveCommandTransportExt;     /* COMMAND_TRANSPORT */
+   FxBool HaveFogCoordExt;             /* FOGCOORD */
+   FxBool HavePixelExt;                        /* PIXEXT */
+   FxBool HaveTextureBufferExt;                /* TEXTUREBUFFER */
+   FxBool HaveTexFmtExt;               /* TEXFMT */
+   FxBool HaveTexUMAExt;               /* TEXUMA */
+   FxBool HaveTexus2;                  /* Texus 2 - FXT1 */
+
+   /* Glide library function pointers */
+   void (*grDrawPoint)( const void *pt );
+   void (*grDrawLine)( const void *v1, const void *v2 );
+   void (*grDrawTriangle)( const void *a, const void *b, const void *c );
+   void (*grVertexLayout)(FxU32 param, FxI32 offset, FxU32 mode);
+   void (*grDrawVertexArray)(FxU32 mode, FxU32 Count, void *pointers);
+   void (*grDrawVertexArrayContiguous)(FxU32 mode, FxU32 Count,
+                                       void *pointers, FxU32 stride);
+   void (*grBufferClear)( GrColor_t color, GrAlpha_t alpha, FxU32 depth );
+   void (*grBufferSwap)( FxU32 swap_interval );
+   void (*grRenderBuffer)( GrBuffer_t buffer );
+   void (*grErrorSetCallback)( GrErrorCallbackFnc_t fnc );
+   void (*grFinish)(void);
+   void (*grFlush)(void);
+   GrContext_t (*grSstWinOpen)(FxU32                hWnd,
+                               GrScreenResolution_t screen_resolution,
+                               GrScreenRefresh_t    refresh_rate,
+                               GrColorFormat_t      color_format,
+                               GrOriginLocation_t   origin_location,
+                               int                  nColBuffers,
+                               int                  nAuxBuffers);
+   void (*grSstWinClose)( GrContext_t context );
+/* Not used */
+#if 0
+   void (*grSetNumPendingBuffers)(FxI32 NumPendingBuffers);
+#endif
+   void (*grSelectContext)( GrContext_t context );
+   void (*grSstOrigin)(GrOriginLocation_t  origin);
+   void (*grSstSelect)( int which_sst );
+   void (*grAlphaBlendFunction)(GrAlphaBlendFnc_t rgb_sf,
+                                GrAlphaBlendFnc_t rgb_df,
+                                GrAlphaBlendFnc_t alpha_sf,
+                                GrAlphaBlendFnc_t alpha_df);
+   void (*grAlphaCombine)(GrCombineFunction_t function,
+                          GrCombineFactor_t factor,
+                          GrCombineLocal_t local, GrCombineOther_t other,
+                          FxBool invert);
+   void (*grAlphaControlsITRGBLighting)( FxBool enable );
+   void (*grAlphaTestFunction)( GrCmpFnc_t function );
+   void (*grAlphaTestReferenceValue)( GrAlpha_t value );
+   void (*grChromakeyMode)( GrChromakeyMode_t mode );
+   void (*grChromakeyValue)( GrColor_t value );
+   void (*grClipWindow)( FxU32 minx, FxU32 miny, FxU32 maxx, FxU32 maxy );
+   void (*grColorCombine)( GrCombineFunction_t function,
+                           GrCombineFactor_t factor,
+                           GrCombineLocal_t local,
+                           GrCombineOther_t other,
+                           FxBool invert );
+   void (*grColorMask)( FxBool rgb, FxBool a );
+   void (*grCullMode)( GrCullMode_t mode );
+   void (*grConstantColorValue)( GrColor_t value );
+   void (*grDepthBiasLevel)( FxI32 level );
+   void (*grDepthBufferFunction)( GrCmpFnc_t function );
+   void (*grDepthBufferMode)( GrDepthBufferMode_t mode );
+   void (*grDepthMask)( FxBool mask );
+   void (*grDisableAllEffects)( void );
+   void (*grDitherMode)( GrDitherMode_t mode );
+   void (*grFogColorValue)( GrColor_t fogcolor );
+   void (*grFogMode)( GrFogMode_t mode );
+   void (*grFogTable)( const GrFog_t ft[] );
+   void (*grLoadGammaTable)( FxU32 nentries, FxU32 *red, FxU32 *green, FxU32 *blue);
+   void (*grSplash)(float x, float y, float width, float height, FxU32 frame);
+   FxU32 (*grGet)( FxU32 pname, FxU32 plength, FxI32 *params );
+   const char * (*grGetString)( FxU32 pname );
+   FxI32 (*grQueryResolutions)( const GrResolution *resTemplate,
+                                GrResolution *output );
+   FxBool (*grReset)( FxU32 what );
+   GrProc (*grGetProcAddress)( char *procName );
+   void (*grEnable)( GrEnableMode_t mode );
+   void (*grDisable)( GrEnableMode_t mode );
+   void (*grCoordinateSpace)( GrCoordinateSpaceMode_t mode );
+   void (*grDepthRange)( FxFloat n, FxFloat f );
+   void (*grStippleMode)( GrStippleMode_t mode );
+   void (*grStipplePattern)( GrStipplePattern_t mode );
+   void (*grViewport)( FxI32 x, FxI32 y, FxI32 width, FxI32 height );
+   FxU32 (*grTexCalcMemRequired)(GrLOD_t lodmin, GrLOD_t lodmax,
+                                GrAspectRatio_t aspect, GrTextureFormat_t fmt);
+   FxU32 (*grTexTextureMemRequired)( FxU32 evenOdd, GrTexInfo *info );
+   FxU32 (*grTexMinAddress)( GrChipID_t tmu );
+   FxU32 (*grTexMaxAddress)( GrChipID_t tmu );
+   void (*grTexNCCTable)( GrNCCTable_t table );
+   void (*grTexSource)( GrChipID_t tmu, FxU32 startAddress,
+                        FxU32 evenOdd, GrTexInfo *info );
+   void (*grTexClampMode)( GrChipID_t tmu,
+                           GrTextureClampMode_t s_clampmode,
+                           GrTextureClampMode_t t_clampmode );
+   void (*grTexCombine)( GrChipID_t tmu,
+                         GrCombineFunction_t rgb_function,
+                         GrCombineFactor_t rgb_factor, 
+                         GrCombineFunction_t alpha_function,
+                         GrCombineFactor_t alpha_factor,
+                         FxBool rgb_invert,
+                         FxBool alpha_invert);
+   void (*grTexDetailControl)( GrChipID_t tmu, int lod_bias,
+                               FxU8 detail_scale, float detail_max );
+   void (*grTexFilterMode)( GrChipID_t tmu,
+                            GrTextureFilterMode_t minfilter_mode,
+                            GrTextureFilterMode_t magfilter_mode );
+   void (*grTexLodBiasValue)(GrChipID_t tmu, float bias );
+   void (*grTexDownloadMipMap)( GrChipID_t tmu, FxU32 startAddress,
+                                FxU32 evenOdd, GrTexInfo *info );
+   void (*grTexDownloadMipMapLevel)( GrChipID_t        tmu,
+                                     FxU32             startAddress,
+                                     GrLOD_t           thisLod,
+                                     GrLOD_t           largeLod,
+                                     GrAspectRatio_t   aspectRatio,
+                                     GrTextureFormat_t format,
+                                     FxU32             evenOdd,
+                                     void              *data );
+   FxBool (*grTexDownloadMipMapLevelPartial)( GrChipID_t        tmu,
+                                              FxU32             startAddress,
+                                              GrLOD_t           thisLod,
+                                              GrLOD_t           largeLod,
+                                              GrAspectRatio_t   aspectRatio,
+                                              GrTextureFormat_t format,
+                                              FxU32             evenOdd,
+                                              void              *data,
+                                              int               start,
+                                              int               end );
+   void (*grTexDownloadTable)( GrTexTable_t type, void *data );
+   void (*grTexDownloadTablePartial)( GrTexTable_t type, 
+                                      void *data, int start, int end );
+   void (*grTexMipMapMode)( GrChipID_t tmu, GrMipMapMode_t mode,
+                            FxBool lodBlend );
+   void (*grTexMultibase)( GrChipID_t tmu, FxBool enable );
+   void (*grTexMultibaseAddress)( GrChipID_t       tmu,
+                                  GrTexBaseRange_t range,
+                                  FxU32            startAddress,
+                                  FxU32            evenOdd,
+                                  GrTexInfo        *info );
+   FxBool (*grLfbLock)( GrLock_t type, GrBuffer_t buffer,
+                        GrLfbWriteMode_t writeMode,
+                        GrOriginLocation_t origin, FxBool pixelPipeline, 
+                        GrLfbInfo_t *info );
+   FxBool (*grLfbUnlock)( GrLock_t type, GrBuffer_t buffer );
+   void (*grLfbConstantAlpha)( GrAlpha_t alpha );
+   void (*grLfbConstantDepth)( FxU32 depth );
+   void (*grLfbWriteColorSwizzle)(FxBool swizzleBytes, FxBool swapWords);
+   void (*grLfbWriteColorFormat)(GrColorFormat_t colorFormat);
+   FxBool (*grLfbWriteRegion)( GrBuffer_t dst_buffer, 
+                               FxU32 dst_x, FxU32 dst_y, 
+                               GrLfbSrcFmt_t src_format, 
+                               FxU32 src_width, FxU32 src_height, 
+                               FxBool pixelPipeline,
+                               FxI32 src_stride, void *src_data );
+   FxBool (*grLfbReadRegion)( GrBuffer_t src_buffer,
+                              FxU32 src_x, FxU32 src_y,
+                              FxU32 src_width, FxU32 src_height,
+                              FxU32 dst_stride, void *dst_data );
+   void (*grGlideInit)( void );
+   void (*grGlideShutdown)( void );
+   void (*grGlideGetState)( void *state );
+   void (*grGlideSetState)( const void *state );
+   void (*grGlideGetVertexLayout)( void *layout );
+   void (*grGlideSetVertexLayout)( const void *layout );
+   /* Glide utility functions */
+   void (*guFogGenerateExp)( GrFog_t *fogtable, float density );
+   void (*guFogGenerateExp2)( GrFog_t *fogtable, float density );
+   void (*guFogGenerateLinear)(GrFog_t *fogtable, float nearZ, float farZ );
+   /* DRI functions */
+   void (*grDRIOpen)( char *pFB, char *pRegs, int deviceID,
+                      int width, int height,
+                      int mem, int cpp, int stride,
+                      int fifoOffset, int fifoSize,
+                      int fbOffset, int backOffset, int depthOffset,
+                      int textureOffset, int textureSize,
+                      volatile int *fifoPtr, volatile int *fifoRead );
+   void (*grDRIPosition)( int x, int y, int w, int h,
+                          int numClip, XF86DRIClipRectPtr pClip );
+   void (*grDRILostContext)( void );
+   void (*grDRIImportFifo)( int fifoPtr, int fifoRead );
+   void (*grDRIInvalidateAll)( void );
+   void (*grDRIResetSAREA)( void );
+   void (*grDRIBufferSwap)( FxU32 swapInterval );
+   /* Glide extensions */
+   /* PIXEXT extension */
+   void (*grStencilFunc)( GrCmpFnc_t func, GrStencil_t ref, GrStencil_t mask );
+   void (*grStencilMask)( GrStencil_t mask );
+   void (*grStencilOp)( GrStencilOp_t fail, GrStencilOp_t zfail,
+                        GrStencilOp_t zpass );
+   void (*grBufferClearExt)( GrColor_t color, GrAlpha_t alpha,
+                             FxU32 depth, GrStencil_t stencil );
+   void (*grColorMaskExt)( FxBool r, FxBool g, FxBool b, FxBool a );
+   /* COMBINE extension */
+   void (*grColorCombineExt)( GrCCUColor_t a, GrCombineMode_t a_mode,
+                              GrCCUColor_t b, GrCombineMode_t b_mode,
+                              GrCCUColor_t c, FxBool c_invert,
+                              GrCCUColor_t d, FxBool d_invert,
+                              FxU32 shift, FxBool invert );
+   void (*grTexColorCombineExt)( FxU32 tmu,
+                                 GrTCCUColor_t a, GrCombineMode_t a_mode,
+                                 GrTCCUColor_t b, GrCombineMode_t b_mode,
+                                 GrTCCUColor_t c, FxBool c_invert,
+                                 GrTCCUColor_t d, FxBool d_invert,
+                                 FxU32 shift, FxBool invert );
+   void (*grAlphaCombineExt)( GrACUColor_t a, GrCombineMode_t a_mode,
+                              GrACUColor_t b, GrCombineMode_t b_mode,
+                              GrACUColor_t c, FxBool c_invert,
+                              GrACUColor_t d, FxBool d_invert,
+                              FxU32 shift, FxBool invert );
+   void (*grTexAlphaCombineExt)( FxU32 tmu,
+                                 GrTACUColor_t a, GrCombineMode_t a_mode,
+                                 GrTACUColor_t b, GrCombineMode_t b_mode,
+                                 GrTACUColor_t c, FxBool c_invert,
+                                 GrTACUColor_t d, FxBool d_invert,
+                                 FxU32 shift, FxBool invert );
+   void (*grAlphaBlendFunctionExt)( GrAlphaBlendFnc_t rgb_sf,
+                                    GrAlphaBlendFnc_t rgb_df,
+                                    GrAlphaBlendOp_t rgb_op,
+                                    GrAlphaBlendFnc_t alpha_sf,
+                                    GrAlphaBlendFnc_t alpha_df,
+                                    GrAlphaBlendOp_t alpha_op );
+   void (*grConstantColorValueExt)( FxU32 tmu, GrColor_t value );
+   /* Texus 2 */
+   void (*txImgQuantize)( void *xxx_unknown_arguments );
+   void (*txImgDequantizeFXT1)( void *txMip, void *pxMip );
+   void (*txErrorSetCallback)( void *fnc );
+};
+
+typedef void (*tdfx_tri_func)( tdfxContextPtr, tdfxVertex *, tdfxVertex *,
+                              tdfxVertex * );
+typedef void (*tdfx_line_func)( tdfxContextPtr, tdfxVertex *, tdfxVertex * );
+typedef void (*tdfx_point_func)( tdfxContextPtr, tdfxVertex * );
+
+struct tdfx_context {
+   /* Set once and never changed:
+    */
+   GLcontext *glCtx;                   /* The core Mesa context */
+
+   GLuint new_gl_state;
+   GLuint new_state;
+   GLuint dirty;
+
+   /* Mirror of hardware state, Glide parameters
+    */
+   struct tdfx_texsource       TexSource[TDFX_NUM_TMU];
+   struct tdfx_texparams       TexParams[TDFX_NUM_TMU];
+   struct tdfx_texpalette      TexPalette;
+
+   /* Voodoo3 texture/color combine state */
+   struct tdfx_combine         ColorCombine;
+   struct tdfx_combine         AlphaCombine;
+   struct tdfx_texcombine      TexCombine[TDFX_NUM_TMU];
+
+   /* Voodoo5 texture/color combine state */
+   struct tdfx_combine_color_ext       ColorCombineExt;
+   struct tdfx_combine_alpha_ext       AlphaCombineExt;
+   struct tdfx_texcombine_ext          TexCombineExt[TDFX_NUM_TMU];
+
+   /* Tracks tex state difference between Glide and Mesa */
+   struct tdfx_texstate                TexState;
+
+   GrBuffer_t          DrawBuffer;     /* Current draw buffer */
+   GrBuffer_t          ReadBuffer;     /* Current read buffer */
+
+   struct tdfx_color   Color;
+   struct tdfx_depth   Depth;
+   struct tdfx_fog     Fog;
+   struct tdfx_stencil Stencil;
+   struct tdfx_scissor Scissor;
+   struct tdfx_viewport        Viewport;
+   struct tdfx_stipple Stipple;
+
+   GrCullMode_t                CullMode;
+
+   struct tdfx_glide   Glide;
+
+
+   /* Temporaries for translating away float colors:
+    */
+   struct gl_client_array UbyteColor;
+
+   /* Fallback rasterization functions 
+    */
+   tdfx_point_func draw_point;
+   tdfx_line_func draw_line;
+   tdfx_tri_func draw_triangle;
+
+
+   /* Variable-size Glide vertex formats
+    */
+   GLuint vertexFormat;            /* the current format */
+   GLuint vertex_stride_shift;
+   void *layout[TDFX_NUM_LAYOUTS];
+   GLubyte *verts;                        /* tdfxVertices, arbitarily packed */
+   
+   GLfloat hw_viewport[16];
+   
+   GLuint SetupIndex;
+   GLuint SetupNewInputs;
+   GLuint RenderIndex;
+   GLuint Fallback;
+   GLenum render_primitive;    /* what GL thinks */
+   GLenum raster_primitive;    /* what the hardware thinks */
+
+   GLfloat sScale0, tScale0;
+   GLfloat sScale1, tScale1;
+
+   GLuint texBindNumber;
+   GLint tmuSrc;
+
+   int screen_width;
+   int screen_height;
+
+   GLboolean haveTwoTMUs;      /* True if we have 2 tmu's  */
+   GLboolean haveHwStencil;
+   GLboolean haveHwStipple;
+
+   GLint maxPendingSwapBuffers;
+
+   char rendererString[100];
+
+   /* stuff added for DRI */
+   __DRIscreenPrivate *driScreen;
+   __DRIcontextPrivate *driContext;
+   __DRIdrawablePrivate *driDrawable;
+   drmContext hHWContext;
+   drmLock *driHwLock;
+   int driFd;
+   tdfxScreenPrivate *fxScreen;
+   TDFXSAREAPriv *sarea;
+
+
+   /*
+    * Changes during execution:
+    */
+   int width, height;   /* size of window */
+   int x_offset;        /* distance from window left to screen left */
+   int y_offset;        /* distance from window top to screen top */
+   int y_delta;         /* distance from window bottom to screen bottom */
+
+   int numClipRects;
+   XF86DRIClipRectPtr pClipRects;
+   GLboolean scissoredClipRects;  /* if true, pClipRects is private storage */
+
+   GuTexPalette glbPalette;         /* global texture palette */
+
+   tdfxStats stats;
+
+   GLboolean debugFallbacks;
+};
+
+#define TDFX_CONTEXT(ctx)      ((tdfxContextPtr)((ctx)->DriverCtx))
+
+
+extern GLboolean
+tdfxCreateContext( const __GLcontextModes *mesaVis,
+                   __DRIcontextPrivate *driContextPriv,
+                   void *sharedContextPrivate );
+
+extern void
+tdfxDestroyContext( __DRIcontextPrivate *driContextPriv );
+
+extern GLboolean
+tdfxUnbindContext( __DRIcontextPrivate *driContextPriv );
+
+extern GLboolean
+tdfxMakeCurrent( __DRIcontextPrivate *driContextPriv,
+                 __DRIdrawablePrivate *driDrawPriv,
+                 __DRIdrawablePrivate *driReadPriv );
+
+extern GLboolean
+tdfxInitGlide( tdfxContextPtr tmesa );
+
+extern void
+FX_grColorMaskv(GLcontext *ctx, const GLboolean rgba[4]);
+
+extern void
+FX_grColorMaskv_NoLock(GLcontext *ctx, const GLboolean rgba[4]);
+
+
+/* Color packing utilities
+ */
+#define TDFXPACKCOLOR332( r, g, b )                                       \
+   (((b) & 0xe0) | (((g) & 0xe0) >> 3) | (((r) & 0xc0) >> 6))
+
+#define TDFXPACKCOLOR1555( r, g, b, a )                                           \
+   ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) |     \
+    ((a) ? 0x8000 : 0))
+
+#define TDFXPACKCOLOR565( r, g, b )                                       \
+   ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3))
+
+#define TDFXPACKCOLOR888( r, g, b )                                       \
+   (((b) << 16) | ((g) << 8) | (r))
+
+#define TDFXPACKCOLOR8888( r, g, b, a )                                           \
+   (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+
+#define TDFXPACKCOLOR4444( r, g, b, a )                                           \
+   ((((a) & 0xf0) << 8) | (((b) & 0xf0) << 4) | ((g) & 0xf0) | ((r) >> 4))
+
+static __inline__ GrColor_t tdfxPackColor( GLuint cpp,
+                                          GLubyte r, GLubyte g,
+                                          GLubyte b, GLubyte a )
+{
+   switch ( cpp ) {
+   case 2:
+      return TDFXPACKCOLOR565( r, g, b );
+   case 4:
+      return TDFXPACKCOLOR8888( r, g, b, a );
+   default:
+      return 0;
+  }
+}
+
+#define DO_DEBUG               0
+#if DO_DEBUG
+extern int TDFX_DEBUG;
+#else
+#define TDFX_DEBUG             0
+#endif
+
+#define DEBUG_ALWAYS_SYNC      0x01
+#define DEBUG_VERBOSE_API      0x02
+#define DEBUG_VERBOSE_MSG      0x04
+#define DEBUG_VERBOSE_LRU      0x08
+#define DEBUG_VERBOSE_DRI      0x10
+#define DEBUG_VERBOSE_IOCTL    0x20
+#define DEBUG_VERBOSE_2D       0x40
+
+#endif /* GLX_DIRECT_RENDERING */
+
+#endif /* __TDFX_CONTEXT_H__ */
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_dd.c b/src/mesa/drivers/dri/tdfx/tdfx_dd.c
new file mode 100644 (file)
index 0000000..31604e3
--- /dev/null
@@ -0,0 +1,330 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_dd.c,v 1.10 2002/10/30 12:52:00 alanh Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#include "tdfx_context.h"
+#include "tdfx_dd.h"
+#include "tdfx_lock.h"
+#include "tdfx_vb.h"
+#include "tdfx_pixels.h"
+
+#include "context.h"
+#include "enums.h"
+#include "swrast/swrast.h"
+#if defined(USE_X86_ASM)
+#include "X86/common_x86_asm.h"
+#endif
+
+
+#define TDFX_DATE      "20021125"
+
+
+/* These are used in calls to FX_grColorMaskv() */
+const GLboolean false4[4] = { GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE };
+const GLboolean true4[4] = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE };
+
+
+
+/* KW: Put the word Mesa in the render string because quakeworld
+ * checks for this rather than doing a glGet(GL_MAX_TEXTURE_SIZE).
+ * Why?
+ */
+static const GLubyte *tdfxDDGetString( GLcontext *ctx, GLenum name )
+{
+   tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
+
+   switch ( name ) {
+   case GL_RENDERER:
+   {
+      /* The renderer string must be per-context state to handle
+       * multihead correctly.
+       */
+      char *buffer = fxMesa->rendererString;
+      char hardware[100];
+
+      LOCK_HARDWARE(fxMesa);
+      strcpy( hardware, fxMesa->Glide.grGetString(GR_HARDWARE) );
+      UNLOCK_HARDWARE(fxMesa);
+
+      strcpy( buffer, "Mesa DRI " );
+      strcat( buffer, TDFX_DATE );
+      strcat( buffer, " " );
+
+      if ( strcmp( hardware, "Voodoo3 (tm)" ) == 0 ) {
+        strcat( buffer, "Voodoo3" );
+      }
+      else if ( strcmp( hardware, "Voodoo Banshee (tm)" ) == 0 ) {
+        strcat( buffer, "VoodooBanshee" );
+      }
+      else if ( strcmp( hardware, "Voodoo4 (tm)" ) == 0 ) {
+        strcat( buffer, "Voodoo4" );
+      }
+      else if ( strcmp( hardware, "Voodoo5 (tm)" ) == 0 ) {
+        strcat( buffer, "Voodoo5" );
+      }
+      else {
+        /* unexpected result: replace spaces with hyphens */
+        int i;
+        for ( i = 0 ; hardware[i] && i < 60 ; i++ ) {
+           if ( hardware[i] == ' ' || hardware[i] == '\t' )
+              hardware[i] = '-';
+        }
+         strcat( buffer, hardware );
+      }
+
+      /* Append any CPU-specific information.
+       */
+#ifdef USE_X86_ASM
+      if ( _mesa_x86_cpu_features ) {
+        strncat( buffer, " x86", 4 );
+      }
+#endif
+#ifdef USE_MMX_ASM
+      if ( cpu_has_mmx ) {
+        strncat( buffer, "/MMX", 4 );
+      }
+#endif
+#ifdef USE_3DNOW_ASM
+      if ( cpu_has_3dnow ) {
+        strncat( buffer, "/3DNow!", 7 );
+      }
+#endif
+#ifdef USE_SSE_ASM
+      if ( cpu_has_xmm ) {
+        strncat( buffer, "/SSE", 4 );
+      }
+#endif
+      return (const GLubyte *) buffer;
+   }
+   case GL_VENDOR:
+      return (const GLubyte *)"VA Linux Systems, Inc.";
+   default:
+      return NULL;
+   }
+}
+
+
+/* Return uptodate buffer size information.
+ */
+static void tdfxDDGetBufferSize( GLframebuffer *buffer,
+                                GLuint *width, GLuint *height )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   LOCK_HARDWARE( fxMesa );
+   *width = fxMesa->width;
+   *height = fxMesa->height;
+   UNLOCK_HARDWARE( fxMesa );
+}
+
+
+
+/*
+ * Return the current value of the occlusion test flag and
+ * reset the flag (hardware counters) to false.
+ */
+static GLboolean get_occlusion_result( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLboolean result;
+
+   LOCK_HARDWARE( fxMesa );
+   fxMesa->Glide.grFinish(); /* required to flush the FIFO - FB 21-01-2002 */ 
+
+   if (ctx->Depth.OcclusionTest) {
+      if (ctx->OcclusionResult) {
+        result = GL_TRUE;  /* result of software rendering */
+      }
+      else {
+        FxI32 zfail, in;
+         fxMesa->Glide.grGet(GR_STATS_PIXELS_DEPTHFUNC_FAIL, 4, &zfail);
+         fxMesa->Glide.grGet(GR_STATS_PIXELS_IN, 4, &in);
+         /* Geometry is occluded if there is no input (in == 0) */
+         /* or if all pixels failed the depth test (zfail == in) */
+         /* The < 1 is there because I have empirically seen cases where */
+         /* zfail > in.... go figure.  FB - 21-01-2002. */
+         result = ((in - zfail) < 1 || in == 0) ? GL_FALSE : GL_TRUE;
+      }
+   }
+   else {
+      result = ctx->OcclusionResultSaved;
+   }
+
+   /* reset results now */
+   fxMesa->Glide.grReset(GR_STATS_PIXELS);
+   ctx->OcclusionResult = GL_FALSE;
+   ctx->OcclusionResultSaved = GL_FALSE;
+
+   UNLOCK_HARDWARE( fxMesa );
+
+   return result;
+}
+
+
+/*
+ * We're only implementing this function to handle the
+ * GL_OCCLUSTION_TEST_RESULT_HP case.  It's special because it
+ * has a side-effect: resetting the occlustion result flag.
+ */
+static GLboolean tdfxDDGetBooleanv( GLcontext *ctx, GLenum pname,
+                                   GLboolean *result )
+{
+   if ( pname == GL_OCCLUSION_TEST_RESULT_HP ) {
+      *result = get_occlusion_result( ctx );
+      return GL_TRUE;
+   }
+   return GL_FALSE;
+}
+
+static GLboolean tdfxDDGetDoublev( GLcontext *ctx, GLenum pname,
+                                  GLdouble *result )
+{
+   if ( pname == GL_OCCLUSION_TEST_RESULT_HP ) {
+      *result = (GLdouble) get_occlusion_result( ctx );
+      return GL_TRUE;
+   }
+   return GL_FALSE;
+}
+
+static GLboolean tdfxDDGetFloatv( GLcontext *ctx, GLenum pname,
+                                 GLfloat *result )
+{
+   if ( pname == GL_OCCLUSION_TEST_RESULT_HP ) {
+      *result = (GLfloat) get_occlusion_result( ctx );
+      return GL_TRUE;
+   }
+   return GL_FALSE;
+}
+
+static GLboolean tdfxDDGetIntegerv( GLcontext *ctx, GLenum pname,
+                                   GLint *result )
+{
+   if ( pname == GL_OCCLUSION_TEST_RESULT_HP ) {
+      *result = (GLint) get_occlusion_result( ctx );
+      return GL_TRUE;
+   }
+   return GL_FALSE;
+}
+
+
+
+#define VISUAL_EQUALS_RGBA(vis, r, g, b, a)        \
+   ((vis.redBits == r) &&                         \
+    (vis.greenBits == g) &&                       \
+    (vis.blueBits == b) &&                        \
+    (vis.alphaBits == a))
+
+void tdfxDDInitDriverFuncs( GLcontext *ctx )
+{
+   if ( MESA_VERBOSE & VERBOSE_DRIVER ) {
+      fprintf( stderr, "tdfx: %s()\n", __FUNCTION__ );
+   }
+
+   ctx->Driver.GetString               = tdfxDDGetString;
+   ctx->Driver.GetBufferSize           = tdfxDDGetBufferSize;
+   ctx->Driver.ResizeBuffers            = _swrast_alloc_buffers;
+   ctx->Driver.Error                   = NULL;
+
+   /* Pixel path fallbacks.
+    */
+   ctx->Driver.Accum                    = _swrast_Accum;
+   ctx->Driver.Bitmap                   = _swrast_Bitmap;
+   ctx->Driver.CopyPixels               = _swrast_CopyPixels;
+   ctx->Driver.DrawPixels               = _swrast_DrawPixels;
+   ctx->Driver.ReadPixels               = _swrast_ReadPixels;
+
+   /* Accelerated paths
+    */
+   if ( VISUAL_EQUALS_RGBA(ctx->Visual, 8, 8, 8, 8) )
+   {
+      ctx->Driver.DrawPixels           = tdfx_drawpixels_R8G8B8A8;
+      ctx->Driver.ReadPixels           = tdfx_readpixels_R8G8B8A8;
+   }
+   else if ( VISUAL_EQUALS_RGBA(ctx->Visual, 5, 6, 5, 0) )
+   {
+      ctx->Driver.ReadPixels           = tdfx_readpixels_R5G6B5;
+   }
+
+   ctx->Driver.GetBooleanv             = tdfxDDGetBooleanv;
+   ctx->Driver.GetDoublev              = tdfxDDGetDoublev;
+   ctx->Driver.GetFloatv               = tdfxDDGetFloatv;
+   ctx->Driver.GetIntegerv             = tdfxDDGetIntegerv;
+   ctx->Driver.GetPointerv             = NULL;
+}
+
+
+/*
+ * These are here for lack of a better place.
+ */
+
+void
+FX_grColorMaskv(GLcontext *ctx, const GLboolean rgba[4])
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   LOCK_HARDWARE(fxMesa);
+   if (ctx->Visual.redBits == 8) {
+      /* 32bpp mode */
+      ASSERT( fxMesa->Glide.grColorMaskExt );
+      fxMesa->Glide.grColorMaskExt(rgba[RCOMP], rgba[GCOMP],
+                                   rgba[BCOMP], rgba[ACOMP]);
+   }
+   else {
+      /* 16 bpp mode */
+      /* we never have an alpha buffer */
+      fxMesa->Glide.grColorMask(rgba[RCOMP] || rgba[GCOMP] || rgba[BCOMP],
+                                GL_FALSE);
+   }
+   UNLOCK_HARDWARE(fxMesa);
+}
+
+void
+FX_grColorMaskv_NoLock(GLcontext *ctx, const GLboolean rgba[4])
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   if (ctx->Visual.redBits == 8) {
+      /* 32bpp mode */
+      ASSERT( fxMesa->Glide.grColorMaskExt );
+      fxMesa->Glide.grColorMaskExt(rgba[RCOMP], rgba[GCOMP],
+                                   rgba[BCOMP], rgba[ACOMP]);
+   }
+   else {
+      /* 16 bpp mode */
+      /* we never have an alpha buffer */
+      fxMesa->Glide.grColorMask(rgba[RCOMP] || rgba[GCOMP] || rgba[BCOMP],
+                                GL_FALSE);
+   }
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_dd.h b/src/mesa/drivers/dri/tdfx/tdfx_dd.h
new file mode 100644 (file)
index 0000000..dbb585e
--- /dev/null
@@ -0,0 +1,47 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_dd.h,v 1.1 2001/03/21 16:14:27 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_DD_H__
+#define __TDFX_DD_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "context.h"
+
+extern void tdfxDDInitDriverFuncs( GLcontext *ctx );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_glide.h b/src/mesa/drivers/dri/tdfx/tdfx_glide.h
new file mode 100644 (file)
index 0000000..f077aa6
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+ * This file defines macros and types necessary for accessing glide3.
+ */
+
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_glide.h,v 1.1 2002/02/22 21:45:03 dawes Exp $ */
+
+#ifndef NEWGLIDE_H
+#define NEWGLIDE_H
+
+#define FX_CALL
+
+typedef unsigned char FxU8;
+typedef signed char FxI8;
+typedef unsigned short FxU16;
+typedef signed short FxI16;
+#if defined(__alpha__) || defined (__LP64__)
+typedef signed int FxI32;
+typedef unsigned int FxU32;
+#else
+typedef signed long FxI32;
+typedef unsigned long FxU32;
+#endif
+typedef unsigned long AnyPtr;
+typedef int FxBool;
+typedef float FxFloat;
+typedef double FxDouble;
+
+typedef unsigned long FxColor_t;
+typedef struct
+{
+   float r, g, b, a;
+}
+FxColor4;
+
+typedef FxU32 GrColor_t;
+typedef FxU8 GrAlpha_t;
+typedef FxU32 GrMipMapId_t;
+typedef FxU32 GrStipplePattern_t;
+typedef FxU8 GrFog_t;
+typedef FxU32 GrContext_t;
+typedef int (FX_CALL * GrProc) (void);
+
+#define FXTRUE 1
+#define FXFALSE 0
+
+#define FXBIT(i) (1L << (i))
+
+#define GR_NULL_MIPMAP_HANDLE  ((GrMipMapId_t) -1)
+
+#define GR_MIPMAPLEVELMASK_EVEN FXBIT(0)
+#define GR_MIPMAPLEVELMASK_ODD FXBIT(1)
+#define GR_MIPMAPLEVELMASK_BOTH (GR_MIPMAPLEVELMASK_EVEN | GR_MIPMAPLEVELMASK_ODD )
+
+typedef FxI32 GrChipID_t;
+#define GR_TMU0 0x0
+#define GR_TMU1 0x1
+#define GR_TMU2 0x2
+
+#define GR_FBI  0x0
+
+typedef FxI32 GrCombineFunction_t;
+#define GR_COMBINE_FUNCTION_ZERO        0x0
+#define GR_COMBINE_FUNCTION_NONE        GR_COMBINE_FUNCTION_ZERO
+#define GR_COMBINE_FUNCTION_LOCAL       0x1
+#define GR_COMBINE_FUNCTION_LOCAL_ALPHA 0x2
+#define GR_COMBINE_FUNCTION_SCALE_OTHER 0x3
+#define GR_COMBINE_FUNCTION_BLEND_OTHER GR_COMBINE_FUNCTION_SCALE_OTHER
+#define GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL 0x4
+#define GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL_ALPHA 0x5
+#define GR_COMBINE_FUNCTION_SCALE_OTHER_MINUS_LOCAL 0x6
+#define GR_COMBINE_FUNCTION_SCALE_OTHER_MINUS_LOCAL_ADD_LOCAL 0x7
+#define GR_COMBINE_FUNCTION_BLEND GR_COMBINE_FUNCTION_SCALE_OTHER_MINUS_LOCAL_ADD_LOCAL
+#define GR_COMBINE_FUNCTION_SCALE_OTHER_MINUS_LOCAL_ADD_LOCAL_ALPHA 0x8
+#define GR_COMBINE_FUNCTION_SCALE_MINUS_LOCAL_ADD_LOCAL 0x9
+#define GR_COMBINE_FUNCTION_BLEND_LOCAL GR_COMBINE_FUNCTION_SCALE_MINUS_LOCAL_ADD_LOCAL
+#define GR_COMBINE_FUNCTION_SCALE_MINUS_LOCAL_ADD_LOCAL_ALPHA 0x10
+
+typedef FxI32 GrCombineFactor_t;
+#define GR_COMBINE_FACTOR_ZERO          0x0
+#define GR_COMBINE_FACTOR_NONE          GR_COMBINE_FACTOR_ZERO
+#define GR_COMBINE_FACTOR_LOCAL         0x1
+#define GR_COMBINE_FACTOR_OTHER_ALPHA   0x2
+#define GR_COMBINE_FACTOR_LOCAL_ALPHA   0x3
+#define GR_COMBINE_FACTOR_TEXTURE_ALPHA 0x4
+#define GR_COMBINE_FACTOR_TEXTURE_RGB   0x5
+#define GR_COMBINE_FACTOR_DETAIL_FACTOR GR_COMBINE_FACTOR_TEXTURE_ALPHA
+#define GR_COMBINE_FACTOR_LOD_FRACTION  0x5
+#define GR_COMBINE_FACTOR_ONE           0x8
+#define GR_COMBINE_FACTOR_ONE_MINUS_LOCAL 0x9
+#define GR_COMBINE_FACTOR_ONE_MINUS_OTHER_ALPHA 0xa
+#define GR_COMBINE_FACTOR_ONE_MINUS_LOCAL_ALPHA 0xb
+#define GR_COMBINE_FACTOR_ONE_MINUS_TEXTURE_ALPHA 0xc
+#define GR_COMBINE_FACTOR_ONE_MINUS_DETAIL_FACTOR GR_COMBINE_FACTOR_ONE_MINUS_TEXTURE_ALPHA
+#define GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION 0xd
+
+typedef FxI32 GrCombineLocal_t;
+#define GR_COMBINE_LOCAL_ITERATED 0x0
+#define GR_COMBINE_LOCAL_CONSTANT 0x1
+#define GR_COMBINE_LOCAL_NONE GR_COMBINE_LOCAL_CONSTANT
+#define GR_COMBINE_LOCAL_DEPTH  0x2
+
+typedef FxI32 GrCombineOther_t;
+#define GR_COMBINE_OTHER_ITERATED 0x0
+#define GR_COMBINE_OTHER_TEXTURE 0x1
+#define GR_COMBINE_OTHER_CONSTANT 0x2
+#define GR_COMBINE_OTHER_NONE GR_COMBINE_OTHER_CONSTANT
+
+typedef FxI32 GrAlphaSource_t;
+#define GR_ALPHASOURCE_CC_ALPHA 0x0
+#define GR_ALPHASOURCE_ITERATED_ALPHA 0x1
+#define GR_ALPHASOURCE_TEXTURE_ALPHA 0x2
+#define GR_ALPHASOURCE_TEXTURE_ALPHA_TIMES_ITERATED_ALPHA 0x3
+
+typedef FxI32 GrColorCombineFnc_t;
+#define GR_COLORCOMBINE_ZERO 0x0
+#define GR_COLORCOMBINE_CCRGB 0x1
+#define GR_COLORCOMBINE_ITRGB 0x2
+#define GR_COLORCOMBINE_ITRGB_DELTA0 0x3
+#define GR_COLORCOMBINE_DECAL_TEXTURE 0x4
+#define GR_COLORCOMBINE_TEXTURE_TIMES_CCRGB 0x5
+#define GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB 0x6
+#define GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB_DELTA0 0x7
+#define GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB_ADD_ALPHA 0x8
+#define GR_COLORCOMBINE_TEXTURE_TIMES_ALPHA 0x9
+#define GR_COLORCOMBINE_TEXTURE_TIMES_ALPHA_ADD_ITRGB 0xa
+#define GR_COLORCOMBINE_TEXTURE_ADD_ITRGB 0xb
+#define GR_COLORCOMBINE_TEXTURE_SUB_ITRGB 0xc
+#define GR_COLORCOMBINE_CCRGB_BLEND_ITRGB_ON_TEXALPHA 0xd
+#define GR_COLORCOMBINE_DIFF_SPEC_A 0xe
+#define GR_COLORCOMBINE_DIFF_SPEC_B 0xf
+#define GR_COLORCOMBINE_ONE 0x10
+
+typedef FxI32 GrAlphaBlendFnc_t;
+#define GR_BLEND_ZERO 0x0
+#define GR_BLEND_SRC_ALPHA 0x1
+#define GR_BLEND_SRC_COLOR 0x2
+#define GR_BLEND_DST_COLOR GR_BLEND_SRC_COLOR
+#define GR_BLEND_DST_ALPHA 0x3
+#define GR_BLEND_ONE 0x4
+#define GR_BLEND_ONE_MINUS_SRC_ALPHA 0x5
+#define GR_BLEND_ONE_MINUS_SRC_COLOR 0x6
+#define GR_BLEND_ONE_MINUS_DST_COLOR GR_BLEND_ONE_MINUS_SRC_COLOR
+#define GR_BLEND_ONE_MINUS_DST_ALPHA 0x7
+#define GR_BLEND_RESERVED_8 0x8
+#define GR_BLEND_RESERVED_9 0x9
+#define GR_BLEND_RESERVED_A 0xa
+#define GR_BLEND_RESERVED_B 0xb
+#define GR_BLEND_RESERVED_C 0xc
+#define GR_BLEND_RESERVED_D 0xd
+#define GR_BLEND_RESERVED_E 0xe
+#define GR_BLEND_ALPHA_SATURATE 0xf
+#define GR_BLEND_PREFOG_COLOR GR_BLEND_ALPHA_SATURATE
+#define GR_BLEND_SAME_COLOR_EXT           0x08
+#define GR_BLEND_ONE_MINUS_SAME_COLOR_EXT 0x09
+
+typedef FxI32 GrAspectRatio_t;
+#define GR_ASPECT_LOG2_8x1        3
+#define GR_ASPECT_LOG2_4x1        2
+#define GR_ASPECT_LOG2_2x1        1
+#define GR_ASPECT_LOG2_1x1        0
+#define GR_ASPECT_LOG2_1x2       -1
+#define GR_ASPECT_LOG2_1x4       -2
+#define GR_ASPECT_LOG2_1x8       -3
+
+typedef FxI32 GrBuffer_t;
+#define GR_BUFFER_FRONTBUFFER   0x0
+#define GR_BUFFER_BACKBUFFER    0x1
+#define GR_BUFFER_AUXBUFFER     0x2
+#define GR_BUFFER_DEPTHBUFFER   0x3
+#define GR_BUFFER_ALPHABUFFER   0x4
+#define GR_BUFFER_TRIPLEBUFFER  0x5
+
+typedef FxI32 GrChromakeyMode_t;
+#define GR_CHROMAKEY_DISABLE    0x0
+#define GR_CHROMAKEY_ENABLE     0x1
+
+typedef FxI32 GrChromaRangeMode_t;
+#define GR_CHROMARANGE_RGB_ALL_EXT  0x0
+
+#define GR_CHROMARANGE_DISABLE_EXT  0x00
+#define GR_CHROMARANGE_ENABLE_EXT   0x01
+
+typedef FxI32 GrTexChromakeyMode_t;
+#define GR_TEXCHROMA_DISABLE_EXT               0x0
+#define GR_TEXCHROMA_ENABLE_EXT                0x1
+
+#define GR_TEXCHROMARANGE_RGB_ALL_EXT  0x0
+
+typedef FxI32 GrCmpFnc_t;
+#define GR_CMP_NEVER    0x0
+#define GR_CMP_LESS     0x1
+#define GR_CMP_EQUAL    0x2
+#define GR_CMP_LEQUAL   0x3
+#define GR_CMP_GREATER  0x4
+#define GR_CMP_NOTEQUAL 0x5
+#define GR_CMP_GEQUAL   0x6
+#define GR_CMP_ALWAYS   0x7
+
+typedef FxI32 GrColorFormat_t;
+#define GR_COLORFORMAT_ARGB     0x0
+#define GR_COLORFORMAT_ABGR     0x1
+
+#define GR_COLORFORMAT_RGBA     0x2
+#define GR_COLORFORMAT_BGRA     0x3
+
+typedef FxI32 GrCullMode_t;
+#define GR_CULL_DISABLE         0x0
+#define GR_CULL_NEGATIVE        0x1
+#define GR_CULL_POSITIVE        0x2
+
+typedef FxI32 GrDepthBufferMode_t;
+#define GR_DEPTHBUFFER_DISABLE                  0x0
+#define GR_DEPTHBUFFER_ZBUFFER                  0x1
+#define GR_DEPTHBUFFER_WBUFFER                  0x2
+#define GR_DEPTHBUFFER_ZBUFFER_COMPARE_TO_BIAS  0x3
+#define GR_DEPTHBUFFER_WBUFFER_COMPARE_TO_BIAS  0x4
+
+typedef FxI32 GrDitherMode_t;
+#define GR_DITHER_DISABLE       0x0
+#define GR_DITHER_2x2           0x1
+#define GR_DITHER_4x4           0x2
+
+typedef FxI32 GrStippleMode_t;
+#define GR_STIPPLE_DISABLE     0x0
+#define GR_STIPPLE_PATTERN     0x1
+#define GR_STIPPLE_ROTATE      0x2
+
+typedef FxI32 GrFogMode_t;
+#define GR_FOG_DISABLE                     0x0
+#define GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT  0x1
+#define GR_FOG_WITH_TABLE_ON_Q             0x2
+#define GR_FOG_WITH_TABLE_ON_W             GR_FOG_WITH_TABLE_ON_Q
+#define GR_FOG_WITH_ITERATED_Z             0x3
+#define GR_FOG_WITH_ITERATED_ALPHA_EXT     0x4
+#define GR_FOG_MULT2                       0x100
+#define GR_FOG_ADD2                        0x200
+
+typedef FxU32 GrLock_t;
+#define GR_LFB_READ_ONLY  0x00
+#define GR_LFB_WRITE_ONLY 0x01
+#define GR_LFB_IDLE       0x00
+#define GR_LFB_NOIDLE     0x10
+
+typedef FxI32 GrLfbBypassMode_t;
+#define GR_LFBBYPASS_DISABLE    0x0
+#define GR_LFBBYPASS_ENABLE     0x1
+
+typedef FxI32 GrLfbWriteMode_t;
+#define GR_LFBWRITEMODE_565        0x0
+#define GR_LFBWRITEMODE_555        0x1
+#define GR_LFBWRITEMODE_1555       0x2
+#define GR_LFBWRITEMODE_RESERVED1  0x3
+#define GR_LFBWRITEMODE_888        0x4
+#define GR_LFBWRITEMODE_8888       0x5
+#define GR_LFBWRITEMODE_RESERVED2  0x6
+#define GR_LFBWRITEMODE_RESERVED3  0x7
+#define GR_LFBWRITEMODE_RESERVED4  0x8
+#define GR_LFBWRITEMODE_RESERVED5  0x9
+#define GR_LFBWRITEMODE_RESERVED6  0xa
+#define GR_LFBWRITEMODE_RESERVED7  0xb
+#define GR_LFBWRITEMODE_565_DEPTH  0xc
+#define GR_LFBWRITEMODE_555_DEPTH  0xd
+#define GR_LFBWRITEMODE_1555_DEPTH 0xe
+#define GR_LFBWRITEMODE_ZA16       0xf
+#define GR_LFBWRITEMODE_ANY        0xFF
+
+typedef FxI32 GrOriginLocation_t;
+#define GR_ORIGIN_UPPER_LEFT    0x0
+#define GR_ORIGIN_LOWER_LEFT    0x1
+#define GR_ORIGIN_ANY           0xFF
+
+typedef struct
+{
+   int size;
+   void *lfbPtr;
+   FxU32 strideInBytes;
+   GrLfbWriteMode_t writeMode;
+   GrOriginLocation_t origin;
+}
+GrLfbInfo_t;
+
+typedef FxI32 GrLOD_t;
+#define GR_LOD_LOG2_2048        0xb
+#define GR_LOD_LOG2_1024        0xa
+#define GR_LOD_LOG2_512         0x9
+#define GR_LOD_LOG2_256         0x8
+#define GR_LOD_LOG2_128         0x7
+#define GR_LOD_LOG2_64          0x6
+#define GR_LOD_LOG2_32          0x5
+#define GR_LOD_LOG2_16          0x4
+#define GR_LOD_LOG2_8           0x3
+#define GR_LOD_LOG2_4           0x2
+#define GR_LOD_LOG2_2           0x1
+#define GR_LOD_LOG2_1           0x0
+
+typedef FxI32 GrMipMapMode_t;
+#define GR_MIPMAP_DISABLE               0x0
+#define GR_MIPMAP_NEAREST               0x1
+#define GR_MIPMAP_NEAREST_DITHER        0x2
+
+typedef FxI32 GrSmoothingMode_t;
+#define GR_SMOOTHING_DISABLE    0x0
+#define GR_SMOOTHING_ENABLE     0x1
+
+typedef FxI32 GrTextureClampMode_t;
+#define GR_TEXTURECLAMP_WRAP        0x0
+#define GR_TEXTURECLAMP_CLAMP       0x1
+#define GR_TEXTURECLAMP_MIRROR_EXT  0x2
+
+typedef FxI32 GrTextureCombineFnc_t;
+#define GR_TEXTURECOMBINE_ZERO          0x0
+#define GR_TEXTURECOMBINE_DECAL         0x1
+#define GR_TEXTURECOMBINE_OTHER         0x2
+#define GR_TEXTURECOMBINE_ADD           0x3
+#define GR_TEXTURECOMBINE_MULTIPLY      0x4
+#define GR_TEXTURECOMBINE_SUBTRACT      0x5
+#define GR_TEXTURECOMBINE_DETAIL        0x6
+#define GR_TEXTURECOMBINE_DETAIL_OTHER  0x7
+#define GR_TEXTURECOMBINE_TRILINEAR_ODD 0x8
+#define GR_TEXTURECOMBINE_TRILINEAR_EVEN 0x9
+#define GR_TEXTURECOMBINE_ONE           0xa
+
+typedef FxI32 GrTextureFilterMode_t;
+#define GR_TEXTUREFILTER_POINT_SAMPLED  0x0
+#define GR_TEXTUREFILTER_BILINEAR       0x1
+
+typedef FxI32 GrTextureFormat_t;
+#define GR_TEXFMT_8BIT                  0x0
+#define GR_TEXFMT_RGB_332 GR_TEXFMT_8BIT
+#define GR_TEXFMT_YIQ_422               0x1
+#define GR_TEXFMT_ALPHA_8               0x2
+#define GR_TEXFMT_INTENSITY_8           0x3
+#define GR_TEXFMT_ALPHA_INTENSITY_44    0x4
+#define GR_TEXFMT_P_8                   0x5
+#define GR_TEXFMT_RSVD0                 0x6
+#define GR_TEXFMT_RSVD1                 0x7
+#define GR_TEXFMT_16BIT                 0x8
+#define GR_TEXFMT_ARGB_8332 GR_TEXFMT_16BIT
+#define GR_TEXFMT_AYIQ_8422             0x9
+#define GR_TEXFMT_RGB_565               0xa
+#define GR_TEXFMT_ARGB_1555             0xb
+#define GR_TEXFMT_ARGB_4444             0xc
+#define GR_TEXFMT_ALPHA_INTENSITY_88    0xd
+#define GR_TEXFMT_AP_88                 0xe
+#define GR_TEXFMT_RSVD2                 0xf
+#define GR_TEXFMT_ARGB_CMP_FXT1           0x11
+#define GR_TEXFMT_ARGB_8888               0x12
+#define GR_TEXFMT_YUYV_422                0x13
+#define GR_TEXFMT_UYVY_422                0x14
+#define GR_TEXFMT_AYUV_444                0x15
+#define GR_TEXFMT_ARGB_CMP_DXT1           0x16
+#define GR_TEXFMT_ARGB_CMP_DXT2           0x17
+#define GR_TEXFMT_ARGB_CMP_DXT3           0x18
+#define GR_TEXFMT_ARGB_CMP_DXT4           0x19
+#define GR_TEXFMT_ARGB_CMP_DXT5           0x1A
+
+typedef FxU32 GrTexTable_t;
+#define GR_TEXTABLE_NCC0                 0x0
+#define GR_TEXTABLE_NCC1                 0x1
+#define GR_TEXTABLE_PALETTE              0x2
+#define GR_TEXTABLE_PALETTE_6666_EXT     0x3
+
+typedef FxU32 GrNCCTable_t;
+#define GR_NCCTABLE_NCC0    0x0
+#define GR_NCCTABLE_NCC1    0x1
+
+typedef FxU32 GrTexBaseRange_t;
+#define GR_TEXBASE_256      0x3
+#define GR_TEXBASE_128      0x2
+#define GR_TEXBASE_64       0x1
+#define GR_TEXBASE_32_TO_1  0x0
+#define GR_TEXBASE_2048     0x7
+#define GR_TEXBASE_1024     0x6
+#define GR_TEXBASE_512      0x5
+#define GR_TEXBASE_256_TO_1 0x4
+
+typedef FxU32 GrEnableMode_t;
+#define GR_MODE_DISABLE     0x0
+#define GR_MODE_ENABLE      0x1
+
+#define GR_AA_ORDERED            0x01
+#define GR_ALLOW_MIPMAP_DITHER   0x02
+#define GR_PASSTHRU              0x03
+#define GR_SHAMELESS_PLUG        0x04
+#define GR_VIDEO_SMOOTHING       0x05
+
+typedef FxU32 GrCoordinateSpaceMode_t;
+#define GR_WINDOW_COORDS    0x00
+#define GR_CLIP_COORDS      0x01
+
+/* Parameters for strips */
+#define GR_PARAM_XY       0x01
+#define GR_PARAM_Z        0x02
+#define GR_PARAM_W        0x03
+#define GR_PARAM_Q        0x04
+#define GR_PARAM_FOG_EXT  0x05
+
+#define GR_PARAM_A        0x10
+
+#define GR_PARAM_RGB      0x20
+
+#define GR_PARAM_PARGB    0x30
+
+#define GR_PARAM_ST0      0x40
+#define GR_PARAM_ST1      GR_PARAM_ST0+1
+#define GR_PARAM_ST2      GR_PARAM_ST0+2
+
+#define GR_PARAM_Q0       0x50
+#define GR_PARAM_Q1       GR_PARAM_Q0+1
+#define GR_PARAM_Q2       GR_PARAM_Q0+2
+
+#define GR_PARAM_DISABLE  0x00
+#define GR_PARAM_ENABLE   0x01
+
+/* grDrawVertexArray/grDrawVertexArrayContiguous */
+#define GR_POINTS                        0
+#define GR_LINE_STRIP                    1
+#define GR_LINES                         2
+#define GR_POLYGON                       3
+#define GR_TRIANGLE_STRIP                4
+#define GR_TRIANGLE_FAN                  5
+#define GR_TRIANGLES                     6
+#define GR_TRIANGLE_STRIP_CONTINUE       7
+#define GR_TRIANGLE_FAN_CONTINUE         8
+
+/* grGet/grReset */
+#define GR_BITS_DEPTH                   0x01
+#define GR_BITS_RGBA                    0x02
+#define GR_FIFO_FULLNESS                0x03
+#define GR_FOG_TABLE_ENTRIES            0x04
+#define GR_GAMMA_TABLE_ENTRIES          0x05
+#define GR_GLIDE_STATE_SIZE             0x06
+#define GR_GLIDE_VERTEXLAYOUT_SIZE      0x07
+#define GR_IS_BUSY                      0x08
+#define GR_LFB_PIXEL_PIPE               0x09
+#define GR_MAX_TEXTURE_SIZE             0x0a
+#define GR_MAX_TEXTURE_ASPECT_RATIO     0x0b
+#define GR_MEMORY_FB                    0x0c
+#define GR_MEMORY_TMU                   0x0d
+#define GR_MEMORY_UMA                   0x0e
+#define GR_NUM_BOARDS                   0x0f
+#define GR_NON_POWER_OF_TWO_TEXTURES    0x10
+#define GR_NUM_FB                       0x11
+#define GR_NUM_SWAP_HISTORY_BUFFER      0x12
+#define GR_NUM_TMU                      0x13
+#define GR_PENDING_BUFFERSWAPS          0x14
+#define GR_REVISION_FB                  0x15
+#define GR_REVISION_TMU                 0x16
+#define GR_STATS_LINES                  0x17
+#define GR_STATS_PIXELS_AFUNC_FAIL      0x18
+#define GR_STATS_PIXELS_CHROMA_FAIL     0x19
+#define GR_STATS_PIXELS_DEPTHFUNC_FAIL  0x1a
+#define GR_STATS_PIXELS_IN              0x1b
+#define GR_STATS_PIXELS_OUT             0x1c
+#define GR_STATS_PIXELS                 0x1d
+#define GR_STATS_POINTS                 0x1e
+#define GR_STATS_TRIANGLES_IN           0x1f
+#define GR_STATS_TRIANGLES_OUT          0x20
+#define GR_STATS_TRIANGLES              0x21
+#define GR_SWAP_HISTORY                 0x22
+#define GR_SUPPORTS_PASSTHRU            0x23
+#define GR_TEXTURE_ALIGN                0x24
+#define GR_VIDEO_POSITION               0x25
+#define GR_VIEWPORT                     0x26
+#define GR_WDEPTH_MIN_MAX               0x27
+#define GR_ZDEPTH_MIN_MAX               0x28
+#define GR_VERTEX_PARAMETER             0x29
+#define GR_BITS_GAMMA                   0x2a
+#define GR_GET_RESERVED_1               0x1000
+
+/* grGetString types */
+#define GR_EXTENSION                    0xa0
+#define GR_HARDWARE                     0xa1
+#define GR_RENDERER                     0xa2
+#define GR_VENDOR                       0xa3
+#define GR_VERSION                      0xa4
+
+typedef FxI32 GrScreenRefresh_t;
+#define GR_REFRESH_NONE   0xff
+
+typedef FxI32 GrScreenResolution_t;
+#define GR_RESOLUTION_NONE      0xff
+
+typedef struct
+{
+   GrLOD_t smallLodLog2;
+   GrLOD_t largeLodLog2;
+   GrAspectRatio_t aspectRatioLog2;
+   GrTextureFormat_t format;
+   void *data;
+}
+GrTexInfo;
+
+typedef struct GrSstPerfStats_s
+{
+   FxU32 pixelsIn;
+   FxU32 chromaFail;
+   FxU32 zFuncFail;
+   FxU32 aFuncFail;
+   FxU32 pixelsOut;
+}
+GrSstPerfStats_t;
+
+typedef struct
+{
+   GrScreenResolution_t resolution;
+   GrScreenRefresh_t refresh;
+   int numColorBuffers;
+   int numAuxBuffers;
+}
+GrResolution;
+
+typedef GrResolution GlideResolution;
+#define GR_QUERY_ANY  ((FxU32)(~0))
+
+typedef FxU32 GrLfbSrcFmt_t;
+#define GR_LFB_SRC_FMT_565          0x00
+#define GR_LFB_SRC_FMT_555          0x01
+#define GR_LFB_SRC_FMT_1555         0x02
+#define GR_LFB_SRC_FMT_888          0x04
+#define GR_LFB_SRC_FMT_8888         0x05
+#define GR_LFB_SRC_FMT_565_DEPTH    0x0c
+#define GR_LFB_SRC_FMT_555_DEPTH    0x0d
+#define GR_LFB_SRC_FMT_1555_DEPTH   0x0e
+#define GR_LFB_SRC_FMT_ZA16         0x0f
+#define GR_LFB_SRC_FMT_RLE16        0x80
+
+typedef FxU32 GrPixelFormat_t;
+#define GR_PIXFMT_I_8                           0x0001
+#define GR_PIXFMT_AI_88                         0x0002
+#define GR_PIXFMT_RGB_565                       0x0003
+#define GR_PIXFMT_ARGB_1555                     0x0004
+#define GR_PIXFMT_ARGB_8888                     0x0005
+#define GR_PIXFMT_AA_2_RGB_565                  0x0006
+#define GR_PIXFMT_AA_2_ARGB_1555                0x0007
+#define GR_PIXFMT_AA_2_ARGB_8888                0x0008
+#define GR_PIXFMT_AA_4_RGB_565                  0x0009
+#define GR_PIXFMT_AA_4_ARGB_1555                0x000a
+#define GR_PIXFMT_AA_4_ARGB_8888                0x000b
+
+#define GR_LFBWRITEMODE_Z32                     0x0008
+
+typedef FxU32 GrAAMode_t;
+#define GR_AA_NONE                              0x0000
+#define GR_AA_4SAMPLES                          0x0001
+
+typedef FxU8 GrStencil_t;
+
+typedef FxU32 GrStencilOp_t;
+#define GR_STENCILOP_KEEP        0x00
+#define GR_STENCILOP_ZERO        0x01
+#define GR_STENCILOP_REPLACE     0x02
+#define GR_STENCILOP_INCR_CLAMP  0x03
+#define GR_STENCILOP_DECR_CLAMP  0x04
+#define GR_STENCILOP_INVERT      0x05
+#define GR_STENCILOP_INCR_WRAP   0x06
+#define GR_STENCILOP_DECR_WRAP   0x07
+
+#define GR_TEXTURE_UMA_EXT       0x06
+#define GR_STENCIL_MODE_EXT      0x07
+#define GR_OPENGL_MODE_EXT       0x08
+
+typedef FxU32 GrCCUColor_t;
+typedef FxU32 GrACUColor_t;
+typedef FxU32 GrTCCUColor_t;
+typedef FxU32 GrTACUColor_t;
+#define GR_CMBX_ZERO                      0x00
+#define GR_CMBX_TEXTURE_ALPHA             0x01
+#define GR_CMBX_ALOCAL                    0x02
+#define GR_CMBX_AOTHER                    0x03
+#define GR_CMBX_B                         0x04
+#define GR_CMBX_CONSTANT_ALPHA            0x05
+#define GR_CMBX_CONSTANT_COLOR            0x06
+#define GR_CMBX_DETAIL_FACTOR             0x07
+#define GR_CMBX_ITALPHA                   0x08
+#define GR_CMBX_ITRGB                     0x09
+#define GR_CMBX_LOCAL_TEXTURE_ALPHA       0x0a
+#define GR_CMBX_LOCAL_TEXTURE_RGB         0x0b
+#define GR_CMBX_LOD_FRAC                  0x0c
+#define GR_CMBX_OTHER_TEXTURE_ALPHA       0x0d
+#define GR_CMBX_OTHER_TEXTURE_RGB         0x0e
+#define GR_CMBX_TEXTURE_RGB               0x0f
+#define GR_CMBX_TMU_CALPHA                0x10
+#define GR_CMBX_TMU_CCOLOR                0x11
+
+typedef FxU32 GrCombineMode_t;
+#define GR_FUNC_MODE_ZERO                 0x00
+#define GR_FUNC_MODE_X                    0x01
+#define GR_FUNC_MODE_ONE_MINUS_X          0x02
+#define GR_FUNC_MODE_NEGATIVE_X           0x03
+#define GR_FUNC_MODE_X_MINUS_HALF         0x04
+
+typedef FxU32 GrAlphaBlendOp_t;
+#define GR_BLEND_OP_ADD                   0x00
+#define GR_BLEND_OP_SUB                   0x01
+#define GR_BLEND_OP_REVSUB                0x02
+
+typedef struct
+{
+   FxU32 data[256];
+}
+GuTexPalette;
+
+typedef void (*GrErrorCallbackFnc_t) (const char *string, FxBool fatal);
+
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_lock.c b/src/mesa/drivers/dri/tdfx/tdfx_lock.c
new file mode 100644 (file)
index 0000000..6bbfb8d
--- /dev/null
@@ -0,0 +1,90 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_lock.c,v 1.5 2002/12/16 16:19:00 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include "tdfx_context.h"
+#include "tdfx_lock.h"
+#include "tdfx_state.h"
+#include "tdfx_render.h"
+#include "tdfx_texman.h"
+#include "tdfx_tris.h"
+
+
+void tdfxGetLock( tdfxContextPtr fxMesa )
+{
+    __DRIcontextPrivate *cPriv = fxMesa->driContext;
+    __DRIdrawablePrivate *dPriv = cPriv->driDrawablePriv;
+    __DRIscreenPrivate *sPriv = dPriv->driScreenPriv;
+    TDFXSAREAPriv *saPriv = (TDFXSAREAPriv *) (((char *) sPriv->pSAREA) +
+                                       fxMesa->fxScreen->sarea_priv_offset);
+    unsigned int stamp = dPriv->lastStamp;
+
+    drmGetLock( fxMesa->driFd, fxMesa->hHWContext, 0 );
+
+    /* This macro will update dPriv's cliprects if needed */
+    DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv );
+
+    if ( saPriv->fifoOwner != fxMesa->hHWContext ) {
+        fxMesa->Glide.grDRIImportFifo( saPriv->fifoPtr, saPriv->fifoRead );
+    }
+
+    if ( saPriv->ctxOwner != fxMesa->hHWContext ) {
+        /* This sequence looks a little odd. Glide mirrors the state, and
+        * when you get the state you are forcing the mirror to be up to
+        * date, and then getting a copy from the mirror. You can then force
+        * that state onto the hardware when you set the state.
+        */
+        void *state;
+        FxI32 stateSize;
+        fxMesa->Glide.grGet(GR_GLIDE_STATE_SIZE, 4, &stateSize);
+        state = malloc(stateSize);
+        fxMesa->Glide.grGlideGetState( state );
+        fxMesa->Glide.grGlideSetState( state );
+        free( state );
+    }
+
+#if 0
+    if ( saPriv->texOwner != fxMesa->hHWContext ) {
+        tdfxTMRestoreTextures_NoLock( fxMesa );
+    }
+#endif
+
+    if ( *dPriv->pStamp != stamp || saPriv->ctxOwner != fxMesa->hHWContext ) {
+       tdfxUpdateClipping(fxMesa->glCtx);
+       tdfxUploadClipping(fxMesa);
+    }
+
+    DEBUG_LOCK();
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_lock.h b/src/mesa/drivers/dri/tdfx/tdfx_lock.h
new file mode 100644 (file)
index 0000000..90d4937
--- /dev/null
@@ -0,0 +1,149 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_lock.h,v 1.3 2002/02/22 21:45:03 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_LOCK_H__
+#define __TDFX_LOCK_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+/* You can turn this on to find locking conflicts.
+ */
+#define DEBUG_LOCKING          0
+
+#if DEBUG_LOCKING
+extern char *prevLockFile;
+extern int prevLockLine;
+
+#define DEBUG_LOCK()                                                   \
+   do {                                                                        \
+      prevLockFile = (__FILE__);                                       \
+      prevLockLine = (__LINE__);                                       \
+   } while (0)
+
+#define DEBUG_RESET()                                                  \
+   do {                                                                        \
+      prevLockFile = 0;                                                        \
+      prevLockLine = 0;                                                        \
+   } while (0)
+
+#define DEBUG_CHECK_LOCK()                                             \
+   do {                                                                        \
+      if ( prevLockFile ) {                                            \
+        fprintf( stderr,                                               \
+                 "LOCK SET!\n\tPrevious %s:%d\n\tCurrent: %s:%d\n",    \
+                 prevLockFile, prevLockLine, __FILE__, __LINE__ );     \
+        exit( 1 );                                                     \
+      }                                                                        \
+   } while (0)
+
+#else
+
+#define DEBUG_LOCK()
+#define DEBUG_RESET()
+#define DEBUG_CHECK_LOCK()
+
+#endif /* DEBUG_LOCKING */
+
+
+extern void tdfxGetLock( tdfxContextPtr fxMesa );
+
+
+/* !!! We may want to separate locks from locks with validation.
+   This could be used to improve performance for those things
+   commands that do not do any drawing !!! */
+
+#define DRM_LIGHT_LOCK_RETURN(fd,lock,context,__ret)                   \
+       do {                                                           \
+               DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret);     \
+                if (__ret) drmGetLock(fd,context,0);                   \
+        } while(0)
+
+#define LOCK_HARDWARE( fxMesa )                                                \
+   do {                                                                        \
+      char __ret = 0;                                                  \
+                                                                       \
+      DEBUG_CHECK_LOCK();                                              \
+      DRM_CAS( fxMesa->driHwLock, fxMesa->hHWContext,                  \
+             DRM_LOCK_HELD | fxMesa->hHWContext, __ret );              \
+      if ( __ret ) {                                                   \
+        tdfxGetLock( fxMesa );                                         \
+      }                                                                        \
+      DEBUG_LOCK();                                                    \
+   } while (0)
+
+/* Unlock the hardware using the global current context */
+#define UNLOCK_HARDWARE( fxMesa )                                      \
+  do {                                                                 \
+    DRM_UNLOCK( fxMesa->driFd, fxMesa->driHwLock, fxMesa->hHWContext );        \
+    DEBUG_RESET();                                                     \
+  } while (0)
+
+/*
+ * This pair of macros makes a loop over the drawing operations
+ * so it is not self contained and doesn't have the nice single
+ * statement semantics of most macros.
+ */
+#define BEGIN_CLIP_LOOP(fxMesa)                        \
+  do {                                         \
+    LOCK_HARDWARE( fxMesa );                   \
+    BEGIN_CLIP_LOOP_LOCKED( fxMesa )
+
+#define BEGIN_CLIP_LOOP_LOCKED(fxMesa)                         \
+  do {                                                         \
+    int _nc = fxMesa->numClipRects;                            \
+    while (_nc--) {                                            \
+      if (fxMesa->numClipRects > 1) {                          \
+        int _height = fxMesa->screen_height;                   \
+        fxMesa->Glide.grClipWindow(fxMesa->pClipRects[_nc].x1, \
+                     _height - fxMesa->pClipRects[_nc].y2,     \
+                     fxMesa->pClipRects[_nc].x2,               \
+                     _height - fxMesa->pClipRects[_nc].y1);    \
+      }
+
+
+#define END_CLIP_LOOP_LOCKED( fxMesa )         \
+    }                                          \
+  } while (0)
+
+#define END_CLIP_LOOP( fxMesa )                        \
+    END_CLIP_LOOP_LOCKED( fxMesa );            \
+    UNLOCK_HARDWARE( fxMesa );                 \
+  } while (0)
+
+
+#endif /* GLX_DIRECT_RENDERING */
+
+#endif /* __TDFX_LOCK_H__ */
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_pixels.c b/src/mesa/drivers/dri/tdfx/tdfx_pixels.c
new file mode 100644 (file)
index 0000000..803c8c5
--- /dev/null
@@ -0,0 +1,689 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_pixels.c,v 1.4 2002/02/22 21:45:03 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *     Nathan Hand <nhand@valinux.com>
+ *
+ */
+
+#include "tdfx_context.h"
+#include "tdfx_dd.h"
+#include "tdfx_lock.h"
+#include "tdfx_vb.h"
+#include "tdfx_pixels.h"
+#include "tdfx_render.h"
+
+#include "swrast/swrast.h"
+
+#include "image.h"
+
+
+#define FX_grLfbWriteRegion(fxMesa,dst_buffer,dst_x,dst_y,src_format,src_width,src_height,src_stride,src_data)         \
+  do {                         \
+    LOCK_HARDWARE(fxMesa);             \
+    fxMesa->Glide.grLfbWriteRegion(dst_buffer,dst_x,dst_y,src_format,src_width,src_height,FXFALSE,src_stride,src_data);        \
+    UNLOCK_HARDWARE(fxMesa);           \
+  } while(0)
+
+
+#define FX_grLfbReadRegion(fxMesa,src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data)                     \
+  do {                         \
+    LOCK_HARDWARE(fxMesa);             \
+    fxMesa->Glide.grLfbReadRegion(src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data);                            \
+    UNLOCK_HARDWARE(fxMesa);           \
+  } while (0);
+
+
+#if 0
+static FxBool
+FX_grLfbLock(tdfxContextPtr fxMesa, GrLock_t type, GrBuffer_t buffer,
+             GrLfbWriteMode_t writeMode, GrOriginLocation_t origin,
+             FxBool pixelPipeline, GrLfbInfo_t * info)
+{
+   FxBool result;
+
+   LOCK_HARDWARE(fxMesa);
+   result = fxMesa->Glide.grLfbLock(type, buffer, writeMode, origin, pixelPipeline, info);
+   UNLOCK_HARDWARE(fxMesa);
+   return result;
+}
+#endif
+
+
+#define FX_grLfbUnlock(fxMesa, t, b)   \
+  do {                                 \
+    LOCK_HARDWARE(fxMesa);             \
+    fxMesa->Glide.grLfbUnlock(t, b);   \
+    UNLOCK_HARDWARE(fxMesa);           \
+  } while (0)
+
+
+
+#if 0
+/* test if window coord (px,py) is visible */
+static GLboolean
+inClipRects(tdfxContextPtr fxMesa, int px, int py)
+{
+    int i;
+    for (i = 0; i < fxMesa->numClipRects; i++) {
+        if ((px >= fxMesa->pClipRects[i].x1) &&
+            (px < fxMesa->pClipRects[i].x2) &&
+            (py >= fxMesa->pClipRects[i].y1) &&
+            (py < fxMesa->pClipRects[i].y2)) return GL_TRUE;
+    }
+    return GL_FALSE;
+}
+#endif
+
+/* test if rectangle of pixels (px,py) (px+width,py+height) is visible */
+static GLboolean
+inClipRects_Region(tdfxContextPtr fxMesa, int x, int y, int width, int height)
+{
+    int i;
+    int x1, y1, x2, y2;
+    int xmin, xmax, ymin, ymax, pixelsleft;
+
+    y1 = y - height + 1; y2 = y;
+    x1 = x; x2 = x + width - 1;
+    pixelsleft = width * height;
+
+    for (i = 0; i < fxMesa->numClipRects; i++)
+    {
+        /* algorithm requires x1 < x2 and y1 < y2 */
+        if ((fxMesa->pClipRects[i].x1 < fxMesa->pClipRects[i].x2)) {
+            xmin = fxMesa->pClipRects[i].x1;
+            xmax = fxMesa->pClipRects[i].x2-1;
+        } else {
+            xmin = fxMesa->pClipRects[i].x2;
+            xmax = fxMesa->pClipRects[i].x1-1;
+        }
+        if ((fxMesa->pClipRects[i].y1 < fxMesa->pClipRects[i].y2)) {
+            ymin = fxMesa->pClipRects[i].y1;
+            ymax = fxMesa->pClipRects[i].y2-1;
+        } else {
+            ymin = fxMesa->pClipRects[i].y2;
+            ymax = fxMesa->pClipRects[i].y1-1;
+        }
+
+        /* reject trivial cases */
+        if (xmax < x1) continue;
+        if (ymax < y1) continue;
+        if (xmin > x2) continue;
+        if (ymin > y2) continue;
+
+        /* find the intersection */
+        if (xmin < x1) xmin = x1;
+        if (ymin < y1) ymin = y1;
+        if (xmax > x2) xmax = x2;
+        if (ymax > y2) ymax = y2;
+
+        pixelsleft -= (xmax-xmin+1) * (ymax-ymin+1);
+    }
+
+    return pixelsleft == 0;
+}
+
+#if 0
+GLboolean
+tdfx_bitmap_R5G6B5(GLcontext * ctx, GLint px, GLint py,
+                  GLsizei width, GLsizei height,
+                  const struct gl_pixelstore_attrib *unpack,
+                  const GLubyte * bitmap)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrLfbInfo_t info;
+   TdfxU16 color;
+   const struct gl_pixelstore_attrib *finalUnpack;
+   struct gl_pixelstore_attrib scissoredUnpack;
+
+   /* check if there's any raster operations enabled which we can't handle */
+   if (ctx->RasterMask & (ALPHATEST_BIT |
+                         BLEND_BIT |
+                         DEPTH_BIT |
+                         FOG_BIT |
+                         LOGIC_OP_BIT |
+                         SCISSOR_BIT |
+                         STENCIL_BIT |
+                         MASKING_BIT |
+                         ALPHABUF_BIT | MULTI_DRAW_BIT)) return GL_FALSE;
+
+   if (ctx->Scissor.Enabled) {
+      /* This is a bit tricky, but by carefully adjusting the px, py,
+       * width, height, skipPixels and skipRows values we can do
+       * scissoring without special code in the rendering loop.
+       */
+
+      /* we'll construct a new pixelstore struct */
+      finalUnpack = &scissoredUnpack;
+      scissoredUnpack = *unpack;
+      if (scissoredUnpack.RowLength == 0)
+        scissoredUnpack.RowLength = width;
+
+      /* clip left */
+      if (px < ctx->Scissor.X) {
+        scissoredUnpack.SkipPixels += (ctx->Scissor.X - px);
+        width -= (ctx->Scissor.X - px);
+        px = ctx->Scissor.X;
+      }
+      /* clip right */
+      if (px + width >= ctx->Scissor.X + ctx->Scissor.Width) {
+        width -= (px + width - (ctx->Scissor.X + ctx->Scissor.Width));
+      }
+      /* clip bottom */
+      if (py < ctx->Scissor.Y) {
+        scissoredUnpack.SkipRows += (ctx->Scissor.Y - py);
+        height -= (ctx->Scissor.Y - py);
+        py = ctx->Scissor.Y;
+      }
+      /* clip top */
+      if (py + height >= ctx->Scissor.Y + ctx->Scissor.Height) {
+        height -= (py + height - (ctx->Scissor.Y + ctx->Scissor.Height));
+      }
+
+      if (width <= 0 || height <= 0)
+        return GL_TRUE;     /* totally scissored away */
+   }
+   else {
+      finalUnpack = unpack;
+   }
+
+   /* compute pixel value */
+   {
+      GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0f);
+      GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0f);
+      GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0f);
+      /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f); */
+      if (fxMesa->bgrOrder) {
+        color = (TdfxU16)
+           (((TdfxU16) 0xf8 & b) << (11 - 3)) |
+           (((TdfxU16) 0xfc & g) << (5 - 3 + 1)) |
+           (((TdfxU16) 0xf8 & r) >> 3);
+      }
+      else
+        color = (TdfxU16)
+           (((TdfxU16) 0xf8 & r) << (11 - 3)) |
+           (((TdfxU16) 0xfc & g) << (5 - 3 + 1)) |
+           (((TdfxU16) 0xf8 & b) >> 3);
+   }
+
+   info.size = sizeof(info);
+   if (!TDFX_grLfbLock(fxMesa,
+                    GR_LFB_WRITE_ONLY,
+                    fxMesa->currentFB,
+                    GR_LFBWRITEMODE_565,
+                    GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) {
+#ifndef TDFX_SILENT
+      fprintf(stderr, "tdfx Driver: error locking the linear frame buffer\n");
+#endif
+      return GL_TRUE;
+   }
+
+   {
+      const GLint winX = fxMesa->x_offset;
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      /* The dest stride depends on the hardware and whether we're drawing
+       * to the front or back buffer.  This compile-time test seems to do
+       * the job for now.
+       */
+      const GLint dstStride = (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT)
+        ? (fxMesa->screen_width) : (info.strideInBytes / 2);
+      GLint row;
+      /* compute dest address of bottom-left pixel in bitmap */
+      GLushort *dst = (GLushort *) info.lfbPtr
+        + (winY - py) * dstStride + (winX + px);
+
+      for (row = 0; row < height; row++) {
+        const GLubyte *src =
+           (const GLubyte *) _mesa_image_address(finalUnpack,
+                                                 bitmap, width, height,
+                                                 GL_COLOR_INDEX,
+                                                 GL_BITMAP, 0, row, 0);
+        if (finalUnpack->LsbFirst) {
+           /* least significan bit first */
+           GLubyte mask = 1U << (finalUnpack->SkipPixels & 0x7);
+           GLint col;
+           for (col = 0; col < width; col++) {
+              if (*src & mask) {
+                 if (inClipRects(fxMesa, winX + px + col, winY - py - row))
+                    dst[col] = color;
+              }
+              if (mask == 128U) {
+                 src++;
+                 mask = 1U;
+              }
+              else {
+                 mask = mask << 1;
+              }
+           }
+           if (mask != 1)
+              src++;
+        }
+        else {
+           /* most significan bit first */
+           GLubyte mask = 128U >> (finalUnpack->SkipPixels & 0x7);
+           GLint col;
+           for (col = 0; col < width; col++) {
+              if (*src & mask) {
+                 if (inClipRects(fxMesa, winX + px + col, winY - py - row))
+                    dst[col] = color;
+              }
+              if (mask == 1U) {
+                 src++;
+                 mask = 128U;
+              }
+              else {
+                 mask = mask >> 1;
+              }
+           }
+           if (mask != 128)
+              src++;
+        }
+        dst -= dstStride;
+      }
+   }
+
+   TDFX_grLfbUnlock(fxMesa, GR_LFB_WRITE_ONLY, fxMesa->currentFB);
+   return GL_TRUE;
+}
+#endif
+
+#if 0
+GLboolean
+tdfx_bitmap_R8G8B8A8(GLcontext * ctx, GLint px, GLint py,
+                    GLsizei width, GLsizei height,
+                    const struct gl_pixelstore_attrib *unpack,
+                    const GLubyte * bitmap)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrLfbInfo_t info;
+   GLuint color;
+   const struct gl_pixelstore_attrib *finalUnpack;
+   struct gl_pixelstore_attrib scissoredUnpack;
+
+   /* check if there's any raster operations enabled which we can't handle */
+   if (ctx->RasterMask & (ALPHATEST_BIT |
+                         BLEND_BIT |
+                         DEPTH_BIT |
+                         FOG_BIT |
+                         LOGIC_OP_BIT |
+                         SCISSOR_BIT |
+                         STENCIL_BIT |
+                         MASKING_BIT |
+                         ALPHABUF_BIT | MULTI_DRAW_BIT)) return GL_FALSE;
+
+   if (ctx->Scissor.Enabled) {
+      /* This is a bit tricky, but by carefully adjusting the px, py,
+       * width, height, skipPixels and skipRows values we can do
+       * scissoring without special code in the rendering loop.
+       */
+
+      /* we'll construct a new pixelstore struct */
+      finalUnpack = &scissoredUnpack;
+      scissoredUnpack = *unpack;
+      if (scissoredUnpack.RowLength == 0)
+        scissoredUnpack.RowLength = width;
+
+      /* clip left */
+      if (px < ctx->Scissor.X) {
+        scissoredUnpack.SkipPixels += (ctx->Scissor.X - px);
+        width -= (ctx->Scissor.X - px);
+        px = ctx->Scissor.X;
+      }
+      /* clip right */
+      if (px + width >= ctx->Scissor.X + ctx->Scissor.Width) {
+        width -= (px + width - (ctx->Scissor.X + ctx->Scissor.Width));
+      }
+      /* clip bottom */
+      if (py < ctx->Scissor.Y) {
+        scissoredUnpack.SkipRows += (ctx->Scissor.Y - py);
+        height -= (ctx->Scissor.Y - py);
+        py = ctx->Scissor.Y;
+      }
+      /* clip top */
+      if (py + height >= ctx->Scissor.Y + ctx->Scissor.Height) {
+        height -= (py + height - (ctx->Scissor.Y + ctx->Scissor.Height));
+      }
+
+      if (width <= 0 || height <= 0)
+        return GL_TRUE;     /* totally scissored away */
+   }
+   else {
+      finalUnpack = unpack;
+   }
+
+   /* compute pixel value */
+   {
+      GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0f);
+      GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0f);
+      GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0f);
+      GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0f);
+      color = PACK_BGRA32(r, g, b, a);
+   }
+
+   info.size = sizeof(info);
+   if (!TDFX_grLfbLock(fxMesa, GR_LFB_WRITE_ONLY,
+                    fxMesa->currentFB, GR_LFBWRITEMODE_8888,
+                    GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) {
+#ifndef TDFX_SILENT
+      fprintf(stderr, "tdfx Driver: error locking the linear frame buffer\n");
+#endif
+      return GL_TRUE;
+   }
+
+   {
+      const GLint winX = fxMesa->x_offset;
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      GLint dstStride;
+      GLuint *dst;
+      GLint row;
+
+      if (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT) {
+        dstStride = fxMesa->screen_width;
+        dst =
+           (GLuint *) info.lfbPtr + (winY - py) * dstStride + (winX +
+                                                               px);
+      }
+      else {
+        dstStride = info.strideInBytes / 4;
+        dst =
+           (GLuint *) info.lfbPtr + (winY - py) * dstStride + (winX +
+                                                               px);
+      }
+
+      /* compute dest address of bottom-left pixel in bitmap */
+      for (row = 0; row < height; row++) {
+        const GLubyte *src =
+           (const GLubyte *) _mesa_image_address(finalUnpack,
+                                                 bitmap, width, height,
+                                                 GL_COLOR_INDEX,
+                                                 GL_BITMAP, 0, row, 0);
+        if (finalUnpack->LsbFirst) {
+           /* least significan bit first */
+           GLubyte mask = 1U << (finalUnpack->SkipPixels & 0x7);
+           GLint col;
+           for (col = 0; col < width; col++) {
+              if (*src & mask) {
+                 if (inClipRects(fxMesa, winX + px + col, winY - py - row))
+                    dst[col] = color;
+              }
+              if (mask == 128U) {
+                 src++;
+                 mask = 1U;
+              }
+              else {
+                 mask = mask << 1;
+              }
+           }
+           if (mask != 1)
+              src++;
+        }
+        else {
+           /* most significan bit first */
+           GLubyte mask = 128U >> (finalUnpack->SkipPixels & 0x7);
+           GLint col;
+           for (col = 0; col < width; col++) {
+              if (*src & mask) {
+                 if (inClipRects(fxMesa, winX + px + col, winY - py - row))
+                    dst[col] = color;
+              }
+              if (mask == 1U) {
+                 src++;
+                 mask = 128U;
+              }
+              else {
+                 mask = mask >> 1;
+              }
+           }
+           if (mask != 128)
+              src++;
+        }
+        dst -= dstStride;
+      }
+   }
+
+   TDFX_grLfbUnlock(fxMesa, GR_LFB_WRITE_ONLY, fxMesa->currentFB);
+   return GL_TRUE;
+}
+#endif
+
+void
+tdfx_readpixels_R5G6B5(GLcontext * ctx, GLint x, GLint y,
+                      GLsizei width, GLsizei height,
+                      GLenum format, GLenum type,
+                      const struct gl_pixelstore_attrib *packing,
+                      GLvoid * dstImage)
+{
+   if (format != GL_RGB ||
+       type != GL_UNSIGNED_SHORT_5_6_5 ||
+       (ctx->_ImageTransferState & (IMAGE_SCALE_BIAS_BIT|
+                                   IMAGE_MAP_COLOR_BIT)))
+   {
+      _swrast_ReadPixels( ctx, x, y, width, height, format, type, packing,
+                         dstImage );
+      return;
+   }
+
+   {
+      tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+      GrLfbInfo_t info;
+
+      const GLint winX = fxMesa->x_offset;
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      const GLint scrX = winX + x;
+      const GLint scrY = winY - y;
+
+      LOCK_HARDWARE( fxMesa );
+      info.size = sizeof(info);
+      if (fxMesa->Glide.grLfbLock(GR_LFB_READ_ONLY,
+                   fxMesa->ReadBuffer,
+                   GR_LFBWRITEMODE_ANY,
+                   GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) {
+        const GLint srcStride = (fxMesa->glCtx->Color.DrawBuffer ==
+            GL_FRONT) ? (fxMesa->screen_width) : (info.strideInBytes / 2);
+        const GLushort *src = (const GLushort *) info.lfbPtr
+           + scrY * srcStride + scrX;
+        GLubyte *dst = (GLubyte *) _mesa_image_address(packing,
+            dstImage, width, height, format, type, 0, 0, 0);
+        const GLint dstStride = _mesa_image_row_stride(packing,
+            width, format, type);
+
+        /* directly memcpy 5R6G5B pixels into client's buffer */
+        const GLint widthInBytes = width * 2;
+        GLint row;
+        for (row = 0; row < height; row++) {
+           MEMCPY(dst, src, widthInBytes);
+           dst += dstStride;
+           src -= srcStride;
+        }
+
+        fxMesa->Glide.grLfbUnlock(GR_LFB_READ_ONLY, fxMesa->ReadBuffer);
+      }
+      UNLOCK_HARDWARE( fxMesa );
+      return;
+   }
+}
+
+void
+tdfx_readpixels_R8G8B8A8(GLcontext * ctx, GLint x, GLint y,
+                         GLsizei width, GLsizei height,
+                         GLenum format, GLenum type,
+                         const struct gl_pixelstore_attrib *packing,
+                         GLvoid * dstImage)
+{
+   if ((!(format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8) &&
+       !(format == GL_BGRA && type == GL_UNSIGNED_BYTE)) ||
+       (ctx->_ImageTransferState & (IMAGE_SCALE_BIAS_BIT|
+                                   IMAGE_MAP_COLOR_BIT)))
+   {
+      _swrast_ReadPixels( ctx, x, y, width, height, format, type, packing,
+                         dstImage );
+      return;
+   }
+
+
+   {
+      tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+      GrLfbInfo_t info;
+
+      const GLint winX = fxMesa->x_offset;
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      const GLint scrX = winX + x;
+      const GLint scrY = winY - y;
+
+      LOCK_HARDWARE(fxMesa);
+      info.size = sizeof(info);
+      if (fxMesa->Glide.grLfbLock(GR_LFB_READ_ONLY,
+                    fxMesa->ReadBuffer,
+                    GR_LFBWRITEMODE_ANY,
+                    GR_ORIGIN_UPPER_LEFT, FXFALSE, &info))
+      {
+         const GLint srcStride = (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT)
+            ? (fxMesa->screen_width) : (info.strideInBytes / 4);
+         const GLuint *src = (const GLuint *) info.lfbPtr
+            + scrY * srcStride + scrX;
+         const GLint dstStride =
+            _mesa_image_row_stride(packing, width, format, type);
+         GLubyte *dst = (GLubyte *) _mesa_image_address(packing,
+            dstImage, width, height, format, type, 0, 0, 0);
+         const GLint widthInBytes = width * 4;
+
+        {
+            GLint row;
+            for (row = 0; row < height; row++) {
+               MEMCPY(dst, src, widthInBytes);
+               dst += dstStride;
+               src -= srcStride;
+            }
+         }
+
+         fxMesa->Glide.grLfbUnlock(GR_LFB_READ_ONLY, fxMesa->ReadBuffer);
+      }
+      UNLOCK_HARDWARE(fxMesa);
+   }
+}
+
+void
+tdfx_drawpixels_R8G8B8A8(GLcontext * ctx, GLint x, GLint y,
+                         GLsizei width, GLsizei height,
+                         GLenum format, GLenum type,
+                         const struct gl_pixelstore_attrib *unpack,
+                         const GLvoid * pixels)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if ((!(format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8) &&
+       !(format == GL_BGRA && type == GL_UNSIGNED_BYTE)) ||
+       ctx->Pixel.ZoomX != 1.0F || 
+       ctx->Pixel.ZoomY != 1.0F ||
+       (ctx->_ImageTransferState & (IMAGE_SCALE_BIAS_BIT|
+                                   IMAGE_MAP_COLOR_BIT)) ||
+       ctx->Color.AlphaEnabled ||
+       ctx->Depth.Test ||
+       ctx->Fog.Enabled ||
+       ctx->Scissor.Enabled ||
+       ctx->Stencil.Enabled ||
+       !ctx->Color.ColorMask[0] ||
+       !ctx->Color.ColorMask[1] ||
+       !ctx->Color.ColorMask[2] ||
+       !ctx->Color.ColorMask[3] ||
+       ctx->Color.ColorLogicOpEnabled ||
+       ctx->Texture._EnabledUnits ||
+       ctx->Depth.OcclusionTest ||
+       fxMesa->Fallback)       
+   {
+      _swrast_DrawPixels( ctx, x, y, width, height, format, type, 
+                         unpack, pixels );
+      return; 
+   }
+
+   {
+      tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+      GrLfbInfo_t info;
+      GLboolean result = GL_FALSE;
+
+      const GLint winX = fxMesa->x_offset;
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      const GLint scrX = winX + x;
+      const GLint scrY = winY - y;
+
+      /* lock early to make sure cliprects are right */
+      LOCK_HARDWARE(fxMesa);
+
+      /* make sure hardware has latest blend funcs */
+      if (ctx->Color.BlendEnabled) {
+         fxMesa->dirty |= TDFX_UPLOAD_BLEND_FUNC;
+         tdfxEmitHwStateLocked( fxMesa );
+      }
+
+      /* look for clipmasks, giveup if region obscured */
+      if (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT) {
+         if (!inClipRects_Region(fxMesa, scrX, scrY, width, height)) {
+            UNLOCK_HARDWARE(fxMesa);
+           _swrast_DrawPixels( ctx, x, y, width, height, format, type, 
+                               unpack, pixels );
+            return;
+         }
+      }
+
+      info.size = sizeof(info);
+      if (fxMesa->Glide.grLfbLock(GR_LFB_WRITE_ONLY,
+                    fxMesa->DrawBuffer,
+                    GR_LFBWRITEMODE_8888,
+                    GR_ORIGIN_UPPER_LEFT, FXTRUE, &info))
+      {
+         const GLint dstStride = (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT)
+            ? (fxMesa->screen_width * 4) : (info.strideInBytes);
+         GLubyte *dst = (GLubyte *) info.lfbPtr
+            + scrY * dstStride + scrX * 4;
+         const GLint srcStride =
+            _mesa_image_row_stride(unpack, width, format, type);
+         const GLubyte *src = (GLubyte *) _mesa_image_address(unpack,
+            pixels, width, height, format, type, 0, 0, 0);
+         const GLint widthInBytes = width * 4;
+
+         if ((format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8) ||
+             (format == GL_BGRA && type == GL_UNSIGNED_BYTE)) {
+            GLint row;
+            for (row = 0; row < height; row++) {
+               MEMCPY(dst, src, widthInBytes);
+               dst -= dstStride;
+               src += srcStride;
+            }
+            result = GL_TRUE;
+         }
+
+         fxMesa->Glide.grLfbUnlock(GR_LFB_WRITE_ONLY, fxMesa->DrawBuffer);
+      }
+      UNLOCK_HARDWARE(fxMesa);
+   }
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_pixels.h b/src/mesa/drivers/dri/tdfx/tdfx_pixels.h
new file mode 100644 (file)
index 0000000..93b7b88
--- /dev/null
@@ -0,0 +1,80 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_pixels.h,v 1.2 2002/02/22 21:45:03 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *     Nathan Hand <nhand@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_PIXELS_H__
+#define __TDFX_PIXELS_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "context.h"
+
+extern void
+tdfx_bitmap_R5G6B5( GLcontext *ctx, GLint px, GLint py,
+                   GLsizei width, GLsizei height,
+                   const struct gl_pixelstore_attrib *unpack,
+                   const GLubyte *bitmap );
+
+extern void
+tdfx_bitmap_R8G8B8A8( GLcontext *ctx, GLint px, GLint py,
+                     GLsizei width, GLsizei height,
+                     const struct gl_pixelstore_attrib *unpack,
+                     const GLubyte *bitmap );
+
+extern void
+tdfx_readpixels_R5G6B5( GLcontext *ctx, GLint x, GLint y,
+                       GLsizei width, GLsizei height,
+                       GLenum format, GLenum type,
+                       const struct gl_pixelstore_attrib *packing,
+                       GLvoid *dstImage );
+
+extern void
+tdfx_readpixels_R8G8B8A8( GLcontext *ctx, GLint x, GLint y,
+                         GLsizei width, GLsizei height,
+                         GLenum format, GLenum type,
+                         const struct gl_pixelstore_attrib *packing,
+                         GLvoid *dstImage );
+
+extern void
+tdfx_drawpixels_R8G8B8A8( GLcontext *ctx, GLint x, GLint y,
+                         GLsizei width, GLsizei height,
+                         GLenum format, GLenum type,
+                         const struct gl_pixelstore_attrib *unpack,
+                         const GLvoid *pixels );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_render.c b/src/mesa/drivers/dri/tdfx/tdfx_render.c
new file mode 100644 (file)
index 0000000..1cb3eed
--- /dev/null
@@ -0,0 +1,802 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_render.c,v 1.4 2002/02/22 21:45:03 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#include "tdfx_context.h"
+#include "tdfx_render.h"
+#include "tdfx_state.h"
+#include "tdfx_texman.h"
+#include "swrast/swrast.h"
+
+/* Clear the color and/or depth buffers.
+ */
+static void tdfxDDClear( GLcontext *ctx,
+                        GLbitfield mask, GLboolean all,
+                        GLint x, GLint y, GLint width, GLint height )
+{
+   tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
+   GLbitfield softwareMask = mask & (DD_ACCUM_BIT);
+   const GLuint stencil_size =
+      fxMesa->haveHwStencil ? fxMesa->glCtx->Visual.stencilBits : 0;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s( %d, %d, %d, %d )\n",
+              __FUNCTION__, (int) x, (int) y, (int) width, (int) height );
+   }
+
+   /* Need this check to respond to glScissor and clipping updates */
+   if ((fxMesa->new_state & (TDFX_NEW_CLIP | TDFX_NEW_DEPTH)) ||
+       (fxMesa->dirty & TDFX_UPLOAD_COLOR_MASK)) {
+      tdfxDDUpdateHwState(ctx);
+   }
+
+   /* we can't clear accum buffers */
+   mask &= ~(DD_ACCUM_BIT);
+
+   if (mask & DD_STENCIL_BIT) {
+      if (!fxMesa->haveHwStencil || ctx->Stencil.WriteMask[0] != 0xff) {
+         /* Napalm seems to have trouble with stencil write masks != 0xff */
+         /* do stencil clear in software */
+         mask &= ~(DD_STENCIL_BIT);
+         softwareMask |= DD_STENCIL_BIT;
+      }
+   }
+
+   if (fxMesa->glCtx->Visual.redBits != 8) {
+      /* can only do color masking if running in 24/32bpp on Napalm */
+      if (ctx->Color.ColorMask[RCOMP] != ctx->Color.ColorMask[GCOMP] ||
+          ctx->Color.ColorMask[GCOMP] != ctx->Color.ColorMask[BCOMP]) {
+         softwareMask |= (mask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT));
+         mask &= ~(DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT);
+      }
+   }
+
+   if (fxMesa->haveHwStencil) {
+      /*
+       * If we want to clear stencil, it must be enabled
+       * in the HW, even if the stencil test is not enabled
+       * in the OGL state.
+       */
+      LOCK_HARDWARE(fxMesa);
+      if (mask & DD_STENCIL_BIT) {
+        fxMesa->Glide.grStencilMask(/*ctx->Stencil.WriteMask*/ 0xff);
+        /* set stencil ref value = desired clear value */
+        fxMesa->Glide.grStencilFunc(GR_CMP_ALWAYS,
+                                     ctx->Stencil.Clear, 0xff);
+        fxMesa->Glide.grStencilOp(GR_STENCILOP_REPLACE,
+                                   GR_STENCILOP_REPLACE, GR_STENCILOP_REPLACE);
+        fxMesa->Glide.grEnable(GR_STENCIL_MODE_EXT);
+      }
+      else {
+        fxMesa->Glide.grDisable(GR_STENCIL_MODE_EXT);
+      }
+      UNLOCK_HARDWARE(fxMesa);
+   }
+
+   /*
+    * This may be ugly, but it's needed in order to work around a number
+    * of Glide bugs.
+    */
+   BEGIN_CLIP_LOOP(fxMesa);
+   {
+      /*
+       * This could probably be done fancier but doing each possible case
+       * explicitly is less error prone.
+       */
+      switch (mask & ~DD_STENCIL_BIT) {
+      case DD_BACK_LEFT_BIT | DD_DEPTH_BIT:
+        /* back buffer & depth */
+        FX_grColorMaskv_NoLock(ctx, true4); /* work around Voodoo3 bug */
+        fxMesa->Glide.grDepthMask(FXTRUE);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_BACKBUFFER);
+        if (stencil_size > 0) {
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+         }
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        if (!ctx->Depth.Mask || !ctx->Depth.Test) {
+            fxMesa->Glide.grDepthMask(FXFALSE);
+        }
+        break;
+      case DD_FRONT_LEFT_BIT | DD_DEPTH_BIT:
+        /* XXX it appears that the depth buffer isn't cleared when
+         * glRenderBuffer(GR_BUFFER_FRONTBUFFER) is set.
+         * This is a work-around/
+         */
+        /* clear depth */
+        fxMesa->Glide.grDepthMask(FXTRUE);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_BACKBUFFER);
+        FX_grColorMaskv_NoLock(ctx, false4);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        /* clear front */
+        FX_grColorMaskv_NoLock(ctx, true4);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        if (!ctx->Depth.Mask || !ctx->Depth.Test) {
+            fxMesa->Glide.grDepthMask(FXFALSE);
+        }
+        break;
+      case DD_BACK_LEFT_BIT:
+        /* back buffer only */
+        fxMesa->Glide.grDepthMask(FXFALSE);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_BACKBUFFER);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        if (ctx->Depth.Mask && ctx->Depth.Test) {
+            fxMesa->Glide.grDepthMask(FXTRUE);
+        }
+        break;
+      case DD_FRONT_LEFT_BIT:
+        /* front buffer only */
+        fxMesa->Glide.grDepthMask(FXFALSE);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        if (ctx->Depth.Mask && ctx->Depth.Test) {
+            fxMesa->Glide.grDepthMask(FXTRUE);
+        }
+        break;
+      case DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT:
+        /* front and back */
+        fxMesa->Glide.grDepthMask(FXFALSE);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_BACKBUFFER);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        if (ctx->Depth.Mask && ctx->Depth.Test) {
+            fxMesa->Glide.grDepthMask(FXTRUE);
+        }
+        break;
+      case DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT | DD_DEPTH_BIT:
+        /* clear front */
+        fxMesa->Glide.grDepthMask(FXFALSE);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        /* clear back and depth */
+        fxMesa->Glide.grDepthMask(FXTRUE);
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_BACKBUFFER);
+         if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        if (!ctx->Depth.Mask || !ctx->Depth.Mask) {
+            fxMesa->Glide.grDepthMask(FXFALSE);
+        }
+        break;
+      case DD_DEPTH_BIT:
+        /* just the depth buffer */
+        fxMesa->Glide.grRenderBuffer(GR_BUFFER_BACKBUFFER);
+        FX_grColorMaskv_NoLock(ctx, false4);
+        fxMesa->Glide.grDepthMask(FXTRUE);
+        if (stencil_size > 0)
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+        else
+            fxMesa->Glide.grBufferClear(fxMesa->Color.ClearColor,
+                                        fxMesa->Color.ClearAlpha,
+                                        fxMesa->Depth.Clear);
+        FX_grColorMaskv_NoLock(ctx, true4);
+        if (ctx->Color._DrawDestMask & FRONT_LEFT_BIT)
+            fxMesa->Glide.grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+        if (!ctx->Depth.Test || !ctx->Depth.Mask)
+           fxMesa->Glide.grDepthMask(FXFALSE);
+        break;
+      default:
+         /* clear no color buffers or depth buffer but might clear stencil */
+        if (stencil_size > 0 && (mask & DD_STENCIL_BIT)) {
+            /* XXX need this RenderBuffer call to work around Glide bug */
+            fxMesa->Glide.grRenderBuffer(GR_BUFFER_BACKBUFFER);
+            fxMesa->Glide.grDepthMask(FXFALSE);
+            FX_grColorMaskv_NoLock(ctx, false4);
+            fxMesa->Glide.grBufferClearExt(fxMesa->Color.ClearColor,
+                                           fxMesa->Color.ClearAlpha,
+                                           fxMesa->Depth.Clear,
+                                           (FxU32) ctx->Stencil.Clear);
+            if (ctx->Depth.Mask && ctx->Depth.Test) {
+               fxMesa->Glide.grDepthMask(FXTRUE);
+            }
+            FX_grColorMaskv_NoLock(ctx, true4);
+            if (ctx->Color._DrawDestMask & FRONT_LEFT_BIT)
+               fxMesa->Glide.grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+         }
+      }
+   }
+   END_CLIP_LOOP(fxMesa);
+
+   if (fxMesa->haveHwStencil && (mask & DD_STENCIL_BIT)) {
+      /* We changed the stencil state above.  Signal that we need to
+       * upload it again.
+       */
+      fxMesa->dirty |= TDFX_UPLOAD_STENCIL;
+   }
+
+   if (softwareMask)
+      _swrast_Clear( ctx, softwareMask, all, x, y, width, height );
+}
+
+
+
+static void tdfxDDFinish( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FLUSH_BATCH( fxMesa );
+
+   LOCK_HARDWARE( fxMesa );
+   fxMesa->Glide.grFinish();
+   UNLOCK_HARDWARE( fxMesa );
+}
+
+static void tdfxDDFlush( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FLUSH_BATCH( fxMesa );
+
+   LOCK_HARDWARE( fxMesa );
+   fxMesa->Glide.grFlush();
+   UNLOCK_HARDWARE( fxMesa );
+}
+
+
+#if 0
+static const char *texSource(int k)
+{
+   switch (k) {
+      case GR_CMBX_ZERO:
+         return "GR_CMBX_ZERO";
+      case GR_CMBX_TEXTURE_ALPHA:
+         return "GR_CMBX_TEXTURE_ALPHA";
+      case GR_CMBX_ALOCAL:
+         return "GR_CMBX_ALOCAL";
+      case GR_CMBX_AOTHER:
+         return "GR_CMBX_AOTHER";
+      case GR_CMBX_B:
+         return "GR_CMBX_B";
+      case GR_CMBX_CONSTANT_ALPHA:
+         return "GR_CMBX_CONSTANT_ALPHA";
+      case GR_CMBX_CONSTANT_COLOR:
+         return "GR_CMBX_CONSTANT_COLOR";
+      case GR_CMBX_DETAIL_FACTOR:
+         return "GR_CMBX_DETAIL_FACTOR";
+      case GR_CMBX_ITALPHA:
+         return "GR_CMBX_ITALPHA";
+      case GR_CMBX_ITRGB:
+         return "GR_CMBX_ITRGB";
+      case GR_CMBX_LOCAL_TEXTURE_ALPHA:
+         return "GR_CMBX_LOCAL_TEXTURE_ALPHA";
+      case GR_CMBX_LOCAL_TEXTURE_RGB:
+         return "GR_CMBX_LOCAL_TEXTURE_RGB";
+      case GR_CMBX_LOD_FRAC:
+         return "GR_CMBX_LOD_FRAC";
+      case GR_CMBX_OTHER_TEXTURE_ALPHA:
+         return "GR_CMBX_OTHER_TEXTURE_ALPHA";
+      case GR_CMBX_OTHER_TEXTURE_RGB:
+         return "GR_CMBX_OTHER_TEXTURE_RGB";
+      case GR_CMBX_TEXTURE_RGB:
+         return "GR_CMBX_TEXTURE_RGB";
+      case GR_CMBX_TMU_CALPHA:
+         return "GR_CMBX_TMU_CALPHA";
+      case GR_CMBX_TMU_CCOLOR:
+         return "GR_CMBX_TMU_CCOLOR";
+      default:
+         return "";
+   }
+}
+#endif
+
+#if 0
+static const char *texMode(int k)
+{
+   switch (k) {
+      case GR_FUNC_MODE_ZERO:
+         return "GR_FUNC_MODE_ZERO";
+      case GR_FUNC_MODE_X:
+         return "GR_FUNC_MODE_X";
+      case GR_FUNC_MODE_ONE_MINUS_X:
+         return "GR_FUNC_MODE_ONE_MINUS_X";
+      case GR_FUNC_MODE_NEGATIVE_X:
+         return "GR_FUNC_MODE_NEGATIVE_X";
+      case GR_FUNC_MODE_X_MINUS_HALF:
+         return "GR_FUNC_MODE_X_MINUS_HALF";
+      default:
+         return "";
+   }
+}
+#endif
+
+#if 0
+static const char *texInvert(int k)
+{
+   return k ? "FXTRUE" : "FXFALSE";
+}
+#endif
+
+static void uploadTextureEnv( tdfxContextPtr fxMesa )
+{
+   if (TDFX_IS_NAPALM(fxMesa)) {
+      int unit;
+      for (unit = 0; unit < TDFX_NUM_TMU; unit++) {
+#if 0
+         printf("upload env %d\n", unit);
+         printf("   cSourceA = %s\t", texSource(fxMesa->TexCombineExt[unit].Color.SourceA));
+         printf("     cModeA = %s\n", texMode(fxMesa->TexCombineExt[unit].Color.ModeA));
+         printf("   cSourceB = %s\t", texSource(fxMesa->TexCombineExt[unit].Color.SourceB));
+         printf("     cModeB = %s\n", texMode(fxMesa->TexCombineExt[unit].Color.ModeB));
+         printf("   cSourceC = %s\t", texSource(fxMesa->TexCombineExt[unit].Color.SourceC));
+         printf("   cInvertC = %s\n", texInvert(fxMesa->TexCombineExt[unit].Color.InvertC));
+         printf("   cSourceD = %s\t", texSource(fxMesa->TexCombineExt[unit].Color.SourceD));
+         printf("   cInvertD = %s\n", texInvert(fxMesa->TexCombineExt[unit].Color.InvertD));
+         printf("     cShift = %d\t", fxMesa->TexCombineExt[unit].Color.Shift);
+         printf("    cInvert = %d\n", fxMesa->TexCombineExt[unit].Color.Invert);
+         printf("   aSourceA = %s\t", texSource(fxMesa->TexCombineExt[unit].Alpha.SourceA));
+         printf("     aModeA = %s\n", texMode(fxMesa->TexCombineExt[unit].Alpha.ModeA));
+         printf("   aSourceB = %s\t", texSource(fxMesa->TexCombineExt[unit].Alpha.SourceB));
+         printf("     aModeB = %s\n", texMode(fxMesa->TexCombineExt[unit].Alpha.ModeB));
+         printf("   aSourceC = %s\t", texSource(fxMesa->TexCombineExt[unit].Alpha.SourceC));
+         printf("   aInvertC = %s\n", texInvert(fxMesa->TexCombineExt[unit].Alpha.InvertC));
+         printf("   aSourceD = %s\t", texSource(fxMesa->TexCombineExt[unit].Alpha.SourceD));
+         printf("   aInvertD = %s\n", texInvert(fxMesa->TexCombineExt[unit].Alpha.InvertD));
+         printf("     aShift = %d\t", fxMesa->TexCombineExt[unit].Alpha.Shift);
+         printf("    aInvert = %d\n", fxMesa->TexCombineExt[unit].Alpha.Invert);
+         printf("      Color = 0x%08x\n", fxMesa->TexCombineExt[unit].EnvColor);
+#endif
+         fxMesa->Glide.grTexColorCombineExt(TDFX_TMU0 + unit,
+                                     fxMesa->TexCombineExt[unit].Color.SourceA,
+                                     fxMesa->TexCombineExt[unit].Color.ModeA,
+                                     fxMesa->TexCombineExt[unit].Color.SourceB,
+                                     fxMesa->TexCombineExt[unit].Color.ModeB,
+                                     fxMesa->TexCombineExt[unit].Color.SourceC,
+                                     fxMesa->TexCombineExt[unit].Color.InvertC,
+                                     fxMesa->TexCombineExt[unit].Color.SourceD,
+                                     fxMesa->TexCombineExt[unit].Color.InvertD,
+                                     fxMesa->TexCombineExt[unit].Color.Shift,
+                                     fxMesa->TexCombineExt[unit].Color.Invert);
+         fxMesa->Glide.grTexAlphaCombineExt(TDFX_TMU0 + unit,
+                                     fxMesa->TexCombineExt[unit].Alpha.SourceA,
+                                     fxMesa->TexCombineExt[unit].Alpha.ModeA,
+                                     fxMesa->TexCombineExt[unit].Alpha.SourceB,
+                                     fxMesa->TexCombineExt[unit].Alpha.ModeB,
+                                     fxMesa->TexCombineExt[unit].Alpha.SourceC,
+                                     fxMesa->TexCombineExt[unit].Alpha.InvertC,
+                                     fxMesa->TexCombineExt[unit].Alpha.SourceD,
+                                     fxMesa->TexCombineExt[unit].Alpha.InvertD,
+                                     fxMesa->TexCombineExt[unit].Alpha.Shift,
+                                     fxMesa->TexCombineExt[unit].Alpha.Invert);
+         fxMesa->Glide.grConstantColorValueExt(TDFX_TMU0 + unit,
+                                        fxMesa->TexCombineExt[unit].EnvColor);
+      }
+   }
+   else {
+      /* Voodoo3 */
+      int unit;
+      for (unit = 0; unit < TDFX_NUM_TMU; unit++) {
+         struct tdfx_texcombine *comb = &fxMesa->TexCombine[unit];
+         fxMesa->Glide.grTexCombine(TDFX_TMU0 + unit,
+                                    comb->FunctionRGB,
+                                    comb->FactorRGB,
+                                    comb->FunctionAlpha,
+                                    comb->FactorAlpha,
+                                    comb->InvertRGB,
+                                    comb->InvertAlpha);
+      }
+   }
+}
+
+
+static void uploadTextureParams( tdfxContextPtr fxMesa )
+{
+   int unit;
+   for (unit = 0; unit < TDFX_NUM_TMU; unit++) {
+      const struct tdfx_texparams *p = &fxMesa->TexParams[unit];
+      /*
+      printf("upload params %d\n", unit);
+      printf("   clamp %x %x\n", env->sClamp, env->tClamp);
+      printf("   filter %x %x\n", env->minFilt, env->magFilt);
+      printf("   mipmap %x %x\n", env->mmMode, env->LODblend);
+      printf("   lod bias %f\n", env->LodBias);
+      */
+      fxMesa->Glide.grTexClampMode(GR_TMU0 + unit, p->sClamp, p->tClamp);
+      fxMesa->Glide.grTexFilterMode(GR_TMU0 + unit, p->minFilt, p->magFilt);
+      fxMesa->Glide.grTexMipMapMode(GR_TMU0 + unit, p->mmMode, p->LODblend);
+      fxMesa->Glide.grTexLodBiasValue(GR_TMU0 + unit, p->LodBias);
+   }
+}
+
+
+static void uploadTextureSource( tdfxContextPtr fxMesa )
+{
+   int unit;
+   for (unit = 0; unit < TDFX_NUM_TMU; unit++) {
+      const struct tdfx_texsource *src = &fxMesa->TexSource[unit];
+      /*
+      printf("upload source %d @ %d %p\n", unit, src->StartAddress, src->Info);
+      */
+      if (src->Info) {
+         /*
+         printf("  smallLodLog2=%d largeLodLog2=%d ar=%d format=%d data=%p\n",
+                src->Info->smallLodLog2, src->Info->largeLodLog2,
+                src->Info->aspectRatioLog2, src->Info->format,
+                src->Info->data);
+         */
+         fxMesa->Glide.grTexSource(GR_TMU0 + unit,
+                                   src->StartAddress,
+                                   src->EvenOdd,
+                                   src->Info);
+      }
+   }
+}
+
+
+static void uploadTextureImages( tdfxContextPtr fxMesa )
+{
+   GLcontext *ctx = fxMesa->glCtx;
+   int unit;
+   for (unit = 0; unit < TDFX_NUM_TMU; unit++) {
+      if (ctx->Texture.Unit[unit]._ReallyEnabled == TEXTURE_2D_BIT) {
+         struct gl_texture_object *tObj = ctx->Texture.Unit[unit].Current2D;
+         tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+         if (ti && ti->reloadImages && ti->whichTMU != TDFX_TMU_NONE) {
+            /*
+            printf("download texture image on unit %d\n", unit);
+            */
+            tdfxTMDownloadTexture(fxMesa, tObj);
+            ti->reloadImages = GL_FALSE;
+         }
+      }
+   }
+}
+
+
+
+/*
+ * If scissoring is enabled, compute intersection of scissor region
+ * with all X clip rects, resulting in new cliprect list.
+ * If number of cliprects is zero or one, call grClipWindow to setup
+ * the clip region.  Otherwise we'll call grClipWindow inside the
+ * BEGIN_CLIP_LOOP macro.
+ */
+void tdfxUploadClipping( tdfxContextPtr fxMesa )
+{
+   __DRIdrawablePrivate *dPriv = fxMesa->driDrawable;
+
+   assert(dPriv);
+
+   if (fxMesa->numClipRects == 0) {
+      /* all drawing clipped away */
+      fxMesa->Glide.grClipWindow(0, 0, 0, 0);
+   }
+   else if (fxMesa->numClipRects == 1) {
+      fxMesa->Glide.grClipWindow(fxMesa->pClipRects[0].x1,
+                            fxMesa->screen_height - fxMesa->pClipRects[0].y2,
+                            fxMesa->pClipRects[0].x2,
+                            fxMesa->screen_height - fxMesa->pClipRects[0].y1);
+   }
+   /* else, we'll do a cliprect loop around all drawing */
+
+   fxMesa->Glide.grDRIPosition( dPriv->x, dPriv->y, dPriv->w, dPriv->h,
+                                fxMesa->numClipRects, fxMesa->pClipRects );
+}
+
+
+void tdfxEmitHwStateLocked( tdfxContextPtr fxMesa )
+{
+   if ( !fxMesa->dirty )
+      return;
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_COLOR_COMBINE ) {
+      if (TDFX_IS_NAPALM(fxMesa)) {
+         fxMesa->Glide.grColorCombineExt(fxMesa->ColorCombineExt.SourceA,
+                                         fxMesa->ColorCombineExt.ModeA,
+                                         fxMesa->ColorCombineExt.SourceB,
+                                         fxMesa->ColorCombineExt.ModeB,
+                                         fxMesa->ColorCombineExt.SourceC,
+                                         fxMesa->ColorCombineExt.InvertC,
+                                         fxMesa->ColorCombineExt.SourceD,
+                                         fxMesa->ColorCombineExt.InvertD,
+                                         fxMesa->ColorCombineExt.Shift,
+                                         fxMesa->ColorCombineExt.Invert);
+      }
+      else {
+         /* Voodoo 3 */
+         fxMesa->Glide.grColorCombine( fxMesa->ColorCombine.Function,
+                                       fxMesa->ColorCombine.Factor,
+                                       fxMesa->ColorCombine.Local,
+                                       fxMesa->ColorCombine.Other,
+                                       fxMesa->ColorCombine.Invert );
+      }
+      fxMesa->dirty &= ~TDFX_UPLOAD_COLOR_COMBINE;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_ALPHA_COMBINE ) {
+      if (TDFX_IS_NAPALM(fxMesa)) {
+         fxMesa->Glide.grAlphaCombineExt(fxMesa->AlphaCombineExt.SourceA,
+                                         fxMesa->AlphaCombineExt.ModeA,
+                                         fxMesa->AlphaCombineExt.SourceB,
+                                         fxMesa->AlphaCombineExt.ModeB,
+                                         fxMesa->AlphaCombineExt.SourceC,
+                                         fxMesa->AlphaCombineExt.InvertC,
+                                         fxMesa->AlphaCombineExt.SourceD,
+                                         fxMesa->AlphaCombineExt.InvertD,
+                                         fxMesa->AlphaCombineExt.Shift,
+                                         fxMesa->AlphaCombineExt.Invert);
+      }
+      else {
+         /* Voodoo 3 */
+         fxMesa->Glide.grAlphaCombine( fxMesa->AlphaCombine.Function,
+                                       fxMesa->AlphaCombine.Factor,
+                                       fxMesa->AlphaCombine.Local,
+                                       fxMesa->AlphaCombine.Other,
+                                       fxMesa->AlphaCombine.Invert );
+      }
+      fxMesa->dirty &= ~TDFX_UPLOAD_ALPHA_COMBINE;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_RENDER_BUFFER ) {
+      fxMesa->Glide.grRenderBuffer( fxMesa->DrawBuffer );
+      fxMesa->dirty &= ~TDFX_UPLOAD_RENDER_BUFFER;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_STIPPLE) {
+      fxMesa->Glide.grStipplePattern( fxMesa->Stipple.Pattern );
+      fxMesa->Glide.grStippleMode( fxMesa->Stipple.Mode );
+      fxMesa->dirty &= ~TDFX_UPLOAD_STIPPLE;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_ALPHA_TEST ) {
+      fxMesa->Glide.grAlphaTestFunction( fxMesa->Color.AlphaFunc );
+      fxMesa->dirty &= ~TDFX_UPLOAD_ALPHA_TEST;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_ALPHA_REF ) {
+      fxMesa->Glide.grAlphaTestReferenceValue( fxMesa->Color.AlphaRef );
+      fxMesa->dirty &= ~TDFX_UPLOAD_ALPHA_REF;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_BLEND_FUNC ) {
+      if (fxMesa->Glide.grAlphaBlendFunctionExt) {
+         fxMesa->Glide.grAlphaBlendFunctionExt( fxMesa->Color.BlendSrcRGB,
+                                                fxMesa->Color.BlendDstRGB,
+                                                GR_BLEND_OP_ADD,
+                                                fxMesa->Color.BlendSrcA,
+                                                fxMesa->Color.BlendDstA,
+                                                GR_BLEND_OP_ADD );
+      }
+      else {
+         fxMesa->Glide.grAlphaBlendFunction( fxMesa->Color.BlendSrcRGB,
+                                             fxMesa->Color.BlendDstRGB,
+                                             fxMesa->Color.BlendSrcA,
+                                             fxMesa->Color.BlendDstA );
+      }
+      fxMesa->dirty &= ~TDFX_UPLOAD_BLEND_FUNC;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_DEPTH_MODE ) {
+      fxMesa->Glide.grDepthBufferMode( fxMesa->Depth.Mode );
+      fxMesa->dirty &= ~TDFX_UPLOAD_DEPTH_MODE;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_DEPTH_BIAS ) {
+      fxMesa->Glide.grDepthBiasLevel( fxMesa->Depth.Bias );
+      fxMesa->dirty &= ~TDFX_UPLOAD_DEPTH_BIAS;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_DEPTH_FUNC ) {
+      fxMesa->Glide.grDepthBufferFunction( fxMesa->Depth.Func );
+      fxMesa->dirty &= ~TDFX_UPLOAD_DEPTH_FUNC;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_DEPTH_MASK ) {
+      fxMesa->Glide.grDepthMask( fxMesa->Depth.Mask );
+      fxMesa->dirty &= ~TDFX_UPLOAD_DEPTH_MASK;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_DITHER) {
+      fxMesa->Glide.grDitherMode( fxMesa->Color.Dither );
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_FOG_MODE ) {
+      fxMesa->Glide.grFogMode( fxMesa->Fog.Mode );
+      fxMesa->dirty &= ~TDFX_UPLOAD_FOG_MODE;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_FOG_COLOR ) {
+      fxMesa->Glide.grFogColorValue( fxMesa->Fog.Color );
+      fxMesa->dirty &= ~TDFX_UPLOAD_FOG_COLOR;
+   }
+   if ( fxMesa->dirty & TDFX_UPLOAD_FOG_TABLE ) {
+      fxMesa->Glide.grFogTable( fxMesa->Fog.Table );
+      fxMesa->dirty &= ~TDFX_UPLOAD_FOG_TABLE;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_CULL ) {
+      fxMesa->Glide.grCullMode( fxMesa->CullMode );
+      fxMesa->dirty &= ~TDFX_UPLOAD_CULL;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_CLIP ) {
+      tdfxUploadClipping( fxMesa );
+      fxMesa->dirty &= ~TDFX_UPLOAD_CLIP;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_COLOR_MASK ) {
+      if ( fxMesa->Glide.grColorMaskExt
+           && fxMesa->glCtx->Visual.redBits == 8) {
+        fxMesa->Glide.grColorMaskExt( fxMesa->Color.ColorMask[RCOMP],
+                                       fxMesa->Color.ColorMask[GCOMP],
+                                       fxMesa->Color.ColorMask[BCOMP],
+                                       fxMesa->Color.ColorMask[ACOMP] );
+      } else {
+        fxMesa->Glide.grColorMask( fxMesa->Color.ColorMask[RCOMP] ||
+                                    fxMesa->Color.ColorMask[GCOMP] ||
+                                    fxMesa->Color.ColorMask[BCOMP],
+                                    fxMesa->Color.ColorMask[ACOMP] );
+      }
+      fxMesa->dirty &= ~TDFX_UPLOAD_COLOR_MASK;
+   }
+
+/*     if ( fxMesa->dirty & TDFX_UPLOAD_CONSTANT_COLOR ) { */
+/*        grConstantColorValue( fxMesa->Color.MonoColor ); */
+/*        fxMesa->dirty &= ~TDFX_UPLOAD_CONSTANT_COLOR; */
+/*     } */
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_LINE ) {
+      if (fxMesa->glCtx->Line.SmoothFlag && fxMesa->glCtx->Line.Width == 1.0)
+         fxMesa->Glide.grEnable(GR_AA_ORDERED);
+      else
+         fxMesa->Glide.grDisable(GR_AA_ORDERED);
+      fxMesa->dirty &= ~TDFX_UPLOAD_LINE;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_STENCIL ) {
+      if (fxMesa->glCtx->Stencil.Enabled) {
+         fxMesa->Glide.grEnable(GR_STENCIL_MODE_EXT);
+         fxMesa->Glide.grStencilOp(fxMesa->Stencil.FailFunc,
+                                   fxMesa->Stencil.ZFailFunc,
+                                   fxMesa->Stencil.ZPassFunc);
+         fxMesa->Glide.grStencilFunc(fxMesa->Stencil.Function,
+                                     fxMesa->Stencil.RefValue,
+                                     fxMesa->Stencil.ValueMask);
+         fxMesa->Glide.grStencilMask(fxMesa->Stencil.WriteMask);
+      }
+      else {
+         fxMesa->Glide.grDisable(GR_STENCIL_MODE_EXT);
+      }
+      fxMesa->dirty &= ~TDFX_UPLOAD_STENCIL;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_VERTEX_LAYOUT ) {
+      fxMesa->Glide.grGlideSetVertexLayout( fxMesa->layout[fxMesa->vertexFormat] );
+      fxMesa->dirty &= ~TDFX_UPLOAD_VERTEX_LAYOUT;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_TEXTURE_ENV ) {
+      uploadTextureEnv(fxMesa);
+      fxMesa->dirty &= ~TDFX_UPLOAD_TEXTURE_ENV;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_TEXTURE_PARAMS ) {
+      uploadTextureParams(fxMesa);
+      fxMesa->dirty &= ~TDFX_UPLOAD_TEXTURE_PARAMS;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_TEXTURE_PALETTE ) {
+      if (fxMesa->TexPalette.Data) {
+         fxMesa->Glide.grTexDownloadTable(fxMesa->TexPalette.Type, fxMesa->TexPalette.Data);
+      }
+      fxMesa->dirty &= ~TDFX_UPLOAD_TEXTURE_PALETTE;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_TEXTURE_SOURCE ) {
+      uploadTextureSource(fxMesa);
+      fxMesa->dirty &= ~TDFX_UPLOAD_TEXTURE_SOURCE;
+   }
+
+   if ( fxMesa->dirty & TDFX_UPLOAD_TEXTURE_IMAGES ) {
+      uploadTextureImages(fxMesa);
+      fxMesa->dirty &= ~TDFX_UPLOAD_TEXTURE_IMAGES;
+   }
+
+   fxMesa->dirty = 0;
+}
+
+
+
+void tdfxDDInitRenderFuncs( GLcontext *ctx )
+{
+   ctx->Driver.Clear           = tdfxDDClear;
+   ctx->Driver.Finish          = tdfxDDFinish;
+   ctx->Driver.Flush           = tdfxDDFlush;
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_render.h b/src/mesa/drivers/dri/tdfx/tdfx_render.h
new file mode 100644 (file)
index 0000000..146120b
--- /dev/null
@@ -0,0 +1,54 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_render.h,v 1.1 2001/03/21 16:14:28 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_RENDER_H__
+#define __TDFX_RENDER_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "tdfx_context.h"
+
+extern void tdfxDDInitRenderFuncs( GLcontext *ctx );
+
+extern void tdfxEmitHwStateLocked( tdfxContextPtr fxMesa );
+
+extern void tdfxUploadClipping( tdfxContextPtr fxMesa );
+
+#define FLUSH_BATCH( fxMesa )
+
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_screen.c b/src/mesa/drivers/dri/tdfx/tdfx_screen.c
new file mode 100644 (file)
index 0000000..480dc80
--- /dev/null
@@ -0,0 +1,331 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_screen.c,v 1.3 2002/02/22 21:45:03 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include "tdfx_dri.h"
+#include "tdfx_context.h"
+#include "tdfx_lock.h"
+#include "tdfx_vb.h"
+#include "tdfx_tris.h"
+
+
+#ifdef DEBUG_LOCKING
+char *prevLockFile = 0;
+int prevLockLine = 0;
+#endif
+
+#ifndef TDFX_DEBUG
+int TDFX_DEBUG = (0
+/*               | DEBUG_ALWAYS_SYNC */
+/*               | DEBUG_VERBOSE_API */
+/*               | DEBUG_VERBOSE_MSG */
+/*               | DEBUG_VERBOSE_LRU */
+/*               | DEBUG_VERBOSE_DRI */
+/*               | DEBUG_VERBOSE_IOCTL */
+/*               | DEBUG_VERBOSE_2D */
+   );
+#endif
+
+
+
+static GLboolean
+tdfxCreateScreen( __DRIscreenPrivate *sPriv )
+{
+   tdfxScreenPrivate *fxScreen;
+   TDFXDRIPtr fxDRIPriv = (TDFXDRIPtr) sPriv->pDevPriv;
+
+   /* Allocate the private area */
+   fxScreen = (tdfxScreenPrivate *) Xmalloc( sizeof(tdfxScreenPrivate) );
+   if ( !fxScreen )
+      return GL_FALSE;
+
+   fxScreen->driScrnPriv = sPriv;
+   sPriv->private = (void *) fxScreen;
+
+   fxScreen->regs.handle       = fxDRIPriv->regs;
+   fxScreen->regs.size         = fxDRIPriv->regsSize;
+   fxScreen->deviceID          = fxDRIPriv->deviceID;
+   fxScreen->width             = fxDRIPriv->width;
+   fxScreen->height            = fxDRIPriv->height;
+   fxScreen->mem               = fxDRIPriv->mem;
+   fxScreen->cpp               = fxDRIPriv->cpp;
+   fxScreen->stride            = fxDRIPriv->stride;
+   fxScreen->fifoOffset                = fxDRIPriv->fifoOffset;
+   fxScreen->fifoSize          = fxDRIPriv->fifoSize;
+   fxScreen->fbOffset          = fxDRIPriv->fbOffset;
+   fxScreen->backOffset                = fxDRIPriv->backOffset;
+   fxScreen->depthOffset       = fxDRIPriv->depthOffset;
+   fxScreen->textureOffset     = fxDRIPriv->textureOffset;
+   fxScreen->textureSize       = fxDRIPriv->textureSize;
+   fxScreen->sarea_priv_offset = fxDRIPriv->sarea_priv_offset;
+
+   if ( drmMap( sPriv->fd, fxScreen->regs.handle,
+               fxScreen->regs.size, &fxScreen->regs.map ) ) {
+      return GL_FALSE;
+   }
+
+   return GL_TRUE;
+}
+
+
+static void
+tdfxDestroyScreen( __DRIscreenPrivate *sPriv )
+{
+   tdfxScreenPrivate *fxScreen = (tdfxScreenPrivate *) sPriv->private;
+
+   if ( fxScreen ) {
+      drmUnmap( fxScreen->regs.map, fxScreen->regs.size );
+
+      Xfree( fxScreen );
+      sPriv->private = NULL;
+   }
+}
+
+
+static GLboolean
+tdfxInitDriver( __DRIscreenPrivate *sPriv )
+{
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
+      fprintf( stderr, "%s( %p )\n", __FUNCTION__, sPriv );
+   }
+
+   /* Check the DRI externsion version */
+   if ( sPriv->driMajor != 4 || sPriv->driMinor < 0 ) {
+       __driUtilMessage( "tdfx DRI driver expected DRI version 4.0.x "
+                         "but got version %d.%d.%d",
+                         sPriv->driMajor, sPriv->driMinor, sPriv->driPatch );
+       return GL_FALSE;
+   }
+
+   /* Check that the DDX driver version is compatible */
+   if ( sPriv->ddxMajor != 1 ||
+       sPriv->ddxMinor < 0 ) {
+      __driUtilMessage(
+              "3dfx DRI driver expected DDX driver version 1.0.x "
+              "but got version %d.%d.%d",
+              sPriv->ddxMajor, sPriv->ddxMinor, sPriv->ddxPatch );
+      return GL_FALSE;
+   }
+
+   /* Check that the DRM driver version is compatible */
+   if ( sPriv->drmMajor != 1 ||
+       sPriv->drmMinor < 0 ) {
+      __driUtilMessage(
+              "3dfx DRI driver expected DRM driver version 1.0.x "
+              "but got version %d.%d.%d",
+              sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch );
+      return GL_FALSE;
+   }
+
+   if ( !tdfxCreateScreen( sPriv ) ) {
+      tdfxDestroyScreen( sPriv );
+      return GL_FALSE;
+   }
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+tdfxCreateBuffer( __DRIscreenPrivate *driScrnPriv,
+                  __DRIdrawablePrivate *driDrawPriv,
+                  const __GLcontextModes *mesaVis,
+                  GLboolean isPixmap )
+{
+   if (isPixmap) {
+      return GL_FALSE; /* not implemented */
+   }
+   else {
+      driDrawPriv->driverPrivate = (void *) 
+         _mesa_create_framebuffer( mesaVis,
+                                   GL_FALSE, /* software depth buffer? */
+                                   mesaVis->stencilBits > 0,
+                                   mesaVis->accumRedBits > 0,
+                                   GL_FALSE /* software alpha channel? */ );
+      return (driDrawPriv->driverPrivate != NULL);
+   }
+}
+
+
+static void
+tdfxDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
+{
+   _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
+}
+
+
+static void
+tdfxSwapBuffers( __DRIdrawablePrivate *driDrawPriv )
+
+{
+   GET_CURRENT_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = 0;
+   GLframebuffer *mesaBuffer;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
+      fprintf( stderr, "%s( %p )\n", __FUNCTION__, driDrawPriv );
+   }
+
+   mesaBuffer = (GLframebuffer *) driDrawPriv->driverPrivate;
+   if ( !mesaBuffer->Visual.doubleBufferMode )
+      return; /* can't swap a single-buffered window */
+
+   /* If the current context's drawable matches the given drawable
+    * we have to do a glFinish (per the GLX spec).
+    */
+   if ( ctx ) {
+      __DRIdrawablePrivate *curDrawPriv;
+      fxMesa = TDFX_CONTEXT(ctx);
+      curDrawPriv = fxMesa->driContext->driDrawablePriv;
+
+      if ( curDrawPriv == driDrawPriv ) {
+        /* swapping window bound to current context, flush first */
+        _mesa_notifySwapBuffers( ctx );
+        LOCK_HARDWARE( fxMesa );
+      }
+      else {
+         /* find the fxMesa context previously bound to the window */
+        fxMesa = (tdfxContextPtr) driDrawPriv->driContextPriv->driverPrivate;
+         if (!fxMesa)
+            return;
+        LOCK_HARDWARE( fxMesa );
+        fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
+         printf("SwapBuf SetState 1\n");
+        fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
+      }
+   }
+
+#ifdef STATS
+   {
+      int stalls;
+      static int prevStalls = 0;
+
+      stalls = fxMesa->Glide.grFifoGetStalls();
+
+      fprintf( stderr, "%s:\n", __FUNCTION__ );
+      if ( stalls != prevStalls ) {
+        fprintf( stderr, "    %d stalls occurred\n",
+                 stalls - prevStalls );
+        prevStalls = stalls;
+      }
+      if ( fxMesa && fxMesa->texSwaps ) {
+        fprintf( stderr, "    %d texture swaps occurred\n",
+                 fxMesa->texSwaps );
+        fxMesa->texSwaps = 0;
+      }
+   }
+#endif
+
+   if (fxMesa->scissoredClipRects) {
+      /* restore clip rects without scissor box */
+      fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
+                                   driDrawPriv->w, driDrawPriv->h,
+                                   driDrawPriv->numClipRects,
+                                   driDrawPriv->pClipRects );
+   }
+
+   fxMesa->Glide.grDRIBufferSwap( fxMesa->Glide.SwapInterval );
+
+   if (fxMesa->scissoredClipRects) {
+      /* restore clip rects WITH scissor box */
+      fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
+                                   driDrawPriv->w, driDrawPriv->h,
+                                   fxMesa->numClipRects, fxMesa->pClipRects );
+   }
+
+
+#if 0
+   {
+      FxI32 result;
+      do {
+         FxI32 result;
+         fxMesa->Glide.grGet(GR_PENDING_BUFFERSWAPS, 4, &result);
+      } while ( result > fxMesa->maxPendingSwapBuffers );
+   }
+#endif
+
+   fxMesa->stats.swapBuffer++;
+
+   if (ctx) {
+      if (ctx->DriverCtx != fxMesa) {
+         fxMesa = TDFX_CONTEXT(ctx);
+        fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
+         printf("SwapBuf SetState 2\n");
+        fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
+      }
+      UNLOCK_HARDWARE( fxMesa );
+   }
+}
+
+
+static GLboolean
+tdfxOpenCloseFullScreen(__DRIcontextPrivate *driContextPriv)
+{
+    return GL_TRUE;
+}
+
+
+static const struct __DriverAPIRec tdfxAPI = {
+   .InitDriver      = tdfxInitDriver,
+   .DestroyScreen   = tdfxDestroyScreen,
+   .CreateContext   = tdfxCreateContext,
+   .DestroyContext  = tdfxDestroyContext,
+   .CreateBuffer    = tdfxCreateBuffer,
+   .DestroyBuffer   = tdfxDestroyBuffer,
+   .SwapBuffers     = tdfxSwapBuffers,
+   .MakeCurrent     = tdfxMakeCurrent,
+   .UnbindContext   = tdfxUnbindContext,
+   .OpenFullScreen  = tdfxOpenCloseFullScreen,
+   .CloseFullScreen = tdfxOpenCloseFullScreen,
+   .GetSwapInfo     = NULL,
+   .GetMSC          = NULL,
+   .WaitForMSC      = NULL,
+   .WaitForSBC      = NULL,
+   .SwapBuffersMSC  = NULL
+};
+
+
+/*
+ * This is the bootstrap function for the driver.
+ * The __driCreateScreen name is the symbol that libGL.so fetches.
+ * Return:  pointer to a __DRIscreenPrivate.
+ */
+void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
+                        int numConfigs, __GLXvisualConfig *config)
+{
+   __DRIscreenPrivate *psp;
+   psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &tdfxAPI);
+   return (void *) psp;
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_screen.h b/src/mesa/drivers/dri/tdfx/tdfx_screen.h
new file mode 100644 (file)
index 0000000..2a79c88
--- /dev/null
@@ -0,0 +1,73 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_screen.h,v 1.2 2002/02/22 21:45:03 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_SCREEN_H__
+#define __TDFX_SCREEN_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+typedef struct {
+   drmHandle handle;
+   drmSize size;
+   drmAddress map;
+} tdfxRegion, *tdfxRegionPtr;
+
+typedef struct {
+   tdfxRegion regs;
+
+   int deviceID;
+   int width;
+   int height;
+   int mem;
+   int cpp;
+   int stride;
+
+   int fifoOffset;
+   int fifoSize;
+
+   int fbOffset;
+   int backOffset;
+   int depthOffset;
+   int textureOffset;
+   int textureSize;
+
+   __DRIscreenPrivate *driScrnPriv;
+   unsigned int sarea_priv_offset;
+} tdfxScreenPrivate;
+
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_span.c b/src/mesa/drivers/dri/tdfx/tdfx_span.c
new file mode 100644 (file)
index 0000000..d94ef69
--- /dev/null
@@ -0,0 +1,1399 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_span.c,v 1.7 2002/10/30 12:52:00 alanh Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *     Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#include "tdfx_context.h"
+#include "tdfx_lock.h"
+#include "tdfx_span.h"
+#include "tdfx_render.h"
+#include "swrast/swrast.h"
+
+
+#define DBG 0
+
+
+#define LOCAL_VARS                                                     \
+   __DRIdrawablePrivate *dPriv = fxMesa->driDrawable;                  \
+   tdfxScreenPrivate *fxPriv = fxMesa->fxScreen;                       \
+   GLuint pitch = (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT)         \
+               ? (fxMesa->screen_width * BYTESPERPIXEL) :               \
+               (info.strideInBytes);                                    \
+   GLuint height = fxMesa->height;                                     \
+   char *buf = (char *)((char *)info.lfbPtr +                          \
+                        dPriv->x * fxPriv->cpp +                       \
+                        dPriv->y * pitch);                             \
+   GLuint p;                                                           \
+   (void) buf; (void) p;
+
+
+#define CLIPPIXEL( _x, _y )    ( _x >= minx && _x < maxx &&            \
+                                 _y >= miny && _y < maxy )
+
+#define CLIPSPAN( _x, _y, _n, _x1, _n1, _i )                           \
+   if ( _y < miny || _y >= maxy ) {                                    \
+      _n1 = 0, _x1 = x;                                                        \
+   } else {                                                            \
+      _n1 = _n;                                                                \
+      _x1 = _x;                                                                \
+      if ( _x1 < minx ) _i += (minx-_x1), n1 -= (minx-_x1), _x1 = minx; \
+      if ( _x1 + _n1 >= maxx ) n1 -= (_x1 + n1 - maxx);                        \
+   }
+
+#define Y_FLIP(_y)             (height - _y - 1)
+
+
+#define HW_WRITE_LOCK()                                                        \
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);                          \
+   GrLfbInfo_t info;                                                   \
+   FLUSH_BATCH( fxMesa );                                              \
+   UNLOCK_HARDWARE( fxMesa );                                          \
+   LOCK_HARDWARE( fxMesa );                                            \
+   info.size = sizeof(GrLfbInfo_t);                                    \
+   if ( fxMesa->Glide.grLfbLock( GR_LFB_WRITE_ONLY,                    \
+                   fxMesa->DrawBuffer, LFB_MODE,                       \
+                  GR_ORIGIN_UPPER_LEFT, FXFALSE, &info ) )             \
+   {
+
+#define HW_WRITE_UNLOCK()                                              \
+      fxMesa->Glide.grLfbUnlock( GR_LFB_WRITE_ONLY, fxMesa->DrawBuffer );\
+   }
+
+
+#define HW_READ_LOCK()                                                 \
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);                          \
+   GrLfbInfo_t info;                                                   \
+   FLUSH_BATCH( fxMesa );                                              \
+   UNLOCK_HARDWARE( fxMesa );                                          \
+   LOCK_HARDWARE( fxMesa );                                            \
+   info.size = sizeof(GrLfbInfo_t);                                    \
+   if ( fxMesa->Glide.grLfbLock( GR_LFB_READ_ONLY, fxMesa->ReadBuffer, \
+                   LFB_MODE, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info ) )  \
+   {
+
+#define HW_READ_UNLOCK()                                               \
+      fxMesa->Glide.grLfbUnlock( GR_LFB_READ_ONLY, fxMesa->ReadBuffer );\
+   }
+
+
+#define HW_WRITE_CLIPLOOP()                                            \
+      do {                                                             \
+         int _nc = fxMesa->numClipRects;                               \
+         while (_nc--) {                                               \
+            int minx = fxMesa->pClipRects[_nc].x1 - fxMesa->x_offset;  \
+           int miny = fxMesa->pClipRects[_nc].y1 - fxMesa->y_offset;   \
+           int maxx = fxMesa->pClipRects[_nc].x2 - fxMesa->x_offset;   \
+           int maxy = fxMesa->pClipRects[_nc].y2 - fxMesa->y_offset;
+
+#define HW_READ_CLIPLOOP()                                             \
+      do {                                                             \
+         const __DRIdrawablePrivate *dPriv = fxMesa->driDrawable;      \
+         XF86DRIClipRectPtr rect = dPriv->pClipRects;                  \
+         int _nc = dPriv->numClipRects;                                        \
+         while (_nc--) {                                               \
+            const int minx = rect->x1 - fxMesa->x_offset;              \
+            const int miny = rect->y1 - fxMesa->y_offset;              \
+            const int maxx = rect->x2 - fxMesa->x_offset;              \
+            const int maxy = rect->y2 - fxMesa->y_offset;              \
+            rect++;
+
+#define HW_ENDCLIPLOOP()                                               \
+        }                                                              \
+      } while (0)
+
+
+
+#define LFB_MODE       GR_LFBWRITEMODE_565
+
+
+/* 16 bit, RGB565 color spanline and pixel functions */                        \
+
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+  p = TDFXPACKCOLOR565( color[0], color[1], color[2] )
+
+
+#define WRITE_RGBA( _x, _y, r, g, b, a )                               \
+   *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)r & 0xf8) << 8) |    \
+                                          (((int)g & 0xfc) << 3) |     \
+                                          (((int)b & 0xf8) >> 3))
+
+#define WRITE_PIXEL( _x, _y, p )                                       \
+    *(GLushort *)(buf + _x*2 + _y*pitch) = p
+
+#define READ_RGBA( rgba, _x, _y )                                      \
+    do {                                                               \
+       GLushort p = *(GLushort *)(buf + _x*2 + _y*pitch);              \
+       rgba[0] = (((p >> 11) & 0x1f) * 255) / 31;                      \
+       rgba[1] = (((p >>  5) & 0x3f) * 255) / 63;                      \
+       rgba[2] = (((p >>  0) & 0x1f) * 255) / 31;                      \
+       rgba[3] = 0xff;                                                 \
+    } while (0)
+
+#define TAG(x) tdfx##x##_RGB565
+#define BYTESPERPIXEL 2
+#include "spantmp.h"
+#undef BYTESPERPIXEL
+
+
+/* 16 bit, BGR565 color spanline and pixel functions */                        \
+#if 0
+
+#define WRITE_RGBA( _x, _y, r, g, b, a )                               \
+   *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)b & 0xf8) << 8) |    \
+                                          (((int)g & 0xfc) << 3) |     \
+                                          (((int)r & 0xf8) >> 3))
+
+#define WRITE_PIXEL( _x, _y, p )                                       \
+    *(GLushort *)(buf + _x*2 + _y*pitch) = p
+
+#define READ_RGBA( rgba, _x, _y )                                      \
+    do {                                                               \
+       GLushort p = *(GLushort *)(buf + _x*2 + _y*pitch);              \
+       rgba[0] = (p << 3) & 0xf8;                                      \
+       rgba[1] = (p >> 3) & 0xfc;                                      \
+       rgba[2] = (p >> 8) & 0xf8;                                      \
+       rgba[3] = 0xff;                                                 \
+    } while (0)
+
+#define TAG(x) tdfx##x##_BGR565
+#define BYTESPERPIXEL 2
+#include "spantmp.h"
+#undef BYTESPERPIXEL
+#endif
+
+
+#undef LFB_MODE
+#define LFB_MODE       GR_LFBWRITEMODE_888
+
+
+/* 24 bit, RGB888 color spanline and pixel functions */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+  p = TDFXPACKCOLOR888( color[0], color[1], color[2] )
+
+#define WRITE_RGBA( _x, _y, r, g, b, a )                               \
+   *(GLuint *)(buf + _x*3 + _y*pitch) = ((b << 0) |                    \
+                                        (g << 8) |                     \
+                                        (r << 16))
+
+#define WRITE_PIXEL( _x, _y, p )                                       \
+   *(GLuint *)(buf + _x*3 + _y*pitch) = p
+
+#define READ_RGBA( rgba, _x, _y )                                      \
+do {                                                                   \
+   GLuint p = *(GLuint *)(buf + _x*3 + _y*pitch);                      \
+   rgba[0] = (p >> 16) & 0xff;                                         \
+   rgba[1] = (p >> 8)  & 0xff;                                         \
+   rgba[2] = (p >> 0)  & 0xff;                                         \
+   rgba[3] = 0xff;                                                     \
+} while (0)
+
+#define TAG(x) tdfx##x##_RGB888
+#define BYTESPERPIXEL 4
+#include "spantmp.h"
+#undef BYTESPERPIXEL
+
+
+#undef LFB_MODE
+#define LFB_MODE       GR_LFBWRITEMODE_8888
+
+
+/* 32 bit, ARGB8888 color spanline and pixel functions */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+  p = TDFXPACKCOLOR8888( color[0], color[1], color[2], color[3] )
+
+#define WRITE_RGBA( _x, _y, r, g, b, a )                               \
+   *(GLuint *)(buf + _x*4 + _y*pitch) = ((b <<  0) |                   \
+                                        (g <<  8) |                    \
+                                        (r << 16) |                    \
+                                        (a << 24) )
+
+#define WRITE_PIXEL( _x, _y, p )                                       \
+   *(GLuint *)(buf + _x*4 + _y*pitch) = p
+
+#define READ_RGBA( rgba, _x, _y )                                      \
+do {                                                                   \
+   GLuint p = *(GLuint *)(buf + _x*4 + _y*pitch);                      \
+   rgba[0] = (p >> 16) & 0xff;                                         \
+   rgba[1] = (p >>  8) & 0xff;                                         \
+   rgba[2] = (p >>  0) & 0xff;                                         \
+   rgba[3] = (p >> 24) & 0xff;                                         \
+} while (0)
+
+#define TAG(x) tdfx##x##_ARGB8888
+#define BYTESPERPIXEL 4
+#include "spantmp.h"
+#undef BYTESPERPIXEL
+
+
+
+/* ================================================================
+ * Old span functions below...
+ */
+
+
+/*
+ * Examine the cliprects to generate an array of flags to indicate
+ * which pixels in a span are visible.  Note: (x,y) is a screen
+ * coordinate.
+ */
+static void
+generate_vismask(const tdfxContextPtr fxMesa, GLint x, GLint y, GLint n,
+                 GLubyte vismask[])
+{
+   GLboolean initialized = GL_FALSE;
+   GLint i, j;
+
+   /* Ensure we clear the visual mask */
+   MEMSET(vismask, 0, n);
+
+   /* turn on flags for all visible pixels */
+   for (i = 0; i < fxMesa->numClipRects; i++) {
+      const XF86DRIClipRectPtr rect = &fxMesa->pClipRects[i];
+
+      if (y >= rect->y1 && y < rect->y2) {
+        if (x >= rect->x1 && x + n <= rect->x2) {
+           /* common case, whole span inside cliprect */
+           MEMSET(vismask, 1, n);
+           return;
+        }
+        if (x < rect->x2 && x + n >= rect->x1) {
+           /* some of the span is inside the rect */
+           GLint start, end;
+           if (!initialized) {
+              MEMSET(vismask, 0, n);
+              initialized = GL_TRUE;
+           }
+           if (x < rect->x1)
+              start = rect->x1 - x;
+           else
+              start = 0;
+           if (x + n > rect->x2)
+              end = rect->x2 - x;
+           else
+              end = n;
+           assert(start >= 0);
+           assert(end <= n);
+           for (j = start; j < end; j++)
+              vismask[j] = 1;
+        }
+      }
+   }
+}
+
+/*
+ * Examine cliprects and determine if the given screen pixel is visible.
+ */
+static GLboolean
+visible_pixel(const tdfxContextPtr fxMesa, int scrX, int scrY)
+{
+   int i;
+   for (i = 0; i < fxMesa->numClipRects; i++) {
+      const XF86DRIClipRectPtr rect = &fxMesa->pClipRects[i];
+      if (scrX >= rect->x1 &&
+         scrX < rect->x2 &&
+         scrY >= rect->y1 && scrY < rect->y2) return GL_TRUE;
+   }
+   return GL_FALSE;
+}
+
+
+
+/*
+ * Depth buffer read/write functions.
+ */
+/*
+ * To read the frame buffer, we need to lock and unlock it.  The
+ * four macros {READ,WRITE}_FB_SPAN_{LOCK,UNLOCK}
+ * do this for us.
+ *
+ * Note that the lock must be matched with an unlock.  These
+ * macros include a spare curly brace, so they must
+ * be syntactically matched.
+ *
+ * Note, also, that you can't lock a buffer twice with different
+ * modes.  That is to say, you can't lock a buffer in both read
+ * and write modes.  The strideInBytes and LFB pointer will be
+ * the same with read and write locks, so you can use either.
+ * o The HW has different state for reads and writes, so
+ *   locking it twice may give screwy results.
+ * o The DRM won't let you lock twice.  It hangs.  This is probably
+ *   because of the LOCK_HARDWARE IN THE *_FB_SPAN_LOCK macros,
+ *   and could be eliminated with nonlocking lock routines.  But
+ *   what's the point after all.
+ */
+#define READ_FB_SPAN_LOCK(fxMesa, info, target_buffer)              \
+  UNLOCK_HARDWARE(fxMesa);                                          \
+  LOCK_HARDWARE(fxMesa);                                            \
+  (info).size=sizeof(info);                                         \
+  if (fxMesa->Glide.grLfbLock(GR_LFB_READ_ONLY,                     \
+                target_buffer,                                      \
+                GR_LFBWRITEMODE_ANY,                                \
+                GR_ORIGIN_UPPER_LEFT,                               \
+                FXFALSE,                                            \
+                &(info))) {
+
+#define READ_FB_SPAN_UNLOCK(fxMesa, target_buffer)                  \
+    fxMesa->Glide.grLfbUnlock(GR_LFB_READ_ONLY, target_buffer);     \
+  } else {                                                          \
+    fprintf(stderr, "tdfxDriver: Can't get %s (%d) read lock\n",    \
+            (target_buffer == GR_BUFFER_BACKBUFFER)                 \
+                ? "back buffer"                                     \
+            : ((target_buffer == GR_BUFFER_AUXBUFFER)               \
+                ? "depth buffer"                                    \
+               : "unknown buffer"),                                 \
+            target_buffer);                                         \
+  }
+
+#define WRITE_FB_SPAN_LOCK(fxMesa, info, target_buffer, write_mode) \
+  UNLOCK_HARDWARE(fxMesa);                                          \
+  LOCK_HARDWARE(fxMesa);                                            \
+  info.size=sizeof(info);                                           \
+  if (fxMesa->Glide.grLfbLock(GR_LFB_WRITE_ONLY,                    \
+                target_buffer,                                      \
+                write_mode,                                         \
+                GR_ORIGIN_UPPER_LEFT,                               \
+                FXFALSE,                                            \
+                &info)) {
+
+#define WRITE_FB_SPAN_UNLOCK(fxMesa, target_buffer)                 \
+    fxMesa->Glide.grLfbUnlock(GR_LFB_WRITE_ONLY, target_buffer);    \
+  } else {                                                          \
+    fprintf(stderr, "tdfxDriver: Can't get %s (%d) write lock\n",   \
+            (target_buffer == GR_BUFFER_BACKBUFFER)                 \
+                ? "back buffer"                                     \
+            : ((target_buffer == GR_BUFFER_AUXBUFFER)               \
+                ? "depth buffer"                                    \
+               : "unknown buffer"),                                 \
+            target_buffer);                                         \
+  }
+
+/*
+ * Because the Linear Frame Buffer is not necessarily aligned
+ * with the depth buffer, we have to do some fiddling
+ * around to get the right addresses.
+ *
+ * Perhaps a picture is in order.  The Linear Frame Buffer
+ * looks like this:
+ *
+ *   |<----------------------info.strideInBytes------------->|
+ *   |<-----physicalStrideInBytes------->|
+ *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
+ *   |                                   |                   |
+ *   |          Legal Memory             |  Forbidden Zone   |
+ *   |                                   |                   |
+ *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
+ *
+ * You can only reliably read and write legal locations.  Reads
+ * and writes from the Forbidden Zone will return undefined values,
+ * and may cause segmentation faults.
+ *
+ * Now, the depth buffer may not end up in a location such each
+ * scan line is an LFB line.  For example, the depth buffer may
+ * look like this:
+ *
+ *    wrapped               ordinary.
+ *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
+ *   |0000000000000000000000             |                   | back
+ *   |1111111111111111111111             |                   | buffer
+ *   |2222222222222222222222             |                   |
+ *   |4096b align. padxx00000000000000000|  Forbidden Zone   | depth
+ *   |0000              11111111111111111|                   | buffer
+ *   |1111              22222222222222222|                   |
+ *   |2222                               |                   |
+ *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
+ * where each number is the scan line number.  We know it will
+ * be aligned on 128 byte boundaries, at least.  Aligning this
+ * on a scanline boundary causes the back and depth buffers to
+ * thrash in the SST1 cache.  (Note that the back buffer is always
+ * allocated at the beginning of LFB memory, and so it is always
+ * properly aligned with the LFB stride.)
+ *
+ * We call the beginning of the line (which is the rightmost
+ * part of the depth line in the picture above) the *ordinary* part
+ * of the scanline, and the end of the line (which is the
+ * leftmost part, one line below) the *wrapped* part of the scanline.
+ * a.) We need to know what x value to subtract from the screen
+ *     x coordinate to index into the wrapped part.
+ * b.) We also need to figure out if we need to read from the ordinary
+ *     part scan line, or from the wrapped part of the scan line.
+ *
+ * [ad a]
+ * The first wrapped x coordinate is that coordinate such that
+ *           depthBufferOffset&(info.strideInBytes) + x*elmentSize  {*}
+ *                            > physicalStrideInBytes
+ *     where depthBufferOffset is the LFB distance in bytes
+ *     from the back buffer to the depth buffer.  The expression
+ *           depthBufferOffset&(info.strideInBytes)
+ *     is then the offset (in bytes) from the beginining of (any)
+ *     depth buffer line to first element in the line.
+ * Simplifying inequation {*} above we see that x is the smallest
+ * value such that
+ *         x*elementSize > physicalStrideInBytes                      {**}
+ *                            - depthBufferOffset&(info.strideInBytes)
+ * Now, we know that both the summands on the right are multiples of
+ * 128, and elementSize <= 4, so if equality holds in {**}, x would
+ * be a multiple of 32.  Thus we can set x to
+ *         xwrapped = (physicalStrideInBytes
+ *                      - depthBufferOffset&(info.strideInBytes))/elementSize
+ *                      + 1
+ *
+ * [ad b]
+ * Question b is now simple.  We read from the wrapped scan line if
+ * x is greater than xwrapped.
+ */
+#define TILE_WIDTH_IN_BYTES            128
+#define TILE_WIDTH_IN_ZOXELS(bpz)      (TILE_WIDTH_IN_BYTES/(bpz))
+#define TILE_HEIGHT_IN_LINES           32
+typedef struct
+{
+   void *lfbPtr;
+   void *lfbWrapPtr;
+   FxU32 LFBStrideInElts;
+   GLint firstWrappedX;
+}
+LFBParameters;
+
+/*
+ * We need information about the back buffer.  Note that
+ * this function *cannot be called* while the aux buffer
+ * is locked, or the caller will hang.
+ *
+ * Only Glide knows the LFB address of the back and depth
+ * offsets.  The upper levels of Mesa know the depth offset,
+ * but that is not in LFB space, it is tiled memory space,
+ * and is not useable for us.
+ */
+static void
+GetBackBufferInfo(tdfxContextPtr fxMesa, GrLfbInfo_t * backBufferInfo)
+{
+   READ_FB_SPAN_LOCK(fxMesa, *backBufferInfo, GR_BUFFER_BACKBUFFER);
+   READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_BACKBUFFER);
+}
+
+static void
+GetFbParams(tdfxContextPtr fxMesa,
+            GrLfbInfo_t * info,
+            GrLfbInfo_t * backBufferInfo,
+            LFBParameters * ReadParamsp, FxU32 elementSize)
+{
+   FxU32 physicalStrideInBytes, bufferOffset;
+   FxU32 strideInBytes = info->strideInBytes;
+   char *lfbPtr = (char *) (info->lfbPtr); /* For arithmetic, use char * */
+
+   /*
+    * These two come directly from the info structure.
+    */
+   ReadParamsp->lfbPtr = (void *) lfbPtr;
+   ReadParamsp->LFBStrideInElts = strideInBytes / elementSize;
+   /*
+    * Now, calculate the value of firstWrappedX.
+    *
+    * The physical stride is the screen width in bytes rounded up to
+    * the next highest multiple of 128 bytes.  Note that this fails
+    * when TILE_WIDTH_IN_BYTES is not a power of two.
+    *
+    * The buffer Offset is the distance between the beginning of
+    * the LFB space, which is the beginning of the back buffer,
+    * and the buffer we are gathering information about.
+    * We want to make this routine usable for operations on the
+    * back buffer, though we don't actually use it on the back
+    * buffer.  Note, then, that if bufferOffset == 0, the firstWrappedX
+    * is in the forbidden zone, and is therefore never reached.
+    *
+    * Note that if
+    *     physicalStrideInBytes
+    *             < bufferOffset&(info->strideInBytes-1)
+    * the buffer begins in the forbidden zone.  We assert for this.
+    */
+   bufferOffset = (FxU32)(lfbPtr - (char *) backBufferInfo->lfbPtr);
+   physicalStrideInBytes
+      = (fxMesa->screen_width * elementSize + TILE_WIDTH_IN_BYTES - 1)
+      & ~(TILE_WIDTH_IN_BYTES - 1);
+   assert(physicalStrideInBytes > (bufferOffset & (strideInBytes - 1)));
+   ReadParamsp->firstWrappedX
+      = (physicalStrideInBytes
+        - (bufferOffset & (strideInBytes - 1))) / elementSize;
+   /*
+    * This is the address of the next physical line.
+    */
+   ReadParamsp->lfbWrapPtr
+      = (void *) ((char *) backBufferInfo->lfbPtr
+                 + (bufferOffset & ~(strideInBytes - 1))
+                 + (TILE_HEIGHT_IN_LINES) * strideInBytes);
+}
+
+/*
+ * These macros fetch data from the frame buffer.  The type is
+ * the type of data we want to fetch.  It should match the type
+ * whose size was used with GetFbParams to fill in the structure
+ * in *ReadParamsp.  We have a macro to read the ordinary
+ * part, a second macro to read the wrapped part, and one which
+ * will do either.  When we are reading a span, we will know
+ * when the ordinary part ends, so there's no need to test for
+ * it.  However, when reading and writing pixels, we don't
+ * necessarily know.  I suppose it's a matter of taste whether
+ * it's better in the macro or in the call.
+ *
+ * Recall that x and y are screen coordinates.
+ */
+#define GET_FB_DATA(ReadParamsp, type, x, y)                        \
+   (((x) < (ReadParamsp)->firstWrappedX)                            \
+        ? (((type *)((ReadParamsp)->lfbPtr))                        \
+                 [(y) * ((ReadParamsp)->LFBStrideInElts)            \
+                   + (x)])                                          \
+        : (((type *)((ReadParamsp)->lfbWrapPtr))                    \
+                 [((y)) * ((ReadParamsp)->LFBStrideInElts)          \
+                   + ((x) - (ReadParamsp)->firstWrappedX)]))
+#define GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y)               \
+    (((type *)((ReadParamsp)->lfbPtr))                              \
+                 [(y) * ((ReadParamsp)->LFBStrideInElts)            \
+                   + (x)])
+#define GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y)                \
+    (((type *)((ReadParamsp)->lfbWrapPtr))                          \
+                 [((y)) * ((ReadParamsp)->LFBStrideInElts)          \
+                   + ((x) - (ReadParamsp)->firstWrappedX)])
+#define PUT_FB_DATA(ReadParamsp, type, x, y, value)                        \
+    (GET_FB_DATA(ReadParamsp, type, x, y) = (type)(value))
+#define PUT_ORDINARY_FB_DATA(ReadParamsp, type, x, y, value)              \
+    (GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y) = (type)(value))
+#define PUT_WRAPPED_FB_DATA(ReadParamsp, type, x, y, value)                \
+    (GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y) = (type)(value))
+
+static void
+tdfxDDWriteDepthSpan(GLcontext * ctx,
+                    GLuint n, GLint x, GLint y, const GLdepth depth[],
+                    const GLubyte mask[])
+{
+   tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
+   GLint bottom = fxMesa->y_offset + fxMesa->height - 1;
+   GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
+   GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits;
+   GrLfbInfo_t info;
+   GLubyte visMask[MAX_WIDTH];
+
+   if (MESA_VERBOSE & VERBOSE_DRIVER) {
+      fprintf(stderr, "tdfxmesa: tdfxDDWriteDepthSpan(...)\n");
+   }
+
+   assert((depth_size == 16) || (depth_size == 24) || (depth_size == 32));
+   /*
+    * Convert x and y to screen coordinates.
+    */
+   x += fxMesa->x_offset;
+   y = bottom - y;
+   if (mask) {
+      GLint i;
+      GLushort d16;
+      GrLfbInfo_t backBufferInfo;
+
+      switch (depth_size) {
+      case 16:
+        GetBackBufferInfo(fxMesa, &backBufferInfo);
+        /*
+         * Note that the _LOCK macro adds a curly brace,
+         * and the UNLOCK macro removes it.
+         */
+        WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER,
+                           GR_LFBWRITEMODE_ANY);
+        generate_vismask(fxMesa, x, y, n, visMask);
+        {
+           LFBParameters ReadParams;
+           int wrappedPartStart;
+           GetFbParams(fxMesa, &info, &backBufferInfo,
+                       &ReadParams, sizeof(GLushort));
+           if (ReadParams.firstWrappedX <= x) {
+              wrappedPartStart = 0;
+           }
+           else if (n <= (ReadParams.firstWrappedX - x)) {
+              wrappedPartStart = n;
+           }
+           else {
+              wrappedPartStart = (ReadParams.firstWrappedX - x);
+           }
+           for (i = 0; i < wrappedPartStart; i++) {
+              if (mask[i] && visMask[i]) {
+                 d16 = depth[i];
+                 PUT_ORDINARY_FB_DATA(&ReadParams, GLushort, x + i, y, d16);
+              }
+           }
+           for (; i < n; i++) {
+              if (mask[i] && visMask[i]) {
+                 d16 = depth[i];
+                 PUT_WRAPPED_FB_DATA(&ReadParams, GLushort, x + i, y, d16);
+              }
+           }
+        }
+        WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+        break;
+      case 24:
+      case 32:
+        GetBackBufferInfo(fxMesa, &backBufferInfo);
+        /*
+         * Note that the _LOCK macro adds a curly brace,
+         * and the UNLOCK macro removes it.
+         */
+        WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER,
+                           GR_LFBWRITEMODE_ANY);
+        generate_vismask(fxMesa, x, y, n, visMask);
+        {
+           LFBParameters ReadParams;
+           int wrappedPartStart;
+           GetFbParams(fxMesa, &info, &backBufferInfo,
+                       &ReadParams, sizeof(GLuint));
+           if (ReadParams.firstWrappedX <= x) {
+              wrappedPartStart = 0;
+           }
+           else if (n <= (ReadParams.firstWrappedX - x)) {
+              wrappedPartStart = n;
+           }
+           else {
+              wrappedPartStart = (ReadParams.firstWrappedX - x);
+           }
+           for (i = 0; i < wrappedPartStart; i++) {
+              GLuint d32;
+              if (mask[i] && visMask[i]) {
+                 if (stencil_size > 0) {
+                    d32 =
+                       GET_ORDINARY_FB_DATA(&ReadParams, GLuint,
+                                            x + i, y);
+                    d32 =
+                       (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
+                 }
+                 else {
+                    d32 = depth[i];
+                 }
+                 PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
+              }
+           }
+           for (; i < n; i++) {
+              GLuint d32;
+              if (mask[i] && visMask[i]) {
+                 if (stencil_size > 0) {
+                    d32 =
+                       GET_WRAPPED_FB_DATA(&ReadParams, GLuint,
+                                           x + i, y);
+                    d32 =
+                       (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
+                 }
+                 else {
+                    d32 = depth[i];
+                 }
+                 PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
+              }
+           }
+        }
+        WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+        break;
+      }
+   }
+   else {
+      GLint i;
+      GLuint d32;
+      GLushort d16;
+      GrLfbInfo_t backBufferInfo;
+
+      switch (depth_size) {
+      case 16:
+        GetBackBufferInfo(fxMesa, &backBufferInfo);
+        /*
+         * Note that the _LOCK macro adds a curly brace,
+         * and the UNLOCK macro removes it.
+         */
+        WRITE_FB_SPAN_LOCK(fxMesa, info,
+                           GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
+        generate_vismask(fxMesa, x, y, n, visMask);
+        {
+           LFBParameters ReadParams;
+           GLuint wrappedPartStart;
+           GetFbParams(fxMesa, &info, &backBufferInfo,
+                       &ReadParams, sizeof(GLushort));
+           if (ReadParams.firstWrappedX <= x) {
+              wrappedPartStart = 0;
+           }
+           else if (n <= (ReadParams.firstWrappedX - x)) {
+              wrappedPartStart = n;
+           }
+           else {
+              wrappedPartStart = (ReadParams.firstWrappedX - x);
+           }
+           for (i = 0; i < wrappedPartStart; i++) {
+              if (visMask[i]) {
+                 d16 = depth[i];
+                 PUT_ORDINARY_FB_DATA(&ReadParams,
+                                      GLushort,
+                                      x + i, y,
+                                      d16);
+              }
+           }
+           for (; i < n; i++) {
+              if (visMask[i]) {
+                 d16 = depth[i];
+                 PUT_WRAPPED_FB_DATA(&ReadParams,
+                                     GLushort,
+                                     x + i, y,
+                                     d16);
+              }
+           }
+        }
+        WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+        break;
+      case 24:
+      case 32:
+        GetBackBufferInfo(fxMesa, &backBufferInfo);
+        /*
+         * Note that the _LOCK macro adds a curly brace,
+         * and the UNLOCK macro removes it.
+         */
+        WRITE_FB_SPAN_LOCK(fxMesa, info,
+                           GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
+        generate_vismask(fxMesa, x, y, n, visMask);
+        {
+           LFBParameters ReadParams;
+           GLuint wrappedPartStart;
+
+           GetFbParams(fxMesa, &info, &backBufferInfo,
+                       &ReadParams, sizeof(GLuint));
+           if (ReadParams.firstWrappedX <= x) {
+              wrappedPartStart = 0;
+           }
+           else if (n <= (ReadParams.firstWrappedX - x)) {
+              wrappedPartStart = n;
+           }
+           else {
+              wrappedPartStart = (ReadParams.firstWrappedX - x);
+           }
+           for (i = 0; i < wrappedPartStart; i++) {
+              if (visMask[i]) {
+                 if (stencil_size > 0) {
+                    d32 = GET_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y);
+                    d32 =
+                       (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
+                 }
+                 else {
+                    d32 = depth[i];
+                 }
+                 PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
+              }
+           }
+           for (; i < n; i++) {
+              if (visMask[i]) {
+                 if (stencil_size > 0) {
+                    d32 = GET_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y);
+                    d32 =
+                       (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
+                 }
+                 else {
+                    d32 = depth[i];
+                 }
+                 PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
+              }
+           }
+        }
+        WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+        break;
+      }
+   }
+}
+
+static void
+tdfxDDReadDepthSpan(GLcontext * ctx,
+                   GLuint n, GLint x, GLint y, GLdepth depth[])
+{
+   tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
+   GLint bottom = fxMesa->height + fxMesa->y_offset - 1;
+   GLuint i;
+   GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
+   GrLfbInfo_t info;
+
+   if (MESA_VERBOSE & VERBOSE_DRIVER) {
+      fprintf(stderr, "tdfxmesa: tdfxDDReadDepthSpan(...)\n");
+   }
+
+   /*
+    * Convert to screen coordinates.
+    */
+   x += fxMesa->x_offset;
+   y = bottom - y;
+   switch (depth_size) {
+   case 16:
+   {
+      LFBParameters ReadParams;
+      GrLfbInfo_t backBufferInfo;
+      int wrappedPartStart;
+      GetBackBufferInfo(fxMesa, &backBufferInfo);
+      /*
+       * Note that the _LOCK macro adds a curly brace,
+       * and the UNLOCK macro removes it.
+       */
+      READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
+      GetFbParams(fxMesa, &info, &backBufferInfo,
+                 &ReadParams, sizeof(GLushort));
+      if (ReadParams.firstWrappedX <= x) {
+        wrappedPartStart = 0;
+      }
+      else if (n <= (ReadParams.firstWrappedX - x)) {
+        wrappedPartStart = n;
+      }
+      else {
+        wrappedPartStart = (ReadParams.firstWrappedX - x);
+      }
+      /*
+       * Read the line.
+       */
+      for (i = 0; i < wrappedPartStart; i++) {
+        depth[i] =
+           GET_ORDINARY_FB_DATA(&ReadParams, GLushort, x + i, y);
+      }
+      for (; i < n; i++) {
+        depth[i] = GET_WRAPPED_FB_DATA(&ReadParams, GLushort,
+                                       x + i, y);
+      }
+      READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+      break;
+   }
+   case 24:
+   case 32:
+   {
+      LFBParameters ReadParams;
+      GrLfbInfo_t backBufferInfo;
+      int wrappedPartStart;
+      GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits;
+      GetBackBufferInfo(fxMesa, &backBufferInfo);
+      /*
+       * Note that the _LOCK macro adds a curly brace,
+       * and the UNLOCK macro removes it.
+       */
+      READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
+      GetFbParams(fxMesa, &info, &backBufferInfo,
+                 &ReadParams, sizeof(GLuint));
+      if (ReadParams.firstWrappedX <= x) {
+        wrappedPartStart = 0;
+      }
+      else if (n <= (ReadParams.firstWrappedX - x)) {
+        wrappedPartStart = n;
+      }
+      else {
+        wrappedPartStart = (ReadParams.firstWrappedX - x);
+      }
+      /*
+       * Read the line.
+       */
+      for (i = 0; i < wrappedPartStart; i++) {
+        const GLuint mask =
+           (stencil_size > 0) ? 0x00FFFFFF : 0xFFFFFFFF;
+        depth[i] =
+           GET_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y);
+        depth[i] &= mask;
+      }
+      for (; i < n; i++) {
+        const GLuint mask =
+           (stencil_size > 0) ? 0x00FFFFFF : 0xFFFFFFFF;
+        depth[i] = GET_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y);
+        depth[i] &= mask;
+      }
+      READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+      break;
+   }
+   }
+}
+
+
+static void
+tdfxDDWriteDepthPixels(GLcontext * ctx,
+                      GLuint n, const GLint x[], const GLint y[],
+                      const GLdepth depth[], const GLubyte mask[])
+{
+   tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
+   GLint bottom = fxMesa->height + fxMesa->y_offset - 1;
+   GLuint i;
+   GLushort d16;
+   GLuint d32;
+   GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
+   GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits;
+   GrLfbInfo_t info;
+   int xpos;
+   int ypos;
+   GrLfbInfo_t backBufferInfo;
+
+   if (MESA_VERBOSE & VERBOSE_DRIVER) {
+      fprintf(stderr, "tdfxmesa: tdfxDDWriteDepthPixels(...)\n");
+   }
+
+   switch (depth_size) {
+   case 16:
+      GetBackBufferInfo(fxMesa, &backBufferInfo);
+      /*
+       * Note that the _LOCK macro adds a curly brace,
+       * and the UNLOCK macro removes it.
+       */
+      WRITE_FB_SPAN_LOCK(fxMesa, info,
+                        GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
+      {
+        LFBParameters ReadParams;
+        GetFbParams(fxMesa, &info, &backBufferInfo,
+                    &ReadParams, sizeof(GLushort));
+        for (i = 0; i < n; i++) {
+           if (mask[i] && visible_pixel(fxMesa, x[i], y[i])) {
+              xpos = x[i] + fxMesa->x_offset;
+              ypos = bottom - y[i];
+              d16 = depth[i];
+              PUT_FB_DATA(&ReadParams, GLushort, xpos, ypos, d16);
+           }
+        }
+      }
+      WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+      break;
+   case 24:
+   case 32:
+      GetBackBufferInfo(fxMesa, &backBufferInfo);
+      /*
+       * Note that the _LOCK macro adds a curly brace,
+       * and the UNLOCK macro removes it.
+       */
+      WRITE_FB_SPAN_LOCK(fxMesa, info,
+                        GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
+      {
+        LFBParameters ReadParams;
+        GetFbParams(fxMesa, &info, &backBufferInfo,
+                    &ReadParams, sizeof(GLuint));
+        for (i = 0; i < n; i++) {
+           if (mask[i]) {
+              if (visible_pixel(fxMesa, x[i], y[i])) {
+                 xpos = x[i] + fxMesa->x_offset;
+                 ypos = bottom - y[i];
+                 if (stencil_size > 0) {
+                    d32 =
+                       GET_FB_DATA(&ReadParams, GLuint, xpos, ypos);
+                    d32 = (d32 & 0xFF000000) | (depth[i] & 0xFFFFFF);
+                 }
+                 else {
+                    d32 = depth[i];
+                 }
+                 PUT_FB_DATA(&ReadParams, GLuint, xpos, ypos, d32);
+              }
+           }
+        }
+      }
+      WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+      break;
+   }
+}
+
+
+static void
+tdfxDDReadDepthPixels(GLcontext * ctx, GLuint n,
+                     const GLint x[], const GLint y[], GLdepth depth[])
+{
+   tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
+   GLint bottom = fxMesa->height + fxMesa->y_offset - 1;
+   GLuint i;
+   GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
+   GLushort d16;
+   int xpos;
+   int ypos;
+   GrLfbInfo_t info;
+   GLuint stencil_size;
+   GrLfbInfo_t backBufferInfo;
+
+   if (MESA_VERBOSE & VERBOSE_DRIVER) {
+      fprintf(stderr, "tdfxmesa: tdfxDDReadDepthPixels(...)\n");
+   }
+
+   assert((depth_size == 16) || (depth_size == 24) || (depth_size == 32));
+   switch (depth_size) {
+   case 16:
+      GetBackBufferInfo(fxMesa, &backBufferInfo);
+      /*
+       * Note that the _LOCK macro adds a curly brace,
+       * and the UNLOCK macro removes it.
+       */
+      READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
+      {
+        LFBParameters ReadParams;
+        GetFbParams(fxMesa, &info, &backBufferInfo,
+                    &ReadParams, sizeof(GLushort));
+        for (i = 0; i < n; i++) {
+           /*
+            * Convert to screen coordinates.
+            */
+           xpos = x[i] + fxMesa->x_offset;
+           ypos = bottom - y[i];
+           d16 = GET_FB_DATA(&ReadParams, GLushort, xpos, ypos);
+           depth[i] = d16;
+        }
+      }
+      READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+      break;
+   case 24:
+   case 32:
+      GetBackBufferInfo(fxMesa, &backBufferInfo);
+      /*
+       * Note that the _LOCK macro adds a curly brace,
+       * and the UNLOCK macro removes it.
+       */
+      READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
+      stencil_size = fxMesa->glCtx->Visual.stencilBits;
+      {
+        LFBParameters ReadParams;
+        GetFbParams(fxMesa, &info, &backBufferInfo,
+                    &ReadParams, sizeof(GLuint));
+        for (i = 0; i < n; i++) {
+           GLuint d32;
+
+           /*
+            * Convert to screen coordinates.
+            */
+           xpos = x[i] + fxMesa->x_offset;
+           ypos = bottom - y[i];
+           d32 = GET_FB_DATA(&ReadParams, GLuint, xpos, ypos);
+           if (stencil_size > 0) {
+              d32 &= 0x00FFFFFF;
+           }
+           depth[i] = d32;
+        }
+      }
+      READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+      break;
+   default:
+      assert(0);
+   }
+}
+
+/*
+ * Stencil buffer read/write functions.
+ */
+#define EXTRACT_S_FROM_ZS(zs) (((zs) >> 24) & 0xFF)
+#define EXTRACT_Z_FROM_ZS(zs) ((zs) & 0xffffff)
+#define BUILD_ZS(z, s)  (((s) << 24) | (z))
+
+static void
+write_stencil_span(GLcontext * ctx, GLuint n, GLint x, GLint y,
+                   const GLstencil stencil[], const GLubyte mask[])
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrLfbInfo_t info;
+   GrLfbInfo_t backBufferInfo;
+
+   GetBackBufferInfo(fxMesa, &backBufferInfo);
+   /*
+    * Note that the _LOCK macro adds a curly brace,
+    * and the UNLOCK macro removes it.
+    */
+   WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
+   {
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      const GLint winX = fxMesa->x_offset;
+      const GLint scrX = winX + x;
+      const GLint scrY = winY - y;
+      LFBParameters ReadParams;
+      GLubyte visMask[MAX_WIDTH];
+      GLuint i;
+      int wrappedPartStart;
+
+      GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
+                 sizeof(GLuint));
+      if (ReadParams.firstWrappedX <= x) {
+        wrappedPartStart = 0;
+      }
+      else if (n <= (ReadParams.firstWrappedX - x)) {
+        wrappedPartStart = n;
+      }
+      else {
+        wrappedPartStart = (ReadParams.firstWrappedX - x);
+      }
+      generate_vismask(fxMesa, scrX, scrY, n, visMask);
+      for (i = 0; i < wrappedPartStart; i++) {
+        if (visMask[i] && (!mask || mask[i])) {
+           GLuint z = GET_ORDINARY_FB_DATA(&ReadParams, GLuint,
+                                           scrX + i, scrY) & 0x00FFFFFF;
+           z |= (stencil[i] & 0xFF) << 24;
+           PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, scrX + i, scrY, z);
+        }
+      }
+      for (; i < n; i++) {
+        if (visMask[i] && (!mask || mask[i])) {
+           GLuint z = GET_WRAPPED_FB_DATA(&ReadParams, GLuint,
+                                          scrX + i, scrY) & 0x00FFFFFF;
+           z |= (stencil[i] & 0xFF) << 24;
+           PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, scrX + i, scrY, z);
+        }
+      }
+   }
+   WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+}
+
+
+static void
+read_stencil_span(GLcontext * ctx, GLuint n, GLint x, GLint y,
+                  GLstencil stencil[])
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrLfbInfo_t info;
+   GrLfbInfo_t backBufferInfo;
+
+   GetBackBufferInfo(fxMesa, &backBufferInfo);
+   /*
+    * Note that the _LOCK macro adds a curly brace,
+    * and the UNLOCK macro removes it.
+    */
+   READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
+   {
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      const GLint winX = fxMesa->x_offset;
+      GLuint i;
+      LFBParameters ReadParams;
+      int wrappedPartStart;
+
+      /*
+       * Convert to screen coordinates.
+       */
+      x += winX;
+      y = winY - y;
+      GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
+                 sizeof(GLuint));
+      if (ReadParams.firstWrappedX <= x) {
+        wrappedPartStart = 0;
+      }
+      else if (n <= (ReadParams.firstWrappedX - x)) {
+        wrappedPartStart = n;
+      }
+      else {
+        wrappedPartStart = (ReadParams.firstWrappedX - x);
+      }
+      for (i = 0; i < wrappedPartStart; i++) {
+        stencil[i] = (GET_ORDINARY_FB_DATA(&ReadParams, GLuint,
+                                           x + i, y) >> 24) & 0xFF;
+      }
+      for (; i < n; i++) {
+        stencil[i] = (GET_WRAPPED_FB_DATA(&ReadParams, GLuint,
+                                          x + i, y) >> 24) & 0xFF;
+      }
+   }
+   READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+}
+
+
+static void
+write_stencil_pixels(GLcontext * ctx, GLuint n,
+                     const GLint x[], const GLint y[],
+                     const GLstencil stencil[], const GLubyte mask[])
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrLfbInfo_t info;
+   GrLfbInfo_t backBufferInfo;
+
+   GetBackBufferInfo(fxMesa, &backBufferInfo);
+   /*
+    * Note that the _LOCK macro adds a curly brace,
+    * and the UNLOCK macro removes it.
+    */
+   WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
+   {
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      const GLint winX = fxMesa->x_offset;
+      LFBParameters ReadParams;
+      GLuint i;
+
+      GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
+                 sizeof(GLuint));
+      for (i = 0; i < n; i++) {
+        const GLint scrX = winX + x[i];
+        const GLint scrY = winY - y[i];
+        if ((!mask || mask[i]) && visible_pixel(fxMesa, scrX, scrY)) {
+           GLuint z =
+              GET_FB_DATA(&ReadParams, GLuint, scrX, scrY) & 0x00FFFFFF;
+           z |= (stencil[i] & 0xFF) << 24;
+           PUT_FB_DATA(&ReadParams, GLuint, scrX, scrY, z);
+        }
+      }
+   }
+   WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+}
+
+
+static void
+read_stencil_pixels(GLcontext * ctx, GLuint n, const GLint x[],
+                    const GLint y[], GLstencil stencil[])
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrLfbInfo_t info;
+   GrLfbInfo_t backBufferInfo;
+
+   GetBackBufferInfo(fxMesa, &backBufferInfo);
+   /*
+    * Note that the _LOCK macro adds a curly brace,
+    * and the UNLOCK macro removes it.
+    */
+   READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
+   {
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+      const GLint winX = fxMesa->x_offset;
+      GLuint i;
+      LFBParameters ReadParams;
+
+      GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
+                 sizeof(GLuint));
+      for (i = 0; i < n; i++) {
+        const GLint scrX = winX + x[i];
+        const GLint scrY = winY - y[i];
+        stencil[i] =
+           (GET_FB_DATA(&ReadParams, GLuint, scrX, scrY) >> 24) & 0xFF;
+      }
+   }
+   READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
+}
+
+#define VISUAL_EQUALS_RGBA(vis, r, g, b, a)        \
+   ((vis.redBits == r) &&                         \
+    (vis.greenBits == g) &&                       \
+    (vis.blueBits == b) &&                        \
+    (vis.alphaBits == a))
+
+
+
+
+/**********************************************************************/
+/*                    Locking for swrast                              */
+/**********************************************************************/
+
+
+static void tdfxSpanRenderStart( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   LOCK_HARDWARE(fxMesa);
+}
+
+static void tdfxSpanRenderFinish( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   _swrast_flush( ctx );
+   UNLOCK_HARDWARE(fxMesa);
+}
+
+/* Set the buffer used for reading */
+static void tdfxDDSetBuffer( GLcontext *ctx,
+                             GLframebuffer *buffer, GLuint bufferBit )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   (void) buffer;
+
+   switch ( bufferBit ) {
+   case FRONT_LEFT_BIT:
+      fxMesa->DrawBuffer = fxMesa->ReadBuffer = GR_BUFFER_FRONTBUFFER;
+      break;
+   case BACK_LEFT_BIT:
+      fxMesa->DrawBuffer = fxMesa->ReadBuffer = GR_BUFFER_BACKBUFFER;
+      break;
+   default:
+      break;
+   }
+}
+
+/**********************************************************************/
+/*                    Initialize swrast device driver                 */
+/**********************************************************************/
+
+void tdfxDDInitSpanFuncs( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference( ctx );
+
+   swdd->SetBuffer = tdfxDDSetBuffer;
+
+   if ( VISUAL_EQUALS_RGBA(ctx->Visual, 5, 6, 5, 0) )
+   {
+      /* 16bpp mode */
+      swdd->WriteRGBASpan      = tdfxWriteRGBASpan_RGB565;
+      swdd->WriteRGBSpan       = tdfxWriteRGBSpan_RGB565;
+      swdd->WriteMonoRGBASpan  = tdfxWriteMonoRGBASpan_RGB565;
+      swdd->WriteRGBAPixels    = tdfxWriteRGBAPixels_RGB565;
+      swdd->WriteMonoRGBAPixels        = tdfxWriteMonoRGBAPixels_RGB565;
+      swdd->ReadRGBASpan       = tdfxReadRGBASpan_RGB565;
+      swdd->ReadRGBAPixels     = tdfxReadRGBAPixels_RGB565;
+   }
+   else if ( VISUAL_EQUALS_RGBA(ctx->Visual, 8, 8, 8, 0) )
+   {
+      /* 24bpp mode */
+      swdd->WriteRGBASpan      = tdfxWriteRGBASpan_RGB888;
+      swdd->WriteRGBSpan       = tdfxWriteRGBSpan_RGB888;
+      swdd->WriteMonoRGBASpan  = tdfxWriteMonoRGBASpan_RGB888;
+      swdd->WriteRGBAPixels    = tdfxWriteRGBAPixels_RGB888;
+      swdd->WriteMonoRGBAPixels        = tdfxWriteMonoRGBAPixels_RGB888;
+      swdd->ReadRGBASpan       = tdfxReadRGBASpan_RGB888;
+      swdd->ReadRGBAPixels     = tdfxReadRGBAPixels_RGB888;
+   }
+   else if ( VISUAL_EQUALS_RGBA(ctx->Visual, 8, 8, 8, 8) )
+   {
+      /* 32bpp mode */
+      swdd->WriteRGBASpan      = tdfxWriteRGBASpan_ARGB8888;
+      swdd->WriteRGBSpan       = tdfxWriteRGBSpan_ARGB8888;
+      swdd->WriteMonoRGBASpan  = tdfxWriteMonoRGBASpan_ARGB8888;
+      swdd->WriteRGBAPixels    = tdfxWriteRGBAPixels_ARGB8888;
+      swdd->WriteMonoRGBAPixels        = tdfxWriteMonoRGBAPixels_ARGB8888;
+      swdd->ReadRGBAPixels      = tdfxReadRGBAPixels_ARGB8888;
+      swdd->ReadRGBASpan       = tdfxReadRGBASpan_ARGB8888;
+   }
+   else
+   {
+      abort();
+   }
+
+   if ( fxMesa->haveHwStencil ) {
+      swdd->WriteStencilSpan   = write_stencil_span;
+      swdd->ReadStencilSpan    = read_stencil_span;
+      swdd->WriteStencilPixels = write_stencil_pixels;
+      swdd->ReadStencilPixels  = read_stencil_pixels;
+   }
+
+   swdd->WriteDepthSpan                = tdfxDDWriteDepthSpan;
+   swdd->WriteDepthPixels      = tdfxDDWriteDepthPixels;
+   swdd->ReadDepthSpan         = tdfxDDReadDepthSpan;
+   swdd->ReadDepthPixels       = tdfxDDReadDepthPixels;
+
+   swdd->WriteCI8Span          = NULL;
+   swdd->WriteCI32Span         = NULL;
+   swdd->WriteMonoCISpan       = NULL;
+   swdd->WriteCI32Pixels       = NULL;
+   swdd->WriteMonoCIPixels     = NULL;
+   swdd->ReadCI32Span          = NULL;
+   swdd->ReadCI32Pixels                = NULL;
+
+   swdd->SpanRenderStart          = tdfxSpanRenderStart;
+   swdd->SpanRenderFinish         = tdfxSpanRenderFinish; 
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_span.h b/src/mesa/drivers/dri/tdfx/tdfx_span.h
new file mode 100644 (file)
index 0000000..8373d1a
--- /dev/null
@@ -0,0 +1,48 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_span.h,v 1.1 2001/03/21 16:14:28 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_SPAN_H__
+#define __TDFX_SPAN_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "context.h"
+
+extern void tdfxDDInitSpanFuncs( GLcontext *ctx );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_state.c b/src/mesa/drivers/dri/tdfx/tdfx_state.c
new file mode 100644 (file)
index 0000000..bab3854
--- /dev/null
@@ -0,0 +1,1466 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_state.c,v 1.7 2002/10/30 12:52:00 alanh Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *      Keith Whitwell <keith@tungstengraphics.com> (port to 3.5)
+ *
+ */
+
+#include "mtypes.h"
+#include "colormac.h"
+#include "texformat.h"
+#include "texstore.h"
+
+#include "swrast/swrast.h"
+#include "array_cache/acache.h"
+#include "tnl/tnl.h"
+#include "tnl/t_pipeline.h"
+#include "swrast_setup/swrast_setup.h"
+
+#include "tdfx_context.h"
+#include "tdfx_state.h"
+#include "tdfx_vb.h"
+#include "tdfx_tex.h"
+#include "tdfx_texman.h"
+#include "tdfx_texstate.h"
+#include "tdfx_tris.h"
+#include "tdfx_render.h"
+
+
+
+/* =============================================================
+ * Alpha blending
+ */
+
+static void tdfxUpdateAlphaMode( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrCmpFnc_t func;
+   GrAlphaBlendFnc_t srcRGB, dstRGB, srcA, dstA;
+   GrAlpha_t ref = (GLint) (ctx->Color.AlphaRef * 255.0);
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   if ( ctx->Color.AlphaEnabled ) {
+      switch ( ctx->Color.AlphaFunc ) {
+      case GL_NEVER:
+        func = GR_CMP_NEVER;
+        break;
+      case GL_LESS:
+        func = GR_CMP_LESS;
+         break;
+      case GL_LEQUAL:
+        func = GR_CMP_LEQUAL;
+        break;
+      case GL_EQUAL:
+        func = GR_CMP_EQUAL;
+        break;
+      case GL_GEQUAL:
+        func = GR_CMP_GEQUAL;
+        break;
+      case GL_GREATER:
+        func = GR_CMP_GREATER;
+        break;
+      case GL_NOTEQUAL:
+        func = GR_CMP_NOTEQUAL;
+        break;
+      case GL_ALWAYS:
+      default:
+        func = GR_CMP_ALWAYS;
+        break;
+      }
+   } else {
+      func = GR_CMP_ALWAYS;
+   }
+
+   if ( ctx->Color.BlendEnabled
+        && (fxMesa->Fallback & TDFX_FALLBACK_BLEND) == 0 ) {
+      switch ( ctx->Color.BlendSrcRGB ) {
+      case GL_ZERO:
+        srcRGB = GR_BLEND_ZERO;
+        break;
+      case GL_ONE:
+        srcRGB = GR_BLEND_ONE;
+        break;
+      case GL_DST_COLOR:
+        srcRGB = GR_BLEND_DST_COLOR;
+        break;
+      case GL_ONE_MINUS_DST_COLOR:
+        srcRGB = GR_BLEND_ONE_MINUS_DST_COLOR;
+        break;
+      case GL_SRC_ALPHA:
+        srcRGB = GR_BLEND_SRC_ALPHA;
+        break;
+      case GL_ONE_MINUS_SRC_ALPHA:
+        srcRGB = GR_BLEND_ONE_MINUS_SRC_ALPHA;
+        break;
+      case GL_DST_ALPHA:
+        srcRGB = GR_BLEND_DST_ALPHA;
+        break;
+      case GL_ONE_MINUS_DST_ALPHA:
+        srcRGB = GR_BLEND_ONE_MINUS_DST_ALPHA;
+        break;
+      case GL_SRC_ALPHA_SATURATE:
+        srcRGB = GR_BLEND_ALPHA_SATURATE;
+        break;
+      default:
+        srcRGB = GR_BLEND_ONE;
+      }
+
+      switch ( ctx->Color.BlendSrcA ) {
+      case GL_ZERO:
+        srcA = GR_BLEND_ZERO;
+        break;
+      case GL_ONE:
+        srcA = GR_BLEND_ONE;
+        break;
+      case GL_DST_COLOR:
+        srcA = GR_BLEND_DST_ALPHA;  /* Napalm only */
+        break;
+      case GL_ONE_MINUS_DST_COLOR:
+        srcA = GR_BLEND_ONE_MINUS_DST_ALPHA;  /* Napalm only */
+        break;
+      case GL_SRC_ALPHA:
+        srcA = GR_BLEND_SRC_ALPHA;  /* Napalm only */
+        break;
+      case GL_ONE_MINUS_SRC_ALPHA:
+        srcA = GR_BLEND_ONE_MINUS_SRC_ALPHA;  /* Napalm only */
+        break;
+      case GL_DST_ALPHA:
+        srcA = GR_BLEND_DST_ALPHA;  /* Napalm only */
+        break;
+      case GL_ONE_MINUS_DST_ALPHA:
+        srcA = GR_BLEND_ONE_MINUS_DST_ALPHA;  /* Napalm only */
+        break;
+      case GL_SRC_ALPHA_SATURATE:
+         srcA = GR_BLEND_ONE;
+        break;
+      default:
+        srcA = GR_BLEND_ONE;
+      }
+
+      switch ( ctx->Color.BlendDstRGB ) {
+      case GL_ZERO:
+        dstRGB = GR_BLEND_ZERO;
+        break;
+      case GL_ONE:
+        dstRGB = GR_BLEND_ONE;
+        break;
+      case GL_SRC_COLOR:
+        dstRGB = GR_BLEND_SRC_COLOR;
+        break;
+      case GL_ONE_MINUS_SRC_COLOR:
+        dstRGB = GR_BLEND_ONE_MINUS_SRC_COLOR;
+        break;
+      case GL_SRC_ALPHA:
+        dstRGB = GR_BLEND_SRC_ALPHA;
+        break;
+      case GL_ONE_MINUS_SRC_ALPHA:
+        dstRGB = GR_BLEND_ONE_MINUS_SRC_ALPHA;
+        break;
+      case GL_DST_ALPHA:
+        dstRGB = GR_BLEND_DST_ALPHA;
+        break;
+      case GL_ONE_MINUS_DST_ALPHA:
+        dstRGB = GR_BLEND_ONE_MINUS_DST_ALPHA;
+        break;
+      default:
+        dstRGB = GR_BLEND_ZERO;
+      }
+
+      switch ( ctx->Color.BlendDstA ) {
+      case GL_ZERO:
+        dstA = GR_BLEND_ZERO;
+        break;
+      case GL_ONE:
+        dstA = GR_BLEND_ONE;
+        break;
+      case GL_SRC_COLOR:
+        dstA = GR_BLEND_SRC_ALPHA;  /* Napalm only */
+        break;
+      case GL_ONE_MINUS_SRC_COLOR:
+        dstA = GR_BLEND_ONE_MINUS_SRC_ALPHA;  /* Napalm only */
+        break;
+      case GL_SRC_ALPHA:
+        dstA = GR_BLEND_SRC_ALPHA;  /* Napalm only */
+        break;
+      case GL_ONE_MINUS_SRC_ALPHA:
+        dstA = GR_BLEND_ONE_MINUS_SRC_ALPHA;  /* Napalm only */
+        break;
+      case GL_DST_ALPHA:
+        dstA = GR_BLEND_DST_ALPHA;  /* Napalm only */
+        break;
+      case GL_ONE_MINUS_DST_ALPHA:
+        dstA = GR_BLEND_ONE_MINUS_DST_ALPHA;  /* Napalm only */
+        break;
+      default:
+        dstA = GR_BLEND_ZERO;
+      }
+   } else {
+      /* blend disabled */
+      srcRGB = GR_BLEND_ONE;
+      dstRGB = GR_BLEND_ZERO;
+      srcA = GR_BLEND_ONE;
+      dstA = GR_BLEND_ZERO;
+   }
+
+   if ( fxMesa->Color.AlphaFunc != func ) {
+      fxMesa->Color.AlphaFunc = func;
+      fxMesa->dirty |= TDFX_UPLOAD_ALPHA_TEST;
+   }
+   if ( fxMesa->Color.AlphaRef != ref ) {
+      fxMesa->Color.AlphaRef = ref;
+      fxMesa->dirty |= TDFX_UPLOAD_ALPHA_REF;
+   }
+
+   if ( fxMesa->Color.BlendSrcRGB != srcRGB ||
+       fxMesa->Color.BlendDstRGB != dstRGB ||
+       fxMesa->Color.BlendSrcA != srcA ||
+       fxMesa->Color.BlendDstA != dstA )
+   {
+      fxMesa->Color.BlendSrcRGB = srcRGB;
+      fxMesa->Color.BlendDstRGB = dstRGB;
+      fxMesa->Color.BlendSrcA = srcA;
+      fxMesa->Color.BlendDstA = dstA;
+      fxMesa->dirty |= TDFX_UPLOAD_BLEND_FUNC;
+   }
+}
+
+static void tdfxDDAlphaFunc( GLcontext *ctx, GLenum func, GLfloat ref )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_ALPHA;
+}
+
+static void tdfxDDBlendEquation( GLcontext *ctx, GLenum mode )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_ALPHA;
+}
+
+static void tdfxDDBlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_ALPHA;
+
+   /*
+    * XXX - Voodoo5 seems to suffer from precision problems in some
+    * blend modes.  To pass all the conformance tests we'd have to
+    * fall back to software for many modes.  Revisit someday.
+    */
+}
+
+static void tdfxDDBlendFuncSeparate( GLcontext *ctx,
+                                    GLenum sfactorRGB, GLenum dfactorRGB,
+                                    GLenum sfactorA, GLenum dfactorA )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_ALPHA;
+}
+
+/* =============================================================
+ * Stipple
+ */
+
+void tdfxUpdateStipple( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   GrStippleMode_t mode = GR_STIPPLE_DISABLE;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   FLUSH_BATCH( fxMesa );
+
+   if (ctx->Polygon.StippleFlag) {
+      mode = GR_STIPPLE_PATTERN;
+   }
+
+   if ( fxMesa->Stipple.Mode != mode ) {
+      fxMesa->Stipple.Mode = mode;
+      fxMesa->dirty |= TDFX_UPLOAD_STIPPLE;
+   }
+}
+
+
+/* =============================================================
+ * Depth testing
+ */
+
+static void tdfxUpdateZMode( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   GrCmpFnc_t func;
+   FxI32 bias;
+   FxBool mask;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) 
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+
+
+   bias = (FxI32) (ctx->Polygon.OffsetUnits * TDFX_DEPTH_BIAS_SCALE);
+
+   if ( ctx->Depth.Test ) {
+      switch ( ctx->Depth.Func ) {
+      case GL_NEVER:
+        func = GR_CMP_NEVER;
+        break;
+      case GL_LESS:
+        func = GR_CMP_LESS;
+         break;
+      case GL_LEQUAL:
+        func = GR_CMP_LEQUAL;
+        break;
+      case GL_EQUAL:
+        func = GR_CMP_EQUAL;
+        break;
+      case GL_GEQUAL:
+        func = GR_CMP_GEQUAL;
+        break;
+      case GL_GREATER:
+        func = GR_CMP_GREATER;
+        break;
+      case GL_NOTEQUAL:
+        func = GR_CMP_NOTEQUAL;
+        break;
+      case GL_ALWAYS:
+      default:
+        func = GR_CMP_ALWAYS;
+        break;
+      }
+
+      if ( ctx->Depth.Mask ) {
+         mask = FXTRUE;
+      }
+      else {
+         mask = FXFALSE;
+      }
+   }
+   else {
+      /* depth testing disabled */
+      func = GR_CMP_ALWAYS;  /* fragments always pass */
+      mask = FXFALSE;        /* zbuffer is not touched */
+   }
+
+   fxMesa->Depth.Clear = (FxU32) (((1 << fxMesa->glCtx->Visual.depthBits) - 1)
+                                  * ctx->Depth.Clear);
+
+   if ( fxMesa->Depth.Bias != bias ) {
+      fxMesa->Depth.Bias = bias;
+      fxMesa->dirty |= TDFX_UPLOAD_DEPTH_BIAS;
+   }
+   if ( fxMesa->Depth.Func != func ) {
+      fxMesa->Depth.Func = func;
+      fxMesa->dirty |= TDFX_UPLOAD_DEPTH_FUNC | TDFX_UPLOAD_DEPTH_MASK;
+   }
+   if ( fxMesa->Depth.Mask != mask ) {
+      fxMesa->Depth.Mask = mask;
+      fxMesa->dirty |= TDFX_UPLOAD_DEPTH_MASK;
+   }
+}
+
+static void tdfxDDDepthFunc( GLcontext *ctx, GLenum func )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_DEPTH;
+}
+
+static void tdfxDDDepthMask( GLcontext *ctx, GLboolean flag )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_DEPTH;
+}
+
+static void tdfxDDClearDepth( GLcontext *ctx, GLclampd d )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_DEPTH;
+}
+
+
+
+/* =============================================================
+ * Stencil
+ */
+
+
+/* Evaluate all stencil state and make the Glide calls.
+ */
+static GrStencil_t convertGLStencilOp( GLenum op )
+{
+   switch ( op ) {
+   case GL_KEEP:
+      return GR_STENCILOP_KEEP;
+   case GL_ZERO:
+      return GR_STENCILOP_ZERO;
+   case GL_REPLACE:
+      return GR_STENCILOP_REPLACE;
+   case GL_INCR:
+      return GR_STENCILOP_INCR_CLAMP;
+   case GL_DECR:
+      return GR_STENCILOP_DECR_CLAMP;
+   case GL_INVERT:
+      return GR_STENCILOP_INVERT;
+   case GL_INCR_WRAP_EXT:
+      return GR_STENCILOP_INCR_WRAP;
+   case GL_DECR_WRAP_EXT:
+      return GR_STENCILOP_DECR_WRAP;
+   default:
+      _mesa_problem( NULL, "bad stencil op in convertGLStencilOp" );
+   }
+   return GR_STENCILOP_KEEP;   /* never get, silence compiler warning */
+}
+
+
+static void tdfxUpdateStencil( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   if (fxMesa->haveHwStencil) {
+      if (ctx->Stencil.Enabled) {
+         fxMesa->Stencil.Function = ctx->Stencil.Function[0] - GL_NEVER;
+         fxMesa->Stencil.RefValue = ctx->Stencil.Ref[0];
+         fxMesa->Stencil.ValueMask = ctx->Stencil.ValueMask[0];
+         fxMesa->Stencil.WriteMask = ctx->Stencil.WriteMask[0];
+         fxMesa->Stencil.FailFunc = convertGLStencilOp(ctx->Stencil.FailFunc[0]);
+         fxMesa->Stencil.ZFailFunc = convertGLStencilOp(ctx->Stencil.ZFailFunc[0]);
+         fxMesa->Stencil.ZPassFunc = convertGLStencilOp(ctx->Stencil.ZPassFunc[0]);
+         fxMesa->Stencil.Clear = ctx->Stencil.Clear & 0xff;
+      }
+      fxMesa->dirty |= TDFX_UPLOAD_STENCIL;
+   }
+}
+
+
+static void tdfxDDStencilFunc( GLcontext *ctx, GLenum func,
+                              GLint ref, GLuint mask )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_STENCIL;
+}
+
+static void tdfxDDStencilMask( GLcontext *ctx, GLuint mask )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_STENCIL;
+}
+
+static void tdfxDDStencilOp( GLcontext *ctx, GLenum sfail,
+                            GLenum zfail, GLenum zpass )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_STENCIL;
+}
+
+
+/* =============================================================
+ * Fog - orthographic fog still not working
+ */
+
+static void tdfxUpdateFogAttrib( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrFogMode_t mode;
+   GrColor_t color;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   if ( ctx->Fog.Enabled ) {
+      mode = GR_FOG_WITH_TABLE_ON_Q;
+   } else {
+      mode = GR_FOG_DISABLE;
+   }
+
+   color = TDFXPACKCOLOR888((GLubyte)(ctx->Fog.Color[0]*255.0F),
+                           (GLubyte)(ctx->Fog.Color[1]*255.0F),
+                           (GLubyte)(ctx->Fog.Color[2]*255.0F));
+
+   if ( fxMesa->Fog.Mode != mode ) {
+      fxMesa->Fog.Mode = mode;
+      fxMesa->dirty |= TDFX_UPLOAD_FOG_MODE;
+   }
+   if ( fxMesa->Fog.Color != color ) {
+      fxMesa->Fog.Color = color;
+      fxMesa->dirty |= TDFX_UPLOAD_FOG_COLOR;
+   }
+   if ( fxMesa->Fog.TableMode != ctx->Fog.Mode ||
+       fxMesa->Fog.Density != ctx->Fog.Density ||
+       fxMesa->Fog.Near != ctx->Fog.Start ||
+       fxMesa->Fog.Far != ctx->Fog.End )
+   {
+      switch( ctx->Fog.Mode ) {
+      case GL_EXP:
+        fxMesa->Glide.guFogGenerateExp( fxMesa->Fog.Table, ctx->Fog.Density );
+        break;
+      case GL_EXP2:
+        fxMesa->Glide.guFogGenerateExp2( fxMesa->Fog.Table, ctx->Fog.Density);
+        break;
+      case GL_LINEAR:
+        fxMesa->Glide.guFogGenerateLinear( fxMesa->Fog.Table,
+                                            ctx->Fog.Start, ctx->Fog.End );
+        break;
+      }
+
+      fxMesa->Fog.TableMode = ctx->Fog.Mode;
+      fxMesa->Fog.Density = ctx->Fog.Density;
+      fxMesa->Fog.Near = ctx->Fog.Start;
+      fxMesa->Fog.Far = ctx->Fog.End;
+      fxMesa->dirty |= TDFX_UPLOAD_FOG_TABLE;
+   }
+}
+
+static void tdfxDDFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_FOG;
+}
+
+
+/* =============================================================
+ * Clipping
+ */
+
+static int intersect_rect( XF86DRIClipRectPtr out,
+                          const XF86DRIClipRectPtr a,
+                          const XF86DRIClipRectPtr b)
+{
+   *out = *a;
+   if (b->x1 > out->x1) out->x1 = b->x1;
+   if (b->y1 > out->y1) out->y1 = b->y1;
+   if (b->x2 < out->x2) out->x2 = b->x2;
+   if (b->y2 < out->y2) out->y2 = b->y2;
+   if (out->x1 >= out->x2) return 0;
+   if (out->y1 >= out->y2) return 0;
+   return 1;
+}
+
+
+/*
+ * Examine XF86 cliprect list and scissor state to recompute our
+ * cliprect list.
+ */
+void tdfxUpdateClipping( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   __DRIdrawablePrivate *dPriv = fxMesa->driDrawable;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   assert(ctx);
+   assert(fxMesa);
+   assert(dPriv);
+
+   if ( dPriv->x != fxMesa->x_offset || dPriv->y != fxMesa->y_offset ||
+       dPriv->w != fxMesa->width || dPriv->h != fxMesa->height ) {
+      fxMesa->x_offset = dPriv->x;
+      fxMesa->y_offset = dPriv->y;
+      fxMesa->width = dPriv->w;
+      fxMesa->height = dPriv->h;
+      fxMesa->y_delta =
+        fxMesa->screen_height - fxMesa->y_offset - fxMesa->height;
+      tdfxUpdateViewport( ctx );
+   }
+
+   if (fxMesa->scissoredClipRects && fxMesa->pClipRects) {
+      free(fxMesa->pClipRects);
+   }
+
+   if (ctx->Scissor.Enabled) {
+      /* intersect OpenGL scissor box with all cliprects to make a new
+       * list of cliprects.
+       */
+      XF86DRIClipRectRec scissor;
+      int x1 = ctx->Scissor.X + fxMesa->x_offset;
+      int y1 = fxMesa->screen_height - fxMesa->y_delta
+             - ctx->Scissor.Y - ctx->Scissor.Height;
+      int x2 = x1 + ctx->Scissor.Width;
+      int y2 = y1 + ctx->Scissor.Height;
+      scissor.x1 = MAX2(x1, 0);
+      scissor.y1 = MAX2(y1, 0);
+      scissor.x2 = MAX2(x2, 0);
+      scissor.y2 = MAX2(y2, 0);
+
+      assert(scissor.x2 >= scissor.x1);
+      assert(scissor.y2 >= scissor.y1);
+
+      fxMesa->pClipRects = malloc(dPriv->numClipRects
+                                  * sizeof(XF86DRIClipRectRec));
+      if (fxMesa->pClipRects) {
+         int i;
+         fxMesa->numClipRects = 0;
+         for (i = 0; i < dPriv->numClipRects; i++) {
+            if (intersect_rect(&fxMesa->pClipRects[fxMesa->numClipRects],
+                               &scissor, &dPriv->pClipRects[i])) {
+               fxMesa->numClipRects++;
+            }
+         }
+         fxMesa->scissoredClipRects = GL_TRUE;
+      }
+      else {
+         /* out of memory, forgo scissor */
+         fxMesa->numClipRects = dPriv->numClipRects;
+         fxMesa->pClipRects = dPriv->pClipRects;
+         fxMesa->scissoredClipRects = GL_FALSE;
+      }
+   }
+   else {
+      fxMesa->numClipRects = dPriv->numClipRects;
+      fxMesa->pClipRects = dPriv->pClipRects;
+      fxMesa->scissoredClipRects = GL_FALSE;
+   }
+
+   fxMesa->dirty |= TDFX_UPLOAD_CLIP;
+}
+
+
+
+/* =============================================================
+ * Culling
+ */
+
+void tdfxUpdateCull( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrCullMode_t mode = GR_CULL_DISABLE;
+
+   /* KW: don't need to check raster_primitive here as we don't
+    * attempt to draw lines or points with triangles.
+    */
+   if ( ctx->Polygon.CullFlag ) {
+      switch ( ctx->Polygon.CullFaceMode ) {
+      case GL_FRONT:
+        if ( ctx->Polygon.FrontFace == GL_CCW ) {
+           mode = GR_CULL_POSITIVE;
+        } else {
+           mode = GR_CULL_NEGATIVE;
+        }
+        break;
+
+      case GL_BACK:
+        if ( ctx->Polygon.FrontFace == GL_CCW ) {
+           mode = GR_CULL_NEGATIVE;
+        } else {
+           mode = GR_CULL_POSITIVE;
+        }
+        break;
+
+      case GL_FRONT_AND_BACK:
+        /* Handled as a fallback on triangles in tdfx_tris.c */
+        return;
+
+      default:
+        ASSERT(0);
+        break;
+      }
+   }
+
+   if ( fxMesa->CullMode != mode ) {
+      fxMesa->CullMode = mode;
+      fxMesa->dirty |= TDFX_UPLOAD_CULL;
+   }
+}
+
+static void tdfxDDCullFace( GLcontext *ctx, GLenum mode )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_CULL;
+}
+
+static void tdfxDDFrontFace( GLcontext *ctx, GLenum mode )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_CULL;
+}
+
+
+/* =============================================================
+ * Line drawing.
+ */
+
+static void tdfxUpdateLine( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   FLUSH_BATCH( fxMesa );
+   fxMesa->dirty |= TDFX_UPLOAD_LINE;
+}
+
+
+static void tdfxDDLineWidth( GLcontext *ctx, GLfloat width )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_LINE;
+}
+
+
+/* =============================================================
+ * Color Attributes
+ */
+
+static void tdfxDDColorMask( GLcontext *ctx,
+                            GLboolean r, GLboolean g,
+                            GLboolean b, GLboolean a )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FLUSH_BATCH( fxMesa );
+
+   if ( fxMesa->Color.ColorMask[RCOMP] != r ||
+       fxMesa->Color.ColorMask[GCOMP] != g ||
+       fxMesa->Color.ColorMask[BCOMP] != b ||
+       fxMesa->Color.ColorMask[ACOMP] != a ) {
+      fxMesa->Color.ColorMask[RCOMP] = r;
+      fxMesa->Color.ColorMask[GCOMP] = g;
+      fxMesa->Color.ColorMask[BCOMP] = b;
+      fxMesa->Color.ColorMask[ACOMP] = a;
+      fxMesa->dirty |= TDFX_UPLOAD_COLOR_MASK;
+
+      if (ctx->Visual.redBits < 8) {
+         /* Can't do RGB colormasking in 16bpp mode. */
+         /* We can completely ignore the alpha mask. */
+        FALLBACK( fxMesa, TDFX_FALLBACK_COLORMASK, (r != g || g != b) );
+      }
+   }
+}
+
+
+static void tdfxDDClearColor( GLcontext *ctx,
+                             const GLfloat color[4] )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLubyte c[4];
+   FLUSH_BATCH( fxMesa );
+   CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
+   CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
+   CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
+   CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
+   fxMesa->Color.ClearColor = TDFXPACKCOLOR888( c[0], c[1], c[2] );
+   fxMesa->Color.ClearAlpha = c[3];
+}
+
+
+/* =============================================================
+ * Light Model
+ */
+
+static void tdfxDDLightModelfv( GLcontext *ctx, GLenum pname,
+                               const GLfloat *param )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if ( pname == GL_LIGHT_MODEL_COLOR_CONTROL ) {
+      FALLBACK( fxMesa, TDFX_FALLBACK_SPECULAR,
+               (ctx->Light.Enabled &&
+                ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR ));
+   }
+}
+
+static void tdfxDDShadeModel( GLcontext *ctx, GLenum mode )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   /* FIXME: Can we implement native flat shading? */
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_TEXTURE;
+}
+
+
+/* =============================================================
+ * Scissor
+ */
+
+static void
+tdfxDDScissor(GLcontext * ctx, GLint x, GLint y, GLsizei w, GLsizei h)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_CLIP;
+}
+
+/* =============================================================
+ * Render
+ */
+
+static void tdfxUpdateRenderAttrib( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   FLUSH_BATCH( fxMesa );
+   fxMesa->dirty |= TDFX_UPLOAD_RENDER_BUFFER;
+}
+
+/* =============================================================
+ * Viewport
+ */
+
+void tdfxUpdateViewport( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   const GLfloat *v = ctx->Viewport._WindowMap.m;
+   GLfloat *m = fxMesa->hw_viewport;
+
+   m[MAT_SX] = v[MAT_SX];
+   m[MAT_TX] = v[MAT_TX] + fxMesa->x_offset + TRI_X_OFFSET;
+   m[MAT_SY] = v[MAT_SY];
+   m[MAT_TY] = v[MAT_TY] + fxMesa->y_delta + TRI_Y_OFFSET;
+   m[MAT_SZ] = v[MAT_SZ];
+   m[MAT_TZ] = v[MAT_TZ];
+
+   fxMesa->SetupNewInputs |= VERT_BIT_CLIP;
+}
+
+
+static void tdfxDDViewport( GLcontext *ctx, GLint x, GLint y,
+                           GLsizei w, GLsizei h )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_VIEWPORT;
+}
+
+
+static void tdfxDDDepthRange( GLcontext *ctx, GLclampd nearVal, GLclampd farVal )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   FLUSH_BATCH( fxMesa );
+   fxMesa->new_state |= TDFX_NEW_VIEWPORT;
+}
+
+
+/* =============================================================
+ * State enable/disable
+ */
+
+static void tdfxDDEnable( GLcontext *ctx, GLenum cap, GLboolean state )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   switch ( cap ) {
+   case GL_ALPHA_TEST:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_ALPHA;
+      break;
+
+   case GL_BLEND:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_ALPHA;
+      FALLBACK( fxMesa, TDFX_FALLBACK_LOGICOP,
+               (ctx->Color.ColorLogicOpEnabled &&
+                ctx->Color.LogicOp != GL_COPY));
+      break;
+
+   case GL_CULL_FACE:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_CULL;
+      break;
+
+   case GL_DEPTH_TEST:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_DEPTH;
+      break;
+
+   case GL_DITHER:
+      FLUSH_BATCH( fxMesa );
+      if ( state ) {
+        fxMesa->Color.Dither = GR_DITHER_2x2;
+      } else {
+        fxMesa->Color.Dither = GR_DITHER_DISABLE;
+      }
+      fxMesa->dirty |= TDFX_UPLOAD_DITHER;
+      break;
+
+   case GL_FOG:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_FOG;
+      break;
+
+   case GL_COLOR_LOGIC_OP:
+      FALLBACK( fxMesa, TDFX_FALLBACK_LOGICOP,
+               (ctx->Color.ColorLogicOpEnabled &&
+                ctx->Color.LogicOp != GL_COPY));
+      break;
+
+   case GL_LIGHTING:
+      FALLBACK( fxMesa, TDFX_FALLBACK_SPECULAR,
+               (ctx->Light.Enabled &&
+                ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR ));
+      break;
+
+   case GL_LINE_SMOOTH:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_LINE;
+      break;
+
+   case GL_LINE_STIPPLE:
+      FALLBACK(fxMesa, TDFX_FALLBACK_LINE_STIPPLE, state);
+      break;
+
+   case GL_POLYGON_STIPPLE:
+      FLUSH_BATCH(fxMesa);
+      fxMesa->new_state |= TDFX_NEW_STIPPLE;
+      break;
+
+   case GL_SCISSOR_TEST:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_CLIP;
+      break;
+
+   case GL_STENCIL_TEST:
+      FLUSH_BATCH( fxMesa );
+      FALLBACK( fxMesa, TDFX_FALLBACK_STENCIL, state && !fxMesa->haveHwStencil);
+      break;
+
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_3D:
+      FLUSH_BATCH( fxMesa );
+      FALLBACK( fxMesa, TDFX_FALLBACK_TEXTURE_1D_3D, state); /* wrong */
+      fxMesa->new_state |= TDFX_NEW_TEXTURE;
+      break;
+
+   case GL_TEXTURE_2D:
+      FLUSH_BATCH( fxMesa );
+      fxMesa->new_state |= TDFX_NEW_TEXTURE;
+      break;
+
+   default:
+      return;
+   }
+}
+
+
+
+/* Set the buffer used for drawing */
+/* XXX support for separate read/draw buffers hasn't been tested */
+static void tdfxDDDrawBuffer( GLcontext *ctx, GLenum mode )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   FLUSH_BATCH( fxMesa );
+
+   /*
+    * _DrawDestMask is easier to cope with than <mode>.
+    */
+   switch ( ctx->Color._DrawDestMask ) {
+   case FRONT_LEFT_BIT:
+      fxMesa->DrawBuffer = fxMesa->ReadBuffer = GR_BUFFER_FRONTBUFFER;
+      fxMesa->new_state |= TDFX_NEW_RENDER;
+      FALLBACK( fxMesa, TDFX_FALLBACK_DRAW_BUFFER, GL_FALSE );
+      break;
+   case BACK_LEFT_BIT:
+      fxMesa->DrawBuffer = fxMesa->ReadBuffer = GR_BUFFER_BACKBUFFER;
+      fxMesa->new_state |= TDFX_NEW_RENDER;
+      FALLBACK( fxMesa, TDFX_FALLBACK_DRAW_BUFFER, GL_FALSE );
+      break;
+   case 0:
+      FX_grColorMaskv( ctx, false4 );
+      FALLBACK( fxMesa, TDFX_FALLBACK_DRAW_BUFFER, GL_FALSE );
+      break;
+   default:
+      FALLBACK( fxMesa, TDFX_FALLBACK_DRAW_BUFFER, GL_TRUE );
+      break;
+   }
+
+   /* We want to update the s/w rast state too so that tdfxDDSetBuffer()
+    * gets called.
+    */
+   _swrast_DrawBuffer(ctx, mode);
+}
+
+
+static void tdfxDDReadBuffer( GLcontext *ctx, GLenum mode )
+{
+   /* XXX ??? */
+}
+
+
+/* =============================================================
+ * Polygon stipple
+ */
+
+static void tdfxDDPolygonStipple( GLcontext *ctx, const GLubyte *mask )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   const GLubyte *m = mask;
+   GLubyte q[4];
+   int i,j,k;
+   GLboolean allBitsSet;
+
+/*     int active = (ctx->Polygon.StippleFlag &&  */
+/*              fxMesa->reduced_prim == GL_TRIANGLES); */
+
+   FLUSH_BATCH(fxMesa);
+   fxMesa->Stipple.Pattern = 0xffffffff;
+   fxMesa->dirty |= TDFX_UPLOAD_STIPPLE;
+   fxMesa->new_state |= TDFX_NEW_STIPPLE;
+
+   /* Check if the stipple pattern is fully opaque.  If so, use software
+    * rendering.  This basically a trick to make sure the OpenGL conformance
+    * test passes.
+    */
+   allBitsSet = GL_TRUE;
+   for (i = 0; i < 32; i++) {
+      if (((GLuint *) mask)[i] != 0xffffffff) {
+         allBitsSet = GL_FALSE;
+         break;
+      }
+   }
+   if (allBitsSet) {
+      fxMesa->haveHwStipple = GL_FALSE;
+      return;
+   }
+
+   q[0] = mask[0];
+   q[1] = mask[4];
+   q[2] = mask[8];
+   q[3] = mask[12];
+
+   for (k = 0 ; k < 8 ; k++)
+      for (j = 0 ; j < 4; j++)
+        for (i = 0 ; i < 4 ; i++,m++) {
+           if (*m != q[j]) {
+              fxMesa->haveHwStipple = GL_FALSE;
+              return;
+           }
+         }
+
+   fxMesa->haveHwStipple = GL_TRUE;
+   fxMesa->Stipple.Pattern = ( (q[0] << 0) |
+                               (q[1] << 8) |
+                               (q[2] << 16) |
+                               (q[3] << 24) );
+}
+
+
+
+static void tdfxDDRenderMode( GLcontext *ctx, GLenum mode )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   FALLBACK( fxMesa, TDFX_FALLBACK_RENDER_MODE, (mode != GL_RENDER) );
+}
+
+
+
+static void tdfxDDPrintState( const char *msg, GLuint flags )
+{
+   fprintf( stderr,
+           "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+           msg,
+           flags,
+           (flags & TDFX_NEW_COLOR) ? "color, " : "",
+           (flags & TDFX_NEW_ALPHA) ? "alpha, " : "",
+           (flags & TDFX_NEW_DEPTH) ? "depth, " : "",
+           (flags & TDFX_NEW_RENDER) ? "render, " : "",
+           (flags & TDFX_NEW_FOG) ? "fog, " : "",
+           (flags & TDFX_NEW_STENCIL) ? "stencil, " : "",
+           (flags & TDFX_NEW_STIPPLE) ? "stipple, " : "",
+           (flags & TDFX_NEW_CLIP) ? "clip, " : "",
+           (flags & TDFX_NEW_VIEWPORT) ? "viewport, " : "",
+           (flags & TDFX_NEW_CULL) ? "cull, " : "",
+           (flags & TDFX_NEW_GLIDE) ? "glide, " : "",
+           (flags & TDFX_NEW_TEXTURE) ? "texture, " : "",
+           (flags & TDFX_NEW_CONTEXT) ? "context, " : "");
+}
+
+
+
+void tdfxDDUpdateHwState( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   int new_state = fxMesa->new_state;
+
+   if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+      fprintf( stderr, "%s()\n", __FUNCTION__ );
+   }
+
+   if ( new_state )
+   {
+      FLUSH_BATCH( fxMesa );
+
+      fxMesa->new_state = 0;
+
+      if ( 0 )
+        tdfxDDPrintState( "tdfxUpdateHwState", new_state );
+
+      /* Update the various parts of the context's state.
+       */
+      if ( new_state & TDFX_NEW_ALPHA ) {
+        tdfxUpdateAlphaMode( ctx );
+      }
+
+      if ( new_state & TDFX_NEW_DEPTH )
+        tdfxUpdateZMode( ctx );
+
+      if ( new_state & TDFX_NEW_FOG )
+        tdfxUpdateFogAttrib( ctx );
+
+      if ( new_state & TDFX_NEW_CLIP )
+        tdfxUpdateClipping( ctx );
+
+      if ( new_state & TDFX_NEW_STIPPLE )
+        tdfxUpdateStipple( ctx );
+
+      if ( new_state & TDFX_NEW_CULL )
+        tdfxUpdateCull( ctx );
+
+      if ( new_state & TDFX_NEW_LINE )
+         tdfxUpdateLine( ctx );
+
+      if ( new_state & TDFX_NEW_VIEWPORT )
+        tdfxUpdateViewport( ctx );
+
+      if ( new_state & TDFX_NEW_RENDER )
+        tdfxUpdateRenderAttrib( ctx );
+
+      if ( new_state & TDFX_NEW_STENCIL )
+         tdfxUpdateStencil( ctx );
+
+      if ( new_state & TDFX_NEW_TEXTURE ) {
+        tdfxUpdateTextureState( ctx );
+      }
+      else if ( new_state & TDFX_NEW_TEXTURE_BIND ) {
+        tdfxUpdateTextureBinding( ctx );
+      }
+   }
+
+   if ( 0 ) {
+      FxI32 bias = (FxI32) (ctx->Polygon.OffsetUnits * TDFX_DEPTH_BIAS_SCALE);
+
+      if ( fxMesa->Depth.Bias != bias ) {
+        fxMesa->Depth.Bias = bias;
+        fxMesa->dirty |= TDFX_UPLOAD_DEPTH_BIAS;
+      }
+   }
+
+   if ( fxMesa->dirty ) {
+      LOCK_HARDWARE( fxMesa );
+      tdfxEmitHwStateLocked( fxMesa );
+      UNLOCK_HARDWARE( fxMesa );
+   }
+}
+
+
+static void tdfxDDInvalidateState( GLcontext *ctx, GLuint new_state )
+{
+   _swrast_InvalidateState( ctx, new_state );
+   _swsetup_InvalidateState( ctx, new_state );
+   _ac_InvalidateState( ctx, new_state );
+   _tnl_InvalidateState( ctx, new_state );
+   TDFX_CONTEXT(ctx)->new_gl_state |= new_state;
+}
+
+
+
+/* Initialize the context's Glide state mirror.  These values will be
+ * used as Glide function call parameters when the time comes.
+ */
+void tdfxInitState( tdfxContextPtr fxMesa )
+{
+   GLcontext *ctx = fxMesa->glCtx;
+   GLint i;
+
+   fxMesa->ColorCombine.Function       = GR_COMBINE_FUNCTION_LOCAL;
+   fxMesa->ColorCombine.Factor         = GR_COMBINE_FACTOR_NONE;
+   fxMesa->ColorCombine.Local          = GR_COMBINE_LOCAL_ITERATED;
+   fxMesa->ColorCombine.Other          = GR_COMBINE_OTHER_NONE;
+   fxMesa->ColorCombine.Invert         = FXFALSE;
+   fxMesa->AlphaCombine.Function       = GR_COMBINE_FUNCTION_LOCAL;
+   fxMesa->AlphaCombine.Factor         = GR_COMBINE_FACTOR_NONE;
+   fxMesa->AlphaCombine.Local          = GR_COMBINE_LOCAL_ITERATED;
+   fxMesa->AlphaCombine.Other          = GR_COMBINE_OTHER_NONE;
+   fxMesa->AlphaCombine.Invert         = FXFALSE;
+
+   fxMesa->ColorCombineExt.SourceA     = GR_CMBX_ITRGB;
+   fxMesa->ColorCombineExt.ModeA       = GR_FUNC_MODE_X;
+   fxMesa->ColorCombineExt.SourceB     = GR_CMBX_ZERO;
+   fxMesa->ColorCombineExt.ModeB       = GR_FUNC_MODE_ZERO;
+   fxMesa->ColorCombineExt.SourceC     = GR_CMBX_ZERO;
+   fxMesa->ColorCombineExt.InvertC     = FXTRUE;
+   fxMesa->ColorCombineExt.SourceD     = GR_CMBX_ZERO;
+   fxMesa->ColorCombineExt.InvertD     = FXFALSE;
+   fxMesa->ColorCombineExt.Shift       = 0;
+   fxMesa->ColorCombineExt.Invert      = FXFALSE;
+   fxMesa->AlphaCombineExt.SourceA     = GR_CMBX_ITALPHA;
+   fxMesa->AlphaCombineExt.ModeA       = GR_FUNC_MODE_X;
+   fxMesa->AlphaCombineExt.SourceB     = GR_CMBX_ZERO;
+   fxMesa->AlphaCombineExt.ModeB       = GR_FUNC_MODE_ZERO;
+   fxMesa->AlphaCombineExt.SourceC     = GR_CMBX_ZERO;
+   fxMesa->AlphaCombineExt.InvertC     = FXTRUE;
+   fxMesa->AlphaCombineExt.SourceD     = GR_CMBX_ZERO;
+   fxMesa->AlphaCombineExt.InvertD     = FXFALSE;
+   fxMesa->AlphaCombineExt.Shift       = 0;
+   fxMesa->AlphaCombineExt.Invert      = FXFALSE;
+
+   fxMesa->sScale0 = fxMesa->tScale0 = 1.0;
+   fxMesa->sScale1 = fxMesa->tScale1 = 1.0;
+
+   fxMesa->TexPalette.Type = 0;
+   fxMesa->TexPalette.Data = NULL;
+
+   for ( i = 0 ; i < TDFX_NUM_TMU ; i++ ) {
+      fxMesa->TexSource[i].StartAddress        = 0;
+      fxMesa->TexSource[i].EvenOdd     = GR_MIPMAPLEVELMASK_EVEN;
+      fxMesa->TexSource[i].Info                = NULL;
+
+      fxMesa->TexCombine[i].FunctionRGB                = 0;
+      fxMesa->TexCombine[i].FactorRGB          = 0;
+      fxMesa->TexCombine[i].FunctionAlpha      = 0;
+      fxMesa->TexCombine[i].FactorAlpha                = 0;
+      fxMesa->TexCombine[i].InvertRGB          = FXFALSE;
+      fxMesa->TexCombine[i].InvertAlpha                = FXFALSE;
+
+      fxMesa->TexCombineExt[i].Alpha.SourceA   = 0;
+      /* XXX more state to init here */
+      fxMesa->TexCombineExt[i].Color.SourceA   = 0;
+      fxMesa->TexCombineExt[i].EnvColor        = 0x0;
+
+      fxMesa->TexParams[i].sClamp      = GR_TEXTURECLAMP_WRAP;
+      fxMesa->TexParams[i].tClamp      = GR_TEXTURECLAMP_WRAP;
+      fxMesa->TexParams[i].minFilt     = GR_TEXTUREFILTER_POINT_SAMPLED;
+      fxMesa->TexParams[i].magFilt     = GR_TEXTUREFILTER_BILINEAR;
+      fxMesa->TexParams[i].mmMode      = GR_MIPMAP_DISABLE;
+      fxMesa->TexParams[i].LODblend    = FXFALSE;
+      fxMesa->TexParams[i].LodBias     = 0.0;
+
+      fxMesa->TexState.EnvMode[i]      = ~0;
+      fxMesa->TexState.TexFormat[i]    = ~0;
+      fxMesa->TexState.Enabled[i]      = 0;
+   }
+
+   if ( ctx->Visual.doubleBufferMode) {
+      fxMesa->DrawBuffer               = GR_BUFFER_BACKBUFFER;
+      fxMesa->ReadBuffer               = GR_BUFFER_BACKBUFFER;
+   } else {
+      fxMesa->DrawBuffer               = GR_BUFFER_FRONTBUFFER;
+      fxMesa->ReadBuffer               = GR_BUFFER_FRONTBUFFER;
+   }
+
+   fxMesa->Color.ClearColor            = 0x00000000;
+   fxMesa->Color.ClearAlpha            = 0x00;
+   fxMesa->Color.ColorMask[RCOMP]      = FXTRUE;
+   fxMesa->Color.ColorMask[BCOMP]      = FXTRUE;
+   fxMesa->Color.ColorMask[GCOMP]      = FXTRUE;
+   fxMesa->Color.ColorMask[ACOMP]      = FXTRUE;
+   fxMesa->Color.MonoColor             = 0xffffffff;
+
+   fxMesa->Color.AlphaFunc             = GR_CMP_ALWAYS;
+   fxMesa->Color.AlphaRef              = 0x00;
+   fxMesa->Color.BlendSrcRGB           = GR_BLEND_ONE;
+   fxMesa->Color.BlendDstRGB           = GR_BLEND_ZERO;
+   fxMesa->Color.BlendSrcA             = GR_BLEND_ONE;
+   fxMesa->Color.BlendSrcA             = GR_BLEND_ZERO;
+
+   fxMesa->Color.Dither                        = GR_DITHER_2x2;
+
+   if ( fxMesa->glCtx->Visual.depthBits > 0 ) {
+      fxMesa->Depth.Mode               = GR_DEPTHBUFFER_ZBUFFER;
+   } else {
+      fxMesa->Depth.Mode               = GR_DEPTHBUFFER_DISABLE;
+   }
+   fxMesa->Depth.Bias                  = 0;
+   fxMesa->Depth.Func                  = GR_CMP_LESS;
+   fxMesa->Depth.Clear                 = 0; /* computed later */
+   fxMesa->Depth.Mask                  = FXTRUE;
+
+
+   fxMesa->Fog.Mode                    = GR_FOG_DISABLE;
+   fxMesa->Fog.Color                   = 0x00000000;
+   fxMesa->Fog.Table                   = NULL;
+   fxMesa->Fog.Density                 = 1.0;
+   fxMesa->Fog.Near                    = 1.0;
+   fxMesa->Fog.Far                     = 1.0;
+
+   fxMesa->Stencil.Function            = GR_CMP_ALWAYS;
+   fxMesa->Stencil.RefValue            = 0;
+   fxMesa->Stencil.ValueMask           = 0xff;
+   fxMesa->Stencil.WriteMask           = 0xff;
+   fxMesa->Stencil.FailFunc            = 0;
+   fxMesa->Stencil.ZFailFunc           = 0;
+   fxMesa->Stencil.ZPassFunc           = 0;
+   fxMesa->Stencil.Clear               = 0;
+
+   fxMesa->Stipple.Mode                 = GR_STIPPLE_DISABLE;
+   fxMesa->Stipple.Pattern              = 0xffffffff;
+
+   fxMesa->Scissor.minX                        = 0;
+   fxMesa->Scissor.minY                        = 0;
+   fxMesa->Scissor.maxX                        = 0;
+   fxMesa->Scissor.maxY                        = 0;
+
+   fxMesa->Viewport.Mode               = GR_WINDOW_COORDS;
+   fxMesa->Viewport.X                  = 0;
+   fxMesa->Viewport.Y                  = 0;
+   fxMesa->Viewport.Width              = 0;
+   fxMesa->Viewport.Height             = 0;
+   fxMesa->Viewport.Near               = 0.0;
+   fxMesa->Viewport.Far                        = 0.0;
+
+   fxMesa->CullMode                    = GR_CULL_DISABLE;
+
+   fxMesa->Glide.ColorFormat           = GR_COLORFORMAT_ABGR;
+   fxMesa->Glide.Origin                        = GR_ORIGIN_LOWER_LEFT;
+   fxMesa->Glide.Initialized           = FXFALSE;
+}
+
+
+
+void tdfxDDInitStateFuncs( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   ctx->Driver.UpdateState             = tdfxDDInvalidateState;
+
+
+   /* State notification callbacks:
+    */
+   ctx->Driver.ClearIndex              = NULL;
+   ctx->Driver.ClearColor              = tdfxDDClearColor;
+   ctx->Driver.DrawBuffer              = tdfxDDDrawBuffer;
+   ctx->Driver.ReadBuffer              = tdfxDDReadBuffer;
+
+   ctx->Driver.IndexMask               = NULL;
+   ctx->Driver.ColorMask               = tdfxDDColorMask;
+
+   ctx->Driver.AlphaFunc               = tdfxDDAlphaFunc;
+   ctx->Driver.BlendEquation           = tdfxDDBlendEquation;
+   ctx->Driver.BlendFunc               = tdfxDDBlendFunc;
+   ctx->Driver.BlendFuncSeparate       = tdfxDDBlendFuncSeparate;
+   ctx->Driver.ClearDepth              = tdfxDDClearDepth;
+   ctx->Driver.ClearStencil            = NULL;
+   ctx->Driver.CullFace                        = tdfxDDCullFace;
+   ctx->Driver.FrontFace               = tdfxDDFrontFace;
+   ctx->Driver.DepthFunc               = tdfxDDDepthFunc;
+   ctx->Driver.DepthMask               = tdfxDDDepthMask;
+   ctx->Driver.DepthRange              = tdfxDDDepthRange;
+   ctx->Driver.Enable                  = tdfxDDEnable;
+   ctx->Driver.Fogfv                   = tdfxDDFogfv;
+   ctx->Driver.Hint                    = NULL;
+   ctx->Driver.Lightfv                 = NULL;
+   ctx->Driver.LightModelfv            = tdfxDDLightModelfv;
+   ctx->Driver.LineStipple             = NULL;
+   ctx->Driver.LineWidth               = tdfxDDLineWidth;
+   ctx->Driver.PolygonStipple          = tdfxDDPolygonStipple;
+   ctx->Driver.RenderMode               = tdfxDDRenderMode;
+   ctx->Driver.Scissor                 = tdfxDDScissor;
+   ctx->Driver.ShadeModel              = tdfxDDShadeModel;
+
+   ctx->Driver.BindTexture             = tdfxDDBindTexture;
+   ctx->Driver.DeleteTexture           = tdfxDDDeleteTexture;
+   ctx->Driver.TexEnv                  = tdfxDDTexEnv;
+   ctx->Driver.TexParameter            = tdfxDDTexParameter;
+   ctx->Driver.ChooseTextureFormat      = tdfxDDChooseTextureFormat;
+   ctx->Driver.TexImage2D              = tdfxDDTexImage2D;
+   ctx->Driver.TexSubImage2D           = tdfxDDTexSubImage2D;
+   /*
+   ctx->Driver.TexImage2D               = _mesa_store_teximage2d;
+   ctx->Driver.TexSubImage2D            = _mesa_store_texsubimage2d;
+   */
+
+   ctx->Driver.TexImage1D               = _mesa_store_teximage1d;
+   ctx->Driver.TexImage3D               = _mesa_store_teximage3d;
+   ctx->Driver.TexSubImage1D            = _mesa_store_texsubimage1d;
+   ctx->Driver.TexSubImage3D            = _mesa_store_texsubimage3d;
+   ctx->Driver.CopyTexImage1D           = _swrast_copy_teximage1d;
+   ctx->Driver.CopyTexImage2D           = _swrast_copy_teximage2d;
+   ctx->Driver.CopyTexSubImage1D        = _swrast_copy_texsubimage1d;
+   ctx->Driver.CopyTexSubImage2D        = _swrast_copy_texsubimage2d;
+   ctx->Driver.CopyTexSubImage3D        = _swrast_copy_texsubimage3d;
+   ctx->Driver.TestProxyTexImage        = _mesa_test_proxy_teximage;
+
+/*     ctx->Driver.GetTexImage         = tdfxDDGetTexImage; */
+   ctx->Driver.UpdateTexturePalette    = tdfxDDTexturePalette;
+
+   if ( fxMesa->haveHwStencil ) {
+      ctx->Driver.StencilFunc          = tdfxDDStencilFunc;
+      ctx->Driver.StencilMask          = tdfxDDStencilMask;
+      ctx->Driver.StencilOp            = tdfxDDStencilOp;
+   } else {
+      ctx->Driver.StencilFunc          = NULL;
+      ctx->Driver.StencilMask          = NULL;
+      ctx->Driver.StencilOp            = NULL;
+   }
+
+   ctx->Driver.Viewport                        = tdfxDDViewport;
+
+
+   /* Swrast hooks for imaging extensions:
+    */
+   ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
+   ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
+   ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
+   ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_state.h b/src/mesa/drivers/dri/tdfx/tdfx_state.h
new file mode 100644 (file)
index 0000000..5e59a16
--- /dev/null
@@ -0,0 +1,64 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_state.h,v 1.2 2002/02/22 21:45:04 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_STATE_H__
+#define __TDFX_STATE_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "context.h"
+#include "tdfx_context.h"
+
+extern void tdfxDDInitStateFuncs( GLcontext *ctx );
+
+extern void tdfxDDUpdateHwState( GLcontext *ctx );
+
+extern void tdfxInitState( tdfxContextPtr fxMesa );
+
+extern void tdfxUpdateClipping( GLcontext *ctx );
+
+
+extern void tdfxFallback( GLcontext *ctx, GLuint bit, GLboolean mode );
+#define FALLBACK( rmesa, bit, mode ) tdfxFallback( rmesa->glCtx, bit, mode )
+
+extern void tdfxUpdateCull( GLcontext *ctx );
+extern void tdfxUpdateStipple( GLcontext *ctx );
+extern void tdfxUpdateViewport( GLcontext *ctx );
+
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_tex.c b/src/mesa/drivers/dri/tdfx/tdfx_tex.c
new file mode 100644 (file)
index 0000000..bffee96
--- /dev/null
@@ -0,0 +1,1473 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_tex.c,v 1.7 2002/11/05 17:46:10 tsi Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#include "image.h"
+#include "texutil.h"
+#include "texformat.h"
+#include "teximage.h"
+#include "texstore.h"
+#include "tdfx_context.h"
+#include "tdfx_tex.h"
+#include "tdfx_texman.h"
+
+
+
+static int
+logbase2(int n)
+{
+    GLint i = 1;
+    GLint log2 = 0;
+
+    if (n < 0) {
+        return -1;
+    }
+
+    while (n > i) {
+        i *= 2;
+        log2++;
+    }
+    if (i != n) {
+        return -1;
+    }
+    else {
+        return log2;
+    }
+}
+
+
+/*
+ * Compute various texture image parameters.
+ * Input:  w, h - source texture width and height
+ * Output:  lodlevel - Glide lod level token for the larger texture dimension
+ *          aspectratio - Glide aspect ratio token
+ *          sscale - S scale factor used during triangle setup
+ *          tscale - T scale factor used during triangle setup
+ *          wscale - OpenGL -> Glide image width scale factor
+ *          hscale - OpenGL -> Glide image height scale factor
+ *
+ * Sample results:
+ *      w    h       lodlevel               aspectRatio
+ *     128  128  GR_LOD_LOG2_128 (=7)  GR_ASPECT_LOG2_1x1 (=0)
+ *      64   64  GR_LOD_LOG2_64 (=6)   GR_ASPECT_LOG2_1x1 (=0)
+ *      64   32  GR_LOD_LOG2_64 (=6)   GR_ASPECT_LOG2_2x1 (=1)
+ *      32   64  GR_LOD_LOG2_64 (=6)   GR_ASPECT_LOG2_1x2 (=-1)
+ *      32   32  GR_LOD_LOG2_32 (=5)   GR_ASPECT_LOG2_1x1 (=0)
+ */
+static void
+tdfxTexGetInfo(const GLcontext *ctx, int w, int h,
+               GrLOD_t *lodlevel, GrAspectRatio_t *aspectratio,
+               float *sscale, float *tscale,
+               int *wscale, int *hscale)
+{
+    int logw, logh, ar, lod, ws, hs;
+    float s, t;
+
+    ASSERT(w >= 1);
+    ASSERT(h >= 1);
+
+    logw = logbase2(w);
+    logh = logbase2(h);
+    ar = logw - logh;  /* aspect ratio = difference in log dimensions */
+
+    /* Hardware only allows a maximum aspect ratio of 8x1, so handle
+       |ar| > 3 by scaling the image and using an 8x1 aspect ratio */
+    if (ar >= 0) {
+        ASSERT(width >= height);
+        lod = logw;
+        s = 256.0;
+        ws = 1;
+        if (ar <= GR_ASPECT_LOG2_8x1) {
+            t = 256 >> ar;
+            hs = 1;
+        }
+        else {
+            /* have to stretch image height */
+            t = 32.0;
+            hs = 1 << (ar - 3);
+        }
+    }
+    else {
+        ASSERT(width < height);
+        lod = logh;
+        t = 256.0;
+        hs = 1;
+        if (ar >= GR_ASPECT_LOG2_1x8) {
+            s = 256 >> -ar;
+            ws = 1;
+        }
+        else {
+            /* have to stretch image width */
+            s = 32.0;
+            ws = 1 << (-ar - 3);
+        }
+    }
+
+    if (ar < GR_ASPECT_LOG2_1x8)
+        ar = GR_ASPECT_LOG2_1x8;
+    else if (ar > GR_ASPECT_LOG2_8x1)
+        ar = GR_ASPECT_LOG2_8x1;
+
+    if (lodlevel)
+        *lodlevel = (GrLOD_t) lod;
+    if (aspectratio)
+        *aspectratio = (GrAspectRatio_t) ar;
+    if (sscale)
+        *sscale = s;
+    if (tscale)
+        *tscale = t;
+    if (wscale)
+        *wscale = ws;
+    if (hscale)
+        *hscale = hs;
+}
+
+
+/*
+ * We need to call this when a texture object's minification filter
+ * or texture image sizes change.
+ */
+static void RevalidateTexture(GLcontext *ctx, struct gl_texture_object *tObj)
+{
+    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+    GLint minl, maxl;
+
+    if (!ti)
+       return;
+
+    minl = maxl = tObj->BaseLevel;
+
+    if (tObj->Image[minl]) {
+       maxl = MIN2(tObj->MaxLevel, tObj->Image[minl]->MaxLog2);
+
+       /* compute largeLodLog2, aspect ratio and texcoord scale factors */
+       tdfxTexGetInfo(ctx, tObj->Image[minl]->Width, tObj->Image[minl]->Height,
+                      &ti->info.largeLodLog2,
+                      &ti->info.aspectRatioLog2,
+                      &(ti->sScale), &(ti->tScale), NULL, NULL);
+    }
+
+    if (tObj->Image[maxl] && (tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR)) {
+        /* mipmapping: need to compute smallLodLog2 */
+        tdfxTexGetInfo(ctx, tObj->Image[maxl]->Width,
+                       tObj->Image[maxl]->Height,
+                       &ti->info.smallLodLog2, NULL,
+                       NULL, NULL, NULL, NULL);
+    }
+    else {
+        /* not mipmapping: smallLodLog2 = largeLodLog2 */
+        ti->info.smallLodLog2 = ti->info.largeLodLog2;
+        maxl = minl;
+    }
+
+    ti->minLevel = minl;
+    ti->maxLevel = maxl;
+    ti->info.data = NULL;
+}
+
+
+static tdfxTexInfo *
+fxAllocTexObjData(tdfxContextPtr fxMesa)
+{
+    tdfxTexInfo *ti;
+
+    if (!(ti = CALLOC(sizeof(tdfxTexInfo)))) {
+        _mesa_problem(NULL, "tdfx driver: out of memory");
+        return NULL;
+    }
+
+    ti->isInTM = GL_FALSE;
+
+    ti->whichTMU = TDFX_TMU_NONE;
+
+    ti->tm[TDFX_TMU0] = NULL;
+    ti->tm[TDFX_TMU1] = NULL;
+
+    ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
+    ti->magFilt = GR_TEXTUREFILTER_BILINEAR;
+
+    ti->sClamp = GR_TEXTURECLAMP_WRAP;
+    ti->tClamp = GR_TEXTURECLAMP_WRAP;
+
+    ti->mmMode = GR_MIPMAP_NEAREST;
+    ti->LODblend = FXFALSE;
+
+    return ti;
+}
+
+
+/*
+ * Called via glBindTexture.
+ */
+
+void
+tdfxDDBindTexture(GLcontext * ctx, GLenum target,
+                  struct gl_texture_object *tObj)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    tdfxTexInfo *ti;
+
+    if (MESA_VERBOSE & VERBOSE_DRIVER) {
+        fprintf(stderr, "fxmesa: fxDDTexBind(%d,%p)\n", tObj->Name,
+                tObj->DriverData);
+    }
+
+    if (target != GL_TEXTURE_2D)
+        return;
+
+    if (!tObj->DriverData) {
+        tObj->DriverData = fxAllocTexObjData(fxMesa);
+    }
+
+    ti = TDFX_TEXTURE_DATA(tObj);
+    ti->lastTimeUsed = fxMesa->texBindNumber++;
+
+    fxMesa->new_state |= TDFX_NEW_TEXTURE;
+}
+
+
+/*
+ * Called via glTexEnv.
+ */
+void
+tdfxDDTexEnv(GLcontext * ctx, GLenum target, GLenum pname,
+             const GLfloat * param)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+    if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
+        if (param)
+            fprintf(stderr, "fxmesa: texenv(%x,%x)\n", pname,
+                    (GLint) (*param));
+        else
+            fprintf(stderr, "fxmesa: texenv(%x)\n", pname);
+    }
+
+    /* XXX this is a bit of a hack to force the Glide texture
+     * state to be updated.
+     */
+    fxMesa->TexState.EnvMode[ctx->Texture.CurrentUnit]  = 0;
+
+    fxMesa->new_state |= TDFX_NEW_TEXTURE;
+}
+
+
+/*
+ * Called via glTexParameter.
+ */
+void
+tdfxDDTexParameter(GLcontext * ctx, GLenum target,
+                   struct gl_texture_object *tObj,
+                   GLenum pname, const GLfloat * params)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    GLenum param = (GLenum) (GLint) params[0];
+    tdfxTexInfo *ti;
+
+    if (MESA_VERBOSE & VERBOSE_DRIVER) {
+        fprintf(stderr, "fxmesa: fxDDTexParam(%d,%p,%x,%x)\n", tObj->Name,
+                tObj->DriverData, pname, param);
+    }
+
+    if (target != GL_TEXTURE_2D)
+        return;
+
+    if (!tObj->DriverData)
+        tObj->DriverData = fxAllocTexObjData(fxMesa);
+
+    ti = TDFX_TEXTURE_DATA(tObj);
+
+    switch (pname) {
+    case GL_TEXTURE_MIN_FILTER:
+        switch (param) {
+        case GL_NEAREST:
+            ti->mmMode = GR_MIPMAP_DISABLE;
+            ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
+            ti->LODblend = FXFALSE;
+            break;
+        case GL_LINEAR:
+            ti->mmMode = GR_MIPMAP_DISABLE;
+            ti->minFilt = GR_TEXTUREFILTER_BILINEAR;
+            ti->LODblend = FXFALSE;
+            break;
+        case GL_NEAREST_MIPMAP_LINEAR:
+            if (TDFX_IS_NAPALM(fxMesa)) {
+                 if (fxMesa->haveTwoTMUs) {
+                     ti->mmMode = GR_MIPMAP_NEAREST;
+                     ti->LODblend = FXTRUE;
+                 }
+                 else {
+                     ti->mmMode = GR_MIPMAP_NEAREST_DITHER;
+                     ti->LODblend = FXFALSE;
+                 }
+                 ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
+                 break;
+            }
+            /* XXX Voodoo3/Banshee mipmap blending seems to produce
+             * incorrectly filtered colors for the smallest mipmap levels.
+             * To work-around we fall-through here and use a different filter.
+             */
+        case GL_NEAREST_MIPMAP_NEAREST:
+            ti->mmMode = GR_MIPMAP_NEAREST;
+            ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
+            ti->LODblend = FXFALSE;
+            break;
+        case GL_LINEAR_MIPMAP_LINEAR:
+            if (TDFX_IS_NAPALM(fxMesa)) {
+                if (fxMesa->haveTwoTMUs) {
+                    ti->mmMode = GR_MIPMAP_NEAREST;
+                    ti->LODblend = FXTRUE;
+                }
+                else {
+                    ti->mmMode = GR_MIPMAP_NEAREST_DITHER;
+                    ti->LODblend = FXFALSE;
+                }
+                ti->minFilt = GR_TEXTUREFILTER_BILINEAR;
+                break;
+            }
+            /* XXX Voodoo3/Banshee mipmap blending seems to produce
+             * incorrectly filtered colors for the smallest mipmap levels.
+             * To work-around we fall-through here and use a different filter.
+             */
+        case GL_LINEAR_MIPMAP_NEAREST:
+            ti->mmMode = GR_MIPMAP_NEAREST;
+            ti->minFilt = GR_TEXTUREFILTER_BILINEAR;
+            ti->LODblend = FXFALSE;
+            break;
+        default:
+            break;
+        }
+        RevalidateTexture(ctx, tObj);
+        fxMesa->new_state |= TDFX_NEW_TEXTURE;
+        break;
+
+    case GL_TEXTURE_MAG_FILTER:
+        switch (param) {
+        case GL_NEAREST:
+            ti->magFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
+            break;
+        case GL_LINEAR:
+            ti->magFilt = GR_TEXTUREFILTER_BILINEAR;
+            break;
+        default:
+            break;
+        }
+        fxMesa->new_state |= TDFX_NEW_TEXTURE;
+        break;
+
+    case GL_TEXTURE_WRAP_S:
+        switch (param) {
+        case GL_CLAMP:
+            ti->sClamp = GR_TEXTURECLAMP_CLAMP;
+            break;
+        case GL_REPEAT:
+            ti->sClamp = GR_TEXTURECLAMP_WRAP;
+            break;
+        default:
+            break;
+        }
+        fxMesa->new_state |= TDFX_NEW_TEXTURE;
+        break;
+
+    case GL_TEXTURE_WRAP_T:
+        switch (param) {
+        case GL_CLAMP:
+            ti->tClamp = GR_TEXTURECLAMP_CLAMP;
+            break;
+        case GL_REPEAT:
+            ti->tClamp = GR_TEXTURECLAMP_WRAP;
+            break;
+        default:
+            break;
+        }
+        fxMesa->new_state |= TDFX_NEW_TEXTURE;
+        break;
+
+    case GL_TEXTURE_BORDER_COLOR:
+        /* TO DO */
+        break;
+    case GL_TEXTURE_MIN_LOD:
+        /* TO DO */
+        break;
+    case GL_TEXTURE_MAX_LOD:
+        /* TO DO */
+        break;
+    case GL_TEXTURE_BASE_LEVEL:
+        RevalidateTexture(ctx, tObj);
+        break;
+    case GL_TEXTURE_MAX_LEVEL:
+        RevalidateTexture(ctx, tObj);
+        break;
+
+    default:
+        break;
+    }
+}
+
+
+/*
+ * Called via glDeleteTextures to delete a texture object.
+ * Here, we delete the Glide data associated with the texture.
+ */
+void
+tdfxDDDeleteTexture(GLcontext * ctx, struct gl_texture_object *tObj)
+{
+    if (ctx && ctx->DriverCtx) {
+        tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+        tdfxTMFreeTexture(fxMesa, tObj);
+        fxMesa->new_state |= TDFX_NEW_TEXTURE;
+    }
+}
+
+
+/*
+ * Return true if texture is resident, false otherwise.
+ */
+GLboolean
+tdfxDDIsTextureResident(GLcontext *ctx, struct gl_texture_object *tObj)
+{
+    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+    return (GLboolean) (ti && ti->isInTM);
+}
+
+
+
+/*
+ * Convert a gl_color_table texture palette to Glide's format.
+ */
+static void
+convertPalette(FxU32 data[256], const struct gl_color_table *table)
+{
+    const GLubyte *tableUB = (const GLubyte *) table->Table;
+    GLint width = table->Size;
+    FxU32 r, g, b, a;
+    GLint i;
+
+    ASSERT(table->TableType == GL_UNSIGNED_BYTE);
+
+    switch (table->Format) {
+    case GL_INTENSITY:
+        for (i = 0; i < width; i++) {
+            r = tableUB[i];
+            g = tableUB[i];
+            b = tableUB[i];
+            a = tableUB[i];
+            data[i] = (a << 24) | (r << 16) | (g << 8) | b;
+        }
+        break;
+    case GL_LUMINANCE:
+        for (i = 0; i < width; i++) {
+            r = tableUB[i];
+            g = tableUB[i];
+            b = tableUB[i];
+            a = 255;
+            data[i] = (a << 24) | (r << 16) | (g << 8) | b;
+        }
+        break;
+    case GL_ALPHA:
+        for (i = 0; i < width; i++) {
+            r = g = b = 255;
+            a = tableUB[i];
+            data[i] = (a << 24) | (r << 16) | (g << 8) | b;
+        }
+        break;
+    case GL_LUMINANCE_ALPHA:
+        for (i = 0; i < width; i++) {
+            r = g = b = tableUB[i * 2 + 0];
+            a = tableUB[i * 2 + 1];
+            data[i] = (a << 24) | (r << 16) | (g << 8) | b;
+        }
+        break;
+    case GL_RGB:
+        for (i = 0; i < width; i++) {
+            r = tableUB[i * 3 + 0];
+            g = tableUB[i * 3 + 1];
+            b = tableUB[i * 3 + 2];
+            a = 255;
+            data[i] = (a << 24) | (r << 16) | (g << 8) | b;
+        }
+        break;
+    case GL_RGBA:
+        for (i = 0; i < width; i++) {
+            r = tableUB[i * 4 + 0];
+            g = tableUB[i * 4 + 1];
+            b = tableUB[i * 4 + 2];
+            a = tableUB[i * 4 + 3];
+            data[i] = (a << 24) | (r << 16) | (g << 8) | b;
+        }
+        break;
+    }
+}
+
+
+
+void
+tdfxDDTexturePalette(GLcontext * ctx, struct gl_texture_object *tObj)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+    if (tObj) {
+        /* per-texture palette */
+        tdfxTexInfo *ti;
+        
+        /* This might be a proxy texture. */
+        if (!tObj->Palette.Table)
+            return;
+            
+        if (!tObj->DriverData)
+            tObj->DriverData = fxAllocTexObjData(fxMesa);
+        ti = TDFX_TEXTURE_DATA(tObj);
+        convertPalette(ti->palette.data, &tObj->Palette);
+        /*tdfxTexInvalidate(ctx, tObj);*/
+    }
+    else {
+        /* global texture palette */
+        convertPalette(fxMesa->glbPalette.data, &ctx->Texture.Palette);
+    }
+    fxMesa->new_state |= TDFX_NEW_TEXTURE; /* XXX too heavy-handed */
+}
+
+
+/**********************************************************************/
+/**** NEW TEXTURE IMAGE FUNCTIONS                                  ****/
+/**********************************************************************/
+
+#if 000
+static FxBool TexusFatalError = FXFALSE;
+static FxBool TexusError = FXFALSE;
+
+#define TX_DITHER_NONE                                  0x00000000
+
+static void
+fxTexusError(const char *string, FxBool fatal)
+{
+    _mesa_problem(NULL, string);
+   /*
+    * Just propagate the fatal value up.
+    */
+    TexusError = FXTRUE;
+    TexusFatalError = fatal;
+}
+#endif
+
+
+const struct gl_texture_format *
+tdfxDDChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+                           GLenum srcFormat, GLenum srcType )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   const GLboolean allow32bpt = TDFX_IS_NAPALM(fxMesa);
+
+   switch (internalFormat) {
+   case GL_ALPHA:
+   case GL_ALPHA4:
+   case GL_ALPHA8:
+   case GL_ALPHA12:
+   case GL_ALPHA16:
+      return &_mesa_texformat_a8;
+   case 1:
+   case GL_LUMINANCE:
+   case GL_LUMINANCE4:
+   case GL_LUMINANCE8:
+   case GL_LUMINANCE12:
+   case GL_LUMINANCE16:
+      return &_mesa_texformat_l8;
+   case 2:
+   case GL_LUMINANCE_ALPHA:
+   case GL_LUMINANCE4_ALPHA4:
+   case GL_LUMINANCE6_ALPHA2:
+   case GL_LUMINANCE8_ALPHA8:
+   case GL_LUMINANCE12_ALPHA4:
+   case GL_LUMINANCE12_ALPHA12:
+   case GL_LUMINANCE16_ALPHA16:
+      return &_mesa_texformat_al88;
+   case GL_INTENSITY:
+   case GL_INTENSITY4:
+   case GL_INTENSITY8:
+   case GL_INTENSITY12:
+   case GL_INTENSITY16:
+      return &_mesa_texformat_i8;
+   case GL_R3_G3_B2:
+   case GL_RGB4:
+   case GL_RGB5:
+      return &_mesa_texformat_rgb565;
+   case 3:
+   case GL_RGB:
+   case GL_RGB8:
+   case GL_RGB10:
+   case GL_RGB12:
+   case GL_RGB16:
+      return (allow32bpt) ? &_mesa_texformat_argb8888
+                          : &_mesa_texformat_rgb565;
+      break;
+   case GL_RGBA2:
+   case GL_RGBA4:
+      return &_mesa_texformat_argb4444;
+   case 4:
+   case GL_RGBA:
+   case GL_RGBA8:
+   case GL_RGB10_A2:
+   case GL_RGBA12:
+   case GL_RGBA16:
+      return allow32bpt ? &_mesa_texformat_argb8888
+                        : &_mesa_texformat_argb4444;
+   case GL_RGB5_A1:
+      return &_mesa_texformat_argb1555;
+   case GL_COLOR_INDEX:
+   case GL_COLOR_INDEX1_EXT:
+   case GL_COLOR_INDEX2_EXT:
+   case GL_COLOR_INDEX4_EXT:
+   case GL_COLOR_INDEX8_EXT:
+   case GL_COLOR_INDEX12_EXT:
+   case GL_COLOR_INDEX16_EXT:
+      return &_mesa_texformat_ci8;
+   default:
+      _mesa_problem(ctx, "unexpected format in tdfxDDChooseTextureFormat");
+      return NULL;
+   }
+}
+
+
+/*
+ * Return the Glide format for the given mesa texture format.
+ */
+static GrTextureFormat_t
+fxGlideFormat(GLint mesaFormat)
+{
+   switch (mesaFormat) {
+   case MESA_FORMAT_I8:
+      return GR_TEXFMT_ALPHA_8;
+   case MESA_FORMAT_A8:
+      return GR_TEXFMT_ALPHA_8;
+   case MESA_FORMAT_L8:
+      return GR_TEXFMT_INTENSITY_8;
+   case MESA_FORMAT_CI8:
+      return GR_TEXFMT_P_8;
+   case MESA_FORMAT_AL88:
+      return GR_TEXFMT_ALPHA_INTENSITY_88;
+   case MESA_FORMAT_RGB565:
+      return GR_TEXFMT_RGB_565;
+   case MESA_FORMAT_ARGB4444:
+      return GR_TEXFMT_ARGB_4444;
+   case MESA_FORMAT_ARGB1555:
+      return GR_TEXFMT_ARGB_1555;
+   case MESA_FORMAT_ARGB8888:
+      return GR_TEXFMT_ARGB_8888;
+   default:
+      _mesa_problem(NULL, "Unexpected format in fxGlideFormat");
+      return 0;
+   }
+}
+
+
+/* Texel-fetch functions for software texturing and glGetTexImage().
+ * We should have been able to use some "standard" fetch functions (which
+ * may get defined in texutil.c) but we have to account for scaled texture
+ * images on tdfx hardware (the 8:1 aspect ratio limit).
+ * Hence, we need special functions here.
+ */
+
+static void
+fetch_intensity8(const struct gl_texture_image *texImage,
+                GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLubyte *texel;
+
+    i = i * mml->wScale;
+    j = j * mml->hScale;
+
+    texel = ((GLubyte *) texImage->Data) + j * mml->width + i;
+    rgba[RCOMP] = *texel;
+    rgba[GCOMP] = *texel;
+    rgba[BCOMP] = *texel;
+    rgba[ACOMP] = *texel;
+}
+
+
+static void
+fetch_luminance8(const struct gl_texture_image *texImage,
+                GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLubyte *texel;
+
+    i = i * mml->wScale;
+    j = j * mml->hScale;
+
+    texel = ((GLubyte *) texImage->Data) + j * mml->width + i;
+    rgba[RCOMP] = *texel;
+    rgba[GCOMP] = *texel;
+    rgba[BCOMP] = *texel;
+    rgba[ACOMP] = 255;
+}
+
+
+static void
+fetch_alpha8(const struct gl_texture_image *texImage,
+            GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLubyte *texel;
+
+    i = i * mml->wScale;
+    j = j * mml->hScale;
+    i = i * mml->width / texImage->Width;
+    j = j * mml->height / texImage->Height;
+
+    texel = ((GLubyte *) texImage->Data) + j * mml->width + i;
+    rgba[RCOMP] = 255;
+    rgba[GCOMP] = 255;
+    rgba[BCOMP] = 255;
+    rgba[ACOMP] = *texel;
+}
+
+
+static void
+fetch_index8(const struct gl_texture_image *texImage,
+            GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    (void) mml;
+   /* XXX todo */
+}
+
+
+static void
+fetch_luminance8_alpha8(const struct gl_texture_image *texImage,
+                       GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLubyte *texel;
+
+   i = i * mml->wScale;
+   j = j * mml->hScale;
+
+   texel = ((GLubyte *) texImage->Data) + (j * mml->width + i) * 2;
+   rgba[RCOMP] = texel[0];
+   rgba[GCOMP] = texel[0];
+   rgba[BCOMP] = texel[0];
+   rgba[ACOMP] = texel[1];
+}
+
+
+static void
+fetch_r5g6b5(const struct gl_texture_image *texImage,
+            GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLushort *texel;
+
+    i = i * mml->wScale;
+    j = j * mml->hScale;
+
+    texel = ((GLushort *) texImage->Data) + j * mml->width + i;
+    rgba[RCOMP] = (((*texel) >> 11) & 0x1f) * 255 / 31;
+    rgba[GCOMP] = (((*texel) >> 5) & 0x3f) * 255 / 63;
+    rgba[BCOMP] = (((*texel) >> 0) & 0x1f) * 255 / 31;
+    rgba[ACOMP] = 255;
+}
+
+
+static void
+fetch_r4g4b4a4(const struct gl_texture_image *texImage,
+              GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLushort *texel;
+
+    i = i * mml->wScale;
+    j = j * mml->hScale;
+
+    texel = ((GLushort *) texImage->Data) + j * mml->width + i;
+    rgba[RCOMP] = (((*texel) >> 12) & 0xf) * 255 / 15;
+    rgba[GCOMP] = (((*texel) >> 8) & 0xf) * 255 / 15;
+    rgba[BCOMP] = (((*texel) >> 4) & 0xf) * 255 / 15;
+    rgba[ACOMP] = (((*texel) >> 0) & 0xf) * 255 / 15;
+}
+
+
+static void
+fetch_r5g5b5a1(const struct gl_texture_image *texImage,
+              GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLushort *texel;
+
+    i = i * mml->wScale;
+    j = j * mml->hScale;
+
+    texel = ((GLushort *) texImage->Data) + j * mml->width + i;
+    rgba[RCOMP] = (((*texel) >> 11) & 0x1f) * 255 / 31;
+    rgba[GCOMP] = (((*texel) >> 6) & 0x1f) * 255 / 31;
+    rgba[BCOMP] = (((*texel) >> 1) & 0x1f) * 255 / 31;
+    rgba[ACOMP] = (((*texel) >> 0) & 0x01) * 255;
+}
+
+
+static void
+fetch_a8r8g8b8(const struct gl_texture_image *texImage,
+              GLint i, GLint j, GLint k, GLvoid * texelOut)
+{
+    GLchan *rgba = (GLchan *) texelOut;
+    const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
+    const GLuint *texel;
+
+    i = i * mml->wScale;
+    j = j * mml->hScale;
+
+    texel = ((GLuint *) texImage->Data) + j * mml->width + i;
+    rgba[RCOMP] = (((*texel) >> 16) & 0xff);
+    rgba[GCOMP] = (((*texel) >>  8) & 0xff);
+    rgba[BCOMP] = (((*texel)      ) & 0xff);
+    rgba[ACOMP] = (((*texel) >> 24) & 0xff);
+}
+
+
+static FetchTexelFunc
+fxFetchFunction(GLint mesaFormat)
+{
+   switch (mesaFormat) {
+   case MESA_FORMAT_I8:
+      return fetch_intensity8;
+   case MESA_FORMAT_A8:
+      return fetch_alpha8;
+   case MESA_FORMAT_L8:
+      return fetch_luminance8;
+   case MESA_FORMAT_CI8:
+      return fetch_index8;
+   case MESA_FORMAT_AL88:
+      return fetch_luminance8_alpha8;
+   case MESA_FORMAT_RGB565:
+      return fetch_r5g6b5;
+   case MESA_FORMAT_ARGB4444:
+      return fetch_r4g4b4a4;
+   case MESA_FORMAT_ARGB1555:
+      return fetch_r5g5b5a1;
+   case MESA_FORMAT_ARGB8888:
+      return fetch_a8r8g8b8;
+   default:
+      _mesa_problem(NULL, "Unexpected format in fxFetchFunction");
+      printf("%d\n", mesaFormat);
+      return NULL;
+   }
+}
+
+
+void
+tdfxDDTexImage2D(GLcontext *ctx, GLenum target, GLint level,
+               GLint internalFormat, GLint width, GLint height, GLint border,
+               GLenum format, GLenum type, const GLvoid *pixels,
+               const struct gl_pixelstore_attrib *packing,
+               struct gl_texture_object *texObj,
+               struct gl_texture_image *texImage)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    tdfxTexInfo *ti;
+    tdfxMipMapLevel *mml;
+    GLint texelBytes;
+
+    /*
+    printf("TexImage id=%d int 0x%x  format 0x%x  type 0x%x  %dx%d\n",
+           texObj->Name, texImage->IntFormat, format, type,
+           texImage->Width, texImage->Height);
+    */
+
+    ti = TDFX_TEXTURE_DATA(texObj);
+    if (!ti) {
+        texObj->DriverData = fxAllocTexObjData(fxMesa);
+        if (!texObj->DriverData) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+            return;
+        }
+        ti = TDFX_TEXTURE_DATA(texObj);
+    }
+
+    mml = TDFX_TEXIMAGE_DATA(texImage);
+    if (!mml) {
+        texImage->DriverData = CALLOC(sizeof(tdfxMipMapLevel));
+        if (!texImage->DriverData) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+            return;
+        }
+        mml = TDFX_TEXIMAGE_DATA(texImage);
+    }
+
+    /* Determine width and height scale factors for texture.
+     * Remember, Glide is limited to 8:1 aspect ratios.
+     */
+    tdfxTexGetInfo(ctx,
+                   texImage->Width, texImage->Height,
+                   NULL,       /* lod level          */
+                   NULL,       /* aspect ratio       */
+                   NULL, NULL, /* sscale, tscale     */
+                   &mml->wScale, &mml->hScale);
+
+    /* rescaled size: */
+    mml->width = width * mml->wScale;
+    mml->height = height * mml->hScale;
+
+
+    /* choose the texture format */
+    assert(ctx->Driver.ChooseTextureFormat);
+    texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
+                                     internalFormat, format, type);
+    assert(texImage->TexFormat);
+    mml->glideFormat = fxGlideFormat(texImage->TexFormat->MesaFormat);
+    ti->info.format = mml->glideFormat;
+    texImage->FetchTexel = fxFetchFunction(texImage->TexFormat->MesaFormat);
+    texelBytes = texImage->TexFormat->TexelBytes;
+
+    if (mml->width != width || mml->height != height) {
+        /* rescale the image to overcome 1:8 aspect limitation */
+        GLvoid *tempImage;
+        tempImage = MALLOC(width * height * texelBytes);
+        if (!tempImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+            return;
+        }
+        /* unpack image, apply transfer ops and store in tempImage */
+        _mesa_transfer_teximage(ctx, 2, texImage->Format,
+                                texImage->TexFormat,
+                                tempImage,
+                                width, height, 1, 0, 0, 0,
+                                width * texelBytes,
+                                0, /* dstImageStride */
+                                format, type, pixels, packing);
+        assert(!texImage->Data);
+        texImage->Data = MESA_PBUFFER_ALLOC(mml->width * mml->height * texelBytes);
+        if (!texImage->Data) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+            FREE(tempImage);
+            return;
+        }
+        _mesa_rescale_teximage2d(texelBytes,
+                                 mml->width * texelBytes, /* dst stride */
+                                 width, height,
+                                 mml->width, mml->height,
+                                 tempImage /*src*/, texImage->Data /*dst*/ );
+        FREE(tempImage);
+    }
+    else {
+        /* no rescaling needed */
+      assert(!texImage->Data);
+      texImage->Data = MESA_PBUFFER_ALLOC(mml->width * mml->height * texelBytes);
+      if (!texImage->Data) {
+          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+          return;
+      }
+      /* unpack image, apply transfer ops and store in texImage->Data */
+      _mesa_transfer_teximage(ctx, 2, texImage->Format,
+                              texImage->TexFormat, texImage->Data,
+                              width, height, 1, 0, 0, 0,
+                              texImage->Width * texelBytes,
+                              0, /* dstImageStride */
+                              format, type, pixels, packing);
+    }
+
+    RevalidateTexture(ctx, texObj);
+
+    ti->reloadImages = GL_TRUE;
+    fxMesa->new_state |= TDFX_NEW_TEXTURE;
+}
+
+
+void
+tdfxDDTexSubImage2D(GLcontext *ctx, GLenum target, GLint level,
+                    GLint xoffset, GLint yoffset,
+                    GLsizei width, GLsizei height,
+                    GLenum format, GLenum type,
+                    const GLvoid *pixels,
+                    const struct gl_pixelstore_attrib *packing,
+                    struct gl_texture_object *texObj,
+                    struct gl_texture_image *texImage )
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    tdfxTexInfo *ti;
+    tdfxMipMapLevel *mml;
+    GLint texelBytes;
+
+    if (!texObj->DriverData) {
+        _mesa_problem(ctx, "problem in fxDDTexSubImage2D");
+        return;
+    }
+
+    ti = TDFX_TEXTURE_DATA(texObj);
+    assert(ti);
+    mml = TDFX_TEXIMAGE_DATA(texImage);
+    assert(mml);
+
+    assert(texImage->Data);    /* must have an existing texture image! */
+    assert(texImage->Format);
+
+    texelBytes = texImage->TexFormat->TexelBytes;
+
+    if (mml->wScale != 1 || mml->hScale != 1) {
+        /* need to rescale subimage to match mipmap level's rescale factors */
+        const GLint newWidth = width * mml->wScale;
+        const GLint newHeight = height * mml->hScale;
+        GLvoid *scaledImage, *tempImage;
+        GLubyte *destAddr;
+        tempImage = MALLOC(width * height * texelBytes);
+        if (!tempImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
+            return;
+        }
+
+        _mesa_transfer_teximage(ctx, 2, texImage->Format,/* Tex int format */
+                                texImage->TexFormat,     /* dest format */
+                                (GLubyte *) tempImage,   /* dest */
+                                width, height, 1,        /* subimage size */
+                                0, 0, 0,                 /* subimage pos */
+                                width * texelBytes,      /* dest row stride */
+                                0,                       /* dst image stride */
+                                format, type, pixels, packing);
+
+        /* now rescale */
+        scaledImage = MALLOC(newWidth * newHeight * texelBytes);
+        if (!scaledImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
+            FREE(tempImage);
+            return;
+        }
+
+        /* compute address of dest subimage within the overal tex image */
+        destAddr = (GLubyte *) texImage->Data
+            + (yoffset * mml->hScale * mml->width
+               + xoffset * mml->wScale) * texelBytes;
+
+        _mesa_rescale_teximage2d(texelBytes,
+                                 mml->width * texelBytes, /* dst stride */
+                                 width, height,
+                                 newWidth, newHeight,
+                                 tempImage, destAddr);
+
+        FREE(tempImage);
+        FREE(scaledImage);
+    }
+    else {
+        /* no rescaling needed */
+        _mesa_transfer_teximage(ctx, 2, texImage->Format,  /* Tex int format */
+                                texImage->TexFormat,       /* dest format */
+                                (GLubyte *) texImage->Data,/* dest */
+                                width, height, 1,          /* subimage size */
+                                xoffset, yoffset, 0,       /* subimage pos */
+                                mml->width * texelBytes, /* dest row stride */
+                                0,                       /* dst image stride */
+                                format, type, pixels, packing);
+    }
+
+    ti->reloadImages = GL_TRUE; /* signal the image needs to be reloaded */
+    fxMesa->new_state |= TDFX_NEW_TEXTURE;  /* XXX this might be a bit much */
+}
+
+
+
+/**********************************************************************/
+/**** COMPRESSED TEXTURE IMAGE FUNCTIONS                           ****/
+/**********************************************************************/
+
+#if 0000
+GLboolean
+tdfxDDCompressedTexImage2D( GLcontext *ctx, GLenum target,
+                            GLint level, GLsizei imageSize,
+                            const GLvoid *data,
+                            struct gl_texture_object *texObj,
+                            struct gl_texture_image *texImage,
+                            GLboolean *retainInternalCopy)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    const GLboolean allow32bpt = TDFX_IS_NAPALM(fxMesa);
+    GrTextureFormat_t gldformat;
+    tdfxTexInfo *ti;
+    tdfxMipMapLevel *mml;
+    GLint dstWidth, dstHeight, wScale, hScale, texelSize;
+    MesaIntTexFormat intFormat;
+    GLboolean isCompressedFormat;
+    GLsizei texSize;
+
+    if (target != GL_TEXTURE_2D || texImage->Border > 0)
+        return GL_FALSE;
+
+    if (!texObj->DriverData)
+        texObj->DriverData = fxAllocTexObjData(fxMesa);
+
+    ti = TDFX_TEXTURE_DATA(texObj);
+    mml = &ti->mipmapLevel[level];
+
+    isCompressedFormat = tdfxDDIsCompressedGlideFormatMacro(texImage->IntFormat);
+    if (!isCompressedFormat) {
+        _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage2D(format)");
+        return GL_FALSE;
+    }
+    /* Determine the apporpriate GL internal texel format, Mesa internal
+     * texel format, and texelSize (bytes) given the user's internal
+     * texture format hint.
+     */
+    tdfxTexGetFormat(texImage->IntFormat, allow32bpt,
+                     &gldformat, &intFormat, &texelSize);
+
+    /* Determine width and height scale factors for texture.
+     * Remember, Glide is limited to 8:1 aspect ratios.
+     */
+    tdfxTexGetInfo(ctx,
+                   texImage->Width, texImage->Height,
+                   NULL,       /* lod level          */
+                   NULL,       /* aspect ratio       */
+                   NULL, NULL, /* sscale, tscale     */
+                   &wScale, &hScale);
+    dstWidth = texImage->Width * wScale;
+    dstHeight = texImage->Height * hScale;
+    /* housekeeping */
+    _mesa_set_teximage_component_sizes(intFormat, texImage);
+
+    texSize = tdfxDDCompressedImageSize(ctx,
+                                        texImage->IntFormat,
+                                        2,
+                                        texImage->Width,
+                                        texImage->Height,
+                                        1);
+    if (texSize != imageSize) {
+        _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage2D(texSize)");
+        return GL_FALSE;
+    }
+
+    /* allocate new storage for texture image, if needed */
+    if (!mml->data || mml->glideFormat != gldformat ||
+        mml->width != dstWidth || mml->height != dstHeight ||
+        texSize != mml->dataSize) {
+        if (mml->data) {
+            FREE(mml->data);
+        }
+        mml->data = MALLOC(texSize);
+        if (!mml->data) {
+            return GL_FALSE;
+        }
+        mml->texelSize = texelSize;
+        mml->glideFormat = gldformat;
+        mml->width = dstWidth;
+        mml->height = dstHeight;
+        tdfxTMMoveOutTM(fxMesa, texObj);
+        /*tdfxTexInvalidate(ctx, texObj);*/
+    }
+
+    /* save the texture data */
+    MEMCPY(mml->data, data, imageSize);
+
+    RevalidateTexture(ctx, texObj);
+
+    ti->reloadImages = GL_TRUE;
+    fxMesa->new_state |= TDFX_NEW_TEXTURE;
+
+    *retainInternalCopy = GL_FALSE;
+    return GL_TRUE;
+}
+
+GLboolean
+tdfxDDCompressedTexSubImage2D( GLcontext *ctx, GLenum target,
+                               GLint level, GLint xoffset,
+                               GLint yoffset, GLsizei width,
+                               GLint height, GLenum format,
+                               GLsizei imageSize, const GLvoid *data,
+                               struct gl_texture_object *texObj,
+                               struct gl_texture_image *texImage )
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    tdfxTexInfo *ti;
+    tdfxMipMapLevel *mml;
+
+    /*
+     * We punt if we are not replacing the entire image.  This
+     * is allowed by the spec.
+     */
+    if ((xoffset != 0) && (yoffset != 0)
+        && (width != texImage->Width)
+        && (height != texImage->Height)) {
+        return GL_FALSE;
+    }
+
+    ti = TDFX_TEXTURE_DATA(texObj);
+    mml = &ti->mipmapLevel[level];
+    if (imageSize != mml->dataSize) {
+        return GL_FALSE;
+    }
+    MEMCPY(data, mml->data, imageSize);
+
+    ti->reloadImages = GL_TRUE;
+    fxMesa->new_state |= TDFX_NEW_TEXTURE;
+
+    return GL_TRUE;
+}
+#endif
+
+
+
+#if    0
+static void
+PrintTexture(int w, int h, int c, const GLubyte * data)
+{
+    int i, j;
+    for (i = 0; i < h; i++) {
+        for (j = 0; j < w; j++) {
+            if (c == 2)
+                printf("%02x %02x  ", data[0], data[1]);
+            else if (c == 3)
+                printf("%02x %02x %02x  ", data[0], data[1], data[2]);
+            data += c;
+        }
+        printf("\n");
+    }
+}
+#endif
+
+
+GLboolean
+tdfxDDTestProxyTexImage(GLcontext *ctx, GLenum target,
+                        GLint level, GLint internalFormat,
+                        GLenum format, GLenum type,
+                        GLint width, GLint height,
+                        GLint depth, GLint border)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+
+    switch (target) {
+    case GL_PROXY_TEXTURE_1D:
+        return GL_TRUE;  /* software rendering */
+    case GL_PROXY_TEXTURE_2D:
+        {
+            struct gl_texture_object *tObj;
+            tdfxTexInfo *ti;
+            int memNeeded;
+
+            tObj = ctx->Texture.Proxy2D;
+            if (!tObj->DriverData)
+                tObj->DriverData = fxAllocTexObjData(fxMesa);
+            ti = TDFX_TEXTURE_DATA(tObj);
+
+            /* assign the parameters to test against */
+            tObj->Image[level]->Width = width;
+            tObj->Image[level]->Height = height;
+            tObj->Image[level]->Border = border;
+#if 0
+            tObj->Image[level]->IntFormat = internalFormat;
+#endif
+            if (level == 0) {
+               /* don't use mipmap levels > 0 */
+               tObj->MinFilter = tObj->MagFilter = GL_NEAREST;
+            }
+            else {
+               /* test with all mipmap levels */
+               tObj->MinFilter = GL_LINEAR_MIPMAP_LINEAR;
+               tObj->MagFilter = GL_NEAREST;
+            }
+            RevalidateTexture(ctx, tObj);
+
+            /*
+            printf("small lodlog2 0x%x\n", ti->info.smallLodLog2);
+            printf("large lodlog2 0x%x\n", ti->info.largeLodLog2);
+            printf("aspect ratio 0x%x\n", ti->info.aspectRatioLog2);
+            printf("glide format 0x%x\n", ti->info.format);
+            printf("data %p\n", ti->info.data);
+            printf("lodblend %d\n", (int) ti->LODblend);
+            */
+
+            /* determine where texture will reside */
+            if (ti->LODblend && !shared->umaTexMemory) {
+                /* XXX GR_MIPMAPLEVELMASK_BOTH might not be right, but works */
+                memNeeded = fxMesa->Glide.grTexTextureMemRequired(
+                                        GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
+            }
+            else {
+                /* XXX GR_MIPMAPLEVELMASK_BOTH might not be right, but works */
+                memNeeded = fxMesa->Glide.grTexTextureMemRequired(
+                                        GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
+            }
+            /*
+            printf("Proxy test %d > %d\n", memNeeded, shared->totalTexMem[0]);
+            */
+            if (memNeeded > shared->totalTexMem[0])
+                return GL_FALSE;
+            else
+                return GL_TRUE;
+        }
+    case GL_PROXY_TEXTURE_3D:
+        return GL_TRUE;  /* software rendering */
+    default:
+        return GL_TRUE;  /* never happens, silence compiler */
+    }
+}
+
+
+#if 000
+/*
+ * This is called from _mesa_GetCompressedTexImage.  We just
+ * copy out the compressed data.
+ */
+void
+tdfxDDGetCompressedTexImage( GLcontext *ctx, GLenum target,
+                             GLint lod, void *image,
+                             const struct gl_texture_object *texObj,
+                             struct gl_texture_image *texImage )
+{
+    tdfxTexInfo *ti;
+    tdfxMipMapLevel *mml;
+
+    if (target != GL_TEXTURE_2D)
+        return;
+
+    if (!texObj->DriverData)
+        return;
+
+    ti = TDFX_TEXTURE_DATA(texObj);
+    mml = &ti->mipmapLevel[lod];
+    if (mml->data) {
+        MEMCPY(image, mml->data, mml->dataSize);
+    }
+}
+#endif
+
+/*
+ * Calculate a specific texture format given a generic
+ * texture format.
+ */
+GLint
+tdfxDDSpecificCompressedTexFormat(GLcontext *ctx,
+                                  GLint internalFormat,
+                                  GLint numDimensions)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+    if (numDimensions != 2) {
+        return internalFormat;
+    }
+   /*
+    * If we don't have pointers to the functions, then
+    * we drop back to uncompressed format.  The logic
+    * in Mesa proper handles this for us.
+    *
+    * This is just to ease the transition to a Glide with
+    * the texus2 library.
+    */
+    if (!fxMesa->Glide.txImgQuantize || !fxMesa->Glide.txImgDequantizeFXT1) {
+        return internalFormat;
+    }
+    switch (internalFormat) {
+    case GL_COMPRESSED_RGB_ARB:
+        return GL_COMPRESSED_RGB_FXT1_3DFX;
+    case GL_COMPRESSED_RGBA_ARB:
+        return GL_COMPRESSED_RGBA_FXT1_3DFX;
+    }
+    return internalFormat;
+}
+
+/*
+ * Calculate a specific texture format given a generic
+ * texture format.
+ */
+GLint
+tdfxDDBaseCompressedTexFormat(GLcontext *ctx,
+                              GLint internalFormat)
+{
+    switch (internalFormat) {
+    case GL_COMPRESSED_RGB_FXT1_3DFX:
+        return GL_RGB;
+    case GL_COMPRESSED_RGBA_FXT1_3DFX:
+        return GL_RGBA;
+    }
+    return -1;
+}
+
+/*
+ * Tell us if an image is compressed.  The real work is done
+ * in a macro, but we need to have a function to create a
+ * function pointer.
+ */
+GLboolean
+tdfxDDIsCompressedFormat(GLcontext *ctx, GLint internalFormat)
+{
+    return tdfxDDIsCompressedFormatMacro(internalFormat);
+}
+
+
+/*
+ * Calculate the image size of a compressed texture.
+ *
+ * The current compressed format, the FXT1 family, all
+ * map 8x32 texel blocks into 128 bits.
+ *
+ * We return 0 if we can't calculate the size.
+ *
+ * Glide would report this out to us, but we don't have
+ * exactly the right parameters.
+ */
+GLsizei
+tdfxDDCompressedImageSize(GLcontext *ctx,
+                          GLenum intFormat,
+                          GLuint numDimensions,
+                          GLuint width,
+                          GLuint height,
+                          GLuint depth)
+{
+    if (numDimensions != 2) {
+        return 0;
+    }
+    switch (intFormat) {
+    case GL_COMPRESSED_RGB_FXT1_3DFX:
+    case GL_COMPRESSED_RGBA_FXT1_3DFX:
+       /*
+        * Round height and width to multiples of 4 and 8,
+        * divide the resulting product by 32 to get the number
+        * of blocks, and multiply by 32 = 128/8 to get the.
+        * number of bytes required.  That is to say, just
+        * return the product.  Remember that we are returning
+        * bytes, not texels, so we have shrunk the texture
+        * by a factor of the texel size.
+        */
+        width = (width   + 0x7) &~ 0x7;
+        height = (height + 0x3) &~ 0x3;
+        return width * height;
+    }
+    return 0;
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_tex.h b/src/mesa/drivers/dri/tdfx/tdfx_tex.h
new file mode 100644 (file)
index 0000000..5fc7c74
--- /dev/null
@@ -0,0 +1,165 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_tex.h,v 1.2 2002/02/22 21:45:04 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#ifndef _TDFX_TEX_H_
+#define _TDFX_TEX_H_
+
+
+#include "texutil.h"
+
+
+#define tdfxDDIsCompressedFormatMacro(internalFormat) \
+    (((internalFormat) == GL_COMPRESSED_RGB_FXT1_3DFX) || \
+     ((internalFormat) == GL_COMPRESSED_RGBA_FXT1_3DFX))
+#define tdfxDDIsCompressedGlideFormatMacro(internalFormat) \
+    ((internalFormat) == GR_TEXFMT_ARGB_CMP_FXT1)
+
+
+
+extern void
+tdfxTexValidate(GLcontext * ctx, struct gl_texture_object *tObj);
+
+extern void
+tdfxDDBindTexture(GLcontext * ctx, GLenum target,
+                  struct gl_texture_object *tObj);
+
+extern void
+tdfxDDDeleteTexture(GLcontext * ctx, struct gl_texture_object *tObj);
+
+extern GLboolean
+tdfxDDIsTextureResident(GLcontext *ctx, struct gl_texture_object *tObj);
+
+extern void
+tdfxDDTexturePalette(GLcontext * ctx, struct gl_texture_object *tObj);
+
+#if 000 /* DEAD? */
+extern void
+fxDDTexUseGlobalPalette(GLcontext * ctx, GLboolean state);
+#endif
+
+extern void
+tdfxDDTexEnv(GLcontext * ctx, GLenum target, GLenum pname,
+             const GLfloat * param);
+
+extern void
+tdfxDDTexParameter(GLcontext * ctx, GLenum target,
+                   struct gl_texture_object *tObj,
+                   GLenum pname, const GLfloat * params);
+
+extern const struct gl_texture_format *
+tdfxDDChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+                           GLenum srcFormat, GLenum srcType );
+
+extern void
+tdfxDDTexImage2D(GLcontext * ctx, GLenum target, GLint level,
+                 GLint internalFormat, GLint width, GLint height,
+                 GLint border,
+                 GLenum format, GLenum type, const GLvoid * pixels,
+                 const struct gl_pixelstore_attrib * packing,
+                 struct gl_texture_object * texObj,
+                 struct gl_texture_image * texImage);
+
+extern void
+tdfxDDTexSubImage2D(GLcontext *ctx, GLenum target, GLint level,
+                    GLint xoffset, GLint yoffset,
+                    GLsizei width, GLsizei height,
+                    GLenum format, GLenum type,
+                    const GLvoid *pixels,
+                    const struct gl_pixelstore_attrib *packing,
+                    struct gl_texture_object *texObj,
+                    struct gl_texture_image *texImage );
+
+#if 000
+extern GLboolean
+tdfxDDCompressedTexImage2D( GLcontext *ctx, GLenum target,
+                            GLint level, GLsizei imageSize,
+                            const GLvoid *data,
+                            struct gl_texture_object *texObj,
+                            struct gl_texture_image *texImage,
+                            GLboolean *retainInternalCopy);
+
+extern GLboolean
+tdfxDDCompressedTexSubImage2D( GLcontext *ctx, GLenum target,
+                               GLint level, GLint xoffset,
+                               GLint yoffset, GLsizei width,
+                               GLint height, GLenum format,
+                               GLsizei imageSize, const GLvoid *data,
+                               struct gl_texture_object *texObj,
+                               struct gl_texture_image *texImage );
+#endif
+
+extern GLboolean
+tdfxDDTestProxyTexImage(GLcontext *ctx, GLenum target,
+                        GLint level, GLint internalFormat,
+                        GLenum format, GLenum type,
+                        GLint width, GLint height,
+                        GLint depth, GLint border);
+
+extern GLvoid *
+tdfxDDGetTexImage(GLcontext * ctx, GLenum target, GLint level,
+                  const struct gl_texture_object *texObj,
+                  GLenum * formatOut, GLenum * typeOut,
+                  GLboolean * freeImageOut);
+
+extern void
+tdfxDDGetCompressedTexImage( GLcontext *ctx, GLenum target,
+                             GLint lod, void *image,
+                             const struct gl_texture_object *texObj,
+                             struct gl_texture_image *texImage );
+
+extern GLint
+tdfxDDSpecificCompressedTexFormat(GLcontext *ctx,
+                                  GLint internalFormat,
+                                  GLint numDimensions);
+
+extern GLint
+tdfxDDBaseCompressedTexFormat(GLcontext *ctx,
+                              GLint internalFormat);
+
+extern GLboolean
+tdfxDDIsCompressedFormat(GLcontext *ctx, GLint internalFormat);
+
+extern GLsizei
+tdfxDDCompressedImageSize(GLcontext *ctx,
+                          GLenum intFormat,
+                          GLuint numDimensions,
+                          GLuint width,
+                          GLuint height,
+                          GLuint depth);
+
+
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_texman.c b/src/mesa/drivers/dri/tdfx/tdfx_texman.c
new file mode 100644 (file)
index 0000000..b34779c
--- /dev/null
@@ -0,0 +1,970 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_texman.c,v 1.5 2002/02/22 21:45:04 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#include "tdfx_context.h"
+#include "tdfx_tex.h"
+#include "tdfx_texman.h"
+
+
+#define BAD_ADDRESS ((FxU32) -1)
+
+
+#if 0 /* DEBUG use */
+/*
+ * Verify the consistancy of the texture memory manager.
+ * This involves:
+ *    Traversing all texture objects and computing total memory used.
+ *    Traverse the free block list and computing total memory free.
+ *    Compare the total free and total used amounts to the total memory size.
+ *    Make various assertions about the results.
+ */
+static void
+VerifyFreeList(tdfxContextPtr fxMesa, FxU32 tmu)
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    tdfxMemRange *block;
+    int prevStart = -1, prevEnd = -1;
+    int totalFree = 0;
+    int numObj = 0, numRes = 0;
+    int totalUsed = 0;
+
+    for (block = shared->tmFree[tmu]; block; block = block->next) {
+       assert( block->endAddr > 0 );
+       assert( block->startAddr <= shared->totalTexMem[tmu] );
+       assert( block->endAddr <= shared->totalTexMem[tmu] );
+       assert( (int) block->startAddr > prevStart );
+       assert( (int) block->startAddr >= prevEnd );
+       prevStart = (int) block->startAddr;
+       prevEnd = (int) block->endAddr;
+       totalFree += (block->endAddr - block->startAddr);
+    }
+    assert(totalFree == shared->freeTexMem[tmu]);
+
+    {
+       struct gl_texture_object *obj;
+       for (obj = mesaShared->TexObjectList; obj; obj = obj->Next) {
+          tdfxTexInfo *ti = TDFX_TEXTURE_DATA(obj);
+          numObj++;
+          if (ti) {
+             if (ti->isInTM) {
+                numRes++;
+                assert(ti->tm[0]);
+                if (ti->tm[tmu])
+                   totalUsed += (ti->tm[tmu]->endAddr - ti->tm[tmu]->startAddr);
+             }
+             else {
+                assert(!ti->tm[0]);
+             }
+          }
+       }
+    }
+
+    printf("totalFree: %d  totalUsed: %d  totalMem: %d #objs=%d  #res=%d\n",
+           shared->freeTexMem[tmu], totalUsed, shared->totalTexMem[tmu],
+           numObj, numRes);
+
+    assert(totalUsed + totalFree == shared->totalTexMem[tmu]);
+}
+
+
+static void
+dump_texmem(tdfxContextPtr fxMesa)
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    struct gl_texture_object *oldestObj, *obj, *lowestPriorityObj;
+    tdfxMemRange *r;
+    FxU32 prev;
+
+    printf("DUMP Objects:\n");
+    for (obj = mesaShared->TexObjectList; obj; obj = obj->Next) {
+        tdfxTexInfo *info = TDFX_TEXTURE_DATA(obj);
+
+        if (info && info->isInTM) {
+        printf("Obj %8p: %4d  info = %p\n", obj, obj->Name, info);
+
+           printf("  isInTM=%d  whichTMU=%d  lastTimeUsed=%d\n",
+                  info->isInTM, info->whichTMU, info->lastTimeUsed);
+           printf("    tm[0] = %p", info->tm[0]);
+           assert(info->tm[0]);
+           if (info->tm[0]) {
+              printf("  tm startAddr = %d  endAddr = %d",
+                     info->tm[0]->startAddr,
+                     info->tm[0]->endAddr);
+           }
+           printf("\n");
+           printf("    tm[1] = %p", info->tm[1]);
+           if (info->tm[1]) {
+              printf("  tm startAddr = %d  endAddr = %d",
+                     info->tm[1]->startAddr,
+                     info->tm[1]->endAddr);
+           }
+           printf("\n");
+        }
+    }
+
+    VerifyFreeList(fxMesa, 0);
+    VerifyFreeList(fxMesa, 1);
+
+    printf("Free memory unit 0:  %d bytes\n", shared->freeTexMem[0]);
+    prev = 0;
+    for (r = shared->tmFree[0]; r; r = r->next) {
+       printf("%8p:  start %8d  end %8d  size %8d  gap %8d\n", r, r->startAddr, r->endAddr, r->endAddr - r->startAddr, r->startAddr - prev);
+       prev = r->endAddr;
+    }
+
+    printf("Free memory unit 1:  %d bytes\n", shared->freeTexMem[1]);
+    prev = 0;
+    for (r = shared->tmFree[1]; r; r = r->next) {
+       printf("%8p:  start %8d  end %8d  size %8d  gap %8d\n", r, r->startAddr, r->endAddr, r->endAddr - r->startAddr, r->startAddr - prev);
+       prev = r->endAddr;
+    }
+
+}
+#endif
+
+
+
+#ifdef TEXSANITY
+static void
+fubar(void)
+{
+}
+
+/*
+ * Sanity Check
+ */
+static void
+sanity(tdfxContextPtr fxMesa)
+{
+    tdfxMemRange *tmp, *prev, *pos;
+
+    prev = 0;
+    tmp = fxMesa->tmFree[0];
+    while (tmp) {
+        if (!tmp->startAddr && !tmp->endAddr) {
+            fprintf(stderr, "Textures fubar\n");
+            fubar();
+        }
+        if (tmp->startAddr >= tmp->endAddr) {
+            fprintf(stderr, "Node fubar\n");
+            fubar();
+        }
+        if (prev && (prev->startAddr >= tmp->startAddr ||
+                     prev->endAddr > tmp->startAddr)) {
+            fprintf(stderr, "Sorting fubar\n");
+            fubar();
+        }
+        prev = tmp;
+        tmp = tmp->next;
+    }
+    prev = 0;
+    tmp = fxMesa->tmFree[1];
+    while (tmp) {
+        if (!tmp->startAddr && !tmp->endAddr) {
+            fprintf(stderr, "Textures fubar\n");
+            fubar();
+        }
+        if (tmp->startAddr >= tmp->endAddr) {
+            fprintf(stderr, "Node fubar\n");
+            fubar();
+        }
+        if (prev && (prev->startAddr >= tmp->startAddr ||
+                     prev->endAddr > tmp->startAddr)) {
+            fprintf(stderr, "Sorting fubar\n");
+            fubar();
+        }
+        prev = tmp;
+        tmp = tmp->next;
+    }
+}
+#endif
+
+
+
+
+
+/*
+ * Allocate and initialize a new MemRange struct.
+ * Try to allocate it from the pool of free MemRange nodes rather than malloc.
+ */
+static tdfxMemRange *
+NewRangeNode(tdfxContextPtr fxMesa, FxU32 start, FxU32 end)
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    tdfxMemRange *result;
+
+    _glthread_LOCK_MUTEX(mesaShared->Mutex);
+    if (shared && shared->tmPool) {
+        result = shared->tmPool;
+        shared->tmPool = shared->tmPool->next;
+    }
+    else {
+        result = MALLOC(sizeof(tdfxMemRange));
+
+    }
+    _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
+
+    if (!result) {
+        /*fprintf(stderr, "fxDriver: out of memory!\n");*/
+        return NULL;
+    }
+
+    result->startAddr = start;
+    result->endAddr = end;
+    result->next = NULL;
+
+    return result;
+}
+
+
+/*
+ * Initialize texture memory.
+ * We take care of one or both TMU's here.
+ */
+void
+tdfxTMInit(tdfxContextPtr fxMesa)
+{
+    if (!fxMesa->glCtx->Shared->DriverData) {
+        const char *extensions;
+        struct tdfxSharedState *shared = CALLOC_STRUCT(tdfxSharedState);
+        if (!shared)
+           return;
+
+        LOCK_HARDWARE(fxMesa);
+        extensions = fxMesa->Glide.grGetString(GR_EXTENSION);
+        UNLOCK_HARDWARE(fxMesa);
+        if (strstr(extensions, "TEXUMA")) {
+            FxU32 start, end;
+            shared->umaTexMemory = GL_TRUE;
+            LOCK_HARDWARE(fxMesa);
+            fxMesa->Glide.grEnable(GR_TEXTURE_UMA_EXT);
+            start = fxMesa->Glide.grTexMinAddress(0);
+            end = fxMesa->Glide.grTexMaxAddress(0);
+            UNLOCK_HARDWARE(fxMesa);
+            shared->totalTexMem[0] = end - start;
+            shared->totalTexMem[1] = 0;
+            shared->freeTexMem[0] = end - start;
+            shared->freeTexMem[1] = 0;
+            shared->tmFree[0] = NewRangeNode(fxMesa, start, end);
+            shared->tmFree[1] = NULL;
+            /*printf("UMA tex memory: %d\n", (int) (end - start));*/
+        }
+        else {
+            const int numTMUs = fxMesa->haveTwoTMUs ? 2 : 1;
+            int tmu;
+            shared->umaTexMemory = GL_FALSE;
+            LOCK_HARDWARE(fxMesa);
+            for (tmu = 0; tmu < numTMUs; tmu++) {
+                FxU32 start = fxMesa->Glide.grTexMinAddress(tmu);
+                FxU32 end = fxMesa->Glide.grTexMaxAddress(tmu);
+                shared->totalTexMem[tmu] = end - start;
+                shared->freeTexMem[tmu] = end - start;
+                shared->tmFree[tmu] = NewRangeNode(fxMesa, start, end);
+                /*printf("Split tex memory: %d\n", (int) (end - start));*/
+            }
+            UNLOCK_HARDWARE(fxMesa);
+        }
+
+        shared->tmPool = NULL;
+        fxMesa->glCtx->Shared->DriverData = shared;
+        /*printf("Texture memory init UMA: %d\n", shared->umaTexMemory);*/
+    }
+}
+
+
+/*
+ * Clean-up texture memory before destroying context.
+ */
+void
+tdfxTMClose(tdfxContextPtr fxMesa)
+{
+    if (fxMesa->glCtx->Shared->RefCount == 1 && fxMesa->driDrawable) {
+        /* refcount will soon go to zero, free our 3dfx stuff */
+        struct tdfxSharedState *shared = (struct tdfxSharedState *) fxMesa->glCtx->Shared->DriverData;
+
+        const int numTMUs = fxMesa->haveTwoTMUs ? 2 : 1;
+        int tmu;
+        tdfxMemRange *tmp, *next;
+
+        /* Deallocate the pool of free tdfxMemRange nodes */
+        tmp = shared->tmPool;
+        while (tmp) {
+            next = tmp->next;
+            FREE(tmp);
+            tmp = next;
+        }
+
+        /* Delete the texture memory block tdfxMemRange nodes */
+        for (tmu = 0; tmu < numTMUs; tmu++) {
+            tmp = shared->tmFree[tmu];
+            while (tmp) {
+                next = tmp->next;
+                FREE(tmp);
+                tmp = next;
+            }
+        }
+
+        FREE(shared);
+        fxMesa->glCtx->Shared->DriverData = NULL;
+    }
+}
+
+
+
+/*
+ * Delete a tdfxMemRange struct.
+ * We keep a linked list of free/available tdfxMemRange structs to
+ * avoid extra malloc/free calls.
+ */
+#if 0
+static void
+DeleteRangeNode_NoLock(struct TdfxSharedState *shared, tdfxMemRange *range)
+{
+    /* insert at head of list */
+    range->next = shared->tmPool;
+    shared->tmPool = range;
+}
+#endif
+
+#define DELETE_RANGE_NODE(shared, range) \
+    (range)->next = (shared)->tmPool;    \
+    (shared)->tmPool = (range)
+
+
+
+/*
+ * When we've run out of texture memory we have to throw out an
+ * existing texture to make room for the new one.  This function
+ * determins the texture to throw out.
+ */
+static struct gl_texture_object *
+FindOldestObject(tdfxContextPtr fxMesa, FxU32 tmu)
+{
+    const GLuint bindnumber = fxMesa->texBindNumber;
+    struct gl_texture_object *oldestObj, *obj, *lowestPriorityObj;
+    GLfloat lowestPriority;
+    GLuint oldestAge;
+
+    oldestObj = NULL;
+    oldestAge = 0;
+
+    lowestPriority = 1.0F;
+    lowestPriorityObj = NULL;
+
+    for (obj = fxMesa->glCtx->Shared->TexObjectList; obj; obj = obj->Next) {
+        tdfxTexInfo *info = TDFX_TEXTURE_DATA(obj);
+
+        if (info && info->isInTM &&
+            ((info->whichTMU == tmu) || (info->whichTMU == TDFX_TMU_BOTH) ||
+             (info->whichTMU == TDFX_TMU_SPLIT))) {
+            GLuint age, lasttime;
+
+            assert(info->tm[0]);
+            lasttime = info->lastTimeUsed;
+
+            if (lasttime > bindnumber)
+                age = bindnumber + (UINT_MAX - lasttime + 1); /* TO DO: check wrap around */
+            else
+                age = bindnumber - lasttime;
+
+            if (age >= oldestAge) {
+                oldestAge = age;
+                oldestObj = obj;
+            }
+
+            /* examine priority */
+            if (obj->Priority < lowestPriority) {
+                lowestPriority = obj->Priority;
+                lowestPriorityObj = obj;
+            }
+        }
+    }
+
+    if (lowestPriority < 1.0) {
+        ASSERT(lowestPriorityObj);
+        /*
+        printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
+        */
+        return lowestPriorityObj;
+    }
+    else {
+        /*
+        printf("discard %d age=%d\n", oldestObj->Name, oldestAge);
+        */
+        return oldestObj;
+    }
+}
+
+
+#if 0
+static void
+FlushTexMemory(tdfxContextPtr fxMesa)
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    struct gl_texture_object *obj;
+
+    for (obj = mesaShared->TexObjectList; obj; obj = obj->Next) {
+       if (obj->RefCount < 2) {
+          /* don't flush currently bound textures */
+          tdfxTMMoveOutTM_NoLock(fxMesa, obj);
+       }
+    }
+}
+#endif
+
+
+/*
+ * Find the address (offset?) at which we can store a new texture.
+ * <tmu> is the texture unit.
+ * <size> is the texture size in bytes.
+ */
+static FxU32
+FindStartAddr(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 size)
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    tdfxMemRange *prev, *block;
+    FxU32 result;
+#if 0
+    int discardedCount = 0;
+#define MAX_DISCARDS 10
+#endif
+
+    if (shared->umaTexMemory) {
+        assert(tmu == TDFX_TMU0);
+    }
+
+    _glthread_LOCK_MUTEX(mesaShared->Mutex);
+    while (1) {
+        prev = NULL;
+        block = shared->tmFree[tmu];
+        while (block) {
+            if (block->endAddr - block->startAddr >= size) {
+                /* The texture will fit here */
+                result = block->startAddr;
+                block->startAddr += size;
+                if (block->startAddr == block->endAddr) {
+                    /* Remove this node since it's empty */
+                    if (prev) {
+                        prev->next = block->next;
+                    }
+                    else {
+                        shared->tmFree[tmu] = block->next;
+                    }
+                    DELETE_RANGE_NODE(shared, block);
+                }
+                shared->freeTexMem[tmu] -= size;
+                _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
+                return result;
+            }
+            prev = block;
+            block = block->next;
+        }
+        /* We failed to find a block large enough to accomodate <size> bytes.
+         * Find the oldest texObject and free it.
+         */
+#if 0
+        discardedCount++;
+        if (discardedCount > MAX_DISCARDS + 1) {
+            _mesa_problem(NULL, "%s: extreme texmem fragmentation", __FUNCTION__);
+            _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
+            return BAD_ADDRESS;
+        }
+        else if (discardedCount > MAX_DISCARDS) {
+            /* texture memory is probably really fragmented, flush it */
+            FlushTexMemory(fxMesa);
+        }
+        else
+#endif
+        {
+            struct gl_texture_object *obj = FindOldestObject(fxMesa, tmu);
+            if (obj) {
+                tdfxTMMoveOutTM_NoLock(fxMesa, obj);
+                fxMesa->stats.texSwaps++;
+            }
+            else {
+                _mesa_problem(NULL, "%s: extreme texmem fragmentation", __FUNCTION__);
+                _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
+                return BAD_ADDRESS;
+            }
+        }
+    }
+
+    /* never get here, but play it safe */
+    _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
+    return BAD_ADDRESS;
+}
+
+
+/*
+ * Remove the given tdfxMemRange node from hardware texture memory.
+ */
+static void
+RemoveRange_NoLock(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range)
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    tdfxMemRange *block, *prev;
+
+    if (shared->umaTexMemory) {
+       assert(tmu == TDFX_TMU0);
+    }
+
+    if (!range)
+        return;
+
+    if (range->startAddr == range->endAddr) {
+        DELETE_RANGE_NODE(shared, range);
+        return;
+    }
+    shared->freeTexMem[tmu] += range->endAddr - range->startAddr;
+
+    /* find position in linked list to insert this tdfxMemRange node */
+    prev = NULL;
+    block = shared->tmFree[tmu];
+    while (block) {
+        assert(range->startAddr != block->startAddr);
+        if (range->startAddr > block->startAddr) {
+            prev = block;
+            block = block->next;
+        }
+        else {
+            break;
+        }
+    }
+
+    /* Insert the free block, combine with adjacent blocks when possible */
+    range->next = block;
+    if (block) {
+        if (range->endAddr == block->startAddr) {
+            /* Combine */
+            block->startAddr = range->startAddr;
+            DELETE_RANGE_NODE(shared, range);
+            range = block;
+        }
+    }
+    if (prev) {
+        if (prev->endAddr == range->startAddr) {
+            /* Combine */
+            prev->endAddr = range->endAddr;
+            prev->next = range->next;
+            DELETE_RANGE_NODE(shared, range);
+        }
+        else {
+            prev->next = range;
+        }
+    }
+    else {
+        shared->tmFree[tmu] = range;
+    }
+}
+
+
+#if 0 /* NOT USED */
+static void
+RemoveRange(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range)
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    _glthread_LOCK_MUTEX(mesaShared->Mutex);
+    RemoveRange_NoLock(fxMesa, tmu, range);
+    _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
+}
+#endif
+
+
+/*
+ * Allocate space for a texture image.
+ * <tmu> is the texture unit
+ * <texmemsize> is the number of bytes to allocate
+ */
+static tdfxMemRange *
+AllocTexMem(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 texmemsize)
+{
+    FxU32 startAddr;
+    startAddr = FindStartAddr(fxMesa, tmu, texmemsize);
+    if (startAddr == BAD_ADDRESS) {
+        _mesa_problem(fxMesa->glCtx, "%s returned NULL!  tmu=%d texmemsize=%d",
+               __FUNCTION__, (int) tmu, (int) texmemsize);
+        return NULL;
+    }
+    else {
+        tdfxMemRange *range;
+        range = NewRangeNode(fxMesa, startAddr, startAddr + texmemsize);
+        return range;
+    }
+}
+
+
+/*
+ * Download (copy) the given texture data (all mipmap levels) into the
+ * Voodoo's texture memory.
+ * The texture memory must have already been allocated.
+ */
+void
+tdfxTMDownloadTexture(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
+{
+    tdfxTexInfo *ti;
+    GLint l;
+    FxU32 targetTMU;
+
+    assert(tObj);
+    ti = TDFX_TEXTURE_DATA(tObj);
+    assert(ti);
+    targetTMU = ti->whichTMU;
+
+    switch (targetTMU) {
+    case TDFX_TMU0:
+    case TDFX_TMU1:
+        if (ti->tm[targetTMU]) {
+            for (l = ti->minLevel; l <= ti->maxLevel
+                    && tObj->Image[l]->Data; l++) {
+                GrLOD_t glideLod = ti->info.largeLodLog2 - l + tObj->BaseLevel;
+                fxMesa->Glide.grTexDownloadMipMapLevel(targetTMU,
+                                                  ti->tm[targetTMU]->startAddr,
+                                                  glideLod,
+                                                  ti->info.largeLodLog2,
+                                                  ti->info.aspectRatioLog2,
+                                                  ti->info.format,
+                                                  GR_MIPMAPLEVELMASK_BOTH,
+                                                  tObj->Image[l]->Data);
+            }
+        }
+        break;
+    case TDFX_TMU_SPLIT:
+        if (ti->tm[TDFX_TMU0] && ti->tm[TDFX_TMU1]) {
+            for (l = ti->minLevel; l <= ti->maxLevel
+                    && tObj->Image[l]->Data; l++) {
+                GrLOD_t glideLod = ti->info.largeLodLog2 - l + tObj->BaseLevel;
+                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
+                                                  ti->tm[TDFX_TMU0]->startAddr,
+                                                  glideLod,
+                                                  ti->info.largeLodLog2,
+                                                  ti->info.aspectRatioLog2,
+                                                  ti->info.format,
+                                                  GR_MIPMAPLEVELMASK_ODD,
+                                                  tObj->Image[l]->Data);
+
+                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
+                                                  ti->tm[TDFX_TMU1]->startAddr,
+                                                  glideLod,
+                                                  ti->info.largeLodLog2,
+                                                  ti->info.aspectRatioLog2,
+                                                  ti->info.format,
+                                                  GR_MIPMAPLEVELMASK_EVEN,
+                                                  tObj->Image[l]->Data);
+            }
+        }
+        break;
+    case TDFX_TMU_BOTH:
+        if (ti->tm[TDFX_TMU0] && ti->tm[TDFX_TMU1]) {
+            for (l = ti->minLevel; l <= ti->maxLevel
+                    && tObj->Image[l]->Data; l++) {
+                GrLOD_t glideLod = ti->info.largeLodLog2 - l + tObj->BaseLevel;
+                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
+                                                  ti->tm[TDFX_TMU0]->startAddr,
+                                                  glideLod,
+                                                  ti->info.largeLodLog2,
+                                                  ti->info.aspectRatioLog2,
+                                                  ti->info.format,
+                                                  GR_MIPMAPLEVELMASK_BOTH,
+                                                  tObj->Image[l]->Data);
+
+                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
+                                                  ti->tm[TDFX_TMU1]->startAddr,
+                                                  glideLod,
+                                                  ti->info.largeLodLog2,
+                                                  ti->info.aspectRatioLog2,
+                                                  ti->info.format,
+                                                  GR_MIPMAPLEVELMASK_BOTH,
+                                                  tObj->Image[l]->Data);
+            }
+        }
+        break;
+    default:
+        _mesa_problem(NULL, "%s: bad tmu (%d)", __FUNCTION__, (int)targetTMU);
+        return;
+    }
+}
+
+
+void
+tdfxTMReloadMipMapLevel(GLcontext *ctx, struct gl_texture_object *tObj,
+                        GLint level)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+    GrLOD_t glideLod;
+    FxU32 tmu;
+
+    tmu = ti->whichTMU;
+    glideLod =  ti->info.largeLodLog2 - level + tObj->BaseLevel;
+    ASSERT(ti->isInTM);
+
+    LOCK_HARDWARE(fxMesa);
+
+    switch (tmu) {
+    case TDFX_TMU0:
+    case TDFX_TMU1:
+        fxMesa->Glide.grTexDownloadMipMapLevel(tmu,
+                                    ti->tm[tmu]->startAddr,
+                                    glideLod,
+                                    ti->info.largeLodLog2,
+                                    ti->info.aspectRatioLog2,
+                                    ti->info.format,
+                                    GR_MIPMAPLEVELMASK_BOTH,
+                                    tObj->Image[level]->Data);
+        break;
+    case TDFX_TMU_SPLIT:
+        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
+                                    ti->tm[GR_TMU0]->startAddr,
+                                    glideLod,
+                                    ti->info.largeLodLog2,
+                                    ti->info.aspectRatioLog2,
+                                    ti->info.format,
+                                    GR_MIPMAPLEVELMASK_ODD,
+                                    tObj->Image[level]->Data);
+
+        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
+                                    ti->tm[GR_TMU1]->startAddr,
+                                    glideLod,
+                                    ti->info.largeLodLog2,
+                                    ti->info.aspectRatioLog2,
+                                    ti->info.format,
+                                    GR_MIPMAPLEVELMASK_EVEN,
+                                    tObj->Image[level]->Data);
+        break;
+    case TDFX_TMU_BOTH:
+        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
+                                    ti->tm[GR_TMU0]->startAddr,
+                                    glideLod,
+                                    ti->info.largeLodLog2,
+                                    ti->info.aspectRatioLog2,
+                                    ti->info.format,
+                                    GR_MIPMAPLEVELMASK_BOTH,
+                                    tObj->Image[level]->Data);
+
+        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
+                                    ti->tm[GR_TMU1]->startAddr,
+                                    glideLod,
+                                    ti->info.largeLodLog2,
+                                    ti->info.aspectRatioLog2,
+                                    ti->info.format,
+                                    GR_MIPMAPLEVELMASK_BOTH,
+                                    tObj->Image[level]->Data);
+        break;
+
+    default:
+        _mesa_problem(ctx, "%s: bad tmu (%d)", __FUNCTION__, (int)tmu);
+        break;
+    }
+    UNLOCK_HARDWARE(fxMesa);
+}
+
+
+/*
+ * Allocate space for the given texture in texture memory then
+ * download (copy) it into that space.
+ */
+void
+tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa, struct gl_texture_object *tObj,
+                       FxU32 targetTMU )
+{
+    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+    FxU32 texmemsize;
+
+    fxMesa->stats.reqTexUpload++;
+
+    if (ti->isInTM) {
+        if (ti->whichTMU == targetTMU)
+            return;
+        if (targetTMU == TDFX_TMU_SPLIT || ti->whichTMU == TDFX_TMU_SPLIT) {
+            tdfxTMMoveOutTM_NoLock(fxMesa, tObj);
+        }
+        else {
+            if (ti->whichTMU == TDFX_TMU_BOTH)
+                return;
+            targetTMU = TDFX_TMU_BOTH;
+        }
+    }
+
+    ti->whichTMU = targetTMU;
+
+    switch (targetTMU) {
+    case TDFX_TMU0:
+    case TDFX_TMU1:
+        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
+                                                       &(ti->info));
+        ti->tm[targetTMU] = AllocTexMem(fxMesa, targetTMU, texmemsize);
+        break;
+    case TDFX_TMU_SPLIT:
+        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD,
+                                                       &(ti->info));
+        ti->tm[TDFX_TMU0] = AllocTexMem(fxMesa, TDFX_TMU0, texmemsize);
+        if (ti->tm[TDFX_TMU0])
+           fxMesa->stats.memTexUpload += texmemsize;
+
+        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN,
+                                                       &(ti->info));
+        ti->tm[TDFX_TMU1] = AllocTexMem(fxMesa, TDFX_TMU1, texmemsize);
+        break;
+    case TDFX_TMU_BOTH:
+        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
+                                                       &(ti->info));
+        ti->tm[TDFX_TMU0] = AllocTexMem(fxMesa, TDFX_TMU0, texmemsize);
+        if (ti->tm[TDFX_TMU0])
+           fxMesa->stats.memTexUpload += texmemsize;
+
+        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
+                                                       &(ti->info));
+        ti->tm[TDFX_TMU1] = AllocTexMem(fxMesa, TDFX_TMU1, texmemsize);
+        break;
+    default:
+        _mesa_problem(NULL, "%s: bad tmu (%d)", __FUNCTION__, (int)targetTMU);
+        return;
+    }
+
+    ti->reloadImages = GL_TRUE;
+    ti->isInTM = GL_TRUE;
+
+    fxMesa->stats.texUpload++;
+}
+
+
+/*
+ * Move the given texture out of hardware texture memory.
+ * This deallocates the texture's memory space.
+ */
+void
+tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa, struct gl_texture_object *tObj )
+{
+    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+
+    if (MESA_VERBOSE & VERBOSE_DRIVER) {
+        fprintf(stderr, "fxmesa: %s(%p (%d))\n", __FUNCTION__, tObj, tObj->Name);
+    }
+
+    /*
+    VerifyFreeList(fxMesa, 0);
+    VerifyFreeList(fxMesa, 1);
+    */
+
+    if (!ti || !ti->isInTM)
+        return;
+
+    switch (ti->whichTMU) {
+    case TDFX_TMU0:
+    case TDFX_TMU1:
+        RemoveRange_NoLock(fxMesa, ti->whichTMU, ti->tm[ti->whichTMU]);
+        break;
+    case TDFX_TMU_SPLIT:
+    case TDFX_TMU_BOTH:
+        assert(!shared->umaTexMemory);
+        RemoveRange_NoLock(fxMesa, TDFX_TMU0, ti->tm[TDFX_TMU0]);
+        RemoveRange_NoLock(fxMesa, TDFX_TMU1, ti->tm[TDFX_TMU1]);
+        break;
+    default:
+        _mesa_problem(NULL, "%s: bad tmu (%d)", __FUNCTION__, (int)ti->whichTMU);
+        return;
+    }
+
+    ti->isInTM = GL_FALSE;
+    ti->tm[0] = NULL;
+    ti->tm[1] = NULL;
+    ti->whichTMU = TDFX_TMU_NONE;
+
+    /*
+    VerifyFreeList(fxMesa, 0);
+    VerifyFreeList(fxMesa, 1);
+    */
+}
+
+
+/*
+ * Called via glDeleteTexture to delete a texture object.
+ */
+void
+tdfxTMFreeTexture(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
+{
+    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+    if (ti) {
+        tdfxTMMoveOutTM(fxMesa, tObj);
+        FREE(ti);
+        tObj->DriverData = NULL;
+    }
+    /*
+    VerifyFreeList(fxMesa, 0);
+    VerifyFreeList(fxMesa, 1);
+    */
+}
+
+
+
+/*
+ * After a context switch this function will be called to restore
+ * texture memory for the new context.
+ */
+void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa )
+{
+   GLcontext *ctx = fxMesa->glCtx;
+   struct gl_texture_object *tObj;
+   int i;
+
+   for ( tObj = ctx->Shared->TexObjectList ; tObj ; tObj = tObj->Next ) {
+      tdfxTexInfo *ti = TDFX_TEXTURE_DATA( tObj );
+      if ( ti && ti->isInTM ) {
+        for ( i = 0 ; i < MAX_TEXTURE_UNITS ; i++ ) {
+           if ( ctx->Texture.Unit[i]._Current == tObj ) {
+              tdfxTMDownloadTexture( fxMesa, tObj );
+              break;
+           }
+        }
+        if ( i == MAX_TEXTURE_UNITS ) {
+           tdfxTMMoveOutTM_NoLock( fxMesa, tObj );
+        }
+      }
+   }
+   /*
+   VerifyFreeList(fxMesa, 0);
+   VerifyFreeList(fxMesa, 1);
+   */
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_texman.h b/src/mesa/drivers/dri/tdfx/tdfx_texman.h
new file mode 100644 (file)
index 0000000..739d4e1
--- /dev/null
@@ -0,0 +1,84 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_texman.h,v 1.2 2002/02/22 21:45:04 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_TEXMAN_H__
+#define __TDFX_TEXMAN_H__
+
+
+#include "tdfx_lock.h"
+
+
+extern void tdfxTMInit( tdfxContextPtr fxMesa );
+
+extern void tdfxTMClose( tdfxContextPtr fxMesa );
+
+extern void tdfxTMDownloadTexture(tdfxContextPtr fxMesa,
+                                  struct gl_texture_object *tObj);
+
+extern void tdfxTMReloadMipMapLevel( GLcontext *ctx,
+                                    struct gl_texture_object *tObj,
+                                    GLint level );
+
+extern void tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa,
+                                   struct gl_texture_object *tObj,
+                                   FxU32 targetTMU );
+
+extern void tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa,
+                                    struct gl_texture_object *tObj );
+
+extern void tdfxTMFreeTexture( tdfxContextPtr fxMesa,
+                              struct gl_texture_object *tObj );
+
+extern void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa );
+
+
+#define tdfxTMMoveInTM( fxMesa, tObj, targetTMU )              \
+   do {                                                                \
+      LOCK_HARDWARE( fxMesa );                                 \
+      tdfxTMMoveInTM_NoLock( fxMesa, tObj, targetTMU );                \
+      UNLOCK_HARDWARE( fxMesa );                               \
+   } while (0)
+
+#define tdfxTMMoveOutTM( fxMesa, tObj )                                \
+   do {                                                                \
+      LOCK_HARDWARE( fxMesa );                                 \
+      tdfxTMMoveOutTM_NoLock( fxMesa, tObj );                  \
+      UNLOCK_HARDWARE( fxMesa );                               \
+   } while (0)
+
+
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_texstate.c b/src/mesa/drivers/dri/tdfx/tdfx_texstate.c
new file mode 100644 (file)
index 0000000..e20938b
--- /dev/null
@@ -0,0 +1,2107 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_texstate.c,v 1.2 2002/02/22 21:45:04 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#include "tdfx_state.h"
+#include "tdfx_tex.h"
+#include "tdfx_texman.h"
+#include "tdfx_texstate.h"
+
+
+/* =============================================================
+ * Texture
+ */
+
+/*
+ * These macros are used below when handling COMBINE_EXT.
+ */
+#define TEXENV_OPERAND_INVERTED(operand)                            \
+  (((operand) == GL_ONE_MINUS_SRC_ALPHA)                            \
+   || ((operand) == GL_ONE_MINUS_SRC_COLOR))
+#define TEXENV_OPERAND_ALPHA(operand)                               \
+  (((operand) == GL_SRC_ALPHA) || ((operand) == GL_ONE_MINUS_SRC_ALPHA))
+#define TEXENV_SETUP_ARG_A(param, source, operand, iteratedAlpha)   \
+    switch (source) {                                               \
+    case GL_TEXTURE:                                                \
+        param = GR_CMBX_LOCAL_TEXTURE_ALPHA;                        \
+        break;                                                      \
+    case GL_CONSTANT_EXT:                                           \
+        param = GR_CMBX_TMU_CALPHA;                                 \
+        break;                                                      \
+    case GL_PRIMARY_COLOR_EXT:                                      \
+        param = GR_CMBX_ITALPHA;                                    \
+        break;                                                      \
+    case GL_PREVIOUS_EXT:                                           \
+        param = iteratedAlpha;                                      \
+        break;                                                      \
+    default:                                                        \
+       /*                                                           \
+        * This is here just to keep from getting                    \
+        * compiler warnings.                                        \
+        */                                                          \
+        param = GR_CMBX_ZERO;                                       \
+        break;                                                      \
+    }
+
+#define TEXENV_SETUP_ARG_RGB(param, source, operand, iteratedColor, iteratedAlpha) \
+    if (!TEXENV_OPERAND_ALPHA(operand)) {                           \
+        switch (source) {                                           \
+        case GL_TEXTURE:                                            \
+            param = GR_CMBX_LOCAL_TEXTURE_RGB;                      \
+            break;                                                  \
+        case GL_CONSTANT_EXT:                                       \
+            param = GR_CMBX_TMU_CCOLOR;                             \
+            break;                                                  \
+        case GL_PRIMARY_COLOR_EXT:                                  \
+            param = GR_CMBX_ITRGB;                                  \
+            break;                                                  \
+        case GL_PREVIOUS_EXT:                                       \
+            param = iteratedColor;                                  \
+            break;                                                  \
+        default:                                                    \
+           /*                                                       \
+            * This is here just to keep from getting                \
+            * compiler warnings.                                    \
+            */                                                      \
+            param = GR_CMBX_ZERO;                                   \
+            break;                                                  \
+        }                                                           \
+    } else {                                                        \
+        switch (source) {                                           \
+        case GL_TEXTURE:                                            \
+            param = GR_CMBX_LOCAL_TEXTURE_ALPHA;                    \
+            break;                                                  \
+        case GL_CONSTANT_EXT:                                       \
+            param = GR_CMBX_TMU_CALPHA;                             \
+            break;                                                  \
+        case GL_PRIMARY_COLOR_EXT:                                  \
+            param = GR_CMBX_ITALPHA;                                \
+            break;                                                  \
+        case GL_PREVIOUS_EXT:                                       \
+            param = iteratedAlpha;                                  \
+            break;                                                  \
+        default:                                                    \
+           /*                                                       \
+            * This is here just to keep from getting                \
+            * compiler warnings.                                    \
+            */                                                      \
+            param = GR_CMBX_ZERO;                                   \
+            break;                                                  \
+        }                                                           \
+    }
+
+#define TEXENV_SETUP_MODE_RGB(param, operand)                       \
+    switch (operand) {                                              \
+    case GL_SRC_COLOR:                                              \
+    case GL_SRC_ALPHA:                                              \
+        param = GR_FUNC_MODE_X;                                     \
+        break;                                                      \
+    case GL_ONE_MINUS_SRC_ALPHA:                                    \
+    case GL_ONE_MINUS_SRC_COLOR:                                    \
+        param = GR_FUNC_MODE_ONE_MINUS_X;                           \
+        break;                                                      \
+    default:                                                        \
+        param = GR_FUNC_MODE_ZERO;                                  \
+        break;                                                      \
+    }
+
+#define TEXENV_SETUP_MODE_A(param, operand)                         \
+    switch (operand) {                                              \
+    case GL_SRC_ALPHA:                                              \
+        param = GR_FUNC_MODE_X;                                     \
+        break;                                                      \
+    case GL_ONE_MINUS_SRC_ALPHA:                                    \
+        param = GR_FUNC_MODE_ONE_MINUS_X;                           \
+        break;                                                      \
+    default:                                                        \
+        param = GR_FUNC_MODE_ZERO;                                  \
+        break;                                                      \
+    }
+
+
+
+/*
+ * Setup a texture environment on Voodoo5.
+ * Return GL_TRUE for success, GL_FALSE for failure.
+ * If we fail, we'll have to use software rendering.
+ */
+static GLboolean
+SetupTexEnvNapalm(GLcontext *ctx, GLboolean useIteratedRGBA,
+                  const struct gl_texture_unit *texUnit, GLenum baseFormat,
+                  struct tdfx_texcombine_ext *env)
+{
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+    GrTCCUColor_t incomingRGB, incomingAlpha;
+    const GLenum envMode = texUnit->EnvMode;
+
+    if (useIteratedRGBA) {
+        incomingRGB = GR_CMBX_ITRGB;
+        incomingAlpha = GR_CMBX_ITALPHA;
+    }
+    else {
+        incomingRGB = GR_CMBX_OTHER_TEXTURE_RGB;
+        incomingAlpha = GR_CMBX_OTHER_TEXTURE_ALPHA;
+    }
+
+    /* invariant: */
+    env->Color.Shift = 0;
+    env->Color.Invert = FXFALSE;
+    env->Alpha.Shift = 0;
+    env->Alpha.Invert = FXFALSE;
+
+    switch (envMode) {
+    case GL_REPLACE:
+        /* -- Setup RGB combiner */
+        if (baseFormat == GL_ALPHA) {
+            /* Rv = Rf */
+            env->Color.SourceA = incomingRGB;
+        }
+        else {
+            /* Rv = Rt */
+            env->Color.SourceA = GR_CMBX_LOCAL_TEXTURE_RGB;
+        }
+        env->Color.ModeA = GR_FUNC_MODE_X;
+        env->Color.SourceB = GR_CMBX_ZERO;
+        env->Color.ModeB = GR_FUNC_MODE_ZERO;
+        env->Color.SourceC = GR_CMBX_ZERO;
+        env->Color.InvertC = FXTRUE;
+        env->Color.SourceD = GR_CMBX_ZERO;
+        env->Color.InvertD = FXFALSE;
+        /* -- Setup Alpha combiner */
+        if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+            /* Av = Af */
+           env->Alpha.SourceD = incomingAlpha;
+        }
+        else {
+            /* Av = At */
+           env->Alpha.SourceD = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+        }
+        env->Alpha.SourceA = GR_CMBX_ITALPHA;
+        env->Alpha.ModeA = GR_FUNC_MODE_ZERO;
+        env->Alpha.SourceB = GR_CMBX_ITALPHA;
+        env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+        env->Alpha.SourceC = GR_CMBX_ZERO;
+        env->Alpha.InvertC = FXFALSE;
+        env->Alpha.InvertD = FXFALSE;
+        break;
+
+    case GL_MODULATE:
+        /* -- Setup RGB combiner */
+        if (baseFormat == GL_ALPHA) {
+            /* Rv = Rf */
+           env->Color.SourceC = GR_CMBX_ZERO;
+           env->Color.InvertC = FXTRUE;
+        }
+        else {
+            /* Result = Frag * Tex */
+           env->Color.SourceC = GR_CMBX_LOCAL_TEXTURE_RGB;
+           env->Color.InvertC = FXFALSE;
+        }
+        env->Color.SourceA = incomingRGB;
+        env->Color.ModeA = GR_FUNC_MODE_X;
+        env->Color.SourceB = GR_CMBX_ZERO;
+        env->Color.ModeB = GR_FUNC_MODE_ZERO;
+        env->Color.SourceD = GR_CMBX_ZERO;
+        env->Color.InvertD = FXFALSE;
+        /* -- Setup Alpha combiner */
+        if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+            /* Av = Af */
+           env->Alpha.SourceA = incomingAlpha;
+           env->Alpha.SourceC = GR_CMBX_ZERO;
+           env->Alpha.InvertC = FXTRUE;
+        }
+        else {
+            /* Av = Af * At */
+           env->Alpha.SourceA = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+           env->Alpha.SourceC = incomingAlpha;
+           env->Alpha.InvertC = FXFALSE;
+        }
+        env->Alpha.ModeA = GR_FUNC_MODE_X;
+        env->Alpha.SourceB = GR_CMBX_ITALPHA;
+        env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+        env->Alpha.SourceD = GR_CMBX_ZERO;
+        env->Alpha.InvertD = FXFALSE;
+        break;
+
+    case GL_DECAL:
+        /* -- Setup RGB combiner */
+        if (baseFormat == GL_RGB) {
+            /* Rv = Rt */
+           env->Color.SourceB = GR_CMBX_ZERO;
+           env->Color.ModeB = GR_FUNC_MODE_X;
+           env->Color.SourceC = GR_CMBX_ZERO;
+           env->Color.InvertC = FXTRUE;
+           env->Color.SourceD = GR_CMBX_ZERO;
+           env->Color.InvertD = FXFALSE;
+        }
+        else {
+            /* Rv = Rf * (1 - At) + Rt * At */
+           env->Color.SourceB = incomingRGB;
+           env->Color.ModeB = GR_FUNC_MODE_NEGATIVE_X;
+           env->Color.SourceC = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+           env->Color.InvertC = FXFALSE;
+           env->Color.SourceD = GR_CMBX_B;
+           env->Color.InvertD = FXFALSE;
+        }
+        env->Color.SourceA = GR_CMBX_LOCAL_TEXTURE_RGB;
+        env->Color.ModeA = GR_FUNC_MODE_X;
+        /* -- Setup Alpha combiner */
+        /* Av = Af */
+        env->Alpha.SourceA = incomingAlpha;
+        env->Alpha.ModeA = GR_FUNC_MODE_X;
+        env->Alpha.SourceB = GR_CMBX_ITALPHA;
+        env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+        env->Alpha.SourceC = GR_CMBX_ZERO;
+        env->Alpha.InvertC = FXTRUE;
+        env->Alpha.SourceD = GR_CMBX_ZERO;
+        env->Alpha.InvertD = FXFALSE;
+        break;
+
+    case GL_BLEND:
+        /* -- Setup RGB combiner */
+        if (baseFormat == GL_ALPHA) {
+            /* Rv = Rf */
+            env->Color.SourceA = incomingRGB;
+            env->Color.ModeA = GR_FUNC_MODE_X;
+            env->Color.SourceB = GR_CMBX_ZERO;
+            env->Color.ModeB = GR_FUNC_MODE_ZERO;
+            env->Color.SourceC = GR_CMBX_ZERO;
+            env->Color.InvertC = FXTRUE;
+            env->Color.SourceD = GR_CMBX_ZERO;
+            env->Color.InvertD = FXFALSE;
+        }
+        else {
+            /* Rv = Rf * (1 - Rt) + Rc * Rt */
+            env->Color.SourceA = GR_CMBX_TMU_CCOLOR;
+            env->Color.ModeA = GR_FUNC_MODE_X;
+            env->Color.SourceB = incomingRGB;
+            env->Color.ModeB = GR_FUNC_MODE_NEGATIVE_X;
+            env->Color.SourceC = GR_CMBX_LOCAL_TEXTURE_RGB;
+            env->Color.InvertC = FXFALSE;
+            env->Color.SourceD = GR_CMBX_B;
+            env->Color.InvertD = FXFALSE;
+        }
+        /* -- Setup Alpha combiner */
+        if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+            /* Av = Af */
+            env->Alpha.SourceA = incomingAlpha;
+            env->Alpha.ModeA = GR_FUNC_MODE_X;
+            env->Alpha.SourceB = GR_CMBX_ZERO;
+            env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+            env->Alpha.SourceC = GR_CMBX_ZERO;
+            env->Alpha.InvertC = FXTRUE;
+            env->Alpha.SourceD = GR_CMBX_ZERO;
+            env->Alpha.InvertD = FXFALSE;
+        }
+        else if (baseFormat == GL_INTENSITY) {
+            /* Av = Af * (1 - It) + Ac * It */
+            env->Alpha.SourceA = GR_CMBX_TMU_CALPHA;
+            env->Alpha.ModeA = GR_FUNC_MODE_X;
+            env->Alpha.SourceB = incomingAlpha;
+            env->Alpha.ModeB = GR_FUNC_MODE_NEGATIVE_X;
+            env->Alpha.SourceC = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+            env->Alpha.InvertC = FXFALSE;
+            env->Alpha.SourceD = GR_CMBX_B;
+            env->Alpha.InvertD = FXFALSE;
+        }
+        else {
+            /* Av = Af * At */
+            env->Alpha.SourceA = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+            env->Alpha.ModeA = GR_FUNC_MODE_X;
+            env->Alpha.SourceB = GR_CMBX_ITALPHA;
+            env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+            env->Alpha.SourceC = incomingAlpha;
+            env->Alpha.InvertC = FXFALSE;
+            env->Alpha.SourceD = GR_CMBX_ZERO;
+            env->Alpha.InvertD = FXFALSE;
+        }
+        /* Also have to set up the tex env constant color */
+        env->EnvColor = PACK_RGBA32(texUnit->EnvColor[0] * 255.0F,
+                                    texUnit->EnvColor[1] * 255.0F,
+                                    texUnit->EnvColor[2] * 255.0F,
+                                    texUnit->EnvColor[3] * 255.0F);
+        break;
+    case GL_ADD:
+        /* -- Setup RGB combiner */
+        if (baseFormat == GL_ALPHA) {
+            /* Rv = Rf */
+           env->Color.SourceB = GR_CMBX_ZERO;
+           env->Color.ModeB = GR_FUNC_MODE_ZERO;
+        }
+        else {
+            /* Rv = Rf + Tt */
+           env->Color.SourceB = GR_CMBX_LOCAL_TEXTURE_RGB;
+           env->Color.ModeB = GR_FUNC_MODE_X;
+        }
+        env->Color.SourceA = incomingRGB;
+        env->Color.ModeA = GR_FUNC_MODE_X;
+        env->Color.SourceC = GR_CMBX_ZERO;
+        env->Color.InvertC = FXTRUE;
+        env->Color.SourceD = GR_CMBX_ZERO;
+        env->Color.InvertD = FXFALSE;
+        /* -- Setup Alpha combiner */
+        if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+            /* Av = Af */
+           env->Alpha.SourceA = incomingAlpha;
+           env->Alpha.SourceB = GR_CMBX_ITALPHA;
+           env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+           env->Alpha.SourceC = GR_CMBX_ZERO;
+           env->Alpha.InvertC = FXTRUE;
+
+        }
+        else if (baseFormat == GL_INTENSITY) {
+            /* Av = Af + It */
+           env->Alpha.SourceA = incomingAlpha;
+           env->Alpha.SourceB = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+           env->Alpha.ModeB = GR_FUNC_MODE_X;
+           env->Alpha.SourceC = GR_CMBX_ZERO;
+           env->Alpha.InvertC = FXTRUE;
+        }
+        else {
+            /* Av = Af * At */
+           env->Alpha.SourceA = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+           env->Alpha.SourceB = GR_CMBX_ITALPHA;
+           env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+           env->Alpha.SourceC = incomingAlpha;
+           env->Alpha.InvertC = FXFALSE;
+        }
+        env->Alpha.ModeA = GR_FUNC_MODE_X;
+        env->Alpha.SourceD = GR_CMBX_ZERO;
+        env->Alpha.InvertD = FXFALSE;
+        break;
+
+    case GL_COMBINE_EXT:
+        {
+            FxU32 A_RGB, B_RGB, C_RGB, D_RGB;
+            FxU32 Amode_RGB, Bmode_RGB;
+            FxBool Cinv_RGB, Dinv_RGB, Ginv_RGB;
+            FxU32 Shift_RGB;
+            FxU32 A_A, B_A, C_A, D_A;
+            FxU32 Amode_A, Bmode_A;
+            FxBool Cinv_A, Dinv_A, Ginv_A;
+            FxU32 Shift_A;
+
+           /*
+            *
+            * In the formulas below, we write:
+            *  o "1(x)" for the identity function applied to x,
+            *    so 1(x) = x.
+            *  o "0(x)" for the constant function 0, so
+            *    0(x) = 0 for all values of x.
+            *
+            * Calculate the color combination.
+            */
+            Shift_RGB = texUnit->CombineScaleShiftRGB;
+            Shift_A = texUnit->CombineScaleShiftA;
+            switch (texUnit->CombineModeRGB) {
+            case GL_REPLACE:
+               /*
+                * The formula is: Arg0
+                * We implement this by the formula:
+                *   (Arg0 + 0(0))*(1-0) + 0
+                */
+                TEXENV_SETUP_ARG_RGB(A_RGB,
+                                     texUnit->CombineSourceRGB[0],
+                                     texUnit->CombineOperandRGB[0],
+                                     incomingRGB, incomingAlpha);
+                TEXENV_SETUP_MODE_RGB(Amode_RGB,
+                                      texUnit->CombineOperandRGB[0]);
+                B_RGB = C_RGB = D_RGB = GR_CMBX_ZERO;
+                Bmode_RGB = GR_FUNC_MODE_ZERO;
+                Cinv_RGB = FXTRUE;
+                Dinv_RGB = Ginv_RGB = FXFALSE;
+                break;
+            case GL_MODULATE:
+               /*
+                * The formula is: Arg0 * Arg1
+                *
+                * We implement this by the formula
+                *   (Arg0 + 0(0)) * Arg1 + 0(0)
+                */
+                TEXENV_SETUP_ARG_RGB(A_RGB,
+                                     texUnit->CombineSourceRGB[0],
+                                     texUnit->CombineOperandRGB[0],
+                                     incomingRGB, incomingAlpha);
+                TEXENV_SETUP_MODE_RGB(Amode_RGB,
+                                      texUnit->CombineOperandRGB[0]);
+                B_RGB = GR_CMBX_ZERO;
+                Bmode_RGB = GR_CMBX_ZERO;
+                TEXENV_SETUP_ARG_RGB(C_RGB,
+                                     texUnit->CombineSourceRGB[1],
+                                     texUnit->CombineOperandRGB[1],
+                                     incomingRGB, incomingAlpha);
+                Cinv_RGB = TEXENV_OPERAND_INVERTED
+                               (texUnit->CombineOperandRGB[1]);
+                D_RGB = GR_CMBX_ZERO;
+                Dinv_RGB = Ginv_RGB = FXFALSE;
+                break;
+            case GL_ADD:
+               /*
+                * The formula is Arg0 + Arg1
+                */
+                TEXENV_SETUP_ARG_RGB(A_RGB,
+                                     texUnit->CombineSourceRGB[0],
+                                     texUnit->CombineOperandRGB[0],
+                                     incomingRGB, incomingAlpha);
+                TEXENV_SETUP_MODE_RGB(Amode_RGB,
+                                      texUnit->CombineOperandRGB[0]);
+                TEXENV_SETUP_ARG_RGB(B_RGB,
+                                     texUnit->CombineSourceRGB[1],
+                                     texUnit->CombineOperandRGB[1],
+                                     incomingRGB, incomingAlpha);
+                TEXENV_SETUP_MODE_RGB(Bmode_RGB,
+                                      texUnit->CombineOperandRGB[1]);
+                C_RGB = D_RGB = GR_CMBX_ZERO;
+                Cinv_RGB = FXTRUE;
+                Dinv_RGB = Ginv_RGB = FXFALSE;
+                break;
+            case GL_ADD_SIGNED_EXT:
+               /*
+                * The formula is: Arg0 + Arg1 - 0.5.
+                * We compute this by calculating:
+                *      (Arg0 - 1/2) + Arg1         if op0 is SRC_{COLOR,ALPHA}
+                *      Arg0 + (Arg1 - 1/2)         if op1 is SRC_{COLOR,ALPHA}
+                * If both op0 and op1 are ONE_MINUS_SRC_{COLOR,ALPHA}
+                * we cannot implement the formula properly.
+                */
+                TEXENV_SETUP_ARG_RGB(A_RGB,
+                                     texUnit->CombineSourceRGB[0],
+                                     texUnit->CombineOperandRGB[0],
+                                     incomingRGB, incomingAlpha);
+                TEXENV_SETUP_ARG_RGB(B_RGB,
+                                     texUnit->CombineSourceRGB[1],
+                                     texUnit->CombineOperandRGB[1],
+                                     incomingRGB, incomingAlpha);
+                if (!TEXENV_OPERAND_INVERTED(texUnit->CombineOperandRGB[0])) {
+                   /*
+                    * A is not inverted.  So, choose it.
+                    */
+                    Amode_RGB = GR_FUNC_MODE_X_MINUS_HALF;
+                    if (!TEXENV_OPERAND_INVERTED
+                            (texUnit->CombineOperandRGB[1])) {
+                        Bmode_RGB = GR_FUNC_MODE_X;
+                    }
+                    else {
+                        Bmode_RGB = GR_FUNC_MODE_ONE_MINUS_X;
+                    }
+                }
+                else {
+                   /*
+                    * A is inverted, so try to subtract 1/2
+                    * from B.
+                    */
+                    Amode_RGB = GR_FUNC_MODE_ONE_MINUS_X;
+                    if (!TEXENV_OPERAND_INVERTED
+                            (texUnit->CombineOperandRGB[1])) {
+                        Bmode_RGB = GR_FUNC_MODE_X_MINUS_HALF;
+                    }
+                    else {
+                       /*
+                        * Both are inverted.  This is the case
+                        * we cannot handle properly.  We just
+                        * choose to not add the - 1/2.
+                        */
+                        Bmode_RGB = GR_FUNC_MODE_ONE_MINUS_X;
+                        return GL_FALSE;
+                    }
+                }
+                C_RGB = D_RGB = GR_CMBX_ZERO;
+                Cinv_RGB = FXTRUE;
+                Dinv_RGB = Ginv_RGB = FXFALSE;
+                break;
+            case GL_INTERPOLATE_EXT:
+               /*
+                * The formula is: Arg0 * Arg2 + Arg1 * (1 - Arg2).
+                * We compute this by the formula:
+                *            (Arg0 - Arg1) * Arg2 + Arg1
+                *               == Arg0 * Arg2 - Arg1 * Arg2 + Arg1
+                *               == Arg0 * Arg2 + Arg1 * (1 - Arg2)
+                * However, if both Arg1 is ONE_MINUS_X, the HW does
+                * not support it properly.
+                */
+                TEXENV_SETUP_ARG_RGB(A_RGB,
+                                     texUnit->CombineSourceRGB[0],
+                                     texUnit->CombineOperandRGB[0],
+                                     incomingRGB, incomingAlpha);
+                TEXENV_SETUP_MODE_RGB(Amode_RGB,
+                                      texUnit->CombineOperandRGB[0]);
+                TEXENV_SETUP_ARG_RGB(B_RGB,
+                                     texUnit->CombineSourceRGB[1],
+                                     texUnit->CombineOperandRGB[1],
+                                     incomingRGB, incomingAlpha);
+                if (TEXENV_OPERAND_INVERTED(texUnit->CombineOperandRGB[1])) {
+                   /*
+                    * This case is wrong.
+                    */
+                   Bmode_RGB = GR_FUNC_MODE_NEGATIVE_X;
+                   return GL_FALSE;
+                }
+                else {
+                    Bmode_RGB = GR_FUNC_MODE_NEGATIVE_X;
+                }
+               /*
+                * The Source/Operand for the C value must
+                * specify some kind of alpha value.
+                */
+                TEXENV_SETUP_ARG_A(C_RGB,
+                                   texUnit->CombineSourceRGB[2],
+                                   texUnit->CombineOperandRGB[2],
+                                   incomingAlpha);
+                Cinv_RGB = FXFALSE;
+                D_RGB = GR_CMBX_B;
+                Dinv_RGB = Ginv_RGB = FXFALSE;
+                break;
+            default:
+               /*
+                * This is here mostly to keep from getting
+                * a compiler warning about these not being set.
+                * However, this should set all the texture values
+                * to zero.
+                */
+                A_RGB = B_RGB = C_RGB = D_RGB = GR_CMBX_ZERO;
+                Amode_RGB = Bmode_RGB = GR_FUNC_MODE_X;
+                Cinv_RGB = Dinv_RGB = Ginv_RGB = FXFALSE;
+                break;
+            }
+           /*
+            * Calculate the alpha combination.
+            */
+            switch (texUnit->CombineModeA) {
+            case GL_REPLACE:
+               /*
+                * The formula is: Arg0
+                * We implement this by the formula:
+                *   (Arg0 + 0(0))*(1-0) + 0
+                */
+                TEXENV_SETUP_ARG_A(A_A,
+                                   texUnit->CombineSourceA[0],
+                                   texUnit->CombineOperandA[0],
+                                   incomingAlpha);
+                TEXENV_SETUP_MODE_A(Amode_A,
+                                    texUnit->CombineOperandA[0]);
+                B_A = GR_CMBX_ITALPHA;
+                Bmode_A = GR_FUNC_MODE_ZERO;
+                C_A = D_A = GR_CMBX_ZERO;
+                Cinv_A = FXTRUE;
+                Dinv_A = Ginv_A = FXFALSE;
+                break;
+            case GL_MODULATE:
+               /*
+                * The formula is: Arg0 * Arg1
+                *
+                * We implement this by the formula
+                *   (Arg0 + 0(0)) * Arg1 + 0(0)
+                */
+                TEXENV_SETUP_ARG_A(A_A,
+                                   texUnit->CombineSourceA[0],
+                                   texUnit->CombineOperandA[0],
+                                   incomingAlpha);
+                TEXENV_SETUP_MODE_A(Amode_A,
+                                    texUnit->CombineOperandA[0]);
+                B_A = GR_CMBX_ZERO;
+                Bmode_A = GR_CMBX_ZERO;
+                TEXENV_SETUP_ARG_A(C_A,
+                                   texUnit->CombineSourceA[1],
+                                   texUnit->CombineOperandA[1],
+                                   incomingAlpha);
+                Cinv_A = TEXENV_OPERAND_INVERTED
+                               (texUnit->CombineOperandA[1]);
+                D_A = GR_CMBX_ZERO;
+                Dinv_A = Ginv_A = FXFALSE;
+                break;
+            case GL_ADD:
+               /*
+                * The formula is Arg0 + Arg1
+                */
+                TEXENV_SETUP_ARG_A(A_A,
+                                   texUnit->CombineSourceA[0],
+                                   texUnit->CombineOperandA[0],
+                                   incomingAlpha);
+                TEXENV_SETUP_MODE_A(Amode_A,
+                                    texUnit->CombineOperandA[0]);
+                TEXENV_SETUP_ARG_A(B_A,
+                                   texUnit->CombineSourceA[1],
+                                   texUnit->CombineOperandA[1],
+                                   incomingAlpha);
+                TEXENV_SETUP_MODE_A(Bmode_A,
+                                    texUnit->CombineOperandA[1]);
+                C_A = D_A = GR_CMBX_ZERO;
+                Cinv_A = FXTRUE;
+                Dinv_A = Ginv_A = FXFALSE;
+                break;
+            case GL_ADD_SIGNED_EXT:
+               /*
+                * The formula is: Arg0 + Arg1 - 0.5.
+                * We compute this by calculating:
+                *      (Arg0 - 1/2) + Arg1         if op0 is SRC_{COLOR,ALPHA}
+                *      Arg0 + (Arg1 - 1/2)         if op1 is SRC_{COLOR,ALPHA}
+                * If both op0 and op1 are ONE_MINUS_SRC_{COLOR,ALPHA}
+                * we cannot implement the formula properly.
+                */
+                TEXENV_SETUP_ARG_A(A_A,
+                                   texUnit->CombineSourceA[0],
+                                   texUnit->CombineOperandA[0],
+                                   incomingAlpha);
+                TEXENV_SETUP_ARG_A(B_A,
+                                   texUnit->CombineSourceA[1],
+                                   texUnit->CombineOperandA[1],
+                                   incomingAlpha);
+                if (!TEXENV_OPERAND_INVERTED(texUnit->CombineOperandA[0])) {
+                   /*
+                    * A is not inverted.  So, choose it.
+                    */
+                    Amode_A = GR_FUNC_MODE_X_MINUS_HALF;
+                    if (!TEXENV_OPERAND_INVERTED
+                            (texUnit->CombineOperandA[1])) {
+                        Bmode_A = GR_FUNC_MODE_X;
+                    } else {
+                        Bmode_A = GR_FUNC_MODE_ONE_MINUS_X;
+                    }
+                } else {
+                   /*
+                    * A is inverted, so try to subtract 1/2
+                    * from B.
+                    */
+                    Amode_A = GR_FUNC_MODE_ONE_MINUS_X;
+                    if (!TEXENV_OPERAND_INVERTED
+                            (texUnit->CombineOperandA[1])) {
+                        Bmode_A = GR_FUNC_MODE_X_MINUS_HALF;
+                    } else {
+                       /*
+                        * Both are inverted.  This is the case
+                        * we cannot handle properly.  We just
+                        * choose to not add the - 1/2.
+                        */
+                        Bmode_A = GR_FUNC_MODE_ONE_MINUS_X;
+                        return GL_FALSE;
+                    }
+                }
+                C_A = D_A = GR_CMBX_ZERO;
+                Cinv_A = FXTRUE;
+                Dinv_A = Ginv_A = FXFALSE;
+                break;
+            case GL_INTERPOLATE_EXT:
+               /*
+                * The formula is: Arg0 * Arg2 + Arg1 * (1 - Arg2).
+                * We compute this by the formula:
+                *            (Arg0 - Arg1) * Arg2 + Arg1
+                *               == Arg0 * Arg2 - Arg1 * Arg2 + Arg1
+                *               == Arg0 * Arg2 + Arg1 * (1 - Arg2)
+                * However, if both Arg1 is ONE_MINUS_X, the HW does
+                * not support it properly.
+                */
+                TEXENV_SETUP_ARG_A(A_A,
+                                   texUnit->CombineSourceA[0],
+                                   texUnit->CombineOperandA[0],
+                                   incomingAlpha);
+                TEXENV_SETUP_MODE_A(Amode_A,
+                                    texUnit->CombineOperandA[0]);
+                TEXENV_SETUP_ARG_A(B_A,
+                                   texUnit->CombineSourceA[1],
+                                   texUnit->CombineOperandA[1],
+                                   incomingAlpha);
+                if (!TEXENV_OPERAND_INVERTED(texUnit->CombineOperandA[1])) {
+                    Bmode_A = GR_FUNC_MODE_NEGATIVE_X;
+                }
+                else {
+                   /*
+                    * This case is wrong.
+                    */
+                    Bmode_A = GR_FUNC_MODE_NEGATIVE_X;
+                    return GL_FALSE;
+                }
+               /*
+                * The Source/Operand for the C value must
+                * specify some kind of alpha value.
+                */
+                TEXENV_SETUP_ARG_A(C_A,
+                                   texUnit->CombineSourceA[2],
+                                   texUnit->CombineOperandA[2],
+                                   incomingAlpha);
+                Cinv_A = FXFALSE;
+                D_A = GR_CMBX_B;
+                Dinv_A = Ginv_A = FXFALSE;
+                break;
+            default:
+               /*
+                * This is here mostly to keep from getting
+                * a compiler warning about these not being set.
+                * However, this should set all the alpha values
+                * to one.
+                */
+                A_A = B_A = C_A = D_A = GR_CMBX_ZERO;
+                Amode_A = Bmode_A = GR_FUNC_MODE_X;
+                Cinv_A = Dinv_A = FXFALSE;
+                Ginv_A = FXTRUE;
+                break;
+            }
+           /*
+            * Save the parameters.
+            */
+            env->Color.SourceA = A_RGB;
+            env->Color.ModeA = Amode_RGB;
+            env->Color.SourceB = B_RGB;
+            env->Color.ModeB = Bmode_RGB;
+            env->Color.SourceC = C_RGB;
+            env->Color.InvertC = Cinv_RGB;
+            env->Color.SourceD = D_RGB;
+            env->Color.InvertD = Dinv_RGB;
+            env->Color.Shift = Shift_RGB;
+            env->Color.Invert = Ginv_RGB;
+            env->Alpha.SourceA = A_A;
+            env->Alpha.ModeA = Amode_A;
+            env->Alpha.SourceB = B_A;
+            env->Alpha.ModeB = Bmode_A;
+            env->Alpha.SourceC = C_A;
+            env->Alpha.InvertC = Cinv_A;
+            env->Alpha.SourceD = D_A;
+            env->Alpha.InvertD = Dinv_A;
+            env->Alpha.Shift = Shift_A;
+            env->Alpha.Invert = Ginv_A;
+            env->EnvColor = PACK_RGBA32(texUnit->EnvColor[0] * 255.0F,
+                                        texUnit->EnvColor[1] * 255.0F,
+                                        texUnit->EnvColor[2] * 255.0F,
+                                        texUnit->EnvColor[3] * 255.0F);
+        }
+        break;
+
+    default:
+        _mesa_problem(ctx, "%s: Bad envMode", __FUNCTION__);
+    }
+
+    fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_ENV;
+
+    fxMesa->ColorCombineExt.SourceA = GR_CMBX_TEXTURE_RGB;
+    fxMesa->ColorCombineExt.ModeA = GR_FUNC_MODE_X,
+    fxMesa->ColorCombineExt.SourceB = GR_CMBX_ZERO;
+    fxMesa->ColorCombineExt.ModeB = GR_FUNC_MODE_X;
+    fxMesa->ColorCombineExt.SourceC = GR_CMBX_ZERO;
+    fxMesa->ColorCombineExt.InvertC = FXTRUE;
+    fxMesa->ColorCombineExt.SourceD = GR_CMBX_ZERO;
+    fxMesa->ColorCombineExt.InvertD = FXFALSE;
+    fxMesa->ColorCombineExt.Shift = 0;
+    fxMesa->ColorCombineExt.Invert = FXFALSE;
+    fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+    fxMesa->AlphaCombineExt.SourceA = GR_CMBX_TEXTURE_ALPHA;
+    fxMesa->AlphaCombineExt.ModeA = GR_FUNC_MODE_X;
+    fxMesa->AlphaCombineExt.SourceB = GR_CMBX_ZERO;
+    fxMesa->AlphaCombineExt.ModeB = GR_FUNC_MODE_X;
+    fxMesa->AlphaCombineExt.SourceC = GR_CMBX_ZERO;
+    fxMesa->AlphaCombineExt.InvertC = FXTRUE;
+    fxMesa->AlphaCombineExt.SourceD = GR_CMBX_ZERO;
+    fxMesa->AlphaCombineExt.InvertD = FXFALSE;
+    fxMesa->AlphaCombineExt.Shift = 0;
+    fxMesa->AlphaCombineExt.Invert = FXFALSE;
+    fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+    return GL_TRUE; /* success */
+}
+
+
+
+/*
+ * Setup the Voodoo3 texture environment for a single texture unit.
+ * Return GL_TRUE for success, GL_FALSE for failure.
+ * If failure, we'll use software rendering.
+ */
+static GLboolean
+SetupSingleTexEnvVoodoo3(GLcontext *ctx, int unit,
+                         GLenum envMode, GLenum baseFormat)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GrCombineLocal_t localc, locala;
+   struct tdfx_combine alphaComb, colorComb;
+
+   if (1 /*iteratedRGBA*/)
+      localc = locala = GR_COMBINE_LOCAL_ITERATED;
+   else
+      localc = locala = GR_COMBINE_LOCAL_CONSTANT;
+
+   switch (envMode) {
+   case GL_DECAL:
+      alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+      alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+      alphaComb.Local = locala;
+      alphaComb.Other = GR_COMBINE_OTHER_NONE;
+      alphaComb.Invert = FXFALSE;
+      colorComb.Function = GR_COMBINE_FUNCTION_BLEND;
+      colorComb.Factor = GR_COMBINE_FACTOR_TEXTURE_ALPHA;
+      colorComb.Local = localc;
+      colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+      colorComb.Invert = FXFALSE;
+      break;
+   case GL_MODULATE:
+      alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      alphaComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+      alphaComb.Local = locala;
+      alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+      alphaComb.Invert = FXFALSE;
+      if (baseFormat == GL_ALPHA) {
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_NONE;
+         colorComb.Invert = FXFALSE;
+      }
+      else {
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         colorComb.Invert = FXFALSE;
+      }
+      break;
+
+   case GL_BLEND:
+      /*
+       * XXX we can't do real GL_BLEND mode.  These settings assume that
+       * the TexEnv color is black and incoming fragment color is white.
+       */
+      if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+         /* Av = Af */
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_NONE;
+         alphaComb.Invert = FXFALSE;
+      }
+      else if (baseFormat == GL_INTENSITY) {
+         /* Av = Af * (1 - It) + Ac * It */
+         /* XXX this is wrong */
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_NONE;
+         alphaComb.Invert = FXFALSE;
+      }
+      else {
+         /* Av = Af * At */
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         alphaComb.Invert = FXFALSE;
+      }
+      if (baseFormat == GL_ALPHA) {
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_NONE;
+         colorComb.Invert = FXFALSE;
+      }
+      else {
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor = GR_COMBINE_FACTOR_ONE;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         colorComb.Invert = FXTRUE;
+      }
+      /* XXX return GL_FALSE for modes we don't support */
+      break;
+
+   case GL_REPLACE:
+      if ((baseFormat == GL_RGB) || (baseFormat == GL_LUMINANCE)) {
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_NONE;
+         alphaComb.Invert = FXFALSE;
+      }
+      else {
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor = GR_COMBINE_FACTOR_ONE;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         alphaComb.Invert = FXFALSE;
+      }
+      if (baseFormat == GL_ALPHA) {
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_NONE;
+         colorComb.Invert = FXFALSE;
+      }
+      else {
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor = GR_COMBINE_FACTOR_ONE;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         colorComb.Invert = FXFALSE;
+      }
+      break;
+
+   case GL_ADD:
+      if (baseFormat == GL_ALPHA ||
+          baseFormat == GL_LUMINANCE_ALPHA ||
+          baseFormat == GL_RGBA) {
+         /* product of texel and fragment alpha */
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         alphaComb.Invert = FXFALSE;
+      }
+      else if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+         /* fragment alpha is unchanged */
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_NONE;
+         alphaComb.Invert = FXFALSE;
+      }
+      else {
+         ASSERT(baseFormat == GL_INTENSITY);
+         /* sum of texel and fragment alpha */
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
+         alphaComb.Factor = GR_COMBINE_FACTOR_ONE;
+         alphaComb.Local = locala;
+         alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         alphaComb.Invert = FXFALSE;
+      }
+      if (baseFormat == GL_ALPHA) {
+         /* rgb unchanged */
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_NONE;
+         colorComb.Invert = FXFALSE;
+      }
+      else {
+         /* sum of texel and fragment rgb */
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
+         colorComb.Factor = GR_COMBINE_FACTOR_ONE;
+         colorComb.Local = localc;
+         colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+         colorComb.Invert = FXFALSE;
+      }
+      break;
+
+   default:
+      _mesa_problem(ctx, "bad texture env mode in %s", __FUNCTION__);
+   }
+
+   if (colorComb.Function != fxMesa->ColorCombine.Function ||
+       colorComb.Factor != fxMesa->ColorCombine.Factor ||
+       colorComb.Local != fxMesa->ColorCombine.Local ||
+       colorComb.Other != fxMesa->ColorCombine.Other ||
+       colorComb.Invert != fxMesa->ColorCombine.Invert) {
+      fxMesa->ColorCombine = colorComb;
+      fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+   }
+
+   if (alphaComb.Function != fxMesa->AlphaCombine.Function ||
+       alphaComb.Factor != fxMesa->AlphaCombine.Factor ||
+       alphaComb.Local != fxMesa->AlphaCombine.Local ||
+       alphaComb.Other != fxMesa->AlphaCombine.Other ||
+       alphaComb.Invert != fxMesa->AlphaCombine.Invert) {
+      fxMesa->AlphaCombine = alphaComb;
+      fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+   }
+   return GL_TRUE;
+}
+
+
+/*
+ * Setup the Voodoo3 texture environment for dual texture units.
+ * Return GL_TRUE for success, GL_FALSE for failure.
+ * If failure, we'll use software rendering.
+ */
+static GLboolean
+SetupDoubleTexEnvVoodoo3(GLcontext *ctx, int tmu0,
+                         GLenum envMode0, GLenum baseFormat0,
+                         GLenum envMode1, GLenum baseFormat1)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   const GrCombineLocal_t locala = GR_COMBINE_LOCAL_ITERATED;
+   const GrCombineLocal_t localc = GR_COMBINE_LOCAL_ITERATED;
+   const int tmu1 = 1 - tmu0;
+
+   if (envMode0 == GL_MODULATE && envMode1 == GL_MODULATE) {
+      GLboolean isalpha[TDFX_NUM_TMU];
+
+      if (baseFormat0 == GL_ALPHA)
+         isalpha[tmu0] = GL_TRUE;
+      else
+         isalpha[tmu0] = GL_FALSE;
+
+      if (baseFormat1 == GL_ALPHA)
+         isalpha[tmu1] = GL_TRUE;
+      else
+         isalpha[tmu1] = GL_FALSE;
+
+      if (isalpha[TDFX_TMU1]) {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_ZERO;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXTRUE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+      }
+      else {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+      }
+      if (isalpha[TDFX_TMU0]) {
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+      else {
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+      fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+      fxMesa->ColorCombine.Local = localc;
+      fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+      fxMesa->ColorCombine.Invert = FXFALSE;
+      fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+      fxMesa->AlphaCombine.Local = locala;
+      fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+      fxMesa->AlphaCombine.Invert = FXFALSE;
+   }
+   else if (envMode0 == GL_REPLACE && envMode1 == GL_BLEND) { /* Quake */
+      if (tmu1 == TDFX_TMU1) {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXTRUE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+      else {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE_MINUS_LOCAL;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE_MINUS_LOCAL;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+      fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_ONE;
+      fxMesa->ColorCombine.Local = localc;
+      fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+      fxMesa->ColorCombine.Invert = FXFALSE;
+      fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+      fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_NONE;
+      fxMesa->AlphaCombine.Local = locala;
+      fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+      fxMesa->AlphaCombine.Invert = FXFALSE;
+   }
+   else if (envMode0 == GL_REPLACE && envMode1 == GL_MODULATE) {
+      /* Quake 2/3 */
+      if (tmu1 == TDFX_TMU1) {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[1].InvertAlpha = FXTRUE;
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+      else {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+
+      fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_ONE;
+      fxMesa->ColorCombine.Local = localc;
+      fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+      fxMesa->ColorCombine.Invert = FXFALSE;
+      if (baseFormat0 == GL_RGB) {
+         fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_NONE;
+         fxMesa->AlphaCombine.Local = locala;
+         fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+         fxMesa->AlphaCombine.Invert = FXFALSE;
+      }
+      else {
+         fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_ONE;
+         fxMesa->AlphaCombine.Local = locala;
+         fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+         fxMesa->AlphaCombine.Invert = FXFALSE;
+      }
+   }
+   else if (envMode0 == GL_MODULATE && envMode1 == GL_ADD) {
+      /* Quake 3 sky */
+      GLboolean isalpha[TDFX_NUM_TMU];
+      if (baseFormat0 == GL_ALPHA)
+         isalpha[tmu0] = GL_TRUE;
+      else
+         isalpha[tmu0] = GL_FALSE;
+      if (baseFormat1 == GL_ALPHA)
+         isalpha[tmu1] = GL_TRUE;
+      else
+         isalpha[tmu1] = GL_FALSE;
+
+      if (isalpha[TDFX_TMU1]) {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_ZERO;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXTRUE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+      }
+      else {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+      }
+      if (isalpha[TDFX_TMU0]) {
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+      else {
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+      }
+      fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+      fxMesa->ColorCombine.Local = localc;
+      fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+      fxMesa->ColorCombine.Invert = FXFALSE;
+      fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+      fxMesa->AlphaCombine.Local = locala;
+      fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+      fxMesa->AlphaCombine.Invert = FXFALSE;
+   }
+   else {
+      /*_mesa_problem(ctx, "%s: Unexpected dual texture mode encountered", __FUNCTION__);*/
+      return GL_FALSE;
+   }
+
+   fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_ENV;
+   fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+   fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+   return GL_TRUE;
+}
+
+
+/*
+ * This function makes sure that the correct mipmap levels are loaded
+ * in the right places in memory and then makes the Glide calls to
+ * setup the texture source pointers.
+ */
+static void
+setupSingleTMU(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
+{
+   struct tdfxSharedState *shared = (struct tdfxSharedState *) fxMesa->glCtx->Shared->DriverData;
+   tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+   const GLcontext *ctx = fxMesa->glCtx;
+
+   /* Make sure we're not loaded incorrectly */
+   if (ti->isInTM && !shared->umaTexMemory) {
+      /* if doing filtering between mipmap levels, alternate mipmap levels
+       * must be in alternate TMUs.
+       */
+      if (ti->LODblend) {
+         if (ti->whichTMU != TDFX_TMU_SPLIT)
+            tdfxTMMoveOutTM_NoLock(fxMesa, tObj);
+      }
+      else {
+         if (ti->whichTMU == TDFX_TMU_SPLIT)
+            tdfxTMMoveOutTM_NoLock(fxMesa, tObj);
+      }
+   }
+
+   /* Make sure we're loaded correctly */
+   if (!ti->isInTM) {
+      /* Have to download the texture */
+      if (shared->umaTexMemory) {
+         tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU0);
+      }
+      else {
+         /* Voodoo3 (split texture memory) */
+         if (ti->LODblend) {
+            tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU_SPLIT);
+         }
+         else {
+#if 0
+            /* XXX putting textures into the second memory bank when the
+             * first bank is full is not working at this time.
+             */
+            if (fxMesa->haveTwoTMUs) {
+               GLint memReq = fxMesa->Glide.grTexTextureMemRequired(
+                                       GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
+               if (shared->freeTexMem[TDFX_TMU0] > memReq) {
+                  tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU0);
+               }
+               else {
+                  tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU1);
+               }
+            }
+            else
+#endif
+            {
+               tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU0);
+            }
+         }
+      }
+   }
+
+   if (ti->LODblend && ti->whichTMU == TDFX_TMU_SPLIT) {
+      /* mipmap levels split between texture banks */
+      GLint u;
+
+      if (ti->info.format == GR_TEXFMT_P_8 && !ctx->Texture.SharedPalette) {
+         fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+         fxMesa->TexPalette.Data = &(ti->palette);
+         fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+      }
+
+      for (u = 0; u < 2; u++) {
+         fxMesa->TexParams[u].sClamp = ti->sClamp;
+         fxMesa->TexParams[u].tClamp = ti->tClamp;
+         fxMesa->TexParams[u].minFilt = ti->minFilt;
+         fxMesa->TexParams[u].magFilt = ti->magFilt;
+         fxMesa->TexParams[u].mmMode = ti->mmMode;
+         fxMesa->TexParams[u].LODblend = ti->LODblend;
+         fxMesa->TexParams[u].LodBias = ctx->Texture.Unit[u].LodBias;
+      }
+      fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+
+      fxMesa->TexSource[0].StartAddress = ti->tm[TDFX_TMU0]->startAddr;
+      fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_ODD;
+      fxMesa->TexSource[0].Info = &(ti->info);
+      fxMesa->TexSource[1].StartAddress = ti->tm[TDFX_TMU1]->startAddr;
+      fxMesa->TexSource[1].EvenOdd = GR_MIPMAPLEVELMASK_EVEN;
+      fxMesa->TexSource[1].Info = &(ti->info);
+      fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+   }
+   else {
+      FxU32 tmu;
+
+      if (ti->whichTMU == TDFX_TMU_BOTH)
+         tmu = TDFX_TMU0;
+      else
+         tmu = ti->whichTMU;
+
+      if (shared->umaTexMemory) {
+         assert(ti->whichTMU == TDFX_TMU0);
+         assert(tmu == TDFX_TMU0);
+      }
+
+      if (ti->info.format == GR_TEXFMT_P_8 && !ctx->Texture.SharedPalette) {
+         fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+         fxMesa->TexPalette.Data = &(ti->palette);
+         fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+      }
+
+      /* KW: The alternative is to do the download to the other tmu.  If
+       * we get to this point, I think it means we are thrashing the
+       * texture memory, so perhaps it's not a good idea.
+       */
+
+      if (fxMesa->TexParams[tmu].sClamp != ti->sClamp ||
+          fxMesa->TexParams[tmu].tClamp != ti->tClamp ||
+          fxMesa->TexParams[tmu].minFilt != ti->minFilt ||
+          fxMesa->TexParams[tmu].magFilt != ti->magFilt ||
+          fxMesa->TexParams[tmu].mmMode != ti->mmMode ||
+          fxMesa->TexParams[tmu].LODblend != FXFALSE ||
+          fxMesa->TexParams[tmu].LodBias != ctx->Texture.Unit[tmu].LodBias) {
+         fxMesa->TexParams[tmu].sClamp = ti->sClamp;
+         fxMesa->TexParams[tmu].tClamp = ti->tClamp;
+         fxMesa->TexParams[tmu].minFilt = ti->minFilt;
+         fxMesa->TexParams[tmu].magFilt = ti->magFilt;
+         fxMesa->TexParams[tmu].mmMode = ti->mmMode;
+         fxMesa->TexParams[tmu].LODblend = FXFALSE;
+         fxMesa->TexParams[tmu].LodBias = ctx->Texture.Unit[tmu].LodBias;
+         fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+      }
+
+      /* Glide texture source info */
+      fxMesa->TexSource[0].Info = NULL;
+      fxMesa->TexSource[1].Info = NULL;
+      if (ti->tm[tmu]) {
+         fxMesa->TexSource[tmu].StartAddress = ti->tm[tmu]->startAddr;
+         fxMesa->TexSource[tmu].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+         fxMesa->TexSource[tmu].Info = &(ti->info);
+         fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+      }
+   }
+
+   fxMesa->sScale0 = ti->sScale;
+   fxMesa->tScale0 = ti->tScale;
+}
+
+static void
+selectSingleTMUSrc(tdfxContextPtr fxMesa, GLint tmu, FxBool LODblend)
+{
+   if (LODblend) {
+      fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND;
+      fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION;
+      fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND;
+      fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION;
+      fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+      fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+
+      if (fxMesa->haveTwoTMUs) {
+         const struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+         const struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+         int tmu;
+
+         if (shared->umaTexMemory)
+            tmu = GR_TMU0;
+         else
+            tmu = GR_TMU1;
+
+         fxMesa->TexCombine[tmu].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[tmu].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[tmu].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[tmu].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[tmu].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[tmu].InvertAlpha = FXFALSE;
+      }
+      fxMesa->tmuSrc = TDFX_TMU_SPLIT;
+   }
+   else {
+      if (tmu != TDFX_TMU1) {
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+         if (fxMesa->haveTwoTMUs) {
+            fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_ZERO;
+            fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+            fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+            fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+            fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+            fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+         }
+         fxMesa->tmuSrc = TDFX_TMU0;
+      }
+      else {
+         fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+         fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+         /* GR_COMBINE_FUNCTION_SCALE_OTHER doesn't work ?!? */
+         fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND;
+         fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND;
+         fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+         fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+         fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+         fxMesa->tmuSrc = TDFX_TMU1;
+      }
+   }
+
+   fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_ENV;
+}
+
+static void print_state(tdfxContextPtr fxMesa)
+{
+   GLcontext *ctx = fxMesa->glCtx;
+   struct gl_texture_object *tObj0 = ctx->Texture.Unit[0].Current2D;
+   struct gl_texture_object *tObj1 = ctx->Texture.Unit[1].Current2D;
+   GLenum base0 = tObj0->Image[tObj0->BaseLevel] ? tObj0->Image[tObj0->BaseLevel]->Format : 99;
+   GLenum base1 = tObj1->Image[tObj1->BaseLevel] ? tObj1->Image[tObj1->BaseLevel]->Format : 99;
+
+   printf("Unit 0: Enabled:  GL=%d   Gr=%d\n", ctx->Texture.Unit[0]._ReallyEnabled,
+          fxMesa->TexState.Enabled[0]);
+   printf("   EnvMode: GL=0x%x  Gr=0x%x\n", ctx->Texture.Unit[0].EnvMode,
+          fxMesa->TexState.EnvMode[0]);
+   printf("   BaseFmt: GL=0x%x  Gr=0x%x\n", base0, fxMesa->TexState.TexFormat[0]);
+
+
+   printf("Unit 1: Enabled:  GL=%d  Gr=%d\n", ctx->Texture.Unit[1]._ReallyEnabled,
+          fxMesa->TexState.Enabled[1]);
+   printf("   EnvMode: GL=0x%x  Gr:0x%x\n", ctx->Texture.Unit[1].EnvMode,
+          fxMesa->TexState.EnvMode[1]);
+   printf("   BaseFmt: GL=0x%x  Gr:0x%x\n", base1, fxMesa->TexState.TexFormat[1]);
+}
+
+
+/*
+ * When we're only using a single texture unit, we always use the 0th
+ * Glide/hardware unit, regardless if it's GL_TEXTURE0_ARB or GL_TEXTURE1_ARB
+ * that's enalbed.
+ * Input:  ctx - the context
+ *         unit - the OpenGL texture unit to use.
+ */
+static void setupTextureSingleTMU(GLcontext * ctx, GLuint unit)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   tdfxTexInfo *ti;
+   struct gl_texture_object *tObj;
+   int tmu;
+   GLenum envMode, baseFormat;
+
+   tObj = ctx->Texture.Unit[unit].Current2D;
+   if (tObj->Image[tObj->BaseLevel]->Border > 0) {
+      FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_BORDER, GL_TRUE);
+      return;
+   }
+
+   setupSingleTMU(fxMesa, tObj);
+
+   ti = TDFX_TEXTURE_DATA(tObj);
+   if (ti->whichTMU == TDFX_TMU_BOTH)
+      tmu = TDFX_TMU0;
+   else
+      tmu = ti->whichTMU;
+
+   if (fxMesa->tmuSrc != tmu) {
+      selectSingleTMUSrc(fxMesa, tmu, ti->LODblend);
+   }
+
+   if (ti->reloadImages)
+      fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_IMAGES;
+
+   /* Check if we really need to update the texenv state */
+   envMode = ctx->Texture.Unit[unit].EnvMode;
+   baseFormat = tObj->Image[tObj->BaseLevel]->Format;
+
+   if (TDFX_IS_NAPALM(fxMesa)) {
+      /* see if we really need to update the unit */
+      if (fxMesa->TexState.Enabled[unit] != ctx->Texture.Unit[unit]._ReallyEnabled ||
+          envMode != fxMesa->TexState.EnvMode[0] ||
+          envMode == GL_COMBINE_EXT ||
+          baseFormat != fxMesa->TexState.TexFormat[0]) {
+         struct tdfx_texcombine_ext *otherEnv;
+         if (!SetupTexEnvNapalm(ctx, GL_TRUE,
+                                &ctx->Texture.Unit[unit], baseFormat,
+                                &fxMesa->TexCombineExt[0])) {
+            /* software fallback */
+            FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+         }
+         /* disable other unit */
+         otherEnv = &fxMesa->TexCombineExt[1];
+         otherEnv->Color.SourceA = GR_CMBX_ZERO;
+         otherEnv->Color.ModeA = GR_FUNC_MODE_ZERO;
+         otherEnv->Color.SourceB = GR_CMBX_ZERO;
+         otherEnv->Color.ModeB = GR_FUNC_MODE_ZERO;
+         otherEnv->Color.SourceC = GR_CMBX_ZERO;
+         otherEnv->Color.InvertC = FXFALSE;
+         otherEnv->Color.SourceD = GR_CMBX_ZERO;
+         otherEnv->Color.InvertD = FXFALSE;
+         otherEnv->Color.Shift = 0;
+         otherEnv->Color.Invert = FXFALSE;
+         otherEnv->Alpha.SourceA = GR_CMBX_ITALPHA;
+         otherEnv->Alpha.ModeA = GR_FUNC_MODE_ZERO;
+         otherEnv->Alpha.SourceB = GR_CMBX_ITALPHA;
+         otherEnv->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+         otherEnv->Alpha.SourceC = GR_CMBX_ZERO;
+         otherEnv->Alpha.InvertC = FXFALSE;
+         otherEnv->Alpha.SourceD = GR_CMBX_ZERO;
+         otherEnv->Alpha.InvertD = FXFALSE;
+         otherEnv->Alpha.Shift = 0;
+         otherEnv->Alpha.Invert = FXFALSE;
+
+         fxMesa->TexState.Enabled[unit] = ctx->Texture.Unit[unit]._ReallyEnabled;
+         fxMesa->TexState.EnvMode[0] = envMode;
+         fxMesa->TexState.TexFormat[0] = baseFormat;
+         fxMesa->TexState.EnvMode[1] = 0;
+         fxMesa->TexState.TexFormat[1] = 0;
+      }
+   }
+   else {
+      /* Voodoo3 */
+
+      /* see if we really need to update the unit */
+      if (fxMesa->TexState.Enabled[unit] != ctx->Texture.Unit[unit]._ReallyEnabled ||
+          envMode != fxMesa->TexState.EnvMode[0] ||
+          envMode == GL_COMBINE_EXT ||
+          baseFormat != fxMesa->TexState.TexFormat[0]) {
+         if (!SetupSingleTexEnvVoodoo3(ctx, tmu, envMode, baseFormat)) {
+            /* software fallback */
+            FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+         }
+         fxMesa->TexState.Enabled[unit] = ctx->Texture.Unit[unit]._ReallyEnabled;
+         fxMesa->TexState.EnvMode[0] = envMode;
+         fxMesa->TexState.TexFormat[0] = baseFormat;
+         fxMesa->TexState.EnvMode[1] = 0;
+         fxMesa->TexState.TexFormat[1] = 0;
+      }
+   }
+}
+
+
+static void
+setupDoubleTMU(tdfxContextPtr fxMesa,
+               struct gl_texture_object *tObj0,
+               struct gl_texture_object *tObj1)
+{
+#define T0_NOT_IN_TMU  0x01
+#define T1_NOT_IN_TMU  0x02
+#define T0_IN_TMU0     0x04
+#define T1_IN_TMU0     0x08
+#define T0_IN_TMU1     0x10
+#define T1_IN_TMU1     0x20
+
+    const struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    const struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+    const GLcontext *ctx = fxMesa->glCtx;
+    tdfxTexInfo *ti0 = TDFX_TEXTURE_DATA(tObj0);
+    tdfxTexInfo *ti1 = TDFX_TEXTURE_DATA(tObj1);
+    GLuint tstate = 0;
+    int tmu0 = 0, tmu1 = 1;
+
+    if (shared->umaTexMemory) {
+       if (!ti0->isInTM) {
+          tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU0);
+          assert(ti0->isInTM);
+       }
+       if (!ti1->isInTM) {
+          tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU0);
+          assert(ti1->isInTM);
+       }
+    }
+    else {
+       /* We shouldn't need to do this. There is something wrong with
+          multitexturing when the TMUs are swapped. So, we're forcing
+          them to always be loaded correctly. !!! */
+       if (ti0->whichTMU == TDFX_TMU1)
+           tdfxTMMoveOutTM_NoLock(fxMesa, tObj0);
+       if (ti1->whichTMU == TDFX_TMU0)
+           tdfxTMMoveOutTM_NoLock(fxMesa, tObj1);
+
+       if (ti0->isInTM) {
+           switch (ti0->whichTMU) {
+           case TDFX_TMU0:
+               tstate |= T0_IN_TMU0;
+               break;
+           case TDFX_TMU1:
+               tstate |= T0_IN_TMU1;
+               break;
+           case TDFX_TMU_BOTH:
+               tstate |= T0_IN_TMU0 | T0_IN_TMU1;
+               break;
+           case TDFX_TMU_SPLIT:
+               tstate |= T0_NOT_IN_TMU;
+               break;
+           }
+       }
+       else
+           tstate |= T0_NOT_IN_TMU;
+
+       if (ti1->isInTM) {
+           switch (ti1->whichTMU) {
+           case TDFX_TMU0:
+               tstate |= T1_IN_TMU0;
+               break;
+           case TDFX_TMU1:
+               tstate |= T1_IN_TMU1;
+               break;
+           case TDFX_TMU_BOTH:
+               tstate |= T1_IN_TMU0 | T1_IN_TMU1;
+               break;
+           case TDFX_TMU_SPLIT:
+               tstate |= T1_NOT_IN_TMU;
+               break;
+           }
+       }
+       else
+           tstate |= T1_NOT_IN_TMU;
+
+       /* Move texture maps into TMUs */
+
+       if (!(((tstate & T0_IN_TMU0) && (tstate & T1_IN_TMU1)) ||
+             ((tstate & T0_IN_TMU1) && (tstate & T1_IN_TMU0)))) {
+           if (tObj0 == tObj1) {
+              tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU_BOTH);
+           }
+           else {
+               /* Find the minimal way to correct the situation */
+               if ((tstate & T0_IN_TMU0) || (tstate & T1_IN_TMU1)) {
+                   /* We have one in the standard order, setup the other */
+                   if (tstate & T0_IN_TMU0) {
+                      /* T0 is in TMU0, put T1 in TMU1 */
+                      tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU1);
+                   }
+                   else {
+                       tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU0);
+                   }
+                   /* tmu0 and tmu1 are setup */
+               }
+               else if ((tstate & T0_IN_TMU1) || (tstate & T1_IN_TMU0)) {
+                   /* we have one in the reverse order, setup the other */
+                   if (tstate & T1_IN_TMU0) {
+                      /* T1 is in TMU0, put T0 in TMU1 */
+                      tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU1);
+                   }
+                   else {
+                       tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU0);
+                   }
+                   tmu0 = 1;
+                   tmu1 = 0;
+               }
+               else {              /* Nothing is loaded */
+                   tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU0);
+                   tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU1);
+                   /* tmu0 and tmu1 are setup */
+               }
+           }
+       }
+    }
+
+    ti0->lastTimeUsed = fxMesa->texBindNumber;
+    ti1->lastTimeUsed = fxMesa->texBindNumber;
+
+
+    if (!ctx->Texture.SharedPalette) {
+        if (ti0->info.format == GR_TEXFMT_P_8) {
+            fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+            fxMesa->TexPalette.Data = &(ti0->palette);
+            fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+        }
+        else if (ti1->info.format == GR_TEXFMT_P_8) {
+            fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+            fxMesa->TexPalette.Data = &(ti1->palette);
+            fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+        }
+        else {
+            fxMesa->TexPalette.Data = NULL;
+        }
+    }
+
+    /*
+     * Setup Unit 0
+     */
+    assert(ti0->isInTM);
+    assert(ti0->tm[tmu0]);
+    fxMesa->TexSource[tmu0].StartAddress = ti0->tm[tmu0]->startAddr;
+    fxMesa->TexSource[tmu0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+    fxMesa->TexSource[tmu0].Info = &(ti0->info);
+    fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+
+    if (fxMesa->TexParams[tmu0].sClamp != ti0->sClamp ||
+        fxMesa->TexParams[tmu0].tClamp != ti0->tClamp ||
+        fxMesa->TexParams[tmu0].minFilt != ti0->minFilt ||
+        fxMesa->TexParams[tmu0].magFilt != ti0->magFilt ||
+        fxMesa->TexParams[tmu0].mmMode != ti0->mmMode ||
+        fxMesa->TexParams[tmu0].LODblend != FXFALSE ||
+        fxMesa->TexParams[tmu0].LodBias != ctx->Texture.Unit[tmu0].LodBias) {
+       fxMesa->TexParams[tmu0].sClamp = ti0->sClamp;
+       fxMesa->TexParams[tmu0].tClamp = ti0->tClamp;
+       fxMesa->TexParams[tmu0].minFilt = ti0->minFilt;
+       fxMesa->TexParams[tmu0].magFilt = ti0->magFilt;
+       fxMesa->TexParams[tmu0].mmMode = ti0->mmMode;
+       fxMesa->TexParams[tmu0].LODblend = FXFALSE;
+       fxMesa->TexParams[tmu0].LodBias = ctx->Texture.Unit[tmu0].LodBias;
+       fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+    }
+
+    /*
+     * Setup Unit 1
+     */
+    if (shared->umaTexMemory) {
+        ASSERT(ti1->isInTM);
+        ASSERT(ti1->tm[0]);
+        fxMesa->TexSource[tmu1].StartAddress = ti1->tm[0]->startAddr;
+        fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+        fxMesa->TexSource[tmu1].Info = &(ti1->info);
+    }
+    else {
+        ASSERT(ti1->isInTM);
+        ASSERT(ti1->tm[tmu1]);
+        fxMesa->TexSource[tmu1].StartAddress = ti1->tm[tmu1]->startAddr;
+        fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+        fxMesa->TexSource[tmu1].Info = &(ti1->info);
+    }
+
+    if (fxMesa->TexParams[tmu1].sClamp != ti1->sClamp ||
+        fxMesa->TexParams[tmu1].tClamp != ti1->tClamp ||
+        fxMesa->TexParams[tmu1].minFilt != ti1->minFilt ||
+        fxMesa->TexParams[tmu1].magFilt != ti1->magFilt ||
+        fxMesa->TexParams[tmu1].mmMode != ti1->mmMode ||
+        fxMesa->TexParams[tmu1].LODblend != FXFALSE ||
+        fxMesa->TexParams[tmu1].LodBias != ctx->Texture.Unit[tmu1].LodBias) {
+       fxMesa->TexParams[tmu1].sClamp = ti1->sClamp;
+       fxMesa->TexParams[tmu1].tClamp = ti1->tClamp;
+       fxMesa->TexParams[tmu1].minFilt = ti1->minFilt;
+       fxMesa->TexParams[tmu1].magFilt = ti1->magFilt;
+       fxMesa->TexParams[tmu1].mmMode = ti1->mmMode;
+       fxMesa->TexParams[tmu1].LODblend = FXFALSE;
+       fxMesa->TexParams[tmu1].LodBias = ctx->Texture.Unit[tmu1].LodBias;
+       fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+    }
+
+    fxMesa->sScale0 = ti0->sScale;
+    fxMesa->tScale0 = ti0->tScale;
+    fxMesa->sScale1 = ti1->sScale;
+    fxMesa->tScale1 = ti1->tScale;
+
+#undef T0_NOT_IN_TMU
+#undef T1_NOT_IN_TMU
+#undef T0_IN_TMU0
+#undef T1_IN_TMU0
+#undef T0_IN_TMU1
+#undef T1_IN_TMU1
+}
+
+static void setupTextureDoubleTMU(GLcontext * ctx)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   struct gl_texture_object *tObj0 = ctx->Texture.Unit[0].Current2D;
+   struct gl_texture_object *tObj1 = ctx->Texture.Unit[1].Current2D;
+   tdfxTexInfo *ti0 = TDFX_TEXTURE_DATA(tObj0);
+   tdfxTexInfo *ti1 = TDFX_TEXTURE_DATA(tObj1);
+   struct gl_texture_image *baseImage0 = tObj0->Image[tObj0->BaseLevel];
+   struct gl_texture_image *baseImage1 = tObj1->Image[tObj1->BaseLevel];
+   const GLenum envMode0 = ctx->Texture.Unit[0].EnvMode;
+   const GLenum envMode1 = ctx->Texture.Unit[1].EnvMode;
+
+   if (baseImage0->Border > 0 || baseImage1->Border > 0) {
+      FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_BORDER, GL_TRUE);
+      return;
+   }
+
+   setupDoubleTMU(fxMesa, tObj0, tObj1);
+
+   if (ti0->reloadImages || ti1->reloadImages)
+      fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_IMAGES;
+
+   fxMesa->tmuSrc = TDFX_TMU_BOTH;
+
+   if (TDFX_IS_NAPALM(fxMesa)) {
+      /* Remember, Glide has its texture units numbered in backward
+       * order compared to OpenGL.
+       */
+      GLboolean hw1 = GL_TRUE, hw2 = GL_TRUE;
+
+      /* check if we really need to update glide unit 1 */
+      if (fxMesa->TexState.Enabled[0] != ctx->Texture.Unit[0]._ReallyEnabled ||
+          envMode0 != fxMesa->TexState.EnvMode[1] ||
+          envMode0 == GL_COMBINE_EXT ||
+          baseImage0->Format != fxMesa->TexState.TexFormat[1] ||
+          (fxMesa->Fallback & TDFX_FALLBACK_TEXTURE_ENV)) {
+         hw1 = SetupTexEnvNapalm(ctx, GL_TRUE, &ctx->Texture.Unit[0],
+                                baseImage0->Format, &fxMesa->TexCombineExt[1]);
+         fxMesa->TexState.EnvMode[1] = envMode0;
+         fxMesa->TexState.TexFormat[1] = baseImage0->Format;
+         fxMesa->TexState.Enabled[0] = ctx->Texture.Unit[0]._ReallyEnabled;
+      }
+
+      /* check if we really need to update glide unit 0 */
+      if (fxMesa->TexState.Enabled[1] != ctx->Texture.Unit[1]._ReallyEnabled ||
+          envMode1 != fxMesa->TexState.EnvMode[0] ||
+          envMode1 == GL_COMBINE_EXT ||
+          baseImage1->Format != fxMesa->TexState.TexFormat[0] ||
+          (fxMesa->Fallback & TDFX_FALLBACK_TEXTURE_ENV)) {
+         hw2 = SetupTexEnvNapalm(ctx, GL_FALSE, &ctx->Texture.Unit[1],
+                                baseImage1->Format, &fxMesa->TexCombineExt[0]);
+         fxMesa->TexState.EnvMode[0] = envMode1;
+         fxMesa->TexState.TexFormat[0] = baseImage1->Format;
+         fxMesa->TexState.Enabled[1] = ctx->Texture.Unit[1]._ReallyEnabled;
+      }
+
+
+      if (!hw1 || !hw2) {
+         FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+      }
+   }
+   else {
+      int unit0, unit1;
+      if ((ti0->whichTMU == TDFX_TMU1) || (ti1->whichTMU == TDFX_TMU0))
+         unit0 = 1;
+      else
+         unit0 = 0;
+      unit1 = 1 - unit0;
+
+      if (fxMesa->TexState.Enabled[0] != ctx->Texture.Unit[0]._ReallyEnabled ||
+          fxMesa->TexState.Enabled[1] != ctx->Texture.Unit[1]._ReallyEnabled ||
+          envMode0 != fxMesa->TexState.EnvMode[unit0] ||
+          envMode0 == GL_COMBINE_EXT ||
+          envMode1 != fxMesa->TexState.EnvMode[unit1] ||
+          envMode1 == GL_COMBINE_EXT ||
+          baseImage0->Format != fxMesa->TexState.TexFormat[unit0] ||
+          baseImage1->Format != fxMesa->TexState.TexFormat[unit1] ||
+          (fxMesa->Fallback & TDFX_FALLBACK_TEXTURE_ENV)) {
+
+         if (!SetupDoubleTexEnvVoodoo3(ctx, unit0,
+                         ctx->Texture.Unit[0].EnvMode, baseImage0->Format,
+                         ctx->Texture.Unit[1].EnvMode, baseImage1->Format)) {
+            FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+         }
+
+         fxMesa->TexState.EnvMode[unit0] = envMode0;
+         fxMesa->TexState.TexFormat[unit0] = baseImage0->Format;
+         fxMesa->TexState.EnvMode[unit1] = envMode1;
+         fxMesa->TexState.TexFormat[unit1] = baseImage1->Format;
+         fxMesa->TexState.Enabled[0] = ctx->Texture.Unit[0]._ReallyEnabled;
+         fxMesa->TexState.Enabled[1] = ctx->Texture.Unit[1]._ReallyEnabled;
+      }
+   }
+}
+
+
+void
+tdfxUpdateTextureState( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_BORDER, GL_FALSE);
+   FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_FALSE);
+
+   if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+       ctx->Texture.Unit[1]._ReallyEnabled == 0) {
+      LOCK_HARDWARE( fxMesa );  /* XXX remove locking eventually */
+      setupTextureSingleTMU(ctx, 0);
+      UNLOCK_HARDWARE( fxMesa );
+   }
+   else if (ctx->Texture.Unit[0]._ReallyEnabled == 0 && 
+            ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) {
+      LOCK_HARDWARE( fxMesa );
+      setupTextureSingleTMU(ctx, 1);
+      UNLOCK_HARDWARE( fxMesa );
+   }
+   else if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+            ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) {
+      LOCK_HARDWARE( fxMesa );
+      setupTextureDoubleTMU(ctx);
+      UNLOCK_HARDWARE( fxMesa );
+   }
+   else {
+      /* disable hardware texturing */
+      if (TDFX_IS_NAPALM(fxMesa)) {
+         fxMesa->ColorCombineExt.SourceA = GR_CMBX_ITRGB;
+         fxMesa->ColorCombineExt.ModeA = GR_FUNC_MODE_X;
+         fxMesa->ColorCombineExt.SourceB = GR_CMBX_ZERO;
+         fxMesa->ColorCombineExt.ModeB = GR_FUNC_MODE_ZERO;
+         fxMesa->ColorCombineExt.SourceC = GR_CMBX_ZERO;
+         fxMesa->ColorCombineExt.InvertC = FXTRUE;
+         fxMesa->ColorCombineExt.SourceD = GR_CMBX_ZERO;
+         fxMesa->ColorCombineExt.InvertD = FXFALSE;
+         fxMesa->ColorCombineExt.Shift = 0;
+         fxMesa->ColorCombineExt.Invert = FXFALSE;
+         fxMesa->AlphaCombineExt.SourceA = GR_CMBX_ITALPHA;
+         fxMesa->AlphaCombineExt.ModeA = GR_FUNC_MODE_X;
+         fxMesa->AlphaCombineExt.SourceB = GR_CMBX_ZERO;
+         fxMesa->AlphaCombineExt.ModeB = GR_FUNC_MODE_ZERO;
+         fxMesa->AlphaCombineExt.SourceC = GR_CMBX_ZERO;
+         fxMesa->AlphaCombineExt.InvertC = FXTRUE;
+         fxMesa->AlphaCombineExt.SourceD = GR_CMBX_ZERO;
+         fxMesa->AlphaCombineExt.InvertD = FXFALSE;
+         fxMesa->AlphaCombineExt.Shift = 0;
+         fxMesa->AlphaCombineExt.Invert = FXFALSE;
+      }
+      else {
+         /* Voodoo 3*/
+         fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_NONE;
+         fxMesa->ColorCombine.Local = GR_COMBINE_LOCAL_ITERATED;
+         fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_NONE;
+         fxMesa->ColorCombine.Invert = FXFALSE;
+         fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+         fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_NONE;
+         fxMesa->AlphaCombine.Local = GR_COMBINE_LOCAL_ITERATED;
+         fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+         fxMesa->AlphaCombine.Invert = FXFALSE;
+      }
+
+      fxMesa->TexState.Enabled[0] = 0;
+      fxMesa->TexState.Enabled[1] = 0;
+      fxMesa->TexState.EnvMode[0] = 0;
+      fxMesa->TexState.EnvMode[1] = 0;
+
+      fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+      fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+
+      if (ctx->Texture.Unit[0]._ReallyEnabled != 0 ||
+          ctx->Texture.Unit[1]._ReallyEnabled != 0) {
+         /* software texture (cube map, rect tex, etc */
+         FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+      }
+   }
+}
+
+
+
+/*
+ * This is a special case of texture state update.
+ * It's used when we've simply bound a new texture to a texture
+ * unit and the new texture has the exact same attributes as the
+ * previously bound texture.
+ * This is very common in Quake3.
+ */
+void
+tdfxUpdateTextureBinding( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   struct gl_texture_object *tObj0 = ctx->Texture.Unit[0].Current2D;
+   struct gl_texture_object *tObj1 = ctx->Texture.Unit[1].Current2D;
+   tdfxTexInfo *ti0 = TDFX_TEXTURE_DATA(tObj0);
+   tdfxTexInfo *ti1 = TDFX_TEXTURE_DATA(tObj1);
+
+    const struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+    const struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+
+   if (ti0) {
+      fxMesa->sScale0 = ti0->sScale;
+      fxMesa->tScale0 = ti0->tScale;
+      if (ti0->info.format == GR_TEXFMT_P_8) {
+         fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+         fxMesa->TexPalette.Data = &(ti0->palette);
+         fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+      }
+      else if (ti1 && ti1->info.format == GR_TEXFMT_P_8) {
+         fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+         fxMesa->TexPalette.Data = &(ti1->palette);
+         fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+      }
+   }
+   if (ti1) {
+      fxMesa->sScale1 = ti1->sScale;
+      fxMesa->tScale1 = ti1->tScale;
+   }
+
+   if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+       ctx->Texture.Unit[0]._ReallyEnabled == 0) {
+      /* Only unit 0 2D enabled */
+      if (shared->umaTexMemory) {
+         fxMesa->TexSource[0].StartAddress = ti0->tm[0]->startAddr;
+         fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+         fxMesa->TexSource[0].Info = &(ti0->info);
+      }
+      else {
+         if (ti0->LODblend && ti0->whichTMU == TDFX_TMU_SPLIT) {
+            fxMesa->TexSource[0].StartAddress = ti0->tm[TDFX_TMU0]->startAddr;
+            fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_ODD;
+            fxMesa->TexSource[0].Info = &(ti0->info);
+            fxMesa->TexSource[1].StartAddress = ti0->tm[TDFX_TMU1]->startAddr;
+            fxMesa->TexSource[1].EvenOdd = GR_MIPMAPLEVELMASK_EVEN;
+            fxMesa->TexSource[1].Info = &(ti0->info);
+         }
+         else {
+            FxU32 tmu;
+            if (ti0->whichTMU == TDFX_TMU_BOTH)
+               tmu = TDFX_TMU0;
+            else
+               tmu = ti0->whichTMU;
+            fxMesa->TexSource[0].Info = NULL;
+            fxMesa->TexSource[1].Info = NULL;
+            if (ti0->tm[tmu]) {
+               fxMesa->TexSource[tmu].StartAddress = ti0->tm[tmu]->startAddr;
+               fxMesa->TexSource[tmu].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+               fxMesa->TexSource[tmu].Info = &(ti0->info);
+            }
+         }
+      }
+   }
+   else if (ctx->Texture.Unit[0]._ReallyEnabled == 0 && 
+            ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) {
+      /* Only unit 1 2D enabled */
+      if (shared->umaTexMemory) {
+         fxMesa->TexSource[0].StartAddress = ti1->tm[0]->startAddr;
+         fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+         fxMesa->TexSource[0].Info = &(ti1->info);
+      }
+   }
+   else if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT && 
+            ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) {
+      /* Both 2D enabled */
+      if (shared->umaTexMemory) {
+         const FxU32 tmu0 = 0, tmu1 = 1;
+         fxMesa->TexSource[tmu0].StartAddress = ti0->tm[0]->startAddr;
+         fxMesa->TexSource[tmu0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+         fxMesa->TexSource[tmu0].Info = &(ti0->info);
+
+         fxMesa->TexSource[tmu1].StartAddress = ti1->tm[0]->startAddr;
+         fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+         fxMesa->TexSource[tmu1].Info = &(ti1->info);
+      }
+      else {
+         const FxU32 tmu0 = 0, tmu1 = 1;
+         fxMesa->TexSource[tmu0].StartAddress = ti0->tm[tmu0]->startAddr;
+         fxMesa->TexSource[tmu0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+         fxMesa->TexSource[tmu0].Info = &(ti0->info);
+
+         fxMesa->TexSource[tmu1].StartAddress = ti1->tm[tmu1]->startAddr;
+         fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+         fxMesa->TexSource[tmu1].Info = &(ti1->info);
+      }
+   }
+
+
+   fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_texstate.h b/src/mesa/drivers/dri/tdfx/tdfx_texstate.h
new file mode 100644 (file)
index 0000000..234ed44
--- /dev/null
@@ -0,0 +1,44 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_texstate.h,v 1.1 2002/02/22 21:45:04 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ *     Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ *     Gareth Hughes <gareth@valinux.com>
+ *     Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#ifndef __TDFX_TEXSTATE_H__
+#define __TDFX_TEXSTATE_H__
+
+extern void tdfxUpdateTextureState( GLcontext *ctx );
+extern void tdfxUpdateTextureBinding( GLcontext *ctx );
+
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_tris.c b/src/mesa/drivers/dri/tdfx/tdfx_tris.c
new file mode 100644 (file)
index 0000000..7ab25e7
--- /dev/null
@@ -0,0 +1,1258 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_tris.c,v 1.4 2002/10/30 12:52:01 alanh Exp $ */
+
+/* Authors:
+ *    Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "macros.h"
+#include "colormac.h"
+
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "swrast_setup/ss_context.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
+
+#include "tdfx_tris.h"
+#include "tdfx_state.h"
+#include "tdfx_vb.h"
+#include "tdfx_lock.h"
+#include "tdfx_render.h"
+
+
+static void tdfxRasterPrimitive( GLcontext *ctx, GLenum prim );
+static void tdfxRenderPrimitive( GLcontext *ctx, GLenum prim );
+
+/***********************************************************************
+ *          Macros for t_dd_tritmp.h to draw basic primitives          *
+ ***********************************************************************/
+
+#define TRI( a, b, c )                         \
+do {                                           \
+   if (DO_FALLBACK)                            \
+      fxMesa->draw_triangle( fxMesa, a, b, c );        \
+   else                                                \
+      fxMesa->Glide.grDrawTriangle( a, b, c ); \
+} while (0)                                    \
+
+#define QUAD( a, b, c, d )                     \
+do {                                           \
+   if (DO_FALLBACK) {                          \
+      fxMesa->draw_triangle( fxMesa, a, b, d );        \
+      fxMesa->draw_triangle( fxMesa, b, c, d );        \
+   } else {                                    \
+      fxMesa->Glide.grDrawTriangle( a, b, d ); \
+      fxMesa->Glide.grDrawTriangle( b, c, d ); \
+   }                                           \
+} while (0)
+
+#define LINE( v0, v1 )                         \
+do {                                           \
+   if (DO_FALLBACK)                            \
+      fxMesa->draw_line( fxMesa, v0, v1 );     \
+   else {                                      \
+      v0->v.x += LINE_X_OFFSET - TRI_X_OFFSET; \
+      v0->v.y += LINE_Y_OFFSET - TRI_Y_OFFSET; \
+      v1->v.x += LINE_X_OFFSET - TRI_X_OFFSET; \
+      v1->v.y += LINE_Y_OFFSET - TRI_Y_OFFSET; \
+      fxMesa->Glide.grDrawLine( v0, v1 );      \
+      v0->v.x -= LINE_X_OFFSET - TRI_X_OFFSET; \
+      v0->v.y -= LINE_Y_OFFSET - TRI_Y_OFFSET; \
+      v1->v.x -= LINE_X_OFFSET - TRI_X_OFFSET; \
+      v1->v.y -= LINE_Y_OFFSET - TRI_Y_OFFSET; \
+   }                                           \
+} while (0)
+
+#define POINT( v0 )                            \
+do {                                           \
+   if (DO_FALLBACK)                            \
+      fxMesa->draw_point( fxMesa, v0 );                \
+   else {                                      \
+      v0->v.x += PNT_X_OFFSET - TRI_X_OFFSET;  \
+      v0->v.y += PNT_Y_OFFSET - TRI_Y_OFFSET;  \
+      fxMesa->Glide.grDrawPoint( v0 );         \
+      v0->v.x -= PNT_X_OFFSET - TRI_X_OFFSET;  \
+      v0->v.y -= PNT_Y_OFFSET - TRI_Y_OFFSET;  \
+   }                                           \
+} while (0)
+
+
+/***********************************************************************
+ *              Fallback to swrast for basic primitives                *
+ ***********************************************************************/
+
+/* Build an SWvertex from a hardware vertex. 
+ *
+ * This code is hit only when a mix of accelerated and unaccelerated
+ * primitives are being drawn, and only for the unaccelerated
+ * primitives.  
+ */
+static void 
+tdfx_translate_vertex( GLcontext *ctx, const tdfxVertex *src, SWvertex *dst)
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if (fxMesa->vertexFormat == TDFX_LAYOUT_TINY) {
+      dst->win[0] = src->tv.x - fxMesa->x_offset;
+      dst->win[1] = src->tv.y - (fxMesa->screen_height - fxMesa->height - fxMesa->y_offset);
+      dst->win[2] = src->tv.z;
+      dst->win[3] = 1.0;
+
+      dst->color[0] = src->tv.color.red;
+      dst->color[1] = src->tv.color.green;
+      dst->color[2] = src->tv.color.blue;
+      dst->color[3] = src->tv.color.alpha;
+   } 
+   else {
+      GLfloat w = 1.0 / src->v.rhw;
+
+      dst->win[0] = src->v.x - fxMesa->x_offset;
+      dst->win[1] = fxMesa->screen_height - fxMesa->y_offset - src->v.y;
+      dst->win[2] = src->v.z;
+      dst->win[3] = src->v.rhw;
+
+      dst->color[0] = src->v.color.red;
+      dst->color[1] = src->v.color.green;
+      dst->color[2] = src->v.color.blue;
+      dst->color[3] = src->v.color.alpha;
+
+      if (fxMesa->vertexFormat == TDFX_LAYOUT_PROJECT) {
+        dst->texcoord[0][0] = fxMesa->sScale0 * w * src->pv.tu0;
+        dst->texcoord[0][1] = fxMesa->tScale0 * w * src->pv.tv0;
+        dst->texcoord[0][3] = w * src->pv.tq0;
+
+        if (fxMesa->SetupIndex & TDFX_TEX1_BIT) {
+           dst->texcoord[1][0] = fxMesa->sScale1 * w * src->pv.tu1;
+           dst->texcoord[1][1] = fxMesa->tScale1 * w * src->pv.tv1;
+           dst->texcoord[1][3] = w * src->pv.tq1;
+        }
+      } else if (fxMesa->SetupIndex & TDFX_TEX0_BIT) {
+        dst->texcoord[0][0] = fxMesa->sScale0 * w * src->v.tu0;
+        dst->texcoord[0][1] = fxMesa->tScale0 * w * src->v.tv0;
+        dst->texcoord[0][3] = 1.0;
+
+        if (fxMesa->SetupIndex & TDFX_TEX1_BIT) {
+           dst->texcoord[1][0] = fxMesa->sScale1 * w * src->v.tu1;
+           dst->texcoord[1][1] = fxMesa->tScale1 * w * src->v.tv1;
+           dst->texcoord[1][3] = 1.0;
+        }
+      }
+   }
+
+   dst->pointSize = ctx->Point._Size;
+}
+
+
+static void 
+tdfx_fallback_tri( tdfxContextPtr fxMesa, 
+                  tdfxVertex *v0, 
+                  tdfxVertex *v1, 
+                  tdfxVertex *v2 )
+{
+   GLcontext *ctx = fxMesa->glCtx;
+   SWvertex v[3];
+   tdfx_translate_vertex( ctx, v0, &v[0] );
+   tdfx_translate_vertex( ctx, v1, &v[1] );
+   tdfx_translate_vertex( ctx, v2, &v[2] );
+   _swrast_Triangle( ctx, &v[0], &v[1], &v[2] );
+}
+
+
+static void 
+tdfx_fallback_line( tdfxContextPtr fxMesa,
+                   tdfxVertex *v0,
+                   tdfxVertex *v1 )
+{
+   GLcontext *ctx = fxMesa->glCtx;
+   SWvertex v[2];
+   tdfx_translate_vertex( ctx, v0, &v[0] );
+   tdfx_translate_vertex( ctx, v1, &v[1] );
+   _swrast_Line( ctx, &v[0], &v[1] );
+}
+
+
+static void 
+tdfx_fallback_point( tdfxContextPtr fxMesa, 
+                    tdfxVertex *v0 )
+{
+   GLcontext *ctx = fxMesa->glCtx;
+   SWvertex v[1];
+   tdfx_translate_vertex( ctx, v0, &v[0] );
+   _swrast_Point( ctx, &v[0] );
+}
+
+/***********************************************************************
+ *                 Functions to draw basic primitives                  *
+ ***********************************************************************/
+
+static void tdfx_print_vertex( GLcontext *ctx, const tdfxVertex *v )
+{
+   tdfxContextPtr imesa = TDFX_CONTEXT( ctx );
+
+   fprintf(stderr, "vertex at %p\n", v);
+
+   if (imesa->vertexFormat == TDFX_LAYOUT_TINY) {
+      fprintf(stderr, "x %f y %f z %f\n", v->v.x, v->v.y, v->v.z);
+      fprintf(stderr, "r %d g %d b %d a %d\n", 
+             v->tv.color.red,
+             v->tv.color.green,
+             v->tv.color.blue,
+             v->tv.color.alpha);
+   } 
+   else {
+      fprintf(stderr, "x %f y %f z %f oow %f\n", 
+             v->v.x, v->v.y, v->v.z, v->v.rhw);
+      fprintf(stderr, "r %d g %d b %d a %d\n", 
+             v->v.color.red,
+             v->v.color.green,
+             v->v.color.blue,
+             v->v.color.alpha);
+   }
+   
+   fprintf(stderr, "\n");
+}
+
+#define DO_FALLBACK 0
+
+/* Need to do clip loop at each triangle when mixing swrast and hw
+ * rendering.  These functions are only used when mixed-mode rendering
+ * is occurring.
+ */
+static void tdfx_draw_quad( tdfxContextPtr fxMesa,
+                           tdfxVertexPtr v0,
+                           tdfxVertexPtr v1,
+                           tdfxVertexPtr v2,
+                           tdfxVertexPtr v3 )
+{
+/*     fprintf(stderr, "%s\n", __FUNCTION__); */
+   BEGIN_CLIP_LOOP_LOCKED(fxMesa) {
+      QUAD( v0, v1, v2, v3 );
+   } END_CLIP_LOOP_LOCKED(fxMesa);
+}
+
+static void tdfx_draw_triangle( tdfxContextPtr fxMesa,
+                               tdfxVertexPtr v0,
+                               tdfxVertexPtr v1,
+                               tdfxVertexPtr v2 )
+{
+/*     fprintf(stderr, "%s\n", __FUNCTION__); */
+/*     tdfx_print_vertex( fxMesa->glCtx, v0 ); */
+/*     tdfx_print_vertex( fxMesa->glCtx, v1 ); */
+/*     tdfx_print_vertex( fxMesa->glCtx, v2 ); */
+   BEGIN_CLIP_LOOP_LOCKED(fxMesa) {
+      TRI( v0, v1, v2 );
+   } END_CLIP_LOOP_LOCKED(fxMesa);
+}
+
+static void tdfx_draw_line( tdfxContextPtr fxMesa,
+                           tdfxVertexPtr v0,
+                           tdfxVertexPtr v1 )
+{
+   /* No support for wide lines (avoid wide/aa line fallback).
+    */
+   BEGIN_CLIP_LOOP_LOCKED(fxMesa) {
+      LINE(v0, v1);
+   } END_CLIP_LOOP_LOCKED(fxMesa);
+}
+
+static void tdfx_draw_point( tdfxContextPtr fxMesa,
+                            tdfxVertexPtr v0 )
+{
+   /* No support for wide points.
+    */
+   BEGIN_CLIP_LOOP_LOCKED(fxMesa) {
+      POINT( v0 );
+   } END_CLIP_LOOP_LOCKED(fxMesa);
+}
+
+#undef DO_FALLBACK
+
+
+#define TDFX_UNFILLED_BIT    0x1
+#define TDFX_OFFSET_BIT             0x2
+#define TDFX_TWOSIDE_BIT     0x4
+#define TDFX_FLAT_BIT        0x8
+#define TDFX_FALLBACK_BIT    0x10
+#define TDFX_MAX_TRIFUNC     0x20
+
+static struct {
+   points_func         points;
+   line_func           line;
+   triangle_func       triangle;
+   quad_func           quad;
+} rast_tab[TDFX_MAX_TRIFUNC];
+
+#define DO_FALLBACK (IND & TDFX_FALLBACK_BIT)
+#define DO_OFFSET   (IND & TDFX_OFFSET_BIT)
+#define DO_UNFILLED (IND & TDFX_UNFILLED_BIT)
+#define DO_TWOSIDE  (IND & TDFX_TWOSIDE_BIT)
+#define DO_FLAT     (IND & TDFX_FLAT_BIT)
+#define DO_TRI       1
+#define DO_QUAD      1
+#define DO_LINE      1
+#define DO_POINTS    1
+#define DO_FULL_QUAD 1
+
+#define HAVE_RGBA   1
+#define HAVE_SPEC   0
+#define HAVE_HW_FLATSHADE 0
+#define HAVE_BACK_COLORS  0
+#define VERTEX tdfxVertex
+#define TAB rast_tab
+
+#define TDFX_COLOR( dst, src )                 \
+do {                                           \
+   dst[0] = src[2];                            \
+   dst[1] = src[1];                            \
+   dst[2] = src[0];                            \
+   dst[3] = src[3];                            \
+} while (0)
+
+#define DEPTH_SCALE 1.0
+#define UNFILLED_TRI unfilled_tri
+#define UNFILLED_QUAD unfilled_quad
+#define VERT_X(_v) _v->v.x
+#define VERT_Y(_v) _v->v.y
+#define VERT_Z(_v) _v->v.z
+#define AREA_IS_CCW( a ) (a < 0)
+#define GET_VERTEX(e) (fxMesa->verts + (e<<fxMesa->vertex_stride_shift))
+
+#define VERT_SET_RGBA( v, c )    TDFX_COLOR( v->ub4[coloroffset], c )
+#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset]
+#define VERT_SAVE_RGBA( idx )    color[idx] = v[idx]->ui[coloroffset]
+#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = color[idx]   
+
+#define LOCAL_VARS(n)                                  \
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);          \
+   GLuint coloroffset = (fxMesa->vertexFormat ==       \
+                        TDFX_LAYOUT_TINY) ? 3 : 4;     \
+   GLuint color[n];                                    \
+   (void) color; (void)coloroffset
+
+
+
+/***********************************************************************
+ *            Functions to draw basic unfilled primitives              *
+ ***********************************************************************/
+
+#define RASTERIZE(x) if (fxMesa->raster_primitive != x) \
+                        tdfxRasterPrimitive( ctx, x )
+#define RENDER_PRIMITIVE fxMesa->render_primitive
+#define IND TDFX_FALLBACK_BIT
+#define TAG(x) x
+#include "tnl_dd/t_dd_unfilled.h"
+#undef IND
+
+/***********************************************************************
+ *                 Functions to draw GL primitives                     *
+ ***********************************************************************/
+
+#define IND (0)
+#define TAG(x) x
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT)
+#define TAG(x) x##_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT)
+#define TAG(x) x##_twoside
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT)
+#define TAG(x) x##_twoside_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_UNFILLED_BIT)
+#define TAG(x) x##_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT)
+#define TAG(x) x##_offset_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT)
+#define TAG(x) x##_twoside_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT)
+#define TAG(x) x##_twoside_offset_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_FALLBACK_BIT)
+#define TAG(x) x##_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT)
+#define TAG(x) x##_offset_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_FALLBACK_BIT)
+#define TAG(x) x##_twoside_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT)
+#define TAG(x) x##_twoside_offset_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT)
+#define TAG(x) x##_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT)
+#define TAG(x) x##_offset_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT)
+#define TAG(x) x##_twoside_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT| \
+            TDFX_FALLBACK_BIT)
+#define TAG(x) x##_twoside_offset_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+
+/* Tdfx doesn't support provoking-vertex flat-shading?
+ */
+#define IND (TDFX_FLAT_BIT)
+#define TAG(x) x##_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_offset_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_offset_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_UNFILLED_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_unfilled_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_offset_unfilled_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_unfilled_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_offset_unfilled_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_offset_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_offset_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_unfilled_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_offset_unfilled_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_unfilled_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT| \
+            TDFX_FALLBACK_BIT|TDFX_FLAT_BIT)
+#define TAG(x) x##_twoside_offset_unfilled_fallback_flat
+#include "tnl_dd/t_dd_tritmp.h"
+
+
+static void init_rast_tab( void )
+{
+   init();
+   init_offset();
+   init_twoside();
+   init_twoside_offset();
+   init_unfilled();
+   init_offset_unfilled();
+   init_twoside_unfilled();
+   init_twoside_offset_unfilled();
+   init_fallback();
+   init_offset_fallback();
+   init_twoside_fallback();
+   init_twoside_offset_fallback();
+   init_unfilled_fallback();
+   init_offset_unfilled_fallback();
+   init_twoside_unfilled_fallback();
+   init_twoside_offset_unfilled_fallback();
+
+   init_flat();
+   init_offset_flat();
+   init_twoside_flat();
+   init_twoside_offset_flat();
+   init_unfilled_flat();
+   init_offset_unfilled_flat();
+   init_twoside_unfilled_flat();
+   init_twoside_offset_unfilled_flat();
+   init_fallback_flat();
+   init_offset_fallback_flat();
+   init_twoside_fallback_flat();
+   init_twoside_offset_fallback_flat();
+   init_unfilled_fallback_flat();
+   init_offset_unfilled_fallback_flat();
+   init_twoside_unfilled_fallback_flat();
+   init_twoside_offset_unfilled_fallback_flat();
+}
+
+
+/**********************************************************************/
+/*                 Render whole begin/end objects                     */
+/**********************************************************************/
+
+
+/* Accelerate vertex buffer rendering when renderindex == 0 and
+ * there is no clipping.
+ */
+
+static void tdfx_render_vb_points( GLcontext *ctx,
+                                     GLuint start,
+                                     GLuint count,
+                                     GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   int stride = 1<<shift;
+   GLubyte *tmp;
+   GLint i;
+   (void) flags;
+
+   /* Adjust point coords */
+   for (i = start, tmp = fxVB; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x += PNT_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y += PNT_Y_OFFSET - TRI_Y_OFFSET;
+   }
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_POINTS, count-start,
+                                              fxVB, stride);
+   /* restore point coords */
+   for (i = start, tmp = fxVB; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x -= PNT_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y -= PNT_Y_OFFSET - TRI_Y_OFFSET;
+   }
+}
+
+static void tdfx_render_vb_line_strip( GLcontext *ctx,
+                                     GLuint start,
+                                     GLuint count,
+                                     GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   int stride = 1<<shift;
+   GLubyte *tmp;
+   GLint i;
+   (void) flags;
+
+   /* adjust line coords */
+   for (i = start, tmp = fxVB; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x += LINE_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y += LINE_Y_OFFSET - TRI_Y_OFFSET;
+   }
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_LINE_STRIP, count-start,
+                                              fxVB, 1<<shift);
+
+   /* restore line coords */
+   for (i = start, tmp = fxVB; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x -= LINE_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y -= LINE_Y_OFFSET - TRI_Y_OFFSET;
+   }
+}
+
+static void tdfx_render_vb_line_loop( GLcontext *ctx,
+                                     GLuint start,
+                                     GLuint count,
+                                     GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   int stride = 1<<shift;
+   GLubyte *tmp, *tmp2 = fxVB;
+   GLint i;
+   GLint j = start;
+   (void) flags;
+
+   if (!(flags & PRIM_BEGIN)) {
+      fxVB += (1 << shift);
+      j++;
+   }
+
+   /* adjust line coords */
+   for (i = start, tmp = tmp2; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x += LINE_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y += LINE_Y_OFFSET - TRI_Y_OFFSET;
+   }
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_LINE_STRIP, count-j,
+                                              fxVB, 1<<shift);
+
+   if (flags & PRIM_END) 
+      fxMesa->Glide.grDrawLine( fxMesa->verts + ((count - 1)<<shift), 
+                                fxMesa->verts + (start<<shift) );
+
+   /* restore line coords */
+   for (i = start, tmp = tmp2; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x -= LINE_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y -= LINE_Y_OFFSET - TRI_Y_OFFSET;
+   }
+}
+
+static void tdfx_render_vb_lines( GLcontext *ctx,
+                                     GLuint start,
+                                     GLuint count,
+                                     GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   int stride = 1<<shift;
+   GLubyte *tmp;
+   GLint i;
+   (void) flags;
+
+   /* adjust line coords */
+   for (i = start, tmp = fxVB; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x += LINE_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y += LINE_Y_OFFSET - TRI_Y_OFFSET;
+   }
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_LINES, count-start,
+                                              fxVB, 1<<shift);
+
+   /* restore line coords */
+   for (i = start, tmp = fxVB; i < count; i++, tmp += stride) {
+      ((tdfxVertexPtr)tmp)->v.x -= LINE_X_OFFSET - TRI_X_OFFSET;
+      ((tdfxVertexPtr)tmp)->v.y -= LINE_Y_OFFSET - TRI_Y_OFFSET;
+   }
+}
+
+static void tdfx_render_vb_triangles( GLcontext *ctx,
+                                     GLuint start,
+                                     GLuint count,
+                                     GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   (void) flags;
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_TRIANGLES, count-start,
+                                              fxVB, 1<<shift);
+}
+
+
+static void tdfx_render_vb_tri_strip( GLcontext *ctx,
+                                     GLuint start,
+                                     GLuint count,
+                                     GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   int mode;
+   (void) flags;
+
+/*     fprintf(stderr, "%s/%d\n", __FUNCTION__, 1<<shift); */
+/*     if(!prevLockLine) abort(); */
+
+   if (flags & PRIM_PARITY) 
+      mode = GR_TRIANGLE_STRIP_CONTINUE;
+   else
+      mode = GR_TRIANGLE_STRIP;
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( mode, count-start,
+                                              fxVB, 1<<shift);
+}
+
+
+static void tdfx_render_vb_tri_fan( GLcontext *ctx,
+                                   GLuint start,
+                                   GLuint count,
+                                   GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   (void) flags;
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_TRIANGLE_FAN, count-start,
+                                              fxVB, 1<<shift );
+}
+
+static void tdfx_render_vb_quads( GLcontext *ctx,
+                                      GLuint start,
+                                      GLuint count,
+                                      GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts;
+   GLuint i;
+   (void) flags;
+   
+   for (i = start ; i < count-3 ; i += 4 ) {
+#define VERT(x) (fxVB + ((x)<<shift))
+      fxMesa->Glide.grDrawTriangle( VERT(i),   VERT(i+1), VERT(i+3) );
+      fxMesa->Glide.grDrawTriangle( VERT(i+1), VERT(i+2), VERT(i+3) );
+#undef VERT
+   }
+}
+
+static void tdfx_render_vb_quad_strip( GLcontext *ctx,
+                                      GLuint start,
+                                      GLuint count,
+                                      GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   (void) flags;
+
+   count -= (count-start)&1;
+
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_TRIANGLE_STRIP,
+                                              count-start, fxVB, 1<<shift);
+}
+
+static void tdfx_render_vb_poly( GLcontext *ctx,
+                                GLuint start,
+                                GLuint count,
+                                GLuint flags )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint shift = fxMesa->vertex_stride_shift;
+   GLubyte *fxVB = fxMesa->verts + (start << shift);
+   (void) flags;
+   
+   fxMesa->Glide.grDrawVertexArrayContiguous( GR_POLYGON, count-start,
+                                              fxVB, 1<<shift);
+}
+
+static void tdfx_render_vb_noop( GLcontext *ctx,
+                                GLuint start,
+                                GLuint count,
+                                GLuint flags )
+{
+   (void) (ctx && start && count && flags);
+}
+
+static void (*tdfx_render_tab_verts[GL_POLYGON+2])(GLcontext *,
+                                                  GLuint,
+                                                  GLuint,
+                                                  GLuint) = 
+{
+   tdfx_render_vb_points,
+   tdfx_render_vb_lines,
+   tdfx_render_vb_line_loop,
+   tdfx_render_vb_line_strip,
+   tdfx_render_vb_triangles,
+   tdfx_render_vb_tri_strip,
+   tdfx_render_vb_tri_fan,
+   tdfx_render_vb_quads,
+   tdfx_render_vb_quad_strip,
+   tdfx_render_vb_poly,
+   tdfx_render_vb_noop,
+};
+
+
+/**********************************************************************/
+/*            Render whole (indexed) begin/end objects                */
+/**********************************************************************/
+
+
+#define VERT(x) (tdfxVertex *)(vertptr + ((x)<<vertshift))
+
+#define RENDER_POINTS( start, count )          \
+   for ( ; start < count ; start++)            \
+      fxMesa->Glide.grDrawPoint( VERT(ELT(start)) );
+
+#define RENDER_LINE( v0, v1 ) \
+   fxMesa->Glide.grDrawLine( VERT(v0), VERT(v1) )
+
+#define RENDER_TRI( v0, v1, v2 )  \
+   fxMesa->Glide.grDrawTriangle( VERT(v0), VERT(v1), VERT(v2) )
+
+#define RENDER_QUAD( v0, v1, v2, v3 ) \
+   tdfx_draw_quad( fxMesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) )
+
+#define INIT(x) tdfxRenderPrimitive( ctx, x )
+
+#undef LOCAL_VARS
+#define LOCAL_VARS                                             \
+    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);                 \
+    GLubyte *vertptr = (GLubyte *)fxMesa->verts;               \
+    const GLuint vertshift = fxMesa->vertex_stride_shift;      \
+    const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts;      \
+    (void) elt;
+
+#define RESET_STIPPLE 
+#define RESET_OCCLUSION 
+#define PRESERVE_VB_DEFS
+
+/* Elts, no clipping.
+ */
+#undef ELT
+#undef TAG
+#define TAG(x) tdfx_##x##_elts
+#define ELT(x) elt[x]
+#include "tnl_dd/t_dd_rendertmp.h"
+
+
+
+/**********************************************************************/
+/*                   Render clipped primitives                        */
+/**********************************************************************/
+
+
+
+static void tdfxRenderClippedPoly( GLcontext *ctx, const GLuint *elts, 
+                                  GLuint n )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct vertex_buffer *VB = &tnl->vb;
+   GLuint prim = fxMesa->render_primitive;
+
+   /* Render the new vertices as an unclipped polygon. 
+    */
+   {
+      GLuint *tmp = VB->Elts;
+      VB->Elts = (GLuint *)elts;
+      tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END );
+      VB->Elts = tmp;
+   }
+
+   /* Restore the render primitive
+    */
+   if (prim != GL_POLYGON)
+      tnl->Driver.Render.PrimitiveNotify( ctx, prim );
+}
+
+static void tdfxRenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tnl->Driver.Render.Line( ctx, ii, jj );
+}
+
+static void tdfxFastRenderClippedPoly( GLcontext *ctx, const GLuint *elts, 
+                                      GLuint n )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   GLubyte *vertptr = (GLubyte *)fxMesa->verts;                        
+   const GLuint vertshift = fxMesa->vertex_stride_shift;               
+   const GLuint *start = (const GLuint *)VERT(elts[0]);
+   int i;
+
+   for (i = 2 ; i < n ; i++) {
+      fxMesa->Glide.grDrawTriangle( VERT(elts[i-1]), VERT(elts[i]), start );
+   }
+}
+
+/**********************************************************************/
+/*                    Choose render functions                         */
+/**********************************************************************/
+
+
+#define POINT_FALLBACK (DD_POINT_SMOOTH)
+#define LINE_FALLBACK (DD_LINE_STIPPLE)
+#define TRI_FALLBACK (DD_TRI_SMOOTH)
+#define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK|DD_TRI_STIPPLE)
+#define ANY_RASTER_FLAGS (DD_FLATSHADE|DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET| \
+                         DD_TRI_UNFILLED)
+
+
+/* All state referenced below:
+ */
+#define _TDFX_NEW_RENDERSTATE (_DD_NEW_POINT_SMOOTH |          \
+                               _DD_NEW_LINE_STIPPLE |          \
+                               _DD_NEW_TRI_SMOOTH |            \
+                              _DD_NEW_FLATSHADE |              \
+                              _DD_NEW_TRI_UNFILLED |           \
+                              _DD_NEW_TRI_LIGHT_TWOSIDE |      \
+                              _DD_NEW_TRI_OFFSET |             \
+                              _DD_NEW_TRI_STIPPLE |            \
+                              _NEW_POLYGONSTIPPLE)
+
+
+static void tdfxChooseRenderState(GLcontext *ctx)
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint flags = ctx->_TriangleCaps;
+   GLuint index = 0;
+
+   if (0) {
+      fxMesa->draw_point = tdfx_draw_point;
+      fxMesa->draw_line = tdfx_draw_line;
+      fxMesa->draw_triangle = tdfx_draw_triangle;
+      index |= TDFX_FALLBACK_BIT;
+   }
+
+   if (flags & (ANY_FALLBACK_FLAGS|ANY_RASTER_FLAGS)) {
+      if (flags & ANY_RASTER_FLAGS) {
+        if (flags & DD_TRI_LIGHT_TWOSIDE)    index |= TDFX_TWOSIDE_BIT;
+        if (flags & DD_TRI_OFFSET)           index |= TDFX_OFFSET_BIT;
+        if (flags & DD_TRI_UNFILLED)         index |= TDFX_UNFILLED_BIT;
+        if (flags & DD_FLATSHADE)            index |= TDFX_FLAT_BIT;
+      }
+
+      fxMesa->draw_point = tdfx_draw_point;
+      fxMesa->draw_line = tdfx_draw_line;
+      fxMesa->draw_triangle = tdfx_draw_triangle;
+
+      /* Hook in fallbacks for specific primitives.
+       *
+       * DD_TRI_UNFILLED is here because the unfilled_tri functions use
+       * fxMesa->draw_tri *always*, and thus can't use the multipass
+       * approach to cliprects.
+       *
+       */
+      if (flags & (POINT_FALLBACK|
+                  LINE_FALLBACK|
+                  TRI_FALLBACK|
+                  DD_TRI_STIPPLE|
+                  DD_TRI_UNFILLED))
+      {
+        if (flags & POINT_FALLBACK)
+           fxMesa->draw_point = tdfx_fallback_point;
+
+        if (flags & LINE_FALLBACK)
+           fxMesa->draw_line = tdfx_fallback_line;
+
+        if (flags & TRI_FALLBACK)
+           fxMesa->draw_triangle = tdfx_fallback_tri;
+
+        if ((flags & DD_TRI_STIPPLE) && !fxMesa->haveHwStipple)
+           fxMesa->draw_triangle = tdfx_fallback_tri;
+
+        index |= TDFX_FALLBACK_BIT;
+      }
+   }
+
+   if (fxMesa->RenderIndex != index) {
+      fxMesa->RenderIndex = index;
+
+      tnl->Driver.Render.Points = rast_tab[index].points;
+      tnl->Driver.Render.Line = rast_tab[index].line;
+      tnl->Driver.Render.Triangle = rast_tab[index].triangle;
+      tnl->Driver.Render.Quad = rast_tab[index].quad;
+
+      if (index == 0) {
+        tnl->Driver.Render.PrimTabVerts = tdfx_render_tab_verts;
+        tnl->Driver.Render.PrimTabElts = tdfx_render_tab_elts;
+        tnl->Driver.Render.ClippedLine = line; /* from tritmp.h */
+        tnl->Driver.Render.ClippedPolygon = tdfxFastRenderClippedPoly;
+      } else {
+        tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
+        tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
+        tnl->Driver.Render.ClippedLine = tdfxRenderClippedLine;
+        tnl->Driver.Render.ClippedPolygon = tdfxRenderClippedPoly;
+      }
+   }
+}
+
+/**********************************************************************/
+/*                Use multipass rendering for cliprects               */
+/**********************************************************************/
+
+
+
+/* TODO: Benchmark this.
+ * TODO: Use single back-buffer cliprect where possible.  
+ * NOTE: <pass> starts at 1, not zero!
+ */
+static GLboolean multipass_cliprect( GLcontext *ctx, GLuint pass )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   if (pass >= fxMesa->numClipRects)
+      return GL_FALSE;
+   else {   
+      fxMesa->Glide.grClipWindow(fxMesa->pClipRects[pass].x1,
+                  fxMesa->screen_height - fxMesa->pClipRects[pass].y2,
+                  fxMesa->pClipRects[pass].x2,
+                  fxMesa->screen_height - fxMesa->pClipRects[pass].y1);
+      
+      return GL_TRUE;
+   }
+}
+
+
+/**********************************************************************/
+/*                Runtime render state and callbacks                  */
+/**********************************************************************/
+
+static void tdfxRunPipeline( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if (fxMesa->new_state) {
+      tdfxDDUpdateHwState( ctx );
+   }
+
+   if (!fxMesa->Fallback && fxMesa->new_gl_state) {
+      if (fxMesa->new_gl_state & _TDFX_NEW_RASTERSETUP)
+        tdfxChooseVertexState( ctx );
+      
+      if (fxMesa->new_gl_state & _TDFX_NEW_RENDERSTATE)
+        tdfxChooseRenderState( ctx );
+      
+      fxMesa->new_gl_state = 0;
+   }
+
+   _tnl_run_pipeline( ctx );
+}
+
+
+static void tdfxRenderStart( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   tdfxCheckTexSizes( ctx );
+
+   LOCK_HARDWARE(fxMesa);
+
+   /* Make sure vertex format changes get uploaded before we start
+    * sending triangles.  
+    */
+   if (fxMesa->dirty) {
+      tdfxEmitHwStateLocked( fxMesa );
+   }
+
+   if (fxMesa->numClipRects && !(fxMesa->RenderIndex & TDFX_FALLBACK_BIT)) {
+      fxMesa->Glide.grClipWindow(fxMesa->pClipRects[0].x1,
+                  fxMesa->screen_height - fxMesa->pClipRects[0].y2,
+                  fxMesa->pClipRects[0].x2,
+                  fxMesa->screen_height - fxMesa->pClipRects[0].y1);
+      if (fxMesa->numClipRects > 1)
+         tnl->Driver.Render.Multipass = multipass_cliprect;
+      else
+         tnl->Driver.Render.Multipass = NULL;
+   }
+   else
+      tnl->Driver.Render.Multipass = NULL;
+}
+
+
+static GLenum reduced_prim[GL_POLYGON+1] = {
+   GL_POINTS,
+   GL_LINES,
+   GL_LINES,
+   GL_LINES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES
+};
+
+
+
+/* Always called between RenderStart and RenderFinish --> We already
+ * hold the lock.
+ */
+static void tdfxRasterPrimitive( GLcontext *ctx, GLenum prim )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   FLUSH_BATCH( fxMesa );
+
+   fxMesa->raster_primitive = prim;
+
+   tdfxUpdateCull(ctx);
+   if ( fxMesa->dirty & TDFX_UPLOAD_CULL ) {
+      fxMesa->Glide.grCullMode( fxMesa->CullMode );
+      fxMesa->dirty &= ~TDFX_UPLOAD_CULL;
+   }
+
+   tdfxUpdateStipple(ctx);
+   if ( fxMesa->dirty & TDFX_UPLOAD_STIPPLE ) {
+      fxMesa->Glide.grStipplePattern ( fxMesa->Stipple.Pattern );
+      fxMesa->Glide.grStippleMode ( fxMesa->Stipple.Mode );
+      fxMesa->dirty &= ~TDFX_UPLOAD_STIPPLE;
+   }
+}
+
+
+
+/* Determine the rasterized primitive when not drawing unfilled 
+ * polygons.
+ *
+ * Used only for the default render stage which always decomposes
+ * primitives to trianges/lines/points.  For the accelerated stage,
+ * which renders strips as strips, the equivalent calculations are
+ * performed in tdfx_render.c.
+ */
+static void tdfxRenderPrimitive( GLcontext *ctx, GLenum prim )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint rprim = reduced_prim[prim];
+
+   fxMesa->render_primitive = prim;
+
+   if (rprim == GL_TRIANGLES && (ctx->_TriangleCaps & DD_TRI_UNFILLED))
+      return;
+       
+   if (fxMesa->raster_primitive != rprim) {
+      tdfxRasterPrimitive( ctx, rprim );
+   }
+}
+
+static void tdfxRenderFinish( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+   if (fxMesa->RenderIndex & TDFX_FALLBACK_BIT)
+      _swrast_flush( ctx );
+
+   UNLOCK_HARDWARE(fxMesa);
+}
+
+
+/**********************************************************************/
+/*               Manage total rasterization fallbacks                 */
+/**********************************************************************/
+
+static char *fallbackStrings[] = {
+   "1D/3D Texture map",
+   "glDrawBuffer(GL_FRONT_AND_BACK)",
+   "Separate specular color",
+   "glEnable/Disable(GL_STENCIL_TEST)",
+   "glRenderMode(selection or feedback)",
+   "glLogicOp()",
+   "Texture env mode",
+   "Texture border",
+   "glColorMask",
+   "blend mode",
+   "line stipple"
+};
+
+
+static char *getFallbackString(GLuint bit)
+{
+   int i = 0;
+   while (bit > 1) {
+      i++;
+      bit >>= 1;
+   }
+   return fallbackStrings[i];
+}
+
+
+void tdfxFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint oldfallback = fxMesa->Fallback;
+
+   if (mode) {
+      fxMesa->Fallback |= bit;
+      if (oldfallback == 0) {
+         /*printf("Go to software rendering, bit = 0x%x\n", bit);*/
+        FLUSH_BATCH(fxMesa);
+        _swsetup_Wakeup( ctx );
+        fxMesa->RenderIndex = ~0;
+         if (fxMesa->debugFallbacks) {
+            fprintf(stderr, "Tdfx begin software fallback: 0x%x %s\n",
+                    bit, getFallbackString(bit));
+         }
+      }
+   }
+   else {
+      fxMesa->Fallback &= ~bit;
+      if (oldfallback == bit) {
+         /*printf("Go to hardware rendering, bit = 0x%x\n", bit);*/
+        _swrast_flush( ctx );
+        tnl->Driver.Render.Start = tdfxRenderStart;
+        tnl->Driver.Render.PrimitiveNotify = tdfxRenderPrimitive;
+        tnl->Driver.Render.Finish = tdfxRenderFinish;
+        tnl->Driver.Render.BuildVertices = tdfxBuildVertices;
+        fxMesa->new_gl_state |= (_TDFX_NEW_RENDERSTATE|
+                                 _TDFX_NEW_RASTERSETUP);
+         if (fxMesa->debugFallbacks) {
+            fprintf(stderr, "Tdfx end software fallback: 0x%x %s\n",
+                    bit, getFallbackString(bit));
+         }
+      }
+   }
+}
+
+
+void tdfxDDInitTriFuncs( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   static int firsttime = 1;
+
+   if (firsttime) {
+      init_rast_tab();
+      firsttime = 0;
+   }
+
+   fxMesa->RenderIndex = ~0;
+       
+   tnl->Driver.RunPipeline              = tdfxRunPipeline;
+   tnl->Driver.Render.Start             = tdfxRenderStart;
+   tnl->Driver.Render.Finish            = tdfxRenderFinish; 
+   tnl->Driver.Render.PrimitiveNotify   = tdfxRenderPrimitive;
+   tnl->Driver.Render.ResetLineStipple  = _swrast_ResetLineStipple;
+   tnl->Driver.Render.BuildVertices     = tdfxBuildVertices;
+   tnl->Driver.Render.Multipass                = NULL;
+
+   (void) tdfx_print_vertex;
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_tris.h b/src/mesa/drivers/dri/tdfx/tdfx_tris.h
new file mode 100644 (file)
index 0000000..57e5d9b
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * Authors:
+ *     Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_tris.h,v 1.5 2002/10/30 12:52:01 alanh Exp $ */
+
+#ifndef TDFX_TRIS_INC
+#define TDFX_TRIS_INC
+
+#include "mtypes.h"
+
+extern void tdfxDDInitTriFuncs( GLcontext *ctx );
+
+
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_vb.c b/src/mesa/drivers/dri/tdfx/tdfx_vb.c
new file mode 100644 (file)
index 0000000..de5b936
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * GLX Hardware Device Driver for Intel i810
+ * Copyright (C) 1999 Keith Whitwell
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_vb.c,v 1.3 2002/10/30 12:52:01 alanh Exp $ */
+#include "glheader.h"
+#include "mtypes.h"
+#include "imports.h"
+#include "macros.h"
+#include "colormac.h"
+
+#include "math/m_translate.h"
+#include "swrast_setup/swrast_setup.h"
+
+#include "tdfx_context.h"
+#include "tdfx_vb.h"
+#include "tdfx_tris.h"
+#include "tdfx_state.h"
+#include "tdfx_render.h"
+
+static void copy_pv_rgba4( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   GLubyte *tdfxverts = (GLubyte *)fxMesa->verts;
+   GLuint shift = fxMesa->vertex_stride_shift;
+   tdfxVertex *dst = (tdfxVertex *)(tdfxverts + (edst << shift));
+   tdfxVertex *src = (tdfxVertex *)(tdfxverts + (esrc << shift));
+   dst->ui[4] = src->ui[4];
+}
+
+static void copy_pv_rgba3( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   GLubyte *tdfxverts = (GLubyte *)fxMesa->verts;
+   GLuint shift = fxMesa->vertex_stride_shift;
+   tdfxVertex *dst = (tdfxVertex *)(tdfxverts + (edst << shift));
+   tdfxVertex *src = (tdfxVertex *)(tdfxverts + (esrc << shift));
+   dst->ui[3] = src->ui[3];
+}
+
+typedef void (*emit_func)( GLcontext *, GLuint, GLuint, void *, GLuint );
+
+static struct {
+   emit_func           emit;
+   interp_func         interp;
+   copy_pv_func                copy_pv;
+   GLboolean           (*check_tex_sizes)( GLcontext *ctx );
+   GLuint               vertex_size;
+   GLuint               vertex_stride_shift;
+   GLuint               vertex_format;
+} setup_tab[TDFX_MAX_SETUP];
+
+
+static void import_float_colors( GLcontext *ctx )
+{
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   struct gl_client_array *from = VB->ColorPtr[0];
+   struct gl_client_array *to = &TDFX_CONTEXT(ctx)->UbyteColor;
+   GLuint count = VB->Count;
+
+   if (!to->Ptr) {
+      to->Ptr = ALIGN_MALLOC( VB->Size * 4 * sizeof(GLubyte), 32 );
+      to->Type = GL_UNSIGNED_BYTE;
+   }
+
+   /* No need to transform the same value 3000 times.
+    */
+   if (!from->StrideB) {
+      to->StrideB = 0;
+      count = 1;
+   }
+   else
+      to->StrideB = 4 * sizeof(GLubyte);
+   
+   _math_trans_4ub( (GLubyte (*)[4]) to->Ptr,
+                   from->Ptr,
+                   from->StrideB,
+                   from->Type,
+                   from->Size,
+                   0,
+                   count);
+
+   VB->ColorPtr[0] = to;
+}
+
+
+#define GET_COLOR(ptr, idx) (((GLchan (*)[4])((ptr)->Ptr))[idx])
+
+
+static void interp_extras( GLcontext *ctx,
+                          GLfloat t,
+                          GLuint dst, GLuint out, GLuint in,
+                          GLboolean force_boundary )
+{
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+   /*fprintf(stderr, "%s\n", __FUNCTION__);*/
+
+   if (VB->ColorPtr[1]) {
+      INTERP_4CHAN( t,
+                   GET_COLOR(VB->ColorPtr[1], dst),
+                   GET_COLOR(VB->ColorPtr[1], out),
+                   GET_COLOR(VB->ColorPtr[1], in) );
+   }
+
+   if (VB->EdgeFlag) {
+      VB->EdgeFlag[dst] = VB->EdgeFlag[out] || force_boundary;
+   }
+
+   setup_tab[TDFX_CONTEXT(ctx)->SetupIndex].interp(ctx, t, dst, out, in,
+                                                  force_boundary);
+}
+
+static void copy_pv_extras( GLcontext *ctx, GLuint dst, GLuint src )
+{
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+   if (VB->ColorPtr[1]) {
+        COPY_CHAN4( GET_COLOR(VB->ColorPtr[1], dst), 
+                    GET_COLOR(VB->ColorPtr[1], src) );
+   }
+
+   setup_tab[TDFX_CONTEXT(ctx)->SetupIndex].copy_pv(ctx, dst, src);
+}
+
+
+
+#define IND (TDFX_XYZ_BIT|TDFX_RGBA_BIT)
+#define TAG(x) x##_wg
+#include "tdfx_vbtmp.h"
+
+/* Special for tdfx: fog requires w
+ */
+#define IND (TDFX_XYZ_BIT|TDFX_RGBA_BIT|TDFX_W_BIT)
+#define TAG(x) x##_wg_fog
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_XYZ_BIT|TDFX_RGBA_BIT|TDFX_W_BIT|TDFX_TEX0_BIT)
+#define TAG(x) x##_wgt0
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_XYZ_BIT|TDFX_RGBA_BIT|TDFX_W_BIT|TDFX_TEX0_BIT|TDFX_TEX1_BIT)
+#define TAG(x) x##_wgt0t1
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_XYZ_BIT|TDFX_RGBA_BIT|TDFX_W_BIT|TDFX_TEX0_BIT|TDFX_PTEX_BIT)
+#define TAG(x) x##_wgpt0
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_XYZ_BIT|TDFX_RGBA_BIT|TDFX_W_BIT|TDFX_TEX0_BIT|TDFX_TEX1_BIT|\
+             TDFX_PTEX_BIT)
+#define TAG(x) x##_wgpt0t1
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_RGBA_BIT)
+#define TAG(x) x##_g
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_TEX0_BIT)
+#define TAG(x) x##_t0
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_TEX0_BIT|TDFX_TEX1_BIT)
+#define TAG(x) x##_t0t1
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_RGBA_BIT|TDFX_TEX0_BIT)
+#define TAG(x) x##_gt0
+#include "tdfx_vbtmp.h"
+
+#define IND (TDFX_RGBA_BIT|TDFX_TEX0_BIT|TDFX_TEX1_BIT)
+#define TAG(x) x##_gt0t1
+#include "tdfx_vbtmp.h"
+
+
+
+static void init_setup_tab( void )
+{
+   init_wg();
+   init_wg_fog();
+   init_wgt0();
+   init_wgt0t1();
+   init_wgpt0();
+   init_wgpt0t1();
+
+   init_g();
+   init_t0();
+   init_t0t1();
+   init_gt0();
+   init_gt0t1();
+}
+
+
+void tdfxPrintSetupFlags(char *msg, GLuint flags )
+{
+   fprintf(stderr, "%s(%x): %s%s%s%s%s\n",
+          msg,
+          (int)flags,
+          (flags & TDFX_XYZ_BIT)     ? " xyz," : "", 
+          (flags & TDFX_W_BIT)     ? " w," : "", 
+          (flags & TDFX_RGBA_BIT)     ? " rgba," : "",
+          (flags & TDFX_TEX0_BIT)     ? " tex-0," : "",
+          (flags & TDFX_TEX1_BIT)     ? " tex-1," : "");
+}
+
+
+
+void tdfxCheckTexSizes( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+
+   if (!setup_tab[fxMesa->SetupIndex].check_tex_sizes(ctx)) {
+      GLuint ind = fxMesa->SetupIndex |= (TDFX_PTEX_BIT|TDFX_RGBA_BIT);
+
+      /* Tdfx handles projective textures nicely; just have to change
+       * up to the new vertex format.
+       */
+      if (setup_tab[ind].vertex_format != fxMesa->vertexFormat) {
+        FLUSH_BATCH(fxMesa);
+        fxMesa->dirty |= TDFX_UPLOAD_VERTEX_LAYOUT;      
+        fxMesa->vertexFormat = setup_tab[ind].vertex_format;
+        fxMesa->vertex_stride_shift = setup_tab[ind].vertex_stride_shift;
+
+        /* This is required as we have just changed the vertex
+         * format, so the interp and copy routines must also change.
+         * In the unfilled and twosided cases we are using the
+         * swrast_setup ones anyway, so leave them in place.
+         */
+        if (!(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+           tnl->Driver.Render.Interp = setup_tab[fxMesa->SetupIndex].interp;
+           tnl->Driver.Render.CopyPV = setup_tab[fxMesa->SetupIndex].copy_pv;
+        }
+      }
+   }
+}
+
+
+void tdfxBuildVertices( GLcontext *ctx, GLuint start, GLuint count,
+                       GLuint newinputs )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   GLubyte *v = (fxMesa->verts + (start<<fxMesa->vertex_stride_shift));
+   GLuint stride = 1<<fxMesa->vertex_stride_shift;
+
+   newinputs |= fxMesa->SetupNewInputs;
+   fxMesa->SetupNewInputs = 0;
+
+   if (!newinputs)
+      return;
+
+   if (newinputs & VERT_BIT_CLIP) {
+      setup_tab[fxMesa->SetupIndex].emit( ctx, start, count, v, stride );   
+   } else {
+      GLuint ind = 0;
+
+      if (newinputs & VERT_BIT_COLOR0)
+        ind |= TDFX_RGBA_BIT;
+      
+      if (newinputs & VERT_BIT_TEX0)
+        ind |= TDFX_TEX0_BIT;
+
+      if (newinputs & VERT_BIT_TEX1)
+        ind |= TDFX_TEX0_BIT|TDFX_TEX1_BIT;
+
+      if (fxMesa->SetupIndex & TDFX_PTEX_BIT)
+        ind = ~0;
+
+      ind &= fxMesa->SetupIndex;
+
+      if (ind) {
+        setup_tab[ind].emit( ctx, start, count, v, stride );   
+      }
+   }
+}
+
+
+void tdfxChooseVertexState( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   GLuint ind = TDFX_XYZ_BIT|TDFX_RGBA_BIT;
+
+   if (ctx->Texture._EnabledUnits & 0x2)
+      /* unit 1 enabled */
+      ind |= TDFX_W_BIT|TDFX_TEX1_BIT|TDFX_TEX0_BIT;
+   else if (ctx->Texture._EnabledUnits & 0x1) 
+      /* unit 0 enabled */
+      ind |= TDFX_W_BIT|TDFX_TEX0_BIT;
+   else if (ctx->Fog.Enabled)
+      ind |= TDFX_W_BIT;
+   
+   fxMesa->SetupIndex = ind;
+
+   if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) {
+      tnl->Driver.Render.Interp = interp_extras;
+      tnl->Driver.Render.CopyPV = copy_pv_extras;
+   } else {
+      tnl->Driver.Render.Interp = setup_tab[ind].interp;
+      tnl->Driver.Render.CopyPV = setup_tab[ind].copy_pv;
+   }
+
+   if (setup_tab[ind].vertex_format != fxMesa->vertexFormat) {
+      FLUSH_BATCH(fxMesa);
+      fxMesa->dirty |= TDFX_UPLOAD_VERTEX_LAYOUT;      
+      fxMesa->vertexFormat = setup_tab[ind].vertex_format;
+      fxMesa->vertex_stride_shift = setup_tab[ind].vertex_stride_shift;
+   }
+}
+
+
+
+void tdfxInitVB( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   GLuint size = TNL_CONTEXT(ctx)->vb.Size;
+   static int firsttime = 1;
+   if (firsttime) {
+      init_setup_tab();
+      firsttime = 0;
+   }
+
+   fxMesa->verts = (GLubyte *)ALIGN_MALLOC(size * sizeof(tdfxVertex), 32);
+   fxMesa->vertexFormat = setup_tab[TDFX_XYZ_BIT|TDFX_RGBA_BIT].vertex_format;
+   fxMesa->vertex_stride_shift = setup_tab[(TDFX_XYZ_BIT|
+                                           TDFX_RGBA_BIT)].vertex_stride_shift;
+   fxMesa->SetupIndex = TDFX_XYZ_BIT|TDFX_RGBA_BIT;
+}
+
+
+void tdfxFreeVB( GLcontext *ctx )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   if (fxMesa->verts) {
+      ALIGN_FREE(fxMesa->verts);
+      fxMesa->verts = 0;
+   }
+
+   if (fxMesa->UbyteColor.Ptr) {
+      ALIGN_FREE(fxMesa->UbyteColor.Ptr);
+      fxMesa->UbyteColor.Ptr = 0;
+   }
+
+}
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_vb.h b/src/mesa/drivers/dri/tdfx/tdfx_vb.h
new file mode 100644 (file)
index 0000000..7cb90f5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * GLX Hardware Device Driver for Intel tdfx
+ * Copyright (C) 1999 Keith Whitwell
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_vb.h,v 1.2 2002/02/22 21:45:04 dawes Exp $ */
+
+#ifndef TDFXVB_INC
+#define TDFXVB_INC
+
+#include "mtypes.h"
+
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "math/m_xform.h"
+
+#define TDFX_XYZ_BIT        0x1
+#define TDFX_W_BIT          0x2
+#define TDFX_RGBA_BIT       0x4
+#define TDFX_TEX1_BIT       0x8
+#define TDFX_TEX0_BIT       0x10       
+#define TDFX_PTEX_BIT       0x20
+#define TDFX_MAX_SETUP      0x40
+
+#define _TDFX_NEW_RASTERSETUP (_NEW_TEXTURE |                  \
+                              _DD_NEW_SEPARATE_SPECULAR |      \
+                              _DD_NEW_TRI_UNFILLED |           \
+                              _DD_NEW_TRI_LIGHT_TWOSIDE |      \
+                              _NEW_FOG)
+
+
+extern void tdfxValidateBuildProjVerts(GLcontext *ctx,
+                                      GLuint start, GLuint count,
+                                      GLuint newinputs );
+
+extern void tdfxPrintSetupFlags(char *msg, GLuint flags );
+
+extern void tdfxInitVB( GLcontext *ctx );
+
+extern void tdfxFreeVB( GLcontext *ctx );
+
+extern void tdfxCheckTexSizes( GLcontext *ctx );
+
+extern void tdfxChooseVertexState( GLcontext *ctx );
+
+extern void tdfxBuildVertices( GLcontext *ctx, GLuint start, GLuint count,
+                               GLuint newinputs );
+
+#endif
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_vbtmp.h b/src/mesa/drivers/dri/tdfx/tdfx_vbtmp.h
new file mode 100644 (file)
index 0000000..9925a10
--- /dev/null
@@ -0,0 +1,442 @@
+
+#if (IND & (TDFX_W_BIT|TDFX_TEX0_BIT|TDFX_TEX1_BIT))
+
+static void TAG(emit)( GLcontext *ctx,
+                      GLuint start, GLuint end,
+                      void *dest,
+                      GLuint stride )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   GLfloat (*tc0)[4], (*tc1)[4];
+   GLubyte (*col)[4];
+   GLuint tc0_stride, tc1_stride, col_stride;
+   GLuint tc0_size, tc1_size;
+   GLfloat (*proj)[4] = VB->NdcPtr->data; 
+   GLuint proj_stride = VB->NdcPtr->stride;
+   tdfxVertex *v = (tdfxVertex *)dest;
+   GLfloat u0scale,v0scale,u1scale,v1scale;
+   const GLubyte *mask = VB->ClipMask;
+   const GLfloat *s = fxMesa->hw_viewport;
+   int i;
+
+/*     fprintf(stderr, "%s\n", __FUNCTION__); */
+   ASSERT(stride > 16);
+
+
+   if (IND & TDFX_TEX0_BIT) {
+      tc0_stride = VB->TexCoordPtr[0]->stride;
+      tc0 = VB->TexCoordPtr[0]->data;
+      u0scale = fxMesa->sScale0;
+      v0scale = fxMesa->tScale0;
+      if (IND & TDFX_PTEX_BIT)
+        tc0_size = VB->TexCoordPtr[0]->size;
+   }
+
+   if (IND & TDFX_TEX1_BIT) {
+      tc1 = VB->TexCoordPtr[1]->data;
+      tc1_stride = VB->TexCoordPtr[1]->stride;
+      u1scale = fxMesa->sScale1;
+      v1scale = fxMesa->tScale1;
+      if (IND & TDFX_PTEX_BIT)
+        tc1_size = VB->TexCoordPtr[1]->size;
+   }
+   
+   if (IND & TDFX_RGBA_BIT) {
+      if (VB->ColorPtr[0]->Type != GL_UNSIGNED_BYTE)
+        import_float_colors( ctx );
+      col = VB->ColorPtr[0]->Ptr;
+      col_stride = VB->ColorPtr[0]->StrideB;
+   }
+
+   if (VB->importable_data) {
+      /* May have nonstandard strides:
+       */
+      if (start) {
+        proj =  (GLfloat (*)[4])((GLubyte *)proj + start * proj_stride);
+        if (IND & TDFX_TEX0_BIT)
+           tc0 =  (GLfloat (*)[4])((GLubyte *)tc0 + start * tc0_stride);
+        if (IND & TDFX_TEX1_BIT) 
+           tc1 =  (GLfloat (*)[4])((GLubyte *)tc1 + start * tc1_stride);
+        if (IND & TDFX_RGBA_BIT) 
+           STRIDE_4UB(col, start * col_stride);
+      }
+
+      for (i=start; i < end; i++, v = (tdfxVertex *)((GLubyte *)v + stride)) {
+        if (IND & TDFX_XYZ_BIT) {
+           if (mask[i] == 0) {
+               /* unclipped */
+              v->v.x   = s[0]  * proj[0][0] + s[12];   
+              v->v.y   = s[5]  * proj[0][1] + s[13];   
+              v->v.z   = s[10] * proj[0][2] + s[14];   
+              v->v.rhw = proj[0][3];   
+           } else {
+               /* clipped */
+               v->v.rhw = 1.0;
+           }
+           proj =  (GLfloat (*)[4])((GLubyte *)proj +  proj_stride);
+        }
+        if (IND & TDFX_RGBA_BIT) {
+#if 0
+           *(GLuint *)&v->v.color = *(GLuint *)col;
+#else
+           GLubyte *b = (GLubyte *) &v->v.color;
+           b[0] = col[0][2];
+           b[1] = col[0][1];
+           b[2] = col[0][0];
+           b[3] = col[0][3];
+
+#endif
+           STRIDE_4UB(col, col_stride);
+        }
+        if (IND & TDFX_TEX0_BIT) {
+           GLfloat w = v->v.rhw;
+           if (IND & TDFX_PTEX_BIT) {
+              v->pv.tu0 = tc0[0][0] * u0scale * w;
+              v->pv.tv0 = tc0[0][1] * v0scale * w;
+              v->pv.tq0 = w;
+              if (tc0_size == 4) 
+                 v->pv.tq0 = tc0[0][3] * w;
+           } 
+           else {
+              v->v.tu0 = tc0[0][0] * u0scale * w;
+              v->v.tv0 = tc0[0][1] * v0scale * w;
+           } 
+           tc0 =  (GLfloat (*)[4])((GLubyte *)tc0 +  tc0_stride);
+        }
+        if (IND & TDFX_TEX1_BIT) {
+           GLfloat w = v->v.rhw;
+           if (IND & TDFX_PTEX_BIT) {
+              v->pv.tu1 = tc1[0][0] * u1scale * w;
+              v->pv.tv1 = tc1[0][1] * v1scale * w;
+              v->pv.tq1 = w;
+              if (tc1_size == 4) 
+                 v->pv.tq1 = tc1[0][3] * w;
+           } 
+           else {
+              v->v.tu1 = tc1[0][0] * u1scale * w;
+              v->v.tv1 = tc1[0][1] * v1scale * w;
+           }
+           tc1 =  (GLfloat (*)[4])((GLubyte *)tc1 +  tc1_stride);
+        } 
+      }
+   }
+   else {
+      for (i=start; i < end; i++, v = (tdfxVertex *)((GLubyte *)v + stride)) {
+        if (IND & TDFX_XYZ_BIT) {
+           if (mask[i] == 0) {
+              v->v.x   = s[0]  * proj[i][0] + s[12];   
+              v->v.y   = s[5]  * proj[i][1] + s[13];   
+              v->v.z   = s[10] * proj[i][2] + s[14];   
+              v->v.rhw = proj[i][3];   
+           } else {
+              v->v.rhw = 1.0;
+           }
+        }
+        if (IND & TDFX_RGBA_BIT) {
+#if 0
+           *(GLuint *)&v->v.color = *(GLuint *)&col[i];
+#else
+           GLubyte *b = (GLubyte *) &v->v.color;
+           b[0] = col[i][2];
+           b[1] = col[i][1];
+           b[2] = col[i][0];
+           b[3] = col[i][3];
+
+#endif
+        }
+        if (IND & TDFX_TEX0_BIT) {
+           GLfloat w = v->v.rhw;
+           if (IND & TDFX_PTEX_BIT) {
+              v->pv.tu0 = tc0[i][0] * u0scale * w;
+              v->pv.tv0 = tc0[i][1] * v0scale * w;
+              v->pv.tq0 = w;
+              if (tc0_size == 4) 
+                 v->pv.tq0 = tc0[i][3] * w;
+           } 
+           else {
+              v->v.tu0 = tc0[i][0] * u0scale * w;
+               v->v.tv0 = tc0[i][1] * v0scale * w;
+           }
+        }
+        if (IND & TDFX_TEX1_BIT) {
+           GLfloat w = v->v.rhw;
+           if (IND & TDFX_PTEX_BIT) {
+              v->pv.tu1 = tc1[i][0] * u1scale * w;
+              v->pv.tv1 = tc1[i][1] * v1scale * w;
+              v->pv.tq1 = w;
+              if (tc1_size == 4) 
+                 v->pv.tq1 = tc1[i][3] * w;
+           } 
+           else {
+              v->v.tu1 = tc1[i][0] * u1scale * w;
+              v->v.tv1 = tc1[i][1] * v1scale * w;
+           }
+        }
+      }
+   }
+}
+#else 
+#if (IND & TDFX_XYZ_BIT)
+static void TAG(emit)( GLcontext *ctx, GLuint start, GLuint end,
+                      void *dest, GLuint stride )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   GLubyte (*col)[4];
+   GLuint col_stride;
+   GLfloat (*proj)[4] = VB->NdcPtr->data; 
+   GLuint proj_stride = VB->NdcPtr->stride;
+   GLfloat *v = (GLfloat *)dest;
+   const GLubyte *mask = VB->ClipMask;
+   const GLfloat *s = fxMesa->hw_viewport;
+   int i;
+
+/*       fprintf(stderr, "%s %d..%d dest %p stride %d\n", __FUNCTION__,  */
+/*        start, end, dest, stride);  */
+
+   ASSERT(fxMesa->SetupIndex == (TDFX_XYZ_BIT|TDFX_RGBA_BIT));
+   ASSERT(stride == 16);
+
+   if (VB->ColorPtr[0]->Type != GL_UNSIGNED_BYTE)
+      import_float_colors( ctx );
+
+   col = (GLubyte (*)[4])VB->ColorPtr[0]->Ptr;
+   col_stride = VB->ColorPtr[0]->StrideB;
+   ASSERT(VB->ColorPtr[0]->Type == GL_UNSIGNED_BYTE);
+
+   /* Pack what's left into a 4-dword vertex.  Color is in a different
+    * place, and there is no 'w' coordinate.  
+    */
+   if (VB->importable_data) {
+      if (start) {
+        proj =  (GLfloat (*)[4])((GLubyte *)proj + start * proj_stride);
+        STRIDE_4UB(col, start * col_stride);
+      }
+
+      for (i=start; i < end; i++, v+=4) {
+        if (mask[i] == 0) {
+           v[0]   = s[0]  * proj[0][0] + s[12];        
+           v[1]   = s[5]  * proj[0][1] + s[13];        
+           v[2]   = s[10] * proj[0][2] + s[14];        
+        }
+        proj =  (GLfloat (*)[4])((GLubyte *)proj +  proj_stride);
+        {
+           GLubyte *b = (GLubyte *)&v[3];
+           b[0] = col[0][2];
+           b[1] = col[0][1];
+           b[2] = col[0][0];
+           b[3] = col[0][3];
+           STRIDE_4UB(col, col_stride);
+        }
+      }
+   }
+   else {
+      for (i=start; i < end; i++, v+=4) {
+        if (mask[i] == 0) {
+           v[0]   = s[0]  * proj[i][0] + s[12];        
+           v[1]   = s[5]  * proj[i][1] + s[13];        
+           v[2]   = s[10] * proj[i][2] + s[14];        
+        }
+        {
+           GLubyte *b = (GLubyte *)&v[3];
+           b[0] = col[i][2];
+           b[1] = col[i][1];
+           b[2] = col[i][0];
+           b[3] = col[i][3];
+        }
+      }
+   }
+}
+#else
+static void TAG(emit)( GLcontext *ctx, GLuint start, GLuint end,
+                      void *dest, GLuint stride )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   GLubyte (*col)[4];
+   GLuint col_stride;
+   GLfloat *v = (GLfloat *)dest;
+   int i;
+
+   if (VB->ColorPtr[0]->Type != GL_UNSIGNED_BYTE)
+      import_float_colors( ctx );
+
+   col = VB->ColorPtr[0]->Ptr;
+   col_stride = VB->ColorPtr[0]->StrideB;
+
+   if (start)
+      STRIDE_4UB(col, col_stride * start);
+
+   /* Need to figure out where color is:
+    */
+   if (fxMesa->SetupIndex & TDFX_W_BIT )
+      v += 4;
+   else
+      v += 3;
+
+   for (i=start; i < end; i++, STRIDE_F(v, stride)) {
+      GLubyte *b = (GLubyte *)v;
+      b[0] = col[0][2];
+      b[1] = col[0][1];
+      b[2] = col[0][0];
+      b[3] = col[0][3];
+      STRIDE_4UB( col, col_stride );
+   }
+}
+#endif
+#endif
+
+#if (IND & TDFX_XYZ_BIT) && (IND & TDFX_RGBA_BIT)
+
+static GLboolean TAG(check_tex_sizes)( GLcontext *ctx )
+{
+/*     fprintf(stderr, "%s\n", __FUNCTION__); */
+
+   if (IND & TDFX_PTEX_BIT)
+      return GL_TRUE;
+   
+   if (IND & TDFX_TEX0_BIT) {
+      struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+      if (IND & TDFX_TEX1_BIT) {
+        if (VB->TexCoordPtr[0] == 0)
+           VB->TexCoordPtr[0] = VB->TexCoordPtr[1];
+        
+        if (VB->TexCoordPtr[1]->size == 4)
+           return GL_FALSE;
+      }
+
+      if (VB->TexCoordPtr[0]->size == 4)
+        return GL_FALSE;
+   }
+
+   return GL_TRUE;
+}
+
+static void TAG(interp)( GLcontext *ctx,
+                        GLfloat t, 
+                        GLuint edst, GLuint eout, GLuint ein,
+                        GLboolean force_boundary )
+{
+   tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx );
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   const GLuint shift = fxMesa->vertex_stride_shift;
+   const GLfloat *dstclip = VB->ClipPtr->data[edst];
+   const GLfloat oow = (dstclip[3] == 0.0F) ? 1.0F : (1.0F / dstclip[3]);
+   const GLfloat *s = fxMesa->hw_viewport;
+   GLubyte *tdfxverts = (GLubyte *)fxMesa->verts;
+   tdfxVertex *dst = (tdfxVertex *) (tdfxverts + (edst << shift));
+   const tdfxVertex *out = (const tdfxVertex *) (tdfxverts + (eout << shift));
+   const tdfxVertex *in = (const tdfxVertex *) (tdfxverts + (ein << shift));
+   const GLfloat wout = 1.0F / out->v.rhw;
+   const GLfloat win = 1.0F / in->v.rhw;
+
+   dst->v.x   = s[0]  * dstclip[0] * oow + s[12];      
+   dst->v.y   = s[5]  * dstclip[1] * oow + s[13];      
+   dst->v.z   = s[10] * dstclip[2] * oow + s[14];      
+
+   if (IND & (TDFX_W_BIT|TDFX_TEX0_BIT|TDFX_TEX1_BIT)) {
+      dst->v.rhw = oow;        
+   
+      INTERP_UB( t, dst->ub4[4][0], out->ub4[4][0], in->ub4[4][0] );
+      INTERP_UB( t, dst->ub4[4][1], out->ub4[4][1], in->ub4[4][1] );
+      INTERP_UB( t, dst->ub4[4][2], out->ub4[4][2], in->ub4[4][2] );
+      INTERP_UB( t, dst->ub4[4][3], out->ub4[4][3], in->ub4[4][3] );
+
+      if (IND & TDFX_TEX0_BIT) {
+        if (IND & TDFX_PTEX_BIT) {
+           INTERP_F( t, dst->pv.tu0, out->pv.tu0 * wout, in->pv.tu0 * win );
+           INTERP_F( t, dst->pv.tv0, out->pv.tv0 * wout, in->pv.tv0 * win );
+           INTERP_F( t, dst->pv.tq0, out->pv.tq0 * wout, in->pv.tq0 * win );
+           dst->pv.tu0 *= oow;
+           dst->pv.tv0 *= oow;
+           dst->pv.tq0 *= oow;
+        } else {
+           INTERP_F( t, dst->v.tu0, out->v.tu0 * wout, in->v.tu0 * win );
+           INTERP_F( t, dst->v.tv0, out->v.tv0 * wout, in->v.tv0 * win );
+           dst->v.tu0 *= oow;
+           dst->v.tv0 *= oow;
+        }
+      }
+      if (IND & TDFX_TEX1_BIT) {
+        if (IND & TDFX_PTEX_BIT) {
+           INTERP_F( t, dst->pv.tu1, out->pv.tu1 * wout, in->pv.tu1 * win );
+           INTERP_F( t, dst->pv.tv1, out->pv.tv1 * wout, in->pv.tv1 * win );
+           INTERP_F( t, dst->pv.tq1, out->pv.tq1 * wout, in->pv.tq1 * win );
+           dst->pv.tu1 *= oow;
+           dst->pv.tv1 *= oow;
+           dst->pv.tq1 *= oow;
+        } else {
+           INTERP_F( t, dst->v.tu1, out->v.tu1 * wout, in->v.tu1 * win );
+           INTERP_F( t, dst->v.tv1, out->v.tv1 * wout, in->v.tv1 * win );
+           dst->v.tu1 *= oow;
+           dst->v.tv1 *= oow;
+        }
+      }
+   } else {
+      /* 4-dword vertex.  Color is in v[3] and there is no oow coordinate.
+       */
+      INTERP_UB( t, dst->ub4[3][0], out->ub4[3][0], in->ub4[3][0] );
+      INTERP_UB( t, dst->ub4[3][1], out->ub4[3][1], in->ub4[3][1] );
+      INTERP_UB( t, dst->ub4[3][2], out->ub4[3][2], in->ub4[3][2] );
+      INTERP_UB( t, dst->ub4[3][3], out->ub4[3][3], in->ub4[3][3] );
+   }
+}
+#endif
+
+
+static void TAG(init)( void )
+{
+/*     fprintf(stderr, "%s\n", __FUNCTION__); */
+
+   setup_tab[IND].emit = TAG(emit);
+   
+#if ((IND & TDFX_XYZ_BIT) && (IND & TDFX_RGBA_BIT))
+   setup_tab[IND].check_tex_sizes = TAG(check_tex_sizes);
+   setup_tab[IND].interp = TAG(interp);
+   
+   if (IND & (TDFX_W_BIT|TDFX_TEX0_BIT|TDFX_TEX1_BIT))
+      setup_tab[IND].copy_pv = copy_pv_rgba4;
+   else
+      setup_tab[IND].copy_pv = copy_pv_rgba3;
+
+
+   if (IND & TDFX_TEX1_BIT) {
+      if (IND & TDFX_PTEX_BIT) {
+        setup_tab[IND].vertex_format = TDFX_LAYOUT_PROJECT;
+        setup_tab[IND].vertex_size = 12;
+        setup_tab[IND].vertex_stride_shift = 6; 
+      }
+      else {
+        setup_tab[IND].vertex_format = TDFX_LAYOUT_MULTI;
+        setup_tab[IND].vertex_size = 10;
+        setup_tab[IND].vertex_stride_shift = 6; 
+      }
+   } 
+   else if (IND & TDFX_TEX0_BIT) {
+      if (IND & TDFX_PTEX_BIT) {
+        setup_tab[IND].vertex_format = TDFX_LAYOUT_PROJECT;
+        setup_tab[IND].vertex_size = 12;
+        setup_tab[IND].vertex_stride_shift = 6; 
+      } else {
+        setup_tab[IND].vertex_format = TDFX_LAYOUT_SINGLE;
+        setup_tab[IND].vertex_size = 8;
+        setup_tab[IND].vertex_stride_shift = 5; 
+      }
+   }
+   else if (IND & TDFX_W_BIT) {
+      setup_tab[IND].vertex_format = TDFX_LAYOUT_NOTEX;
+      setup_tab[IND].vertex_size = 6;
+      setup_tab[IND].vertex_stride_shift = 5; 
+   } else {
+      setup_tab[IND].vertex_format = TDFX_LAYOUT_TINY;
+      setup_tab[IND].vertex_size = 4;
+      setup_tab[IND].vertex_stride_shift = 4; 
+   }
+#endif
+}
+
+
+#undef IND
+#undef TAG