From: Alan Hourihane Date: Thu, 4 Dec 2003 13:27:05 +0000 (+0000) Subject: add tdfx DRI driver X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e05ab2795b7463a053562b233d75e62f4138e0d3;p=mesa.git add tdfx DRI driver --- diff --git a/src/mesa/drivers/dri/tdfx/BUGS b/src/mesa/drivers/dri/tdfx/BUGS new file mode 100644 index 00000000000..b15f6a91ed8 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/BUGS @@ -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 index 00000000000..b05717f1004 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/Makefile.X11 @@ -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 index 00000000000..0f4cc45089b --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fastpath.S @@ -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 index 00000000000..9ec4935d781 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/X86/fx_3dnow_fasttmp.h @@ -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 index 00000000000..0af560174e5 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/dri_glide.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#ifndef __DRI_GLIDE_H__ +#define __DRI_GLIDE_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include +#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 index 00000000000..f3a719146d8 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_context.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#include +#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 index 00000000000..9b0c912769b --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_context.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#ifndef __TDFX_CONTEXT_H__ +#define __TDFX_CONTEXT_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include +#include "dri_util.h" +#ifdef XFree86Server +#include "GL/xf86glx.h" +#else +#include "glheader.h" +#endif +#if defined(__linux__) +#include +#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 index 00000000000..31604e3e156 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_dd.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..dbb585e3b25 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_dd.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#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 index 00000000000..f077aa678b3 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_glide.h @@ -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 index 00000000000..6bbfb8d3a2c --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_lock.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#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 index 00000000000..90d49376281 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_lock.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#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 index 00000000000..803c8c5c1cc --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_pixels.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * Nathan Hand + * + */ + +#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 index 00000000000..93b7b8874fd --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_pixels.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * Nathan Hand + * + */ + +#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 index 00000000000..1cb3eeddbc6 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_render.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..146120bc05e --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_render.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#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 index 00000000000..480dc8064a8 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_screen.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#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 index 00000000000..2a79c88b0f6 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_screen.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * + */ + +#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 index 00000000000..d94ef699e88 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_span.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * Keith Whitwell + * + */ + +#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 index 00000000000..8373d1af40a --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_span.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..bab3854a7c4 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_state.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * Keith Whitwell (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 . + */ + 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 index 00000000000..5e59a160164 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_state.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..bffee960668 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_tex.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..5fc7c740bf9 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_tex.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..b34779c21fe --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_texman.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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. + * is the texture unit. + * 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 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. + * is the texture unit + * 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 index 00000000000..739d4e142f6 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_texman.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..e20938bf282 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_texstate.c @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..234ed4439af --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_texstate.h @@ -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 , 29 Sep - 1 Oct 2000 + * + * Authors: + * Gareth Hughes + * Brian Paul + * + */ + +#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 index 00000000000..7ab25e7b9ab --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_tris.c @@ -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 + */ + +#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<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<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<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<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<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<Glide.grDrawLine( fxMesa->verts + ((count - 1)<verts + (start<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<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<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<vertex_stride_shift; + GLubyte *fxVB = fxMesa->verts + (start << shift); + int mode; + (void) flags; + +/* fprintf(stderr, "%s/%d\n", __FUNCTION__, 1<Glide.grDrawVertexArrayContiguous( mode, count-start, + fxVB, 1<vertex_stride_shift; + GLubyte *fxVB = fxMesa->verts + (start << shift); + (void) flags; + + fxMesa->Glide.grDrawVertexArrayContiguous( GR_TRIANGLE_FAN, count-start, + fxVB, 1<vertex_stride_shift; + GLubyte *fxVB = fxMesa->verts; + GLuint i; + (void) flags; + + for (i = start ; i < count-3 ; i += 4 ) { +#define VERT(x) (fxVB + ((x)<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<vertex_stride_shift; + GLubyte *fxVB = fxMesa->verts + (start << shift); + (void) flags; + + fxMesa->Glide.grDrawVertexArrayContiguous( GR_POLYGON, count-start, + fxVB, 1<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: 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 index 00000000000..57e5d9b0ae0 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_tris.h @@ -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 + * + */ +/* $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 index 00000000000..de5b9360e0b --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_vb.c @@ -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<vertex_stride_shift)); + GLuint stride = 1<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 index 00000000000..7cb90f5a5b6 --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_vb.h @@ -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 index 00000000000..9925a10eabb --- /dev/null +++ b/src/mesa/drivers/dri/tdfx/tdfx_vbtmp.h @@ -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