summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Make-config16
-rw-r--r--Makefile.X1131
-rw-r--r--src/glu/mini/Makefile.X1165
-rw-r--r--src/glu/mini/all.h55
-rw-r--r--src/glu/mini/glu.c417
-rw-r--r--src/glu/mini/gluP.h142
-rw-r--r--src/glu/mini/mipmap.c764
-rw-r--r--src/glu/mini/nurbs.c158
-rw-r--r--src/glu/mini/nurbs.h253
-rw-r--r--src/glu/mini/nurbscrv.c133
-rw-r--r--src/glu/mini/polytest.c938
-rw-r--r--src/glu/mini/project.c402
-rw-r--r--src/glu/mini/quadric.c774
-rw-r--r--src/glu/mini/tess.c328
-rw-r--r--src/glu/mini/tess.h108
-rw-r--r--src/glu/mini/tesselat.c407
-rw-r--r--src/glut/mini/Makefile.X1178
-rw-r--r--src/glut/mini/bitmap.c56
-rw-r--r--src/glut/mini/callback.c152
-rw-r--r--src/glut/mini/color.c46
-rw-r--r--src/glut/mini/globals.c61
-rw-r--r--src/glut/mini/init.c59
-rw-r--r--src/glut/mini/internal.h78
-rw-r--r--src/glut/mini/menu.c86
-rw-r--r--src/glut/mini/models.c598
-rw-r--r--src/glut/mini/overlay.c60
-rw-r--r--src/glut/mini/state.c70
-rw-r--r--src/glut/mini/teapot.c214
-rw-r--r--src/glut/mini/window.c273
-rw-r--r--src/glx/mini/Makefile.X1179
-rw-r--r--src/glx/mini/NOTES115
-rw-r--r--src/glx/mini/dispatch.c64
-rw-r--r--src/glx/mini/dri.h124
-rw-r--r--src/glx/mini/dri_util.c715
-rw-r--r--src/glx/mini/dri_util.h523
-rw-r--r--src/glx/mini/driver.h177
-rw-r--r--src/glx/mini/drm.h657
-rw-r--r--src/glx/mini/drmtest.c140
-rw-r--r--src/glx/mini/example.miniglx.conf26
-rw-r--r--src/glx/mini/miniglx.c1975
-rw-r--r--src/glx/mini/miniglxP.h194
-rw-r--r--src/glx/mini/miniglx_events.c962
-rw-r--r--src/glx/mini/sarea.h96
-rw-r--r--src/glx/mini/xf86drm.c1587
-rw-r--r--src/glx/mini/xf86drm.h609
-rw-r--r--src/mesa/Makefile.X118
-rw-r--r--src/mesa/drivers/dri/mga/Doxyfile234
-rw-r--r--src/mesa/drivers/dri/mga/Makefile.X1127
-rw-r--r--src/mesa/drivers/dri/mga/mga_texstate.c747
-rw-r--r--src/mesa/drivers/dri/mga/mga_xmesa.c356
-rw-r--r--src/mesa/drivers/dri/mga/mga_xmesa.h9
-rw-r--r--src/mesa/drivers/dri/mga/mgacontext.h193
-rw-r--r--src/mesa/drivers/dri/mga/mgadd.c92
-rw-r--r--src/mesa/drivers/dri/mga/mgadd.h1
-rw-r--r--src/mesa/drivers/dri/mga/mgaioctl.c127
-rw-r--r--src/mesa/drivers/dri/mga/mgaioctl.h7
-rw-r--r--src/mesa/drivers/dri/mga/mgapixel.c42
-rw-r--r--src/mesa/drivers/dri/mga/mgaregs.h14
-rw-r--r--src/mesa/drivers/dri/mga/mgarender.c5
-rw-r--r--src/mesa/drivers/dri/mga/mgaspan.c31
-rw-r--r--src/mesa/drivers/dri/mga/mgastate.c1297
-rw-r--r--src/mesa/drivers/dri/mga/mgastate.h5
-rw-r--r--src/mesa/drivers/dri/mga/mgatex.c904
-rw-r--r--src/mesa/drivers/dri/mga/mgatex.h13
-rw-r--r--src/mesa/drivers/dri/mga/mgatexmem.c616
-rw-r--r--src/mesa/drivers/dri/mga/mgatris.c85
-rw-r--r--src/mesa/drivers/dri/mga/mgatris.h9
-rw-r--r--src/mesa/drivers/dri/mga/mgavb.c23
-rw-r--r--src/mesa/drivers/dri/mga/server/mga_common.h2
-rw-r--r--src/mesa/drivers/dri/r128/Makefile.X11116
-rw-r--r--src/mesa/drivers/dri/r128/r128_context.c335
-rw-r--r--src/mesa/drivers/dri/r128/r128_context.h270
-rw-r--r--src/mesa/drivers/dri/r128/r128_dd.c148
-rw-r--r--src/mesa/drivers/dri/r128/r128_dd.h44
-rw-r--r--src/mesa/drivers/dri/r128/r128_ioctl.c812
-rw-r--r--src/mesa/drivers/dri/r128/r128_ioctl.h146
-rw-r--r--src/mesa/drivers/dri/r128/r128_lock.c123
-rw-r--r--src/mesa/drivers/dri/r128/r128_lock.h111
-rw-r--r--src/mesa/drivers/dri/r128/r128_screen.c357
-rw-r--r--src/mesa/drivers/dri/r128/r128_screen.h84
-rw-r--r--src/mesa/drivers/dri/r128/r128_span.c475
-rw-r--r--src/mesa/drivers/dri/r128/r128_span.h44
-rw-r--r--src/mesa/drivers/dri/r128/r128_state.c1239
-rw-r--r--src/mesa/drivers/dri/r128/r128_state.h54
-rw-r--r--src/mesa/drivers/dri/r128/r128_tex.c598
-rw-r--r--src/mesa/drivers/dri/r128/r128_tex.h88
-rw-r--r--src/mesa/drivers/dri/r128/r128_texmem.c302
-rw-r--r--src/mesa/drivers/dri/r128/r128_texobj.h69
-rw-r--r--src/mesa/drivers/dri/r128/r128_texstate.c652
-rw-r--r--src/mesa/drivers/dri/r128/r128_tris.c721
-rw-r--r--src/mesa/drivers/dri/r128/r128_tris.h48
-rw-r--r--src/mesa/drivers/dri/r128/r128_vb.c522
-rw-r--r--src/mesa/drivers/dri/r128/r128_vb.h74
-rw-r--r--src/mesa/drivers/dri/r128/server/r128.h566
-rw-r--r--src/mesa/drivers/dri/r128/server/r128_common.h169
-rw-r--r--src/mesa/drivers/dri/r128/server/r128_dri.c1165
-rw-r--r--src/mesa/drivers/dri/r128/server/r128_dri.h103
-rw-r--r--src/mesa/drivers/dri/r128/server/r128_macros.h135
-rw-r--r--src/mesa/drivers/dri/r128/server/r128_reg.h1431
-rw-r--r--src/mesa/drivers/dri/r128/server/r128_sarea.h195
-rw-r--r--src/mesa/drivers/dri/r128/server/r128_version.h60
-rw-r--r--src/mesa/drivers/dri/r200/Makefile.X1116
-rw-r--r--src/mesa/drivers/dri/r200/r200_context.c5
-rw-r--r--src/mesa/drivers/dri/r200/r200_context.h2
-rw-r--r--src/mesa/drivers/dri/r200/r200_ioctl.c6
-rw-r--r--src/mesa/drivers/dri/r200/r200_swtcl.c4
-rw-r--r--src/mesa/drivers/dri/r200/r200_tcl.c68
-rw-r--r--src/mesa/drivers/dri/radeon/Makefile.X11154
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_compat.c304
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_context.c598
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_context.h839
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_ioctl.c1191
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_ioctl.h188
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_lighting.c682
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_lock.c128
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_lock.h113
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_maos.c12
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_maos.h47
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_maos_arrays.c591
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_maos_vbtmp.h368
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_maos_verts.c335
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_sanity.c1043
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_sanity.h8
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_screen.c421
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_screen.h101
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_span.c415
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_span.h45
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_state.c2211
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_state.h77
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_state_init.c531
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset.h75
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset_bitmap.c197
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset_readpix.c246
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset_select.c998
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset_tex.c1018
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset_vtx.c989
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_swtcl.c1332
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_swtcl.h77
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_tcl.c527
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_tcl.h70
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_tex.c733
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_tex.h53
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_texmem.c378
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_texstate.c1628
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_vtxfmt.c1089
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_vtxfmt.h124
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_vtxfmt_c.c905
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_vtxfmt_sse.c232
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_vtxfmt_x86.c437
-rw-r--r--src/mesa/drivers/dri/radeon/server/radeon_common.h397
-rw-r--r--src/mesa/drivers/dri/radeon/server/radeon_dri.c6
-rw-r--r--src/mesa/drivers/dri/radeon/server/radeon_reg.h132
-rw-r--r--src/mesa/drivers/dri/radeon/server/radeon_sarea.h4
-rw-r--r--src/mesa/tnl_dd/imm/NOTES.imm112
-rw-r--r--src/mesa/tnl_dd/imm/t_dd_imm_capi.h419
-rw-r--r--src/mesa/tnl_dd/imm/t_dd_imm_napi.h226
-rw-r--r--src/mesa/tnl_dd/imm/t_dd_imm_primtmp.h570
-rw-r--r--src/mesa/tnl_dd/imm/t_dd_imm_tapi.h75
-rw-r--r--src/mesa/tnl_dd/imm/t_dd_imm_vapi.h159
-rw-r--r--src/mesa/tnl_dd/imm/t_dd_imm_vb.c204
-rw-r--r--src/mesa/tnl_dd/imm/t_dd_imm_vbtmp.h268
-rw-r--r--src/mesa/tnl_dd/t_dd.c58
-rw-r--r--src/mesa/tnl_dd/t_dd_dmatmp.h1105
-rw-r--r--src/mesa/tnl_dd/t_dd_dmatmp2.h949
-rw-r--r--src/mesa/tnl_dd/t_dd_rendertmp.h437
-rw-r--r--src/mesa/tnl_dd/t_dd_triemit.h157
-rw-r--r--src/mesa/tnl_dd/t_dd_tritmp.h739
-rw-r--r--src/mesa/tnl_dd/t_dd_unfilled.h212
-rw-r--r--src/mesa/tnl_dd/t_dd_vb.c392
-rw-r--r--src/mesa/tnl_dd/t_dd_vbtmp.h834
-rw-r--r--src/mesa/tnl_dd/t_dd_vertex.h78
171 files changed, 57619 insertions, 2493 deletions
diff --git a/Make-config b/Make-config
index fffe356def..4b9d7fb1c9 100644
--- a/Make-config
+++ b/Make-config
@@ -664,6 +664,22 @@ linux-osmesa32:
"GL_LIB_DEPS = -lm -lpthread" \
"APP_LIB_DEPS = -lOSMesa32 -lGL"
+# standalone Mesa -- embedded
+# change -g to -O3 for non-debug
+linux-solo:
+ $(MAKE) $(MFLAGS) -f Makefile.X11 targets \
+ "LIBMESA = mesa.a" \
+ "GLU_LIB = libGLU.so" \
+ "GLUT_LIB = libglut.so" \
+ "CC = gcc" \
+ "CXX = g++" \
+ "CFLAGS = -g -std=c99 -pedantic -fPIC -ffast-math -D_POSIX_SOURCE -D_POSIX_C_SOURCE=199309L -D_SVID_SOURCE -D_BSD_SOURCE" \
+ "CXXFLAGS = $(CFLAGS)" \
+ "GL_LIB_DEPS = -lm -lpthread" \
+ "GLU_LIB_DEPS = -L$(TOP)/lib -lGL -lm -Wl,-rpath,$(TOP)/lib" \
+ "GLUT_LIB_DEPS = -L$(TOP)/lib -lGLU -lGL -lm -Wl,-rpath,$(TOP)/lib" \
+ "APP_LIB_DEPS = -L$(TOP)/lib -lglut -lGLU -lGL -lm -lpthread -Wl,-rpath,$(TOP)/lib"
+
# May want to add these CFLAGS for better performance under LynxOS and GCC:
# -fPIC -O2 -ansi -pedantic -mieee-fp -DUSE_XSHM -funroll-loops
# -fexpensive-optimizations -fomit-frame-pointer -ffast-math
diff --git a/Makefile.X11 b/Makefile.X11
index 95ea5271e1..48b929bcdb 100644
--- a/Makefile.X11
+++ b/Makefile.X11
@@ -1,4 +1,4 @@
-# $Id: Makefile.X11,v 1.79 2003/08/22 18:06:59 brianp Exp $
+# $Id: Makefile.X11,v 1.80 2003/08/22 20:11:43 brianp Exp $
# Mesa 3-D graphics library
# Version: 5.1
@@ -73,6 +73,7 @@ default:
@echo " make linux-sparc-ultra for Linux with UltraSparc optimizations"
@echo " make linux-osmesa16 for 16-bit/channel OSMesa"
@echo " make linux-osmesa32 for 32-bit/channel OSMesa"
+ @echo " make linux-solo for Linux standalone with dri drivers"
@echo " make linux-icc for Linux with the Intel C/C++ compiler"
@echo " make lynxos for LynxOS systems with GCC"
@echo " make mklinux for Linux on Power Macintosh"
@@ -227,21 +228,47 @@ linux-osmesa16 linux-osmesa32:
if [ -d src ] ; then touch src/depend ; fi
if [ -d src ] ; then cd src ; $(MAKE) -f Makefile.OSMesa16 $@ ; fi
+linux-solo:
+ -mkdir lib
+ if [ -d src/mesa ] ; then touch src/mesa/depend ; fi
+ if [ -d src/glx/mini ] ; then touch src/glx/mini/depend ; fi
+ if [ -d src/glu/mini ] ; then touch src/glu/mini/depend ; fi
+ if [ -d src/glut/mini ] ; then touch src/glut/mini/depend ; fi
+ if [ -d src/mesa ] ; then cd src/mesa ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/mesa/drivers/dri/r200 ] ; then cd src/mesa/drivers/dri/r200 ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/mesa/drivers/dri/r128 ] ; then cd src/mesa/drivers/dri/r128 ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/mesa/drivers/dri/radeon ] ; then cd src/mesa/drivers/dri/radeon ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/mesa/drivers/dri/mga ] ; then cd src/mesa/drivers/dri/mga ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/mesa/drivers/dri/fb ] ; then cd src/mesa/drivers/dri/fb ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/glx/mini ] ; then cd src/glx/mini ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/glu/mini ] ; then cd src/glu/mini ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d src/glut/mini ] ; then cd src/glut/mini ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d progs/demos ] ; then cd progs/miniglx ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d progs/demos ] ; then cd progs/tests ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d progs/demos ] ; then cd progs/demos ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d progs/xdemos ] ; then cd progs/xdemos ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d progs/samples ] ; then cd progs/samples ; $(MAKE) -f Makefile.X11 $@ ; fi
+ if [ -d progs/redbook ] ; then cd progs/redbook ; $(MAKE) -f Makefile.X11 $@ ; fi
# Remove .o files, emacs backup files, etc.
clean:
-rm -f src/mesa/*/*.o
-rm -f src/mesa/drivers/*/*.o
- -rm -f src/mesa/drivers/*/*.o
+ -rm -f src/mesa/drivers/*/*/*.o
+ -rm -f src/mesa/drivers/*/*/*/*.o
-rm -f include/*~
-rm -f include/GL/*~
-rm -f src/glu/mesa/*.o src/glu/mesa/*~ src-glu/*.a
-rm -f src/glu/sgi/*/*.o src/glu/sgi/*/*/*.o
-rm -f src/glut/glx/*.o
+ -rm -f src/miniglx/*.o
+ -rm -f src/miniglu/*.o
+ -rm -f src/miniglut/*.o
-rm -f progs/demos/*.o
-rm -f progs/redbook/*.o progs/redbook/*~
-rm -f progs/xdemos/*.o progs/xdemos/*~
-rm -f progs/samples/*.o progs/samples/*~
+ -rm -f progs/tests/*.o progs/tests/*~
-rm -f src/glw/*.o
# Remove everything that can be remade
diff --git a/src/glu/mini/Makefile.X11 b/src/glu/mini/Makefile.X11
new file mode 100644
index 0000000000..d0ef2e50f0
--- /dev/null
+++ b/src/glu/mini/Makefile.X11
@@ -0,0 +1,65 @@
+
+
+TOP = ../../..
+
+default: linux-solo
+
+LIBDIR = $(TOP)/lib
+
+INCLUDES = -I$(TOP)/include
+CFLAGS = -c -g $(INCLUDES) -MD
+
+SOURCES = glu.c \
+ mipmap.c \
+ nurbs.c \
+ polytest.c \
+ project.c \
+ quadric.c \
+ tess.c \
+ tesselat.c
+
+
+OBJS = $(SOURCES:.c=.o)
+
+LIBS=-L$(TOP)/lib -lGL -lm
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+
+##### TARGETS #####
+
+targets: depend libGLU.so.1.1 install
+
+libGLU.so.1.1: $(OBJS) Makefile.X11
+ gcc -shared -Wl,-soname,libGLU.so -Wl,-Bsymbolic $(OBJS) $(LIBS) -o $@
+
+install:
+ rm -f $(TOP)/lib/libGLU.so*
+ install -D libGLU.so.1.1 $(TOP)/lib/libGLU.so.1.1
+ ln -s libGLU.so.1.1 $(TOP)/lib/libGLU.so.1
+ ln -s libGLU.so.1 $(TOP)/lib/libGLU.so
+
+# Run 'make -f Makefile.X11 dep' to update the dependencies if you change
+# what's included by any source file.
+depend: $(SOURCES)
+ makedepend -fdepend -Y $(INCLUDES) \
+ $(SOURCES)
+
+# Emacs tags
+tags:
+ etags `find . -name \*.[ch]` `find ../include`
+
+
+# Remove .o and backup files
+clean:
+ -rm -f *.o *~ *.o *~ *.so
+
+include $(TOP)/Make-config
+
+include depend
diff --git a/src/glu/mini/all.h b/src/glu/mini/all.h
new file mode 100644
index 0000000000..d626bee937
--- /dev/null
+++ b/src/glu/mini/all.h
@@ -0,0 +1,55 @@
+/* $Id: all.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * This file includes all .h files needed for the GLU source code for
+ * the purpose of precompiled headers.
+ *
+ * If the preprocessor symbol PCH is defined at compile time then each
+ * of the .c files will #include "all.h" only, instead of a bunch of
+ * individual .h files.
+ */
+
+
+#ifndef GLU_ALL_H
+#define GLU_ALL_H
+
+
+#ifndef PC_HEADER
+This is an error. all.h should be included only if PCH is defined.
+#endif
+
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "GL/gl.h"
+#include "GL/glu.h"
+#include "gluP.h"
+#include "nurbs.h"
+#include "tess.h"
+
+
+#endif /*GLU_ALL_H */
diff --git a/src/glu/mini/glu.c b/src/glu/mini/glu.c
new file mode 100644
index 0000000000..5c7722c5f0
--- /dev/null
+++ b/src/glu/mini/glu.c
@@ -0,0 +1,417 @@
+/* $Id: glu.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ * Copyright (C) 1995-2001 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * Miscellaneous utility functions
+ */
+
+
+#ifndef M_PI
+#define M_PI 3.1415926536
+#endif
+#define EPS 0.00001
+
+#ifndef GLU_INCOMPATIBLE_GL_VERSION
+#define GLU_INCOMPATIBLE_GL_VERSION 100903
+#endif
+
+
+void GLAPIENTRY
+gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,
+ GLdouble centerx, GLdouble centery, GLdouble centerz,
+ GLdouble upx, GLdouble upy, GLdouble upz)
+{
+ GLfloat m[16];
+ GLfloat x[3], y[3], z[3];
+ GLfloat mag;
+
+ /* Make rotation matrix */
+
+ /* Z vector */
+ z[0] = eyex - centerx;
+ z[1] = eyey - centery;
+ z[2] = eyez - centerz;
+ mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
+ if (mag) { /* mpichler, 19950515 */
+ z[0] /= mag;
+ z[1] /= mag;
+ z[2] /= mag;
+ }
+
+ /* Y vector */
+ y[0] = upx;
+ y[1] = upy;
+ y[2] = upz;
+
+ /* X vector = Y cross Z */
+ x[0] = y[1] * z[2] - y[2] * z[1];
+ x[1] = -y[0] * z[2] + y[2] * z[0];
+ x[2] = y[0] * z[1] - y[1] * z[0];
+
+ /* Recompute Y = Z cross X */
+ y[0] = z[1] * x[2] - z[2] * x[1];
+ y[1] = -z[0] * x[2] + z[2] * x[0];
+ y[2] = z[0] * x[1] - z[1] * x[0];
+
+ /* mpichler, 19950515 */
+ /* cross product gives area of parallelogram, which is < 1.0 for
+ * non-perpendicular unit-length vectors; so normalize x, y here
+ */
+
+ mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
+ if (mag) {
+ x[0] /= mag;
+ x[1] /= mag;
+ x[2] /= mag;
+ }
+
+ mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
+ if (mag) {
+ y[0] /= mag;
+ y[1] /= mag;
+ y[2] /= mag;
+ }
+
+#define M(row,col) m[col*4+row]
+ M(0, 0) = x[0];
+ M(0, 1) = x[1];
+ M(0, 2) = x[2];
+ M(0, 3) = 0.0;
+ M(1, 0) = y[0];
+ M(1, 1) = y[1];
+ M(1, 2) = y[2];
+ M(1, 3) = 0.0;
+ M(2, 0) = z[0];
+ M(2, 1) = z[1];
+ M(2, 2) = z[2];
+ M(2, 3) = 0.0;
+ M(3, 0) = 0.0;
+ M(3, 1) = 0.0;
+ M(3, 2) = 0.0;
+ M(3, 3) = 1.0;
+#undef M
+ glMultMatrixf(m);
+
+ /* Translate Eye to Origin */
+ glTranslatef(-eyex, -eyey, -eyez);
+
+}
+
+
+
+void GLAPIENTRY
+gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
+{
+ glOrtho(left, right, bottom, top, -1.0, 1.0);
+}
+
+
+
+static void
+frustum(GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat nearval, GLfloat farval)
+{
+ GLfloat x, y, a, b, c, d;
+ GLfloat m[16];
+
+ x = (2.0 * nearval) / (right - left);
+ y = (2.0 * nearval) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(farval + nearval) / ( farval - nearval);
+ d = -(2.0 * farval * nearval) / (farval - nearval);
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
+ M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
+ M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
+#undef M
+
+ glMultMatrixf(m);
+}
+
+
+void GLAPIENTRY
+gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
+{
+ GLfloat xmin, xmax, ymin, ymax;
+
+ ymax = zNear * tan(fovy * M_PI / 360.0);
+ ymin = -ymax;
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+
+ /* don't call glFrustum() because of error semantics (covglu) */
+ frustum(xmin, xmax, ymin, ymax, zNear, zFar);
+}
+
+
+
+void GLAPIENTRY
+gluPickMatrix(GLdouble x, GLdouble y,
+ GLdouble width, GLdouble height, GLint viewport[4])
+{
+ GLfloat m[16];
+ GLfloat sx, sy;
+ GLfloat tx, ty;
+
+ sx = viewport[2] / width;
+ sy = viewport[3] / height;
+ tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
+ ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
+
+#define M(row,col) m[col*4+row]
+ M(0, 0) = sx;
+ M(0, 1) = 0.0;
+ M(0, 2) = 0.0;
+ M(0, 3) = tx;
+ M(1, 0) = 0.0;
+ M(1, 1) = sy;
+ M(1, 2) = 0.0;
+ M(1, 3) = ty;
+ M(2, 0) = 0.0;
+ M(2, 1) = 0.0;
+ M(2, 2) = 1.0;
+ M(2, 3) = 0.0;
+ M(3, 0) = 0.0;
+ M(3, 1) = 0.0;
+ M(3, 2) = 0.0;
+ M(3, 3) = 1.0;
+#undef M
+
+ glMultMatrixf(m);
+}
+
+
+
+const GLubyte *GLAPIENTRY
+gluErrorString(GLenum errorCode)
+{
+ static char *tess_error[] = {
+ "missing gluBeginPolygon",
+ "missing gluBeginContour",
+ "missing gluEndPolygon",
+ "missing gluEndContour",
+ "misoriented or self-intersecting loops",
+ "coincident vertices",
+ "colinear vertices",
+ "FIST recovery process fatal error"
+ };
+ static char *nurbs_error[] = {
+ "spline order un-supported",
+ "too few knots",
+ "valid knot range is empty",
+ "decreasing knot sequence knot",
+ "knot multiplicity greater than order of spline",
+ "endcurve() must follow bgncurve()",
+ "bgncurve() must precede endcurve()",
+ "missing or extra geometric data",
+ "can't draw pwlcurves",
+ "missing bgncurve()",
+ "missing bgnsurface()",
+ "endtrim() must precede endsurface()",
+ "bgnsurface() must precede endsurface()",
+ "curve of improper type passed as trim curve",
+ "bgnsurface() must precede bgntrim()",
+ "endtrim() must follow bgntrim()",
+ "bgntrim() must precede endtrim()",
+ "invalid or missing trim curve",
+ "bgntrim() must precede pwlcurve()",
+ "pwlcurve referenced twice",
+ "pwlcurve and nurbscurve mixed",
+ "improper usage of trim data type",
+ "nurbscurve referenced twice",
+ "nurbscurve and pwlcurve mixed",
+ "nurbssurface referenced twice",
+ "invalid property",
+ "endsurface() must follow bgnsurface()",
+ "misoriented trim curves",
+ "intersecting trim curves",
+ "UNUSED",
+ "unconnected trim curves",
+ "unknown knot error",
+ "negative vertex count encountered",
+ "negative byte-stride encountered",
+ "unknown type descriptor",
+ "null control array or knot vector",
+ "duplicate point on pwlcurve"
+ };
+
+ /* GL Errors */
+ if (errorCode == GL_NO_ERROR) {
+ return (GLubyte *) "no error";
+ }
+ else if (errorCode == GL_INVALID_VALUE) {
+ return (GLubyte *) "invalid value";
+ }
+ else if (errorCode == GL_INVALID_ENUM) {
+ return (GLubyte *) "invalid enum";
+ }
+ else if (errorCode == GL_INVALID_OPERATION) {
+ return (GLubyte *) "invalid operation";
+ }
+ else if (errorCode == GL_STACK_OVERFLOW) {
+ return (GLubyte *) "stack overflow";
+ }
+ else if (errorCode == GL_STACK_UNDERFLOW) {
+ return (GLubyte *) "stack underflow";
+ }
+ else if (errorCode == GL_OUT_OF_MEMORY) {
+ return (GLubyte *) "out of memory";
+ }
+ /* GLU Errors */
+ else if (errorCode == GLU_NO_ERROR) {
+ return (GLubyte *) "no error";
+ }
+ else if (errorCode == GLU_INVALID_ENUM) {
+ return (GLubyte *) "invalid enum";
+ }
+ else if (errorCode == GLU_INVALID_VALUE) {
+ return (GLubyte *) "invalid value";
+ }
+ else if (errorCode == GLU_OUT_OF_MEMORY) {
+ return (GLubyte *) "out of memory";
+ }
+ else if (errorCode == GLU_INCOMPATIBLE_GL_VERSION) {
+ return (GLubyte *) "incompatible GL version";
+ }
+ else if (errorCode >= GLU_TESS_ERROR1 && errorCode <= GLU_TESS_ERROR8) {
+ return (GLubyte *) tess_error[errorCode - GLU_TESS_ERROR1];
+ }
+ else if (errorCode >= GLU_NURBS_ERROR1 && errorCode <= GLU_NURBS_ERROR37) {
+ return (GLubyte *) nurbs_error[errorCode - GLU_NURBS_ERROR1];
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+
+/*
+ * New in GLU 1.1
+ */
+
+const GLubyte *GLAPIENTRY
+gluGetString(GLenum name)
+{
+ static char *extensions = "GL_EXT_abgr";
+ static char *version = "1.1 Mesa 3.5";
+
+ switch (name) {
+ case GLU_EXTENSIONS:
+ return (GLubyte *) extensions;
+ case GLU_VERSION:
+ return (GLubyte *) version;
+ default:
+ return NULL;
+ }
+}
+
+
+
+#if 0 /* gluGetProcAddressEXT not finalized yet! */
+
+#ifdef __cplusplus
+ /* for BeOS R4.5 */
+void GLAPIENTRY(*gluGetProcAddressEXT(const GLubyte * procName)) (...)
+#else
+void (GLAPIENTRY * gluGetProcAddressEXT(const GLubyte * procName)) ()
+#endif
+{
+ struct proc
+ {
+ const char *name;
+ void *address;
+ };
+ static struct proc procTable[] = {
+ {"gluGetProcAddressEXT", (void *) gluGetProcAddressEXT}, /* me! */
+
+ /* new 1.1 functions */
+ {"gluGetString", (void *) gluGetString},
+
+ /* new 1.2 functions */
+ {"gluTessBeginPolygon", (void *) gluTessBeginPolygon},
+ {"gluTessBeginContour", (void *) gluTessBeginContour},
+ {"gluTessEndContour", (void *) gluTessEndContour},
+ {"gluTessEndPolygon", (void *) gluTessEndPolygon},
+ {"gluGetTessProperty", (void *) gluGetTessProperty},
+
+ /* new 1.3 functions */
+
+ {NULL, NULL}
+ };
+ GLuint i;
+
+ for (i = 0; procTable[i].address; i++) {
+ if (strcmp((const char *) procName, procTable[i].name) == 0)
+ return (void (GLAPIENTRY *) ()) procTable[i].address;
+ }
+
+ return NULL;
+}
+
+#endif
+
+
+
+/*
+ * New in GLU 1.3
+ */
+#ifdef GLU_VERSION_1_3
+GLboolean GLAPIENTRY
+gluCheckExtension(const GLubyte *extName, const GLubyte * extString)
+{
+ assert(extName);
+ assert(extString);
+ {
+ const int len = strlen((const char *) extName);
+ const char *start = (const char *) extString;
+
+ while (1) {
+ const char *c = strstr(start, (const char *) extName);
+ if (!c)
+ return GL_FALSE;
+
+ if ((c == start || c[-1] == ' ') && (c[len] == ' ' || c[len] == 0))
+ return GL_TRUE;
+
+ start = c + len;
+ }
+ }
+}
+#endif
diff --git a/src/glu/mini/gluP.h b/src/glu/mini/gluP.h
new file mode 100644
index 0000000000..85fbc33c62
--- /dev/null
+++ b/src/glu/mini/gluP.h
@@ -0,0 +1,142 @@
+/* $Id: gluP.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * This file allows the GLU code to be compiled either with the Mesa
+ * headers or with the real OpenGL headers.
+ */
+
+
+#ifndef GLUP_H
+#define GLUP_H
+
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <string.h>
+
+
+#if defined(_WIN32) && !defined(__WIN32__)
+# define __WIN32__
+#endif
+
+#if !defined(OPENSTEP) && (defined(__WIN32__) || defined(__CYGWIN__))
+# pragma warning( disable : 4068 ) /* unknown pragma */
+# pragma warning( disable : 4710 ) /* function 'foo' not inlined */
+# pragma warning( disable : 4711 ) /* function 'foo' selected for automatic inline expansion */
+# pragma warning( disable : 4127 ) /* conditional expression is constant */
+# if defined(MESA_MINWARN)
+# pragma warning( disable : 4244 ) /* '=' : conversion from 'const double ' to 'float ', possible loss of data */
+# pragma warning( disable : 4018 ) /* '<' : signed/unsigned mismatch */
+# pragma warning( disable : 4305 ) /* '=' : truncation from 'const double ' to 'float ' */
+# pragma warning( disable : 4550 ) /* 'function' undefined; assuming extern returning int */
+# pragma warning( disable : 4761 ) /* integral size mismatch in argument; conversion supplied */
+# endif
+# if defined(_MSC_VER) && defined(BUILD_GL32) /* tag specify we're building mesa as a DLL */
+# define GLAPI __declspec(dllexport)
+# define WGLAPI __declspec(dllexport)
+# elif defined(_MSC_VER) && defined(_DLL) /* tag specifying we're building for DLL runtime support */
+# define GLAPI __declspec(dllimport)
+# define WGLAPI __declspec(dllimport)
+# else /* for use with static link lib build of Win32 edition only */
+# define GLAPI extern
+# define WGLAPI __declspec(dllimport)
+# endif /* _STATIC_MESA support */
+# define GLAPIENTRY __stdcall
+# define GLAPIENTRYP __stdcall *
+# define GLCALLBACK __stdcall
+# define GLCALLBACKP __stdcall *
+# if defined(__CYGWIN__)
+# define GLCALLBACKPCAST *
+# else
+# define GLCALLBACKPCAST __stdcall *
+# endif
+# define GLWINAPI __stdcall
+# define GLWINAPIV __cdecl
+#else
+/* non-Windows compilation */
+# define GLAPI extern
+# define GLAPIENTRY
+# define GLAPIENTRYP *
+# define GLCALLBACK
+# define GLCALLBACKP *
+# define GLCALLBACKPCAST *
+# define GLWINAPI
+# define GLWINAPIV
+#endif /* WIN32 / CYGWIN bracket */
+
+/* compatibility guard so we don't need to change client code */
+
+#if defined(_WIN32) && !defined(_WINDEF_) && !defined(_GNU_H_WINDOWS32_BASE) && !defined(OPENSTEP)
+# define CALLBACK GLCALLBACK
+typedef int (GLAPIENTRY *PROC)();
+typedef void *HGLRC;
+typedef void *HDC;
+typedef unsigned long COLORREF;
+#endif
+
+#if defined(_WIN32) && !defined(_WINGDI_) && !defined(_GNU_H_WINDOWS32_DEFINES) && !defined(OPENSTEP)
+# define WGL_FONT_LINES 0
+# define WGL_FONT_POLYGONS 1
+#ifndef _GNU_H_WINDOWS32_FUNCTIONS
+# ifdef UNICODE
+# define wglUseFontBitmaps wglUseFontBitmapsW
+# define wglUseFontOutlines wglUseFontOutlinesW
+# else
+# define wglUseFontBitmaps wglUseFontBitmapsA
+# define wglUseFontOutlines wglUseFontOutlinesA
+# endif /* !UNICODE */
+#endif /* _GNU_H_WINDOWS32_FUNCTIONS */
+typedef struct tagLAYERPLANEDESCRIPTOR LAYERPLANEDESCRIPTOR, *PLAYERPLANEDESCRIPTOR, *LPLAYERPLANEDESCRIPTOR;
+typedef struct _GLYPHMETRICSFLOAT GLYPHMETRICSFLOAT, *PGLYPHMETRICSFLOAT, *LPGLYPHMETRICSFLOAT;
+typedef struct tagPIXELFORMATDESCRIPTOR PIXELFORMATDESCRIPTOR, *PPIXELFORMATDESCRIPTOR, *LPPIXELFORMATDESCRIPTOR;
+#include <gl/mesa_wgl.h>
+#endif
+
+
+
+#ifndef GLU_TESS_ERROR9
+ /* If we're using the real OpenGL header files... */
+# define GLU_TESS_ERROR9 100159
+#endif
+
+
+#define GLU_NO_ERROR GL_NO_ERROR
+
+
+/* for Sun: */
+#ifdef SUNOS4
+#define MEMCPY( DST, SRC, BYTES) \
+ memcpy( (char *) (DST), (char *) (SRC), (int) (BYTES) )
+#else
+#define MEMCPY( DST, SRC, BYTES) \
+ memcpy( (void *) (DST), (void *) (SRC), (size_t) (BYTES) )
+#endif
+
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+
+#endif
diff --git a/src/glu/mini/mipmap.c b/src/glu/mini/mipmap.c
new file mode 100644
index 0000000000..97297729e7
--- /dev/null
+++ b/src/glu/mini/mipmap.c
@@ -0,0 +1,764 @@
+/* $Id: mipmap.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * Compute ceiling of integer quotient of A divided by B:
+ */
+#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
+
+
+
+#ifdef EPSILON
+#undef EPSILON
+#endif
+#define EPSILON 0.001
+
+
+/* To work around optimizer bug in MSVC4.1 */
+#if defined(__WIN32__) && !defined(OPENSTEP)
+void
+dummy(GLuint j, GLuint k)
+{
+}
+#else
+#define dummy(J, K)
+#endif
+
+
+GLint GLAPIENTRY
+gluScaleImage(GLenum format,
+ GLsizei widthin, GLsizei heightin,
+ GLenum typein, const void *datain,
+ GLsizei widthout, GLsizei heightout,
+ GLenum typeout, void *dataout)
+{
+ GLint components, i, j, k;
+ GLfloat *tempin, *tempout, f;
+ GLfloat sx, sy;
+ GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
+ GLint packrowlength, packalignment, packskiprows, packskippixels;
+ GLint sizein, sizeout;
+ GLint rowstride, rowlen;
+
+
+ /* Determine number of components per pixel */
+ switch (format) {
+ case GL_COLOR_INDEX:
+ case GL_STENCIL_INDEX:
+ case GL_DEPTH_COMPONENT:
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ components = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ components = 2;
+ break;
+ case GL_RGB:
+ case GL_BGR:
+ components = 3;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+#ifdef GL_EXT_abgr
+ case GL_ABGR_EXT:
+#endif
+ components = 4;
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+ /* Determine bytes per input datum */
+ switch (typein) {
+ case GL_UNSIGNED_BYTE:
+ sizein = sizeof(GLubyte);
+ break;
+ case GL_BYTE:
+ sizein = sizeof(GLbyte);
+ break;
+ case GL_UNSIGNED_SHORT:
+ sizein = sizeof(GLushort);
+ break;
+ case GL_SHORT:
+ sizein = sizeof(GLshort);
+ break;
+ case GL_UNSIGNED_INT:
+ sizein = sizeof(GLuint);
+ break;
+ case GL_INT:
+ sizein = sizeof(GLint);
+ break;
+ case GL_FLOAT:
+ sizein = sizeof(GLfloat);
+ break;
+ case GL_BITMAP:
+ /* not implemented yet */
+ default:
+ return GL_INVALID_ENUM;
+ }
+
+ /* Determine bytes per output datum */
+ switch (typeout) {
+ case GL_UNSIGNED_BYTE:
+ sizeout = sizeof(GLubyte);
+ break;
+ case GL_BYTE:
+ sizeout = sizeof(GLbyte);
+ break;
+ case GL_UNSIGNED_SHORT:
+ sizeout = sizeof(GLushort);
+ break;
+ case GL_SHORT:
+ sizeout = sizeof(GLshort);
+ break;
+ case GL_UNSIGNED_INT:
+ sizeout = sizeof(GLuint);
+ break;
+ case GL_INT:
+ sizeout = sizeof(GLint);
+ break;
+ case GL_FLOAT:
+ sizeout = sizeof(GLfloat);
+ break;
+ case GL_BITMAP:
+ /* not implemented yet */
+ default:
+ return GL_INVALID_ENUM;
+ }
+
+ /* Get glPixelStore state */
+ glGetFloatv(GL_UNPACK_ROW_LENGTH, &f); unpackrowlength = (int)f;
+ glGetFloatv(GL_UNPACK_ALIGNMENT, &f); unpackalignment = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_ROWS, &f); unpackskiprows = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_PIXELS, &f); unpackskippixels = (int)f;
+ glGetFloatv(GL_PACK_ROW_LENGTH, &f); packrowlength = (int)f;
+ glGetFloatv(GL_PACK_ALIGNMENT, &f); packalignment = (int)f;
+ glGetFloatv(GL_PACK_SKIP_ROWS, &f); packskiprows = (int)f;
+ glGetFloatv(GL_PACK_SKIP_PIXELS, &f); packskippixels = (int)f;
+
+ /* Allocate storage for intermediate images */
+ tempin = (GLfloat *) malloc(widthin * heightin
+ * components * sizeof(GLfloat));
+ if (!tempin) {
+ return GLU_OUT_OF_MEMORY;
+ }
+ tempout = (GLfloat *) malloc(widthout * heightout
+ * components * sizeof(GLfloat));
+ if (!tempout) {
+ free(tempin);
+ return GLU_OUT_OF_MEMORY;
+ }
+
+
+ /*
+ * Unpack the pixel data and convert to floating point
+ */
+
+ if (unpackrowlength > 0) {
+ rowlen = unpackrowlength;
+ }
+ else {
+ rowlen = widthin;
+ }
+ if (sizein >= unpackalignment) {
+ rowstride = components * rowlen;
+ }
+ else {
+ rowstride = unpackalignment / sizein
+ * CEILING(components * rowlen * sizein, unpackalignment);
+ }
+
+ switch (typein) {
+ case GL_UNSIGNED_BYTE:
+ k = 0;
+ for (i = 0; i < heightin; i++) {
+ GLubyte *ubptr = (GLubyte *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride + unpackskippixels * components;
+ for (j = 0; j < widthin * components; j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) * ubptr++;
+ }
+ }
+ break;
+ case GL_BYTE:
+ k = 0;
+ for (i = 0; i < heightin; i++) {
+ GLbyte *bptr = (GLbyte *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride + unpackskippixels * components;
+ for (j = 0; j < widthin * components; j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) * bptr++;
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ k = 0;
+ for (i = 0; i < heightin; i++) {
+ GLushort *usptr = (GLushort *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride + unpackskippixels * components;
+ for (j = 0; j < widthin * components; j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) * usptr++;
+ }
+ }
+ break;
+ case GL_SHORT:
+ k = 0;
+ for (i = 0; i < heightin; i++) {
+ GLshort *sptr = (GLshort *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride + unpackskippixels * components;
+ for (j = 0; j < widthin * components; j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) * sptr++;
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ k = 0;
+ for (i = 0; i < heightin; i++) {
+ GLuint *uiptr = (GLuint *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride + unpackskippixels * components;
+ for (j = 0; j < widthin * components; j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) * uiptr++;
+ }
+ }
+ break;
+ case GL_INT:
+ k = 0;
+ for (i = 0; i < heightin; i++) {
+ GLint *iptr = (GLint *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride + unpackskippixels * components;
+ for (j = 0; j < widthin * components; j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) * iptr++;
+ }
+ }
+ break;
+ case GL_FLOAT:
+ k = 0;
+ for (i = 0; i < heightin; i++) {
+ GLfloat *fptr = (GLfloat *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride + unpackskippixels * components;
+ for (j = 0; j < widthin * components; j++) {
+ dummy(j, k);
+ tempin[k++] = *fptr++;
+ }
+ }
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+
+ /*
+ * Scale the image!
+ */
+
+ if (widthout > 1)
+ sx = (GLfloat) (widthin - 1) / (GLfloat) (widthout - 1);
+ else
+ sx = (GLfloat) (widthin - 1);
+ if (heightout > 1)
+ sy = (GLfloat) (heightin - 1) / (GLfloat) (heightout - 1);
+ else
+ sy = (GLfloat) (heightin - 1);
+
+/*#define POINT_SAMPLE*/
+#ifdef POINT_SAMPLE
+ for (i = 0; i < heightout; i++) {
+ GLint ii = i * sy;
+ for (j = 0; j < widthout; j++) {
+ GLint jj = j * sx;
+
+ GLfloat *src = tempin + (ii * widthin + jj) * components;
+ GLfloat *dst = tempout + (i * widthout + j) * components;
+
+ for (k = 0; k < components; k++) {
+ *dst++ = *src++;
+ }
+ }
+ }
+#else
+ if (sx < 1.0 && sy < 1.0) {
+ /* magnify both width and height: use weighted sample of 4 pixels */
+ GLint i0, i1, j0, j1;
+ GLfloat alpha, beta;
+ GLfloat *src00, *src01, *src10, *src11;
+ GLfloat s1, s2;
+ GLfloat *dst;
+
+ for (i = 0; i < heightout; i++) {
+ i0 = i * sy;
+ i1 = i0 + 1;
+ if (i1 >= heightin)
+ i1 = heightin - 1;
+/* i1 = (i+1) * sy - EPSILON;*/
+ alpha = i * sy - i0;
+ for (j = 0; j < widthout; j++) {
+ j0 = j * sx;
+ j1 = j0 + 1;
+ if (j1 >= widthin)
+ j1 = widthin - 1;
+/* j1 = (j+1) * sx - EPSILON; */
+ beta = j * sx - j0;
+
+ /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
+ src00 = tempin + (i0 * widthin + j0) * components;
+ src01 = tempin + (i0 * widthin + j1) * components;
+ src10 = tempin + (i1 * widthin + j0) * components;
+ src11 = tempin + (i1 * widthin + j1) * components;
+
+ dst = tempout + (i * widthout + j) * components;
+
+ for (k = 0; k < components; k++) {
+ s1 = *src00++ * (1.0 - beta) + *src01++ * beta;
+ s2 = *src10++ * (1.0 - beta) + *src11++ * beta;
+ *dst++ = s1 * (1.0 - alpha) + s2 * alpha;
+ }
+ }
+ }
+ }
+ else {
+ /* shrink width and/or height: use an unweighted box filter */
+ GLint i0, i1;
+ GLint j0, j1;
+ GLint ii, jj;
+ GLfloat sum, *dst;
+
+ for (i = 0; i < heightout; i++) {
+ i0 = i * sy;
+ i1 = i0 + 1;
+ if (i1 >= heightin)
+ i1 = heightin - 1;
+/* i1 = (i+1) * sy - EPSILON; */
+ for (j = 0; j < widthout; j++) {
+ j0 = j * sx;
+ j1 = j0 + 1;
+ if (j1 >= widthin)
+ j1 = widthin - 1;
+/* j1 = (j+1) * sx - EPSILON; */
+
+ dst = tempout + (i * widthout + j) * components;
+
+ /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
+ for (k = 0; k < components; k++) {
+ sum = 0.0;
+ for (ii = i0; ii <= i1; ii++) {
+ for (jj = j0; jj <= j1; jj++) {
+ sum += *(tempin + (ii * widthin + jj) * components + k);
+ }
+ }
+ sum /= (j1 - j0 + 1) * (i1 - i0 + 1);
+ *dst++ = sum;
+ }
+ }
+ }
+ }
+#endif
+
+
+ /*
+ * Return output image
+ */
+
+ if (packrowlength > 0) {
+ rowlen = packrowlength;
+ }
+ else {
+ rowlen = widthout;
+ }
+ if (sizeout >= packalignment) {
+ rowstride = components * rowlen;
+ }
+ else {
+ rowstride = packalignment / sizeout
+ * CEILING(components * rowlen * sizeout, packalignment);
+ }
+
+ switch (typeout) {
+ case GL_UNSIGNED_BYTE:
+ k = 0;
+ for (i = 0; i < heightout; i++) {
+ GLubyte *ubptr = (GLubyte *) dataout
+ + i * rowstride
+ + packskiprows * rowstride + packskippixels * components;
+ for (j = 0; j < widthout * components; j++) {
+ dummy(j, k + i);
+ *ubptr++ = (GLubyte) tempout[k++];
+ }
+ }
+ break;
+ case GL_BYTE:
+ k = 0;
+ for (i = 0; i < heightout; i++) {
+ GLbyte *bptr = (GLbyte *) dataout
+ + i * rowstride
+ + packskiprows * rowstride + packskippixels * components;
+ for (j = 0; j < widthout * components; j++) {
+ dummy(j, k + i);
+ *bptr++ = (GLbyte) tempout[k++];
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ k = 0;
+ for (i = 0; i < heightout; i++) {
+ GLushort *usptr = (GLushort *) dataout
+ + i * rowstride
+ + packskiprows * rowstride + packskippixels * components;
+ for (j = 0; j < widthout * components; j++) {
+ dummy(j, k + i);
+ *usptr++ = (GLushort) tempout[k++];
+ }
+ }
+ break;
+ case GL_SHORT:
+ k = 0;
+ for (i = 0; i < heightout; i++) {
+ GLshort *sptr = (GLshort *) dataout
+ + i * rowstride
+ + packskiprows * rowstride + packskippixels * components;
+ for (j = 0; j < widthout * components; j++) {
+ dummy(j, k + i);
+ *sptr++ = (GLshort) tempout[k++];
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ k = 0;
+ for (i = 0; i < heightout; i++) {
+ GLuint *uiptr = (GLuint *) dataout
+ + i * rowstride
+ + packskiprows * rowstride + packskippixels * components;
+ for (j = 0; j < widthout * components; j++) {
+ dummy(j, k + i);
+ *uiptr++ = (GLuint) tempout[k++];
+ }
+ }
+ break;
+ case GL_INT:
+ k = 0;
+ for (i = 0; i < heightout; i++) {
+ GLint *iptr = (GLint *) dataout
+ + i * rowstride
+ + packskiprows * rowstride + packskippixels * components;
+ for (j = 0; j < widthout * components; j++) {
+ dummy(j, k + i);
+ *iptr++ = (GLint) tempout[k++];
+ }
+ }
+ break;
+ case GL_FLOAT:
+ k = 0;
+ for (i = 0; i < heightout; i++) {
+ GLfloat *fptr = (GLfloat *) dataout
+ + i * rowstride
+ + packskiprows * rowstride + packskippixels * components;
+ for (j = 0; j < widthout * components; j++) {
+ dummy(j, k + i);
+ *fptr++ = tempout[k++];
+ }
+ }
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+
+ /* free temporary image storage */
+ free(tempin);
+ free(tempout);
+
+ return 0;
+}
+
+
+
+/*
+ * Return the largest k such that 2^k <= n.
+ */
+static GLint
+ilog2(GLint n)
+{
+ GLint k;
+
+ if (n <= 0)
+ return 0;
+ for (k = 0; n >>= 1; k++);
+ return k;
+}
+
+
+
+/*
+ * Find the value nearest to n which is also a power of two.
+ */
+static GLint
+round2(GLint n)
+{
+ GLint m;
+
+ for (m = 1; m < n; m *= 2);
+
+ /* m>=n */
+ if (m - n <= n - m / 2) {
+ return m;
+ }
+ else {
+ return m / 2;
+ }
+}
+
+
+/*
+ * Given an pixel format and data type, return the number of bytes to
+ * store one pixel.
+ */
+static GLint
+bytes_per_pixel(GLenum format, GLenum type)
+{
+ GLint n, m;
+
+ switch (format) {
+ case GL_COLOR_INDEX:
+ case GL_STENCIL_INDEX:
+ case GL_DEPTH_COMPONENT:
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ n = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ n = 2;
+ break;
+ case GL_RGB:
+ case GL_BGR:
+ n = 3;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+#ifdef GL_EXT_abgr
+ case GL_ABGR_EXT:
+#endif
+ n = 4;
+ break;
+ default:
+ n = 0;
+ }
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ m = sizeof(GLubyte);
+ break;
+ case GL_BYTE:
+ m = sizeof(GLbyte);
+ break;
+ case GL_BITMAP:
+ m = 1;
+ break;
+ case GL_UNSIGNED_SHORT:
+ m = sizeof(GLushort);
+ break;
+ case GL_SHORT:
+ m = sizeof(GLshort);
+ break;
+ case GL_UNSIGNED_INT:
+ m = sizeof(GLuint);
+ break;
+ case GL_INT:
+ m = sizeof(GLint);
+ break;
+ case GL_FLOAT:
+ m = sizeof(GLfloat);
+ break;
+ default:
+ m = 0;
+ }
+
+ return n * m;
+}
+
+
+
+/*
+ * WARNING: This function isn't finished and has never been tested!!!!
+ */
+GLint GLAPIENTRY
+gluBuild1DMipmaps(GLenum target, GLint components,
+ GLsizei width, GLenum format, GLenum type, const void *data)
+{
+ return 0;
+}
+
+
+
+GLint GLAPIENTRY
+gluBuild2DMipmaps(GLenum target, GLint components,
+ GLsizei width, GLsizei height, GLenum format,
+ GLenum type, const void *data)
+{
+ GLint w, h;
+ GLint maxsize;
+ void *image, *newimage;
+ GLint neww, newh, level, bpp;
+ int error;
+ GLboolean done;
+ GLint retval = 0;
+ GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
+ GLint packrowlength, packalignment, packskiprows, packskippixels;
+ GLfloat f;
+
+ if (width < 1 || height < 1)
+ return GLU_INVALID_VALUE;
+
+ glGetFloatv(GL_MAX_TEXTURE_SIZE, &f); maxsize = (int)f;
+
+ w = round2(width);
+ if (w > maxsize) {
+ w = maxsize;
+ }
+ h = round2(height);
+ if (h > maxsize) {
+ h = maxsize;
+ }
+
+ bpp = bytes_per_pixel(format, type);
+ if (bpp == 0) {
+ /* probably a bad format or type enum */
+ return GLU_INVALID_ENUM;
+ }
+
+ /* Get current glPixelStore values */
+ glGetFloatv(GL_UNPACK_ROW_LENGTH, &f); unpackrowlength = (int)f;
+ glGetFloatv(GL_UNPACK_ALIGNMENT, &f); unpackalignment = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_ROWS, &f); unpackskiprows = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_PIXELS, &f); unpackskippixels = (int)f;
+ glGetFloatv(GL_PACK_ROW_LENGTH, &f); packrowlength = (int)f;
+ glGetFloatv(GL_PACK_ALIGNMENT, &f); packalignment = (int)f;
+ glGetFloatv(GL_PACK_SKIP_ROWS, &f); packskiprows = (int)f;
+ glGetFloatv(GL_PACK_SKIP_PIXELS, &f); packskippixels = (int)f;
+
+ /* set pixel packing */
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+
+ done = GL_FALSE;
+
+ if (w != width || h != height) {
+ /* must rescale image to get "top" mipmap texture image */
+ image = malloc((w + 4) * h * bpp);
+ if (!image) {
+ return GLU_OUT_OF_MEMORY;
+ }
+ error = gluScaleImage(format, width, height, type, data,
+ w, h, type, image);
+ if (error) {
+ retval = error;
+ done = GL_TRUE;
+ }
+ }
+ else {
+ image = (void *) data;
+ }
+
+ level = 0;
+ while (!done) {
+ if (image != data) {
+ /* set pixel unpacking */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ }
+
+ glTexImage2D(target, level, components, w, h, 0, format, type, image);
+
+ if (w == 1 && h == 1)
+ break;
+
+ neww = (w < 2) ? 1 : w / 2;
+ newh = (h < 2) ? 1 : h / 2;
+ newimage = malloc((neww + 4) * newh * bpp);
+ if (!newimage) {
+ return GLU_OUT_OF_MEMORY;
+ }
+
+ error = gluScaleImage(format, w, h, type, image,
+ neww, newh, type, newimage);
+ if (error) {
+ retval = error;
+ done = GL_TRUE;
+ }
+
+ if (image != data) {
+ free(image);
+ }
+ image = newimage;
+
+ w = neww;
+ h = newh;
+ level++;
+ }
+
+ if (image != data) {
+ free(image);
+ }
+
+ /* Restore original glPixelStore state */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels);
+ glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength);
+ glPixelStorei(GL_PACK_ALIGNMENT, packalignment);
+ glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels);
+
+ return retval;
+}
diff --git a/src/glu/mini/nurbs.c b/src/glu/mini/nurbs.c
new file mode 100644
index 0000000000..93c0dd3ce2
--- /dev/null
+++ b/src/glu/mini/nurbs.c
@@ -0,0 +1,158 @@
+/* $Id: nurbs.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
+ * See README2 for more info.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include "gluP.h"
+#include "nurbs.h"
+#endif
+
+
+void
+call_user_error(GLUnurbsObj * nobj, GLenum error)
+{
+ nobj->error = error;
+ if (nobj->error_callback != NULL) {
+ (*(nobj->error_callback)) (error);
+ }
+ else {
+ printf("NURBS error %d %s\n", error, (char *) gluErrorString(error));
+ }
+}
+
+
+
+GLUnurbsObj *GLAPIENTRY
+gluNewNurbsRenderer(void)
+{
+ GLUnurbsObj *n;
+ GLfloat tmp_viewport[4];
+ GLint i, j;
+
+ n = (GLUnurbsObj *) malloc(sizeof(GLUnurbsObj));
+ return n;
+}
+
+
+
+void GLAPIENTRY
+gluDeleteNurbsRenderer(GLUnurbsObj * nobj)
+{
+ if (nobj) {
+ free(nobj);
+ }
+}
+
+
+
+void GLAPIENTRY
+gluLoadSamplingMatrices(GLUnurbsObj * nobj,
+ const GLfloat modelMatrix[16],
+ const GLfloat projMatrix[16], const GLint viewport[4])
+{
+}
+
+
+void GLAPIENTRY
+gluNurbsProperty(GLUnurbsObj * nobj, GLenum property, GLfloat value)
+{
+}
+
+
+void GLAPIENTRY
+gluGetNurbsProperty(GLUnurbsObj * nobj, GLenum property, GLfloat * value)
+{
+}
+
+
+
+void GLAPIENTRY
+gluBeginCurve(GLUnurbsObj * nobj)
+{
+}
+
+
+void GLAPIENTRY
+gluEndCurve(GLUnurbsObj * nobj)
+{
+}
+
+
+void GLAPIENTRY
+gluNurbsCurve(GLUnurbsObj * nobj, GLint nknots, GLfloat * knot,
+ GLint stride, GLfloat * ctlarray, GLint order, GLenum type)
+{
+}
+
+
+void GLAPIENTRY
+gluBeginSurface(GLUnurbsObj * nobj)
+{
+}
+
+
+void GLAPIENTRY
+gluEndSurface(GLUnurbsObj * nobj)
+{
+}
+
+
+void GLAPIENTRY
+gluNurbsSurface(GLUnurbsObj * nobj,
+ GLint sknot_count, GLfloat * sknot,
+ GLint tknot_count, GLfloat * tknot,
+ GLint s_stride, GLint t_stride,
+ GLfloat * ctrlarray, GLint sorder, GLint torder, GLenum type)
+{
+}
+
+
+void GLAPIENTRY
+gluNurbsCallback(GLUnurbsObj * nobj, GLenum which, void (GLCALLBACK * fn) ())
+{
+}
+
+void GLAPIENTRY
+gluBeginTrim(GLUnurbsObj * nobj)
+{
+}
+
+void GLAPIENTRY
+gluPwlCurve(GLUnurbsObj * nobj, GLint count, GLfloat * array, GLint stride,
+ GLenum type)
+{
+}
+
+void GLAPIENTRY
+gluEndTrim(GLUnurbsObj * nobj)
+{
+}
diff --git a/src/glu/mini/nurbs.h b/src/glu/mini/nurbs.h
new file mode 100644
index 0000000000..c9c9c094f1
--- /dev/null
+++ b/src/glu/mini/nurbs.h
@@ -0,0 +1,253 @@
+/* $Id: nurbs.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
+ * See README2 for more info.
+ */
+
+
+#ifndef NURBS_H
+#define NURBS_H
+
+
+#define EPSILON 1e-06 /* epsilon for double precision compares */
+
+typedef enum
+{
+ GLU_NURBS_CURVE, GLU_NURBS_SURFACE, GLU_NURBS_TRIM, GLU_NURBS_NO_TRIM,
+ GLU_NURBS_TRIM_DONE, GLU_NURBS_NONE
+}
+GLU_nurbs_enum;
+
+typedef enum
+{
+ GLU_TRIM_NURBS, GLU_TRIM_PWL
+}
+GLU_trim_enum;
+
+typedef struct
+{
+ GLint sknot_count;
+ GLfloat *sknot;
+ GLint tknot_count;
+ GLfloat *tknot;
+ GLint s_stride;
+ GLint t_stride;
+ GLfloat *ctrlarray;
+ GLint sorder;
+ GLint torder;
+ GLint dim;
+ GLenum type;
+}
+surface_attribs;
+
+typedef struct
+{
+ surface_attribs geom;
+ surface_attribs color;
+ surface_attribs texture;
+ surface_attribs normal;
+}
+nurbs_surface;
+
+typedef struct
+{
+ GLint knot_count;
+ GLfloat *knot;
+ GLint stride;
+ GLfloat *ctrlarray;
+ GLint order;
+ GLint dim;
+ GLenum type;
+}
+curve_attribs;
+
+typedef struct
+{
+ GLint pt_count;
+ GLfloat *ctrlarray;
+ GLint stride;
+ GLint dim;
+ GLenum type;
+}
+pwl_curve_attribs;
+
+typedef struct
+{
+ curve_attribs geom;
+ curve_attribs color;
+ curve_attribs texture;
+ curve_attribs normal;
+}
+nurbs_curve;
+
+typedef struct trim_list_str
+{
+ GLU_trim_enum trim_type;
+ union
+ {
+ pwl_curve_attribs pwl_curve;
+ curve_attribs nurbs_curve;
+ }
+ curve;
+ struct trim_list_str *next;
+}
+trim_list;
+
+typedef struct seg_trim_str
+{
+ GLfloat *points;
+ GLint pt_cnt, seg_array_len;
+ struct seg_trim_str *next;
+}
+trim_segments;
+
+typedef struct nurbs_trim_str
+{
+ trim_list *trim_loop;
+ trim_segments *segments;
+ struct nurbs_trim_str *next;
+}
+nurbs_trim;
+
+typedef struct
+{
+ GLfloat model[16], proj[16], viewport[4];
+}
+culling_and_sampling_str;
+
+struct GLUnurbs
+{
+ GLboolean culling;
+ GLenum error;
+ void (GLCALLBACK * error_callback) (GLenum err);
+ GLenum display_mode;
+ GLU_nurbs_enum nurbs_type;
+ GLboolean auto_load_matrix;
+ culling_and_sampling_str sampling_matrices;
+ GLenum sampling_method;
+ GLfloat sampling_tolerance;
+ GLfloat parametric_tolerance;
+ GLint u_step, v_step;
+ nurbs_surface surface;
+ nurbs_curve curve;
+ nurbs_trim *trim;
+};
+
+typedef struct
+{
+ GLfloat *knot;
+ GLint nknots;
+ GLfloat *unified_knot;
+ GLint unified_nknots;
+ GLint order;
+ GLint t_min, t_max;
+ GLint delta_nknots;
+ GLboolean open_at_begin, open_at_end;
+ GLfloat *new_knot;
+ GLfloat *alpha;
+}
+knot_str_type;
+
+typedef struct
+{
+ GLfloat *geom_ctrl;
+ GLint geom_s_stride, geom_t_stride;
+ GLfloat **geom_offsets;
+ GLint geom_s_pt_cnt, geom_t_pt_cnt;
+ GLfloat *color_ctrl;
+ GLint color_s_stride, color_t_stride;
+ GLfloat **color_offsets;
+ GLint color_s_pt_cnt, color_t_pt_cnt;
+ GLfloat *normal_ctrl;
+ GLint normal_s_stride, normal_t_stride;
+ GLfloat **normal_offsets;
+ GLint normal_s_pt_cnt, normal_t_pt_cnt;
+ GLfloat *texture_ctrl;
+ GLint texture_s_stride, texture_t_stride;
+ GLfloat **texture_offsets;
+ GLint texture_s_pt_cnt, texture_t_pt_cnt;
+ GLint s_bezier_cnt, t_bezier_cnt;
+}
+new_ctrl_type;
+
+extern void call_user_error(GLUnurbsObj * nobj, GLenum error);
+
+extern GLenum test_knot(GLint nknots, GLfloat * knot, GLint order);
+
+extern GLenum explode_knot(knot_str_type * the_knot);
+
+extern GLenum calc_alphas(knot_str_type * the_knot);
+
+extern GLenum calc_new_ctrl_pts(GLfloat * ctrl, GLint stride,
+ knot_str_type * the_knot, GLint dim,
+ GLfloat ** new_ctrl, GLint * ncontrol);
+
+extern GLenum glu_do_sampling_crv(GLUnurbsObj * nobj, GLfloat * new_ctrl,
+ GLint n_ctrl, GLint order, GLint dim,
+ GLint ** factors);
+
+extern GLenum glu_do_sampling_3D(GLUnurbsObj * nobj, new_ctrl_type * new_ctrl,
+ int **sfactors, GLint ** tfactors);
+
+extern GLenum glu_do_sampling_uv(GLUnurbsObj * nobj, new_ctrl_type * new_ctrl,
+ int **sfactors, GLint ** tfactors);
+
+extern GLenum glu_do_sampling_param_3D(GLUnurbsObj * nobj,
+ new_ctrl_type * new_ctrl,
+ int **sfactors, GLint ** tfactors);
+
+extern GLboolean fine_culling_test_2D(GLUnurbsObj * nobj, GLfloat * ctrl,
+ GLint n_ctrl, GLint stride, GLint dim);
+
+extern GLboolean fine_culling_test_3D(GLUnurbsObj * nobj, GLfloat * ctrl,
+ GLint s_n_ctrl, GLint t_n_ctrl,
+ GLint s_stride, GLint t_stride,
+ GLint dim);
+
+extern void do_nurbs_curve(GLUnurbsObj * nobj);
+
+extern void do_nurbs_surface(GLUnurbsObj * nobj);
+
+extern GLenum patch_trimming(GLUnurbsObj * nobj, new_ctrl_type * new_ctrl,
+ GLint * sfactors, GLint * tfactors);
+
+extern void collect_unified_knot(knot_str_type * dest, knot_str_type * src,
+ GLfloat maximal_min_knot,
+ GLfloat minimal_max_knot);
+
+extern GLenum select_knot_working_range(GLUnurbsObj * nobj,
+ knot_str_type * geom_knot,
+ knot_str_type * color_knot,
+ knot_str_type * normal_knot,
+ knot_str_type * texture_knot);
+
+extern void free_unified_knots(knot_str_type * geom_knot,
+ knot_str_type * color_knot,
+ knot_str_type * normal_knot,
+ knot_str_type * texture_knot);
+
+
+
+#endif
diff --git a/src/glu/mini/nurbscrv.c b/src/glu/mini/nurbscrv.c
new file mode 100644
index 0000000000..62d91b46d3
--- /dev/null
+++ b/src/glu/mini/nurbscrv.c
@@ -0,0 +1,133 @@
+/* $Id: nurbscrv.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
+ * See README2 for more info.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "gluP.h"
+#include "nurbs.h"
+#endif
+
+
+
+/* main NURBS curve procedure */
+void
+do_nurbs_curve(GLUnurbsObj * nobj)
+{
+ GLint geom_order, color_order = 0, normal_order = 0, texture_order = 0;
+ GLenum geom_type;
+ GLint n_ctrl;
+ GLfloat *new_geom_ctrl, *new_color_ctrl, *new_normal_ctrl,
+ *new_texture_ctrl;
+ GLfloat *geom_ctrl = 0, *color_ctrl = 0, *normal_ctrl = 0, *texture_ctrl = 0;
+ GLint *factors;
+ GLint i, j;
+ GLint geom_dim, color_dim = 0, normal_dim = 0, texture_dim = 0;
+
+ /* test the user supplied data */
+ if (test_nurbs_curves(nobj) != GLU_NO_ERROR)
+ return;
+
+ if (convert_curves(nobj, &new_geom_ctrl, &n_ctrl, &new_color_ctrl,
+ &new_normal_ctrl, &new_texture_ctrl) != GLU_NO_ERROR)
+ return;
+
+ geom_order = nobj->curve.geom.order;
+ geom_type = nobj->curve.geom.type;
+ geom_dim = nobj->curve.geom.dim;
+
+ if (glu_do_sampling_crv(nobj, new_geom_ctrl, n_ctrl, geom_order, geom_dim,
+ &factors) != GLU_NO_ERROR) {
+ free(new_geom_ctrl);
+ if (new_color_ctrl)
+ free(new_color_ctrl);
+ if (new_normal_ctrl)
+ free(new_normal_ctrl);
+ if (new_texture_ctrl)
+ free(new_texture_ctrl);
+ return;
+ }
+ glEnable(geom_type);
+ if (new_color_ctrl) {
+ glEnable(nobj->curve.color.type);
+ color_dim = nobj->curve.color.dim;
+ color_ctrl = new_color_ctrl;
+ color_order = nobj->curve.color.order;
+ }
+ if (new_normal_ctrl) {
+ glEnable(nobj->curve.normal.type);
+ normal_dim = nobj->curve.normal.dim;
+ normal_ctrl = new_normal_ctrl;
+ normal_order = nobj->curve.normal.order;
+ }
+ if (new_texture_ctrl) {
+ glEnable(nobj->curve.texture.type);
+ texture_dim = nobj->curve.texture.dim;
+ texture_ctrl = new_texture_ctrl;
+ texture_order = nobj->curve.texture.order;
+ }
+ for (i = 0, j = 0, geom_ctrl = new_geom_ctrl;
+ i < n_ctrl; i += geom_order, j++, geom_ctrl += geom_order * geom_dim) {
+ if (fine_culling_test_2D
+ (nobj, geom_ctrl, geom_order, geom_dim, geom_dim)) {
+ color_ctrl += color_order * color_dim;
+ normal_ctrl += normal_order * normal_dim;
+ texture_ctrl += texture_order * texture_dim;
+ continue;
+ }
+ glMap1f(geom_type, 0.0, 1.0, geom_dim, geom_order, geom_ctrl);
+ if (new_color_ctrl) {
+ glMap1f(nobj->curve.color.type, 0.0, 1.0, color_dim,
+ color_order, color_ctrl);
+ color_ctrl += color_order * color_dim;
+ }
+ if (new_normal_ctrl) {
+ glMap1f(nobj->curve.normal.type, 0.0, 1.0, normal_dim,
+ normal_order, normal_ctrl);
+ normal_ctrl += normal_order * normal_dim;
+ }
+ if (new_texture_ctrl) {
+ glMap1f(nobj->curve.texture.type, 0.0, 1.0, texture_dim,
+ texture_order, texture_ctrl);
+ texture_ctrl += texture_order * texture_dim;
+ }
+ glMapGrid1f(factors[j], 0.0, 1.0);
+ glEvalMesh1(GL_LINE, 0, factors[j]);
+ }
+ free(new_geom_ctrl);
+ free(factors);
+ if (new_color_ctrl)
+ free(new_color_ctrl);
+ if (new_normal_ctrl)
+ free(new_normal_ctrl);
+ if (new_texture_ctrl)
+ free(new_texture_ctrl);
+}
diff --git a/src/glu/mini/polytest.c b/src/glu/mini/polytest.c
new file mode 100644
index 0000000000..52f272a3cb
--- /dev/null
+++ b/src/glu/mini/polytest.c
@@ -0,0 +1,938 @@
+/* $Id: polytest.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * This file is part of the polygon tesselation code contributed by
+ * Bogdan Sikorski
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "gluP.h"
+#include "tess.h"
+#endif
+
+
+
+static GLenum store_polygon_as_contour(GLUtriangulatorObj *);
+static void free_current_polygon(tess_polygon *);
+static void prepare_projection_info(GLUtriangulatorObj *);
+static GLdouble twice_the_polygon_area(tess_vertex *, tess_vertex *);
+static GLenum verify_edge_vertex_intersections(GLUtriangulatorObj *);
+void tess_find_contour_hierarchies(GLUtriangulatorObj *);
+static GLenum test_for_overlapping_contours(GLUtriangulatorObj *);
+static GLenum contours_overlap(tess_contour *, tess_polygon *);
+static GLenum is_contour_contained_in(tess_contour *, tess_contour *);
+static void add_new_exterior(GLUtriangulatorObj *, tess_contour *);
+static void add_new_interior(GLUtriangulatorObj *, tess_contour *,
+ tess_contour *);
+static void add_interior_with_hierarchy_check(GLUtriangulatorObj *,
+ tess_contour *, tess_contour *);
+static void reverse_hierarchy_and_add_exterior(GLUtriangulatorObj *,
+ tess_contour *,
+ tess_contour *);
+static GLboolean point_in_polygon(tess_contour *, GLdouble, GLdouble);
+static void shift_interior_to_exterior(GLUtriangulatorObj *, tess_contour *);
+static void add_exterior_with_check(GLUtriangulatorObj *, tess_contour *,
+ tess_contour *);
+static GLenum cut_out_hole(GLUtriangulatorObj *, tess_contour *,
+ tess_contour *);
+static GLenum merge_hole_with_contour(GLUtriangulatorObj *,
+ tess_contour *, tess_contour *,
+ tess_vertex *, tess_vertex *);
+
+static GLenum
+find_normal(GLUtriangulatorObj * tobj)
+{
+ tess_polygon *polygon = tobj->current_polygon;
+ tess_vertex *va, *vb, *vc;
+ GLdouble A, B, C;
+ GLdouble A0, A1, A2, B0, B1, B2;
+
+ va = polygon->vertices;
+ vb = va->next;
+ A0 = vb->location[0] - va->location[0];
+ A1 = vb->location[1] - va->location[1];
+ A2 = vb->location[2] - va->location[2];
+ for (vc = vb->next; vc != va; vc = vc->next) {
+ B0 = vc->location[0] - va->location[0];
+ B1 = vc->location[1] - va->location[1];
+ B2 = vc->location[2] - va->location[2];
+ A = A1 * B2 - A2 * B1;
+ B = A2 * B0 - A0 * B2;
+ C = A0 * B1 - A1 * B0;
+ if (fabs(A) > EPSILON || fabs(B) > EPSILON || fabs(C) > EPSILON) {
+ polygon->A = A;
+ polygon->B = B;
+ polygon->C = C;
+ polygon->D =
+ -A * va->location[0] - B * va->location[1] - C * va->location[2];
+ return GLU_NO_ERROR;
+ }
+ }
+ tess_call_user_error(tobj, GLU_TESS_ERROR7);
+ return GLU_ERROR;
+}
+
+void
+tess_test_polygon(GLUtriangulatorObj * tobj)
+{
+ tess_polygon *polygon = tobj->current_polygon;
+
+ /* any vertices defined? */
+ if (polygon->vertex_cnt < 3) {
+ free_current_polygon(polygon);
+ return;
+ }
+ /* wrap pointers */
+ polygon->last_vertex->next = polygon->vertices;
+ polygon->vertices->previous = polygon->last_vertex;
+ /* determine the normal */
+ if (find_normal(tobj) == GLU_ERROR)
+ return;
+ /* compare the normals of previously defined contours and this one */
+ /* first contour define ? */
+ if (tobj->contours == NULL) {
+ tobj->A = polygon->A;
+ tobj->B = polygon->B;
+ tobj->C = polygon->C;
+ tobj->D = polygon->D;
+ /* determine the best projection to use */
+ if (fabs(polygon->A) > fabs(polygon->B))
+ if (fabs(polygon->A) > fabs(polygon->C))
+ tobj->projection = OYZ;
+ else
+ tobj->projection = OXY;
+ else if (fabs(polygon->B) > fabs(polygon->C))
+ tobj->projection = OXZ;
+ else
+ tobj->projection = OXY;
+ }
+ else {
+ GLdouble a[3], b[3];
+ tess_vertex *vertex = polygon->vertices;
+
+ a[0] = tobj->A;
+ a[1] = tobj->B;
+ a[2] = tobj->C;
+ b[0] = polygon->A;
+ b[1] = polygon->B;
+ b[2] = polygon->C;
+
+ /* compare the normals */
+ if (fabs(a[1] * b[2] - a[2] * b[1]) > EPSILON ||
+ fabs(a[2] * b[0] - a[0] * b[2]) > EPSILON ||
+ fabs(a[0] * b[1] - a[1] * b[0]) > EPSILON) {
+ /* not coplanar */
+ tess_call_user_error(tobj, GLU_TESS_ERROR9);
+ return;
+ }
+ /* the normals are parallel - test for plane equation */
+ if (fabs(a[0] * vertex->location[0] + a[1] * vertex->location[1] +
+ a[2] * vertex->location[2] + tobj->D) > EPSILON) {
+ /* not the same plane */
+ tess_call_user_error(tobj, GLU_TESS_ERROR9);
+ return;
+ }
+ }
+ prepare_projection_info(tobj);
+ if (verify_edge_vertex_intersections(tobj) == GLU_ERROR)
+ return;
+ if (test_for_overlapping_contours(tobj) == GLU_ERROR)
+ return;
+ if (store_polygon_as_contour(tobj) == GLU_ERROR)
+ return;
+}
+
+static GLenum
+test_for_overlapping_contours(GLUtriangulatorObj * tobj)
+{
+ tess_contour *contour;
+ tess_polygon *polygon;
+
+ polygon = tobj->current_polygon;
+ for (contour = tobj->contours; contour != NULL; contour = contour->next)
+ if (contours_overlap(contour, polygon) != GLU_NO_ERROR) {
+ tess_call_user_error(tobj, GLU_TESS_ERROR5);
+ return GLU_ERROR;
+ }
+ return GLU_NO_ERROR;
+}
+
+static GLenum
+store_polygon_as_contour(GLUtriangulatorObj * tobj)
+{
+ tess_polygon *polygon = tobj->current_polygon;
+ tess_contour *contour = tobj->contours;
+
+ /* the first contour defined */
+ if (contour == NULL) {
+ if ((contour = (tess_contour *) malloc(sizeof(tess_contour))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ free_current_polygon(polygon);
+ return GLU_ERROR;
+ }
+ tobj->contours = tobj->last_contour = contour;
+ contour->next = contour->previous = NULL;
+ }
+ else {
+ if ((contour = (tess_contour *) malloc(sizeof(tess_contour))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ free_current_polygon(polygon);
+ return GLU_ERROR;
+ }
+ contour->previous = tobj->last_contour;
+ tobj->last_contour->next = contour;
+ tobj->last_contour = contour;
+ contour->next = NULL;
+ }
+ /* mark all vertices in new contour as not special */
+ /* and all are boundary edges */
+ {
+ tess_vertex *vertex;
+ GLuint vertex_cnt, i;
+
+ for (vertex = polygon->vertices, i = 0, vertex_cnt =
+ polygon->vertex_cnt; i < vertex_cnt; vertex = vertex->next, i++) {
+ vertex->shadow_vertex = NULL;
+ vertex->edge_flag = GL_TRUE;
+ }
+ }
+ contour->vertex_cnt = polygon->vertex_cnt;
+ contour->area = polygon->area;
+ contour->orientation = polygon->orientation;
+ contour->type = GLU_UNKNOWN;
+ contour->vertices = polygon->vertices;
+ contour->last_vertex = polygon->last_vertex;
+ polygon->vertices = polygon->last_vertex = NULL;
+ polygon->vertex_cnt = 0;
+ ++(tobj->contour_cnt);
+ return GLU_NO_ERROR;
+}
+
+static void
+free_current_polygon(tess_polygon * polygon)
+{
+ tess_vertex *vertex, *vertex_tmp;
+ GLuint i;
+
+ /* free current_polygon structures */
+ for (vertex = polygon->vertices, i = 0; i < polygon->vertex_cnt; i++) {
+ vertex_tmp = vertex->next;
+ free(vertex);
+ vertex = vertex_tmp;
+ }
+ polygon->vertices = polygon->last_vertex = NULL;
+ polygon->vertex_cnt = 0;
+}
+
+static void
+prepare_projection_info(GLUtriangulatorObj * tobj)
+{
+ tess_polygon *polygon = tobj->current_polygon;
+ tess_vertex *vertex, *last_vertex_ptr;
+ GLdouble area;
+
+ last_vertex_ptr = polygon->last_vertex;
+ switch (tobj->projection) {
+ case OXY:
+ for (vertex = polygon->vertices; vertex != last_vertex_ptr;
+ vertex = vertex->next) {
+ vertex->x = vertex->location[0];
+ vertex->y = vertex->location[1];
+ }
+ last_vertex_ptr->x = last_vertex_ptr->location[0];
+ last_vertex_ptr->y = last_vertex_ptr->location[1];
+ break;
+ case OXZ:
+ for (vertex = polygon->vertices; vertex != last_vertex_ptr;
+ vertex = vertex->next) {
+ vertex->x = vertex->location[0];
+ vertex->y = vertex->location[2];
+ }
+ last_vertex_ptr->x = last_vertex_ptr->location[0];
+ last_vertex_ptr->y = last_vertex_ptr->location[2];
+ break;
+ case OYZ:
+ for (vertex = polygon->vertices; vertex != last_vertex_ptr;
+ vertex = vertex->next) {
+ vertex->x = vertex->location[1];
+ vertex->y = vertex->location[2];
+ }
+ last_vertex_ptr->x = last_vertex_ptr->location[1];
+ last_vertex_ptr->y = last_vertex_ptr->location[2];
+ break;
+ }
+ area = twice_the_polygon_area(polygon->vertices, polygon->last_vertex);
+ if (area >= 0.0) {
+ polygon->orientation = GLU_CCW;
+ polygon->area = area;
+ }
+ else {
+ polygon->orientation = GLU_CW;
+ polygon->area = -area;
+ }
+}
+
+static GLdouble
+twice_the_polygon_area(tess_vertex * vertex, tess_vertex * last_vertex)
+{
+ tess_vertex *next;
+ GLdouble area, x, y;
+
+ area = 0.0;
+ x = vertex->x;
+ y = vertex->y;
+ vertex = vertex->next;
+ for (; vertex != last_vertex; vertex = vertex->next) {
+ next = vertex->next;
+ area +=
+ (vertex->x - x) * (next->y - y) - (vertex->y - y) * (next->x - x);
+ }
+ return area;
+}
+
+/* test if edges ab and cd intersect */
+/* if not return GLU_NO_ERROR, else if cross return GLU_TESS_ERROR8, */
+/* else if adjacent return GLU_TESS_ERROR4 */
+static GLenum
+edge_edge_intersect(tess_vertex * a,
+ tess_vertex * b, tess_vertex * c, tess_vertex * d)
+{
+ GLdouble denom, r, s;
+ GLdouble xba, ydc, yba, xdc, yac, xac;
+
+ xba = b->x - a->x;
+ yba = b->y - a->y;
+ xdc = d->x - c->x;
+ ydc = d->y - c->y;
+ xac = a->x - c->x;
+ yac = a->y - c->y;
+ denom = xba * ydc - yba * xdc;
+ r = yac * xdc - xac * ydc;
+ /* parallel? */
+ if (fabs(denom) < EPSILON) {
+ if (fabs(r) < EPSILON) {
+ /* colinear */
+ if (fabs(xba) < EPSILON) {
+ /* compare the Y coordinate */
+ if (yba > 0.0) {
+ if (
+ (fabs(a->y - c->y) < EPSILON
+ && fabs(c->y - b->y) < EPSILON)
+ || (fabs(a->y - d->y) < EPSILON
+ && fabs(d->y - b->y) <
+ EPSILON)) return GLU_TESS_ERROR4;
+
+ }
+ else {
+ if (
+ (fabs(b->y - c->y) < EPSILON
+ && fabs(c->y - a->y) < EPSILON)
+ || (fabs(b->y - d->y) < EPSILON
+ && fabs(d->y - a->y) <
+ EPSILON)) return GLU_TESS_ERROR4;
+ }
+ }
+ else {
+ /* compare the X coordinate */
+ if (xba > 0.0) {
+ if (
+ (fabs(a->x - c->x) < EPSILON
+ && fabs(c->x - b->x) < EPSILON)
+ || (fabs(a->x - d->x) < EPSILON
+ && fabs(d->x - b->x) <
+ EPSILON)) return GLU_TESS_ERROR4;
+ }
+ else {
+ if (
+ (fabs(b->x - c->x) < EPSILON
+ && fabs(c->x - a->x) < EPSILON)
+ || (fabs(b->x - d->x) < EPSILON
+ && fabs(d->x - a->x) <
+ EPSILON)) return GLU_TESS_ERROR4;
+ }
+ }
+ }
+ return GLU_NO_ERROR;
+ }
+ r /= denom;
+ s = (yac * xba - xac * yba) / denom;
+ /* test if one vertex lies on other edge */
+ if (((fabs(r) < EPSILON || (r < 1.0 + EPSILON && r > 1.0 - EPSILON)) &&
+ s > -EPSILON && s < 1.0 + EPSILON) ||
+ ((fabs(s) < EPSILON || (s < 1.0 + EPSILON && s > 1.0 - EPSILON)) &&
+ r > -EPSILON && r < 1.0 + EPSILON)) {
+ return GLU_TESS_ERROR4;
+ }
+ /* test for crossing */
+ if (r > -EPSILON && r < 1.0 + EPSILON && s > -EPSILON && s < 1.0 + EPSILON) {
+ return GLU_TESS_ERROR8;
+ }
+ return GLU_NO_ERROR;
+}
+
+static GLenum
+verify_edge_vertex_intersections(GLUtriangulatorObj * tobj)
+{
+ tess_polygon *polygon = tobj->current_polygon;
+ tess_vertex *vertex1, *last_vertex, *vertex2;
+ GLenum test;
+
+ last_vertex = polygon->last_vertex;
+ vertex1 = last_vertex;
+ for (vertex2 = vertex1->next->next;
+ vertex2->next != last_vertex; vertex2 = vertex2->next) {
+ test = edge_edge_intersect(vertex1, vertex1->next, vertex2,
+ vertex2->next);
+ if (test != GLU_NO_ERROR) {
+ tess_call_user_error(tobj, test);
+ return GLU_ERROR;
+ }
+ }
+ for (vertex1 = polygon->vertices;
+ vertex1->next->next != last_vertex; vertex1 = vertex1->next) {
+ for (vertex2 = vertex1->next->next;
+ vertex2 != last_vertex; vertex2 = vertex2->next) {
+ test = edge_edge_intersect(vertex1, vertex1->next, vertex2,
+ vertex2->next);
+ if (test != GLU_NO_ERROR) {
+ tess_call_user_error(tobj, test);
+ return GLU_ERROR;
+ }
+ }
+ }
+ return GLU_NO_ERROR;
+}
+
+static int
+#ifdef WIN32
+ __cdecl
+#endif
+area_compare(const void *a, const void *b)
+{
+ GLdouble area1, area2;
+
+ area1 = (*((tess_contour **) a))->area;
+ area2 = (*((tess_contour **) b))->area;
+ if (area1 < area2)
+ return 1;
+ if (area1 > area2)
+ return -1;
+ return 0;
+}
+
+void
+tess_find_contour_hierarchies(GLUtriangulatorObj * tobj)
+{
+ tess_contour **contours; /* dinamic array of pointers */
+ tess_contour *tmp_contour_ptr = tobj->contours;
+ GLuint cnt, i;
+ GLenum result;
+ GLboolean hierarchy_changed;
+
+ /* any contours? */
+ if (tobj->contour_cnt < 2) {
+ tobj->contours->type = GLU_EXTERIOR;
+ return;
+ }
+ if ((contours = (tess_contour **)
+ malloc(sizeof(tess_contour *) * (tobj->contour_cnt))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ return;
+ }
+ for (tmp_contour_ptr = tobj->contours, cnt = 0;
+ tmp_contour_ptr != NULL; tmp_contour_ptr = tmp_contour_ptr->next)
+ contours[cnt++] = tmp_contour_ptr;
+ /* now sort the contours in decreasing area size order */
+ qsort((void *) contours, (size_t) cnt, (size_t) sizeof(tess_contour *),
+ area_compare);
+ /* we leave just the first contour - remove others from list */
+ tobj->contours = contours[0];
+ tobj->contours->next = tobj->contours->previous = NULL;
+ tobj->last_contour = tobj->contours;
+ tobj->contour_cnt = 1;
+ /* first contour is the one with greatest area */
+ /* must be EXTERIOR */
+ tobj->contours->type = GLU_EXTERIOR;
+ tmp_contour_ptr = tobj->contours;
+ /* now we play! */
+ for (i = 1; i < cnt; i++) {
+ hierarchy_changed = GL_FALSE;
+ for (tmp_contour_ptr = tobj->contours;
+ tmp_contour_ptr != NULL; tmp_contour_ptr = tmp_contour_ptr->next) {
+ if (tmp_contour_ptr->type == GLU_EXTERIOR) {
+ /* check if contour completely contained in EXTERIOR */
+ result = is_contour_contained_in(tmp_contour_ptr, contours[i]);
+ switch (result) {
+ case GLU_INTERIOR:
+ /* now we have to check if contour is inside interiors */
+ /* or not */
+ /* any interiors? */
+ if (tmp_contour_ptr->next != NULL &&
+ tmp_contour_ptr->next->type == GLU_INTERIOR) {
+ /* for all interior, check if inside any of them */
+ /* if not inside any of interiors, its another */
+ /* interior */
+ /* or it may contain some interiors, then change */
+ /* the contained interiors to exterior ones */
+ add_interior_with_hierarchy_check(tobj,
+ tmp_contour_ptr,
+ contours[i]);
+ }
+ else {
+ /* not in interior, add as new interior contour */
+ add_new_interior(tobj, tmp_contour_ptr, contours[i]);
+ }
+ hierarchy_changed = GL_TRUE;
+ break;
+ case GLU_EXTERIOR:
+ /* ooops, the marked as EXTERIOR (contours[i]) is */
+ /* actually an interior of tmp_contour_ptr */
+ /* reverse the local hierarchy */
+ reverse_hierarchy_and_add_exterior(tobj, tmp_contour_ptr,
+ contours[i]);
+ hierarchy_changed = GL_TRUE;
+ break;
+ case GLU_NO_ERROR:
+ break;
+ default:
+ abort();
+ }
+ }
+ if (hierarchy_changed)
+ break; /* break from for loop */
+ }
+ if (hierarchy_changed == GL_FALSE) {
+ /* disjoint with all contours, add to contour list */
+ add_new_exterior(tobj, contours[i]);
+ }
+ }
+ free(contours);
+}
+
+/* returns GLU_INTERIOR if inner is completey enclosed within outer */
+/* returns GLU_EXTERIOR if outer is completely enclosed within inner */
+/* returns GLU_NO_ERROR if contours are disjoint */
+static GLenum
+is_contour_contained_in(tess_contour * outer, tess_contour * inner)
+{
+ GLenum relation_flag;
+
+ /* set relation_flag to relation of containment of first inner vertex */
+ /* regarding outer contour */
+ if (point_in_polygon(outer, inner->vertices->x, inner->vertices->y))
+ relation_flag = GLU_INTERIOR;
+ else
+ relation_flag = GLU_EXTERIOR;
+ if (relation_flag == GLU_INTERIOR)
+ return GLU_INTERIOR;
+ if (point_in_polygon(inner, outer->vertices->x, outer->vertices->y))
+ return GLU_EXTERIOR;
+ return GLU_NO_ERROR;
+}
+
+static GLboolean
+point_in_polygon(tess_contour * contour, GLdouble x, GLdouble y)
+{
+ tess_vertex *v1, *v2;
+ GLuint i, vertex_cnt;
+ GLdouble xp1, yp1, xp2, yp2;
+ GLboolean tst;
+
+ tst = GL_FALSE;
+ v1 = contour->vertices;
+ v2 = contour->vertices->previous;
+ for (i = 0, vertex_cnt = contour->vertex_cnt; i < vertex_cnt; i++) {
+ xp1 = v1->x;
+ yp1 = v1->y;
+ xp2 = v2->x;
+ yp2 = v2->y;
+ if ((((yp1 <= y) && (y < yp2)) || ((yp2 <= y) && (y < yp1))) &&
+ (x < (xp2 - xp1) * (y - yp1) / (yp2 - yp1) + xp1))
+ tst = (tst == GL_FALSE ? GL_TRUE : GL_FALSE);
+ v2 = v1;
+ v1 = v1->next;
+ }
+ return tst;
+}
+
+static GLenum
+contours_overlap(tess_contour * contour, tess_polygon * polygon)
+{
+ tess_vertex *vertex1, *vertex2;
+ GLuint vertex1_cnt, vertex2_cnt, i, j;
+ GLenum test;
+
+ vertex1 = contour->vertices;
+ vertex2 = polygon->vertices;
+ vertex1_cnt = contour->vertex_cnt;
+ vertex2_cnt = polygon->vertex_cnt;
+ for (i = 0; i < vertex1_cnt; vertex1 = vertex1->next, i++) {
+ for (j = 0; j < vertex2_cnt; vertex2 = vertex2->next, j++)
+ if ((test = edge_edge_intersect(vertex1, vertex1->next, vertex2,
+ vertex2->next)) != GLU_NO_ERROR)
+ return test;
+ }
+ return GLU_NO_ERROR;
+}
+
+static void
+add_new_exterior(GLUtriangulatorObj * tobj, tess_contour * contour)
+{
+ contour->type = GLU_EXTERIOR;
+ contour->next = NULL;
+ contour->previous = tobj->last_contour;
+ tobj->last_contour->next = contour;
+ tobj->last_contour = contour;
+}
+
+static void
+add_new_interior(GLUtriangulatorObj * tobj,
+ tess_contour * outer, tess_contour * contour)
+{
+ contour->type = GLU_INTERIOR;
+ contour->next = outer->next;
+ contour->previous = outer;
+ if (outer->next != NULL)
+ outer->next->previous = contour;
+ outer->next = contour;
+ if (tobj->last_contour == outer)
+ tobj->last_contour = contour;
+}
+
+static void
+add_interior_with_hierarchy_check(GLUtriangulatorObj * tobj,
+ tess_contour * outer,
+ tess_contour * contour)
+{
+ tess_contour *ptr;
+
+ /* for all interiors of outer check if they are interior of contour */
+ /* if so, change that interior to exterior and move it of of the */
+ /* interior sequence */
+ if (outer->next != NULL && outer->next->type == GLU_INTERIOR) {
+ GLenum test;
+
+ for (ptr = outer->next; ptr != NULL && ptr->type == GLU_INTERIOR;
+ ptr = ptr->next) {
+ test = is_contour_contained_in(ptr, contour);
+ switch (test) {
+ case GLU_INTERIOR:
+ /* contour is contained in one of the interiors */
+ /* check if possibly contained in other exteriors */
+ /* move ptr to first EXTERIOR */
+ for (; ptr != NULL && ptr->type == GLU_INTERIOR; ptr = ptr->next);
+ if (ptr == NULL)
+ /* another exterior */
+ add_new_exterior(tobj, contour);
+ else
+ add_exterior_with_check(tobj, ptr, contour);
+ return;
+ case GLU_EXTERIOR:
+ /* one of the interiors is contained in the contour */
+ /* change it to EXTERIOR, and shift it away from the */
+ /* interior sequence */
+ shift_interior_to_exterior(tobj, ptr);
+ break;
+ case GLU_NO_ERROR:
+ /* disjoint */
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+ /* add contour to the interior sequence */
+ add_new_interior(tobj, outer, contour);
+}
+
+static void
+reverse_hierarchy_and_add_exterior(GLUtriangulatorObj * tobj,
+ tess_contour * outer,
+ tess_contour * contour)
+{
+ tess_contour *ptr;
+
+ /* reverse INTERIORS to EXTERIORS */
+ /* any INTERIORS? */
+ if (outer->next != NULL && outer->next->type == GLU_INTERIOR)
+ for (ptr = outer->next; ptr != NULL && ptr->type == GLU_INTERIOR;
+ ptr = ptr->next) ptr->type = GLU_EXTERIOR;
+ /* the outer now becomes inner */
+ outer->type = GLU_INTERIOR;
+ /* contour is the EXTERIOR */
+ contour->next = outer;
+ if (tobj->contours == outer) {
+ /* first contour beeing reversed */
+ contour->previous = NULL;
+ tobj->contours = contour;
+ }
+ else {
+ outer->previous->next = contour;
+ contour->previous = outer->previous;
+ }
+ outer->previous = contour;
+}
+
+static void
+shift_interior_to_exterior(GLUtriangulatorObj * tobj, tess_contour * contour)
+{
+ contour->previous->next = contour->next;
+ if (contour->next != NULL)
+ contour->next->previous = contour->previous;
+ else
+ tobj->last_contour = contour->previous;
+}
+
+static void
+add_exterior_with_check(GLUtriangulatorObj * tobj,
+ tess_contour * outer, tess_contour * contour)
+{
+ GLenum test;
+
+ /* this contour might be interior to further exteriors - check */
+ /* if not, just add as a new exterior */
+ for (; outer != NULL && outer->type == GLU_EXTERIOR; outer = outer->next) {
+ test = is_contour_contained_in(outer, contour);
+ switch (test) {
+ case GLU_INTERIOR:
+ /* now we have to check if contour is inside interiors */
+ /* or not */
+ /* any interiors? */
+ if (outer->next != NULL && outer->next->type == GLU_INTERIOR) {
+ /* for all interior, check if inside any of them */
+ /* if not inside any of interiors, its another */
+ /* interior */
+ /* or it may contain some interiors, then change */
+ /* the contained interiors to exterior ones */
+ add_interior_with_hierarchy_check(tobj, outer, contour);
+ }
+ else {
+ /* not in interior, add as new interior contour */
+ add_new_interior(tobj, outer, contour);
+ }
+ return;
+ case GLU_NO_ERROR:
+ /* disjoint */
+ break;
+ default:
+ abort();
+ }
+ }
+ /* add contour to the exterior sequence */
+ add_new_exterior(tobj, contour);
+}
+
+void
+tess_handle_holes(GLUtriangulatorObj * tobj)
+{
+ tess_contour *contour, *hole;
+ GLenum exterior_orientation;
+
+ /* verify hole orientation */
+ for (contour = tobj->contours; contour != NULL;) {
+ exterior_orientation = contour->orientation;
+ for (contour = contour->next;
+ contour != NULL && contour->type == GLU_INTERIOR;
+ contour = contour->next) {
+ if (contour->orientation == exterior_orientation) {
+ tess_call_user_error(tobj, GLU_TESS_ERROR5);
+ return;
+ }
+ }
+ }
+ /* now cut-out holes */
+ for (contour = tobj->contours; contour != NULL;) {
+ hole = contour->next;
+ while (hole != NULL && hole->type == GLU_INTERIOR) {
+ if (cut_out_hole(tobj, contour, hole) == GLU_ERROR)
+ return;
+ hole = contour->next;
+ }
+ contour = contour->next;
+ }
+}
+
+static GLenum
+cut_out_hole(GLUtriangulatorObj * tobj,
+ tess_contour * contour, tess_contour * hole)
+{
+ tess_contour *tmp_hole;
+ tess_vertex *v1, *v2, *tmp_vertex;
+ GLuint vertex1_cnt, vertex2_cnt, tmp_vertex_cnt;
+ GLuint i, j, k;
+ GLenum test = 0;
+
+ /* find an edge connecting contour and hole not intersecting any other */
+ /* edge belonging to either the contour or any of the other holes */
+ for (v1 = contour->vertices, vertex1_cnt = contour->vertex_cnt, i = 0;
+ i < vertex1_cnt; i++, v1 = v1->next) {
+ for (v2 = hole->vertices, vertex2_cnt = hole->vertex_cnt, j = 0;
+ j < vertex2_cnt; j++, v2 = v2->next) {
+ /* does edge (v1,v2) intersect any edge of contour */
+ for (tmp_vertex = contour->vertices, tmp_vertex_cnt =
+ contour->vertex_cnt, k = 0; k < tmp_vertex_cnt;
+ tmp_vertex = tmp_vertex->next, k++) {
+ /* skip edge tests for edges directly connected */
+ if (v1 == tmp_vertex || v1 == tmp_vertex->next)
+ continue;
+ test = edge_edge_intersect(v1, v2, tmp_vertex, tmp_vertex->next);
+ if (test != GLU_NO_ERROR)
+ break;
+ }
+ if (test == GLU_NO_ERROR) {
+ /* does edge (v1,v2) intersect any edge of hole */
+ for (tmp_vertex = hole->vertices,
+ tmp_vertex_cnt = hole->vertex_cnt, k = 0;
+ k < tmp_vertex_cnt; tmp_vertex = tmp_vertex->next, k++) {
+ /* skip edge tests for edges directly connected */
+ if (v2 == tmp_vertex || v2 == tmp_vertex->next)
+ continue;
+ test =
+ edge_edge_intersect(v1, v2, tmp_vertex, tmp_vertex->next);
+ if (test != GLU_NO_ERROR)
+ break;
+ }
+ if (test == GLU_NO_ERROR) {
+ /* does edge (v1,v2) intersect any other hole? */
+ for (tmp_hole = hole->next;
+ tmp_hole != NULL && tmp_hole->type == GLU_INTERIOR;
+ tmp_hole = tmp_hole->next) {
+ /* does edge (v1,v2) intersect any edge of hole */
+ for (tmp_vertex = tmp_hole->vertices,
+ tmp_vertex_cnt = tmp_hole->vertex_cnt, k = 0;
+ k < tmp_vertex_cnt; tmp_vertex = tmp_vertex->next, k++) {
+ test = edge_edge_intersect(v1, v2, tmp_vertex,
+ tmp_vertex->next);
+ if (test != GLU_NO_ERROR)
+ break;
+ }
+ if (test != GLU_NO_ERROR)
+ break;
+ }
+ }
+ }
+ if (test == GLU_NO_ERROR) {
+ /* edge (v1,v2) is good for eliminating the hole */
+ if (merge_hole_with_contour(tobj, contour, hole, v1, v2)
+ == GLU_NO_ERROR)
+ return GLU_NO_ERROR;
+ else
+ return GLU_ERROR;
+ }
+ }
+ }
+ /* other holes are blocking all possible connections of hole */
+ /* with contour, we shift this hole as the last hole and retry */
+ for (tmp_hole = hole;
+ tmp_hole != NULL && tmp_hole->type == GLU_INTERIOR;
+ tmp_hole = tmp_hole->next);
+ contour->next = hole->next;
+ hole->next->previous = contour;
+ if (tmp_hole == NULL) {
+ /* last EXTERIOR contour, shift hole as last contour */
+ hole->next = NULL;
+ hole->previous = tobj->last_contour;
+ tobj->last_contour->next = hole;
+ tobj->last_contour = hole;
+ }
+ else {
+ tmp_hole->previous->next = hole;
+ hole->previous = tmp_hole->previous;
+ tmp_hole->previous = hole;
+ hole->next = tmp_hole;
+ }
+ hole = contour->next;
+ /* try once again - recurse */
+ return cut_out_hole(tobj, contour, hole);
+}
+
+static GLenum
+merge_hole_with_contour(GLUtriangulatorObj * tobj,
+ tess_contour * contour,
+ tess_contour * hole,
+ tess_vertex * v1, tess_vertex * v2)
+{
+ tess_vertex *v1_new, *v2_new;
+
+ /* make copies of v1 and v2, place them respectively after their originals */
+ if ((v1_new = (tess_vertex *) malloc(sizeof(tess_vertex))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ if ((v2_new = (tess_vertex *) malloc(sizeof(tess_vertex))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ v1_new->edge_flag = GL_TRUE;
+ v1_new->data = v1->data;
+ v1_new->location[0] = v1->location[0];
+ v1_new->location[1] = v1->location[1];
+ v1_new->location[2] = v1->location[2];
+ v1_new->x = v1->x;
+ v1_new->y = v1->y;
+ v1_new->shadow_vertex = v1;
+ v1->shadow_vertex = v1_new;
+ v1_new->next = v1->next;
+ v1_new->previous = v1;
+ v1->next->previous = v1_new;
+ v1->next = v1_new;
+ v2_new->edge_flag = GL_TRUE;
+ v2_new->data = v2->data;
+ v2_new->location[0] = v2->location[0];
+ v2_new->location[1] = v2->location[1];
+ v2_new->location[2] = v2->location[2];
+ v2_new->x = v2->x;
+ v2_new->y = v2->y;
+ v2_new->shadow_vertex = v2;
+ v2->shadow_vertex = v2_new;
+ v2_new->next = v2->next;
+ v2_new->previous = v2;
+ v2->next->previous = v2_new;
+ v2->next = v2_new;
+ /* link together the two lists */
+ v1->next = v2_new;
+ v2_new->previous = v1;
+ v2->next = v1_new;
+ v1_new->previous = v2;
+ /* update the vertex count of the contour */
+ contour->vertex_cnt += hole->vertex_cnt + 2;
+ /* remove the INTERIOR contour */
+ contour->next = hole->next;
+ if (hole->next != NULL)
+ hole->next->previous = contour;
+ free(hole);
+ /* update tobj structure */
+ --(tobj->contour_cnt);
+ if (contour->last_vertex == v1)
+ contour->last_vertex = v1_new;
+ /* mark two vertices with edge_flag */
+ v2->edge_flag = GL_FALSE;
+ v1->edge_flag = GL_FALSE;
+ return GLU_NO_ERROR;
+}
diff --git a/src/glu/mini/project.c b/src/glu/mini/project.c
new file mode 100644
index 0000000000..a2747de55f
--- /dev/null
+++ b/src/glu/mini/project.c
@@ -0,0 +1,402 @@
+/* $Id: project.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * This code was contributed by Marc Buffat (buffat@mecaflu.ec-lyon.fr).
+ * Thanks Marc!!!
+ */
+
+
+
+/* implementation de gluProject et gluUnproject */
+/* M. Buffat 17/2/95 */
+
+
+
+/*
+ * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in
+ * Input: m - the 4x4 matrix
+ * in - the 4x1 vector
+ * Output: out - the resulting 4x1 vector.
+ */
+static void
+transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
+{
+#define M(row,col) m[col*4+row]
+ out[0] =
+ M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
+ out[1] =
+ M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
+ out[2] =
+ M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
+ out[3] =
+ M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
+#undef M
+}
+
+
+
+
+/*
+ * Perform a 4x4 matrix multiplication (product = a x b).
+ * Input: a, b - matrices to multiply
+ * Output: product - product of a and b
+ */
+static void
+matmul(GLdouble * product, const GLdouble * a, const GLdouble * b)
+{
+ /* This matmul was contributed by Thomas Malik */
+ GLdouble temp[16];
+ GLint i;
+
+#define A(row,col) a[(col<<2)+row]
+#define B(row,col) b[(col<<2)+row]
+#define T(row,col) temp[(col<<2)+row]
+
+ /* i-te Zeile */
+ for (i = 0; i < 4; i++) {
+ T(i, 0) =
+ A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i,
+ 3) *
+ B(3, 0);
+ T(i, 1) =
+ A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i,
+ 3) *
+ B(3, 1);
+ T(i, 2) =
+ A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i,
+ 3) *
+ B(3, 2);
+ T(i, 3) =
+ A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i,
+ 3) *
+ B(3, 3);
+ }
+
+#undef A
+#undef B
+#undef T
+ MEMCPY(product, temp, 16 * sizeof(GLdouble));
+}
+
+
+
+/*
+ * Compute inverse of 4x4 transformation matrix.
+ * Code contributed by Jacques Leroy jle@star.be
+ * Return GL_TRUE for success, GL_FALSE for failure (singular matrix)
+ */
+static GLboolean
+invert_matrix(const GLdouble * m, GLdouble * out)
+{
+/* NB. OpenGL Matrices are COLUMN major. */
+#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; }
+#define MAT(m,r,c) (m)[(c)*4+(r)]
+
+ GLdouble wtmp[4][8];
+ GLdouble m0, m1, m2, m3, s;
+ GLdouble *r0, *r1, *r2, *r3;
+
+ r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
+
+ r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
+ r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
+ r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
+ r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
+ r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
+ r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
+ r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
+ r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
+ r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
+ r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
+ r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
+ r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
+
+ /* choose pivot - or die */
+ if (fabs(r3[0]) > fabs(r2[0]))
+ SWAP_ROWS(r3, r2);
+ if (fabs(r2[0]) > fabs(r1[0]))
+ SWAP_ROWS(r2, r1);
+ if (fabs(r1[0]) > fabs(r0[0]))
+ SWAP_ROWS(r1, r0);
+ if (0.0 == r0[0])
+ return GL_FALSE;
+
+ /* eliminate first variable */
+ m1 = r1[0] / r0[0];
+ m2 = r2[0] / r0[0];
+ m3 = r3[0] / r0[0];
+ s = r0[1];
+ r1[1] -= m1 * s;
+ r2[1] -= m2 * s;
+ r3[1] -= m3 * s;
+ s = r0[2];
+ r1[2] -= m1 * s;
+ r2[2] -= m2 * s;
+ r3[2] -= m3 * s;
+ s = r0[3];
+ r1[3] -= m1 * s;
+ r2[3] -= m2 * s;
+ r3[3] -= m3 * s;
+ s = r0[4];
+ if (s != 0.0) {
+ r1[4] -= m1 * s;
+ r2[4] -= m2 * s;
+ r3[4] -= m3 * s;
+ }
+ s = r0[5];
+ if (s != 0.0) {
+ r1[5] -= m1 * s;
+ r2[5] -= m2 * s;
+ r3[5] -= m3 * s;
+ }
+ s = r0[6];
+ if (s != 0.0) {
+ r1[6] -= m1 * s;
+ r2[6] -= m2 * s;
+ r3[6] -= m3 * s;
+ }
+ s = r0[7];
+ if (s != 0.0) {
+ r1[7] -= m1 * s;
+ r2[7] -= m2 * s;
+ r3[7] -= m3 * s;
+ }
+
+ /* choose pivot - or die */
+ if (fabs(r3[1]) > fabs(r2[1]))
+ SWAP_ROWS(r3, r2);
+ if (fabs(r2[1]) > fabs(r1[1]))
+ SWAP_ROWS(r2, r1);
+ if (0.0 == r1[1])
+ return GL_FALSE;
+
+ /* eliminate second variable */
+ m2 = r2[1] / r1[1];
+ m3 = r3[1] / r1[1];
+ r2[2] -= m2 * r1[2];
+ r3[2] -= m3 * r1[2];
+ r2[3] -= m2 * r1[3];
+ r3[3] -= m3 * r1[3];
+ s = r1[4];
+ if (0.0 != s) {
+ r2[4] -= m2 * s;
+ r3[4] -= m3 * s;
+ }
+ s = r1[5];
+ if (0.0 != s) {
+ r2[5] -= m2 * s;
+ r3[5] -= m3 * s;
+ }
+ s = r1[6];
+ if (0.0 != s) {
+ r2[6] -= m2 * s;
+ r3[6] -= m3 * s;
+ }
+ s = r1[7];
+ if (0.0 != s) {
+ r2[7] -= m2 * s;
+ r3[7] -= m3 * s;
+ }
+
+ /* choose pivot - or die */
+ if (fabs(r3[2]) > fabs(r2[2]))
+ SWAP_ROWS(r3, r2);
+ if (0.0 == r2[2])
+ return GL_FALSE;
+
+ /* eliminate third variable */
+ m3 = r3[2] / r2[2];
+ r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
+ r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
+
+ /* last check */
+ if (0.0 == r3[3])
+ return GL_FALSE;
+
+ s = 1.0 / r3[3]; /* now back substitute row 3 */
+ r3[4] *= s;
+ r3[5] *= s;
+ r3[6] *= s;
+ r3[7] *= s;
+
+ m2 = r2[3]; /* now back substitute row 2 */
+ s = 1.0 / r2[2];
+ r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
+ r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
+ m1 = r1[3];
+ r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
+ r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
+ m0 = r0[3];
+ r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
+ r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
+
+ m1 = r1[2]; /* now back substitute row 1 */
+ s = 1.0 / r1[1];
+ r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
+ r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
+ m0 = r0[2];
+ r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
+ r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
+
+ m0 = r0[1]; /* now back substitute row 0 */
+ s = 1.0 / r0[0];
+ r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
+ r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
+
+ MAT(out, 0, 0) = r0[4];
+ MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
+ MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
+ MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
+ MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
+ MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
+ MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
+ MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
+ MAT(out, 3, 3) = r3[7];
+
+ return GL_TRUE;
+
+#undef MAT
+#undef SWAP_ROWS
+}
+
+
+
+/* projection du point (objx,objy,obz) sur l'ecran (winx,winy,winz) */
+GLint GLAPIENTRY
+gluProject(GLdouble objx, GLdouble objy, GLdouble objz,
+ const GLdouble model[16], const GLdouble proj[16],
+ const GLint viewport[4],
+ GLdouble * winx, GLdouble * winy, GLdouble * winz)
+{
+ /* matrice de transformation */
+ GLdouble in[4], out[4];
+
+ /* initilise la matrice et le vecteur a transformer */
+ in[0] = objx;
+ in[1] = objy;
+ in[2] = objz;
+ in[3] = 1.0;
+ transform_point(out, model, in);
+ transform_point(in, proj, out);
+
+ /* d'ou le resultat normalise entre -1 et 1 */
+ if (in[3] == 0.0)
+ return GL_FALSE;
+
+ in[0] /= in[3];
+ in[1] /= in[3];
+ in[2] /= in[3];
+
+ /* en coordonnees ecran */
+ *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
+ *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;
+ /* entre 0 et 1 suivant z */
+ *winz = (1 + in[2]) / 2;
+ return GL_TRUE;
+}
+
+
+
+/* transformation du point ecran (winx,winy,winz) en point objet */
+GLint GLAPIENTRY
+gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
+ const GLdouble model[16], const GLdouble proj[16],
+ const GLint viewport[4],
+ GLdouble * objx, GLdouble * objy, GLdouble * objz)
+{
+ /* matrice de transformation */
+ GLdouble m[16], A[16];
+ GLdouble in[4], out[4];
+
+ /* transformation coordonnees normalisees entre -1 et 1 */
+ in[0] = (winx - viewport[0]) * 2 / viewport[2] - 1.0;
+ in[1] = (winy - viewport[1]) * 2 / viewport[3] - 1.0;
+ in[2] = 2 * winz - 1.0;
+ in[3] = 1.0;
+
+ /* calcul transformation inverse */
+ matmul(A, proj, model);
+ invert_matrix(A, m);
+
+ /* d'ou les coordonnees objets */
+ transform_point(out, m, in);
+ if (out[3] == 0.0)
+ return GL_FALSE;
+ *objx = out[0] / out[3];
+ *objy = out[1] / out[3];
+ *objz = out[2] / out[3];
+ return GL_TRUE;
+}
+
+
+/*
+ * New in GLU 1.3
+ * This is like gluUnProject but also takes near and far DepthRange values.
+ */
+#ifdef GLU_VERSION_1_3
+GLint GLAPIENTRY
+gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw,
+ const GLdouble modelMatrix[16],
+ const GLdouble projMatrix[16],
+ const GLint viewport[4],
+ GLclampd nearZ, GLclampd farZ,
+ GLdouble * objx, GLdouble * objy, GLdouble * objz,
+ GLdouble * objw)
+{
+ /* matrice de transformation */
+ GLdouble m[16], A[16];
+ GLdouble in[4], out[4];
+ GLdouble z = nearZ + winz * (farZ - nearZ);
+
+ /* transformation coordonnees normalisees entre -1 et 1 */
+ in[0] = (winx - viewport[0]) * 2 / viewport[2] - 1.0;
+ in[1] = (winy - viewport[1]) * 2 / viewport[3] - 1.0;
+ in[2] = 2.0 * z - 1.0;
+ in[3] = clipw;
+
+ /* calcul transformation inverse */
+ matmul(A, projMatrix, modelMatrix);
+ invert_matrix(A, m);
+
+ /* d'ou les coordonnees objets */
+ transform_point(out, m, in);
+ if (out[3] == 0.0)
+ return GL_FALSE;
+ *objx = out[0] / out[3];
+ *objy = out[1] / out[3];
+ *objz = out[2] / out[3];
+ *objw = out[3];
+ return GL_TRUE;
+}
+#endif
diff --git a/src/glu/mini/quadric.c b/src/glu/mini/quadric.c
new file mode 100644
index 0000000000..015552e123
--- /dev/null
+++ b/src/glu/mini/quadric.c
@@ -0,0 +1,774 @@
+/* $Id: quadric.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1999-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* TODO:
+ * texture coordinate support
+ * flip normals according to orientation
+ * there's still some inside/outside orientation bugs in possibly all
+ * but the sphere function
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gluP.h"
+#endif
+
+
+
+#ifndef M_PI
+# define M_PI (3.1415926)
+#endif
+
+
+/*
+ * Convert degrees to radians:
+ */
+#define DEG_TO_RAD(A) ((A)*(M_PI/180.0))
+
+
+/*
+ * Sin and Cos for degree angles:
+ */
+#define SIND( A ) sin( (A)*(M_PI/180.0) )
+#define COSD( A) cos( (A)*(M_PI/180.0) )
+
+
+/*
+ * Texture coordinates if texture flag is set
+ */
+#define TXTR_COORD(x,y) if (qobj->TextureFlag) glTexCoord2f(x,y);
+
+
+
+struct GLUquadric
+{
+ GLenum DrawStyle; /* GLU_FILL, LINE, SILHOUETTE, or POINT */
+ GLenum Orientation; /* GLU_INSIDE or GLU_OUTSIDE */
+ GLboolean TextureFlag; /* Generate texture coords? */
+ GLenum Normals; /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */
+ void (GLCALLBACK * ErrorFunc) (GLenum err); /* Error handler callback function */
+};
+
+
+
+/*
+ * Process a GLU error.
+ */
+static void
+quadric_error(GLUquadricObj * qobj, GLenum error, const char *msg)
+{
+ /* Call the error call back function if any */
+ if (qobj->ErrorFunc) {
+ (*qobj->ErrorFunc) (error);
+ }
+ /* Print a message to stdout if MESA_DEBUG variable is defined */
+ if (getenv("MESA_DEBUG")) {
+ fprintf(stderr, "GLUError: %s: %s\n", (char *) gluErrorString(error),
+ msg);
+ }
+}
+
+
+
+
+GLUquadricObj *GLAPIENTRY
+gluNewQuadric(void)
+{
+ GLUquadricObj *q;
+
+ q = (GLUquadricObj *) malloc(sizeof(struct GLUquadric));
+ if (q) {
+ q->DrawStyle = GLU_FILL;
+ q->Orientation = GLU_OUTSIDE;
+ q->TextureFlag = GL_FALSE;
+ q->Normals = GLU_SMOOTH;
+ q->ErrorFunc = NULL;
+ }
+ return q;
+}
+
+
+
+void GLAPIENTRY
+gluDeleteQuadric(GLUquadricObj * state)
+{
+ if (state) {
+ free((void *) state);
+ }
+}
+
+
+
+/*
+ * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE,
+ * or GLU_POINT.
+ */
+void GLAPIENTRY
+gluQuadricDrawStyle(GLUquadricObj * quadObject, GLenum drawStyle)
+{
+ if (quadObject && (drawStyle == GLU_FILL || drawStyle == GLU_LINE
+ || drawStyle == GLU_SILHOUETTE
+ || drawStyle == GLU_POINT)) {
+ quadObject->DrawStyle = drawStyle;
+ }
+ else {
+ quadric_error(quadObject, GLU_INVALID_ENUM, "qluQuadricDrawStyle");
+ }
+}
+
+
+
+/*
+ * Set the orientation to GLU_INSIDE or GLU_OUTSIDE.
+ */
+void GLAPIENTRY
+gluQuadricOrientation(GLUquadricObj * quadObject, GLenum orientation)
+{
+ if (quadObject
+ && (orientation == GLU_INSIDE || orientation == GLU_OUTSIDE)) {
+ quadObject->Orientation = orientation;
+ }
+ else {
+ quadric_error(quadObject, GLU_INVALID_ENUM, "qluQuadricOrientation");
+ }
+}
+
+
+
+/*
+ * Set the error handler callback function.
+ */
+void GLAPIENTRY
+gluQuadricCallback(GLUquadricObj * qobj,
+ GLenum which, void (GLCALLBACK * fn) ())
+{
+ /*
+ * UGH, this is a mess! I thought ANSI was a standard.
+ */
+ if (qobj && which == GLU_ERROR) {
+#ifdef __CYGWIN32__
+ qobj->ErrorFunc = (void (GLCALLBACKPCAST) (GLenum)) fn;
+#elif defined(OPENSTEP)
+ qobj->ErrorFunc = (void (*)(GLenum)) fn;
+#elif defined(_WIN32)
+ qobj->ErrorFunc = (void (GLCALLBACK *) (int)) fn;
+#elif defined(__STORM__)
+ qobj->ErrorFunc = (void (GLCALLBACK *) (GLenum)) fn;
+#elif defined(__BEOS__)
+ qobj->ErrorFunc = (void (*)(GLenum)) fn;
+#else
+ qobj->ErrorFunc = (void (GLCALLBACK *) ()) fn;
+#endif
+ }
+}
+
+
+void GLAPIENTRY
+gluQuadricNormals(GLUquadricObj * quadObject, GLenum normals)
+{
+ if (quadObject
+ && (normals == GLU_NONE || normals == GLU_FLAT
+ || normals == GLU_SMOOTH)) {
+ quadObject->Normals = normals;
+ }
+}
+
+
+void GLAPIENTRY
+gluQuadricTexture(GLUquadricObj * quadObject, GLboolean textureCoords)
+{
+ if (quadObject) {
+ quadObject->TextureFlag = textureCoords;
+ }
+}
+
+
+
+
+/*
+ * Call glNormal3f after scaling normal to unit length.
+ */
+static void
+normal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+}
+
+
+
+void GLAPIENTRY
+gluCylinder(GLUquadricObj * qobj,
+ GLdouble baseRadius, GLdouble topRadius,
+ GLdouble height, GLint slices, GLint stacks)
+{
+ GLdouble da, r, dr, dz;
+ GLfloat x, y, z, nz, nsign;
+ GLint i, j;
+
+ if (qobj->Orientation == GLU_INSIDE) {
+ nsign = -1.0;
+ }
+ else {
+ nsign = 1.0;
+ }
+
+ da = 2.0 * M_PI / slices;
+ dr = (topRadius - baseRadius) / stacks;
+ dz = height / stacks;
+ nz = (baseRadius - topRadius) / height; /* Z component of normal vectors */
+
+ if (qobj->DrawStyle == GLU_POINT) {
+ glBegin(GL_POINTS);
+ for (i = 0; i < slices; i++) {
+ x = cos(i * da);
+ y = sin(i * da);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+
+ z = 0.0;
+ r = baseRadius;
+ for (j = 0; j <= stacks; j++) {
+ glVertex3f(x * r, y * r, z);
+ z += dz;
+ r += dr;
+ }
+ }
+ glEnd();
+ }
+ else if (qobj->DrawStyle == GLU_LINE || qobj->DrawStyle == GLU_SILHOUETTE) {
+ /* Draw rings */
+ if (qobj->DrawStyle == GLU_LINE) {
+ z = 0.0;
+ r = baseRadius;
+ for (j = 0; j <= stacks; j++) {
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < slices; i++) {
+ x = cos(i * da);
+ y = sin(i * da);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f(x * r, y * r, z);
+ }
+ glEnd();
+ z += dz;
+ r += dr;
+ }
+ }
+ else {
+ /* draw one ring at each end */
+ if (baseRadius != 0.0) {
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < slices; i++) {
+ x = cos(i * da);
+ y = sin(i * da);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f(x * baseRadius, y * baseRadius, 0.0);
+ }
+ glEnd();
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < slices; i++) {
+ x = cos(i * da);
+ y = sin(i * da);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f(x * topRadius, y * topRadius, height);
+ }
+ glEnd();
+ }
+ }
+ /* draw length lines */
+ glBegin(GL_LINES);
+ for (i = 0; i < slices; i++) {
+ x = cos(i * da);
+ y = sin(i * da);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f(x * baseRadius, y * baseRadius, 0.0);
+ glVertex3f(x * topRadius, y * topRadius, height);
+ }
+ glEnd();
+ }
+ else if (qobj->DrawStyle == GLU_FILL) {
+ GLfloat ds = 1.0 / slices;
+ GLfloat dt = 1.0 / stacks;
+ GLfloat t = 0.0;
+ z = 0.0;
+ r = baseRadius;
+ for (j = 0; j < stacks; j++) {
+ GLfloat s = 0.0;
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= slices; i++) {
+ GLfloat x, y;
+ if (i == slices) {
+ x = sin(0.0);
+ y = cos(0.0);
+ }
+ else {
+ x = sin(i * da);
+ y = cos(i * da);
+ }
+ if (nsign == 1.0) {
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ TXTR_COORD(s, t);
+ glVertex3f(x * r, y * r, z);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ TXTR_COORD(s, t + dt);
+ glVertex3f(x * (r + dr), y * (r + dr), z + dz);
+ }
+ else {
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ TXTR_COORD(s, t);
+ glVertex3f(x * r, y * r, z);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ TXTR_COORD(s, t + dt);
+ glVertex3f(x * (r + dr), y * (r + dr), z + dz);
+ }
+ s += ds;
+ } /* for slices */
+ glEnd();
+ r += dr;
+ t += dt;
+ z += dz;
+ } /* for stacks */
+ }
+}
+
+
+
+
+
+void GLAPIENTRY
+gluSphere(GLUquadricObj * qobj, GLdouble radius, GLint slices, GLint stacks)
+{
+ GLfloat rho, drho, theta, dtheta;
+ GLfloat x, y, z;
+ GLfloat s, t, ds, dt;
+ GLint i, j, imin, imax;
+ GLboolean normals;
+ GLfloat nsign;
+
+ if (qobj->Normals == GLU_NONE) {
+ normals = GL_FALSE;
+ }
+ else {
+ normals = GL_TRUE;
+ }
+ if (qobj->Orientation == GLU_INSIDE) {
+ nsign = -1.0;
+ }
+ else {
+ nsign = 1.0;
+ }
+
+ drho = M_PI / (GLfloat) stacks;
+ dtheta = 2.0 * M_PI / (GLfloat) slices;
+
+ /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
+ /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
+ /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */
+
+ if (qobj->DrawStyle == GLU_FILL) {
+ if (!qobj->TextureFlag) {
+ /* draw +Z end as a triangle fan */
+ glBegin(GL_TRIANGLE_FAN);
+/* glNormal3f(0.0, 0.0, 1.0); */
+ glVertex3f(0.0, 0.0, nsign * radius);
+ for (j = 0; j <= slices; j++) {
+ theta = (j == slices) ? 0.0 : j * dtheta;
+ x = -sin(theta) * sin(drho);
+ y = cos(theta) * sin(drho);
+ z = nsign * cos(drho);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+
+ ds = 1.0 / slices;
+ dt = 1.0 / stacks;
+ t = 1.0; /* because loop now runs from 0 */
+ if (qobj->TextureFlag) {
+ imin = 0;
+ imax = stacks;
+ }
+ else {
+ imin = 1;
+ imax = stacks - 1;
+ }
+
+ /* draw intermediate stacks as quad strips */
+ for (i = imin; i < imax; i++) {
+ rho = i * drho;
+ glBegin(GL_QUAD_STRIP);
+ s = 0.0;
+ for (j = 0; j <= slices; j++) {
+ theta = (j == slices) ? 0.0 : j * dtheta;
+ x = -sin(theta) * sin(rho);
+ y = cos(theta) * sin(rho);
+ z = nsign * cos(rho);
+ TXTR_COORD(s, t);
+ glVertex3f(x * radius, y * radius, z * radius);
+ x = -sin(theta) * sin(rho + drho);
+ y = cos(theta) * sin(rho + drho);
+ z = nsign * cos(rho + drho);
+ TXTR_COORD(s, t - dt);
+ s += ds;
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ t -= dt;
+ }
+
+ if (!qobj->TextureFlag) {
+ /* draw -Z end as a triangle fan */
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex3f(0.0, 0.0, -radius * nsign);
+ rho = M_PI - drho;
+ s = 1.0;
+ t = dt;
+ for (j = slices; j >= 0; j--) {
+ theta = (j == slices) ? 0.0 : j * dtheta;
+ x = -sin(theta) * sin(rho);
+ y = cos(theta) * sin(rho);
+ z = nsign * cos(rho);
+ s -= ds;
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+ }
+ else if (qobj->DrawStyle == GLU_LINE || qobj->DrawStyle == GLU_SILHOUETTE) {
+ /* draw stack lines */
+ for (i = 1; i < stacks; i++) { /* stack line at i==stacks-1 was missing here */
+ rho = i * drho;
+ glBegin(GL_LINE_LOOP);
+ for (j = 0; j < slices; j++) {
+ theta = j * dtheta;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+ /* draw slice lines */
+ for (j = 0; j < slices; j++) {
+ theta = j * dtheta;
+ glBegin(GL_LINE_STRIP);
+ for (i = 0; i <= stacks; i++) {
+ rho = i * drho;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+ }
+ else if (qobj->DrawStyle == GLU_POINT) {
+ /* top and bottom-most points */
+ glBegin(GL_POINTS);
+ glVertex3f(0.0, 0.0, radius);
+ glVertex3f(0.0, 0.0, -radius);
+
+ /* loop over stacks */
+ for (i = 1; i < stacks - 1; i++) {
+ rho = i * drho;
+ for (j = 0; j < slices; j++) {
+ theta = j * dtheta;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ }
+ glEnd();
+ }
+
+}
+
+
+
+void GLAPIENTRY
+gluDisk(GLUquadricObj * qobj,
+ GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops)
+{
+ GLfloat da, dr;
+#if 0
+ GLdouble a, da;
+ GLfloat r, dr;
+ GLfloat x, y;
+ GLfloat r1, r2, dtc;
+ GLint s, l;
+#endif
+
+
+ da = 2.0 * M_PI / slices;
+ dr = (outerRadius - innerRadius) / (GLfloat) loops;
+
+ switch (qobj->DrawStyle) {
+ case GLU_FILL:
+ {
+ /* texture of a gluDisk is a cut out of the texture unit square
+ * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
+ * (linear mapping)
+ */
+ GLfloat dtc = 2.0f * outerRadius;
+ GLfloat sa, ca;
+ GLfloat r1 = innerRadius;
+ GLint l;
+ for (l = 0; l < loops; l++) {
+ GLfloat r2 = r1 + dr;
+ if (qobj->Orientation == GLU_OUTSIDE) {
+ GLint s;
+ glBegin(GL_QUAD_STRIP);
+ for (s = 0; s <= slices; s++) {
+ GLfloat a;
+ if (s == slices)
+ a = 0.0;
+ else
+ a = s * da;
+ sa = sin(a);
+ ca = cos(a);
+ TXTR_COORD(0.5 + sa * r2 / dtc, 0.5 + ca * r2 / dtc);
+ glVertex2f(r2 * sa, r2 * ca);
+ TXTR_COORD(0.5 + sa * r1 / dtc, 0.5 + ca * r1 / dtc);
+ glVertex2f(r1 * sa, r1 * ca);
+ }
+ glEnd();
+ }
+ else {
+ GLint s;
+ glBegin(GL_QUAD_STRIP);
+ for (s = slices; s >= 0; s--) {
+ GLfloat a;
+ if (s == slices)
+ a = 0.0;
+ else
+ a = s * da;
+ sa = sin(a);
+ ca = cos(a);
+ TXTR_COORD(0.5 - sa * r2 / dtc, 0.5 + ca * r2 / dtc);
+ glVertex2f(r2 * sa, r2 * ca);
+ TXTR_COORD(0.5 - sa * r1 / dtc, 0.5 + ca * r1 / dtc);
+ glVertex2f(r1 * sa, r1 * ca);
+ }
+ glEnd();
+ }
+ r1 = r2;
+ }
+ break;
+ }
+ case GLU_LINE:
+ {
+ GLint l, s;
+ /* draw loops */
+ for (l = 0; l <= loops; l++) {
+ GLfloat r = innerRadius + l * dr;
+ glBegin(GL_LINE_LOOP);
+ for (s = 0; s < slices; s++) {
+ GLfloat a = s * da;
+ glVertex2f(r * sin(a), r * cos(a));
+ }
+ glEnd();
+ }
+ /* draw spokes */
+ for (s = 0; s < slices; s++) {
+ GLfloat a = s * da;
+ GLfloat x = sin(a);
+ GLfloat y = cos(a);
+ glBegin(GL_LINE_STRIP);
+ for (l = 0; l <= loops; l++) {
+ GLfloat r = innerRadius + l * dr;
+ glVertex2f(r * x, r * y);
+ }
+ glEnd();
+ }
+ break;
+ }
+ case GLU_POINT:
+ {
+ GLint s;
+ glBegin(GL_POINTS);
+ for (s = 0; s < slices; s++) {
+ GLfloat a = s * da;
+ GLfloat x = sin(a);
+ GLfloat y = cos(a);
+ GLint l;
+ for (l = 0; l <= loops; l++) {
+ GLfloat r = innerRadius * l * dr;
+ glVertex2f(r * x, r * y);
+ }
+ }
+ glEnd();
+ break;
+ }
+ case GLU_SILHOUETTE:
+ {
+ if (innerRadius != 0.0) {
+ GLfloat a;
+ glBegin(GL_LINE_LOOP);
+ for (a = 0.0; a < 2.0 * M_PI; a += da) {
+ GLfloat x = innerRadius * sin(a);
+ GLfloat y = innerRadius * cos(a);
+ glVertex2f(x, y);
+ }
+ glEnd();
+ }
+ {
+ GLfloat a;
+ glBegin(GL_LINE_LOOP);
+ for (a = 0; a < 2.0 * M_PI; a += da) {
+ GLfloat x = outerRadius * sin(a);
+ GLfloat y = outerRadius * cos(a);
+ glVertex2f(x, y);
+ }
+ glEnd();
+ }
+ break;
+ }
+ default:
+ abort();
+ }
+}
+
+
+
+void GLAPIENTRY
+gluPartialDisk(GLUquadricObj * qobj, GLdouble innerRadius,
+ GLdouble outerRadius, GLint slices, GLint loops,
+ GLdouble startAngle, GLdouble sweepAngle)
+{
+ if (qobj->DrawStyle == GLU_POINT) {
+ GLint loop, slice;
+ GLdouble radius, delta_radius;
+ GLdouble angle, delta_angle;
+ delta_radius = (outerRadius - innerRadius) / (loops - 1);
+ delta_angle = DEG_TO_RAD((sweepAngle) / (slices - 1));
+ glBegin(GL_POINTS);
+ radius = innerRadius;
+ for (loop = 0; loop < loops; loop++) {
+ angle = DEG_TO_RAD(startAngle);
+ for (slice = 0; slice < slices; slice++) {
+ glVertex2f(radius * sin(angle), radius * cos(angle));
+ angle += delta_angle;
+ }
+ radius += delta_radius;
+ }
+ glEnd();
+ }
+ else if (qobj->DrawStyle == GLU_LINE) {
+ GLint loop, slice;
+ GLdouble radius, delta_radius;
+ GLdouble angle, delta_angle;
+ delta_radius = (outerRadius - innerRadius) / loops;
+ delta_angle = DEG_TO_RAD(sweepAngle / slices);
+ /* draw rings */
+ radius = innerRadius;
+ for (loop = 0; loop < loops; loop++) {
+ angle = DEG_TO_RAD(startAngle);
+ glBegin(GL_LINE_STRIP);
+ for (slice = 0; slice <= slices; slice++) {
+ glVertex2f(radius * sin(angle), radius * cos(angle));
+ angle += delta_angle;
+ }
+ glEnd();
+ radius += delta_radius;
+ }
+ /* draw spokes */
+ angle = DEG_TO_RAD(startAngle);
+ for (slice = 0; slice <= slices; slice++) {
+ radius = innerRadius;
+ glBegin(GL_LINE_STRIP);
+ for (loop = 0; loop < loops; loop++) {
+ glVertex2f(radius * sin(angle), radius * cos(angle));
+ radius += delta_radius;
+ }
+ glEnd();
+ angle += delta_angle;
+ }
+ }
+ else if (qobj->DrawStyle == GLU_SILHOUETTE) {
+ GLint slice;
+ GLdouble angle, delta_angle;
+ delta_angle = DEG_TO_RAD(sweepAngle / slices);
+ /* draw outer ring */
+ glBegin(GL_LINE_STRIP);
+ angle = DEG_TO_RAD(startAngle);
+ for (slice = 0; slice <= slices; slice++) {
+ glVertex2f(outerRadius * sin(angle), outerRadius * cos(angle));
+ angle += delta_angle;
+ }
+ glEnd();
+ /* draw inner ring */
+ if (innerRadius > 0.0) {
+ glBegin(GL_LINE_STRIP);
+ angle = DEG_TO_RAD(startAngle);
+ for (slice = 0; slice < slices; slice++) {
+ glVertex2f(innerRadius * sin(angle), innerRadius * cos(angle));
+ angle += delta_angle;
+ }
+ glEnd();
+ }
+ /* draw spokes */
+ if (sweepAngle < 360.0) {
+ GLdouble stopAngle = startAngle + sweepAngle;
+ glBegin(GL_LINES);
+ glVertex2f(innerRadius * SIND(startAngle),
+ innerRadius * COSD(startAngle));
+ glVertex2f(outerRadius * SIND(startAngle),
+ outerRadius * COSD(startAngle));
+ glVertex2f(innerRadius * SIND(stopAngle),
+ innerRadius * COSD(stopAngle));
+ glVertex2f(outerRadius * SIND(stopAngle),
+ outerRadius * COSD(stopAngle));
+ glEnd();
+ }
+ }
+ else if (qobj->DrawStyle == GLU_FILL) {
+ GLint loop, slice;
+ GLdouble radius, delta_radius;
+ GLdouble angle, delta_angle;
+ delta_radius = (outerRadius - innerRadius) / loops;
+ delta_angle = DEG_TO_RAD(sweepAngle / slices);
+ radius = innerRadius;
+ for (loop = 0; loop < loops; loop++) {
+ glBegin(GL_QUAD_STRIP);
+ angle = DEG_TO_RAD(startAngle);
+ for (slice = 0; slice <= slices; slice++) {
+ if (qobj->Orientation == GLU_OUTSIDE) {
+ glVertex2f((radius + delta_radius) * sin(angle),
+ (radius + delta_radius) * cos(angle));
+ glVertex2f(radius * sin(angle), radius * cos(angle));
+ }
+ else {
+ glVertex2f(radius * sin(angle), radius * cos(angle));
+ glVertex2f((radius + delta_radius) * sin(angle),
+ (radius + delta_radius) * cos(angle));
+ }
+ angle += delta_angle;
+ }
+ glEnd();
+ radius += delta_radius;
+ }
+ }
+}
diff --git a/src/glu/mini/tess.c b/src/glu/mini/tess.c
new file mode 100644
index 0000000000..1a384239be
--- /dev/null
+++ b/src/glu/mini/tess.c
@@ -0,0 +1,328 @@
+/* $Id: tess.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * This file is part of the polygon tesselation code contributed by
+ * Bogdan Sikorski
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "tess.h"
+#endif
+
+
+/*
+ * This is ugly, but seems the easiest way to do things to make the
+ * code work under YellowBox for Windows
+ */
+#if defined(OPENSTEP) && defined(CALLBACK)
+#undef CALLBACK
+#define CALLBACK
+#endif
+
+
+static void delete_contours(GLUtriangulatorObj *);
+
+#ifdef __CYGWIN32__
+#define _CALLBACK
+#else
+#define _CALLBACK GLCALLBACK
+#endif
+
+
+static void
+init_callbacks(tess_callbacks * callbacks)
+{
+ callbacks->begin = (void (_CALLBACK *) (GLenum)) 0;
+ callbacks->edgeFlag = (void (_CALLBACK *) (GLboolean)) 0;
+ callbacks->vertex = (void (_CALLBACK *) (void *)) 0;
+ callbacks->end = (void (_CALLBACK *) (void)) 0;
+ callbacks->error = (void (_CALLBACK *) (GLenum)) 0;
+}
+
+void
+tess_call_user_error(GLUtriangulatorObj * tobj, GLenum gluerr)
+{
+ if (tobj->error == GLU_NO_ERROR)
+ tobj->error = gluerr;
+ if (tobj->callbacks.error != NULL)
+ (tobj->callbacks.error) (gluerr);
+}
+
+GLUtriangulatorObj *GLAPIENTRY
+gluNewTess(void)
+{
+ GLUtriangulatorObj *tobj;
+
+ if ((tobj = (GLUtriangulatorObj *)
+ malloc(sizeof(struct GLUtesselator))) == NULL)
+ return NULL;
+ tobj->contours = tobj->last_contour = NULL;
+ init_callbacks(&tobj->callbacks);
+ tobj->error = GLU_NO_ERROR;
+ tobj->current_polygon = NULL;
+ tobj->contour_cnt = 0;
+ return tobj;
+}
+
+
+void GLAPIENTRY
+gluTessCallback(GLUtriangulatorObj * tobj, GLenum which,
+ void (GLCALLBACK * fn) ())
+{
+ switch (which) {
+ case GLU_BEGIN:
+ tobj->callbacks.begin = (void (_CALLBACK *) (GLenum)) fn;
+ break;
+ case GLU_EDGE_FLAG:
+ tobj->callbacks.edgeFlag = (void (_CALLBACK *) (GLboolean)) fn;
+ break;
+ case GLU_VERTEX:
+ tobj->callbacks.vertex = (void (_CALLBACK *) (void *)) fn;
+ break;
+ case GLU_END:
+ tobj->callbacks.end = (void (_CALLBACK *) (void)) fn;
+ break;
+ case GLU_ERROR:
+ tobj->callbacks.error = (void (_CALLBACK *) (GLenum)) fn;
+ break;
+ default:
+ tobj->error = GLU_INVALID_ENUM;
+ break;
+ }
+}
+
+
+
+void GLAPIENTRY
+gluDeleteTess(GLUtriangulatorObj * tobj)
+{
+ if (tobj->error == GLU_NO_ERROR && tobj->contour_cnt)
+ /* was gluEndPolygon called? */
+ tess_call_user_error(tobj, GLU_TESS_ERROR1);
+ /* delete all internal structures */
+ delete_contours(tobj);
+ free(tobj);
+}
+
+
+void GLAPIENTRY
+gluBeginPolygon(GLUtriangulatorObj * tobj)
+{
+/*
+ if(tobj->error!=GLU_NO_ERROR)
+ return;
+*/
+ tobj->error = GLU_NO_ERROR;
+ if (tobj->current_polygon != NULL) {
+ /* gluEndPolygon was not called */
+ tess_call_user_error(tobj, GLU_TESS_ERROR1);
+ /* delete all internal structures */
+ delete_contours(tobj);
+ }
+ else {
+ if ((tobj->current_polygon =
+ (tess_polygon *) malloc(sizeof(tess_polygon))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ return;
+ }
+ tobj->current_polygon->vertex_cnt = 0;
+ tobj->current_polygon->vertices =
+ tobj->current_polygon->last_vertex = NULL;
+ }
+}
+
+
+void GLAPIENTRY
+gluEndPolygon(GLUtriangulatorObj * tobj)
+{
+ /*tess_contour *contour_ptr; */
+
+ /* there was an error */
+ if (tobj->error != GLU_NO_ERROR)
+ goto end;
+
+ /* check if gluBeginPolygon was called */
+ if (tobj->current_polygon == NULL) {
+ tess_call_user_error(tobj, GLU_TESS_ERROR2);
+ return;
+ }
+ tess_test_polygon(tobj);
+ /* there was an error */
+ if (tobj->error != GLU_NO_ERROR)
+ goto end;
+
+ /* any real contours? */
+ if (tobj->contour_cnt == 0) {
+ /* delete all internal structures */
+ delete_contours(tobj);
+ return;
+ }
+ tess_find_contour_hierarchies(tobj);
+ /* there was an error */
+ if (tobj->error != GLU_NO_ERROR)
+ goto end;
+
+ tess_handle_holes(tobj);
+ /* there was an error */
+ if (tobj->error != GLU_NO_ERROR)
+ goto end;
+
+ /* if no callbacks, nothing to do */
+ if (tobj->callbacks.begin != NULL && tobj->callbacks.vertex != NULL &&
+ tobj->callbacks.end != NULL) {
+ if (tobj->callbacks.edgeFlag == NULL)
+ tess_tesselate(tobj);
+ else
+ tess_tesselate_with_edge_flag(tobj);
+ }
+
+ end:
+ /* delete all internal structures */
+ delete_contours(tobj);
+}
+
+
+void GLAPIENTRY
+gluNextContour(GLUtriangulatorObj * tobj, GLenum type)
+{
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+ if (tobj->current_polygon == NULL) {
+ tess_call_user_error(tobj, GLU_TESS_ERROR2);
+ return;
+ }
+ /* first contour? */
+ if (tobj->current_polygon->vertex_cnt)
+ tess_test_polygon(tobj);
+}
+
+
+void GLAPIENTRY
+gluTessVertex(GLUtriangulatorObj * tobj, GLdouble v[3], void *data)
+{
+ tess_polygon *polygon = tobj->current_polygon;
+ tess_vertex *last_vertex_ptr;
+
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+ if (polygon == NULL) {
+ tess_call_user_error(tobj, GLU_TESS_ERROR2);
+ return;
+ }
+ last_vertex_ptr = polygon->last_vertex;
+ if (last_vertex_ptr == NULL) {
+ if ((last_vertex_ptr = (tess_vertex *)
+ malloc(sizeof(tess_vertex))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ return;
+ }
+ polygon->vertices = last_vertex_ptr;
+ polygon->last_vertex = last_vertex_ptr;
+ last_vertex_ptr->data = data;
+ last_vertex_ptr->location[0] = v[0];
+ last_vertex_ptr->location[1] = v[1];
+ last_vertex_ptr->location[2] = v[2];
+ last_vertex_ptr->next = NULL;
+ last_vertex_ptr->previous = NULL;
+ ++(polygon->vertex_cnt);
+ }
+ else {
+ tess_vertex *vertex_ptr;
+
+ /* same point twice? */
+ if (fabs(last_vertex_ptr->location[0] - v[0]) < EPSILON &&
+ fabs(last_vertex_ptr->location[1] - v[1]) < EPSILON &&
+ fabs(last_vertex_ptr->location[2] - v[2]) < EPSILON) {
+ tess_call_user_error(tobj, GLU_TESS_ERROR6);
+ return;
+ }
+ if ((vertex_ptr = (tess_vertex *)
+ malloc(sizeof(tess_vertex))) == NULL) {
+ tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
+ return;
+ }
+ vertex_ptr->data = data;
+ vertex_ptr->location[0] = v[0];
+ vertex_ptr->location[1] = v[1];
+ vertex_ptr->location[2] = v[2];
+ vertex_ptr->next = NULL;
+ vertex_ptr->previous = last_vertex_ptr;
+ ++(polygon->vertex_cnt);
+ last_vertex_ptr->next = vertex_ptr;
+ polygon->last_vertex = vertex_ptr;
+ }
+}
+
+
+static void
+delete_contours(GLUtriangulatorObj * tobj)
+{
+ tess_polygon *polygon = tobj->current_polygon;
+ tess_contour *contour, *contour_tmp;
+ tess_vertex *vertex, *vertex_tmp;
+
+ /* remove current_polygon list - if exists due to detected error */
+ if (polygon != NULL) {
+ if (polygon->vertices) {
+ for (vertex = polygon->vertices; vertex != polygon->last_vertex;) {
+ vertex_tmp = vertex->next;
+ free(vertex);
+ vertex = vertex_tmp;
+ }
+ free(vertex);
+ }
+ free(polygon);
+ tobj->current_polygon = NULL;
+ }
+ /* remove all contour data */
+ for (contour = tobj->contours; contour != NULL;) {
+ for (vertex = contour->vertices; vertex != contour->last_vertex;) {
+ vertex_tmp = vertex->next;
+ free(vertex);
+ vertex = vertex_tmp;
+ }
+ free(vertex);
+ contour_tmp = contour->next;
+ free(contour);
+ contour = contour_tmp;
+ }
+ tobj->contours = tobj->last_contour = NULL;
+ tobj->contour_cnt = 0;
+}
+
+
+void GLAPIENTRY
+gluTessNormal(GLUtesselator *tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ)
+{
+ /* dummy function */
+ (void) tess;
+ (void) valueX;
+ (void) valueY;
+ (void) valueZ;
+}
diff --git a/src/glu/mini/tess.h b/src/glu/mini/tess.h
new file mode 100644
index 0000000000..908e20972c
--- /dev/null
+++ b/src/glu/mini/tess.h
@@ -0,0 +1,108 @@
+/* $Id: tess.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * This file is part of the polygon tesselation code contributed by
+ * Bogdan Sikorski
+ */
+
+
+#ifndef TESS_H
+#define TESS_H
+
+
+#include "gluP.h"
+
+#define EPSILON 1e-06 /* epsilon for double precision compares */
+
+typedef enum
+{
+ OXY,
+ OYZ,
+ OXZ
+}
+projection_type;
+
+typedef struct callbacks_str
+{
+ void (GLCALLBACK * begin) (GLenum mode);
+ void (GLCALLBACK * edgeFlag) (GLboolean flag);
+ void (GLCALLBACK * vertex) (GLvoid * v);
+ void (GLCALLBACK * end) (void);
+ void (GLCALLBACK * error) (GLenum err);
+}
+tess_callbacks;
+
+typedef struct vertex_str
+{
+ void *data;
+ GLdouble location[3];
+ GLdouble x, y;
+ GLboolean edge_flag;
+ struct vertex_str *shadow_vertex;
+ struct vertex_str *next, *previous;
+}
+tess_vertex;
+
+typedef struct contour_str
+{
+ GLenum type;
+ GLuint vertex_cnt;
+ GLdouble area;
+ GLenum orientation;
+ struct vertex_str *vertices, *last_vertex;
+ struct contour_str *next, *previous;
+}
+tess_contour;
+
+typedef struct polygon_str
+{
+ GLuint vertex_cnt;
+ GLdouble A, B, C, D;
+ GLdouble area;
+ GLenum orientation;
+ struct vertex_str *vertices, *last_vertex;
+}
+tess_polygon;
+
+struct GLUtesselator
+{
+ tess_contour *contours, *last_contour;
+ GLuint contour_cnt;
+ tess_callbacks callbacks;
+ tess_polygon *current_polygon;
+ GLenum error;
+ GLdouble A, B, C, D;
+ projection_type projection;
+};
+
+
+extern void tess_call_user_error(GLUtriangulatorObj *, GLenum);
+extern void tess_test_polygon(GLUtriangulatorObj *);
+extern void tess_find_contour_hierarchies(GLUtriangulatorObj *);
+extern void tess_handle_holes(GLUtriangulatorObj *);
+extern void tess_tesselate(GLUtriangulatorObj *);
+extern void tess_tesselate_with_edge_flag(GLUtriangulatorObj *);
+
+
+#endif
diff --git a/src/glu/mini/tesselat.c b/src/glu/mini/tesselat.c
new file mode 100644
index 0000000000..a1102e6e5a
--- /dev/null
+++ b/src/glu/mini/tesselat.c
@@ -0,0 +1,407 @@
+/* $Id: tesselat.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * This file is part of the polygon tesselation code contributed by
+ * Bogdan Sikorski
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <stdlib.h>
+#include <math.h>
+#include "tess.h"
+#endif
+
+
+
+static GLboolean edge_flag;
+
+static void emit_triangle(GLUtriangulatorObj *, tess_vertex *,
+ tess_vertex *, tess_vertex *);
+
+static void emit_triangle_with_edge_flag(GLUtriangulatorObj *,
+ tess_vertex *, GLboolean,
+ tess_vertex *, GLboolean,
+ tess_vertex *, GLboolean);
+
+static GLdouble
+twice_the_triangle_area(tess_vertex * va, tess_vertex * vb, tess_vertex * vc)
+{
+ return (vb->x - va->x) * (vc->y - va->y) - (vb->y - va->y) * (vc->x -
+ va->x);
+}
+
+static GLboolean
+left(GLdouble A, GLdouble B, GLdouble C, GLdouble x, GLdouble y)
+{
+ if (A * x + B * y + C > -EPSILON)
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
+
+static GLboolean
+right(GLdouble A, GLdouble B, GLdouble C, GLdouble x, GLdouble y)
+{
+ if (A * x + B * y + C < EPSILON)
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
+
+static GLint
+convex_ccw(tess_vertex * va,
+ tess_vertex * vb, tess_vertex * vc, GLUtriangulatorObj * tobj)
+{
+ GLdouble d;
+
+ d = twice_the_triangle_area(va, vb, vc);
+
+ if (d > EPSILON) {
+ return 1;
+ }
+ else if (d < -EPSILON) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+static GLint
+convex_cw(tess_vertex * va,
+ tess_vertex * vb, tess_vertex * vc, GLUtriangulatorObj * tobj)
+{
+ GLdouble d;
+
+ d = twice_the_triangle_area(va, vb, vc);
+
+ if (d < -EPSILON) {
+ return 1;
+ }
+ else if (d > EPSILON) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+static GLboolean
+diagonal_ccw(tess_vertex * va,
+ tess_vertex * vb,
+ GLUtriangulatorObj * tobj, tess_contour * contour)
+{
+ tess_vertex *vc = va->next, *vertex, *shadow_vertex;
+ struct
+ {
+ GLdouble A, B, C;
+ }
+ ac, cb, ba;
+ GLdouble x, y;
+
+ GLint res = convex_ccw(va, vc, vb, tobj);
+ if (res == 0)
+ return GL_FALSE;
+ if (res == -1)
+ return GL_TRUE;
+
+ ba.A = vb->y - va->y;
+ ba.B = va->x - vb->x;
+ ba.C = -ba.A * va->x - ba.B * va->y;
+ ac.A = va->y - vc->y;
+ ac.B = vc->x - va->x;
+ ac.C = -ac.A * vc->x - ac.B * vc->y;
+ cb.A = vc->y - vb->y;
+ cb.B = vb->x - vc->x;
+ cb.C = -cb.A * vb->x - cb.B * vb->y;
+ for (vertex = vb->next; vertex != va; vertex = vertex->next) {
+ shadow_vertex = vertex->shadow_vertex;
+ if (shadow_vertex != NULL &&
+ (shadow_vertex == va || shadow_vertex == vb || shadow_vertex == vc))
+ continue;
+ x = vertex->x;
+ y = vertex->y;
+ if (left(ba.A, ba.B, ba.C, x, y) &&
+ left(ac.A, ac.B, ac.C, x, y) && left(cb.A, cb.B, cb.C, x, y))
+ return GL_FALSE;
+ }
+ return GL_TRUE;
+}
+
+static GLboolean
+diagonal_cw(tess_vertex * va,
+ tess_vertex * vb,
+ GLUtriangulatorObj * tobj, tess_contour * contour)
+{
+ tess_vertex *vc = va->next, *vertex, *shadow_vertex;
+ struct
+ {
+ GLdouble A, B, C;
+ }
+ ac, cb, ba;
+ GLdouble x, y;
+
+ GLint res = convex_cw(va, vc, vb, tobj);
+ if (res == 0)
+ return GL_FALSE;
+ if (res == -1)
+ return GL_TRUE;
+
+ ba.A = vb->y - va->y;
+ ba.B = va->x - vb->x;
+ ba.C = -ba.A * va->x - ba.B * va->y;
+ ac.A = va->y - vc->y;
+ ac.B = vc->x - va->x;
+ ac.C = -ac.A * vc->x - ac.B * vc->y;
+ cb.A = vc->y - vb->y;
+ cb.B = vb->x - vc->x;
+ cb.C = -cb.A * vb->x - cb.B * vb->y;
+ for (vertex = vb->next; vertex != va; vertex = vertex->next) {
+ shadow_vertex = vertex->shadow_vertex;
+ if (shadow_vertex != NULL &&
+ (shadow_vertex == va || shadow_vertex == vb || shadow_vertex == vc))
+ continue;
+ x = vertex->x;
+ y = vertex->y;
+ if (right(ba.A, ba.B, ba.C, x, y) &&
+ right(ac.A, ac.B, ac.C, x, y) && right(cb.A, cb.B, cb.C, x, y))
+ return GL_FALSE;
+ }
+ return GL_TRUE;
+}
+
+static void
+clip_ear(GLUtriangulatorObj * tobj, tess_vertex * v, tess_contour * contour)
+{
+ emit_triangle(tobj, v->previous, v, v->next);
+ /* the first in the list */
+ if (contour->vertices == v) {
+ contour->vertices = v->next;
+ contour->last_vertex->next = v->next;
+ v->next->previous = contour->last_vertex;
+ }
+ else
+ /* the last ? */
+ if (contour->last_vertex == v) {
+ contour->vertices->previous = v->previous;
+ v->previous->next = v->next;
+ contour->last_vertex = v->previous;
+ }
+ else {
+ v->next->previous = v->previous;
+ v->previous->next = v->next;
+ }
+ free(v);
+ --(contour->vertex_cnt);
+}
+
+static void
+clip_ear_with_edge_flag(GLUtriangulatorObj * tobj,
+ tess_vertex * v, tess_contour * contour)
+{
+ emit_triangle_with_edge_flag(tobj, v->previous, v->previous->edge_flag,
+ v, v->edge_flag, v->next, GL_FALSE);
+ v->previous->edge_flag = GL_FALSE;
+ /* the first in the list */
+ if (contour->vertices == v) {
+ contour->vertices = v->next;
+ contour->last_vertex->next = v->next;
+ v->next->previous = contour->last_vertex;
+ }
+ else
+ /* the last ? */
+ if (contour->last_vertex == v) {
+ contour->vertices->previous = v->previous;
+ v->previous->next = v->next;
+ contour->last_vertex = v->previous;
+ }
+ else {
+ v->next->previous = v->previous;
+ v->previous->next = v->next;
+ }
+ free(v);
+ --(contour->vertex_cnt);
+}
+
+static void
+triangulate_ccw(GLUtriangulatorObj * tobj, tess_contour * contour)
+{
+ tess_vertex *vertex;
+ GLuint vertex_cnt = contour->vertex_cnt;
+
+ while (vertex_cnt > 3) {
+ vertex = contour->vertices;
+ while (diagonal_ccw(vertex, vertex->next->next, tobj, contour) ==
+ GL_FALSE && tobj->error == GLU_NO_ERROR)
+ vertex = vertex->next;
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+ clip_ear(tobj, vertex->next, contour);
+ --vertex_cnt;
+ }
+}
+
+static void
+triangulate_cw(GLUtriangulatorObj * tobj, tess_contour * contour)
+{
+ tess_vertex *vertex;
+ GLuint vertex_cnt = contour->vertex_cnt;
+
+ while (vertex_cnt > 3) {
+ vertex = contour->vertices;
+ while (diagonal_cw(vertex, vertex->next->next, tobj, contour) ==
+ GL_FALSE && tobj->error == GLU_NO_ERROR)
+ vertex = vertex->next;
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+ clip_ear(tobj, vertex->next, contour);
+ --vertex_cnt;
+ }
+}
+
+static void
+triangulate_ccw_with_edge_flag(GLUtriangulatorObj * tobj,
+ tess_contour * contour)
+{
+ tess_vertex *vertex;
+ GLuint vertex_cnt = contour->vertex_cnt;
+
+ while (vertex_cnt > 3) {
+ vertex = contour->vertices;
+ while (diagonal_ccw(vertex, vertex->next->next, tobj, contour) ==
+ GL_FALSE && tobj->error == GLU_NO_ERROR)
+ vertex = vertex->next;
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+ clip_ear_with_edge_flag(tobj, vertex->next, contour);
+ --vertex_cnt;
+ }
+}
+
+static void
+triangulate_cw_with_edge_flag(GLUtriangulatorObj * tobj,
+ tess_contour * contour)
+{
+ tess_vertex *vertex;
+ GLuint vertex_cnt = contour->vertex_cnt;
+
+ while (vertex_cnt > 3) {
+ vertex = contour->vertices;
+ while (diagonal_cw(vertex, vertex->next->next, tobj, contour) ==
+ GL_FALSE && tobj->error == GLU_NO_ERROR)
+ vertex = vertex->next;
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+ clip_ear_with_edge_flag(tobj, vertex->next, contour);
+ --vertex_cnt;
+ }
+}
+
+void
+tess_tesselate(GLUtriangulatorObj * tobj)
+{
+ tess_contour *contour;
+
+ for (contour = tobj->contours; contour != NULL; contour = contour->next) {
+ if (contour->orientation == GLU_CCW) {
+ triangulate_ccw(tobj, contour);
+ }
+ else {
+ triangulate_cw(tobj, contour);
+ }
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+
+ /* emit the last triangle */
+ emit_triangle(tobj, contour->vertices, contour->vertices->next,
+ contour->vertices->next->next);
+ }
+}
+
+void
+tess_tesselate_with_edge_flag(GLUtriangulatorObj * tobj)
+{
+ tess_contour *contour;
+
+ edge_flag = GL_TRUE;
+ /* first callback with edgeFlag set to GL_TRUE */
+ (tobj->callbacks.edgeFlag) (GL_TRUE);
+
+ for (contour = tobj->contours; contour != NULL; contour = contour->next) {
+ if (contour->orientation == GLU_CCW)
+ triangulate_ccw_with_edge_flag(tobj, contour);
+ else
+ triangulate_cw_with_edge_flag(tobj, contour);
+ if (tobj->error != GLU_NO_ERROR)
+ return;
+ /* emit the last triangle */
+ emit_triangle_with_edge_flag(tobj, contour->vertices,
+ contour->vertices->edge_flag,
+ contour->vertices->next,
+ contour->vertices->next->edge_flag,
+ contour->vertices->next->next,
+ contour->vertices->next->next->edge_flag);
+ }
+}
+
+static void
+emit_triangle(GLUtriangulatorObj * tobj,
+ tess_vertex * v1, tess_vertex * v2, tess_vertex * v3)
+{
+ (tobj->callbacks.begin) (GL_TRIANGLES);
+ (tobj->callbacks.vertex) (v1->data);
+ (tobj->callbacks.vertex) (v2->data);
+ (tobj->callbacks.vertex) (v3->data);
+ (tobj->callbacks.end) ();
+}
+
+static void
+emit_triangle_with_edge_flag(GLUtriangulatorObj * tobj,
+ tess_vertex * v1,
+ GLboolean edge_flag1,
+ tess_vertex * v2,
+ GLboolean edge_flag2,
+ tess_vertex * v3, GLboolean edge_flag3)
+{
+ (tobj->callbacks.begin) (GL_TRIANGLES);
+ if (edge_flag1 != edge_flag) {
+ edge_flag = (edge_flag == GL_TRUE ? GL_FALSE : GL_TRUE);
+ (tobj->callbacks.edgeFlag) (edge_flag);
+ }
+ (tobj->callbacks.vertex) (v1->data);
+ if (edge_flag2 != edge_flag) {
+ edge_flag = (edge_flag == GL_TRUE ? GL_FALSE : GL_TRUE);
+ (tobj->callbacks.edgeFlag) (edge_flag);
+ }
+ (tobj->callbacks.vertex) (v2->data);
+ if (edge_flag3 != edge_flag) {
+ edge_flag = (edge_flag == GL_TRUE ? GL_FALSE : GL_TRUE);
+ (tobj->callbacks.edgeFlag) (edge_flag);
+ }
+ (tobj->callbacks.vertex) (v3->data);
+ (tobj->callbacks.end) ();
+}
diff --git a/src/glut/mini/Makefile.X11 b/src/glut/mini/Makefile.X11
new file mode 100644
index 0000000000..097a665e4e
--- /dev/null
+++ b/src/glut/mini/Makefile.X11
@@ -0,0 +1,78 @@
+
+TOP = ../../..
+
+default: linux-solo
+
+MARK = $(TOP)/src/glut/glx
+
+INCLUDES = -I$(TOP)/include -I$(MARK)
+
+CORE_SOURCES = \
+ bitmap.c \
+ callback.c \
+ color.c \
+ globals.c \
+ init.c \
+ menu.c \
+ models.c \
+ overlay.c \
+ state.c \
+ teapot.c \
+ window.c
+
+
+MARK_SOURCES = \
+ $(MARK)/glut_8x13.c \
+ $(MARK)/glut_9x15.c \
+ $(MARK)/glut_hel10.c \
+ $(MARK)/glut_hel12.c \
+ $(MARK)/glut_hel18.c \
+ $(MARK)/glut_tr10.c \
+ $(MARK)/glut_tr24.c
+
+SOURCES = $(CORE_SOURCES) $(MARK_SOURCES)
+
+OBJS = $(SOURCES:.c=.o)
+
+LIBS = -L$(TOP)/lib -lGL -lGLU -lm
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+
+##### TARGETS #####
+
+targets: depend libglut.so.3.7 install
+
+libglut.so.3.7: $(OBJS) Makefile.X11
+ gcc -shared -Wl,-soname,libglut.so -Wl,-Bsymbolic $(OBJS) $(LIBS) -o $@
+
+install:
+ rm -f $(TOP)/lib/libglut.so*
+ install -D libglut.so.3.7 $(TOP)/lib/libglut.so.3.7
+ ln -s libglut.so.3.7 $(TOP)/lib/libglut.so.3
+ ln -s libglut.so.3 $(TOP)/lib/libglut.so
+
+# Run 'make -f Makefile.X11 dep' to update the dependencies if you change
+# what's included by any source file.
+depend: $(SOURCES)
+ makedepend -fdepend -Y $(INCLUDES) \
+ $(SOURCES)
+
+# Emacs tags
+tags:
+ etags `find . -name \*.[ch]` `find ../include`
+
+
+# Remove .o and backup files
+clean:
+ -rm -f *.o *~ *.o *~ *.so
+
+include $(TOP)/Make-config
+
+include depend
diff --git a/src/glut/mini/bitmap.c b/src/glut/mini/bitmap.c
new file mode 100644
index 0000000000..55a031af0a
--- /dev/null
+++ b/src/glut/mini/bitmap.c
@@ -0,0 +1,56 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994. */
+
+/* This program is freely distributable without licensing fees
+ and is provided without guarantee or warrantee expressed or
+ implied. This program is -not- in the public domain. */
+
+#include "glutbitmap.h"
+
+void APIENTRY
+glutBitmapCharacter(GLUTbitmapFont font, int c)
+{
+ const BitmapCharRec *ch;
+ BitmapFontPtr fontinfo;
+ GLfloat swapbytes, lsbfirst, rowlength;
+ GLfloat skiprows, skippixels, alignment;
+
+#if defined(_WIN32)
+ fontinfo = (BitmapFontPtr) __glutFont(font);
+#else
+ fontinfo = (BitmapFontPtr) font;
+#endif
+
+ if (c < fontinfo->first ||
+ c >= fontinfo->first + fontinfo->num_chars)
+ return;
+ ch = fontinfo->ch[c - fontinfo->first];
+ if (ch) {
+ /* Save current modes. */
+/* glGetFloatv(GL_UNPACK_SWAP_BYTES, &swapbytes); */
+/* glGetFloatv(GL_UNPACK_LSB_FIRST, &lsbfirst); */
+/* glGetFloatv(GL_UNPACK_ROW_LENGTH, &rowlength); */
+/* glGetFloatv(GL_UNPACK_SKIP_ROWS, &skiprows); */
+/* glGetFloatv(GL_UNPACK_SKIP_PIXELS, &skippixels); */
+ glGetFloatv(GL_UNPACK_ALIGNMENT, &alignment);
+ /* Little endian machines (DEC Alpha for example) could
+ benefit from setting GL_UNPACK_LSB_FIRST to GL_TRUE
+ instead of GL_FALSE, but this would require changing the
+ generated bitmaps too. */
+/* glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); */
+/* glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); */
+/* glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); */
+/* glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); */
+/* glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); */
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glBitmap(ch->width, ch->height, ch->xorig, ch->yorig,
+ ch->advance, 0, ch->bitmap);
+ /* Restore saved modes. */
+/* glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes); */
+/* glPixelStorei(GL_UNPACK_LSB_FIRST, (int)lsbfirst); */
+/* glPixelStorei(GL_UNPACK_ROW_LENGTH, (int)rowlength); */
+/* glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows); */
+/* glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels); */
+ glPixelStorei(GL_UNPACK_ALIGNMENT, (int)alignment);
+ }
+}
diff --git a/src/glut/mini/callback.c b/src/glut/mini/callback.c
new file mode 100644
index 0000000000..d4e3101cc0
--- /dev/null
+++ b/src/glut/mini/callback.c
@@ -0,0 +1,152 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include "GL/glut.h"
+#include "internal.h"
+
+
+void APIENTRY glutDisplayFunc (void (GLUTCALLBACK *func) (void))
+{
+ display_func = func;
+}
+
+
+void APIENTRY glutReshapeFunc (void (GLUTCALLBACK *func) (int width, int height))
+{
+ reshape_func = func;
+}
+
+
+void APIENTRY glutKeyboardFunc (void (GLUTCALLBACK *func) (unsigned char key, int x, int y))
+{
+ keyboard_func = func;
+}
+
+
+void APIENTRY glutMouseFunc (void (GLUTCALLBACK *func) (int button, int state, int x, int y))
+{
+ mouse_func = func;
+}
+
+
+void APIENTRY glutMotionFunc (void (GLUTCALLBACK *func) (int x, int y))
+{
+ motion_func = func;
+}
+
+
+void APIENTRY glutPassiveMotionFunc (void (GLUTCALLBACK *func) (int x, int y))
+{
+ passive_motion_func = func;
+}
+
+
+void APIENTRY glutEntryFunc (void (GLUTCALLBACK *func) (int state))
+{
+ entry_func = func;
+}
+
+
+void APIENTRY glutVisibilityFunc (void (GLUTCALLBACK *func) (int state))
+{
+ visibility_func = func;
+}
+
+
+void APIENTRY glutIdleFunc (void (GLUTCALLBACK *func) (void))
+{
+ idle_func = func;
+}
+
+
+void APIENTRY glutTimerFunc (unsigned int millis, void (GLUTCALLBACK *func) (int value), int value)
+{
+}
+
+
+void APIENTRY glutMenuStateFunc (void (GLUTCALLBACK *func) (int state))
+{
+ menu_state_func = func;
+}
+
+
+void APIENTRY glutSpecialFunc (void (GLUTCALLBACK *func) (int key, int x, int y))
+{
+ special_func = func;
+}
+
+
+void APIENTRY glutSpaceballMotionFunc (void (GLUTCALLBACK *func) (int x, int y, int z))
+{
+}
+
+
+void APIENTRY glutSpaceballRotateFunc (void (GLUTCALLBACK *func) (int x, int y, int z))
+{
+}
+
+
+void APIENTRY glutSpaceballButtonFunc (void (GLUTCALLBACK *func) (int button, int state))
+{
+}
+
+
+void APIENTRY glutButtonBoxFunc (void (GLUTCALLBACK *func) (int button, int state))
+{
+}
+
+
+void APIENTRY glutDialsFunc (void (GLUTCALLBACK *func) (int dial, int value))
+{
+}
+
+
+void APIENTRY glutTabletMotionFunc (void (GLUTCALLBACK *func) (int x, int y))
+{
+}
+
+
+void APIENTRY glutTabletButtonFunc (void (GLUTCALLBACK *func) (int button, int state, int x, int y))
+{
+}
+
+
+void APIENTRY glutMenuStatusFunc (void (GLUTCALLBACK *func) (int status, int x, int y))
+{
+}
+
+
+void APIENTRY glutOverlayDisplayFunc (void (GLUTCALLBACK *func) (void))
+{
+}
+
+
+void APIENTRY glutWindowStatusFunc (void (GLUTCALLBACK *func) (int state))
+{
+}
diff --git a/src/glut/mini/color.c b/src/glut/mini/color.c
new file mode 100644
index 0000000000..b53c5b669e
--- /dev/null
+++ b/src/glut/mini/color.c
@@ -0,0 +1,46 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include "GL/glut.h"
+
+
+void APIENTRY glutSetColor (int ndx, GLfloat red, GLfloat green, GLfloat blue)
+{
+}
+
+
+GLfloat APIENTRY glutGetColor (int ndx, int component)
+{
+ return 0.0;
+}
+
+
+void APIENTRY glutCopyColormap (int win)
+{
+}
diff --git a/src/glut/mini/globals.c b/src/glut/mini/globals.c
new file mode 100644
index 0000000000..76db53c695
--- /dev/null
+++ b/src/glut/mini/globals.c
@@ -0,0 +1,61 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include "GL/glut.h"
+#include "internal.h"
+
+GLenum g_display_mode = 0;
+GLuint g_width = DEFAULT_WIDTH;
+GLuint g_height = DEFAULT_HEIGHT;
+GLint g_mouse = GL_FALSE;
+GLboolean g_redisplay = GL_FALSE;
+GLint g_xpos = 0;
+GLint g_ypos = 0;
+
+void (GLUTCALLBACK *display_func) (void) = 0;
+void (GLUTCALLBACK *reshape_func) (int width, int height) = 0;
+void (GLUTCALLBACK *keyboard_func) (unsigned char key, int x, int y) = 0;
+void (GLUTCALLBACK *mouse_func) (int button, int state, int x, int y) = 0;
+void (GLUTCALLBACK *motion_func) (int x, int y) = 0;
+void (GLUTCALLBACK *passive_motion_func) (int x, int y) = 0;
+void (GLUTCALLBACK *entry_func) (int state) = 0;
+void (GLUTCALLBACK *visibility_func) (int state) = 0;
+void (GLUTCALLBACK *idle_func) (void) = 0;
+void (GLUTCALLBACK *menu_state_func) (int state) = 0;
+void (GLUTCALLBACK *special_func) (int key, int x, int y) = 0;
+void (GLUTCALLBACK *spaceball_motion_func) (int x, int y, int z) = 0;
+void (GLUTCALLBACK *spaceball_rotate_func) (int x, int y, int z) = 0;
+void (GLUTCALLBACK *spaceball_button_func) (int button, int state) = 0;
+void (GLUTCALLBACK *button_box_func) (int button, int state) = 0;
+void (GLUTCALLBACK *dials_func) (int dial, int value) = 0;
+void (GLUTCALLBACK *tablet_motion_func) (int x, int y) = 0;
+void (GLUTCALLBACK *tabled_button_func) (int button, int state, int x, int y) = 0;
+void (GLUTCALLBACK *menu_status_func) (int status, int x, int y) = 0;
+void (GLUTCALLBACK *overlay_display_func) (void) = 0;
+void (GLUTCALLBACK *window_status_func) (int state) = 0;
diff --git a/src/glut/mini/init.c b/src/glut/mini/init.c
new file mode 100644
index 0000000000..5588db9aba
--- /dev/null
+++ b/src/glut/mini/init.c
@@ -0,0 +1,59 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.0
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include "GL/glut.h"
+#include "internal.h"
+
+
+void APIENTRY glutInit (int *argcp, char **argv)
+{
+ glutGet(GLUT_ELAPSED_TIME);
+}
+
+
+void APIENTRY glutInitDisplayMode (unsigned int mode)
+{
+ g_display_mode = mode;
+}
+
+
+void APIENTRY glutInitWindowPosition (int x, int y)
+{
+ g_xpos = x;
+ g_ypos = y;
+}
+
+
+void APIENTRY glutInitWindowSize (int width, int height)
+{
+ g_width = width;
+ g_height = height;
+}
+
+
diff --git a/src/glut/mini/internal.h b/src/glut/mini/internal.h
new file mode 100644
index 0000000000..ccd12e54af
--- /dev/null
+++ b/src/glut/mini/internal.h
@@ -0,0 +1,78 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.0
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#ifndef INTERNAL_H_included
+#define INTERNAL_H_included
+
+
+#include "GL/glut.h"
+/* #include "pc_hw/pc_hw.h" */
+
+
+#define MAX_WINDOWS 4
+
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
+#define DEFAULT_BPP 16
+
+#define DEPTH_SIZE 16
+#define STENCIL_SIZE 8
+#define ACCUM_SIZE 16
+
+extern GLenum g_display_mode;
+extern GLuint g_width;
+extern GLuint g_height;
+extern GLint g_mouse;
+extern GLboolean g_redisplay;
+extern GLint g_xpos;
+extern GLint g_ypos;
+
+extern void (GLUTCALLBACK *display_func) (void);
+extern void (GLUTCALLBACK *reshape_func) (int width, int height);
+extern void (GLUTCALLBACK *keyboard_func) (unsigned char key, int x, int y);
+extern void (GLUTCALLBACK *mouse_func) (int button, int state, int x, int y);
+extern void (GLUTCALLBACK *motion_func) (int x, int y);
+extern void (GLUTCALLBACK *passive_motion_func) (int x, int y);
+extern void (GLUTCALLBACK *entry_func) (int state);
+extern void (GLUTCALLBACK *visibility_func) (int state);
+extern void (GLUTCALLBACK *idle_func) (void);
+extern void (GLUTCALLBACK *menu_state_func) (int state);
+extern void (GLUTCALLBACK *special_func) (int key, int x, int y);
+extern void (GLUTCALLBACK *spaceball_motion_func) (int x, int y, int z);
+extern void (GLUTCALLBACK *spaceball_rotate_func) (int x, int y, int z);
+extern void (GLUTCALLBACK *spaceball_button_func) (int button, int state);
+extern void (GLUTCALLBACK *button_box_func) (int button, int state);
+extern void (GLUTCALLBACK *dials_func) (int dial, int value);
+extern void (GLUTCALLBACK *tablet_motion_func) (int x, int y);
+extern void (GLUTCALLBACK *tabled_button_func) (int button, int state, int x, int y);
+extern void (GLUTCALLBACK *menu_status_func) (int status, int x, int y);
+extern void (GLUTCALLBACK *overlay_display_func) (void);
+extern void (GLUTCALLBACK *window_status_func) (int state);
+
+#endif
diff --git a/src/glut/mini/menu.c b/src/glut/mini/menu.c
new file mode 100644
index 0000000000..3c571647b1
--- /dev/null
+++ b/src/glut/mini/menu.c
@@ -0,0 +1,86 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include "GL/glut.h"
+
+
+int APIENTRY glutCreateMenu (void (GLUTCALLBACK *func) (int))
+{
+ return 0;
+}
+
+void APIENTRY glutDestroyMenu (int menu)
+{
+}
+
+
+int APIENTRY glutGetMenu (void)
+{
+ return 0;
+}
+
+
+void APIENTRY glutSetMenu (int menu)
+{
+}
+
+
+void APIENTRY glutAddMenuEntry (const char *label, int value)
+{
+}
+
+
+void APIENTRY glutAddSubMenu (const char *label, int submenu)
+{
+}
+
+
+void APIENTRY glutChangeToMenuEntry (int item, const char *label, int value)
+{
+}
+
+
+void APIENTRY glutChangeToSubMenu (int item, const char *label, int submenu)
+{
+}
+
+
+void APIENTRY glutRemoveMenuItem (int item)
+{
+}
+
+
+void APIENTRY glutAttachMenu (int button)
+{
+}
+
+
+void APIENTRY glutDetachMenu (int button)
+{
+}
diff --git a/src/glut/mini/models.c b/src/glut/mini/models.c
new file mode 100644
index 0000000000..57f45a262c
--- /dev/null
+++ b/src/glut/mini/models.c
@@ -0,0 +1,598 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
+
+/**
+(c) Copyright 1993, Silicon Graphics, Inc.
+
+ALL RIGHTS RESERVED
+
+Permission to use, copy, modify, and distribute this software
+for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that
+both the copyright notice and this permission notice appear in
+supporting documentation, and that the name of Silicon
+Graphics, Inc. not be used in advertising or publicity
+pertaining to distribution of the software without specific,
+written prior permission.
+
+THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
+"AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
+OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO
+EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE
+ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
+INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
+SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
+NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY
+OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+US Government Users Restricted Rights
+
+Use, duplication, or disclosure by the Government is subject to
+restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+(c)(1)(ii) of the Rights in Technical Data and Computer
+Software clause at DFARS 252.227-7013 and/or in similar or
+successor clauses in the FAR or the DOD or NASA FAR
+Supplement. Unpublished-- rights reserved under the copyright
+laws of the United States. Contractor/manufacturer is Silicon
+Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA
+94039-7311.
+
+OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+*/
+
+#include <math.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "GL/glut.h"
+
+/* Some <math.h> files do not define M_PI... */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+static GLUquadricObj *quadObj;
+
+#define QUAD_OBJ_INIT() { if(!quadObj) initQuadObj(); }
+
+static void
+initQuadObj(void)
+{
+ quadObj = gluNewQuadric();
+/* if (!quadObj)
+ __glutFatalError("out of memory."); */
+}
+
+/* CENTRY */
+void APIENTRY
+glutWireSphere(GLdouble radius, GLint slices, GLint stacks)
+{
+ QUAD_OBJ_INIT();
+ gluQuadricDrawStyle(quadObj, GLU_LINE);
+ gluQuadricNormals(quadObj, GLU_SMOOTH);
+ /* If we ever changed/used the texture or orientation state
+ of quadObj, we'd need to change it to the defaults here
+ with gluQuadricTexture and/or gluQuadricOrientation. */
+ gluSphere(quadObj, radius, slices, stacks);
+}
+
+void APIENTRY
+glutSolidSphere(GLdouble radius, GLint slices, GLint stacks)
+{
+ QUAD_OBJ_INIT();
+ gluQuadricDrawStyle(quadObj, GLU_FILL);
+ gluQuadricNormals(quadObj, GLU_SMOOTH);
+ /* If we ever changed/used the texture or orientation state
+ of quadObj, we'd need to change it to the defaults here
+ with gluQuadricTexture and/or gluQuadricOrientation. */
+ gluSphere(quadObj, radius, slices, stacks);
+}
+
+void APIENTRY
+glutWireCone(GLdouble base, GLdouble height,
+ GLint slices, GLint stacks)
+{
+ QUAD_OBJ_INIT();
+ gluQuadricDrawStyle(quadObj, GLU_LINE);
+ gluQuadricNormals(quadObj, GLU_SMOOTH);
+ /* If we ever changed/used the texture or orientation state
+ of quadObj, we'd need to change it to the defaults here
+ with gluQuadricTexture and/or gluQuadricOrientation. */
+ gluCylinder(quadObj, base, 0.0, height, slices, stacks);
+}
+
+void APIENTRY
+glutSolidCone(GLdouble base, GLdouble height,
+ GLint slices, GLint stacks)
+{
+ QUAD_OBJ_INIT();
+ gluQuadricDrawStyle(quadObj, GLU_FILL);
+ gluQuadricNormals(quadObj, GLU_SMOOTH);
+ /* If we ever changed/used the texture or orientation state
+ of quadObj, we'd need to change it to the defaults here
+ with gluQuadricTexture and/or gluQuadricOrientation. */
+ gluCylinder(quadObj, base, 0.0, height, slices, stacks);
+}
+
+/* ENDCENTRY */
+
+static void
+drawBox(GLfloat size, GLenum type)
+{
+ static GLfloat n[6][3] =
+ {
+ {-1.0, 0.0, 0.0},
+ {0.0, 1.0, 0.0},
+ {1.0, 0.0, 0.0},
+ {0.0, -1.0, 0.0},
+ {0.0, 0.0, 1.0},
+ {0.0, 0.0, -1.0}
+ };
+ static GLint faces[6][4] =
+ {
+ {0, 1, 2, 3},
+ {3, 2, 6, 7},
+ {7, 6, 5, 4},
+ {4, 5, 1, 0},
+ {5, 6, 2, 1},
+ {7, 4, 0, 3}
+ };
+ GLfloat v[8][3];
+ GLint i;
+
+ v[0][0] = v[1][0] = v[2][0] = v[3][0] = -size / 2;
+ v[4][0] = v[5][0] = v[6][0] = v[7][0] = size / 2;
+ v[0][1] = v[1][1] = v[4][1] = v[5][1] = -size / 2;
+ v[2][1] = v[3][1] = v[6][1] = v[7][1] = size / 2;
+ v[0][2] = v[3][2] = v[4][2] = v[7][2] = -size / 2;
+ v[1][2] = v[2][2] = v[5][2] = v[6][2] = size / 2;
+
+ for (i = 5; i >= 0; i--) {
+ glBegin(type);
+/* glNormal3fv(&n[i][0]); */
+ glVertex3fv(&v[faces[i][0]][0]);
+ glVertex3fv(&v[faces[i][1]][0]);
+ glVertex3fv(&v[faces[i][2]][0]);
+ glVertex3fv(&v[faces[i][3]][0]);
+ glEnd();
+ }
+}
+
+/* CENTRY */
+void APIENTRY
+glutWireCube(GLdouble size)
+{
+ drawBox(size, GL_LINE_LOOP);
+}
+
+void APIENTRY
+glutSolidCube(GLdouble size)
+{
+ drawBox(size, GL_QUADS);
+}
+
+/* ENDCENTRY */
+
+static void
+doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
+{
+ int i, j;
+ GLfloat theta, phi, theta1;
+ GLfloat cosTheta, sinTheta;
+ GLfloat cosTheta1, sinTheta1;
+ GLfloat ringDelta, sideDelta;
+
+ ringDelta = 2.0 * M_PI / rings;
+ sideDelta = 2.0 * M_PI / nsides;
+
+ theta = 0.0;
+ cosTheta = 1.0;
+ sinTheta = 0.0;
+ for (i = rings - 1; i >= 0; i--) {
+ theta1 = theta + ringDelta;
+ cosTheta1 = cos(theta1);
+ sinTheta1 = sin(theta1);
+ glBegin(GL_QUAD_STRIP);
+ phi = 0.0;
+ for (j = nsides; j >= 0; j--) {
+ GLfloat cosPhi, sinPhi, dist;
+
+ phi += sideDelta;
+ cosPhi = cos(phi);
+ sinPhi = sin(phi);
+ dist = R + r * cosPhi;
+
+/* glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); */
+ glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
+/* glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); */
+ glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi);
+ }
+ glEnd();
+ theta = theta1;
+ cosTheta = cosTheta1;
+ sinTheta = sinTheta1;
+ }
+}
+
+/* CENTRY */
+void APIENTRY
+glutWireTorus(GLdouble innerRadius, GLdouble outerRadius,
+ GLint nsides, GLint rings)
+{
+/* glPushAttrib(GL_POLYGON_BIT); */
+/* glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); */
+ doughnut(innerRadius, outerRadius, nsides, rings);
+/* glPopAttrib(); */
+}
+
+void APIENTRY
+glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius,
+ GLint nsides, GLint rings)
+{
+ doughnut(innerRadius, outerRadius, nsides, rings);
+}
+
+/* ENDCENTRY */
+
+static GLfloat dodec[20][3];
+
+static void
+initDodecahedron(void)
+{
+ GLfloat alpha, beta;
+
+ alpha = sqrt(2.0 / (3.0 + sqrt(5.0)));
+ beta = 1.0 + sqrt(6.0 / (3.0 + sqrt(5.0)) -
+ 2.0 + 2.0 * sqrt(2.0 / (3.0 + sqrt(5.0))));
+ /* *INDENT-OFF* */
+ dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
+ dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
+ dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
+ dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
+ dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
+ dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
+ dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
+ dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
+ dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
+ dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
+ dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
+ dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
+ dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
+ dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
+ dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
+ dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
+ dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
+ dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
+ dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
+ dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
+ /* *INDENT-ON* */
+
+}
+
+#define DIFF3(_a,_b,_c) { \
+ (_c)[0] = (_a)[0] - (_b)[0]; \
+ (_c)[1] = (_a)[1] - (_b)[1]; \
+ (_c)[2] = (_a)[2] - (_b)[2]; \
+}
+
+static void
+crossprod(GLfloat v1[3], GLfloat v2[3], GLfloat prod[3])
+{
+ GLfloat p[3]; /* in case prod == v1 or v2 */
+
+ p[0] = v1[1] * v2[2] - v2[1] * v1[2];
+ p[1] = v1[2] * v2[0] - v2[2] * v1[0];
+ p[2] = v1[0] * v2[1] - v2[0] * v1[1];
+ prod[0] = p[0];
+ prod[1] = p[1];
+ prod[2] = p[2];
+}
+
+static void
+normalize(GLfloat v[3])
+{
+ GLfloat d;
+
+ d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ if (d == 0.0) {
+/* __glutWarning("normalize: zero length vector"); */
+ v[0] = d = 1.0;
+ }
+ d = 1 / d;
+ v[0] *= d;
+ v[1] *= d;
+ v[2] *= d;
+}
+
+static void
+pentagon(int a, int b, int c, int d, int e, GLenum shadeType)
+{
+ GLfloat n0[3], d1[3], d2[3];
+
+ DIFF3(dodec[a], dodec[b], d1);
+ DIFF3(dodec[b], dodec[c], d2);
+ crossprod(d1, d2, n0);
+ normalize(n0);
+
+ glBegin(shadeType);
+/* glNormal3fv(n0); */
+ glVertex3fv(&dodec[a][0]);
+ glVertex3fv(&dodec[b][0]);
+ glVertex3fv(&dodec[c][0]);
+ glVertex3fv(&dodec[d][0]);
+ glVertex3fv(&dodec[e][0]);
+ glEnd();
+}
+
+static void
+dodecahedron(GLenum type)
+{
+ static int inited = 0;
+
+ if (inited == 0) {
+ inited = 1;
+ initDodecahedron();
+ }
+ pentagon(0, 1, 9, 16, 5, type);
+ pentagon(1, 0, 3, 18, 7, type);
+ pentagon(1, 7, 11, 10, 9, type);
+ pentagon(11, 7, 18, 19, 6, type);
+ pentagon(8, 17, 16, 9, 10, type);
+ pentagon(2, 14, 15, 6, 19, type);
+ pentagon(2, 13, 12, 4, 14, type);
+ pentagon(2, 19, 18, 3, 13, type);
+ pentagon(3, 0, 5, 12, 13, type);
+ pentagon(6, 15, 8, 10, 11, type);
+ pentagon(4, 17, 8, 15, 14, type);
+ pentagon(4, 12, 5, 16, 17, type);
+}
+
+/* CENTRY */
+void APIENTRY
+glutWireDodecahedron(void)
+{
+ dodecahedron(GL_LINE_LOOP);
+}
+
+void APIENTRY
+glutSolidDodecahedron(void)
+{
+ dodecahedron(GL_TRIANGLE_FAN);
+}
+
+/* ENDCENTRY */
+
+static void
+recorditem(GLfloat * n1, GLfloat * n2, GLfloat * n3,
+ GLenum shadeType)
+{
+ GLfloat q0[3], q1[3];
+
+ DIFF3(n1, n2, q0);
+ DIFF3(n2, n3, q1);
+ crossprod(q0, q1, q1);
+ normalize(q1);
+
+ glBegin(shadeType);
+/* glNormal3fv(q1); */
+ glVertex3fv(n1);
+ glVertex3fv(n2);
+ glVertex3fv(n3);
+ glEnd();
+}
+
+static void
+subdivide(GLfloat * v0, GLfloat * v1, GLfloat * v2,
+ GLenum shadeType)
+{
+ int depth;
+ GLfloat w0[3], w1[3], w2[3];
+ GLfloat l;
+ int i, j, k, n;
+
+ depth = 1;
+ for (i = 0; i < depth; i++) {
+ for (j = 0; i + j < depth; j++) {
+ k = depth - i - j;
+ for (n = 0; n < 3; n++) {
+ w0[n] = (i * v0[n] + j * v1[n] + k * v2[n]) / depth;
+ w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n])
+ / depth;
+ w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n])
+ / depth;
+ }
+ l = sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]);
+ w0[0] /= l;
+ w0[1] /= l;
+ w0[2] /= l;
+ l = sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]);
+ w1[0] /= l;
+ w1[1] /= l;
+ w1[2] /= l;
+ l = sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]);
+ w2[0] /= l;
+ w2[1] /= l;
+ w2[2] /= l;
+ recorditem(w1, w0, w2, shadeType);
+ }
+ }
+}
+
+static void
+drawtriangle(int i, GLfloat data[][3], int ndx[][3],
+ GLenum shadeType)
+{
+ GLfloat *x0, *x1, *x2;
+
+ x0 = data[ndx[i][0]];
+ x1 = data[ndx[i][1]];
+ x2 = data[ndx[i][2]];
+ subdivide(x0, x1, x2, shadeType);
+}
+
+/* octahedron data: The octahedron produced is centered at the
+ origin and has radius 1.0 */
+static GLfloat odata[6][3] =
+{
+ {1.0, 0.0, 0.0},
+ {-1.0, 0.0, 0.0},
+ {0.0, 1.0, 0.0},
+ {0.0, -1.0, 0.0},
+ {0.0, 0.0, 1.0},
+ {0.0, 0.0, -1.0}
+};
+
+static int ondex[8][3] =
+{
+ {0, 4, 2},
+ {1, 2, 4},
+ {0, 3, 4},
+ {1, 4, 3},
+ {0, 2, 5},
+ {1, 5, 2},
+ {0, 5, 3},
+ {1, 3, 5}
+};
+
+static void
+octahedron(GLenum shadeType)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--) {
+ drawtriangle(i, odata, ondex, shadeType);
+ }
+}
+
+/* CENTRY */
+void APIENTRY
+glutWireOctahedron(void)
+{
+ octahedron(GL_LINE_LOOP);
+}
+
+void APIENTRY
+glutSolidOctahedron(void)
+{
+ octahedron(GL_TRIANGLES);
+}
+
+/* ENDCENTRY */
+
+/* icosahedron data: These numbers are rigged to make an
+ icosahedron of radius 1.0 */
+
+#define X .525731112119133606
+#define Z .850650808352039932
+
+static GLfloat idata[12][3] =
+{
+ {-X, 0, Z},
+ {X, 0, Z},
+ {-X, 0, -Z},
+ {X, 0, -Z},
+ {0, Z, X},
+ {0, Z, -X},
+ {0, -Z, X},
+ {0, -Z, -X},
+ {Z, X, 0},
+ {-Z, X, 0},
+ {Z, -X, 0},
+ {-Z, -X, 0}
+};
+
+static int index[20][3] =
+{
+ {0, 4, 1},
+ {0, 9, 4},
+ {9, 5, 4},
+ {4, 5, 8},
+ {4, 8, 1},
+ {8, 10, 1},
+ {8, 3, 10},
+ {5, 3, 8},
+ {5, 2, 3},
+ {2, 7, 3},
+ {7, 10, 3},
+ {7, 6, 10},
+ {7, 11, 6},
+ {11, 0, 6},
+ {0, 1, 6},
+ {6, 1, 10},
+ {9, 0, 11},
+ {9, 11, 2},
+ {9, 2, 5},
+ {7, 2, 11},
+};
+
+static void
+icosahedron(GLenum shadeType)
+{
+ int i;
+
+ for (i = 19; i >= 0; i--) {
+ drawtriangle(i, idata, index, shadeType);
+ }
+}
+
+/* CENTRY */
+void APIENTRY
+glutWireIcosahedron(void)
+{
+ icosahedron(GL_LINE_LOOP);
+}
+
+void APIENTRY
+glutSolidIcosahedron(void)
+{
+ icosahedron(GL_TRIANGLES);
+}
+
+/* ENDCENTRY */
+
+/* tetrahedron data: */
+
+#define T 1.73205080756887729
+
+static GLfloat tdata[4][3] =
+{
+ {T, T, T},
+ {T, -T, -T},
+ {-T, T, -T},
+ {-T, -T, T}
+};
+
+static int tndex[4][3] =
+{
+ {0, 1, 3},
+ {2, 1, 0},
+ {3, 2, 0},
+ {1, 2, 3}
+};
+
+static void
+tetrahedron(GLenum shadeType)
+{
+ int i;
+
+ for (i = 3; i >= 0; i--)
+ drawtriangle(i, tdata, tndex, shadeType);
+}
+
+/* CENTRY */
+void APIENTRY
+glutWireTetrahedron(void)
+{
+ tetrahedron(GL_LINE_LOOP);
+}
+
+void APIENTRY
+glutSolidTetrahedron(void)
+{
+ tetrahedron(GL_TRIANGLES);
+}
+
+/* ENDCENTRY */
diff --git a/src/glut/mini/overlay.c b/src/glut/mini/overlay.c
new file mode 100644
index 0000000000..fc8a8e5b0d
--- /dev/null
+++ b/src/glut/mini/overlay.c
@@ -0,0 +1,60 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include "GL/glut.h"
+
+
+void APIENTRY glutEstablishOverlay (void)
+{
+}
+
+
+void APIENTRY glutRemoveOverlay (void)
+{
+}
+
+
+void APIENTRY glutUseLayer (GLenum layer)
+{
+}
+
+
+void APIENTRY glutPostOverlayRedisplay (void)
+{
+}
+
+
+void APIENTRY glutShowOverlay (void)
+{
+}
+
+
+void APIENTRY glutHideOverlay (void)
+{
+}
diff --git a/src/glut/mini/state.c b/src/glut/mini/state.c
new file mode 100644
index 0000000000..81aefc53bd
--- /dev/null
+++ b/src/glut/mini/state.c
@@ -0,0 +1,70 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.0 for Mesa 4.0
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include "GL/glut.h"
+#include <sys/time.h>
+
+
+#define TIMEDELTA(dest, src1, src2) { \
+ if(((dest).tv_usec = (src1).tv_usec - (src2).tv_usec) < 0) { \
+ (dest).tv_usec += 1000000; \
+ (dest).tv_sec = (src1).tv_sec - (src2).tv_sec - 1; \
+ } else { \
+ (dest).tv_sec = (src1).tv_sec - (src2).tv_sec; \
+ } \
+}
+
+int APIENTRY glutGet (GLenum type)
+{
+
+ switch (type) {
+ case GLUT_WINDOW_RGBA:
+ return 1;
+ case GLUT_ELAPSED_TIME: {
+ static int inited = 0;
+ static struct timeval elapsed, beginning, now;
+ if (!inited) {
+ gettimeofday(&beginning, 0);
+ inited = 1;
+ }
+ gettimeofday(&now, 0);
+ TIMEDELTA(elapsed, now, beginning);
+ /* Return elapsed milliseconds. */
+ return (int) ((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000));
+ }
+ default:
+ return 0;
+ }
+}
+
+
+int APIENTRY glutDeviceGet (GLenum type)
+{
+ return 0;
+}
diff --git a/src/glut/mini/teapot.c b/src/glut/mini/teapot.c
new file mode 100644
index 0000000000..ec2a207763
--- /dev/null
+++ b/src/glut/mini/teapot.c
@@ -0,0 +1,214 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994. */
+
+/**
+(c) Copyright 1993, Silicon Graphics, Inc.
+
+ALL RIGHTS RESERVED
+
+Permission to use, copy, modify, and distribute this software
+for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that
+both the copyright notice and this permission notice appear in
+supporting documentation, and that the name of Silicon
+Graphics, Inc. not be used in advertising or publicity
+pertaining to distribution of the software without specific,
+written prior permission.
+
+THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
+"AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
+OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO
+EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE
+ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
+INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
+SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
+NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY
+OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+US Government Users Restricted Rights
+
+Use, duplication, or disclosure by the Government is subject to
+restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+(c)(1)(ii) of the Rights in Technical Data and Computer
+Software clause at DFARS 252.227-7013 and/or in similar or
+successor clauses in the FAR or the DOD or NASA FAR
+Supplement. Unpublished-- rights reserved under the copyright
+laws of the United States. Contractor/manufacturer is Silicon
+Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA
+94039-7311.
+
+OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+*/
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "GL/glut.h"
+
+/* Rim, body, lid, and bottom data must be reflected in x and
+ y; handle and spout data across the y axis only. */
+
+static int patchdata[][16] =
+{
+ /* rim */
+ {102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15},
+ /* body */
+ {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27},
+ {24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40},
+ /* lid */
+ {96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101,
+ 101, 0, 1, 2, 3,},
+ {0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117},
+ /* bottom */
+ {118, 118, 118, 118, 124, 122, 119, 121, 123, 126,
+ 125, 120, 40, 39, 38, 37},
+ /* handle */
+ {41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56},
+ {53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 28, 65, 66, 67},
+ /* spout */
+ {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83},
+ {80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95}
+};
+/* *INDENT-OFF* */
+
+static float cpdata[][3] =
+{
+ {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0,
+ -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125},
+ {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375,
+ 0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375,
+ 2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84,
+ 2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875},
+ {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75,
+ 1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35},
+ {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2,
+ 0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12,
+ 0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225},
+ {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225},
+ {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0,
+ -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5,
+ -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3,
+ 2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0,
+ 2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0,
+ 2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8},
+ {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3,
+ -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3,
+ 1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2,
+ -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0,
+ 1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0,
+ 0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66,
+ 0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1},
+ {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7,
+ -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0,
+ 2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375},
+ {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475},
+ {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4},
+ {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0,
+ 3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8,
+ 3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4,
+ -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0,
+ 2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4,
+ 2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3,
+ 2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4},
+ {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425,
+ -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425,
+ 0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075},
+ {0.84, -1.5, 0.075}
+};
+
+static float tex[2][2][2] =
+{
+ { {0, 0},
+ {1, 0}},
+ { {0, 1},
+ {1, 1}}
+};
+
+/* *INDENT-ON* */
+
+static void
+teapot(GLint grid, GLdouble scale, GLenum type)
+{
+ float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3];
+ long i, j, k, l;
+
+#if 0
+ glPushAttrib(GL_ENABLE_BIT | GL_EVAL_BIT);
+ glEnable(GL_AUTO_NORMAL);
+ glEnable(GL_NORMALIZE);
+ glEnable(GL_MAP2_VERTEX_3);
+ glEnable(GL_MAP2_TEXTURE_COORD_2);
+ glPushMatrix();
+ glRotatef(270.0, 1.0, 0.0, 0.0);
+ glScalef(0.5 * scale, 0.5 * scale, 0.5 * scale);
+ glTranslatef(0.0, 0.0, -1.5);
+ for (i = 0; i < 10; i++) {
+ for (j = 0; j < 4; j++) {
+ for (k = 0; k < 4; k++) {
+ for (l = 0; l < 3; l++) {
+ p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
+ q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
+ if (l == 1)
+ q[j][k][l] *= -1.0;
+ if (i < 6) {
+ r[j][k][l] =
+ cpdata[patchdata[i][j * 4 + (3 - k)]][l];
+ if (l == 0)
+ r[j][k][l] *= -1.0;
+ s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
+ if (l == 0)
+ s[j][k][l] *= -1.0;
+ if (l == 1)
+ s[j][k][l] *= -1.0;
+ }
+ }
+ }
+ }
+ glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2,
+ &tex[0][0][0]);
+ glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
+ &p[0][0][0]);
+ glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0);
+ glEvalMesh2(type, 0, grid, 0, grid);
+ glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
+ &q[0][0][0]);
+ glEvalMesh2(type, 0, grid, 0, grid);
+ if (i < 6) {
+ glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
+ &r[0][0][0]);
+ glEvalMesh2(type, 0, grid, 0, grid);
+ glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
+ &s[0][0][0]);
+ glEvalMesh2(type, 0, grid, 0, grid);
+ }
+ }
+ glPopMatrix();
+ glPopAttrib();
+#endif
+}
+
+/* CENTRY */
+void APIENTRY
+glutSolidTeapot(GLdouble scale)
+{
+ teapot(7, scale, GL_FILL);
+}
+
+void APIENTRY
+glutWireTeapot(GLdouble scale)
+{
+ teapot(10, scale, GL_LINE);
+}
+
+/* ENDCENTRY */
diff --git a/src/glut/mini/window.c b/src/glut/mini/window.c
new file mode 100644
index 0000000000..73266769c5
--- /dev/null
+++ b/src/glut/mini/window.c
@@ -0,0 +1,273 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.1
+ * Copyright (C) 1995-1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * DOS/DJGPP glut driver v1.2 for Mesa 4.1
+ *
+ * Copyright (C) 2002 - Borca Daniel
+ * Email : dborca@yahoo.com
+ * Web : http://www.geocities.com/dborca
+ */
+
+
+#include <stdio.h>
+#include <GL/gl.h>
+#include "GL/glut.h"
+#include "internal.h"
+
+#define USE_MINI_GLX 1
+#if USE_MINI_GLX
+#include "GL/miniglx.h"
+#else
+#include <GL/glx.h>
+#endif
+
+
+
+static GLXContext context = 0;
+static Window win;
+static XVisualInfo *visinfo = 0;
+static Display *dpy = 0;
+
+
+int APIENTRY glutCreateWindow (const char *title)
+{
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ GLXContext ctx;
+ int scrnum = 0;
+ Window root = RootWindow( dpy, scrnum );
+
+ if (win)
+ return 0;
+
+ if (!dpy) {
+ dpy = XOpenDisplay(NULL);
+ if (!dpy) {
+ printf("Error: XOpenDisplay failed\n");
+ exit(1);
+ }
+ }
+
+ if (!visinfo) {
+ int attrib[] = {GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, g_width, g_height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+ if (!win) {
+ printf("Error: XCreateWindow failed\n");
+ exit(1);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ if (!glXMakeCurrent( dpy, win, ctx )) {
+ printf("Error: glXMakeCurrent failed\n");
+ exit(1);
+ }
+
+ if (!(g_display_mode & GLUT_DOUBLE))
+ glDrawBuffer( GL_FRONT );
+
+
+ XMapWindow( dpy, win );
+
+#if !USE_MINI_GLX
+ {
+ XEvent e;
+ while (1) {
+ XNextEvent( dpy, &e );
+ if (e.type == MapNotify && e.xmap.window == win) {
+ break;
+ }
+ }
+ }
+#endif
+
+ return 1;
+}
+
+
+int APIENTRY glutCreateSubWindow (int win, int x, int y, int width, int height)
+{
+ return GL_FALSE;
+}
+
+
+void APIENTRY glutDestroyWindow (int idx)
+{
+ if (dpy && win)
+ XDestroyWindow( dpy, win );
+
+ if (dpy)
+ XCloseDisplay( dpy );
+
+ win = 0;
+ dpy = 0;
+}
+
+
+void APIENTRY glutPostRedisplay (void)
+{
+ g_redisplay = GL_TRUE;
+}
+
+
+void APIENTRY glutSwapBuffers (void)
+{
+/* if (g_mouse) pc_scare_mouse(); */
+ if (dpy && win) glXSwapBuffers( dpy, win );
+/* if (g_mouse) pc_unscare_mouse(); */
+}
+
+
+int APIENTRY glutGetWindow (void)
+{
+ return 0;
+}
+
+
+void APIENTRY glutSetWindow (int win)
+{
+}
+
+
+void APIENTRY glutSetWindowTitle (const char *title)
+{
+}
+
+
+void APIENTRY glutSetIconTitle (const char *title)
+{
+}
+
+
+void APIENTRY glutPositionWindow (int x, int y)
+{
+}
+
+
+void APIENTRY glutReshapeWindow (int width, int height)
+{
+}
+
+
+void APIENTRY glutPopWindow (void)
+{
+}
+
+
+void APIENTRY glutPushWindow (void)
+{
+}
+
+
+void APIENTRY glutIconifyWindow (void)
+{
+}
+
+
+void APIENTRY glutShowWindow (void)
+{
+}
+
+
+void APIENTRY glutHideWindow (void)
+{
+}
+
+void APIENTRY glutMainLoop (void)
+{
+ GLboolean idle;
+ GLboolean have_event;
+ XEvent evt;
+ int visible = 0;
+
+ glutPostRedisplay();
+ if (reshape_func) reshape_func(g_width, g_height);
+
+ while (GL_TRUE) {
+ idle = GL_TRUE;
+
+
+ if (visible && idle_func)
+ have_event = XCheckMaskEvent( dpy, ~0, &evt );
+ else
+ have_event = XNextEvent( dpy, &evt );
+
+ if (have_event) {
+ idle = GL_FALSE;
+ switch(evt.type) {
+ case MapNotify:
+ if (visibility_func) {
+ visibility_func(GLUT_VISIBLE);
+ }
+ visible = 1;
+ break;
+ case UnmapNotify:
+ if (visibility_func) {
+ visibility_func(GLUT_NOT_VISIBLE);
+ }
+ visible = 0;
+ break;
+ case Expose:
+ g_redisplay = 1;
+ break;
+ }
+ }
+
+ if (visible && g_redisplay && display_func) {
+ idle = GL_FALSE;
+ g_redisplay = GL_FALSE;
+
+ display_func();
+ }
+
+ if (visible && idle && idle_func) {
+ idle_func();
+ }
+ }
+}
diff --git a/src/glx/mini/Makefile.X11 b/src/glx/mini/Makefile.X11
new file mode 100644
index 0000000000..2e818f0b01
--- /dev/null
+++ b/src/glx/mini/Makefile.X11
@@ -0,0 +1,79 @@
+# Build a subset DRI-based libGL.so library.
+# Indirect rendering not supported, etc.
+
+TOP = ../../..
+
+default: linux-solo
+
+C_SOURCES = dispatch.c \
+ dri_util.c \
+ ../../mesa/glapi/glapi.c \
+ ../../mesa/glapi/glthread.c \
+ miniglx.c \
+ miniglx_events.c \
+ xf86drm.c
+
+OBJECTS = $(C_SOURCES:.c=.o)
+
+INCLUDES = -I. $(INCLUDE_DIRS)
+LIBS = -ldl
+
+### 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 $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+
+##### TARGETS #####
+
+targets: depend libGL.so.1.2
+
+libGL.so.1.2: $(OBJECTS) Makefile.X11
+ rm -f $@ && gcc -shared -Wl,-soname,libGL.so -Wl,-Bsymbolic $(OBJECTS) $(LIBS) -o $@
+ rm -f $(TOP)/lib/libGL.so*
+ rm -f $(TOP)/lib/miniglx.conf
+ install -D libGL.so.1.2 $(TOP)/lib/libGL.so.1.2
+ ln -s libGL.so.1.2 $(TOP)/lib/libGL.so.1
+ ln -s libGL.so.1 $(TOP)/lib/libGL.so
+ install example.miniglx.conf $(TOP)/lib/miniglx.conf
+
+drmtest: xf86drm.o drmtest.o
+ rm -f drmtest && $(CC) -o drmtest xf86drm.o drmtest.o
+
+# 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 $(INCLUDES) \
+ $(C_SOURCES) $(ASM_SOURCES)
+
+
+# Emacs tags
+tags:
+ etags `find . -name \*.[ch]` `find ../include`
+
+
+# Remove .o and backup files
+clean:
+ -rm -f drmtest $(TOP)/lib/libGL.so*
+ -rm -f */*.o */*~ */*.o */*~
+
+
+include $(TOP)/Make-config
+
+include depend
diff --git a/src/glx/mini/NOTES b/src/glx/mini/NOTES
new file mode 100644
index 0000000000..1774107d63
--- /dev/null
+++ b/src/glx/mini/NOTES
@@ -0,0 +1,115 @@
+
+
+Getting MiniGLX up and running
+------------------------------
+
+It's necessary to do a bit of work to set up an environment to run miniglx.
+
+For the radeon driver, it's necessary to get the right set of kernel
+modules installed before attempting to run any programs:
+
+ rmmod radeon agpgart;
+ insmod agpgart;
+ insmod $(MESA)/src/kernel/radeonfb/radeonfb.o;
+ insmod $(MESA)/src/kernel/radeon/radeon.o;
+
+For all drivers, its necessary to reach the compiled libraries, and
+tell MiniGLX where to find it's configuration file:
+
+ export LD_LIBRARY_PATH=$(MESA)/lib;
+ export MINIGLX_CONF=$(MESA)/lib/miniglx.conf
+
+------------------------------------------------------------
+
+MiniGLX Example Programs
+------------------------
+
+The following programs will work with miniglx:
+
+ $(MESA)/tests/miniglx
+ $(MESA)/xdemos/glxgears
+
+Thanks to the miniglut stub library, most of the mesa glut demos will
+work. In particular, the following have been tested. (Note there is
+no keyboard or mouse interaction with these demos).
+
+ $(MESA)/demos/gears
+ $(MESA)/demos/geartrain
+ $(MESA)/demos/morph3d
+ $(MESA)/demos/isosurf
+ $(MESA)/demos/texobj
+ $(MESA)/demos/texcyl
+ $(MESA)/demos/gloss
+ $(MESA)/demos/fire
+ $(MESA)/demos/tunnel
+ $(MESA)/demos/teapot
+ $(MESA)/samples/prim
+ $(MESA)/samples/olympic
+ $(MESA)/samples/star
+ $(MESA)/samples/wave
+ ...etc
+
+In fact most of the glut demos seem to work within the constraints of
+having no keyboard/mouse interactivity. Furthermore, the use of the
+glut wrapper means that these programs don't require recompilation to
+run under MiniGLX -- the same binary works with both regular GLX and
+MiniGLX.
+
+
+------------------------------------------------------------
+
+Porting GLX apps to MiniGLX
+---------------------------
+
+A quick list of issues encountered in porting existing GLX apps to
+MiniGLX. Listed in no particular order.
+
+1) No input events
+
+MiniGLX doesn't provide an input layer, so any X11 input event
+handling in the existing app will have to be redone for whatever
+input devices exist on the target.
+
+2) No configuration, expose events
+
+Many GLX and Xlib programs wait on an event to ensure the window has
+become visible after being mapped. MiniGLX provides no equivalent
+facility.
+
+3) Different headers
+
+X11/Xlib.h, GL/GLX.h, etc must not be used if the program is being
+compiled against MiniGLX.
+
+The equivalent header is GL/MiniGLX.h.
+
+4) Different library
+
+It may be necessary to link directly against the minGLX libGL.so.
+
+5) Reduced number of Xlib and GLX entrypoints.
+
+By definition (MiniGLX is a subset of GLX), many Xlib and GLX
+entrypoints, structures and macros are not present in MiniGLX. It
+will be necessary to find and eliminate all references to
+non-supported entrypoints.
+
+
+---------------------------------------------------------------
+
+Bugs in radeonfb.o -- the radeon framebuffer driver.
+----------------------------------------------------
+
+Several bugs have been found in the radeonfb.o framebuffer driver.
+Most of these are resolved in the version included in the MiniGLX
+sources, but some remain:
+
+1) Occasionally, after entering graphics mode, colors appear 'shifted'
+or 'translated', particularly in higher resolution modes. This is
+definitely a bug in radeonfb.o as this can be provoked even when using
+the software dri driver (fb_dri.so). Importance: High. Workaround:
+Use 800x600 as it seems to be less frequent at this resolution,
+otherwise, restart the application.
+
+
+
diff --git a/src/glx/mini/dispatch.c b/src/glx/mini/dispatch.c
new file mode 100644
index 0000000000..264cd4cba8
--- /dev/null
+++ b/src/glx/mini/dispatch.c
@@ -0,0 +1,64 @@
+/**
+ * \file miniglx/dispatch.c
+ *
+ * \brief C-based dispatch of the OpenGL entry points (glAccum(), glBegin(),
+ * etc).
+ *
+ * \author Brian Paul <brian@precisioninsight.com>
+ *
+ * \note This code IS NOT USED if we're compiling on an x86 system and using
+ * the glapi_x86.S assembly code.
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+ */
+
+#include <GL/gl.h>
+#include "glapi.h"
+#include "glapitable.h"
+
+
+#if !(defined(USE_X86_ASM) || defined(USE_SPARC_ASM))
+
+#define KEYWORD1
+
+#define KEYWORD2
+
+#define NAME(func) gl##func
+
+#define DISPATCH(func, args, msg) \
+ const struct _glapi_table *dispatch; \
+ dispatch = _glapi_Dispatch ? _glapi_Dispatch : _glapi_get_dispatch();\
+ (dispatch->func) args
+
+#define RETURN_DISPATCH(func, args, msg) \
+ const struct _glapi_table *dispatch; \
+ dispatch = _glapi_Dispatch ? _glapi_Dispatch : _glapi_get_dispatch();\
+ return (dispatch->func) args
+
+
+#include "glapitemp.h"
+
+#endif /* USE_X86_ASM */
diff --git a/src/glx/mini/dri.h b/src/glx/mini/dri.h
new file mode 100644
index 0000000000..71f9a1acbf
--- /dev/null
+++ b/src/glx/mini/dri.h
@@ -0,0 +1,124 @@
+/**
+ * \file miniglxP.h
+ * \brief Define replacements for some X data types and define the DRI-related
+ * data structures.
+ *
+ * \note Cut down version of glxclient.h.
+ *
+ */
+
+#ifndef _dri_h_
+#define _dri_h_
+
+#include "driver.h"
+
+typedef struct __DRIscreenRec __DRIscreen; /**< \copydoc __DRIscreenRec */
+typedef struct __DRIcontextRec __DRIcontext; /**< \copydoc __DRIcontextRec */
+typedef struct __DRIdrawableRec __DRIdrawable; /**< \copydoc __DRIdrawableRec */
+
+/**
+ * \brief Screen dependent methods.
+ *
+ * This structure is initialized during the MiniGLXDisplayRec::createScreen
+ * call.
+ */
+struct __DRIscreenRec {
+ /**
+ * \brief Method to destroy the private DRI screen data.
+ */
+ void (*destroyScreen)(__DRIscreen *screen);
+
+ /**
+ * \brief Method to create the private DRI context data and initialize the
+ * context dependent methods.
+ */
+ void *(*createContext)(__DRIscreen *screen, const __GLcontextModes *glVisual,
+ void *sharedPrivate);
+ /**
+ * \brief Method to create the private DRI drawable data and initialize the
+ * drawable dependent methods.
+ */
+ void *(*createDrawable)(__DRIscreen *screen,
+ int width, int height, int index,
+ const __GLcontextModes *glVisual);
+
+ /*
+ * XXX in the future, implement this:
+ void *(*createPBuffer)(Display *dpy, int scrn, GLXPbuffer pbuffer,
+ GLXFBConfig config, __DRIdrawable *pdraw);
+ */
+
+ /**
+ * \brief Opaque pointer to private per screen direct rendering data.
+ *
+ * \c NULL if direct rendering is not supported on this screen. Never
+ * dereferenced in libGL.
+ */
+};
+
+/**
+ * \brief Context dependent methods.
+ *
+ * This structure is initialized during the __DRIscreenRec::createContext call.
+ */
+struct __DRIcontextRec {
+ /**
+ * \brief Method to destroy the private DRI context data.
+ */
+ void (*destroyContext)(__DRIcontext *context);
+
+ /**
+ * \brief Method to bind a DRI drawable to a DRI graphics context.
+ *
+ * \todo XXX in the future, also pass a 'read' GLXDrawable for
+ * glXMakeCurrentReadSGI() and GLX 1.3's glXMakeContextCurrent().
+ */
+ GLboolean (*bindContext)(__DRIscreen *screen, __DRIdrawable *drawable, __DRIcontext *context);
+
+ /**
+ * \brief Method to unbind a DRI drawable to a DRI graphics context.
+ */
+ GLboolean (*unbindContext)(__DRIdrawable *drawable, __DRIcontext *context);
+ /**
+ * \brief Opaque pointer to private per context direct rendering data.
+ *
+ * NULL if direct rendering is not supported on the display or
+ * screen used to create this context. Never dereferenced in libGL.
+ */
+};
+
+/**
+ * \brief Drawable dependent methods.
+ *
+ * This structure is initialized during the __DRIscreenRec::createDrawable call.
+ *
+ * __DRIscreenRec::createDrawable is not called by libGL at this time. It's
+ * currently used via the dri_util.c utility code instead.
+ */
+struct __DRIdrawableRec {
+ /**
+ * \brief Method to destroy the private DRI drawable data.
+ */
+ void (*destroyDrawable)(__DRIdrawable *drawable);
+
+
+ /**
+ * \brief Method to swap the front and back buffers.
+ */
+ void (*swapBuffers)(__DRIdrawable *drawable);
+
+ /**
+ * \brief Opaque pointer to private per drawable direct rendering data.
+ *
+ * \c NULL if direct rendering is not supported on the display or
+ * screen used to create this drawable. Never dereferenced in libGL.
+ */
+};
+
+typedef void *(driCreateScreenFunc)(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext);
+
+/** This must be implemented in each driver */
+extern driCreateScreenFunc __driCreateScreen;
+
+#endif /* _dri_h_ */
diff --git a/src/glx/mini/dri_util.c b/src/glx/mini/dri_util.c
new file mode 100644
index 0000000000..6d79d2037c
--- /dev/null
+++ b/src/glx/mini/dri_util.c
@@ -0,0 +1,715 @@
+/**
+ * \file dri_util.c
+ * \brief DRI utility functions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/fb.h>
+#include <linux/vt.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+
+#include "sarea.h"
+#include "dri_util.h"
+
+/**
+ * \brief Print message to \c stderr if the \c LIBGL_DEBUG environment variable
+ * is set.
+ *
+ * Is called from the drivers.
+ *
+ * \param f \e printf like format.
+ *
+ * \internal
+ * This function is a wrapper around vfprintf().
+ */
+void
+__driUtilMessage(const char *f, ...)
+{
+ va_list args;
+
+ if (getenv("LIBGL_DEBUG")) {
+ fprintf(stderr, "libGL error: \n");
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+}
+
+
+/*****************************************************************/
+/** \name Visual utility functions */
+/*****************************************************************/
+/*@{*/
+
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context (un)binding functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Unbind context.
+ *
+ * \param drawable __DRIdrawable
+ * \param context __DRIcontext
+ * \param will_rebind not used.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::UnbindContext, and then decrements
+ * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
+ * return.
+ *
+ * While casting the opaque private pointers associated with the parameters into their
+ * respective real types it also assures they are not null.
+ */
+static GLboolean driUnbindContext(__DRIdrawable *drawable,
+ __DRIcontext *context)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+ __DRIscreenPrivate *psp;
+
+ if (pdp == NULL || pcp == NULL)
+ return GL_FALSE;
+
+ if (!(psp = (__DRIscreenPrivate *)pdp->driScreenPriv))
+ return GL_FALSE;
+
+ /* Let driver unbind drawable from context */
+ (*psp->DriverAPI.UnbindContext)(pcp);
+
+ if (pdp->refcount == 0)
+ return GL_FALSE;
+
+ --pdp->refcount;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * \brief Unbind context.
+ *
+ * \param pDRIScreen __DRIscreen
+ * \param drawable __DRIdrawable
+ * \param context __DRIcontext
+ *
+ * \internal
+ * This function and increments __DRIdrawablePrivateRec::refcount and calls
+ * __DriverAPIRec::MakeCurrent to binds the drawable.
+ *
+ * While casting the opaque private pointers into their
+ * respective real types it also assures they are not null.
+ */
+static GLboolean driBindContext(__DRIscreen *screen, __DRIdrawable *drawable,
+ __DRIcontext *context)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+
+ if (psp == NULL)
+ return GL_FALSE;
+
+ if (pdp == NULL || pcp == NULL) {
+ (*psp->DriverAPI.MakeCurrent)(0, 0, 0);
+ return GL_TRUE;
+ }
+
+ /* Bind the drawable to the context */
+ pcp->driDrawablePriv = pdp;
+ pdp->driContextPriv = pcp;
+ pdp->refcount++;
+
+ /* Call device-specific MakeCurrent */
+ (*psp->DriverAPI.MakeCurrent)(pcp, pdp, pdp);
+
+ return GL_TRUE;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Drawable handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Update private drawable information.
+ *
+ * \param pdp pointer to the private drawable information to update.
+ *
+ * \internal
+ * This function is a no-op. Should never be called but is referenced as an
+ * external symbol from client drivers.
+ */
+void __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
+{
+ __DRIscreenPrivate *psp = pdp->driScreenPriv;
+
+ pdp->numClipRects = psp->pSAREA->drawableTable[pdp->index].flags ? 1 : 0;
+ pdp->lastStamp = *(pdp->pStamp);
+}
+
+
+/**
+ * \brief Swap buffers.
+ *
+ * \param pDRIscreen __DRIscreen
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DRIdrawablePrivate::swapBuffers.
+ *
+ * Is called directly from glXSwapBuffers().
+ */
+static void driSwapBuffers(__DRIdrawable *drawable)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ if (pdp)
+ pdp->swapBuffers(pdp);
+}
+
+
+/**
+ * \brief Destroy per-drawable private information.
+ *
+ * \param pDRIscreen __DRIscreen
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyBuffer on \p drawablePrivate,
+ * frees the clip rects if any, and finally frees \p drawablePrivate itself.
+ */
+static void driDestroyDrawable(__DRIdrawable *drawable)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIscreenPrivate *psp;
+
+ if (pdp) {
+ psp = pdp->driScreenPriv;
+ (*psp->DriverAPI.DestroyBuffer)(pdp);
+ if (pdp->pClipRects)
+ free(pdp->pClipRects);
+ free(pdp);
+ }
+}
+
+
+/**
+ * \brief Create the per-drawable private driver information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param draw the GLX drawable info.
+ * \param vid visual ID.
+ * \param pdraw will receive the drawable dependent methods.
+ *
+ *
+ * \returns a opaque pointer to the per-drawable private info on success, or NULL
+ * on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIdrawablePrivateRec structure,
+ * initializing the invariant window dimensions and clip rects. It obtains the
+ * visual config, converts it into a __GLcontextModesRec and passes it to
+ * __DriverAPIRec::CreateBuffer to create a buffer.
+ */
+static void *driCreateDrawable(__DRIscreen *screen,
+ int width, int height, int index,
+ const __GLcontextModes *glVisual)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIdrawablePrivate *pdp;
+
+ if (!psp)
+ return NULL;
+
+ if (!(pdp = (__DRIdrawablePrivate *)malloc(sizeof(__DRIdrawablePrivate))))
+ return NULL;
+
+ pdp->index = index;
+ pdp->refcount = 0;
+ pdp->lastStamp = -1;
+ pdp->numBackClipRects = 0;
+ pdp->pBackClipRects = NULL;
+
+ /* Initialize with the invariant window dimensions and clip rects here.
+ */
+ pdp->x = 0;
+ pdp->y = 0;
+ pdp->w = width;
+ pdp->h = height;
+ pdp->numClipRects = 0;
+ pdp->pClipRects = (XF86DRIClipRectPtr) malloc(sizeof(XF86DRIClipRectRec));
+ (pdp->pClipRects)[0].x1 = 0;
+ (pdp->pClipRects)[0].y1 = 0;
+ (pdp->pClipRects)[0].x2 = width;
+ (pdp->pClipRects)[0].y2 = height;
+
+ pdp->driScreenPriv = psp;
+ pdp->driContextPriv = 0;
+
+ pdp->frontBuffer = psp->pFB;
+ pdp->currentBuffer = pdp->frontBuffer;
+ pdp->currentPitch = psp->fbStride;
+ pdp->backBuffer = psp->pFB + psp->fbStride * psp->fbHeight;
+
+ if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, glVisual, GL_FALSE)) {
+ free(pdp);
+ return NULL;
+ }
+
+ pdp->entry.destroyDrawable = driDestroyDrawable;
+ pdp->entry.swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
+ pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
+
+ pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
+ return (void *) pdp;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Destroy the per-context private information.
+ *
+ * \param contextPrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
+ * drmDestroyContext(), and finally frees \p contextPrivate.
+ */
+static void driDestroyContext(__DRIcontext *context)
+{
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+ __DRIscreenPrivate *psp = NULL;
+
+ if (pcp) {
+ (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
+ psp = pcp->driDrawablePriv->driScreenPriv;
+ if (psp->fd) {
+ printf(">>> drmDestroyContext(0x%x)\n", (int) pcp->hHWContext);
+ drmDestroyContext(psp->fd, pcp->hHWContext);
+ }
+ free(pcp);
+ }
+}
+
+/**
+ * \brief Create the per-drawable private driver information.
+ *
+ * \param dpy the display handle.
+ * \param vis the visual information.
+ * \param sharedPrivate the shared context dependent methods or NULL if non-existent.
+ * \param pctx will receive the context dependent methods.
+ *
+ * \returns a opaque pointer to the per-context private information on success, or NULL
+ * on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIcontextPrivateRec structure. It
+ * gets the visual, converts it into a __GLcontextModesRec and passes it
+ * to __DriverAPIRec::CreateContext to create the context.
+ */
+static void *driCreateContext(__DRIscreen *screen,
+ const __GLcontextModes *glVisual,
+ void *sharedPrivate)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIcontextPrivate *pcp;
+ __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
+ void *shareCtx;
+
+ if (!psp)
+ return NULL;
+
+ if (!(pcp = (__DRIcontextPrivate *)malloc(sizeof(__DRIcontextPrivate))))
+ return NULL;
+
+ pcp->driScreenPriv = psp;
+ pcp->driDrawablePriv = NULL;
+
+ if (psp->fd) {
+ if (drmCreateContext(psp->fd, &pcp->hHWContext)) {
+ fprintf(stderr, ">>> drmCreateContext failed\n");
+ free(pcp);
+ return NULL;
+ }
+ }
+
+ shareCtx = pshare ? pshare->driverPrivate : NULL;
+
+ if (!(*psp->DriverAPI.CreateContext)(glVisual, pcp, shareCtx)) {
+ if (psp->fd)
+ (void) drmDestroyContext(psp->fd, pcp->hHWContext);
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->entry.destroyContext = driDestroyContext;
+ pcp->entry.bindContext = driBindContext;
+ pcp->entry.unbindContext = driUnbindContext;
+
+ return pcp;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Screen handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Destroy the per-screen private information.
+ *
+ * \param pDRIscreen __DRIscreen
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
+ * drmClose(), and finally frees \p screenPrivate.
+ */
+static void driDestroyScreen(__DRIscreen *screen)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ if (psp) {
+ if (psp->DriverAPI.DestroyScreen)
+ (*psp->DriverAPI.DestroyScreen)(psp);
+
+ if (psp->fd)
+ (void)drmClose(psp->fd);
+
+ free(psp->pDevPriv);
+ free(psp);
+ }
+}
+
+
+/**
+ * \brief Create the per-screen private information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param psc will receive the screen dependent methods.
+ * \param numConfigs number of visuals.
+ * \param config visuals.
+ * \param driverAPI driver callbacks structure.
+ *
+ * \return a pointer to the per-screen private information.
+ *
+ * \internal
+ * This function allocates and fills a __DRIscreenPrivateRec structure. It
+ * opens the DRM device verifying that the exported version matches the
+ * expected. It copies the driver callback functions and calls
+ * __DriverAPIRec::InitDriver.
+ *
+ * If a client maps the framebuffer and SAREA regions.
+ */
+__DRIscreenPrivate *
+__driUtilCreateScreen(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI)
+{
+ __DRIscreenPrivate *psp;
+
+ if(!(psp = (__DRIscreenPrivate *)malloc(sizeof(__DRIscreenPrivate))))
+ return NULL;
+
+ psp->fd = drmOpen(NULL, driverContext->pciBusID);
+ if (psp->fd < 0) {
+ fprintf(stderr, "libGL error: failed to open DRM: %s\n",
+ strerror(-psp->fd));
+ free(psp);
+ return NULL;
+ }
+
+ {
+ drmVersionPtr version = drmGetVersion(psp->fd);
+ if (version) {
+ psp->drmMajor = version->version_major;
+ psp->drmMinor = version->version_minor;
+ psp->drmPatch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+ else {
+ fprintf(stderr, "libGL error: failed to get drm version: %s\n",
+ strerror(-psp->fd));
+ free(psp);
+ return NULL;
+ }
+ }
+
+ /*
+ * Fake various version numbers.
+ */
+ psp->ddxMajor = 4;
+ psp->ddxMinor = 0;
+ psp->ddxPatch = 1;
+ psp->driMajor = 4;
+ psp->driMinor = 1;
+ psp->driPatch = 0;
+
+ /* install driver's callback functions */
+ psp->DriverAPI = *driverAPI;
+
+ /*
+ * Get device-specific info. pDevPriv will point to a struct
+ * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
+ * that has information about the screen size, depth, pitch,
+ * ancilliary buffers, DRM mmap handles, etc.
+ */
+ psp->fbOrigin = driverContext->shared.fbOrigin;
+ psp->fbSize = driverContext->shared.fbSize;
+ psp->fbStride = driverContext->shared.fbStride;
+ psp->devPrivSize = driverContext->driverClientMsgSize;
+ psp->pDevPriv = driverContext->driverClientMsg;
+ psp->fbWidth = driverContext->shared.virtualWidth;
+ psp->fbHeight = driverContext->shared.virtualHeight;
+ psp->fbBPP = driverContext->bpp;
+
+ if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
+ /* Already mapped in server */
+ psp->pFB = driverContext->FBAddress;
+ psp->pSAREA = driverContext->pSAREA;
+ } else {
+ /*
+ * Map the framebuffer region.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
+ (drmAddressPtr)&psp->pFB)) {
+ fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+ /*
+ * Map the SAREA region. Further mmap regions may be setup in
+ * each DRI driver's "createScreen" function.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hSAREA,
+ driverContext->shared.SAREASize,
+ (drmAddressPtr)&psp->pSAREA)) {
+ fprintf(stderr, "libGL error: drmMap of sarea failed\n");
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+#ifdef _EMBEDDED
+ mprotect(psp->pSAREA, driverContext->shared.SAREASize, PROT_READ);
+#endif
+ }
+
+
+ /* Initialize the screen specific GLX driver */
+ if (psp->DriverAPI.InitDriver) {
+ if (!(*psp->DriverAPI.InitDriver)(psp)) {
+ fprintf(stderr, "libGL error: InitDriver failed\n");
+ free(psp->pDevPriv);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+ }
+
+ psp->entry.destroyScreen = driDestroyScreen;
+ psp->entry.createContext = driCreateContext;
+ psp->entry.createDrawable = driCreateDrawable;
+
+ return psp;
+}
+
+
+
+/**
+ * \brief Create the per-screen private information.
+ *
+ * Version for drivers without a DRM module.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param numConfigs number of visuals.
+ * \param config visuals.
+ * \param driverAPI driver callbacks structure.
+ *
+ * \internal
+ * Same as __driUtilCreateScreen() but without opening the DRM device.
+ */
+__DRIscreenPrivate *
+__driUtilCreateScreenNoDRM(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI)
+{
+ __DRIscreenPrivate *psp;
+
+ psp = (__DRIscreenPrivate *)calloc(1, sizeof(__DRIscreenPrivate));
+ if (!psp)
+ return NULL;
+
+ psp->ddxMajor = 4;
+ psp->ddxMinor = 0;
+ psp->ddxPatch = 1;
+ psp->driMajor = 4;
+ psp->driMinor = 1;
+ psp->driPatch = 0;
+ psp->fd = 0;
+
+ psp->fbOrigin = driverContext->shared.fbOrigin;
+ psp->fbSize = driverContext->shared.fbSize;
+ psp->fbStride = driverContext->shared.fbStride;
+ psp->devPrivSize = driverContext->driverClientMsgSize;
+ psp->pDevPriv = driverContext->driverClientMsg;
+ psp->fbWidth = driverContext->shared.virtualWidth;
+ psp->fbHeight = driverContext->shared.virtualHeight;
+ psp->fbBPP = driverContext->bpp;
+
+ psp->pFB = driverContext->FBAddress;
+
+ /* install driver's callback functions */
+ psp->DriverAPI = *driverAPI;
+
+ if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
+ /* Already mapped in server */
+ psp->pFB = driverContext->FBAddress;
+ psp->pSAREA = driverContext->pSAREA;
+ } else {
+ psp->fd = open("/dev/mem", O_RDWR, 0);
+ /*
+ * Map the framebuffer region.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
+ (drmAddressPtr)&psp->pFB)) {
+ fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+ driverContext->FBAddress = psp->pFB;
+
+ /*
+ * Map the SAREA region. Non-DRM drivers use a shmem SAREA
+ */
+ int id;
+ id = shmget(driverContext->shared.hSAREA, driverContext->shared.SAREASize, 0);
+ driverContext->pSAREA = shmat(id, NULL, 0);
+ if (!driverContext->pSAREA) {
+ fprintf(stderr, "libGL error: shmget of sarea failed\n");
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+ close(psp->fd);
+ psp->fd = 0;
+ }
+
+ /* Initialize the screen specific GLX driver */
+ if (psp->DriverAPI.InitDriver) {
+ if (!(*psp->DriverAPI.InitDriver)(psp)) {
+ fprintf(stderr, "libGL error: InitDriver failed\n");
+ free(psp->pDevPriv);
+ free(psp);
+ return NULL;
+ }
+ }
+
+ psp->entry.destroyScreen = driDestroyScreen;
+ psp->entry.createContext = driCreateContext;
+ psp->entry.createDrawable = driCreateDrawable;
+
+ return psp;
+}
+
+/**
+ * Calculate amount of swap interval used between GLX buffer swaps.
+ *
+ * The usage value, on the range [0,max], is the fraction of total swap
+ * interval time used between GLX buffer swaps is calculated.
+ *
+ * \f$p = t_d / (i * t_r)\f$
+ *
+ * Where \f$t_d\$f is the time since the last GLX buffer swap, \f$i\f$ is the
+ * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
+ * required for a single vertical refresh period (as returned by \c
+ * glXGetMscRateOML).
+ *
+ * See the documentation for the GLX_MESA_swap_frame_usage extension for more
+ * details.
+ *
+ * \param dPriv Pointer to the private drawable structure.
+ * \return If less than a single swap interval time period was required
+ * between GLX buffer swaps, a number greater than 0 and less than
+ * 1.0 is returned. If exactly one swap interval time period is
+ * required, 1.0 is returned, and if more than one is required then
+ * a number greater than 1.0 will be returned.
+ *
+ * \sa glXSwapIntervalSGI(), glXGetMscRateOML().
+ */
+float
+driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
+ int64_t current_ust )
+{
+ return 0.0f;
+}
+
+/**
+ * Compare the current GLX API version with a driver supplied required version.
+ *
+ * The minimum required version is compared with the API version exported by
+ * the \c __glXGetInternalVersion function (in libGL.so).
+ *
+ * \param required_version Minimum required internal GLX API version.
+ * \return A tri-value return, as from strcmp is returned. A value less
+ * than, equal to, or greater than zero will be returned if the
+ * internal GLX API version is less than, equal to, or greater
+ * than \c required_version.
+ *
+ * \sa __glXGetInternalVersion().
+ */
+int driCompareGLXAPIVersion( GLuint required_version )
+{
+ return 0;
+}
+
+/*@}*/
diff --git a/src/glx/mini/dri_util.h b/src/glx/mini/dri_util.h
new file mode 100644
index 0000000000..b653b3c431
--- /dev/null
+++ b/src/glx/mini/dri_util.h
@@ -0,0 +1,523 @@
+/**
+ * \file dri_util.h
+ * \brief DRI utility functions definitions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ * Look for more comments in the dri_util.c file.
+ *
+ * \author Kevin E. Martin <kevin@precisioninsight.com>
+ * \author Brian Paul <brian@precisioninsight.com>
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+ */
+
+
+#ifndef _DRI_UTIL_H_
+#define _DRI_UTIL_H_
+
+#include <inttypes.h>
+#include "dri.h" /* public entry points */
+#include "sarea.h" /* for XF86DRISAREAPtr */
+
+#define _SOLO
+
+typedef unsigned long CARD32;
+typedef int (* PFNGLXGETUSTPROC) ( uint64_t * ust );
+
+typedef struct __DRIdisplayPrivateRec __DRIdisplayPrivate; /**< \brief Alias for __DRIdisplayPrivateRec */
+typedef struct __DRIscreenPrivateRec __DRIscreenPrivate; /**< \brief Alias for __DRIscreenPrivateRec */
+typedef struct __DRIcontextPrivateRec __DRIcontextPrivate; /**< \brief Alias for __DRIcontextPrivateRec */
+typedef struct __DRIdrawablePrivateRec __DRIdrawablePrivate; /**< \brief Alias for __DRIdrawablePrivateRec */
+typedef struct __DRIswapInfoRec __DRIswapInfo; /**< \brief Alias for __DRIswapInfoPrivateRec */
+
+
+/**
+ * Used by DRI_VALIDATE_DRAWABLE_INFO
+ */
+#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(pDrawPriv) \
+ do { \
+ if (*(pDrawPriv->pStamp) != pDrawPriv->lastStamp) { \
+ __driUtilUpdateDrawableInfo(pDrawPriv); \
+ } \
+ } while (0)
+
+
+/**
+ * \brief Utility macro to validate the drawable information.
+ *
+ * See __DRIdrawablePrivateRec::pStamp and __DRIdrawablePrivateRec::lastStamp.
+ */
+#define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \
+do { \
+ DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \
+} while (0)
+
+
+/**
+ * Driver callback functions.
+ *
+ * Each DRI driver must have one of these structures with all the pointers set
+ * to appropriate functions within the driver.
+ *
+ * When glXCreateContext() is called, for example, it'll call a helper function
+ * dri_util.c which in turn will jump through the \a CreateContext pointer in
+ * this structure.
+ */
+struct __DriverAPIRec {
+ /**
+ * Driver initialization callback
+ */
+ GLboolean (*InitDriver)(__DRIscreenPrivate *driScrnPriv);
+
+ /**
+ * Screen destruction callback
+ */
+ void (*DestroyScreen)(__DRIscreenPrivate *driScrnPriv);
+
+ /**
+ * Context creation callback
+ */
+ GLboolean (*CreateContext)(const __GLcontextModes *glVis,
+ __DRIcontextPrivate *driContextPriv,
+ void *sharedContextPrivate);
+
+ /**
+ * Context destruction callback
+ */
+ void (*DestroyContext)(__DRIcontextPrivate *driContextPriv);
+
+ /**
+ * Buffer (drawable) creation callback
+ */
+ GLboolean (*CreateBuffer)(__DRIscreenPrivate *driScrnPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ const __GLcontextModes *glVis,
+ GLboolean pixmapBuffer);
+
+ /**
+ * Buffer (drawable) destruction callback
+ */
+ void (*DestroyBuffer)(__DRIdrawablePrivate *driDrawPriv);
+
+ /**
+ * Buffer swapping callback
+ */
+ void (*SwapBuffers)(__DRIdrawablePrivate *driDrawPriv);
+
+ /**
+ * Context activation callback
+ */
+ GLboolean (*MakeCurrent)(__DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv);
+
+ /**
+ * Context unbinding callback
+ */
+ GLboolean (*UnbindContext)(__DRIcontextPrivate *driContextPriv);
+
+ /**
+ * Full screen mode opening callback.
+ *
+ * \deprecated Full screen functionality is no longer used by DRI.
+ * Drivers should simply install a function returning
+ * \c GL_TRUE for backwards compatability.
+ */
+ GLboolean (*OpenFullScreen)(__DRIcontextPrivate *driContextPriv);
+
+ /**
+ * Full screen mode closing callback.
+ *
+ * \deprecated Full screen functionality is no longer used by DRI.
+ * Drivers should simply install a function returning
+ * \c GL_TRUE for backwards compatability.
+ */
+ GLboolean (*CloseFullScreen)(__DRIcontextPrivate *driContextPriv);
+
+ /* Retrieves statistics about buffer swap operations. Required if
+ * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported.
+ */
+ int (*GetSwapInfo)( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
+
+
+ /* Required if GLX_SGI_video_sync or GLX_OML_sync_control is
+ * supported.
+ */
+ int (*GetMSC)( __DRIscreenPrivate * priv, int64_t * count );
+
+ /**
+ * These are required if GLX_OML_sync_control is supported.
+ */
+ /*@{*/
+ int (*WaitForMSC)( __DRIdrawablePrivate *priv, int64_t target_msc,
+ int64_t divisor, int64_t remainder,
+ int64_t * msc );
+ int (*WaitForSBC)( __DRIdrawablePrivate *priv, int64_t target_sbc,
+ int64_t * msc, int64_t * sbc );
+
+ int64_t (*SwapBuffersMSC)( __DRIdrawablePrivate *priv, int64_t target_msc,
+ int64_t divisor, int64_t remainder );
+ /*@}*/
+};
+
+
+struct __DRIswapInfoRec {
+ /**
+ * Number of swapBuffers operations that have been *completed*.
+ */
+ uint64_t swap_count;
+
+ /*
+ * Unadjusted system time of the last buffer swap. This is the time
+ * when the swap completed, not the time when swapBuffers was called.
+ */
+ int64_t swap_ust;
+
+ /*
+ * Number of swap operations that occurred after the swap deadline. That
+ * is if a swap happens more than swap_interval frames after the previous
+ * swap, it has missed its deadline. If swap_interval is 0, then the
+ * swap deadline is 1 frame after the previous swap.
+ */
+ uint64_t swap_missed_count;
+
+ /*
+ * Amount of time used by the last swap that missed its deadline. This
+ * is calculated as (__glXGetUST() - swap_ust) / (swap_interval *
+ * time_for_single_vrefresh)). If the actual value of swap_interval is
+ * 0, then 1 is used instead. If swap_missed_count is non-zero, this
+ * should be greater-than 1.0.
+ */
+ float swap_missed_usage;
+};
+
+
+/**
+ * \brief Per-drawable private DRI driver information.
+ *
+ */
+struct __DRIdrawablePrivateRec {
+
+ /**
+ * \brief Public entry points
+ */
+ __DRIdrawable entry;
+
+ /**
+ * \brief Kernel drawable handle
+ *
+ * \note Not currently used.
+ */
+ drmDrawable hHWDrawable;
+
+ /**
+ * \brief Driver's private drawable information.
+ *
+ * This structure is opaque.
+ */
+ void *driverPrivate;
+
+ /**
+ * \brief Reference count for number of context's currently bound to this
+ * drawable.
+ *
+ * Once it reaches zero, the drawable can be destroyed.
+ *
+ * \note This behavior will change with GLX 1.3.
+ */
+ int refcount;
+
+ /**
+ * \brief Index of this drawable information in the SAREA.
+ */
+ unsigned int index;
+
+ /**
+ * \brief Pointer to the "drawable has changed ID" stamp in the SAREA.
+ */
+ unsigned int *pStamp;
+
+ /**
+ * \brief Last value of the stamp.
+ *
+ * If this differs from the value stored at
+ * __DRIdrawablePrivateRec::pStamp, then the drawable information has been
+ * modified by the X server, and the drawable information (below) should be
+ * retrieved from the X server.
+ */
+ unsigned int lastStamp;
+
+ /**
+ * \name Drawable
+ * Drawable information used in software fallbacks.
+ */
+ /*@{*/
+ int x;
+ int y;
+ int w;
+ int h;
+ int numClipRects;
+ XF86DRIClipRectPtr pClipRects;
+ /*@}*/
+
+ /**
+ * \name Back and depthbuffer
+ * Information about the back and depthbuffer where different from above.
+ */
+ /*@{*/
+ int backX;
+ int backY;
+ int backClipRectType;
+ int numBackClipRects;
+ XF86DRIClipRectPtr pBackClipRects;
+ /*@}*/
+
+ /**
+ * \brief Pointer to context to which this drawable is currently bound.
+ */
+ __DRIcontextPrivate *driContextPriv;
+
+ /**
+ * \brief Pointer to screen on which this drawable was created.
+ */
+ __DRIscreenPrivate *driScreenPriv;
+
+ int cpp;
+ void *frontBuffer;
+ void *backBuffer;
+ void *currentBuffer;
+ int currentPitch;
+
+ int depthCpp;
+ void *depthBuffer;
+ int depthPitch;
+
+ /**
+ * \brief Called via glXSwapBuffers().
+ */
+ void (*swapBuffers)( __DRIdrawablePrivate *dPriv );
+};
+
+/**
+ * \brief Per-context private driver information.
+ */
+struct __DRIcontextPrivateRec {
+ /**
+ * \brief Public entry points
+ */
+ __DRIcontext entry;
+
+ /**
+ * \brief Kernel context handle used to access the device lock.
+ */
+ drmContext hHWContext;
+
+ /**
+ * \brief Device driver's private context data. This structure is opaque.
+ */
+ void *driverPrivate;
+
+ /**
+ * \brief Pointer to drawable currently bound to this context.
+ */
+ __DRIdrawablePrivate *driDrawablePriv;
+
+ /**
+ * \brief Pointer to screen on which this context was created.
+ */
+ __DRIscreenPrivate *driScreenPriv;
+};
+
+/**
+ * \brief Per-screen private driver information.
+ */
+struct __DRIscreenPrivateRec {
+
+ /**
+ * \brief Public entry points
+ */
+ __DRIscreen entry;
+
+ /**
+ * \brief Callback functions into the hardware-specific DRI driver code.
+ */
+ struct __DriverAPIRec DriverAPI;
+
+ /**
+ * \name DDX version
+ * DDX / 2D driver version information.
+ */
+ /*@{*/
+ int ddxMajor;
+ int ddxMinor;
+ int ddxPatch;
+ /*@}*/
+
+ /**
+ * \name DRI version
+ * DRI X extension version information.
+ */
+ /*@{*/
+ int driMajor;
+ int driMinor;
+ int driPatch;
+ /*@}*/
+
+ /**
+ * \name DRM version
+ * DRM (kernel module) version information.
+ */
+ /*@{*/
+ int drmMajor;
+ int drmMinor;
+ int drmPatch;
+ /*@}*/
+
+ /**
+ * \brief ID used when the client sets the drawable lock.
+ *
+ * The X server uses this value to detect if the client has died while
+ * holding the drawable lock.
+ */
+ int drawLockID;
+
+ /**
+ * \brief File descriptor returned when the kernel device driver is opened.
+ *
+ * Used to:
+ * - authenticate client to kernel
+ * - map the frame buffer, SAREA, etc.
+ * - close the kernel device driver
+ */
+ int fd;
+
+ /**
+ * \brief SAREA pointer
+ *
+ * Used to access:
+ * - the device lock
+ * - the device-independent per-drawable and per-context(?) information
+ */
+ XF86DRISAREAPtr pSAREA;
+
+ /**
+ * \name Direct frame buffer access information
+ * Used for software fallbacks.
+ */
+ /*@{*/
+ unsigned char *pFB;
+ int fbSize;
+ int fbOrigin;
+ int fbStride;
+ int fbWidth;
+ int fbHeight;
+ int fbBPP;
+ /*@}*/
+
+ /**
+ * \name Device-dependent private information (stored in the SAREA).
+ *
+ * This data is accessed by the client driver only.
+ */
+ /*@{*/
+ void *pDevPriv;
+ int devPrivSize;
+ /*@}*/
+
+ /**
+ * \brief Dummy context to which drawables are bound when not bound to any
+ * other context.
+ *
+ * A dummy hHWContext is created for this context, and is used by the GL
+ * core when a hardware lock is required but the drawable is not currently
+ * bound (e.g., potentially during a SwapBuffers request). The dummy
+ * context is created when the first "real" context is created on this
+ * screen.
+ */
+ __DRIcontextPrivate dummyContextPriv;
+
+ /**
+ * \brief Hash table to hold the drawable information for this screen.
+ */
+ void *drawHash;
+
+ /**
+ * \brief Device-dependent private information (not stored in the SAREA).
+ *
+ * This pointer is never touched by the DRI layer.
+ */
+ void *private;
+
+ /**
+ * \brief Full screen mode.
+ *
+ * If we're in full screen mode (via DRIOpenFullScreen()), this points to
+ * the drawable that was bound. Otherwise, this is NULL.
+ */
+ __DRIdrawablePrivate *fullscreen;
+};
+
+extern void
+__driUtilMessage(const char *f, ...);
+
+
+extern void
+__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp);
+
+
+extern __DRIscreenPrivate *
+__driUtilCreateScreen(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI);
+
+__DRIscreenPrivate *
+__driUtilCreateScreenNoDRM(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI);
+
+extern float
+driCalculateSwapUsage( __DRIdrawablePrivate *dPriv,
+ int64_t last_swap_ust, int64_t current_ust );
+
+/* Test the version of the internal GLX API. Returns a value like strcmp. */
+extern int
+driCompareGLXAPIVersion( GLuint required_version );
+
+/** This is optionally implemented in each driver */
+extern void
+__driRegisterExtensions( void );
+
+#endif /* _DRI_UTIL_H_ */
diff --git a/src/glx/mini/driver.h b/src/glx/mini/driver.h
new file mode 100644
index 0000000000..a3ec96083b
--- /dev/null
+++ b/src/glx/mini/driver.h
@@ -0,0 +1,177 @@
+/**
+ * \file driver.h
+ * \brief DRI utility functions definitions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ * Look for more comments in the dri_util.c file.
+ *
+ * \author Kevin E. Martin <kevin@precisioninsight.com>
+ * \author Brian Paul <brian@precisioninsight.com>
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef _driver_H_
+#define _driver_H_
+
+#define CAPI /* XXX this should be globally defined somewhere */
+
+#include "GL/gl.h"
+#include "GL/internal/glcore.h"
+
+/**
+ * \brief Clip rectangle definition.
+ */
+typedef struct _XF86DRIClipRect {
+ unsigned short x1; /**< \brief Upper: inclusive */
+ unsigned short y1; /**< \brief Left: inclusive */
+ unsigned short x2; /**< \brief Lower: exclusive */
+ unsigned short y2; /**< \brief Right: exclusive */
+} XF86DRIClipRectRec, *XF86DRIClipRectPtr;
+
+/**
+ * \brief DRIDriverContext type.
+ */
+typedef struct DRIDriverContextRec {
+ const char *pciBusID;
+ int pciBus;
+ int pciDevice;
+ int pciFunc;
+ int chipset;
+ int bpp;
+ int cpp;
+
+ unsigned long FBStart; /**< \brief physical address of the framebuffer */
+ unsigned long MMIOStart; /**< \brief physical address of the MMIO region */
+
+ int FBSize; /**< \brief size of the mmap'd framebuffer in bytes */
+ int MMIOSize; /**< \brief size of the mmap'd MMIO region in bytes */
+
+ void *FBAddress; /**< \brief start of the mmap'd framebuffer */
+ void *MMIOAddress; /**< \brief start of the mmap'd MMIO region */
+
+ /**
+ * \brief Client configuration details
+ *
+ * These are computed on the server and sent to clients as part of
+ * the initial handshaking.
+ */
+ struct {
+ unsigned long hSAREA;
+ int SAREASize;
+ unsigned long hFrameBuffer;
+ int fbOrigin;
+ int fbSize;
+ int fbStride;
+ int virtualWidth;
+ int virtualHeight;
+ } shared;
+
+ /**
+ * \name From DRIInfoRec
+ */
+ /*@{*/
+ int drmFD; /**< \brief DRM device file descriptor */
+ struct _XF86DRISAREA *pSAREA;
+ unsigned int serverContext; /**< \brief DRM context only active on server */
+ /*@}*/
+
+
+ /**
+ * \name Driver private
+ *
+ * Populated by __driInitFBDev()
+ */
+ /*@{*/
+ void *driverPrivate;
+ void *driverClientMsg;
+ int driverClientMsgSize;
+ /*@}*/
+} DRIDriverContext;
+
+/**
+ * \brief Interface to the DRI driver.
+ *
+ * This structure is retrieved from the loadable driver by the \e
+ * __driDriver symbol to access the Mini GLX specific hardware
+ * initialization and take down routines.
+ */
+typedef struct DRIDriverRec {
+ /**
+ * \brief Get the list of supported gl context modes.
+ */
+ int (*initContextModes)( const DRIDriverContext *context,
+ int *numModes, const __GLcontextModes **modes );
+ /**
+ * \brief Validate the framebuffer device mode
+ */
+ int (*validateMode)( const DRIDriverContext *context );
+
+ /**
+ * \brief Examine mode returned by fbdev (may differ from the one
+ * requested), restore any hw regs clobbered by fbdev.
+ */
+ int (*postValidateMode)( const DRIDriverContext *context );
+
+ /**
+ * \brief Initialize the framebuffer device.
+ */
+ int (*initFBDev)( DRIDriverContext *context );
+
+ /**
+ * \brief Halt the framebuffer device.
+ */
+ void (*haltFBDev)( DRIDriverContext *context );
+
+
+ /**
+ * \brief Idle and shutdown hardware in preparation for a VT switch.
+ */
+ int (*shutdownHardware)( const DRIDriverContext *context );
+
+ /**
+ * \brief Restore hardware state after regaining the VT.
+ */
+ int (*restoreHardware)( const DRIDriverContext *context );
+
+ /**
+ * \brief Notify hardware driver of gain/loose focus. May be zero
+ * as this is of limited utility for most drivers.
+ */
+ void (*notifyFocus)( int have_focus );
+} DRIDriver;
+
+#endif /* _driver_H_ */
diff --git a/src/glx/mini/drm.h b/src/glx/mini/drm.h
new file mode 100644
index 0000000000..4180d1eb1a
--- /dev/null
+++ b/src/glx/mini/drm.h
@@ -0,0 +1,657 @@
+/**
+ * \file drm.h
+ * \brief Header for the Direct Rendering Manager
+ *
+ * This file defines the DRM device ioctls and the strucutre of respective user
+ * arguments.
+ *
+ * \sa xf86drm.h and xf86drm.c for an user-friendlier interface.
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ * \par Acknowledgements:
+ * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic \c cmpxchg.
+ */
+
+/*
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, 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 AND/OR ITS SUPPLIERS 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.
+ */
+
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#if defined(__linux__)
+#include <linux/config.h>
+#include <asm/ioctl.h> /* For _IO* macros */
+#define DRM_IOCTL_NR(n) _IOC_NR(n)
+#define DRM_IOC_VOID _IOC_NONE
+#define DRM_IOC_READ _IOC_READ
+#define DRM_IOC_WRITE _IOC_WRITE
+#define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE
+#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) && defined(XFree86Server)
+/* Prevent name collision when including sys/ioccom.h */
+#undef ioctl
+#include <sys/ioccom.h>
+#define ioctl(a,b,c) xf86ioctl(a,b,c)
+#else
+#include <sys/ioccom.h>
+#endif /* __FreeBSD__ && xf86ioctl */
+#define DRM_IOCTL_NR(n) ((n) & 0xff)
+#define DRM_IOC_VOID IOC_VOID
+#define DRM_IOC_READ IOC_OUT
+#define DRM_IOC_WRITE IOC_IN
+#define DRM_IOC_READWRITE IOC_INOUT
+#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
+#endif
+
+#define XFREE86_VERSION(major,minor,patch,snap) \
+ ((major << 16) | (minor << 8) | patch)
+
+#ifndef CONFIG_XFREE86_VERSION
+#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0)
+#endif
+
+#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
+#define DRM_PROC_DEVICES "/proc/devices"
+#define DRM_PROC_MISC "/proc/misc"
+#define DRM_PROC_DRM "/proc/drm"
+#define DRM_DEV_DRM "/dev/drm"
+#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+#define DRM_DEV_UID 0
+#define DRM_DEV_GID 0
+#endif
+
+#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
+#define DRM_MAJOR 226
+#define DRM_MAX_MINOR 15
+#endif
+#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */
+#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */
+#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */
+#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */
+
+#define _DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */
+#define _DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */
+#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+
+typedef unsigned long drm_handle_t;
+typedef unsigned int drm_context_t;
+typedef unsigned int drm_drawable_t;
+typedef unsigned int drm_magic_t;
+
+
+/**
+ * Cliprect.
+ *
+ * \warning: If you change this structure, make sure you change
+ * XF86DRIClipRectRec in the server as well
+ *
+ * \note KW: Actually it's illegal to change either for
+ * backwards-compatibility reasons.
+ */
+typedef struct drm_clip_rect {
+ unsigned short x1;
+ unsigned short y1;
+ unsigned short x2;
+ unsigned short y2;
+} drm_clip_rect_t;
+
+
+/**
+ * Texture region,
+ */
+typedef struct drm_tex_region {
+ unsigned char next;
+ unsigned char prev;
+ unsigned char in_use;
+ unsigned char padding;
+ unsigned int age;
+} drm_tex_region_t;
+
+
+/**
+ * \brief DRM_IOCTL_VERSION ioctl argument type.
+ *
+ * \sa drmGetVersion().
+ */
+typedef struct drm_version {
+ int version_major; /**< Major version */
+ int version_minor; /**< Minor version */
+ int version_patchlevel;/**< Patch level */
+ size_t name_len; /**< Length of name buffer */
+ char *name; /**< Name of driver */
+ size_t date_len; /**< Length of date buffer */
+ char *date; /**< User-space buffer to hold date */
+ size_t desc_len; /**< Length of desc buffer */
+ char *desc; /**< User-space buffer to hold desc */
+} drm_version_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_UNIQUE ioctl argument type.
+ *
+ * \sa drmGetBusid() and drmSetBusId().
+ */
+typedef struct drm_unique {
+ size_t unique_len; /**< Length of unique */
+ char *unique; /**< Unique name for driver instantiation */
+} drm_unique_t;
+
+
+typedef struct drm_list {
+ int count; /**< Length of user-space structures */
+ drm_version_t *version;
+} drm_list_t;
+
+
+typedef struct drm_block {
+ int unused;
+} drm_block_t;
+
+
+/**
+ * \brief DRM_IOCTL_CONTROL ioctl argument type.
+ *
+ * \sa drmCtlInstHandler() and drmCtlUninstHandler().
+ */
+typedef struct drm_control {
+ enum {
+ DRM_ADD_COMMAND,
+ DRM_RM_COMMAND,
+ DRM_INST_HANDLER,
+ DRM_UNINST_HANDLER
+ } func;
+ int irq;
+} drm_control_t;
+
+
+/**
+ * \brief Type of memory to map.
+ */
+typedef enum drm_map_type {
+ _DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */
+ _DRM_REGISTERS = 1, /**< no caching, no core dump */
+ _DRM_SHM = 2, /**< shared, cached */
+ _DRM_AGP = 3, /**< AGP/GART */
+ _DRM_SCATTER_GATHER = 4 /**< Scatter/gather memory for PCI DMA */
+} drm_map_type_t;
+
+
+/**
+ * \brief Memory mapping flags.
+ */
+typedef enum drm_map_flags {
+ _DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */
+ _DRM_READ_ONLY = 0x02,
+ _DRM_LOCKED = 0x04, /**< shared, cached, locked */
+ _DRM_KERNEL = 0x08, /**< kernel requires access */
+ _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
+ _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */
+ _DRM_REMOVABLE = 0x40 /**< Removable mapping */
+} drm_map_flags_t;
+
+
+typedef struct drm_ctx_priv_map {
+ unsigned int ctx_id; /**< Context requesting private mapping */
+ void *handle; /**< Handle of map */
+} drm_ctx_priv_map_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls
+ * argument type.
+ *
+ * \sa drmAddMap().
+ */
+typedef struct drm_map {
+ unsigned long offset; /**< Requested physical address (0 for SAREA)*/
+ unsigned long size; /**< Requested physical size (bytes) */
+ drm_map_type_t type; /**< Type of memory to map */
+ drm_map_flags_t flags; /**< Flags */
+ void *handle; /**< User-space: "Handle" to pass to mmap() */
+ /**< Kernel-space: kernel-virtual address */
+ int mtrr; /**< MTRR slot used */
+ /* Private data */
+} drm_map_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_CLIENT ioctl argument type.
+ */
+typedef struct drm_client {
+ int idx; /**< Which client desired? */
+ int auth; /**< Is client authenticated? */
+ unsigned long pid; /**< Process ID */
+ unsigned long uid; /**< User ID */
+ unsigned long magic; /**< Magic */
+ unsigned long iocs; /**< Ioctl count */
+} drm_client_t;
+
+
+typedef enum {
+ _DRM_STAT_LOCK,
+ _DRM_STAT_OPENS,
+ _DRM_STAT_CLOSES,
+ _DRM_STAT_IOCTLS,
+ _DRM_STAT_LOCKS,
+ _DRM_STAT_UNLOCKS,
+ _DRM_STAT_VALUE, /**< Generic value */
+ _DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */
+ _DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */
+
+ _DRM_STAT_IRQ, /**< IRQ */
+ _DRM_STAT_PRIMARY, /**< Primary DMA bytes */
+ _DRM_STAT_SECONDARY, /**< Secondary DMA bytes */
+ _DRM_STAT_DMA, /**< DMA */
+ _DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */
+ _DRM_STAT_MISSED /**< Missed DMA opportunity */
+
+ /* Add to the *END* of the list */
+} drm_stat_type_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_STATS ioctl argument type.
+ */
+typedef struct drm_stats {
+ unsigned long count;
+ struct {
+ unsigned long value;
+ drm_stat_type_t type;
+ } data[15];
+} drm_stats_t;
+
+
+/**
+ * \brief Hardware locking flags.
+ */
+typedef enum drm_lock_flags {
+ _DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */
+ _DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */
+ _DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */
+ _DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */
+ /* These *HALT* flags aren't supported yet
+ -- they will be used to support the
+ full-screen DGA-like mode. */
+ _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */
+ _DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */
+} drm_lock_flags_t;
+
+
+/**
+ * \brief DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type.
+ *
+ * \sa drmGetLock() and drmUnlock().
+ */
+typedef struct drm_lock {
+ int context;
+ drm_lock_flags_t flags;
+} drm_lock_t;
+
+
+/**
+ * \brief DMA flags
+ *
+ * \warning
+ * These values \e must match xf86drm.h.
+ *
+ * \sa drm_dma.
+ */
+typedef enum drm_dma_flags {
+ /* Flags for DMA buffer dispatch */
+ _DRM_DMA_BLOCK = 0x01, /**<
+ * Block until buffer dispatched.
+ *
+ * \note The buffer may not yet have
+ * been processed by the hardware --
+ * getting a hardware lock with the
+ * hardware quiescent will ensure
+ * that the buffer has been
+ * processed.
+ */
+ _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */
+ _DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */
+
+ /* Flags for DMA buffer request */
+ _DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */
+ _DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */
+ _DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */
+} drm_dma_flags_t;
+
+
+/**
+ * \brief DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type.
+ *
+ * \sa drmAddBufs().
+ */
+typedef struct drm_buf_desc {
+ int count; /**< Number of buffers of this size */
+ int size; /**< Size in bytes */
+ int low_mark; /**< Low water mark */
+ int high_mark; /**< High water mark */
+ enum {
+ _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
+ _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
+ _DRM_SG_BUFFER = 0x04 /**< Scatter/gather memory buffer */
+ } flags;
+ unsigned long agp_start; /**<
+ * Start address of where the AGP buffers are
+ * in the AGP aperture
+ */
+} drm_buf_desc_t;
+
+
+/**
+ * \brief DRM_IOCTL_INFO_BUFS ioctl argument type.
+ */
+typedef struct drm_buf_info {
+ int count; /**< Entries in list */
+ drm_buf_desc_t *list;
+} drm_buf_info_t;
+
+
+/**
+ * \brief DRM_IOCTL_FREE_BUFS ioctl argument type.
+ */
+typedef struct drm_buf_free {
+ int count;
+ int *list;
+} drm_buf_free_t;
+
+
+/**
+ * \brief Buffer information
+ *
+ * \sa drm_buf_map.
+ */
+typedef struct drm_buf_pub {
+ int idx; /**< Index into the master buffer list */
+ int total; /**< Buffer size */
+ int used; /**< Amount of buffer in use (for DMA) */
+ void *address; /**< Address of buffer */
+} drm_buf_pub_t;
+
+
+/**
+ * \brief DRM_IOCTL_MAP_BUFS ioctl argument type.
+ */
+typedef struct drm_buf_map {
+ int count; /**< Length of the buffer list */
+ void *virtual; /**< Mmap'd area in user-virtual */
+ drm_buf_pub_t *list; /**< Buffer information */
+} drm_buf_map_t;
+
+
+/**
+ * \brief DRM_IOCTL_DMA ioctl argument type.
+ *
+ * Indices here refer to the offset into the buffer list in drm_buf_get.
+ *
+ * \sa drmDMA().
+ */
+typedef struct drm_dma {
+ int context; /**< Context handle */
+ int send_count; /**< Number of buffers to send */
+ int *send_indices; /**< List of handles to buffers */
+ int *send_sizes; /**< Lengths of data to send */
+ drm_dma_flags_t flags; /**< Flags */
+ int request_count; /**< Number of buffers requested */
+ int request_size; /**< Desired size for buffers */
+ int *request_indices; /**< Buffer information */
+ int *request_sizes;
+ int granted_count; /**< Number of buffers granted */
+} drm_dma_t;
+
+
+typedef enum {
+ _DRM_CONTEXT_PRESERVED = 0x01,
+ _DRM_CONTEXT_2DONLY = 0x02
+} drm_ctx_flags_t;
+
+
+/**
+ * \brief DRM_IOCTL_ADD_CTX ioctl argument type.
+ *
+ * \sa drmCreateContext() and drmDestroyContext().
+ */
+typedef struct drm_ctx {
+ drm_context_t handle;
+ drm_ctx_flags_t flags;
+} drm_ctx_t;
+
+
+/**
+ * \brief DRM_IOCTL_RES_CTX ioctl argument type.
+ */
+typedef struct drm_ctx_res {
+ int count;
+ drm_ctx_t *contexts;
+} drm_ctx_res_t;
+
+
+/**
+ * \brief DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type.
+ */
+typedef struct drm_draw {
+ drm_drawable_t handle;
+} drm_draw_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
+ */
+typedef struct drm_auth {
+ drm_magic_t magic;
+} drm_auth_t;
+
+
+/**
+ * \brief DRM_IOCTL_IRQ_BUSID ioctl argument type.
+ *
+ * \sa drmGetInterruptFromBusID().
+ */
+typedef struct drm_irq_busid {
+ int irq; /**< IRQ number */
+ int busnum; /**< bus number */
+ int devnum; /**< device number */
+ int funcnum; /**< function number */
+} drm_irq_busid_t;
+
+
+typedef enum {
+ _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
+ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
+ _DRM_VBLANK_SIGNAL = 0x8000 /**< Send signal instead of blocking */
+} drm_vblank_seq_type_t;
+
+
+#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
+
+
+struct drm_wait_vblank_request {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ unsigned long signal;
+};
+
+
+struct drm_wait_vblank_reply {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+};
+
+
+/**
+ * \brief DRM_IOCTL_WAIT_VBLANK ioctl argument type.
+ *
+ * \sa drmWaitVBlank().
+ */
+typedef union drm_wait_vblank {
+ struct drm_wait_vblank_request request;
+ struct drm_wait_vblank_reply reply;
+} drm_wait_vblank_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_ENABLE ioctl argument type.
+ *
+ * \sa drmAgpEnable().
+ */
+typedef struct drm_agp_mode {
+ unsigned long mode; /**< AGP mode */
+} drm_agp_mode_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type.
+ *
+ * \sa drmAgpAlloc() and drmAgpFree().
+ */
+typedef struct drm_agp_buffer {
+ unsigned long size; /**< In bytes -- will round to page boundary */
+ unsigned long handle; /**< Used for binding / unbinding */
+ unsigned long type; /**< Type of memory to allocate */
+ unsigned long physical; /**< Physical used by i810 */
+} drm_agp_buffer_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type.
+ *
+ * \sa drmAgpBind() and drmAgpUnbind().
+ */
+typedef struct drm_agp_binding {
+ unsigned long handle; /**< From drm_agp_buffer */
+ unsigned long offset; /**< In bytes -- will round to page boundary */
+} drm_agp_binding_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_INFO ioctl argument type.
+ *
+ * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(),
+ * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(),
+ * drmAgpVendorId() and drmAgpDeviceId().
+ */
+typedef struct drm_agp_info {
+ int agp_version_major;
+ int agp_version_minor;
+ unsigned long mode;
+ unsigned long aperture_base; /* physical address */
+ unsigned long aperture_size; /* bytes */
+ unsigned long memory_allowed; /* bytes */
+ unsigned long memory_used;
+
+ /* PCI information */
+ unsigned short id_vendor;
+ unsigned short id_device;
+} drm_agp_info_t;
+
+
+/**
+ * \brief DRM_IOCTL_SG_ALLOC ioctl argument type.
+ */
+typedef struct drm_scatter_gather {
+ unsigned long size; /**< In bytes -- will round to page boundary */
+ unsigned long handle; /**< Used for mapping / unmapping */
+} drm_scatter_gather_t;
+
+
+#define DRM_IOCTL_BASE 'd'
+#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
+
+#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t)
+#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
+#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t)
+#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t)
+#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t)
+#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t)
+#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t)
+
+#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
+#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t)
+#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t)
+#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t)
+#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t)
+#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t)
+#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t)
+#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t)
+#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t)
+#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t)
+#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t)
+
+#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, drm_map_t)
+
+#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, drm_ctx_priv_map_t)
+#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, drm_ctx_priv_map_t)
+
+#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t)
+#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t)
+#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t)
+#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t)
+#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t)
+#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t)
+#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t)
+#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t)
+#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t)
+#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t)
+#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t)
+#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t)
+#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t)
+
+#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
+#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
+#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t)
+#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t)
+#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t)
+#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t)
+
+#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
+#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t)
+
+#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+
+/**
+ * Device specific ioctls should only be in their respective headers
+ * The device specific ioctl range is from 0x40 to 0x79.
+ *
+ * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
+ * drmCommandReadWrite().
+ */
+#define DRM_COMMAND_BASE 0x40
+
+#endif
diff --git a/src/glx/mini/drmtest.c b/src/glx/mini/drmtest.c
new file mode 100644
index 0000000000..f9cad3994e
--- /dev/null
+++ b/src/glx/mini/drmtest.c
@@ -0,0 +1,140 @@
+#include <assert.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include "xf86drm.h"
+
+char *pciBusID = "PCI:1:0:0";
+#define DRM_PAGE_SIZE 4096
+void *pSAREA;
+
+
+static int client( void )
+{
+ int fd, ret, err;
+ drmContext clientContext;
+
+ fprintf(stderr, "Opening client drm\n");
+
+ fd = drmOpen(NULL,pciBusID);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open DRM: %s\n", strerror(-fd));
+ return 1;
+ }
+
+
+ fprintf(stderr, "Create server context\n");
+ if ((err = drmCreateContext(fd, &clientContext)) != 0) {
+ fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+
+ fprintf(stderr, "DRM_LOCK( %d %p %d )\n", fd, pSAREA, clientContext);
+ DRM_LOCK(fd, pSAREA, clientContext, 0);
+ fprintf(stderr, "locked\n");
+ DRM_UNLOCK(fd, pSAREA, clientContext);
+ fprintf(stderr, "DRM_UNLOCK finished\n");
+
+
+ fprintf(stderr, "Closing client drm: %d\n", fd);
+ ret = drmClose(fd);
+ fprintf(stderr, "done %d\n", ret);
+
+ return ret;
+}
+
+int main( int argc, char *argv[] )
+{
+ char *drmModuleName = "radeon";
+ int drmFD;
+ int err;
+ int SAREASize;
+ drmHandle hSAREA;
+ drmContext serverContext;
+
+ /* Note that drmOpen will try to load the kernel module, if needed. */
+ drmFD = drmOpen(drmModuleName, NULL );
+ if (drmFD < 0) {
+ /* failed to open DRM */
+ fprintf(stderr, "[drm] drmOpen failed\n");
+ return 0;
+ }
+
+
+ if ((err = drmSetBusid(drmFD, pciBusID)) < 0) {
+ drmClose(drmFD);
+ fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n",
+ drmFD, pciBusID, strerror(-err));
+ return 0;
+ }
+
+
+ SAREASize = DRM_PAGE_SIZE;
+
+ if (drmAddMap( drmFD,
+ 0,
+ SAREASize,
+ DRM_SHM,
+ DRM_CONTAINS_LOCK,
+ &hSAREA) < 0)
+ {
+ drmClose(drmFD);
+ fprintf(stderr, "[drm] drmAddMap failed\n");
+ return 0;
+ }
+
+ fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n",
+ SAREASize, hSAREA);
+
+ if (drmMap( drmFD,
+ hSAREA,
+ SAREASize,
+ (drmAddressPtr)(&pSAREA)) < 0)
+ {
+ drmClose(drmFD);
+ fprintf(stderr, "[drm] drmMap failed\n");
+ return 0;
+ }
+
+ memset(pSAREA, 0, SAREASize);
+ fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
+ hSAREA, pSAREA, SAREASize);
+
+ fprintf(stderr, "Create server context\n");
+ if ((err = drmCreateContext(drmFD, &serverContext)) != 0) {
+ fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+
+ fprintf(stderr, "DRM_LOCK( %d %p %d )\n", drmFD, pSAREA, serverContext);
+ DRM_LOCK(drmFD, pSAREA, serverContext, 0);
+ fprintf(stderr, "locked\n");
+ DRM_UNLOCK(drmFD, pSAREA, serverContext);
+ fprintf(stderr, "DRM_UNLOCK finished\n");
+
+
+ client();
+
+
+ fprintf(stderr, "DRM_LOCK( %d %p %d )\n", drmFD, pSAREA, serverContext);
+ DRM_LOCK(drmFD, pSAREA, serverContext, 0);
+ fprintf(stderr, "locked\n");
+ DRM_UNLOCK(drmFD, pSAREA, serverContext);
+ fprintf(stderr, "DRM_UNLOCK finished\n");
+
+
+ drmUnmap(pSAREA, SAREASize);
+ fprintf(stderr, "[drm] unmapped SAREA 0x%08lx from %p, size %d\n",
+ hSAREA, pSAREA, SAREASize);
+ pSAREA = 0;
+
+ fprintf(stderr, "%s: Closing DRM fd\n", __FUNCTION__);
+ (void)drmClose(drmFD);
+
+ return 0;
+}
+
+
+
diff --git a/src/glx/mini/example.miniglx.conf b/src/glx/mini/example.miniglx.conf
new file mode 100644
index 0000000000..06adbffcf3
--- /dev/null
+++ b/src/glx/mini/example.miniglx.conf
@@ -0,0 +1,26 @@
+# Example miniglx configuration file (/etc/miniglx.conf)
+#
+
+# Framebuffer device to open: Might need to change this on dual-head
+# systems.
+fbdevDevice=/dev/fb0
+
+# Which driver?
+# radeon_dri.so -- HW accelerated radeon driver
+# fb_dri.so -- Software rasterizer
+clientDriverName=radeon_dri.so
+
+# The pci bus id of the video card. Find this with scanpci, lspci or
+# look in /proc/pci.
+pciBusID=PCI:1:0:0
+
+# Virtual screen dimensions. Can reduce this to save videocard memory
+# at the expense of maximum window size available.
+virtualWidth=1280
+virtualHeight=1024
+
+# Screen depth. Only 16 & 32bpp supported.
+bpp=32
+
+# Rotated monitor? -- NOTE: only works with subsetted radeon driver!
+rotateMode=0
diff --git a/src/glx/mini/miniglx.c b/src/glx/mini/miniglx.c
new file mode 100644
index 0000000000..25c7b96362
--- /dev/null
+++ b/src/glx/mini/miniglx.c
@@ -0,0 +1,1975 @@
+/**
+ * \file miniglx.c
+ * \brief Mini GLX interface functions.
+ * \author Brian Paul
+ *
+ * The Mini GLX interface is a subset of the GLX interface, plus a
+ * minimal set of Xlib functions.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.0
+ *
+ * Copyright (C) 1999-2003 Brian Paul 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 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
+ * BRIAN PAUL 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.
+ */
+
+/* $Id: miniglx.c,v 1.1 2003/08/22 20:11:43 brianp Exp $ */
+
+/**
+ * \mainpage Mini GLX
+ *
+ * \section miniglxIntro Introduction
+ *
+ * The Mini GLX interface facilitates OpenGL rendering on embedded devices. The
+ * interface is a subset of the GLX interface, plus a minimal set of Xlib-like
+ * functions.
+ *
+ * Programs written to the Mini GLX specification should run unchanged
+ * on systems with the X Window System and the GLX extension (after
+ * recompilation). The intention is to allow flexibility for
+ * prototyping and testing.
+ *
+ * The files in the src/miniglx/ directory are compiled to build the
+ * libGL.so library. This is the library which applications link with.
+ * libGL.so in turn, loads the hardware-specific device driver.
+ *
+ *
+ * \section miniglxDoxygen About Doxygen
+ *
+ * For a list of all files, select <b>File List</b>. Choose a file from
+ * the list for a list of all functions in the file.
+ *
+ * For a list of all functions, types, constants, etc.
+ * select <b>File Members</b>.
+ *
+ *
+ * \section miniglxReferences References
+ *
+ * - <A HREF="file:../../docs/MiniGLX.html">Mini GLX Specification</A>,
+ * Tungsten Graphics, Inc.
+ * - OpenGL Graphics with the X Window System, Silicon Graphics, Inc.,
+ * ftp://ftp.sgi.com/opengl/doc/opengl1.2/glx1.3.ps
+ * - Xlib - C Language X Interface, X Consortium Standard, X Version 11,
+ * Release 6.4, ftp://ftp.x.org/pub/R6.4/xc/doc/hardcopy/X11/xlib.PS.gz
+ * - XFree86 Man pages, The XFree86 Project, Inc.,
+ * http://www.xfree86.org/current/manindex3.html
+ *
+ */
+
+/**
+ * \page datatypes Notes on the XVisualInfo, Visual, and __GLXvisualConfig data types
+ *
+ * -# X (unfortunately) has two (or three) data types which
+ * describe visuals. Ideally, there would just be one.
+ * -# We need the #__GLXvisualConfig type to augment #XVisualInfo and #Visual
+ * because we need to describe the GLX-specific attributes of visuals.
+ * -# In this interface there is a one-to-one-to-one correspondence between
+ * the three types and they're all interconnected.
+ * -# The #XVisualInfo type has a pointer to a #Visual. The #Visual structure
+ * (aka MiniGLXVisualRec) has a pointer to the #__GLXvisualConfig. The
+ * #Visual structure also has a pointer pointing back to the #XVisualInfo.
+ * -# The #XVisualInfo structure is the only one who's contents are public.
+ * -# The glXChooseVisual() and XGetVisualInfo() are the only functions that
+ * return #XVisualInfo structures. They can be freed with XFree(), though
+ * there is a small memory leak.
+ */
+
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+
+#include "miniglxP.h"
+#include "dri.h"
+
+#include "glapi.h"
+#include "xf86drm.h"
+
+
+/**
+ * \brief Current GLX context.
+ *
+ * \sa glXGetCurrentContext().
+ */
+static GLXContext CurrentContext = NULL;
+
+
+
+static Display *SignalDisplay = 0;
+
+static void SwitchVT(int sig)
+{
+ fprintf(stderr, "SwitchVT %d dpy %p\n", sig, SignalDisplay);
+
+ if (SignalDisplay) {
+ SignalDisplay->vtSignalFlag = 1;
+ switch( sig )
+ {
+ case SIGUSR1: /* vt has been released */
+ SignalDisplay->haveVT = 0;
+ break;
+ case SIGUSR2: /* vt has been acquired */
+ SignalDisplay->haveVT = 1;
+ break;
+ }
+ }
+}
+
+/**********************************************************************/
+/** \name Framebuffer device functions */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * \brief Do the first part of setting up the framebuffer device.
+ *
+ * \param dpy the display handle.
+ * \param use_vt use a VT for display or not
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa This is called during XOpenDisplay().
+ *
+ * \internal
+ * Gets the VT number, opens the respective console TTY device. Saves its state
+ * to restore when exiting and goes into graphics mode.
+ *
+ * Opens the framebuffer device and make a copy of the original variable screen
+ * information and gets the fixed screen information. Maps the framebuffer and
+ * MMIO region into the process address space.
+ */
+static GLboolean
+OpenFBDev( Display *dpy, int use_vt )
+{
+ char ttystr[1000];
+ int fd, vtnumber, ttyfd;
+
+ assert(dpy);
+
+ if (geteuid()) {
+ fprintf(stderr, "error: you need to be root\n");
+ return GL_FALSE;
+ }
+
+ if (use_vt) {
+
+ /* open /dev/tty0 and get the VT number */
+ if ((fd = open("/dev/tty0", O_WRONLY, 0)) < 0) {
+ fprintf(stderr, "error opening /dev/tty0\n");
+ return GL_FALSE;
+ }
+ if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
+ fprintf(stderr, "error: couldn't get a free vt\n");
+ return GL_FALSE;
+ }
+
+ fprintf(stderr, "*** got vt nr: %d\n", vtnumber);
+ close(fd);
+
+ /* open the console tty */
+ sprintf(ttystr, "/dev/tty%d", vtnumber); /* /dev/tty1-64 */
+ dpy->ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0);
+ if (dpy->ConsoleFD < 0) {
+ fprintf(stderr, "error couldn't open console fd\n");
+ return GL_FALSE;
+ }
+
+ /* save current vt number */
+ {
+ struct vt_stat vts;
+ if (ioctl(dpy->ConsoleFD, VT_GETSTATE, &vts) == 0)
+ dpy->OriginalVT = vts.v_active;
+ }
+
+ /* disconnect from controlling tty */
+ ttyfd = open("/dev/tty", O_RDWR);
+ if (ttyfd >= 0) {
+ ioctl(ttyfd, TIOCNOTTY, 0);
+ close(ttyfd);
+ }
+
+ /* some magic to restore the vt when we exit */
+ {
+ struct vt_mode vt;
+ struct sigaction sig_tty;
+
+ /* Set-up tty signal handler to catch the signal we request below */
+ SignalDisplay = dpy;
+ memset( &sig_tty, 0, sizeof( sig_tty ) );
+ sig_tty.sa_handler = SwitchVT;
+ sigemptyset( &sig_tty.sa_mask );
+ if( sigaction( SIGUSR1, &sig_tty, &dpy->OrigSigUsr1 ) ||
+ sigaction( SIGUSR2, &sig_tty, &dpy->OrigSigUsr2 ) )
+ {
+ fprintf(stderr, "error: can't set up signal handler (%s)",
+ strerror(errno) );
+ return GL_FALSE;
+ }
+
+
+
+ vt.mode = VT_PROCESS;
+ vt.waitv = 0;
+ vt.relsig = SIGUSR1;
+ vt.acqsig = SIGUSR2;
+ if (ioctl(dpy->ConsoleFD, VT_SETMODE, &vt) < 0) {
+ fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+ if (ioctl(dpy->ConsoleFD, VT_ACTIVATE, vtnumber) != 0)
+ printf("ioctl VT_ACTIVATE: %s\n", strerror(errno));
+ if (ioctl(dpy->ConsoleFD, VT_WAITACTIVE, vtnumber) != 0)
+ printf("ioctl VT_WAITACTIVE: %s\n", strerror(errno));
+
+ if (ioctl(dpy->ConsoleFD, VT_GETMODE, &vt) < 0) {
+ fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno));
+ return GL_FALSE;
+ }
+
+
+
+ }
+
+ /* go into graphics mode */
+ if (ioctl(dpy->ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) {
+ fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+ }
+
+ /* open the framebuffer device */
+ dpy->FrameBufferFD = open(dpy->fbdevDevice, O_RDWR);
+ if (dpy->FrameBufferFD < 0) {
+ fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* get the original variable screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->OrigVarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* make copy */
+ dpy->VarInfo = dpy->OrigVarInfo; /* structure copy */
+
+ /* Turn off hw accels (otherwise mmap of mmio region will be
+ * refused)
+ */
+ dpy->VarInfo.accel_flags = 0;
+ if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+
+ /* Get the fixed screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+
+ /* mmap the framebuffer into our address space */
+ dpy->driverContext.FBStart = dpy->FixedInfo.smem_start;
+ dpy->driverContext.FBSize = dpy->FixedInfo.smem_len;
+ dpy->driverContext.shared.fbSize = dpy->FixedInfo.smem_len;
+ dpy->driverContext.FBAddress = (caddr_t) mmap(0, /* start */
+ dpy->driverContext.shared.fbSize, /* bytes */
+ PROT_READ | PROT_WRITE, /* prot */
+ MAP_SHARED, /* flags */
+ dpy->FrameBufferFD, /* fd */
+ 0 /* offset */);
+ if (dpy->driverContext.FBAddress == (caddr_t) - 1) {
+ fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* mmap the MMIO region into our address space */
+ dpy->driverContext.MMIOStart = dpy->FixedInfo.mmio_start;
+ dpy->driverContext.MMIOSize = dpy->FixedInfo.mmio_len;
+ dpy->driverContext.MMIOAddress = (caddr_t) mmap(0, /* start */
+ dpy->driverContext.MMIOSize, /* bytes */
+ PROT_READ | PROT_WRITE, /* prot */
+ MAP_SHARED, /* flags */
+ dpy->FrameBufferFD, /* fd */
+ dpy->FixedInfo.smem_len /* offset */);
+ if (dpy->driverContext.MMIOAddress == (caddr_t) - 1) {
+ fprintf(stderr, "error: unable to mmap mmio region: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ fprintf(stderr, "got MMIOAddress %p offset %d\n",
+ dpy->driverContext.MMIOAddress,
+ dpy->FixedInfo.smem_len);
+
+ return GL_TRUE;
+}
+
+
+
+
+/**
+ * \brief Setup up the desired framebuffer device mode.
+ *
+ * \param dpy the display handle.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa This is called during __miniglx_StartServer().
+ *
+ * \internal
+ *
+ * Bumps the size of the window the the next supported mode. Sets the
+ * variable screen information according to the desired mode and asks
+ * the driver to validate the mode. Certifies that a DirectColor or
+ * TrueColor visual is used from the updated fixed screen information.
+ * In the case of DirectColor visuals, sets up an 'identity' colormap to
+ * mimic a TrueColor visual.
+ *
+ * Calls the driver hooks 'ValidateMode' and 'PostValidateMode' to
+ * allow the driver to make modifications to the chosen mode according
+ * to hardware constraints, or to save and restore videocard registers
+ * that may be clobbered by the fbdev driver.
+ *
+ * \todo Timings are hard-coded in the source for a set of supported modes.
+ */
+static GLboolean
+SetupFBDev( Display *dpy )
+{
+ int width, height;
+
+ assert(dpy);
+
+ width = dpy->driverContext.shared.virtualWidth;
+ height = dpy->driverContext.shared.virtualHeight;
+
+ /* Bump size up to next supported mode.
+ */
+ if (width <= 800 && height <= 600) {
+ width = 800; height = 600;
+ }
+ else if (width <= 1024 && height <= 768) {
+ width = 1024; height = 768;
+ }
+ else if (width <= 768 && height <= 1024) {
+ width = 768; height = 1024;
+ }
+ else if (width <= 1280 && height <= 1024) {
+ width = 1280; height = 1024;
+ }
+
+
+ dpy->driverContext.shared.virtualHeight = height;
+ dpy->driverContext.shared.virtualWidth = width;
+ dpy->driverContext.shared.fbStride = width * (dpy->driverContext.bpp / 8);
+
+ /* set the depth, resolution, etc */
+ dpy->VarInfo = dpy->OrigVarInfo;
+ dpy->VarInfo.bits_per_pixel = dpy->driverContext.bpp;
+ dpy->VarInfo.xres_virtual = dpy->driverContext.shared.virtualWidth;
+ dpy->VarInfo.yres_virtual = dpy->driverContext.shared.virtualHeight;
+ dpy->VarInfo.xres = width;
+ dpy->VarInfo.yres = height;
+ dpy->VarInfo.xoffset = 0;
+ dpy->VarInfo.yoffset = 0;
+ dpy->VarInfo.nonstd = 0;
+ dpy->VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
+
+ if (dpy->VarInfo.bits_per_pixel == 32) {
+ dpy->VarInfo.red.offset = 16;
+ dpy->VarInfo.green.offset = 8;
+ dpy->VarInfo.blue.offset = 0;
+ dpy->VarInfo.transp.offset = 24;
+ dpy->VarInfo.red.length = 8;
+ dpy->VarInfo.green.length = 8;
+ dpy->VarInfo.blue.length = 8;
+ dpy->VarInfo.transp.length = 8;
+ }
+ else if (dpy->VarInfo.bits_per_pixel == 16) {
+ dpy->VarInfo.red.offset = 11;
+ dpy->VarInfo.green.offset = 5;
+ dpy->VarInfo.blue.offset = 0;
+ dpy->VarInfo.red.length = 5;
+ dpy->VarInfo.green.length = 6;
+ dpy->VarInfo.blue.length = 5;
+ dpy->VarInfo.transp.offset = 0;
+ dpy->VarInfo.transp.length = 0;
+ }
+ else {
+ fprintf(stderr, "Only 32bpp and 16bpp modes supported at the moment\n");
+ return 0;
+ }
+
+ if (!dpy->driver->validateMode( &dpy->driverContext )) {
+ fprintf(stderr, "Driver validateMode() failed\n");
+ return 0;
+ }
+
+ if (dpy->VarInfo.xres == 1280 &&
+ dpy->VarInfo.yres == 1024) {
+ /* timing values taken from /etc/fb.modes (1280x1024 @ 75Hz) */
+ dpy->VarInfo.pixclock = 7408;
+ dpy->VarInfo.left_margin = 248;
+ dpy->VarInfo.right_margin = 16;
+ dpy->VarInfo.upper_margin = 38;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 144;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else if (dpy->VarInfo.xres == 1024 &&
+ dpy->VarInfo.yres == 768) {
+ /* timing values taken from /etc/fb.modes (1024x768 @ 75Hz) */
+ dpy->VarInfo.pixclock = 12699;
+ dpy->VarInfo.left_margin = 176;
+ dpy->VarInfo.right_margin = 16;
+ dpy->VarInfo.upper_margin = 28;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 96;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else if (dpy->VarInfo.xres == 800 &&
+ dpy->VarInfo.yres == 600) {
+ /* timing values taken from /etc/fb.modes (800x600 @ 75Hz) */
+ dpy->VarInfo.pixclock = 20203;
+ dpy->VarInfo.left_margin = 160;
+ dpy->VarInfo.right_margin = 16;
+ dpy->VarInfo.upper_margin = 21;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 80;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else if (dpy->VarInfo.xres == 768 &&
+ dpy->VarInfo.yres == 1024) {
+ /* timing values for 768x1024 @ 75Hz */
+ dpy->VarInfo.pixclock = 11993;
+ dpy->VarInfo.left_margin = 136;
+ dpy->VarInfo.right_margin = 32;
+ dpy->VarInfo.upper_margin = 41;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 80;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else {
+ /* XXX need timings for other screen sizes */
+ fprintf(stderr, "XXXX screen size %d x %d not supported at this time!\n",
+ dpy->VarInfo.xres, dpy->VarInfo.yres);
+ return GL_FALSE;
+ }
+
+ fprintf(stderr, "[miniglx] Setting mode: visible %dx%d virtual %dx%dx%d\n",
+ dpy->VarInfo.xres, dpy->VarInfo.yres,
+ dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
+ dpy->VarInfo.bits_per_pixel);
+
+ /* set variable screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* get the variable screen info, in case it has been modified */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->VarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+ fprintf(stderr, "[miniglx] Readback mode: visible %dx%d virtual %dx%dx%d\n",
+ dpy->VarInfo.xres, dpy->VarInfo.yres,
+ dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
+ dpy->VarInfo.bits_per_pixel);
+
+ /* Get the fixed screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ if (dpy->FixedInfo.visual != FB_VISUAL_TRUECOLOR &&
+ dpy->FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
+ fprintf(stderr, "non-TRUECOLOR visuals not supported.\n");
+ return GL_FALSE;
+ }
+
+ if (dpy->FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
+ struct fb_cmap cmap;
+ unsigned short red[256], green[256], blue[256];
+ int rcols = 1 << dpy->VarInfo.red.length;
+ int gcols = 1 << dpy->VarInfo.green.length;
+ int bcols = 1 << dpy->VarInfo.blue.length;
+ int i;
+
+ cmap.start = 0;
+ cmap.len = gcols;
+ cmap.red = red;
+ cmap.green = green;
+ cmap.blue = blue;
+ cmap.transp = NULL;
+
+ for (i = 0; i < rcols ; i++)
+ red[i] = (65536/(rcols-1)) * i;
+
+ for (i = 0; i < gcols ; i++)
+ green[i] = (65536/(gcols-1)) * i;
+
+ for (i = 0; i < bcols ; i++)
+ blue[i] = (65536/(bcols-1)) * i;
+
+ if (ioctl(dpy->FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) {
+ fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
+ exit(1);
+ }
+ }
+
+ /* May need to restore regs fbdev has clobbered:
+ */
+ if (!dpy->driver->postValidateMode( &dpy->driverContext )) {
+ fprintf(stderr, "Driver postValidateMode() failed\n");
+ return 0;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * \brief Restore the framebuffer device to state it was in before we started
+ *
+ * Undoes the work done by SetupFBDev().
+ *
+ * \param dpy the display handle.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa Called from XDestroyWindow().
+ *
+ * \internal
+ * Restores the original variable screen info.
+ */
+static GLboolean
+RestoreFBDev( Display *dpy )
+{
+ /* restore original variable screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->OrigVarInfo)) {
+ fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+ dpy->VarInfo = dpy->OrigVarInfo;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * \brief Close the framebuffer device.
+ *
+ * \param dpy the display handle.
+ *
+ * \sa Called from XCloseDisplay().
+ *
+ * \internal
+ * Unmaps the framebuffer and MMIO region. Restores the text mode and the
+ * original virtual terminal. Closes the console and framebuffer devices.
+ */
+static void
+CloseFBDev( Display *dpy )
+{
+ struct vt_mode VT;
+
+ munmap(dpy->driverContext.FBAddress, dpy->driverContext.FBSize);
+ munmap(dpy->driverContext.MMIOAddress, dpy->driverContext.MMIOSize);
+
+ if (dpy->ConsoleFD) {
+ /* restore text mode */
+ ioctl(dpy->ConsoleFD, KDSETMODE, KD_TEXT);
+
+ /* set vt */
+ if (ioctl(dpy->ConsoleFD, VT_GETMODE, &VT) != -1) {
+ VT.mode = VT_AUTO;
+ ioctl(dpy->ConsoleFD, VT_SETMODE, &VT);
+ }
+
+ /* restore original vt */
+ if (dpy->OriginalVT >= 0) {
+ ioctl(dpy->ConsoleFD, VT_ACTIVATE, dpy->OriginalVT);
+ dpy->OriginalVT = -1;
+ }
+
+ close(dpy->ConsoleFD);
+ }
+ close(dpy->FrameBufferFD);
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Misc functions needed for DRI drivers */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * \brief Find the DRI screen dependent methods associated with the display.
+ *
+ * \param dpy a display handle, as returned by XOpenDisplay().
+ * \param scrn the screen number. Not referenced.
+ *
+ * \returns a pointer to a __DRIscreenRec structure.
+ *
+ * \internal
+ * Returns the MiniGLXDisplayRec::driScreen attribute.
+ */
+__DRIscreen *
+__glXFindDRIScreen(Display *dpy, int scrn)
+{
+ (void) scrn;
+ return dpy->driScreen;
+}
+
+/**
+ * \brief Validate a drawable.
+ *
+ * \param dpy a display handle, as returned by XOpenDisplay().
+ * \param draw drawable to validate.
+ *
+ * \internal
+ * Since Mini GLX only supports one window, compares the specified drawable with
+ * the MiniGLXDisplayRec::TheWindow attribute.
+ */
+Bool
+__glXWindowExists(Display *dpy, GLXDrawable draw)
+{
+ if (dpy->TheWindow == draw)
+ return True;
+ else
+ return False;
+}
+
+/**
+ * \brief Get current thread ID.
+ *
+ * \return thread ID.
+ *
+ * \internal
+ * Always returns 0.
+ */
+/*unsigned long
+_glthread_GetID(void)
+{
+ return 0;
+}*/
+
+/*@}*/
+
+
+/**
+ * \brief Scan Linux /prog/bus/pci/devices file to determine hardware
+ * chipset based on supplied bus ID.
+ *
+ * \return probed chipset (non-zero) on success, zero otherwise.
+ *
+ * \internal
+ */
+static int get_chipset_from_busid( Display *dpy )
+{
+ char buf[0x200];
+ FILE *file;
+ const char *fname = "/proc/bus/pci/devices";
+ int retval = 0;
+
+ if (!(file = fopen(fname,"r"))) {
+ fprintf(stderr, "couldn't open %s: %s\n", fname, strerror(errno));
+ return 0;
+ }
+
+ while (fgets(buf, sizeof(buf)-1, file)) {
+ unsigned int nr, bus, dev, fn, vendor, device, encode;
+ nr = sscanf(buf, "%04x\t%04x%04x", &encode,
+ &vendor, &device);
+
+ bus = encode >> 16;
+ dev = (encode & 0xFF) >> 3;
+ fn = encode & 0x7;
+
+ if (nr != 3)
+ break;
+
+ if (bus == dpy->driverContext.pciBus &&
+ dev == dpy->driverContext.pciDevice &&
+ fn == dpy->driverContext.pciFunc) {
+ retval = device;
+ break;
+ }
+ }
+
+ fclose(file);
+
+ if (retval)
+ fprintf(stderr, "[miniglx] probed chipset 0x%x\n", retval);
+ else
+ fprintf(stderr, "[miniglx] failed to probe chipset\n");
+
+ return retval;
+}
+
+
+/**
+ * \brief Read settings from a configuration file.
+ *
+ * The configuration file is usually "/etc/miniglx.conf", but can be overridden
+ * with the MINIGLX_CONF environment variable.
+ *
+ * The format consists in \code option = value \endcode lines. The option names
+ * corresponds to the fields in MiniGLXDisplayRec.
+ *
+ * \param dpy the display handle as.
+ *
+ * \return non-zero on success, zero otherwise.
+ *
+ * \internal
+ * Sets some defaults. Opens and parses the the Mini GLX configuration file and
+ * fills in the MiniGLXDisplayRec field that corresponds for each option.
+ */
+static int __read_config_file( Display *dpy )
+{
+ FILE *file;
+ const char *fname;
+
+ /* Fallback/defaults
+ */
+ dpy->fbdevDevice = "/dev/fb0";
+ dpy->clientDriverName = "fb_dri.so";
+ dpy->driverContext.pciBus = 0;
+ dpy->driverContext.pciDevice = 0;
+ dpy->driverContext.pciFunc = 0;
+ dpy->driverContext.chipset = 0;
+ dpy->driverContext.pciBusID = 0;
+ dpy->driverContext.shared.virtualWidth = 1280;
+ dpy->driverContext.shared.virtualHeight = 1024;
+ dpy->driverContext.bpp = 32;
+ dpy->driverContext.cpp = 4;
+ dpy->rotateMode = 0;
+
+ fname = getenv("MINIGLX_CONF");
+ if (!fname) fname = "/etc/miniglx.conf";
+
+ file = fopen(fname, "r");
+ if (!file) {
+ fprintf(stderr, "couldn't open config file %s: %s\n", fname, strerror(errno));
+ return 0;
+ }
+
+
+ while (!feof(file)) {
+ char buf[81], *opt = buf, *val, *tmp1, *tmp2;
+ fgets(buf, sizeof(buf), file);
+
+ /* Parse 'opt = val' -- must be easier ways to do this.
+ */
+ while (isspace(*opt)) opt++;
+ val = opt;
+ if (*val == '#') continue; /* comment */
+ while (!isspace(*val) && *val != '=' && *val) val++;
+ tmp1 = val;
+ while (isspace(*val)) val++;
+ if (*val != '=') continue;
+ *tmp1 = 0;
+ val++;
+ while (isspace(*val)) val++;
+ tmp2 = val;
+ while (!isspace(*tmp2) && *tmp2 != '\n' && *tmp2) tmp2++;
+ *tmp2 = 0;
+
+
+ if (strcmp(opt, "fbdevDevice") == 0)
+ dpy->fbdevDevice = strdup(val);
+ else if (strcmp(opt, "clientDriverName") == 0)
+ dpy->clientDriverName = strdup(val);
+ else if (strcmp(opt, "rotateMode") == 0)
+ dpy->rotateMode = atoi(val) ? 1 : 0;
+ else if (strcmp(opt, "pciBusID") == 0) {
+ if (sscanf(val, "PCI:%d:%d:%d",
+ &dpy->driverContext.pciBus,
+ &dpy->driverContext.pciDevice,
+ &dpy->driverContext.pciFunc) != 3) {
+ fprintf(stderr, "malformed bus id: %s\n", val);
+ continue;
+ }
+ dpy->driverContext.pciBusID = strdup(val);
+ }
+ else if (strcmp(opt, "chipset") == 0) {
+ if (sscanf(val, "0x%x", &dpy->driverContext.chipset) != 1)
+ fprintf(stderr, "malformed chipset: %s\n", opt);
+ }
+ else if (strcmp(opt, "virtualWidth") == 0) {
+ if (sscanf(val, "%d", &dpy->driverContext.shared.virtualWidth) != 1)
+ fprintf(stderr, "malformed virtualWidth: %s\n", opt);
+ }
+ else if (strcmp(opt, "virtualHeight") == 0) {
+ if (sscanf(val, "%d", &dpy->driverContext.shared.virtualHeight) != 1)
+ fprintf(stderr, "malformed virutalHeight: %s\n", opt);
+ }
+ else if (strcmp(opt, "bpp") == 0) {
+ if (sscanf(val, "%d", &dpy->driverContext.bpp) != 1)
+ fprintf(stderr, "malformed bpp: %s\n", opt);
+ dpy->driverContext.cpp = dpy->driverContext.bpp / 8;
+ }
+ }
+
+ fclose(file);
+
+ if (dpy->driverContext.chipset == 0 && dpy->driverContext.pciBusID != 0)
+ dpy->driverContext.chipset = get_chipset_from_busid( dpy );
+
+ return 1;
+}
+
+static int InitDriver( Display *dpy )
+{
+ /*
+ * Begin DRI setup.
+ * We're kind of combining the per-display and per-screen information
+ * which was kept separate in XFree86/DRI's libGL.
+ */
+ dpy->dlHandle = dlopen(dpy->clientDriverName, RTLD_NOW | RTLD_GLOBAL);
+ if (!dpy->dlHandle) {
+ fprintf(stderr, "Unable to open %s: %s\n", dpy->clientDriverName,
+ dlerror());
+ return GL_FALSE;
+ }
+
+ /* Pull in Mini GLX specific hooks:
+ */
+ dpy->driver = (struct DRIDriverRec *) dlsym(dpy->dlHandle,
+ "__driDriver");
+ if (!dpy->driver) {
+ fprintf(stderr, "Couldn't find __driDriver in %s\n",
+ dpy->clientDriverName);
+ dlclose(dpy->dlHandle);
+ return GL_FALSE;
+ }
+
+ /* Pull in standard DRI client-side driver hooks:
+ */
+ dpy->createScreen = (driCreateScreenFunc*) dlsym(dpy->dlHandle,
+ "__driCreateScreen");
+ if (!dpy->createScreen) {
+ fprintf(stderr, "Couldn't find __driCreateScreen in %s\n",
+ dpy->clientDriverName);
+ dlclose(dpy->dlHandle);
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**********************************************************************/
+/** \name Public API functions (Xlib and GLX) */
+/**********************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Initialize the graphics system.
+ *
+ * \param display_name currently ignored. It is recommended to pass it as NULL.
+ * \return a pointer to a #Display if the function is able to initialize
+ * the graphics system, NULL otherwise.
+ *
+ * Allocates a MiniGLXDisplayRec structure and fills in with information from a
+ * configuration file.
+ *
+ * Calls OpenFBDev() to open the framebuffer device and calls
+ * DRIDriverRec::initFBDev to do the client-side initialization on it.
+ *
+ * Loads the DRI driver and pulls in Mini GLX specific hooks into a
+ * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
+ * Asks the driver for a list of supported visuals. Performs the per-screen
+ * client-side initialization. Also setups the callbacks in the screen private
+ * information.
+ *
+ * Does the framebuffer device setup. Calls __miniglx_open_connections() to
+ * serve clients.
+ */
+Display *
+__miniglx_StartServer( const char *display_name )
+{
+ Display *dpy;
+ int use_vt = 0;
+
+ dpy = (Display *)calloc(1, sizeof(Display));
+ if (!dpy)
+ return NULL;
+
+ dpy->IsClient = False;
+
+ if (!__read_config_file( dpy )) {
+ fprintf(stderr, "Couldn't get configuration details\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Open the fbdev device
+ */
+ if (!OpenFBDev(dpy, use_vt)) {
+ fprintf(stderr, "OpenFBDev failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ if (!InitDriver(dpy)) {
+ fprintf(stderr, "InitDriver failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Ask the driver for a list of supported configs:
+ */
+ dpy->driver->initContextModes( &dpy->driverContext, &dpy->numModes, &dpy->modes );
+
+ /* Perform the initialization normally done in the X server
+ */
+ if (!dpy->driver->initFBDev( &dpy->driverContext )) {
+ fprintf(stderr, "%s: __driInitFBDev failed\n", __FUNCTION__);
+ dlclose(dpy->dlHandle);
+ return GL_FALSE;
+ }
+
+ /* do fbdev setup
+ */
+ if (!SetupFBDev(dpy)) {
+ fprintf(stderr, "SetupFBDev failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* unlock here if not using VT -- JDS */
+ if (!use_vt) {
+ if (dpy->driver->restoreHardware)
+ dpy->driver->restoreHardware( &dpy->driverContext );
+ DRM_UNLOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ dpy->hwActive = 1;
+ }
+
+ /* Ready for clients:
+ */
+ if (!__miniglx_open_connections(dpy)) {
+ free(dpy);
+ return NULL;
+ }
+
+ return dpy;
+}
+
+
+/**
+ * \brief Initialize the graphics system.
+ *
+ * \param display_name currently ignored. It is recommended to pass it as NULL.
+ * \return a pointer to a #Display if the function is able to initialize
+ * the graphics system, NULL otherwise.
+ *
+ * Allocates a MiniGLXDisplayRec structure and fills in with information from a
+ * configuration file.
+ *
+ * Calls __miniglx_open_connections() to connect to the server.
+ *
+ * Loads the DRI driver and pulls in Mini GLX specific hooks into a
+ * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
+ * Asks the driver for a list of supported visuals. Performs the per-screen
+ * client-side initialization. Also setups the callbacks in the screen private
+ * information.
+ *
+ * \todo
+ * - read config file
+ * - what about virtualWidth, etc?
+ * - determine dpy->driverClientMsgSize,
+ * - allocate dpy->driverClientMsg
+ */
+Display *
+XOpenDisplay( const char *display_name )
+{
+ Display *dpy;
+
+ dpy = (Display *)calloc(1, sizeof(Display));
+ if (!dpy)
+ return NULL;
+
+ dpy->IsClient = True;
+
+ /* read config file
+ */
+ if (!__read_config_file( dpy )) {
+ fprintf(stderr, "Couldn't get configuration details\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Connect to the server and receive driverClientMsg
+ */
+ if (!__miniglx_open_connections(dpy)) {
+ free(dpy);
+ return NULL;
+ }
+
+ /* dlopen the driver .so file
+ */
+ if (!InitDriver(dpy)) {
+ fprintf(stderr, "InitDriver failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Ask the driver for a list of supported configs:
+ */
+ dpy->driver->initContextModes( &dpy->driverContext, &dpy->numModes, &dpy->modes );
+
+ /* Perform the client-side initialization.
+ *
+ * Clearly there is a limit of one on the number of windows in
+ * existence at any time.
+ *
+ * Need to shut down DRM and free DRI data in XDestroyWindow(), too.
+ */
+ dpy->driScreen = (*dpy->createScreen)(dpy->driver,
+ &dpy->driverContext);
+ if (!dpy->driScreen) {
+ fprintf(stderr, "%s: __driCreateScreen failed\n", __FUNCTION__);
+ dlclose(dpy->dlHandle);
+ free(dpy);
+ return NULL;
+ }
+
+ /* Anything more to do?
+ */
+ return dpy;
+}
+
+
+/**
+ * \brief Release display resources.
+ *
+ * When the application is about to exit, the resources associated with the
+ * graphics system can be released by calling this function.
+ *
+ * \param dpy display handle. It becomes invalid at this point.
+ *
+ * Destroys the window if any, and destroys the per-screen
+ * driver private information.
+ * Calls __miniglx_close_connections().
+ *
+ * If a server, puts the the framebuffer back into the initial state.
+ *
+ * Finally frees the display structure.
+ */
+void
+XCloseDisplay( Display *dpy )
+{
+ glXMakeCurrent( dpy, NULL, NULL);
+
+ if (dpy->NumWindows)
+ XDestroyWindow( dpy, dpy->TheWindow );
+
+ /* As this is done in XOpenDisplay, need to undo it here:
+ */
+ (*dpy->driScreen->destroyScreen)(dpy->driScreen);
+
+ __miniglx_close_connections( dpy );
+
+ if (!dpy->IsClient) {
+ /* put framebuffer back to initial state
+ */
+ (*dpy->driver->haltFBDev)( &dpy->driverContext );
+ RestoreFBDev(dpy);
+ CloseFBDev(dpy);
+ }
+
+ dlclose(dpy->dlHandle);
+ free(dpy);
+}
+
+
+/**
+ * \brief Window creation.
+ *
+ * \param display a display handle, as returned by XOpenDisplay().
+ * \param parent the parent window for the new window. For Mini GLX this should
+ * be
+ * \code RootWindow(display, 0) \endcode
+ * \param x the window abscissa. For Mini GLX, it should be zero.
+ * \param y the window ordinate. For Mini GLX, it should be zero.
+ * \param width the window width. For Mini GLX, this specifies the desired
+ * screen width such as 1024 or 1280.
+ * \param height the window height. For Mini GLX, this specifies the desired
+ * screen height such as 768 or 1024.
+ * \param border_width the border width. For Mini GLX, it should be zero.
+ * \param depth the window pixel depth. For Mini GLX, this should be the depth
+ * found in the #XVisualInfo object returned by glXChooseVisual()
+ * \param class the window class. For Mini GLX this value should be
+ * #InputOutput.
+ * \param visual the visual type. It should be the visual field of the
+ * #XVisualInfo object returned by glXChooseVisual().
+ * \param valuemask which fields of the XSetWindowAttributes() are to be used.
+ * For Mini GLX this is typically the bitmask
+ * \code CWBackPixel | CWBorderPixel | CWColormap \endcode
+ * \param attributes initial window attributes. The
+ * XSetWindowAttributes::background_pixel, XSetWindowAttributes::border_pixel
+ * and XSetWindowAttributes::colormap fields should be set.
+ *
+ * \return a window handle if it succeeds or zero if it fails.
+ *
+ * \note For Mini GLX, windows are full-screen; they cover the entire frame
+ * buffer. Also, Mini GLX imposes a limit of one window. A second window
+ * cannot be created until the first one is destroyed.
+ *
+ * This function creates and initializes a ::MiniGLXWindowRec structure after
+ * ensuring that there is no other window created. Performs the per-drawable
+ * client-side initialization calling the __DRIscreenRec::createDrawable
+ * method.
+ *
+ */
+Window
+XCreateWindow( Display *dpy, Window parent, int x, int y,
+ unsigned int width, unsigned int height,
+ unsigned int border_width, int depth, unsigned int class,
+ Visual *visual, unsigned long valuemask,
+ XSetWindowAttributes *attributes )
+{
+ Window win;
+
+ /* ignored */
+ (void) x;
+ (void) y;
+ (void) border_width;
+ (void) depth;
+ (void) class;
+ (void) valuemask;
+ (void) attributes;
+
+ if (!dpy->IsClient) {
+ fprintf(stderr, "Server process may not create windows (currently)\n");
+ return NULL;
+ }
+
+ if (dpy->NumWindows > 0)
+ return NULL; /* only allow one window */
+
+ assert(dpy->TheWindow == NULL);
+
+ win = malloc(sizeof(struct MiniGLXWindowRec));
+ if (!win)
+ return NULL;
+
+ /* In rotated mode, translate incoming x,y,width,height into
+ * 'normal' coordinates.
+ */
+ if (dpy->rotateMode) {
+ int tmp;
+ tmp = width; width = height; height = tmp;
+ tmp = x; x = y; y = tmp;
+ }
+
+ /* init other per-window fields */
+ win->x = 0;
+ win->y = 0;
+ win->w = width;
+ win->h = height;
+ win->visual = visual; /* ptr assignment */
+
+ win->bytesPerPixel = dpy->driverContext.cpp;
+ win->rowStride = dpy->driverContext.shared.virtualWidth * win->bytesPerPixel;
+ win->size = win->rowStride * height;
+ win->frontStart = dpy->driverContext.FBAddress;
+ win->frontBottom = (GLubyte *) win->frontStart + (height-1) * win->rowStride;
+
+ /* This is incorrect: the hardware driver could put the backbuffer
+ * just about anywhere. These fields, including the above are
+ * hardware dependent & don't really belong here.
+ */
+ if (visual->mode->doubleBufferMode) {
+ win->backStart = (GLubyte *) win->frontStart +
+ win->rowStride * dpy->driverContext.shared.virtualHeight;
+ win->backBottom = (GLubyte *) win->backStart
+ + (height - 1) * win->rowStride;
+ win->curBottom = win->backBottom;
+ }
+ else {
+ /* single buffered */
+ win->backStart = NULL;
+ win->backBottom = NULL;
+ win->curBottom = win->frontBottom;
+ }
+
+ win->driDrawable = dpy->driScreen->createDrawable(dpy->driScreen,
+ width, height,
+ dpy->clientID, visual->mode);
+
+ if (!win->driDrawable) {
+ fprintf(stderr, "%s: dri.createDrawable failed\n", __FUNCTION__);
+ free(win);
+ return NULL;
+ }
+
+ dpy->NumWindows++;
+ dpy->TheWindow = win;
+
+ return win;
+}
+
+
+/**
+ * \brief Destroy window.
+ *
+ * \param display display handle.
+ * \param w window handle.
+ *
+ * This function calls XUnmapWindow() and frees window \p w.
+ *
+ * In case of destroying the current buffer first unbinds the GLX context
+ * by calling glXMakeCurrent() with no drawable.
+ */
+void
+XDestroyWindow( Display *display, Window win )
+{
+ if (display && display->IsClient && win) {
+ /* check if destroying the current buffer */
+ Window curDraw = glXGetCurrentDrawable();
+ if (win == curDraw) {
+ glXMakeCurrent( display, NULL, NULL);
+ }
+
+ XUnmapWindow( display, win );
+
+ /* Destroy the drawable. */
+ (*win->driDrawable->destroyDrawable)(win->driDrawable);
+ free(win);
+
+ /* unlink window from display */
+ display->NumWindows--;
+ assert(display->NumWindows == 0);
+ display->TheWindow = NULL;
+ }
+}
+
+
+
+
+/**
+ * \brief Create color map structure.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param w the window on whose screen you want to create a color map. This
+ * parameter is ignored by Mini GLX but should be the value returned by the
+ * \code RootWindow(display, 0) \endcode macro.
+ * \param visual a visual type supported on the screen. This parameter is
+ * ignored by Mini GLX but should be the XVisualInfo::visual returned by
+ * glXChooseVisual().
+ * \param alloc the color map entries to be allocated. This parameter is ignored
+ * by Mini GLX but should be set to #AllocNone.
+ *
+ * \return the color map.
+ *
+ * This function is only provided to ease porting. Practically a no-op -
+ * returns a pointer to a dynamically allocated chunk of memory (one byte).
+ */
+Colormap
+XCreateColormap( Display *dpy, Window w, Visual *visual, int alloc )
+{
+ (void) dpy;
+ (void) w;
+ (void) visual;
+ (void) alloc;
+ return (Colormap) malloc(1);
+}
+
+
+/**
+ * \brief Destroy color map structure.
+ *
+ * \param display The display handle as returned by XOpenDisplay().
+ * \param colormap the color map to destroy.
+ *
+ * This function is only provided to ease porting. Practically a no-op.
+ *
+ * Frees the memory pointed by \p colormap.
+ */
+void
+XFreeColormap( Display *display, Colormap colormap )
+{
+ (void) display;
+ (void) colormap;
+ free(colormap);
+}
+
+
+/**
+ * \brief Free client data.
+ *
+ * \param data the data that is to be freed.
+ *
+ * Frees the memory pointed by \p data.
+ */
+void
+XFree( void *data )
+{
+ free(data);
+}
+
+
+/**
+ * \brief Query available visuals.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param vinfo_mask a bitmask indicating which fields of the \p vinfo_template
+ * are to be matched. The value must be \c VisualScreenMask.
+ * \param vinfo_template a template whose fields indicate which visual
+ * attributes must be matched by the results. The XVisualInfo::screen field of
+ * this structure must be zero.
+ * \param nitens_return will hold the number of visuals returned.
+ *
+ * \return the address of an array of all available visuals.
+ *
+ * An example of using XGetVisualInfo() to get all available visuals follows:
+ *
+ * \code
+ * XVisualInfo vinfo_template, *results;
+ * int nitens_return;
+ * Display *dpy = XOpenDisplay(NULL);
+ * vinfo_template.screen = 0;
+ * results = XGetVisualInfo(dpy, VisualScreenMask, &vinfo_template, &nitens_return);
+ * \endcode
+ *
+ * Returns the list of all ::XVisualInfo available, one per
+ * ::__GLcontextMode stored in MiniGLXDisplayRec::modes.
+ */
+XVisualInfo *
+XGetVisualInfo( Display *dpy, long vinfo_mask, XVisualInfo *vinfo_template, int *nitens_return )
+{
+ XVisualInfo *results;
+ Visual *visResults;
+ int i, n;
+
+ ASSERT(vinfo_mask == VisualScreenMask);
+ ASSERT(vinfo_template.screen == 0);
+
+ n = dpy->numModes;
+ results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
+ if (!results) {
+ *nitens_return = 0;
+ return NULL;
+ }
+
+ visResults = (Visual *)calloc(1, n * sizeof(Visual));
+ if (!results) {
+ free(results);
+ *nitens_return = 0;
+ return NULL;
+ }
+
+ for (i = 0; i < n; i++) {
+ visResults[i].mode = dpy->modes + i;
+ visResults[i].visInfo = results + i;
+ visResults[i].dpy = dpy;
+
+ if (dpy->driverContext.bpp == 32)
+ visResults[i].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
+ else
+ visResults[i].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
+
+ results[i].visual = visResults + i;
+ results[i].visualid = i;
+ results[i].class = TrueColor;
+ results[i].depth = dpy->modes[i].redBits +
+ dpy->modes[i].redBits +
+ dpy->modes[i].redBits +
+ dpy->modes[i].redBits;
+ results[i].bits_per_rgb = dpy->driverContext.bpp;
+ }
+ *nitens_return = n;
+ return results;
+}
+
+
+/**
+ * \brief Return a visual that matches specified attributes.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param screen the screen number. It is currently ignored by Mini GLX and
+ * should be zero.
+ * \param attribList a list of GLX attributes which describe the desired pixel
+ * format. It is terminated by the token \c None.
+ *
+ * The attributes are as follows:
+ * \arg GLX_USE_GL:
+ * This attribute should always be present in order to maintain compatibility
+ * with GLX.
+ * \arg GLX_RGBA:
+ * If present, only RGBA pixel formats will be considered. Otherwise, only
+ * color index formats are considered.
+ * \arg GLX_DOUBLEBUFFER:
+ * if present, only double-buffered pixel formats will be chosen.
+ * \arg GLX_RED_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per red pixel component that is acceptable.
+ * \arg GLX_GREEN_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per green pixel component that is acceptable.
+ * \arg GLX_BLUE_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per blue pixel component that is acceptable.
+ * \arg GLX_ALPHA_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per alpha pixel component that is acceptable.
+ * \arg GLX_STENCIL_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per stencil value that is acceptable.
+ * \arg GLX_DEPTH_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per depth component that is acceptable.
+ * \arg None:
+ * This token is used to terminate the attribute list.
+ *
+ * \return a pointer to an #XVisualInfo object which most closely matches the
+ * requirements of the attribute list. If there is no visual which matches the
+ * request, \c NULL will be returned.
+ *
+ * \note Visuals with accumulation buffers are not available.
+ *
+ * This function searches the list of available visual configurations in
+ * MiniGLXDisplayRec::configs for a configuration which best matches the GLX
+ * attribute list parameter. A new ::XVisualInfo object is created which
+ * describes the visual configuration. The match criteria is described in the
+ * specification.
+ */
+XVisualInfo*
+glXChooseVisual( Display *dpy, int screen, int *attribList )
+{
+ Visual *vis;
+ XVisualInfo *visInfo;
+ const int *attrib;
+ GLboolean rgbFlag = GL_FALSE, dbFlag = GL_FALSE, stereoFlag = GL_FALSE;
+ GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits = 0;
+ GLint indexBits = 0, depthBits = 0, stencilBits = 0;
+ GLint numSamples = 0;
+ int i;
+
+ /*
+ * XXX in the future, <screen> might be interpreted as a VT
+ */
+ ASSERT(dpy);
+ ASSERT(screen == 0);
+
+ vis = (Visual *)calloc(1, sizeof(Visual));
+ if (!vis)
+ return NULL;
+
+ visInfo = (XVisualInfo *)malloc(sizeof(XVisualInfo));
+ if (!visInfo) {
+ free(vis);
+ return NULL;
+ }
+
+ visInfo->visual = vis;
+ vis->visInfo = visInfo;
+ vis->dpy = dpy;
+
+ /* parse the attribute list */
+ for (attrib = attribList; attrib && *attrib != None; attrib++) {
+ switch (attrib[0]) {
+ case GLX_DOUBLEBUFFER:
+ dbFlag = GL_TRUE;
+ break;
+ case GLX_RGBA:
+ rgbFlag = GL_TRUE;
+ break;
+ case GLX_RED_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_GREEN_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_BLUE_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ALPHA_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_STENCIL_SIZE:
+ stencilBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_DEPTH_SIZE:
+ depthBits = attrib[1];
+ attrib++;
+ break;
+#if 0
+ case GLX_ACCUM_RED_SIZE:
+ accumRedBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ACCUM_GREEN_SIZE:
+ accumGreenBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ACCUM_BLUE_SIZE:
+ accumBlueBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ACCUM_ALPHA_SIZE:
+ accumAlphaBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_LEVEL:
+ /* ignored for now */
+ break;
+#endif
+ default:
+ /* unexpected token */
+ fprintf(stderr, "unexpected token in glXChooseVisual attrib list\n");
+ free(vis);
+ free(visInfo);
+ return NULL;
+ }
+ }
+
+ /* search screen configs for suitable visual */
+ (void) numSamples;
+ (void) indexBits;
+ (void) redBits;
+ (void) greenBits;
+ (void) blueBits;
+ (void) alphaBits;
+ (void) stereoFlag;
+ for (i = 0; i < dpy->numModes; i++) {
+ const __GLcontextModes *mode = dpy->modes + i;
+ if (mode->rgbMode == rgbFlag &&
+ mode->redBits >= redBits &&
+ mode->greenBits >= greenBits &&
+ mode->blueBits >= blueBits &&
+ mode->alphaBits >= alphaBits &&
+ mode->depthBits >= depthBits &&
+ mode->stencilBits >= stencilBits) {
+ /* found it */
+ visInfo->visualid = i;
+ vis->mode = mode;
+ break;
+ }
+ }
+ if (!vis->mode)
+ return NULL;
+
+ /* compute depth and bpp */
+ if (rgbFlag) {
+ /* XXX maybe support depth 16 someday */
+ visInfo->class = TrueColor;
+ visInfo->depth = dpy->driverContext.bpp;
+ visInfo->bits_per_rgb = dpy->driverContext.bpp;
+ if (dpy->driverContext.bpp == 32)
+ vis->pixelFormat = PF_B8G8R8A8;
+ else
+ vis->pixelFormat = PF_B5G6R5;
+ }
+ else {
+ /* color index mode */
+ visInfo->class = PseudoColor;
+ visInfo->depth = 8;
+ visInfo->bits_per_rgb = 8; /* bits/pixel */
+ vis->pixelFormat = PF_CI8;
+ }
+
+ return visInfo;
+}
+
+
+/**
+ * \brief Return information about GLX visuals.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param vis the visual to be queried, as returned by glXChooseVisual().
+ * \param attrib the visual attribute to be returned.
+ * \param value pointer to an integer in which the result of the query will be
+ * stored.
+ *
+ * \return zero if no error occurs, \c GLX_INVALID_ATTRIBUTE if the attribute
+ * parameter is invalid, or \c GLX_BAD_VISUAL if the \p vis parameter is
+ * invalid.
+ *
+ * Returns the appropriate attribute of ::__GLXvisualConfig pointed by
+ * MiniGLXVisualRec::glxConfig of XVisualInfo::visual.
+ *
+ * \sa data types.
+ */
+int
+glXGetConfig( Display *dpy, XVisualInfo *vis, int attrib, int *value )
+{
+ const __GLcontextModes *mode = vis->visual->mode;
+ if (!mode) {
+ *value = 0;
+ return GLX_BAD_VISUAL;
+ }
+
+ switch (attrib) {
+ case GLX_USE_GL:
+ *value = True;
+ return 0;
+ case GLX_RGBA:
+ *value = mode->rgbMode;
+ return 0;
+ case GLX_DOUBLEBUFFER:
+ *value = mode->doubleBufferMode;
+ return 0;
+ case GLX_RED_SIZE:
+ *value = mode->redBits;
+ return 0;
+ case GLX_GREEN_SIZE:
+ *value = mode->greenBits;
+ return 0;
+ case GLX_BLUE_SIZE:
+ *value = mode->blueBits;
+ return 0;
+ case GLX_ALPHA_SIZE:
+ *value = mode->alphaBits;
+ return 0;
+ case GLX_DEPTH_SIZE:
+ *value = mode->depthBits;
+ return 0;
+ case GLX_STENCIL_SIZE:
+ *value = mode->stencilBits;
+ return 0;
+ default:
+ *value = 0;
+ return GLX_BAD_ATTRIBUTE;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Create a new GLX rendering context.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param vis the visual that defines the frame buffer resources available to
+ * the rendering context, as returned by glXChooseVisual().
+ * \param shareList If non-zero, texture objects and display lists are shared
+ * with the named rendering context. If zero, texture objects and display lists
+ * will (initially) be private to this context. They may be shared when a
+ * subsequent context is created.
+ * \param direct whether direct or indirect rendering is desired. For Mini GLX
+ * this value is ignored but it should be set to \c True.
+ *
+ * \return a ::GLXContext handle if it succeeds or zero if it fails due to
+ * invalid parameter or insufficient resources.
+ *
+ * This function creates and initializes a ::MiniGLXContextRec structure and
+ * calls the __DRIscreenRec::createContext method to initialize the client
+ * private data.
+ */
+GLXContext
+glXCreateContext( Display *dpy, XVisualInfo *vis,
+ GLXContext shareList, Bool direct )
+{
+ GLXContext ctx;
+ void *sharePriv;
+
+ ASSERT(vis);
+
+ ctx = (struct MiniGLXContextRec *)calloc(1, sizeof(struct MiniGLXContextRec));
+ if (!ctx)
+ return NULL;
+
+ ctx->vid = vis->visualid;
+
+ if (shareList)
+ sharePriv = shareList->driContext;
+ else
+ sharePriv = NULL;
+
+ ctx->driContext = (*dpy->driScreen->createContext)(dpy->driScreen,
+ vis->visual->mode,
+ sharePriv);
+ if (!ctx->driContext) {
+ free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+/**
+ * \brief Destroy a GLX context.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param ctx the GLX context to be destroyed.
+ *
+ * This function frees the \p ctx parameter after unbinding the current context
+ * by calling the __DRIcontextRec::bindContext method with zeros and calling
+ * the __DRIcontextRec::destroyContext method.
+ */
+void
+glXDestroyContext( Display *dpy, GLXContext ctx )
+{
+ GLXContext glxctx = glXGetCurrentContext();
+
+ if (ctx) {
+ if (glxctx == ctx) {
+ /* destroying current context */
+ (*ctx->driContext->bindContext)(dpy->driScreen, 0, 0);
+ CurrentContext = 0;
+ }
+ (*ctx->driContext->destroyContext)(ctx->driContext);
+ free(ctx);
+ }
+}
+
+
+/**
+ * \brief Bind a GLX context to a window or a pixmap.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param drawable the window or drawable to bind to the rendering context.
+ * This should be the value returned by XCreateWindow().
+ * \param ctx the GLX context to be destroyed.
+ *
+ * \return \c True if it succeeds, \c False otherwise to indicate an invalid
+ * display, window or context parameter.
+ *
+ * The current rendering context may be unbound by calling glXMakeCurrent()
+ * with the window and context parameters set to zero.
+ *
+ * An application may create any number of rendering contexts and bind them as
+ * needed. Note that binding a rendering context is generally not a
+ * light-weight operation. Most simple OpenGL applications create only one
+ * rendering context.
+ *
+ * This function first unbinds any old context via
+ * __DRIcontextRec::unbindContext and binds the new one via
+ * __DRIcontextRec::bindContext.
+ *
+ * If \p drawable is zero it unbinds the GLX context by calling
+ * __DRIcontextRec::bindContext with zeros.
+ */
+Bool
+glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx)
+{
+ if (dpy && drawable && ctx) {
+ GLXContext oldContext = glXGetCurrentContext();
+ GLXDrawable oldDrawable = glXGetCurrentDrawable();
+ /* unbind old */
+ if (oldContext) {
+ (*oldContext->driContext->unbindContext)(oldDrawable->driDrawable, oldContext->driContext);
+ }
+ /* bind new */
+ CurrentContext = ctx;
+ (*ctx->driContext->bindContext)(dpy->driScreen, drawable->driDrawable, ctx->driContext);
+ ctx->drawBuffer = drawable;
+ ctx->curBuffer = drawable;
+ }
+ else if (ctx && dpy) {
+ /* unbind */
+ (*ctx->driContext->bindContext)(dpy->driScreen, 0, 0);
+ }
+ else if (dpy) {
+ CurrentContext = 0; /* kw: this seems to be intended??? */
+ }
+
+ return True;
+}
+
+
+/**
+ * \brief Exchange front and back buffers.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param drawable the drawable whose buffers are to be swapped.
+ *
+ * Any pending rendering commands will be completed before the buffer swap
+ * takes place.
+ *
+ * Calling glXSwapBuffers() on a window which is single-buffered has no effect.
+ *
+ * This function just calls the __DRIdrawableRec::swapBuffers method to do the
+ * work.
+ */
+void
+glXSwapBuffers( Display *dpy, GLXDrawable drawable )
+{
+ if (!dpy || !drawable)
+ return;
+
+ (*drawable->driDrawable->swapBuffers)(drawable->driDrawable);
+}
+
+
+/**
+ * \brief Return the current context
+ *
+ * \return the current context, as specified by glXMakeCurrent(), or zero if no
+ * context is currently bound.
+ *
+ * \sa glXCreateContext(), glXMakeCurrent()
+ *
+ * Returns the value of the ::CurrentContext global variable.
+ */
+GLXContext
+glXGetCurrentContext( void )
+{
+ return CurrentContext;
+}
+
+
+/**
+ * \brief Return the current drawable.
+ *
+ * \return the current drawable, as specified by glXMakeCurrent(), or zero if
+ * no drawable is currently bound.
+ *
+ * This function gets the current context via glXGetCurrentContext() and
+ * returns the MiniGLXContextRec::drawBuffer attribute.
+ */
+GLXDrawable
+glXGetCurrentDrawable( void )
+{
+ GLXContext glxctx = glXGetCurrentContext();
+ if (glxctx)
+ return glxctx->drawBuffer;
+ else
+ return NULL;
+}
+
+
+/**
+ * \brief Query function address.
+ *
+ * The glXGetProcAddress() function will return the address of any available
+ * OpenGL or Mini GLX function.
+ *
+ * \param procName name of the function to be returned.
+ *
+ * \return If \p procName is a valid function name, a pointer to that function
+ * will be returned. Otherwise, \c NULL will be returned.
+ *
+ * The purpose of glXGetProcAddress() is to facilitate using future extensions
+ * to OpenGL or Mini GLX. If a future version of the library adds new extension
+ * functions they'll be accessible via glXGetProcAddress(). The alternative is
+ * to hard-code calls to the new functions in the application but doing so will
+ * prevent linking the application with older versions of the library.
+ *
+ * Returns the function address by looking up its name in a static (name,
+ * address) pair list.
+ */
+const void *
+glXGetProcAddress( const GLubyte *procName )
+{
+ struct name_address {
+ const char *name;
+ const void *func;
+ };
+ static const struct name_address functions[] = {
+ { "glXChooseVisual", (void *) glXChooseVisual },
+ { "glXCreateContext", (void *) glXCreateContext },
+ { "glXDestroyContext", (void *) glXDestroyContext },
+ { "glXMakeCurrent", (void *) glXMakeCurrent },
+ { "glXSwapBuffers", (void *) glXSwapBuffers },
+ { "glXGetCurrentContext", (void *) glXGetCurrentContext },
+ { "glXGetCurrentDrawable", (void *) glXGetCurrentDrawable },
+ { "glXGetProcAddress", (void *) glXGetProcAddress },
+ { "XOpenDisplay", (void *) XOpenDisplay },
+ { "XCloseDisplay", (void *) XCloseDisplay },
+ { "XCreateWindow", (void *) XCreateWindow },
+ { "XDestroyWindow", (void *) XDestroyWindow },
+ { "XMapWindow", (void *) XMapWindow },
+ { "XCreateColormap", (void *) XCreateColormap },
+ { "XFreeColormap", (void *) XFreeColormap },
+ { "XFree", (void *) XFree },
+ { "XGetVisualinfo", (void *) XGetVisualInfo },
+ { NULL, NULL }
+ };
+ const struct name_address *entry;
+ for (entry = functions; entry->name; entry++) {
+ if (strcmp(entry->name, (const char *) procName) == 0) {
+ return entry->func;
+ }
+ }
+ return _glapi_get_proc_address((const char *) procName);
+}
+
+
+/**
+ * \brief Query the Mini GLX version.
+ *
+ * \param dpy the display handle. It is currently ignored, but should be the
+ * value returned by XOpenDisplay().
+ * \param major receives the major version number of Mini GLX.
+ * \param minor receives the minor version number of Mini GLX.
+ *
+ * \return \c True if the function succeeds, \c False if the function fails due
+ * to invalid parameters.
+ *
+ * \sa #MINI_GLX_VERSION_1_0.
+ *
+ * Returns the hard-coded Mini GLX version.
+ */
+Bool
+glXQueryVersion( Display *dpy, int *major, int *minor )
+{
+ (void) dpy;
+ *major = 1;
+ *minor = 0;
+ return True;
+}
+
+
+/*@}*/
diff --git a/src/glx/mini/miniglxP.h b/src/glx/mini/miniglxP.h
new file mode 100644
index 0000000000..a32429a677
--- /dev/null
+++ b/src/glx/mini/miniglxP.h
@@ -0,0 +1,194 @@
+/**
+ * \file miniglxP.h
+ * \brief Define replacements for some X data types and define the DRI-related
+ * data structures.
+ *
+ * \note Cut down version of glxclient.h.
+ *
+ */
+
+#ifndef _mini_GLX_client_h_
+#define _mini_GLX_client_h_
+
+#include <signal.h>
+#include <linux/fb.h>
+
+#include <GL/miniglx.h>
+#include "glheader.h"
+#include "mtypes.h"
+
+#include "driver.h"
+#include "dri.h"
+
+/**
+ * \brief Supported pixel formats.
+ */
+enum PixelFormat {
+ PF_B8G8R8, /**< \brief 24-bit BGR */
+ PF_B8G8R8A8, /**< \brief 32-bit BGRA */
+ PF_B5G6R5, /**< \brief 16-bit BGR */
+ PF_B5G5R5, /**< \brief 15-bit BGR */
+ PF_CI8 /**< \brief 8-bit color index */
+};
+
+/**
+ * \brief X Visual type.
+ *
+ * \sa ::Visual, \ref datatypes.
+ */
+struct MiniGLXVisualRec {
+ /** \brief GLX visual information */
+ const __GLcontextModes *mode;
+
+ /** \brief pointer back to corresponding ::XVisualInfo */
+ XVisualInfo *visInfo;
+
+ /** \brief display handle */
+ Display *dpy;
+
+ /** \brief pixel format */
+ enum PixelFormat pixelFormat;
+};
+
+
+
+/**
+ * \brief X Window type.
+ *
+ * \sa ::Window, \ref datatypes.
+ */
+struct MiniGLXWindowRec {
+ Visual *visual;
+ /** \brief position (always 0,0) */
+ int x, y;
+ /** \brief size */
+ unsigned int w, h;
+ void *frontStart; /**< \brief start of front color buffer */
+ void *backStart; /**< \brief start of back color buffer */
+ size_t size; /**< \brief color buffer size, in bytes */
+ GLuint bytesPerPixel;
+ GLuint rowStride; /**< \brief in bytes */
+ GLubyte *frontBottom; /**< \brief pointer to last row */
+ GLubyte *backBottom; /**< \brief pointer to last row */
+ GLubyte *curBottom; /**< = frontBottom or backBottom */
+ __DRIdrawable *driDrawable;
+ GLuint ismapped;
+};
+
+
+/**
+ * \brief GLXContext type.
+ *
+ * \sa ::GLXContext, \ref datatypes.
+ */
+struct MiniGLXContextRec {
+ Window drawBuffer; /**< \brief drawing buffer */
+ Window curBuffer; /**< \brief current buffer */
+ VisualID vid; /**< \brief visual ID */
+ __DRIcontext *driContext; /**< \brief context dependent methods */
+};
+
+#define MINIGLX_BUF_SIZE 512
+#define MINIGLX_MAX_SERVER_FDS 10
+#define MINIGLX_MAX_CLIENT_FDS 1
+#define MINIGLX_EVENT_QUEUE_SZ 16
+#define MINIGLX_EVENT_QUEUE_MASK (MINIGLX_EVENT_QUEUE_SZ-1)
+
+/**
+ * A connection to/from the server
+ *
+ * All information is to/from the server is buffered and then dispatched by
+ * __miniglx_Select() to avoid blocking the server.
+ */
+struct MiniGLXConnection {
+ int fd; /**< \brief file descriptor */
+ char readbuf[MINIGLX_BUF_SIZE]; /**< \brief read buffer */
+ char writebuf[MINIGLX_BUF_SIZE]; /**< \brief write buffer */
+ int readbuf_count; /**< \brief count of bytes waiting to be read */
+ int writebuf_count; /**< \brief count of bytes waiting to be written */
+};
+
+
+/**
+ * \brief X Display type
+ *
+ * \sa ::Display, \ref datatypes.
+ */
+struct MiniGLXDisplayRec {
+ /** \brief fixed framebuffer screen info */
+ struct fb_fix_screeninfo FixedInfo;
+ /** \brief original and current variable framebuffer screen info */
+ struct fb_var_screeninfo OrigVarInfo, VarInfo;
+ struct sigaction OrigSigUsr1;
+ struct sigaction OrigSigUsr2;
+ int OriginalVT;
+ int ConsoleFD; /**< \brief console TTY device file descriptor */
+ int FrameBufferFD; /**< \brief framebuffer device file descriptor */
+ int NumWindows; /**< \brief number of open windows */
+ Window TheWindow; /**< \brief open window - only allow one window for now */
+ int rotateMode;
+
+
+ volatile int vtSignalFlag;
+ volatile int haveVT; /**< \brief whether the VT is hold */
+ int hwActive; /**< \brief whether the hardware is active -- mimics
+ the variations of MiniGLXDisplayRec::haveVT */
+
+
+ int IsClient; /**< \brief whether it's a client or the server */
+ int clientID;
+ int nrFds; /**< \brief number of connections (usually just one for the clients) */
+ struct MiniGLXConnection *fd; /**< \brief connections */
+
+ struct {
+ int nr, head, tail;
+ XEvent queue[MINIGLX_EVENT_QUEUE_SZ];
+ } eventqueue;
+
+ /**
+ * \name Visuals
+ *
+ * Visuals (configs) in this screen.
+ */
+ /*@{*/
+ int numModes; /**< \brief Number of modes. */
+ const __GLcontextModes *modes; /**< \brief Modes list pointer. */
+ /*@}*/
+
+ /**
+ * \name From __GLXdisplayPrivate
+ */
+ /*@{*/
+ driCreateScreenFunc *createScreen; /**< \brief \e __driCreateScreen hook */
+ __DRIscreen *driScreen; /**< \brief Screen dependent methods */
+ void *dlHandle; /**<
+ * \brief handle to the client dynamic
+ * library
+ */
+ /*@}*/
+
+ /**
+ * \brief Mini GLX specific driver hooks
+ */
+ struct DRIDriverRec *driver;
+ struct DRIDriverContextRec driverContext;
+
+ /**
+ * \name Configuration details
+ *
+ * They are read from a configuration file by __read_config_file().
+ */
+ /*@{*/
+ const char *fbdevDevice;
+ const char *clientDriverName;
+ /*@}*/
+};
+
+extern __DRIscreen *__glXFindDRIScreen(Display *dpy, int scrn);
+
+extern Bool __glXWindowExists(Display *dpy, GLXDrawable draw);
+
+extern int __miniglx_open_connections( Display *dpy );
+extern void __miniglx_close_connections( Display *dpy );
+
+#endif /* !_mini_GLX_client_h_ */
diff --git a/src/glx/mini/miniglx_events.c b/src/glx/mini/miniglx_events.c
new file mode 100644
index 0000000000..d367dba395
--- /dev/null
+++ b/src/glx/mini/miniglx_events.c
@@ -0,0 +1,962 @@
+/**
+ * \file miniglx_events.c
+ * \brief Mini GLX client/server communication functions.
+ * \author Keith Whitwell
+ *
+ * The Mini GLX interface is a subset of the GLX interface, plus a
+ * minimal set of Xlib functions. This file adds interfaces to
+ * arbitrate a single cliprect between multiple direct rendering
+ * clients.
+ *
+ * A fairly complete client/server non-blocking communication
+ * mechanism. Probably overkill given that none of our messages
+ * currently exceed 1 byte in length and take place over the
+ * relatively benign channel provided by a Unix domain socket.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.0
+ *
+ * Copyright (C) 1999-2003 Brian Paul 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 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
+ * BRIAN PAUL 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.
+ */
+
+/* $Id: miniglx_events.c,v 1.1 2003/08/22 20:11:43 brianp Exp $ */
+
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+
+#include <linux/kd.h>
+#include <linux/vt.h>
+
+#include "miniglxP.h"
+
+#include "xf86drm.h"
+#include "sarea.h"
+
+#define MINIGLX_FIFO_NAME "/tmp/miniglx.fifo"
+
+/** Character messages. */
+enum msgs {
+ _CanIHaveFocus,
+ _IDontWantFocus,
+ _YouveGotFocus,
+ _YouveLostFocus,
+ _RepaintPlease,
+};
+
+/**
+ * \brief Allocate an XEvent structure on the event queue.
+ *
+ * \param dpy the display handle.
+ *
+ * \return Pointer to the queued event structure or NULL on failure.
+ *
+ * \internal
+ * If there is space on the XEvent queue, return a pointer
+ * to the next free event and increment the eventqueue tail value.
+ * Otherwise return null.
+ */
+static XEvent *queue_event( Display *dpy )
+{
+ int incr = (dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK;
+ if (incr == dpy->eventqueue.head) {
+ return 0;
+ }
+ else {
+ XEvent *ev = &dpy->eventqueue.queue[dpy->eventqueue.tail];
+ dpy->eventqueue.tail = incr;
+ return ev;
+ }
+}
+
+/**
+ * \brief Dequeue an XEvent and copy it into provided storage.
+ *
+ * \param dpy the display handle.
+ * \param event_return pointer to copy the queued event to.
+ *
+ * \return True or False depending on success.
+ *
+ * \internal
+ * If there is a queued XEvent on the queue, copy it to the provided
+ * pointer and increment the eventqueue head value. Otherwise return
+ * null.
+ */
+static int dequeue_event( Display *dpy, XEvent *event_return )
+{
+ if (dpy->eventqueue.tail == dpy->eventqueue.head) {
+ return False;
+ }
+ else {
+ *event_return = dpy->eventqueue.queue[dpy->eventqueue.head];
+ dpy->eventqueue.head += 1;
+ dpy->eventqueue.head &= MINIGLX_EVENT_QUEUE_MASK;
+ return True;
+ }
+}
+
+/**
+ * \brief Shutdown a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ *
+ * \internal
+ * Shutdown and close the file descriptor. If this is the special
+ * connection in fd[0], issue an error message and exit - there's been
+ * some sort of failure somewhere. Otherwise, let the application
+ * know about whats happened by issuing a DestroyNotify event.
+ */
+static void shut_fd( Display *dpy, int i )
+{
+ if (dpy->fd[i].fd < 0)
+ return;
+
+ shutdown (dpy->fd[i].fd, SHUT_RDWR);
+ close (dpy->fd[i].fd);
+ dpy->fd[i].fd = -1;
+ dpy->fd[i].readbuf_count = 0;
+ dpy->fd[i].writebuf_count = 0;
+
+ if (i == 0) {
+ fprintf(stderr, "server connection lost\n");
+ exit(1);
+ }
+ else {
+ /* Pass this to the application as a DestroyNotify event.
+ */
+ XEvent *er = queue_event(dpy);
+ if (!er) return;
+ er->xdestroywindow.type = DestroyNotify;
+ er->xdestroywindow.serial = 0;
+ er->xdestroywindow.send_event = 0;
+ er->xdestroywindow.display = dpy;
+ er->xdestroywindow.window = (Window)i;
+ }
+}
+
+/**
+ * \brief Send a message to a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ * \param msg the message to send.
+ * \param sz the size of the message
+ *
+ * \internal
+ * Copy the message to the write buffer for the nominated connection.
+ * This will be actually sent to that file descriptor from
+ * __miniglx_Select().
+ */
+static int send_msg( Display *dpy, int i,
+ const void *msg, size_t sz )
+{
+ int cnt = dpy->fd[i].writebuf_count;
+ if (MINIGLX_BUF_SIZE - cnt < sz) {
+ fprintf(stderr, "client %d: writebuf overflow\n", i);
+ return False;
+ }
+
+ memcpy( dpy->fd[i].writebuf + cnt, msg, sz ); cnt += sz;
+ dpy->fd[i].writebuf_count = cnt;
+ return True;
+}
+
+/**
+ * \brief Send a message to a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ * \param msg the message to send.
+ *
+ * \internal
+ * Use send_msg() to send a one-byte message to a socket.
+ */
+static int send_char_msg( Display *dpy, int i, char msg )
+{
+ return send_msg( dpy, i, &msg, sizeof(char));
+}
+
+
+/**
+ * \brief Block and receive a message from a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param connection the index in dpy->fd of the socket connection.
+ * \param msg storage for the received message.
+ * \param msg_size the number of bytes to read.
+ *
+ * \internal
+ * Block and read from the connection's file descriptor
+ * until msg_size bytes have been received.
+ *
+ * Only called from welcome_message_part().
+ */
+static int blocking_read( Display *dpy, int connection,
+ char *msg, size_t msg_size )
+{
+ int i, r;
+
+ for (i = 0 ; i < msg_size ; i += r) {
+ r = read(dpy->fd[connection].fd, msg + i, msg_size - i);
+ if (r < 1) {
+ fprintf(stderr, "blocking_read: %d %s\n", r, strerror(errno));
+ shut_fd(dpy,connection);
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/**
+ * \brief Send/receive a part of the welcome message.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ * \param msg storage for the sent/received message.
+ * \param sz the number of bytes to write/read.
+ *
+ * \return True on success, or False on failure.
+ *
+ * This function is called by welcome_message_part(), to either send or receive
+ * (via blocking_read()) part of the welcome message, according to whether
+ * Display::IsClient is set.
+ *
+ * Each part of the welcome message on the wire consists of a count and then the
+ * actual message data with that number of bytes.
+ */
+static int welcome_message_part( Display *dpy, int i, void **msg, int sz )
+{
+ if (dpy->IsClient) {
+ int sz;
+ if (!blocking_read( dpy, i, (char *)&sz, sizeof(sz))) return False;
+ if (!*msg) *msg = malloc(sz);
+ if (!*msg) return False;
+ if (!blocking_read( dpy, i, *msg, sz )) return False;
+ }
+ else {
+ if (!send_msg( dpy, i, &sz, sizeof(sz))) return False;
+ if (!send_msg( dpy, i, *msg, sz )) return False;
+ }
+
+ return True;
+}
+
+/**
+ * \brief Send/receive the welcome message.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ *
+ * \return True on success, or False on failure.
+ *
+ * Using welcome_message_part(), sends/receives the client ID, the client
+ * configuration details in DRIDriverContext::shared, and the driver private
+ * message in DRIDriverContext::driverClientMsg.
+ */
+static int welcome_message( Display *dpy, int i )
+{
+ void *tmp = &dpy->driverContext.shared;
+ int *clientid = dpy->IsClient ? &dpy->clientID : &i;
+
+ if (!welcome_message_part( dpy, i, (void **)&clientid, sizeof(*clientid)))
+ return False;
+
+ if (!welcome_message_part( dpy, i, &tmp, sizeof(dpy->driverContext.shared)))
+ return False;
+
+ if (!welcome_message_part( dpy, i,
+ (void **)&dpy->driverContext.driverClientMsg,
+ dpy->driverContext.driverClientMsgSize ))
+ return False;
+
+ return True;
+}
+
+
+/**
+ * \brief Handle a new client connection.
+ *
+ * \param dpy the display handle.
+ *
+ * \return True on success or False on failure.
+ *
+ * Accepts the connection, sets it in non-blocking operation, and finds a free
+ * slot in Display::fd for it.
+ */
+static int handle_new_client( Display *dpy )
+{
+ struct sockaddr_un client_address;
+ unsigned int l = sizeof(client_address);
+ int r, i;
+
+ r = accept(dpy->fd[0].fd, (struct sockaddr *) &client_address, &l);
+ if (r < 0) {
+ perror ("accept()");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+ if (fcntl(r, F_SETFL, O_NONBLOCK) != 0) {
+ perror("fcntl");
+ close(r);
+ return False;
+ }
+
+
+ /* Some rough & ready adaption of the XEvent semantics.
+ */
+ for (i = 1 ; i < dpy->nrFds ; i++) {
+ if (dpy->fd[i].fd < 0) {
+ XEvent *er = queue_event(dpy);
+ if (!er) {
+ close(r);
+ return False;
+ }
+
+ dpy->fd[i].fd = r;
+ er->xcreatewindow.type = CreateNotify;
+ er->xcreatewindow.serial = 0;
+ er->xcreatewindow.send_event = 0;
+ er->xcreatewindow.display = dpy;
+ er->xcreatewindow.window = (Window)i; /* fd slot == window, now? */
+
+ /* Send the driver client message - this is expected as the
+ * first message on a new connection. The recpient already
+ * knows the size of the message.
+ */
+ welcome_message( dpy, i );
+ return True;
+ }
+ }
+
+
+ fprintf(stderr, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__);
+ close(r);
+ return False;
+}
+
+/**
+ * This routine "puffs out" the very basic communications between
+ * client and server to full-sized X Events that can be handled by the
+ * application.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ *
+ * \return True on success or False on failure.
+ *
+ * \internal
+ * Interprets the message (see msg) into a XEvent and advances the file FIFO
+ * buffer.
+ */
+static int
+handle_fifo_read( Display *dpy, int i )
+{
+ while (dpy->fd[i].readbuf_count) {
+ char id = dpy->fd[i].readbuf[0];
+ XEvent *er;
+ int count = 1;
+
+ if (dpy->IsClient) {
+ switch (id) {
+ /* The server has called XMapWindow on a client window */
+ case _YouveGotFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xmap.type = MapNotify;
+ er->xmap.serial = 0;
+ er->xmap.send_event = False;
+ er->xmap.display = dpy;
+ er->xmap.event = dpy->TheWindow;
+ er->xmap.window = dpy->TheWindow;
+ er->xmap.override_redirect = False;
+ if (dpy->driver->notifyFocus)
+ dpy->driver->notifyFocus( 1 );
+ break;
+
+ /* The server has called XMapWindow on a client window */
+ case _RepaintPlease:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xexpose.type = Expose;
+ er->xexpose.serial = 0;
+ er->xexpose.send_event = False;
+ er->xexpose.display = dpy;
+ er->xexpose.window = dpy->TheWindow;
+ if (dpy->rotateMode) {
+ er->xexpose.x = dpy->TheWindow->y;
+ er->xexpose.y = dpy->TheWindow->x;
+ er->xexpose.width = dpy->TheWindow->h;
+ er->xexpose.height = dpy->TheWindow->w;
+ }
+ else {
+ er->xexpose.x = dpy->TheWindow->x;
+ er->xexpose.y = dpy->TheWindow->y;
+ er->xexpose.width = dpy->TheWindow->w;
+ er->xexpose.height = dpy->TheWindow->h;
+ }
+ er->xexpose.count = 0;
+ break;
+
+ /* The server has called 'XUnmapWindow' on a client
+ * window.
+ */
+ case _YouveLostFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xunmap.type = UnmapNotify;
+ er->xunmap.serial = 0;
+ er->xunmap.send_event = False;
+ er->xunmap.display = dpy;
+ er->xunmap.event = dpy->TheWindow;
+ er->xunmap.window = dpy->TheWindow;
+ er->xunmap.from_configure = False;
+ if (dpy->driver->notifyFocus)
+ dpy->driver->notifyFocus( 0 );
+ break;
+
+ default:
+ fprintf(stderr, "Client received unhandled message type %d\n", id);
+ shut_fd(dpy, i); /* Actually shuts down the client */
+ return False;
+ }
+ }
+ else {
+ switch (id) {
+ /* Lets the server know that the client is ready to render
+ * (having called 'XMapWindow' locally).
+ */
+ case _CanIHaveFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xmaprequest.type = MapRequest;
+ er->xmaprequest.serial = 0;
+ er->xmaprequest.send_event = False;
+ er->xmaprequest.display = dpy;
+ er->xmaprequest.parent = 0;
+ er->xmaprequest.window = (Window)i;
+ break;
+
+ /* Both _YouveLostFocus and _IDontWantFocus generate unmap
+ * events. The idea is that _YouveLostFocus lets the client
+ * know that it has had focus revoked by the server, whereas
+ * _IDontWantFocus lets the server know that the client has
+ * unmapped its own window.
+ */
+ case _IDontWantFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xunmap.type = UnmapNotify;
+ er->xunmap.serial = 0;
+ er->xunmap.send_event = False;
+ er->xunmap.display = dpy;
+ er->xunmap.event = (Window)i;
+ er->xunmap.window = (Window)i;
+ er->xunmap.from_configure = False;
+ break;
+
+ default:
+ fprintf(stderr, "Server received unhandled message type %d\n", id);
+ shut_fd(dpy, i); /* Generates DestroyNotify event */
+ return False;
+ }
+ }
+
+ dpy->fd[i].readbuf_count -= count;
+
+ if (dpy->fd[i].readbuf_count) {
+ memmove(dpy->fd[i].readbuf,
+ dpy->fd[i].readbuf + count,
+ dpy->fd[i].readbuf_count);
+ }
+ }
+
+ return True;
+}
+
+/**
+ * Handle a VT signal
+ *
+ * \param dpy display handle.
+ *
+ * The VT switches is detected by comparing Display::haveVT and
+ * Display::hwActive. When loosing the VT the hardware lock is acquired, the
+ * hardware is shutdown via a call to DRIDriverRec::shutdownHardware(), and the
+ * VT released. When acquiring the VT back the hardware state is restored via a
+ * call to DRIDriverRec::restoreHardware() and the hardware lock released.
+ */
+static void __driHandleVtSignals( Display *dpy )
+{
+ dpy->vtSignalFlag = 0;
+
+ fprintf(stderr, "%s: haveVT %d hwActive %d\n", __FUNCTION__,
+ dpy->haveVT, dpy->hwActive);
+
+ if (!dpy->haveVT && dpy->hwActive) {
+ /* Need to get lock and shutdown hardware */
+ DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ dpy->driver->shutdownHardware( &dpy->driverContext );
+
+ /* Can now give up control of the VT */
+ ioctl( dpy->ConsoleFD, VT_RELDISP, 1 );
+ dpy->hwActive = 0;
+ }
+ else if (dpy->haveVT && !dpy->hwActive) {
+ /* Get VT (wait??) */
+ ioctl( dpy->ConsoleFD, VT_RELDISP, VT_ACTIVATE );
+
+ /* restore HW state, release lock */
+ dpy->driver->restoreHardware( &dpy->driverContext );
+ DRM_UNLOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ dpy->hwActive = 1;
+ }
+}
+
+
+#undef max
+#define max(x,y) ((x) > (y) ? (x) : (y))
+
+/**
+ * Logic for the select() call.
+ *
+ * \param dpy display handle.
+ * \param n highest fd in any set plus one.
+ * \param rfds fd set to be watched for reading, or NULL to create one.
+ * \param wfds fd set to be watched for writing, or NULL to create one.
+ * \param xfds fd set to be watched for exceptions or error, or NULL to create one.
+ * \param tv timeout value, or NULL for no timeout.
+ *
+ * \return number of file descriptors contained in the sets, or a negative number on failure.
+ *
+ * \note
+ * This all looks pretty complex, but is necessary especially on the
+ * server side to prevent a poorly-behaved client from causing the
+ * server to block in a read or write and hence not service the other
+ * clients.
+ *
+ * \sa
+ * See select_tut in the Linux manual pages for more discussion.
+ *
+ * \internal
+ * Creates and initializes the file descriptor sets by inspecting Display::fd
+ * if these aren't passed in the function call. Calls select() and fulfill the
+ * demands by trying to fill MiniGLXConnection::readbuf and draining
+ * MiniGLXConnection::writebuf.
+ * The server fd[0] is handled specially for new connections, by calling
+ * handle_new_client().
+ *
+ */
+int
+__miniglx_Select( Display *dpy, int n, fd_set *rfds, fd_set *wfds, fd_set *xfds,
+ struct timeval *tv )
+{
+ int i;
+ int retval;
+ fd_set my_rfds, my_wfds;
+ struct timeval my_tv;
+
+ if (!rfds) {
+ rfds = &my_rfds;
+ FD_ZERO(rfds);
+ }
+
+ if (!wfds) {
+ wfds = &my_wfds;
+ FD_ZERO(wfds);
+ }
+
+ /* Don't block if there are events queued. Review this if the
+ * flush in XMapWindow is changed to blocking. (Test case:
+ * miniglxtest).
+ */
+ if (dpy->eventqueue.head != dpy->eventqueue.tail) {
+ my_tv.tv_sec = my_tv.tv_usec = 0;
+ tv = &my_tv;
+ }
+
+ for (i = 0 ; i < dpy->nrFds; i++) {
+ if (dpy->fd[i].fd < 0)
+ continue;
+
+ if (dpy->fd[i].writebuf_count)
+ FD_SET(dpy->fd[i].fd, wfds);
+
+ if (dpy->fd[i].readbuf_count < MINIGLX_BUF_SIZE)
+ FD_SET(dpy->fd[i].fd, rfds);
+
+ n = max(n, dpy->fd[i].fd + 1);
+ }
+
+ if (dpy->vtSignalFlag)
+ __driHandleVtSignals( dpy );
+
+ retval = select( n, rfds, wfds, xfds, tv );
+
+ if (dpy->vtSignalFlag) {
+ int tmp = errno;
+ __driHandleVtSignals( dpy );
+ errno = tmp;
+ }
+
+ if (retval < 0) {
+ FD_ZERO(rfds);
+ FD_ZERO(wfds);
+ return retval;
+ }
+
+ /* Handle server fd[0] specially on the server - accept new client
+ * connections.
+ */
+ if (!dpy->IsClient) {
+ if (FD_ISSET(dpy->fd[0].fd, rfds)) {
+ FD_CLR(dpy->fd[0].fd, rfds);
+ handle_new_client( dpy );
+ }
+ }
+
+ /* Otherwise, try and fill readbuffer and drain writebuffer:
+ */
+ for (i = 0 ; i < dpy->nrFds ; i++) {
+ if (dpy->fd[i].fd < 0)
+ continue;
+
+ /* If there aren't any event slots left, don't examine
+ * any more file events. This will prevent lost events.
+ */
+ if (dpy->eventqueue.head ==
+ ((dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK)) {
+ fprintf(stderr, "leaving event loop as event queue is full\n");
+ return retval;
+ }
+
+ if (FD_ISSET(dpy->fd[i].fd, wfds)) {
+ int r = write(dpy->fd[i].fd,
+ dpy->fd[i].writebuf,
+ dpy->fd[i].writebuf_count);
+
+ if (r < 1)
+ shut_fd(dpy,i);
+ else {
+ dpy->fd[i].writebuf_count -= r;
+ if (dpy->fd[i].writebuf_count) {
+ memmove(dpy->fd[i].writebuf,
+ dpy->fd[i].writebuf + r,
+ dpy->fd[i].writebuf_count);
+ }
+ }
+ }
+
+ if (FD_ISSET(dpy->fd[i].fd, rfds)) {
+ int r = read(dpy->fd[i].fd,
+ dpy->fd[i].readbuf + dpy->fd[i].readbuf_count,
+ MINIGLX_BUF_SIZE - dpy->fd[i].readbuf_count);
+
+ if (r < 1)
+ shut_fd(dpy,i);
+ else {
+ dpy->fd[i].readbuf_count += r;
+
+ handle_fifo_read( dpy, i );
+ }
+ }
+ }
+
+ return retval;
+}
+
+/**
+ * \brief Handle socket events.
+ *
+ * \param dpy the display handle.
+ * \param nonblock whether to return immediately or wait for an event.
+ *
+ * \return True on success, False on failure. Aborts on critical error.
+ *
+ * \internal
+ * This function is the select() main loop.
+ */
+static int handle_fd_events( Display *dpy, int nonblock )
+{
+ while (1) {
+ struct timeval tv = {0, 0};
+ int r = __miniglx_Select( dpy, 0, 0, 0, 0, nonblock ? &tv : 0 );
+ if (r >= 0)
+ return True;
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ perror ("select()");
+ exit (1);
+ }
+}
+
+/**
+ * Initializes the connections.
+ *
+ * \param dpy the display handle.
+ *
+ * \return True on success or False on failure.
+ *
+ * Allocates and initializes the Display::fd array and create a Unix socket on
+ * the first entry. For a server binds the socket to a filename and listen for
+ * connections. For a client connects to the server and waits for a welcome
+ * message. Sets the socket in nonblocking mode.
+ */
+int __miniglx_open_connections( Display *dpy )
+{
+ struct sockaddr_un sa;
+ int i;
+
+ dpy->nrFds = dpy->IsClient ? 1 : MINIGLX_MAX_SERVER_FDS;
+ dpy->fd = calloc(1, dpy->nrFds * sizeof(struct MiniGLXConnection));
+ if (!dpy->fd)
+ return False;
+
+ for (i = 0 ; i < dpy->nrFds ; i++)
+ dpy->fd[i].fd = -1;
+
+ if (!dpy->IsClient) {
+ if (unlink(MINIGLX_FIFO_NAME) != 0 && errno != ENOENT) {
+ perror("unlink " MINIGLX_FIFO_NAME);
+ return False;
+ }
+
+ }
+
+ /* Create a Unix socket -- Note this is *not* a network connection!
+ */
+ dpy->fd[0].fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (dpy->fd[0].fd < 0) {
+ perror("socket " MINIGLX_FIFO_NAME);
+ return False;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sun_family = AF_UNIX;
+ strcpy(sa.sun_path, MINIGLX_FIFO_NAME);
+
+ if (dpy->IsClient) {
+ /* Connect to server
+ */
+ if (connect(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
+ perror("connect");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+ /* Wait for configuration messages from the server.
+ */
+ welcome_message( dpy, 0 );
+ }
+ else {
+ mode_t tmp = umask( 0000 ); /* open to everybody ? */
+
+ /* Bind socket to our filename
+ */
+ if (bind(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
+ perror("bind");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+ umask( tmp );
+
+ /* Listen for connections
+ */
+ if (listen(dpy->fd[0].fd, 5) != 0) {
+ perror("listen");
+ shut_fd(dpy,0);
+ return False;
+ }
+ }
+
+ if (fcntl(dpy->fd[0].fd, F_SETFL, O_NONBLOCK) != 0) {
+ perror("fcntl");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+
+ return True;
+}
+
+
+/**
+ * Frees the connections initialized by __miniglx_open_connections().
+ *
+ * \param dpy the display handle.
+ */
+void __miniglx_close_connections( Display *dpy )
+{
+ int i;
+
+ for (i = 0 ; i < dpy->nrFds ; i++) {
+ if (dpy->fd[i].fd >= 0) {
+ shutdown (dpy->fd[i].fd, SHUT_RDWR);
+ close (dpy->fd[i].fd);
+ }
+ }
+
+ dpy->nrFds = 0;
+ free(dpy->fd);
+}
+
+
+/**
+ * Set a drawable flag.
+ *
+ * \param dpy the display handle.
+ * \param w drawable (window).
+ * \param flag flag.
+ *
+ * Sets the specified drawable flag in the SAREA and increment its stamp while
+ * holding the light hardware lock.
+ */
+static void set_drawable_flag( Display *dpy, int w, int flag )
+{
+ if (dpy->driverContext.pSAREA) {
+ if (dpy->hwActive)
+ DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+
+ dpy->driverContext.pSAREA->drawableTable[w].stamp++;
+ dpy->driverContext.pSAREA->drawableTable[w].flags = flag;
+
+ if (dpy->hwActive)
+ DRM_UNLOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ }
+}
+
+
+
+/**
+ * \brief Map Window.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param w the window handle.
+ *
+ * If called by a client, sends a request for focus to the server. If
+ * called by the server, will generate a MapNotify and Expose event at
+ * the client.
+ *
+ */
+void
+XMapWindow( Display *dpy, Window w )
+{
+ if (dpy->IsClient)
+ send_char_msg( dpy, 0, _CanIHaveFocus );
+ else {
+ set_drawable_flag( dpy, (int)w, 1 );
+ send_char_msg( dpy, (int)w, _YouveGotFocus );
+ send_char_msg( dpy, (int)w, _RepaintPlease );
+ dpy->TheWindow = w;
+ }
+ handle_fd_events( dpy, 0 ); /* flush write queue */
+}
+
+/**
+ * \brief Unmap Window.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param w the window handle.
+ *
+ * Called from the client: Lets the server know that the window won't
+ * be updated anymore.
+ *
+ * Called from the server: Tells the specified client that it no longer
+ * holds the focus.
+ */
+void
+XUnmapWindow( Display *dpy, Window w )
+{
+ if (dpy->IsClient) {
+ send_char_msg( dpy, 0, _IDontWantFocus );
+ }
+ else {
+ dpy->TheWindow = 0;
+ set_drawable_flag( dpy, (int)w, 0 );
+ send_char_msg( dpy, (int)w, _YouveLostFocus );
+ }
+ handle_fd_events( dpy, 0 ); /* flush write queue */
+}
+
+
+/**
+ * \brief Block and wait for next X event.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param event_return a pointer to an XEvent structure for the returned data.
+ *
+ * Wait until there is a new XEvent pending.
+ */
+int XNextEvent(Display *dpy, XEvent *event_return)
+{
+ for (;;) {
+ if ( dpy->eventqueue.head != dpy->eventqueue.tail )
+ return dequeue_event( dpy, event_return );
+
+ handle_fd_events( dpy, 0 );
+ }
+}
+
+/**
+ * \brief Non-blocking check for next X event.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param event_mask ignored.
+ * \param event_return a pointer to an XEvent structure for the returned data.
+ *
+ * Check if there is a new XEvent pending. Note that event_mask is
+ * ignored and any pending event will be returned.
+ */
+Bool XCheckMaskEvent(Display *dpy, long event_mask, XEvent *event_return)
+{
+ if ( dpy->eventqueue.head != dpy->eventqueue.tail )
+ return dequeue_event( dpy, event_return );
+
+ handle_fd_events( dpy, 1 );
+
+ return dequeue_event( dpy, event_return );
+}
diff --git a/src/glx/mini/sarea.h b/src/glx/mini/sarea.h
new file mode 100644
index 0000000000..47545e10e9
--- /dev/null
+++ b/src/glx/mini/sarea.h
@@ -0,0 +1,96 @@
+/**
+ * \file sarea.h
+ * \brief SAREA definitions.
+ *
+ * The SAREA is a memory region is shared by the DRM device, the X server and
+ * the clients.
+ *
+ * This file defines its layout in user space.
+ *
+ * \author Kevin E. Martin <kevin@precisioninsight.com>
+ * \author Jens Owen <jens@tungstengraphics.com>
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef _SAREA_H_
+#define _SAREA_H_
+
+#include "xf86drm.h"
+
+/* SAREA area needs to be at least a page */
+#if defined(__alpha__)
+#define SAREA_MAX 0x2000
+#elif defined(__ia64__)
+#define SAREA_MAX 0x10000 /* 64kB */
+#else
+/* Intel 830M driver needs at least 8k SAREA */
+#define SAREA_MAX 0x2000
+#endif
+
+#define SAREA_MAX_DRAWABLES 256
+
+#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000
+
+/**
+ * \brief SAREA per drawable information.
+ *
+ * \sa _XF86DRISAREA.
+ */
+typedef struct _XF86DRISAREADrawable {
+ unsigned int stamp;
+ unsigned int flags;
+} XF86DRISAREADrawableRec, *XF86DRISAREADrawablePtr;
+
+/**
+ * \brief SAREA frame information.
+ *
+ * \sa _XF86DRISAREA.
+ */
+typedef struct _XF86DRISAREAFrame {
+ unsigned int x;
+ unsigned int y;
+ unsigned int width;
+ unsigned int height;
+ unsigned int fullscreen;
+} XF86DRISAREAFrameRec, *XF86DRISAREAFramePtr;
+
+/**
+ * \brief SAREA definition.
+ */
+typedef struct _XF86DRISAREA {
+ /** first thing is always the DRM locking structure */
+ drmLock lock;
+ /** \todo Use readers/writer lock for drawable_lock */
+ drmLock drawable_lock;
+ XF86DRISAREADrawableRec drawableTable[SAREA_MAX_DRAWABLES];
+ XF86DRISAREAFrameRec frame;
+ drmContext dummy_context;
+} XF86DRISAREARec, *XF86DRISAREAPtr;
+
+#endif
diff --git a/src/glx/mini/xf86drm.c b/src/glx/mini/xf86drm.c
new file mode 100644
index 0000000000..bbb02e4032
--- /dev/null
+++ b/src/glx/mini/xf86drm.c
@@ -0,0 +1,1587 @@
+/**
+ * \file xf86drm.c
+ * \brief User-level interface to DRM device
+ *
+ * This file is an user-friendly interface to the DRM ioctls defined in drm.h.
+ *
+ * This covers only the device-independent ioctls -- it is up to the driver to
+ * wrap the device-dependent ioctls.
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * \author Kevin E. Martin <martin@valinux.com>
+ */
+
+/*
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, 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
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+ */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <string.h>
+# include <ctype.h>
+# include <fcntl.h>
+# include <errno.h>
+# include <signal.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/mman.h>
+# include <sys/time.h>
+# include <stdarg.h>
+# include "drm.h"
+
+/* Not all systems have MAP_FAILED defined */
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#include "xf86drm.h"
+
+#ifndef DRM_MAJOR
+#define DRM_MAJOR 226 /* Linux */
+#endif
+
+#ifndef __linux__
+#undef DRM_MAJOR
+#define DRM_MAJOR 145 /* Should set in drm.h for *BSD */
+#endif
+
+#ifndef DRM_MAX_MINOR
+#define DRM_MAX_MINOR 16
+#endif
+
+#ifdef __linux__
+#include <sys/sysmacros.h> /* for makedev() */
+#endif
+
+#ifndef makedev
+ /* This definition needs to be changed on
+ some systems if dev_t is a structure.
+ If there is a header file we can get it
+ from, there would be best. */
+#define makedev(x,y) ((dev_t)(((x) << 8) | (y)))
+#endif
+
+
+/**
+ * \brief Output a message to stderr.
+ *
+ * \param format printf() like format string.
+ *
+ * \internal
+ * This function is a wrapper around vfprintf().
+ */
+static void
+drmMsg(const char *format, ...)
+{
+ va_list ap;
+
+ const char *env;
+ if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose"))
+ {
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ }
+}
+
+
+
+/**
+ * \brief Open the DRM device, creating it if necessary.
+ *
+ * \param dev major and minor numbers of the device.
+ * \param minor minor number of the device.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * Assembles the device name from \p minor and opens it, creating the device
+ * special file node with the major and minor numbers specified by \p dev and
+ * parent directory if necessary and was called by root.
+ */
+static int drmOpenDevice(long dev, int minor)
+{
+ struct stat st;
+ char buf[64];
+ int fd;
+ mode_t devmode = DRM_DEV_MODE;
+ int isroot = !geteuid();
+#if defined(XFree86Server)
+ uid_t user = DRM_DEV_UID;
+ gid_t group = DRM_DEV_GID;
+#endif
+
+ drmMsg("drmOpenDevice: minor is %d\n", minor);
+
+#if defined(XFree86Server)
+ devmode = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE;
+ devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
+ group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID;
+#endif
+
+ if (stat(DRM_DIR_NAME, &st)) {
+ if (!isroot) return DRM_ERR_NOT_ROOT;
+ mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
+ chown(DRM_DIR_NAME, 0, 0); /* root:root */
+ chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
+ }
+
+ sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
+ drmMsg("drmOpenDevice: node name is %s\n", buf);
+ if (stat(buf, &st)) {
+ if (!isroot) return DRM_ERR_NOT_ROOT;
+ remove(buf);
+ mknod(buf, S_IFCHR | devmode, dev);
+ }
+#if defined(XFree86Server)
+ chown(buf, user, group);
+ chmod(buf, devmode);
+#endif
+
+ fd = open(buf, O_RDWR, 0);
+ drmMsg("drmOpenDevice: open result is %d, (%s)\n",
+ fd, fd < 0 ? strerror(errno) : "OK");
+ if (fd >= 0) return fd;
+
+ if (st.st_rdev != dev) {
+ if (!isroot) return DRM_ERR_NOT_ROOT;
+ remove(buf);
+ mknod(buf, S_IFCHR | devmode, dev);
+ }
+ fd = open(buf, O_RDWR, 0);
+ drmMsg("drmOpenDevice: open result is %d, (%s)\n",
+ fd, fd < 0 ? strerror(errno) : "OK");
+ if (fd >= 0) return fd;
+
+ drmMsg("drmOpenDevice: Open failed\n");
+ remove(buf);
+ return -errno;
+}
+
+
+/**
+ * \brief Open the DRM device
+ *
+ * \param minor device minor number.
+ * \param create allow to create the device if set.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
+ * name from \p minor and opens it.
+ */
+static int drmOpenMinor(int minor, int create)
+{
+ int fd;
+ char buf[64];
+
+ if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor);
+
+ sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
+ if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd;
+ drmMsg("drmOpenMinor: open result is %d, (%s)\n",
+ fd, fd < 0 ? strerror(errno) : "OK");
+ return -errno;
+}
+
+
+/**
+ * \brief Determine whether the DRM kernel driver has been loaded.
+ *
+ * \return 1 if the DRM driver is loaded, 0 otherwise.
+ *
+ * \internal
+ * Determine the presence of the kernel driver by attempting to open the 0
+ * minor and get version information. For backward compatibility with older
+ * Linux implementations, /proc/dri is also checked.
+ */
+int drmAvailable(void)
+{
+ drmVersionPtr version;
+ int retval = 0;
+ int fd;
+
+ if ((fd = drmOpenMinor(0, 1)) < 0) {
+ /* Try proc for backward Linux compatibility */
+ if (!access("/proc/dri/0", R_OK)) return 1;
+ return 0;
+ }
+
+ if ((version = drmGetVersion(fd))) {
+ retval = 1;
+ drmFreeVersion(version);
+ }
+ close(fd);
+ drmMsg("close %d\n", fd);
+
+ return retval;
+}
+
+
+/**
+ * \brief Open the device by bus ID.
+ *
+ * \param busid bus ID.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
+ * comparing the device bus ID with the one supplied.
+ *
+ * \sa drmOpenMinor() and drmGetBusid().
+ */
+static int drmOpenByBusid(const char *busid)
+{
+ int i;
+ int fd;
+ const char *buf;
+
+ drmMsg("drmOpenByBusid: busid is %s\n", busid);
+ for (i = 0; i < DRM_MAX_MINOR; i++) {
+ fd = drmOpenMinor(i, 1);
+ drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
+ if (fd >= 0) {
+ buf = drmGetBusid(fd);
+ drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
+ if (buf && !strcmp(buf, busid)) {
+ drmFreeBusid(buf);
+ return fd;
+ }
+ if (buf) drmFreeBusid(buf);
+ close(fd);
+ drmMsg("close %d\n", fd);
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * \brief Open the device by name.
+ *
+ * \param name driver name.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * This function opens the first minor number that matches the driver name and
+ * isn't already in use. If it's in use it then it will already have a bus ID
+ * assigned.
+ *
+ * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
+ */
+static int drmOpenByName(const char *name)
+{
+ int i;
+ int fd;
+ drmVersionPtr version;
+ char * id;
+
+ if (!drmAvailable()) {
+#if !defined(XFree86Server)
+ return -1;
+#else
+ /* try to load the kernel module now */
+ if (!xf86LoadKernelModule(name)) {
+ ErrorF("[drm] failed to load kernel module \"%s\"\n",
+ name);
+ return -1;
+ }
+#endif
+ }
+
+ for (i = 0; i < DRM_MAX_MINOR; i++) {
+ if ((fd = drmOpenMinor(i, 1)) >= 0) {
+ if ((version = drmGetVersion(fd))) {
+ if (!strcmp(version->name, name)) {
+ drmFreeVersion(version);
+
+/* return fd; */
+
+ id = drmGetBusid(fd);
+ drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
+ if (!id || !*id) {
+ if (id) {
+ drmFreeBusid(id);
+ }
+ return fd;
+ } else {
+ drmFreeBusid(id);
+ }
+ } else {
+ drmFreeVersion(version);
+ }
+ }
+ close(fd);
+ drmMsg("close %d\n", fd);
+ }
+ }
+
+ return -1;
+}
+
+
+/**
+ * \brief Open the DRM device.
+ *
+ * Looks up the specified name and bus ID, and opens the device found. The
+ * entry in /dev/dri is created if necessary and if called by root.
+ *
+ * \param name driver name. Not referenced if bus ID is supplied.
+ * \param busid bus ID. Zero if not known.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
+ * otherwise.
+ */
+int drmOpen(const char *name, const char *busid)
+{
+
+ if (busid) return drmOpenByBusid(busid);
+ return drmOpenByName(name);
+}
+
+
+/**
+ * \brief Free the version information returned by drmGetVersion().
+ *
+ * \param v pointer to the version information.
+ *
+ * \internal
+ * It frees the memory pointed by \p %v as well as all the non-null strings
+ * pointers in it.
+ */
+void drmFreeVersion(drmVersionPtr v)
+{
+ if (!v) return;
+ if (v->name) free(v->name);
+ if (v->date) free(v->date);
+ if (v->desc) free(v->desc);
+ free(v);
+}
+
+
+/**
+ * \brief Free the non-public version information returned by the kernel.
+ *
+ * \param v pointer to the version information.
+ *
+ * \internal
+ * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
+ * the non-null strings pointers in it.
+ */
+static void drmFreeKernelVersion(drm_version_t *v)
+{
+ if (!v) return;
+ if (v->name) free(v->name);
+ if (v->date) free(v->date);
+ if (v->desc) free(v->desc);
+ free(v);
+}
+
+
+/**
+ * \brief Copy version information.
+ *
+ * \param d destination pointer.
+ * \param s source pointer.
+ *
+ * \internal
+ * Used by drmGetVersion() to translate the information returned by the ioctl
+ * interface in a private structure into the public structure counterpart.
+ */
+static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
+{
+ d->version_major = s->version_major;
+ d->version_minor = s->version_minor;
+ d->version_patchlevel = s->version_patchlevel;
+ d->name_len = s->name_len;
+ d->name = strdup(s->name);
+ d->date_len = s->date_len;
+ d->date = strdup(s->date);
+ d->desc_len = s->desc_len;
+ d->desc = strdup(s->desc);
+}
+
+
+/**
+ * \brief Query the driver version information.
+ *
+ * \param fd file descriptor.
+ *
+ * \return pointer to a drmVersion structure which should be freed with
+ * drmFreeVersion().
+ *
+ * \note Similar information is available via /proc/dri.
+ *
+ * \internal
+ * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
+ * first with zeros to get the string lengths, and then the actually strings.
+ * It also null-terminates them since they might not be already.
+ */
+drmVersionPtr drmGetVersion(int fd)
+{
+ drmVersionPtr retval;
+ drm_version_t *version = malloc(sizeof(*version));
+
+ /* First, get the lengths */
+ version->name_len = 0;
+ version->name = NULL;
+ version->date_len = 0;
+ version->date = NULL;
+ version->desc_len = 0;
+ version->desc = NULL;
+
+ if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
+ drmFreeKernelVersion(version);
+ return NULL;
+ }
+
+ /* Now, allocate space and get the data */
+ if (version->name_len)
+ version->name = malloc(version->name_len + 1);
+ if (version->date_len)
+ version->date = malloc(version->date_len + 1);
+ if (version->desc_len)
+ version->desc = malloc(version->desc_len + 1);
+
+ if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
+ drmFreeKernelVersion(version);
+ return NULL;
+ }
+
+ /* The results might not be null-terminated
+ strings, so terminate them. */
+
+ if (version->name_len) version->name[version->name_len] = '\0';
+ if (version->date_len) version->date[version->date_len] = '\0';
+ if (version->desc_len) version->desc[version->desc_len] = '\0';
+
+ /* Now, copy it all back into the
+ client-visible data structure... */
+ retval = malloc(sizeof(*retval));
+ drmCopyVersion(retval, version);
+ drmFreeKernelVersion(version);
+ return retval;
+}
+
+
+/**
+ * \brief Get version information for the DRM user space library.
+ *
+ * This version number is driver independent.
+ *
+ * \param fd file descriptor.
+ *
+ * \return version information.
+ *
+ * \internal
+ * This function allocates and fills a drm_version structure with a hard coded
+ * version number.
+ */
+drmVersionPtr drmGetLibVersion(int fd)
+{
+ drm_version_t *version = malloc(sizeof(*version));
+
+ /* Version history:
+ * revision 1.0.x = original DRM interface with no drmGetLibVersion
+ * entry point and many drm<Device> extensions
+ * revision 1.1.x = added drmCommand entry points for device extensions
+ * added drmGetLibVersion to identify libdrm.a version
+ */
+ version->version_major = 1;
+ version->version_minor = 1;
+ version->version_patchlevel = 0;
+
+ return (drmVersionPtr)version;
+}
+
+
+/**
+ * \brief Free the bus ID information.
+ *
+ * \param busid bus ID information string as given by drmGetBusid().
+ *
+ * \internal
+ * This function is just frees the memory pointed by \p busid.
+ */
+void drmFreeBusid(const char *busid)
+{
+ free((void *)busid);
+}
+
+
+/**
+ * \brief Get the bus ID of the device.
+ *
+ * \param fd file descriptor.
+ *
+ * \return bus ID string.
+ *
+ * \internal
+ * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
+ * get the string length and data, passing the arguments in a drm_unique
+ * structure.
+ */
+char *drmGetBusid(int fd)
+{
+ drm_unique_t u;
+
+ u.unique_len = 0;
+ u.unique = NULL;
+
+ if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
+ u.unique = malloc(u.unique_len + 1);
+ if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
+ u.unique[u.unique_len] = '\0';
+ return u.unique;
+}
+
+
+/**
+ * \brief Set the bus ID of the device.
+ *
+ * \param fd file descriptor.
+ * \param busid bus ID string.
+ *
+ * \return zero on success, negative on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
+ * the arguments in a drm_unique structure.
+ */
+int drmSetBusid(int fd, const char *busid)
+{
+ drm_unique_t u;
+
+ u.unique = (char *)busid;
+ u.unique_len = strlen(busid);
+
+ if (ioctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Specifies a range of memory that is available for mapping by a
+ * non-root process.
+ *
+ * \param fd file descriptor.
+ * \param offset usually the physical address. The actual meaning depends of
+ * the \p type parameter. See below.
+ * \param size of the memory in bytes.
+ * \param type type of the memory to be mapped.
+ * \param flags combination of several flags to modify the function actions.
+ * \param handle will be set to a value that may be used as the offset
+ * parameter for mmap().
+ *
+ * \return zero on success or a negative value on error.
+ *
+ * \par Mapping the frame buffer
+ * For the frame buffer
+ * - \p offset will be the physical address of the start of the frame buffer,
+ * - \p size will be the size of the frame buffer in bytes, and
+ * - \p type will be DRM_FRAME_BUFFER.
+ *
+ * \par
+ * The area mapped will be uncached. If MTRR support is available in the
+ * kernel, the frame buffer area will be set to write combining.
+ *
+ * \par Mapping the MMIO register area
+ * For the MMIO register area,
+ * - \p offset will be the physical address of the start of the register area,
+ * - \p size will be the size of the register area bytes, and
+ * - \p type will be DRM_REGISTERS.
+ * \par
+ * The area mapped will be uncached.
+ *
+ * \par Mapping the SAREA
+ * For the SAREA,
+ * - \p offset will be ignored and should be set to zero,
+ * - \p size will be the desired size of the SAREA in bytes,
+ * - \p type will be DRM_SHM.
+ *
+ * \par
+ * A shared memory area of the requested size will be created and locked in
+ * kernel memory. This area may be mapped into client-space by using the handle
+ * returned.
+ *
+ * \note May only be called by root.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
+ * the arguments in a drm_map structure.
+ */
+int drmAddMap(int fd,
+ drmHandle offset,
+ drmSize size,
+ drmMapType type,
+ drmMapFlags flags,
+ drmHandlePtr handle)
+{
+ drm_map_t map;
+
+ map.offset = offset;
+ map.size = size;
+ map.handle = 0;
+ map.type = type;
+ map.flags = flags;
+ if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno;
+ if (handle) *handle = (drmHandle)map.handle;
+ return 0;
+}
+
+
+/**
+ * \brief Make buffers available for DMA transfers.
+ *
+ * \param fd file descriptor.
+ * \param count number of buffers.
+ * \param size size of each buffer.
+ * \param flags buffer allocation flags.
+ * \param agp_offset offset in the AGP aperture
+ *
+ * \return number of buffers allocated, negative on error.
+ *
+ * \internal
+ * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
+ *
+ * \sa drm_buf_desc.
+ */
+int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
+ int agp_offset)
+{
+ drm_buf_desc_t request;
+
+ request.count = count;
+ request.size = size;
+ request.low_mark = 0;
+ request.high_mark = 0;
+ request.flags = flags;
+ request.agp_start = agp_offset;
+
+ if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno;
+ return request.count;
+}
+
+
+/**
+ * \brief Free buffers.
+ *
+ * \param fd file descriptor.
+ * \param count number of buffers to free.
+ * \param list list of buffers to be freed.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \note This function is primarily used for debugging.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
+ * the arguments in a drm_buf_free structure.
+ */
+int drmFreeBufs(int fd, int count, int *list)
+{
+ drm_buf_free_t request;
+
+ request.count = count;
+ request.list = list;
+ if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Close the device.
+ *
+ * \param fd file descriptor.
+ *
+ * \internal
+ * This function closes the file descriptor.
+ */
+int drmClose(int fd)
+{
+ drmMsg("close %d\n", fd);
+ return close(fd);
+}
+
+
+/**
+ * \brief Map a region of memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle returned by drmAddMap().
+ * \param size size in bytes. Must match the size used by drmAddMap().
+ * \param address will contain the user-space virtual address where the mapping
+ * begins.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper for mmap().
+ */
+int drmMap(int fd,
+ drmHandle handle,
+ drmSize size,
+ drmAddressPtr address)
+{
+ static unsigned long pagesize_mask = 0;
+
+ if (fd < 0) return -EINVAL;
+
+ if (!pagesize_mask)
+ pagesize_mask = getpagesize() - 1;
+
+ size = (size + pagesize_mask) & ~pagesize_mask;
+
+ *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
+ if (*address == MAP_FAILED) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Unmap mappings obtained with drmMap().
+ *
+ * \param address address as given by drmMap().
+ * \param size size in bytes. Must match the size used by drmMap().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper for unmap().
+ */
+int drmUnmap(drmAddress address, drmSize size)
+{
+ return munmap(address, size);
+}
+
+
+/**
+ * \brief Map all DMA buffers into client-virtual space.
+ *
+ * \param fd file descriptor.
+ *
+ * \return a pointer to a ::drmBufMap structure.
+ *
+ * \note The client may not use these buffers until obtaining buffer indices
+ * with drmDMA().
+ *
+ * \internal
+ * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
+ * information about the buffers in a drm_buf_map structure into the
+ * client-visible data structures.
+ */
+drmBufMapPtr drmMapBufs(int fd)
+{
+ drm_buf_map_t bufs;
+ drmBufMapPtr retval;
+ int i;
+
+ bufs.count = 0;
+ bufs.list = NULL;
+ if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL;
+
+ if (bufs.count) {
+ if (!(bufs.list = malloc(bufs.count * sizeof(*bufs.list))))
+ return NULL;
+
+ if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
+ free(bufs.list);
+ return NULL;
+ }
+ /* Now, copy it all back into the
+ client-visible data structures... */
+ retval = malloc(sizeof(*retval));
+ retval->count = bufs.count;
+ retval->list = malloc(bufs.count * sizeof(*retval->list));
+ for (i = 0; i < bufs.count; i++) {
+ retval->list[i].idx = bufs.list[i].idx;
+ retval->list[i].total = bufs.list[i].total;
+ retval->list[i].used = 0;
+ retval->list[i].address = bufs.list[i].address;
+ }
+ return retval;
+ }
+ return NULL;
+}
+
+
+/**
+ * \brief Unmap buffers allocated with drmMapBufs().
+ *
+ * \return zero on success, or negative value on failure.
+ *
+ * \internal
+ * Calls munmap() for every buffer stored in \p bufs.
+ */
+int drmUnmapBufs(drmBufMapPtr bufs)
+{
+ int i;
+
+ for (i = 0; i < bufs->count; i++) {
+ munmap(bufs->list[i].address, bufs->list[i].total);
+ }
+ return 0;
+}
+
+
+#define DRM_DMA_RETRY 16
+
+/**
+ * \brief Reserve DMA buffers.
+ *
+ * \param fd file descriptor.
+ * \param request
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * Assemble the arguments into a drm_dma structure and keeps issuing the
+ * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
+ */
+int drmDMA(int fd, drmDMAReqPtr request)
+{
+ drm_dma_t dma;
+ int ret, i = 0;
+
+ /* Copy to hidden structure */
+ dma.context = request->context;
+ dma.send_count = request->send_count;
+ dma.send_indices = request->send_list;
+ dma.send_sizes = request->send_sizes;
+ dma.flags = request->flags;
+ dma.request_count = request->request_count;
+ dma.request_size = request->request_size;
+ dma.request_indices = request->request_list;
+ dma.request_sizes = request->request_sizes;
+
+ do {
+ ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
+ } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
+
+ if ( ret == 0 ) {
+ request->granted_count = dma.granted_count;
+ return 0;
+ } else {
+ return -errno;
+ }
+}
+
+
+/**
+ * \brief Obtain heavyweight hardware lock.
+ *
+ * \param fd file descriptor.
+ * \param context context.
+ * \param flags flags that determine the sate of the hardware when the function
+ * returns.
+ *
+ * \return always zero.
+ *
+ * \internal
+ * This function translates the arguments into a drm_lock structure and issue
+ * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
+ */
+int drmGetLock(int fd, drmContext context, drmLockFlags flags)
+{
+ drm_lock_t lock;
+
+ lock.context = context;
+ lock.flags = 0;
+ if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
+ if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
+ if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
+ if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
+ if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
+ if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
+
+ while (ioctl(fd, DRM_IOCTL_LOCK, &lock))
+ ;
+ return 0;
+}
+
+static void (*drm_unlock_callback)( void ) = 0;
+
+/**
+ * \brief Release the hardware lock.
+ *
+ * \param fd file descriptor.
+ * \param context context.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
+ * argument in a drm_lock structure.
+ */
+int drmUnlock(int fd, drmContext context)
+{
+ drm_lock_t lock;
+ int ret;
+
+ lock.context = context;
+ lock.flags = 0;
+ ret = ioctl(fd, DRM_IOCTL_UNLOCK, &lock);
+
+ /* Need this to synchronize vt releasing. Could also teach fbdev
+ * about the drm lock...
+ */
+ if (drm_unlock_callback) {
+ drm_unlock_callback();
+ }
+
+ return ret;
+}
+
+
+/**
+ * \brief Create context.
+ *
+ * Used by the X server during GLXContext initialization. This causes
+ * per-context kernel-level resources to be allocated.
+ *
+ * \param fd file descriptor.
+ * \param handle is set on success. To be used by the client when requesting DMA
+ * dispatch with drmDMA().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \note May only be called by root.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
+ * argument in a drm_ctx structure.
+ */
+int drmCreateContext(int fd, drmContextPtr handle)
+{
+ drm_ctx_t ctx;
+
+ ctx.flags = 0; /* Modified with functions below */
+ if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno;
+ *handle = ctx.handle;
+ return 0;
+}
+
+
+/**
+ * \brief Destroy context.
+ *
+ * Free any kernel-level resources allocated with drmCreateContext() associated
+ * with the context.
+ *
+ * \param fd file descriptor.
+ * \param handle handle given by drmCreateContext().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \note May only be called by root.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
+ * argument in a drm_ctx structure.
+ */
+int drmDestroyContext(int fd, drmContext handle)
+{
+ drm_ctx_t ctx;
+ ctx.handle = handle;
+ if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Acquire the AGP device.
+ *
+ * Must be called before any of the other AGP related calls.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
+ */
+int drmAgpAcquire(int fd)
+{
+ if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Release the AGP device.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
+ */
+int drmAgpRelease(int fd)
+{
+ if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Set the AGP mode.
+ *
+ * \param fd file descriptor.
+ * \param mode AGP mode.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
+ * argument in a drm_agp_mode structure.
+ */
+int drmAgpEnable(int fd, unsigned long mode)
+{
+ drm_agp_mode_t m;
+
+ m.mode = mode;
+ if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Allocate a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param size requested memory size in bytes. Will be rounded to page boundary.
+ * \param type type of memory to allocate.
+ * \param address if not zero, will be set to the physical address of the
+ * allocated memory.
+ * \param handle on success will be set to a handle of the allocated memory.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
+ * arguments in a drm_agp_buffer structure.
+ */
+int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
+ unsigned long *address, unsigned long *handle)
+{
+ drm_agp_buffer_t b;
+ *handle = 0;
+ b.size = size;
+ b.handle = 0;
+ b.type = type;
+ if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno;
+ if (address != 0UL) *address = b.physical;
+ *handle = b.handle;
+ return 0;
+}
+
+
+/**
+ * \brief Free a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle to the allocated memory, as given by drmAgpAllocate().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
+ * argument in a drm_agp_buffer structure.
+ */
+int drmAgpFree(int fd, unsigned long handle)
+{
+ drm_agp_buffer_t b;
+
+ b.size = 0;
+ b.handle = handle;
+ if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Bind a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle to the allocated memory, as given by drmAgpAllocate().
+ * \param offset offset in bytes. It will round to page boundary.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
+ * argument in a drm_agp_binding structure.
+ */
+int drmAgpBind(int fd, unsigned long handle, unsigned long offset)
+{
+ drm_agp_binding_t b;
+
+ b.handle = handle;
+ b.offset = offset;
+ if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Unbind a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle to the allocated memory, as given by drmAgpAllocate().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
+ * the argument in a drm_agp_binding structure.
+ */
+int drmAgpUnbind(int fd, unsigned long handle)
+{
+ drm_agp_binding_t b;
+
+ b.handle = handle;
+ b.offset = 0;
+ if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Get AGP driver major version number.
+ *
+ * \param fd file descriptor.
+ *
+ * \return major version number on success, or a negative value on failure..
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+int drmAgpVersionMajor(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
+ return i.agp_version_major;
+}
+
+
+/**
+ * \brief Get AGP driver minor version number.
+ *
+ * \param fd file descriptor.
+ *
+ * \return minor version number on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+int drmAgpVersionMinor(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
+ return i.agp_version_minor;
+}
+
+
+/**
+ * \brief Get AGP mode.
+ *
+ * \param fd file descriptor.
+ *
+ * \return mode on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpGetMode(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.mode;
+}
+
+
+/**
+ * \brief Get AGP aperture base.
+ *
+ * \param fd file descriptor.
+ *
+ * \return aperture base on success, zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpBase(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.aperture_base;
+}
+
+
+/**
+ * \brief Get AGP aperture size.
+ *
+ * \param fd file descriptor.
+ *
+ * \return aperture size on success, zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpSize(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.aperture_size;
+}
+
+
+/**
+ * \brief Get used AGP memory.
+ *
+ * \param fd file descriptor.
+ *
+ * \return memory used on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpMemoryUsed(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.memory_used;
+}
+
+
+/**
+ * \brief Get available AGP memory.
+ *
+ * \param fd file descriptor.
+ *
+ * \return memory available on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpMemoryAvail(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.memory_allowed;
+}
+
+
+/**
+ * \brief Get hardware vendor ID.
+ *
+ * \param fd file descriptor.
+ *
+ * \return vendor ID on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned int drmAgpVendorId(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.id_vendor;
+}
+
+
+/**
+ * \brief Get hardware device ID.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned int drmAgpDeviceId(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.id_device;
+}
+
+int drmScatterGatherAlloc(int fd, unsigned long size, unsigned long *handle)
+{
+ drm_scatter_gather_t sg;
+
+ *handle = 0;
+ sg.size = size;
+ sg.handle = 0;
+ if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno;
+ *handle = sg.handle;
+ return 0;
+}
+
+int drmScatterGatherFree(int fd, unsigned long handle)
+{
+ drm_scatter_gather_t sg;
+
+ sg.size = 0;
+ sg.handle = handle;
+ if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno;
+ return 0;
+}
+
+/**
+ * \brief Wait for VBLANK.
+ *
+ * \param fd file descriptor.
+ * \param vbl pointer to a drmVBlank structure.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
+ */
+int drmWaitVBlank(int fd, drmVBlankPtr vbl)
+{
+ int ret;
+
+ do {
+ ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
+ } while (ret && errno == EINTR);
+
+ return ret;
+}
+
+
+/**
+ * \brief Install IRQ handler.
+ *
+ * \param fd file descriptor.
+ * \param irq IRQ number.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
+ * argument in a drm_control structure.
+ */
+int drmCtlInstHandler(int fd, int irq)
+{
+ drm_control_t ctl;
+
+ ctl.func = DRM_INST_HANDLER;
+ ctl.irq = irq;
+ if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Uninstall IRQ handler.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
+ * argument in a drm_control structure.
+ */
+int drmCtlUninstHandler(int fd)
+{
+ drm_control_t ctl;
+
+ ctl.func = DRM_UNINST_HANDLER;
+ ctl.irq = 0;
+ if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Get IRQ from bus ID.
+ *
+ * \param fd file descriptor.
+ * \param busnum bus number.
+ * \param devnum device number.
+ * \param funcnum function number.
+ *
+ * \return IRQ number on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
+ * arguments in a drm_irq_busid structure.
+ */
+int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
+{
+ drm_irq_busid_t p;
+
+ p.busnum = busnum;
+ p.devnum = devnum;
+ p.funcnum = funcnum;
+ if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno;
+ return p.irq;
+}
+
+
+/**
+ * \brief Send a device-specific command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandNone(int fd, unsigned long drmCommandIndex)
+{
+ void *data = NULL; /* dummy */
+ unsigned long request;
+
+ request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Send a device-specific read command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ * \param data destination pointer of the data to be read.
+ * \param size size of the data to be read.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a read ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size )
+{
+ unsigned long request;
+
+ request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
+ DRM_COMMAND_BASE + drmCommandIndex, size);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Send a device-specific write command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ * \param data source pointer of the data to be written.
+ * \param size size of the data to be written.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a write ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandWrite(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size )
+{
+ unsigned long request;
+
+ request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
+ DRM_COMMAND_BASE + drmCommandIndex, size);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Send a device-specific read-write command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ * \param data source pointer of the data to be read and written.
+ * \param size size of the data to be read and written.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a read-write ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size )
+{
+ unsigned long request;
+
+ request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
+ DRM_COMMAND_BASE + drmCommandIndex, size);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
diff --git a/src/glx/mini/xf86drm.h b/src/glx/mini/xf86drm.h
new file mode 100644
index 0000000000..cee5ca5f69
--- /dev/null
+++ b/src/glx/mini/xf86drm.h
@@ -0,0 +1,609 @@
+/* xf86drm.h -- OS-independent header for DRM user-level library interface
+ * Created: Tue Jan 5 08:17:23 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, 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
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+ *
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h,v 1.22 2003/06/12 14:12:35 eich Exp $
+ *
+ */
+
+#ifndef _XF86DRM_H_
+#define _XF86DRM_H_
+
+ /* Defaults, if nothing set in xf86config */
+#define DRM_DEV_UID 0
+#define DRM_DEV_GID 0
+/* Default /dev/dri directory permissions 0755 */
+#define DRM_DEV_DIRMODE \
+ (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+
+#define DRM_DIR_NAME "/dev/dri"
+#define DRM_DEV_NAME "%s/card%d"
+#define DRM_PROC_NAME "/proc/dri/" /* For backware Linux compatibility */
+
+#define DRM_ERR_NO_DEVICE (-1001)
+#define DRM_ERR_NO_ACCESS (-1002)
+#define DRM_ERR_NOT_ROOT (-1003)
+#define DRM_ERR_INVALID (-1004)
+#define DRM_ERR_NO_FD (-1005)
+
+#define DRM_AGP_NO_HANDLE 0
+
+typedef unsigned long drmHandle, *drmHandlePtr; /* To mapped regions */
+typedef unsigned int drmSize, *drmSizePtr; /* For mapped regions */
+typedef void *drmAddress, **drmAddressPtr; /* For mapped regions */
+typedef unsigned int drmContext, *drmContextPtr; /* GLXContext handle */
+typedef unsigned int drmDrawable, *drmDrawablePtr; /* Unused */
+typedef unsigned int drmMagic, *drmMagicPtr; /* Magic for auth */
+
+typedef struct _drmVersion {
+ int version_major; /* Major version */
+ int version_minor; /* Minor version */
+ int version_patchlevel; /* Patch level */
+ int name_len; /* Length of name buffer */
+ char *name; /* Name of driver */
+ int date_len; /* Length of date buffer */
+ char *date; /* User-space buffer to hold date */
+ int desc_len; /* Length of desc buffer */
+ char *desc; /* User-space buffer to hold desc */
+} drmVersion, *drmVersionPtr;
+
+typedef struct _drmStats {
+ unsigned long count; /* Number of data */
+ struct {
+ unsigned long value; /* Value from kernel */
+ const char *long_format; /* Suggested format for long_name */
+ const char *long_name; /* Long name for value */
+ const char *rate_format; /* Suggested format for rate_name */
+ const char *rate_name; /* Short name for value per second */
+ int isvalue; /* True if value (vs. counter) */
+ const char *mult_names; /* Multiplier names (e.g., "KGM") */
+ int mult; /* Multiplier value (e.g., 1024) */
+ int verbose; /* Suggest only in verbose output */
+ } data[15];
+} drmStatsT;
+
+
+ /* All of these enums *MUST* match with the
+ kernel implementation -- so do *NOT*
+ change them! (The drmlib implementation
+ will just copy the flags instead of
+ translating them.) */
+typedef enum {
+ DRM_FRAME_BUFFER = 0, /* WC, no caching, no core dump */
+ DRM_REGISTERS = 1, /* no caching, no core dump */
+ DRM_SHM = 2, /* shared, cached */
+ DRM_AGP = 3, /* AGP/GART */
+ DRM_SCATTER_GATHER = 4 /* PCI scatter/gather */
+} drmMapType;
+
+typedef enum {
+ DRM_RESTRICTED = 0x0001, /* Cannot be mapped to client-virtual */
+ DRM_READ_ONLY = 0x0002, /* Read-only in client-virtual */
+ DRM_LOCKED = 0x0004, /* Physical pages locked */
+ DRM_KERNEL = 0x0008, /* Kernel requires access */
+ DRM_WRITE_COMBINING = 0x0010, /* Use write-combining, if available */
+ DRM_CONTAINS_LOCK = 0x0020, /* SHM page that contains lock */
+ DRM_REMOVABLE = 0x0040 /* Removable mapping */
+} drmMapFlags;
+
+typedef enum { /* These values *MUST* match drm.h */
+ /* Flags for DMA buffer dispatch */
+ DRM_DMA_BLOCK = 0x01, /* Block until buffer dispatched. Note,
+ the buffer may not yet have been
+ processed by the hardware -- getting a
+ hardware lock with the hardware
+ quiescent will ensure that the buffer
+ has been processed. */
+ DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held */
+ DRM_DMA_PRIORITY = 0x04, /* High priority dispatch */
+
+ /* Flags for DMA buffer request */
+ DRM_DMA_WAIT = 0x10, /* Wait for free buffers */
+ DRM_DMA_SMALLER_OK = 0x20, /* Smaller-than-requested buffers ok */
+ DRM_DMA_LARGER_OK = 0x40 /* Larger-than-requested buffers ok */
+} drmDMAFlags;
+
+typedef enum {
+ DRM_PAGE_ALIGN = 0x01,
+ DRM_AGP_BUFFER = 0x02,
+ DRM_SG_BUFFER = 0x04
+} drmBufDescFlags;
+
+typedef enum {
+ DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */
+ DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */
+ DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */
+ DRM_LOCK_FLUSH_ALL = 0x08, /* Flush all DMA queues first */
+ /* These *HALT* flags aren't supported yet
+ -- they will be used to support the
+ full-screen DGA-like mode. */
+ DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues */
+ DRM_HALT_CUR_QUEUES = 0x20 /* Halt all current queues */
+} drmLockFlags;
+
+typedef enum {
+ DRM_CONTEXT_PRESERVED = 0x01, /* This context is preserved and
+ never swapped. */
+ DRM_CONTEXT_2DONLY = 0x02 /* This context is for 2D rendering only. */
+} drmContextFlags, *drmContextFlagsPtr;
+
+typedef struct _drmBufDesc {
+ int count; /* Number of buffers of this size */
+ int size; /* Size in bytes */
+ int low_mark; /* Low water mark */
+ int high_mark; /* High water mark */
+} drmBufDesc, *drmBufDescPtr;
+
+typedef struct _drmBufInfo {
+ int count; /* Number of buffers described in list */
+ drmBufDescPtr list; /* List of buffer descriptions */
+} drmBufInfo, *drmBufInfoPtr;
+
+typedef struct _drmBuf {
+ int idx; /* Index into master buflist */
+ int total; /* Buffer size */
+ int used; /* Amount of buffer in use (for DMA) */
+ drmAddress address; /* Address */
+} drmBuf, *drmBufPtr;
+
+typedef struct _drmBufMap {
+ int count; /* Number of buffers mapped */
+ drmBufPtr list; /* Buffers */
+} drmBufMap, *drmBufMapPtr;
+
+typedef struct _drmLock {
+ volatile unsigned int lock;
+ char padding[60];
+ /* This is big enough for most current (and future?) architectures:
+ DEC Alpha: 32 bytes
+ Intel Merced: ?
+ Intel P5/PPro/PII/PIII: 32 bytes
+ Intel StrongARM: 32 bytes
+ Intel i386/i486: 16 bytes
+ MIPS: 32 bytes (?)
+ Motorola 68k: 16 bytes
+ Motorola PowerPC: 32 bytes
+ Sun SPARC: 32 bytes
+ */
+} drmLock, *drmLockPtr;
+
+typedef struct _drmDMAReq {
+ /* Indices here refer to the offset into
+ list in drmBufInfo */
+ drmContext context; /* Context handle */
+ int send_count; /* Number of buffers to send */
+ int *send_list; /* List of handles to buffers */
+ int *send_sizes; /* Lengths of data to send, in bytes */
+ drmDMAFlags flags; /* Flags */
+ int request_count; /* Number of buffers requested */
+ int request_size; /* Desired size of buffers requested */
+ int *request_list; /* Buffer information */
+ int *request_sizes; /* Minimum acceptable sizes */
+ int granted_count; /* Number of buffers granted at this size */
+} drmDMAReq, *drmDMAReqPtr;
+
+typedef struct _drmRegion {
+ drmHandle handle;
+ unsigned int offset;
+ drmSize size;
+ drmAddress map;
+} drmRegion, *drmRegionPtr;
+
+typedef struct _drmTextureRegion {
+ unsigned char next;
+ unsigned char prev;
+ unsigned char in_use;
+ unsigned char padding; /* Explicitly pad this out */
+ unsigned int age;
+} drmTextureRegion, *drmTextureRegionPtr;
+
+
+typedef struct _drmClipRect {
+ unsigned short x1; /* Upper left: inclusive */
+ unsigned short y1;
+ unsigned short x2; /* Lower right: exclusive */
+ unsigned short y2;
+} drmClipRect, *drmClipRectPtr;
+
+
+typedef enum {
+ DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
+ DRM_VBLANK_RELATIVE = 0x1, /* Wait for given number of vblanks */
+ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */
+} drmVBlankSeqType;
+
+typedef struct _drmVBlankReq {
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ unsigned long signal;
+} drmVBlankReq, *drmVBlankReqPtr;
+
+typedef struct _drmVBlankReply {
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+} drmVBlankReply, *drmVBlankReplyPtr;
+
+typedef union _drmVBlank {
+ drmVBlankReq request;
+ drmVBlankReply reply;
+} drmVBlank, *drmVBlankPtr;
+
+
+
+#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock)
+
+#define DRM_LOCK_HELD 0x80000000 /* Hardware lock is held */
+#define DRM_LOCK_CONT 0x40000000 /* Hardware lock is contended */
+
+#if defined(__GNUC__) && (__GNUC__ >= 2)
+# if defined(__i386) || defined(__AMD64__)
+ /* Reflect changes here to drmP.h */
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ int __dummy; /* Can't mark eax as clobbered */ \
+ __asm__ __volatile__( \
+ "lock ; cmpxchg %4,%1\n\t" \
+ "setnz %0" \
+ : "=d" (__ret), \
+ "=m" (__drm_dummy_lock(lock)), \
+ "=a" (__dummy) \
+ : "2" (old), \
+ "r" (new)); \
+ } while (0)
+
+#elif defined(__alpha__)
+
+#define DRM_CAS(lock, old, new, ret) \
+ do { \
+ int old32; \
+ int cur32; \
+ __asm__ __volatile__( \
+ " mb\n" \
+ " zap %4, 0xF0, %0\n" \
+ " ldl_l %1, %2\n" \
+ " zap %1, 0xF0, %1\n" \
+ " cmpeq %0, %1, %1\n" \
+ " beq %1, 1f\n" \
+ " bis %5, %5, %1\n" \
+ " stl_c %1, %2\n" \
+ "1: xor %1, 1, %1\n" \
+ " stl %1, %3" \
+ : "+r" (old32), \
+ "+&r" (cur32), \
+ "=m" (__drm_dummy_lock(lock)),\
+ "=m" (ret) \
+ : "r" (old), \
+ "r" (new)); \
+ } while(0)
+
+#elif defined(__sparc__)
+
+#define DRM_CAS(lock,old,new,__ret) \
+do { register unsigned int __old __asm("o0"); \
+ register unsigned int __new __asm("o1"); \
+ register volatile unsigned int *__lock __asm("o2"); \
+ __old = old; \
+ __new = new; \
+ __lock = (volatile unsigned int *)lock; \
+ __asm__ __volatile__( \
+ /*"cas [%2], %3, %0"*/ \
+ ".word 0xd3e29008\n\t" \
+ /*"membar #StoreStore | #StoreLoad"*/ \
+ ".word 0x8143e00a" \
+ : "=&r" (__new) \
+ : "0" (__new), \
+ "r" (__lock), \
+ "r" (__old) \
+ : "memory"); \
+ __ret = (__new != __old); \
+} while(0)
+
+#elif defined(__ia64__)
+
+#if 0
+/* this currently generates bad code (missing stop bits)... */
+#include <ia64intrin.h>
+
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ __ret = (__sync_val_compare_and_swap(&__drm_dummy_lock(lock), \
+ (old), (new)) \
+ != (old)); \
+ } while (0)
+
+#else
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ unsigned int __result, __old = (old); \
+ __asm__ __volatile__( \
+ "mf\n" \
+ "mov ar.ccv=%2\n" \
+ ";;\n" \
+ "cmpxchg4.acq %0=%1,%3,ar.ccv" \
+ : "=r" (__result), "=m" (__drm_dummy_lock(lock)) \
+ : "r" (__old), "r" (new) \
+ : "memory"); \
+ __ret = (__result) != (__old); \
+ } while (0)
+
+#endif
+
+#elif defined(__powerpc__)
+
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ __asm__ __volatile__( \
+ "sync;" \
+ "0: lwarx %0,0,%1;" \
+ " xor. %0,%3,%0;" \
+ " bne 1f;" \
+ " stwcx. %2,0,%1;" \
+ " bne- 0b;" \
+ "1: " \
+ "sync;" \
+ : "=&r"(__ret) \
+ : "r"(lock), "r"(new), "r"(old) \
+ : "cr0", "memory"); \
+ } while (0)
+
+#endif /* architecture */
+#endif /* __GNUC__ >= 2 */
+
+#ifndef DRM_CAS
+#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */
+#endif
+
+#if defined(__alpha__) || defined(__powerpc__)
+#define DRM_CAS_RESULT(_result) int _result
+#else
+#define DRM_CAS_RESULT(_result) char _result
+#endif
+
+#define DRM_LIGHT_LOCK(fd,lock,context) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \
+ if (__ret) drmGetLock(fd,context,0); \
+ } while(0)
+
+ /* This one counts fast locks -- for
+ benchmarking only. */
+#define DRM_LIGHT_LOCK_COUNT(fd,lock,context,count) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \
+ if (__ret) drmGetLock(fd,context,0); \
+ else ++count; \
+ } while(0)
+
+#define DRM_LOCK(fd,lock,context,flags) \
+ do { \
+ if (flags) drmGetLock(fd,context,flags); \
+ else DRM_LIGHT_LOCK(fd,lock,context); \
+ } while(0)
+
+#define DRM_UNLOCK(fd,lock,context) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ DRM_CAS(lock,DRM_LOCK_HELD|context,context,__ret); \
+ if (__ret) drmUnlock(fd,context); \
+ } while(0)
+
+ /* Simple spin locks */
+#define DRM_SPINLOCK(spin,val) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ do { \
+ DRM_CAS(spin,0,val,__ret); \
+ if (__ret) while ((spin)->lock); \
+ } while (__ret); \
+ } while(0)
+
+#define DRM_SPINLOCK_TAKE(spin,val) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ int cur; \
+ do { \
+ cur = (*spin).lock; \
+ DRM_CAS(spin,cur,val,__ret); \
+ } while (__ret); \
+ } while(0)
+
+#define DRM_SPINLOCK_COUNT(spin,val,count,__ret) \
+ do { \
+ int __i; \
+ __ret = 1; \
+ for (__i = 0; __ret && __i < count; __i++) { \
+ DRM_CAS(spin,0,val,__ret); \
+ if (__ret) for (;__i < count && (spin)->lock; __i++); \
+ } \
+ } while(0)
+
+#define DRM_SPINUNLOCK(spin,val) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ if ((*spin).lock == val) { /* else server stole lock */ \
+ do { \
+ DRM_CAS(spin,val,0,__ret); \
+ } while (__ret); \
+ } \
+ } while(0)
+
+/* General user-level programmer's API: unprivileged */
+extern int drmAvailable(void);
+extern int drmOpen(const char *name, const char *busid);
+extern int drmClose(int fd);
+extern drmVersionPtr drmGetVersion(int fd);
+extern drmVersionPtr drmGetLibVersion(int fd);
+extern void drmFreeVersion(drmVersionPtr);
+extern int drmGetMagic(int fd, drmMagicPtr magic);
+extern char *drmGetBusid(int fd);
+extern int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
+ int funcnum);
+extern int drmGetMap(int fd, int idx, drmHandle *offset,
+ drmSize *size, drmMapType *type,
+ drmMapFlags *flags, drmHandle *handle,
+ int *mtrr);
+extern int drmGetClient(int fd, int idx, int *auth, int *pid,
+ int *uid, unsigned long *magic,
+ unsigned long *iocs);
+extern int drmGetStats(int fd, drmStatsT *stats);
+extern int drmCommandNone(int fd, unsigned long drmCommandIndex);
+extern int drmCommandRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size);
+extern int drmCommandWrite(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size);
+extern int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size);
+
+/* General user-level programmer's API: X server (root) only */
+extern void drmFreeBusid(const char *busid);
+extern int drmSetBusid(int fd, const char *busid);
+extern int drmAuthMagic(int fd, drmMagic magic);
+extern int drmAddMap(int fd,
+ drmHandle offset,
+ drmSize size,
+ drmMapType type,
+ drmMapFlags flags,
+ drmHandlePtr handle);
+extern int drmRmMap(int fd, drmHandle handle);
+extern int drmAddContextPrivateMapping(int fd, drmContext ctx_id,
+ drmHandle handle);
+
+extern int drmAddBufs(int fd, int count, int size,
+ drmBufDescFlags flags,
+ int agp_offset);
+extern int drmMarkBufs(int fd, double low, double high);
+extern int drmCreateContext(int fd, drmContextPtr handle);
+extern int drmSetContextFlags(int fd, drmContext context,
+ drmContextFlags flags);
+extern int drmGetContextFlags(int fd, drmContext context,
+ drmContextFlagsPtr flags);
+extern int drmAddContextTag(int fd, drmContext context, void *tag);
+extern int drmDelContextTag(int fd, drmContext context);
+extern void *drmGetContextTag(int fd, drmContext context);
+extern drmContextPtr drmGetReservedContextList(int fd, int *count);
+extern void drmFreeReservedContextList(drmContextPtr);
+extern int drmSwitchToContext(int fd, drmContext context);
+extern int drmDestroyContext(int fd, drmContext handle);
+extern int drmCreateDrawable(int fd, drmDrawablePtr handle);
+extern int drmDestroyDrawable(int fd, drmDrawable handle);
+extern int drmCtlInstHandler(int fd, int irq);
+extern int drmCtlUninstHandler(int fd);
+extern int drmInstallSIGIOHandler(int fd,
+ void (*f)(int fd,
+ void *oldctx,
+ void *newctx));
+extern int drmRemoveSIGIOHandler(int fd);
+
+/* General user-level programmer's API: authenticated client and/or X */
+extern int drmMap(int fd,
+ drmHandle handle,
+ drmSize size,
+ drmAddressPtr address);
+extern int drmUnmap(drmAddress address, drmSize size);
+extern drmBufInfoPtr drmGetBufInfo(int fd);
+extern drmBufMapPtr drmMapBufs(int fd);
+extern int drmUnmapBufs(drmBufMapPtr bufs);
+extern int drmDMA(int fd, drmDMAReqPtr request);
+extern int drmFreeBufs(int fd, int count, int *list);
+extern int drmGetLock(int fd,
+ drmContext context,
+ drmLockFlags flags);
+extern int drmUnlock(int fd, drmContext context);
+extern int drmFinish(int fd, int context, drmLockFlags flags);
+extern int drmGetContextPrivateMapping(int fd, drmContext ctx_id,
+ drmHandlePtr handle);
+
+/* AGP/GART support: X server (root) only */
+extern int drmAgpAcquire(int fd);
+extern int drmAgpRelease(int fd);
+extern int drmAgpEnable(int fd, unsigned long mode);
+extern int drmAgpAlloc(int fd, unsigned long size,
+ unsigned long type, unsigned long *address,
+ unsigned long *handle);
+extern int drmAgpFree(int fd, unsigned long handle);
+extern int drmAgpBind(int fd, unsigned long handle,
+ unsigned long offset);
+extern int drmAgpUnbind(int fd, unsigned long handle);
+
+/* AGP/GART info: authenticated client and/or X */
+extern int drmAgpVersionMajor(int fd);
+extern int drmAgpVersionMinor(int fd);
+extern unsigned long drmAgpGetMode(int fd);
+extern unsigned long drmAgpBase(int fd); /* Physical location */
+extern unsigned long drmAgpSize(int fd); /* Bytes */
+extern unsigned long drmAgpMemoryUsed(int fd);
+extern unsigned long drmAgpMemoryAvail(int fd);
+extern unsigned int drmAgpVendorId(int fd);
+extern unsigned int drmAgpDeviceId(int fd);
+
+/* PCI scatter/gather support: X server (root) only */
+extern int drmScatterGatherAlloc(int fd, unsigned long size,
+ unsigned long *handle);
+extern int drmScatterGatherFree(int fd, unsigned long handle);
+
+extern int drmWaitVBlank(int fd, drmVBlankPtr vbl);
+
+/* Support routines */
+extern int drmError(int err, const char *label);
+extern void *drmMalloc(int size);
+extern void drmFree(void *pt);
+
+/* Hash table routines */
+extern void *drmHashCreate(void);
+extern int drmHashDestroy(void *t);
+extern int drmHashLookup(void *t, unsigned long key, void **value);
+extern int drmHashInsert(void *t, unsigned long key, void *value);
+extern int drmHashDelete(void *t, unsigned long key);
+extern int drmHashFirst(void *t, unsigned long *key, void **value);
+extern int drmHashNext(void *t, unsigned long *key, void **value);
+
+/* PRNG routines */
+extern void *drmRandomCreate(unsigned long seed);
+extern int drmRandomDestroy(void *state);
+extern unsigned long drmRandom(void *state);
+extern double drmRandomDouble(void *state);
+
+/* Skip list routines */
+
+extern void *drmSLCreate(void);
+extern int drmSLDestroy(void *l);
+extern int drmSLLookup(void *l, unsigned long key, void **value);
+extern int drmSLInsert(void *l, unsigned long key, void *value);
+extern int drmSLDelete(void *l, unsigned long key);
+extern int drmSLNext(void *l, unsigned long *key, void **value);
+extern int drmSLFirst(void *l, unsigned long *key, void **value);
+extern void drmSLDump(void *l);
+extern int drmSLLookupNeighbors(void *l, unsigned long key,
+ unsigned long *prev_key, void **prev_value,
+ unsigned long *next_key, void **next_value);
+
+#endif
diff --git a/src/mesa/Makefile.X11 b/src/mesa/Makefile.X11
index c672cce47a..d014936d36 100644
--- a/src/mesa/Makefile.X11
+++ b/src/mesa/Makefile.X11
@@ -296,7 +296,7 @@ default:
@echo "Specify a target configuration"
-targets: $(LIBDIR)/$(GL_LIB) $(LIBDIR)/$(OSMESA_LIB)
+targets: $(LIBDIR)/$(GL_LIB) $(LIBDIR)/$(OSMESA_LIB) $(LIBMESA)
# Make the GL library
@@ -321,7 +321,9 @@ libmesa: $(LIBDIR)/$(MESA_LIB)
$(LIBDIR)/$(MESA_LIB): $(CORE_OBJECTS)
-
+mesa.a: $(CORE_OBJECTS)
+ rm -f $@ && ar rcv $@ $(CORE_OBJECTS) && ranlib $@
+
# Run 'make -f Makefile.X11 dep' to update the dependencies if you change
# what's included by any source file.
dep: $(CORE_SOURCES) $(DRIVER_SOURCES) $(OSMESA_DRIVER_SOURCES) $(ASM_SOURCES)
@@ -336,9 +338,9 @@ tags:
# Remove .o and backup files
clean:
+ -rm *.a
-rm -f */*.o */*~ */*.o */*~
-rm -f drivers/*/*.o
- -rm -f drivers/dri/*/*.o
include $(TOP)/Make-config
diff --git a/src/mesa/drivers/dri/mga/Doxyfile b/src/mesa/drivers/dri/mga/Doxyfile
new file mode 100644
index 0000000000..0d0c134a72
--- /dev/null
+++ b/src/mesa/drivers/dri/mga/Doxyfile
@@ -0,0 +1,234 @@
+# Doxyfile 1.3.3-Gideon
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = mga
+PROJECT_NUMBER = $VERSION$
+OUTPUT_DIRECTORY =
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ALIASES =
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SHOW_USED_FILES = YES
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = /home/newtree/temp/src/mesa/drivers/dri/mga
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.C \
+ *.H \
+ *.tlh \
+ *.diff \
+ *.patch \
+ *.moc \
+ *.xpm \
+ *.dox
+RECURSIVE = yes
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = yes
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+CGI_NAME = search.cgi
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH = /usr/local/bin/
+EXT_DOC_PATHS =
diff --git a/src/mesa/drivers/dri/mga/Makefile.X11 b/src/mesa/drivers/dri/mga/Makefile.X11
index c69d6e5989..0dce6e7b1a 100644
--- a/src/mesa/drivers/dri/mga/Makefile.X11
+++ b/src/mesa/drivers/dri/mga/Makefile.X11
@@ -1,4 +1,4 @@
-# $Id: Makefile.X11,v 1.1 2003/08/06 18:01:13 keithw Exp $
+# $Id: Makefile.X11,v 1.2 2003/08/22 20:11:44 brianp Exp $
# Mesa 3-D graphics library
# Version: 5.0
@@ -6,8 +6,10 @@
TOP = ../../../../..
+default: linux-solo
+
SHARED_INCLUDES = $(INCLUDE_DIRS) -I. -I../common -Iserver
-MINIGLX_INCLUDES = -I$(TOP)/src/miniglx
+MINIGLX_INCLUDES = -I$(TOP)/src/glx/mini
DEFINES += \
-D_HAVE_SWRAST=1 \
@@ -16,24 +18,27 @@ DEFINES += \
-D_HAVE_CODEGEN=1 \
-D_HAVE_LIGHTING=1 \
-D_HAVE_TEXGEN=1 \
- -D_HAVE_USERCLIP=1
+ -D_HAVE_USERCLIP=1 \
+ -DGLX_DIRECT_RENDERING
MINIGLX_SOURCES = server/mga_dri.c
-DRIVER_SOURCES = mgabuffers.c \
- mgadd.c \
+DRIVER_SOURCES = mgadd.c \
mgaioctl.c \
mgarender.c \
mgastate.c \
mgatris.c \
- ../common/mm.c
+ ../common/mm.c \
+ ../common/utils.c \
+ ../common/texmem.c \
+ ../common/vblank.c
FULL_DRIVER_SOURCES = \
mgapixel.c \
mgaspan.c \
mgatex.c \
- mgatexcnv.c \
mgatexmem.c \
+ mga_texstate.c \
mgavb.c \
mga_xmesa.c
@@ -54,7 +59,7 @@ WINOBJ=$(MESABUILDDIR)/dri/dri.a
WINLIB=
else
WINOBJ=
-WINLIB=-L$(MESA)/src/miniglx
+WINLIB=-L$(MESA)/src/glx/mini
endif
ASM_SOURCES =
@@ -87,7 +92,7 @@ INCLUDE_DIRS = \
##### TARGETS #####
-targets: mga_dri.so
+targets: depend mga_dri.so
mga_dri.so: $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11
rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc -lm
@@ -96,7 +101,7 @@ mga_dri.so: $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11
# Run 'make -f Makefile.X11 dep' to update the dependencies if you change
# what's included by any source file.
-dep: $(C_SOURCES) $(ASM_SOURCES)
+depend: $(C_SOURCES) $(ASM_SOURCES)
makedepend -fdepend -Y $(SHARED_INCLUDES) \
$(C_SOURCES) $(ASM_SOURCES)
@@ -108,7 +113,7 @@ tags:
# Remove .o and backup files
clean:
- -rm -f *.o *~ *.o *~ *.so
+ -rm -f *.o *~ *.o *~ *.so server/*.o
include $(TOP)/Make-config
diff --git a/src/mesa/drivers/dri/mga/mga_texstate.c b/src/mesa/drivers/dri/mga/mga_texstate.c
new file mode 100644
index 0000000000..fc1406cab9
--- /dev/null
+++ b/src/mesa/drivers/dri/mga/mga_texstate.c
@@ -0,0 +1,747 @@
+/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * (c) Copyright IBM Corporation 2002
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS, IBM AND/OR THEIR SUPPLIERS 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:
+ * Ian Romanick <idr@us.ibm.com>
+ * Keith Whitwell <keithw@tungstengraphics.com>
+ */
+/* $XFree86:$ */
+
+#include "mm.h"
+#include "mgacontext.h"
+#include "mgatex.h"
+#include "mgaregs.h"
+#include "mgatris.h"
+#include "mgaioctl.h"
+
+#include "context.h"
+#include "enums.h"
+#include "macros.h"
+#include "imports.h"
+
+#include "simple_list.h"
+#include "texformat.h"
+
+#define MGA_USE_TABLE_FOR_FORMAT
+#ifdef MGA_USE_TABLE_FOR_FORMAT
+#define TMC_nr_tformat (MESA_FORMAT_YCBCR_REV + 1)
+static const unsigned TMC_tformat[ TMC_nr_tformat ] =
+{
+ [MESA_FORMAT_ARGB8888] = TMC_tformat_tw32 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_RGB565] = TMC_tformat_tw16 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_ARGB4444] = TMC_tformat_tw12 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_ARGB1555] = TMC_tformat_tw15 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_CI8] = TMC_tformat_tw8 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_YCBCR] = TMC_tformat_tw422uyvy | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_YCBCR_REV] = TMC_tformat_tw422 | TMC_takey_1 | TMC_tamask_0,
+};
+#endif
+
+static void
+mgaSetTexImages( mgaContextPtr mmesa,
+ const struct gl_texture_object * tObj )
+{
+ mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
+ struct gl_texture_image *baseImage = tObj->Image[ tObj->BaseLevel ];
+ GLint totalSize;
+ GLint width, height;
+ GLint i;
+ GLint firstLevel, lastLevel, numLevels;
+ GLint log2Width, log2Height;
+ GLuint txformat = 0;
+ GLint ofs;
+
+ /* Set the hardware texture format
+ */
+#ifndef MGA_USE_TABLE_FOR_FORMAT
+ switch (baseImage->TexFormat->MesaFormat) {
+
+ case MESA_FORMAT_ARGB8888: txformat = TMC_tformat_tw32; break;
+ case MESA_FORMAT_RGB565: txformat = TMC_tformat_tw16; break;
+ case MESA_FORMAT_ARGB4444: txformat = TMC_tformat_tw12; break;
+ case MESA_FORMAT_ARGB1555: txformat = TMC_tformat_tw15; break;
+ case MESA_FORMAT_CI8: txformat = TMC_tformat_tw8; break;
+ case MESA_FORMAT_YCBCR: txformat = TMC_tformat_tw422uyvy; break;
+ case MESA_FORMAT_YCBCR_REV: txformat = TMC_tformat_tw422; break;
+
+ default:
+ _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__);
+ return;
+ }
+#else
+ if ( (baseImage->TexFormat->MesaFormat >= TMC_nr_tformat)
+ || (TMC_tformat[ baseImage->TexFormat->MesaFormat ] == 0) )
+ {
+ _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__);
+ return;
+ }
+
+ txformat = TMC_tformat[ baseImage->TexFormat->MesaFormat ];
+
+#endif /* MGA_USE_TABLE_FOR_FORMAT */
+
+ if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
+ /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
+ */
+
+ firstLevel = lastLevel = tObj->BaseLevel;
+ } else {
+ /* Compute which mipmap levels we really want to send to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ * Yes, this looks overly complicated, but it's all needed.
+ */
+
+ firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5);
+ firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5);
+ lastLevel = MAX2(lastLevel, tObj->BaseLevel);
+ lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = MIN2(lastLevel, tObj->MaxLevel);
+ lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
+ }
+
+ log2Width = tObj->Image[firstLevel]->WidthLog2;
+ log2Height = tObj->Image[firstLevel]->HeightLog2;
+ width = tObj->Image[firstLevel]->Width;
+ height = tObj->Image[firstLevel]->Height;
+
+ numLevels = MIN2( lastLevel - firstLevel + 1,
+ MGA_IS_G200(mmesa) ? G200_TEX_MAXLEVELS : G400_TEX_MAXLEVELS);
+
+
+ totalSize = 0;
+ for ( i = 0 ; i < numLevels ; i++ ) {
+ const struct gl_texture_image * const texImage = tObj->Image[i+firstLevel];
+
+ if ( (texImage == NULL)
+ || ((i != 0)
+ && ((texImage->Width < 8) || (texImage->Height < 8))) ) {
+ break;
+ }
+
+ t->offsets[i] = totalSize;
+ t->base.dirty_images[0] |= (1<<i);
+
+ totalSize += ((MAX2( texImage->Width, 8 ) *
+ MAX2( texImage->Height, 8 ) *
+ baseImage->TexFormat->TexelBytes) + 31) & ~31;
+ }
+
+ numLevels = i;
+ lastLevel = firstLevel + numLevels - 1;
+
+ /* save these values */
+ t->base.firstLevel = firstLevel;
+ t->base.lastLevel = lastLevel;
+
+ t->base.totalSize = totalSize;
+
+ /* setup hardware register values */
+ t->setup.texctl &= (TMC_tformat_MASK & TMC_tpitch_MASK
+ & TMC_tpitchext_MASK);
+ t->setup.texctl |= txformat;
+
+
+ /* Set the texture width. In order to support non-power of 2 textures and
+ * textures larger than 1024 texels wide, "linear" pitch must be used. For
+ * the linear pitch, if the width is 2048, a value of zero is used.
+ */
+
+ t->setup.texctl |= TMC_tpitchlin_enable;
+ t->setup.texctl |= (width & (2048 - 1)) << TMC_tpitchext_SHIFT;
+
+
+ /* G400 specifies the number of mip levels in a strange way. Since there
+ * are up to 12 levels, it requires 4 bits. Three of the bits are at the
+ * high end of TEXFILTER. The other bit is in the middle. Weird.
+ */
+
+ t->setup.texfilter &= TF_mapnb_MASK & TF_mapnbhigh_MASK & TF_reserved_MASK;
+ t->setup.texfilter |= (((numLevels-1) & 0x07) << (TF_mapnb_SHIFT));
+ t->setup.texfilter |= (((numLevels-1) & 0x08) << (TF_mapnbhigh_SHIFT - 3));
+
+ /* warp texture registers */
+ ofs = MGA_IS_G200(mmesa) ? 28 : 11;
+
+ t->setup.texwidth = (MGA_FIELD(TW_twmask, width - 1) |
+ MGA_FIELD(TW_rfw, (10 - log2Width - 8) & 63 ) |
+ MGA_FIELD(TW_tw, (log2Width + ofs ) | 0x40 ));
+
+ t->setup.texheight = (MGA_FIELD(TH_thmask, height - 1) |
+ MGA_FIELD(TH_rfh, (10 - log2Height - 8) & 63 ) |
+ MGA_FIELD(TH_th, (log2Height + ofs ) | 0x40 ));
+
+ mgaUploadTexImages( mmesa, t );
+}
+
+
+/* ================================================================
+ * Texture unit state management
+ */
+
+static void mgaUpdateTextureEnvG200( GLcontext *ctx, GLuint unit )
+{
+ struct gl_texture_object *tObj = ctx->Texture.Unit[0]._Current;
+ mgaTextureObjectPtr t;
+
+ if (!tObj || !tObj->DriverData)
+ return;
+
+ t = (mgaTextureObjectPtr)tObj->DriverData;
+
+ t->setup.texctl2 &= ~TMC_decalblend_enable;
+
+ switch (ctx->Texture.Unit[0].EnvMode) {
+ case GL_REPLACE:
+ t->setup.texctl &= ~TMC_tmodulate_enable;
+ break;
+ case GL_MODULATE:
+ t->setup.texctl |= TMC_tmodulate_enable;
+ break;
+ case GL_DECAL:
+ t->setup.texctl &= ~TMC_tmodulate_enable;
+ t->setup.texctl2 |= TMC_decalblend_enable;
+ break;
+ case GL_BLEND:
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
+ break;
+ default:
+ break;
+ }
+}
+
+
+#define MGA_DISABLE 0
+#define MGA_REPLACE 1
+#define MGA_MODULATE 2
+#define MGA_DECAL 3
+#define MGA_BLEND 4
+#define MGA_ADD 5
+#define MGA_MAX_COMBFUNC 6
+
+static const GLuint g400_color_combine[][MGA_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2 ),
+
+ /* GL_MODULATE
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2),
+
+ /* GL_BLEND
+ */
+ (0),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+ },
+
+ /* Unit 1:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2 ),
+
+ /* GL_MODULATE
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_alpha_prevstage |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2 ),
+
+ /* GL_BLEND
+ */
+ (0),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_alpha_prevstage |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+ },
+};
+
+static const GLuint g400_alpha_combine[][MGA_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg2 |
+ TD0_color_arg2_diffuse |
+ TD0_alpha_sel_arg1 ),
+
+ /* GL_MODULATE
+ * FIXME: Is this correct?
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_arg2 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2),
+
+ /* GL_BLEND
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+ },
+
+ /* Unit 1:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg2 |
+ TD0_color_arg2_diffuse |
+ TD0_alpha_sel_arg1 ),
+
+ /* GL_MODULATE
+ * FIXME: Is this correct?
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_alpha_prevstage |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_sel_arg2 |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2),
+
+ /* GL_BLEND
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+ },
+};
+
+static void mgaUpdateTextureEnvG400( GLcontext *ctx, GLuint unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ GLuint *reg = ((GLuint *)&mmesa->setup.tdualstage0 + unit);
+ GLenum format;
+
+ if ( tObj != ctx->Texture.Unit[source].Current2D || !tObj )
+ return;
+
+ format = tObj->Image[tObj->BaseLevel]->Format;
+
+ switch (ctx->Texture.Unit[source].EnvMode) {
+ case GL_REPLACE:
+ if (format == GL_RGB || format == GL_LUMINANCE) {
+ *reg = g400_color_combine[unit][MGA_REPLACE];
+ }
+ else if (format == GL_ALPHA) {
+ *reg = g400_alpha_combine[unit][MGA_REPLACE];
+ }
+ else {
+ *reg = (TD0_color_sel_arg1 |
+ TD0_alpha_sel_arg1 );
+ }
+ break;
+
+ case GL_MODULATE:
+ *reg = g400_color_combine[unit][MGA_MODULATE];
+ break;
+ case GL_DECAL:
+ if (format == GL_RGB) {
+ *reg = g400_color_combine[unit][MGA_DECAL];
+ }
+ else if ( format == GL_RGBA ) {
+#if 0
+ if (unit == 0) {
+ /* this doesn't work */
+ *reg = (TD0_color_arg2_diffuse |
+ TD0_color_alpha_currtex |
+ TD0_color_alpha2inv_enable |
+ TD0_color_arg2mul_alpha2 |
+ TD0_color_arg1mul_alpha1 |
+ TD0_color_blend_enable |
+ TD0_color_arg1add_mulout |
+ TD0_color_arg2add_mulout |
+ TD0_color_add_add |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2 );
+ }
+ else {
+ *reg = (TD0_color_arg2_prevstage |
+ TD0_color_alpha_currtex |
+ TD0_color_alpha2inv_enable |
+ TD0_color_arg2mul_alpha2 |
+ TD0_color_arg1mul_alpha1 |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2 );
+ }
+#else
+ /* s/w fallback, pretty sure we can't do in h/w */
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
+ if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
+ fprintf( stderr, "FALLBACK: GL_DECAL RGBA texture, unit=%d\n",
+ unit );
+#endif
+ }
+ else {
+ *reg = g400_alpha_combine[unit][MGA_DECAL];
+ }
+ break;
+
+ case GL_ADD:
+ if (format == GL_INTENSITY) {
+ if (unit == 0) {
+ *reg = ( TD0_color_arg2_diffuse |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_add_enable |
+ TD0_alpha_sel_add);
+ }
+ else {
+ *reg = ( TD0_color_arg2_prevstage |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_add_enable |
+ TD0_alpha_sel_add);
+ }
+ }
+ else if (format == GL_ALPHA) {
+ *reg = g400_alpha_combine[unit][MGA_ADD];
+ }
+ else {
+ *reg = g400_color_combine[unit][MGA_ADD];
+ }
+ break;
+
+ case GL_BLEND:
+ if (format == GL_ALPHA) {
+ *reg = g400_alpha_combine[unit][MGA_BLEND];
+ }
+ else {
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
+ if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
+ fprintf( stderr, "FALLBACK: GL_BLEND envcolor=0x%08x\n",
+ mmesa->envcolor );
+
+ /* Do singletexture GL_BLEND with 'all ones' env-color
+ * by using both texture units. Multitexture gl_blend
+ * is a fallback.
+ */
+ if (unit == 0) {
+ /* Part 1: R1 = Rf ( 1 - Rt )
+ * A1 = Af At
+ */
+ *reg = ( TD0_color_arg2_diffuse |
+ TD0_color_arg1_inv_enable |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg1);
+ } else {
+ /* Part 2: R2 = R1 + Rt
+ * A2 = A1
+ */
+ *reg = ( TD0_color_arg2_prevstage |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void disable_tex( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+
+ /* Texture unit disabled */
+
+ if ( mmesa->CurrentTexObj[unit] != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ mmesa->CurrentTexObj[unit]->base.bound &= ~(1UL << unit);
+ mmesa->CurrentTexObj[unit] = NULL;
+ }
+
+ if ( unit != 0 ) {
+ mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0;
+ }
+
+ if ( ctx->Texture._EnabledUnits == 0 ) {
+ mmesa->setup.dwgctl &= DC_opcod_MASK;
+ mmesa->setup.dwgctl |= DC_opcod_trap;
+ mmesa->hw.alpha_sel = AC_alphasel_diffused;
+ }
+
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT | (MGA_UPLOAD_TEX0 << unit);
+}
+
+static GLboolean enable_tex_2d( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
+
+ /* Upload teximages (not pipelined)
+ */
+ if (t->base.dirty_images[0]) {
+ FLUSH_BATCH( mmesa );
+ mgaSetTexImages( mmesa, tObj );
+ if ( t->base.memBlock == NULL ) {
+ return GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean update_tex_common( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ struct gl_texture_object *tObj = texUnit->_Current;
+ mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
+
+ /* Fallback if there's a texture border */
+ if ( tObj->Image[tObj->BaseLevel]->Border > 0 ) {
+ return GL_FALSE;
+ }
+
+
+ /* Update state if this is a different texture object to last
+ * time.
+ */
+ if ( mmesa->CurrentTexObj[unit] != t ) {
+ if ( mmesa->CurrentTexObj[unit] != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ mmesa->CurrentTexObj[unit]->base.bound &= ~(1UL << unit);
+ }
+
+ mmesa->CurrentTexObj[unit] = t;
+ t->base.bound |= (1UL << unit);
+
+ driUpdateTextureLRU( (driTextureObject *) t ); /* done too often */
+ }
+
+ /* register setup */
+ if ( unit == 1 ) {
+ mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0;
+ }
+
+ t->setup.texctl2 &= TMC_dualtex_MASK;
+ if (ctx->Texture._EnabledUnits == 0x03) {
+ t->setup.texctl2 |= TMC_dualtex_enable;
+ }
+
+ /* FIXME: The Radeon has some cached state so that it can avoid calling
+ * FIXME: UpdateTextureEnv in some cases. Is that possible here?
+ */
+ if (MGA_IS_G400(mmesa)) {
+ /* G400: Regardless of texture env mode, we use the alpha from the
+ * texture unit (AC_alphasel_fromtex) since it will have already
+ * been modulated by the incoming fragment color, if needed.
+ * We don't want (AC_alphasel_modulate) since that'll effectively
+ * do the modulation twice.
+ */
+ mmesa->hw.alpha_sel = AC_alphasel_fromtex;
+
+ mgaUpdateTextureEnvG400( ctx, unit );
+ } else {
+ mmesa->hw.alpha_sel = 0;
+ switch (ctx->Texture.Unit[0].EnvMode) {
+ case GL_DECAL:
+ mmesa->hw.alpha_sel |= AC_alphasel_diffused;
+ case GL_REPLACE:
+ mmesa->hw.alpha_sel |= AC_alphasel_fromtex;
+ break;
+ case GL_BLEND:
+ case GL_MODULATE:
+ mmesa->hw.alpha_sel |= AC_alphasel_modulated;
+ break;
+ default:
+ break;
+ }
+
+ mgaUpdateTextureEnvG200( ctx, unit );
+ }
+
+ mmesa->setup.dwgctl &= DC_opcod_MASK;
+ mmesa->setup.dwgctl |= DC_opcod_texture_trap;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT | (MGA_UPLOAD_TEX0 << unit);
+
+ FALLBACK( ctx, MGA_FALLBACK_BORDER_MODE, t->border_fallback );
+ return !t->border_fallback;
+}
+
+
+static GLboolean updateTextureUnit( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+
+
+ if ( texUnit->_ReallyEnabled == TEXTURE_2D_BIT) {
+ return(enable_tex_2d( ctx, unit ) &&
+ update_tex_common( ctx, unit ));
+ }
+ else if ( texUnit->_ReallyEnabled ) {
+ return GL_FALSE;
+ }
+ else {
+ disable_tex( ctx, unit );
+ return GL_TRUE;
+ }
+}
+
+/* The G400 is now programmed quite differently wrt texture environment.
+ */
+void mgaUpdateTextureState( GLcontext *ctx )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ GLboolean ok;
+ unsigned i;
+
+
+ /* This works around a quirk with the MGA hardware. If only OpenGL
+ * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The
+ * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used.
+ */
+
+ mmesa->tmu_source[0] = 0;
+ mmesa->tmu_source[1] = 1;
+
+ if ((ctx->Texture._EnabledUnits & 0x03) == 0x02) {
+ /* only texture 1 enabled */
+ mmesa->tmu_source[0] = 1;
+ mmesa->tmu_source[1] = 0;
+ }
+
+ for ( i = 0, ok = GL_TRUE
+ ; (i < ctx->Const.MaxTextureUnits) && ok
+ ; i++ ) {
+ ok = updateTextureUnit( ctx, i );
+ }
+
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, !ok );
+
+ /* FIXME: I believe that ChooseVertexState should be called here instead of
+ * FIXME: in mgaDDValidateState.
+ */
+}
diff --git a/src/mesa/drivers/dri/mga/mga_xmesa.c b/src/mesa/drivers/dri/mga/mga_xmesa.c
index de1bcc2a0f..16dc349cac 100644
--- a/src/mesa/drivers/dri/mga/mga_xmesa.c
+++ b/src/mesa/drivers/dri/mga/mga_xmesa.c
@@ -1,4 +1,4 @@
-/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mga_xmesa.c,v 1.19 2003/03/26 20:43:49 tsi Exp $ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mga_xmesa.c,v 1.18 2002/12/16 16:18:52 dawes Exp $ */
/*
* Copyright 2000-2001 VA Linux Systems, Inc.
* All Rights Reserved.
@@ -26,15 +26,14 @@
* Keith Whitwell <keith@tungstengraphics.com>
*/
-#include <stdio.h>
+#ifdef GLX_DIRECT_RENDERING
#include "mga_common.h"
#include "mga_xmesa.h"
#include "context.h"
#include "matrix.h"
-/*#include "mmath.h"*/
#include "simple_list.h"
-/*#include "mem.h"*/
+#include "imports.h"
#include "swrast/swrast.h"
#include "swrast_setup/swrast_setup.h"
@@ -50,26 +49,23 @@
#include "mgaioctl.h"
#include "mgatris.h"
#include "mgavb.h"
-#include "mgabuffers.h"
#include "mgapixel.h"
-
#include "mga_xmesa.h"
-
#include "mga_dri.h"
+#include "utils.h"
+#include "vblank.h"
+#include "dri_util.h"
+#ifndef _SOLO
+#include "glxextensions.h"
+#endif
+
#ifndef MGA_DEBUG
-int MGA_DEBUG = (0
-/* | DEBUG_ALWAYS_SYNC */
-/* | DEBUG_VERBOSE_MSG */
-/* | DEBUG_VERBOSE_LRU */
-/* | DEBUG_VERBOSE_DRI */
-/* | DEBUG_VERBOSE_IOCTL */
-/* | DEBUG_VERBOSE_2D */
-/* | DEBUG_VERBOSE_FALLBACK */
- );
+int MGA_DEBUG = 0;
#endif
+static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
static GLboolean
mgaInitDriver(__DRIscreenPrivate *sPriv)
@@ -77,16 +73,8 @@ mgaInitDriver(__DRIscreenPrivate *sPriv)
mgaScreenPrivate *mgaScreen;
MGADRIPtr serverInfo = (MGADRIPtr)sPriv->pDevPriv;
- if (MGA_DEBUG&DEBUG_VERBOSE_DRI)
- fprintf(stderr, "mgaInitDriver\n");
-
- /* Check that the DRM driver version is compatible */
- if (sPriv->drmMajor != 3 ||
- sPriv->drmMinor < 0) {
- __driUtilMessage("MGA DRI driver expected DRM driver version 3.0.x but got version %d.%d.%d", sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch);
+ if ( ! driCheckDriDdxDrmVersions( sPriv, "MGA", 4, 0, 1, 0, 3, 0 ) )
return GL_FALSE;
- }
-
/* Allocate the private area */
mgaScreen = (mgaScreenPrivate *)MALLOC(sizeof(mgaScreenPrivate));
@@ -103,21 +91,37 @@ mgaInitDriver(__DRIscreenPrivate *sPriv)
drmMGAGetParam gp;
gp.param = MGA_PARAM_IRQ_NR;
- gp.value = (int *) &mgaScreen->irq;
+ gp.value = &mgaScreen->irq;
ret = drmCommandWriteRead( sPriv->fd, DRM_MGA_GETPARAM,
&gp, sizeof(gp));
if (ret) {
fprintf(stderr, "drmMgaGetParam (MGA_PARAM_IRQ_NR): %d\n", ret);
- FREE(mgaScreen);
+ free(mgaScreen);
sPriv->private = NULL;
return GL_FALSE;
}
}
+ mgaScreen->linecomp_sane = (sPriv->ddxMajor > 1) || (sPriv->ddxMinor > 1)
+ || ((sPriv->ddxMinor == 1) && (sPriv->ddxPatch > 0));
+#ifndef _SOLO
+ if ( ! mgaScreen->linecomp_sane ) {
+ PFNGLXDISABLEEXTENSIONPROC glx_disable_extension;
+
+ glx_disable_extension = (PFNGLXDISABLEEXTENSIONPROC)
+ glXGetProcAddress( "__glXDisableExtension" );
+
+ if ( glx_disable_extension != NULL ) {
+ (*glx_disable_extension)( "GLX_SGI_swap_control" );
+ (*glx_disable_extension)( "GLX_SGI_video_sync" );
+ (*glx_disable_extension)( "GLX_MESA_swap_control" );
+ }
+ }
+#endif
if (serverInfo->chipset != MGA_CARD_TYPE_G200 &&
serverInfo->chipset != MGA_CARD_TYPE_G400) {
- FREE(mgaScreen);
+ free(mgaScreen);
sPriv->private = NULL;
__driUtilMessage("Unrecognized chipset");
return GL_FALSE;
@@ -164,7 +168,7 @@ mgaInitDriver(__DRIscreenPrivate *sPriv)
mgaScreen->agp.size,
(drmAddress *)&mgaScreen->agp.map) != 0)
{
- Xfree(mgaScreen);
+ free(mgaScreen);
sPriv->private = NULL;
__driUtilMessage("Couldn't map agp region");
return GL_FALSE;
@@ -210,7 +214,7 @@ mgaInitDriver(__DRIscreenPrivate *sPriv)
mgaScreen->bufs = drmMapBufs(sPriv->fd);
if (!mgaScreen->bufs) {
/*drmUnmap(mgaScreen->agp_tex.map, mgaScreen->agp_tex.size);*/
- FREE(mgaScreen);
+ free(mgaScreen);
sPriv->private = NULL;
__driUtilMessage("Couldn't map dma buffers");
return GL_FALSE;
@@ -254,12 +258,63 @@ static const struct gl_pipeline_stage *mga_pipeline[] = {
};
+static const char * const g400_extensions[] =
+{
+ "GL_ARB_multitexture",
+ "GL_ARB_texture_env_add",
+ "GL_EXT_texture_env_add",
+ "GL_EXT_texture_edge_clamp",
+ "GL_SGIS_texture_edge_clamp",
+#if defined (MESA_packed_depth_stencil)
+ "GL_MESA_packed_depth_stencil",
+#endif
+ NULL
+};
+
+static const char * const card_extensions[] =
+{
+ "GL_ARB_multisample",
+ "GL_ARB_texture_compression",
+ "GL_EXT_fog_coord",
+ /* paletted_textures currently doesn't work, but we could fix them later */
+#if 0
+ "GL_EXT_shared_texture_palette",
+ "GL_EXT_paletted_texture",
+#endif
+ "GL_EXT_secondary_color",
+ "GL_EXT_stencil_wrap",
+ "GL_MESA_ycbcr_texture",
+ "GL_SGIS_generate_mipmap",
+ "GL_SGIS_texture_lod",
+ NULL
+};
+
+static const struct dri_debug_control debug_control[] =
+{
+ { "fall", DEBUG_VERBOSE_FALLBACK },
+ { "tex", DEBUG_VERBOSE_TEXTURE },
+ { "ioctl", DEBUG_VERBOSE_IOCTL },
+ { "verb", DEBUG_VERBOSE_MSG },
+ { "dri", DEBUG_VERBOSE_DRI },
+ { NULL, 0 }
+};
+
+
+static int
+get_ust_nop( uint64_t * ust )
+{
+ *ust = 1;
+ return 0;
+}
+
+
static GLboolean
mgaCreateContext( const __GLcontextModes *mesaVis,
__DRIcontextPrivate *driContextPriv,
void *sharedContextPrivate )
{
int i;
+ unsigned maxlevels;
GLcontext *ctx, *shareCtx;
mgaContextPtr mmesa;
__DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
@@ -281,7 +336,7 @@ mgaCreateContext( const __GLcontextModes *mesaVis,
shareCtx = ((mgaContextPtr) sharedContextPrivate)->glCtx;
else
shareCtx = NULL;
- mmesa->glCtx = _mesa_create_context(mesaVis, shareCtx, mmesa, GL_TRUE);
+ mmesa->glCtx = _mesa_create_context(mesaVis, shareCtx, (void *) mmesa, GL_TRUE);
if (!mmesa->glCtx) {
FREE(mmesa);
return GL_FALSE;
@@ -298,13 +353,20 @@ mgaCreateContext( const __GLcontextModes *mesaVis,
mmesa->sarea = (void *)saPriv;
mmesa->glBuffer = NULL;
- make_empty_list(&mmesa->SwappedOut);
-
- mmesa->lastTexHeap = mgaScreen->texVirtual[MGA_AGP_HEAP] ? 2 : 1;
-
- for (i = 0 ; i < mmesa->lastTexHeap ; i++) {
- mmesa->texHeap[i] = mmInit( 0, mgaScreen->textureSize[i]);
- make_empty_list(&mmesa->TexObjList[i]);
+ (void) memset( mmesa->texture_heaps, 0, sizeof( mmesa->texture_heaps ) );
+ make_empty_list( & mmesa->swapped );
+
+ mmesa->nr_heaps = mgaScreen->texVirtual[MGA_AGP_HEAP] ? 2 : 1;
+ for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) {
+ mmesa->texture_heaps[i] = driCreateTextureHeap( i, mmesa,
+ mgaScreen->textureSize[i],
+ 6,
+ MGA_NR_TEX_REGIONS,
+ mmesa->sarea->texList[i],
+ & mmesa->sarea->texAge[i],
+ & mmesa->swapped,
+ sizeof( mgaTextureObject_t ),
+ (destroy_texture_object_t *) mgaDestroyTexObj );
}
/* Set the maximum texture size small enough that we can guarentee
@@ -312,22 +374,26 @@ mgaCreateContext( const __GLcontextModes *mesaVis,
* on the card at once.
*/
ctx = mmesa->glCtx;
- {
- int nr = 2;
-
- if (mgaScreen->chipset == MGA_CARD_TYPE_G200)
- nr = 1;
-
- if (mgaScreen->textureSize[0] < nr*1024*1024) {
- ctx->Const.MaxTextureLevels = 9;
- } else if (mgaScreen->textureSize[0] < nr*4*1024*1024) {
- ctx->Const.MaxTextureLevels = 10;
- } else {
- ctx->Const.MaxTextureLevels = 11;
- }
+ if ( mgaScreen->chipset == MGA_CARD_TYPE_G200 ) {
+ ctx->Const.MaxTextureUnits = 1;
+ maxlevels = G200_TEX_MAXLEVELS;
- ctx->Const.MaxTextureUnits = nr;
}
+ else {
+ ctx->Const.MaxTextureUnits = 2;
+ maxlevels = G400_TEX_MAXLEVELS;
+ }
+
+ driCalculateMaxTextureLevels( mmesa->texture_heaps,
+ mmesa->nr_heaps,
+ & ctx->Const,
+ 4,
+ 11, /* max 2D texture size is 1024x1024 */
+ 0, /* 3D textures unsupported. */
+ 0, /* cube textures unsupported. */
+ 0, /* texture rectangles unsupported. */
+ maxlevels,
+ GL_FALSE );
ctx->Const.MinLineWidth = 1.0;
ctx->Const.MinLineWidthAA = 1.0;
@@ -335,6 +401,7 @@ mgaCreateContext( const __GLcontextModes *mesaVis,
ctx->Const.MaxLineWidthAA = 10.0;
ctx->Const.LineWidthGranularity = 1.0;
+ mmesa->default32BitTextures = (mesaVis->rgbBits >= 24);
mmesa->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24;
switch (mesaVis->depthBits) {
@@ -361,7 +428,6 @@ mgaCreateContext( const __GLcontextModes *mesaVis,
mmesa->haveHwStipple = GL_FALSE;
mmesa->RenderIndex = -1; /* impossible value */
- mmesa->new_state = ~0;
mmesa->dirty = ~0;
mmesa->vertex_format = 0;
mmesa->CurrentTexObj[0] = 0;
@@ -395,7 +461,11 @@ mgaCreateContext( const __GLcontextModes *mesaVis,
ctx->DriverCtx = (void *) mmesa;
mmesa->glCtx = ctx;
- mgaDDExtensionsInit( ctx );
+ driInitExtensions( ctx, card_extensions, GL_FALSE );
+
+ if (MGA_IS_G400(MGA_CONTEXT(ctx))) {
+ driInitExtensions( ctx, g400_extensions, GL_FALSE );
+ }
mgaDDInitStateFuncs( ctx );
mgaDDInitTextureFuncs( ctx );
@@ -410,6 +480,24 @@ mgaCreateContext( const __GLcontextModes *mesaVis,
driContextPriv->driverPrivate = (void *) mmesa;
+#if DO_DEBUG
+ MGA_DEBUG = driParseDebugString( getenv( "MGA_DEBUG" ),
+ debug_control );
+#endif
+
+ mmesa->vblank_flags = ((mmesa->mgaScreen->irq == 0)
+ || !mmesa->mgaScreen->linecomp_sane)
+ ? VBLANK_FLAG_NO_IRQ : driGetDefaultVBlankFlags();
+#ifndef _SOLO
+ mmesa->get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( "__glXGetUST" );
+ if ( mmesa->get_ust == NULL )
+#endif
+ {
+ mmesa->get_ust = get_ust_nop;
+ }
+
+ (*mmesa->get_ust)( & mmesa->swap_ust );
+
return GL_TRUE;
}
@@ -419,10 +507,15 @@ mgaDestroyContext(__DRIcontextPrivate *driContextPriv)
mgaContextPtr mmesa = (mgaContextPtr) driContextPriv->driverPrivate;
if (MGA_DEBUG&DEBUG_VERBOSE_DRI)
- fprintf(stderr, "mgaDestroyContext\n");
+ fprintf( stderr, "[%s:%d] mgaDestroyContext start\n",
+ __FILE__, __LINE__ );
assert(mmesa); /* should never be null */
if (mmesa) {
+ GLboolean release_texture_heaps;
+
+
+ release_texture_heaps = (mmesa->glCtx->Shared->RefCount == 1);
_swsetup_DestroyContext( mmesa->glCtx );
_tnl_DestroyContext( mmesa->glCtx );
_ac_DestroyContext( mmesa->glCtx );
@@ -433,9 +526,27 @@ mgaDestroyContext(__DRIcontextPrivate *driContextPriv)
/* free the Mesa context */
mmesa->glCtx->DriverCtx = NULL;
_mesa_destroy_context(mmesa->glCtx);
- /* free the mga context */
+
+ if ( release_texture_heaps ) {
+ /* This share group is about to go away, free our private
+ * texture object data.
+ */
+ int i;
+
+ assert( is_empty_list( & mmesa->swapped ) );
+
+ for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) {
+ driDestroyTextureHeap( mmesa->texture_heaps[ i ] );
+ mmesa->texture_heaps[ i ] = NULL;
+ }
+ }
+
FREE(mmesa);
}
+
+ if (MGA_DEBUG&DEBUG_VERBOSE_DRI)
+ fprintf( stderr, "[%s:%d] mgaDestroyContext done\n",
+ __FILE__, __LINE__ );
}
@@ -482,13 +593,7 @@ mgaUnbindContext(__DRIcontextPrivate *driContextPriv)
}
static GLboolean
-mgaOpenFullScreen(__DRIcontextPrivate *driContextPriv)
-{
- return GL_TRUE;
-}
-
-static GLboolean
-mgaCloseFullScreen(__DRIcontextPrivate *driContextPriv)
+mgaOpenCloseFullScreen(__DRIcontextPrivate *driContextPriv)
{
return GL_TRUE;
}
@@ -505,8 +610,6 @@ mgaMakeCurrent(__DRIcontextPrivate *driContextPriv,
__DRIdrawablePrivate *driDrawPriv,
__DRIdrawablePrivate *driReadPriv)
{
- fprintf(stderr, "%s\n", __FUNCTION__);
-
if (driContextPriv) {
mgaContextPtr mmesa = (mgaContextPtr) driContextPriv->driverPrivate;
@@ -532,6 +635,7 @@ mgaMakeCurrent(__DRIcontextPrivate *driContextPriv,
return GL_TRUE;
}
+
void mgaGetLock( mgaContextPtr mmesa, GLuint flags )
{
__DRIdrawablePrivate *dPriv = mmesa->driDrawable;
@@ -539,29 +643,10 @@ void mgaGetLock( mgaContextPtr mmesa, GLuint flags )
int me = mmesa->hHWContext;
int i;
- fprintf(stderr, "%s\n", __FUNCTION__);
-
drmGetLock(mmesa->driFd, mmesa->hHWContext, flags);
-
- fprintf(stderr,
- "mmesa->lastStamp %d dpriv->lastStamp %d *(dpriv->pStamp) %d\n",
- mmesa->lastStamp,
- dPriv->lastStamp,
- *(dPriv->pStamp));
-
- /* The window might have moved, so we might need to get new clip
- * rects.
- *
- * NOTE: This releases and regrabs the hw lock to allow the X server
- * to respond to the DRI protocol request for new drawable info.
- * Since the hardware state depends on having the latest drawable
- * clip rects, all state checking must be done _after_ this call.
- */
- DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv );
- if ( mmesa->lastStamp == 0 ||
- mmesa->lastStamp != dPriv->lastStamp ) {
- mmesa->lastStamp = dPriv->lastStamp;
+ if (*(dPriv->pStamp) != mmesa->lastStamp) {
+ mmesa->lastStamp = *(dPriv->pStamp);
mmesa->SetupNewInputs |= VERT_BIT_CLIP;
mmesa->dirty_cliprects = (MGA_FRONT|MGA_BACK);
mgaUpdateRects( mmesa, (MGA_FRONT|MGA_BACK) );
@@ -569,7 +654,7 @@ void mgaGetLock( mgaContextPtr mmesa, GLuint flags )
mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS;
- mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT;
+ mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT;
if (sarea->ctxOwner != me) {
mmesa->dirty |= (MGA_UPLOAD_CONTEXT | MGA_UPLOAD_TEX0 |
@@ -577,36 +662,48 @@ void mgaGetLock( mgaContextPtr mmesa, GLuint flags )
sarea->ctxOwner=me;
}
- for (i = 0 ; i < mmesa->lastTexHeap ; i++)
- if (sarea->texAge[i] != mmesa->texAge[i])
- mgaAgeTextures( mmesa, i );
+ for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) {
+ DRI_AGE_TEXTURES( mmesa->texture_heaps[ i ] );
+ }
sarea->last_quiescent = -1; /* just kill it for now */
}
-
static const struct __DriverAPIRec mgaAPI = {
- mgaInitDriver,
- mgaDestroyScreen,
- mgaCreateContext,
- mgaDestroyContext,
- mgaCreateBuffer,
- mgaDestroyBuffer,
- mgaSwapBuffers,
- mgaMakeCurrent,
- mgaUnbindContext,
- mgaOpenFullScreen,
- mgaCloseFullScreen
+ .InitDriver = mgaInitDriver,
+ .DestroyScreen = mgaDestroyScreen,
+ .CreateContext = mgaCreateContext,
+ .DestroyContext = mgaDestroyContext,
+ .CreateBuffer = mgaCreateBuffer,
+ .DestroyBuffer = mgaDestroyBuffer,
+ .SwapBuffers = mgaSwapBuffers,
+ .MakeCurrent = mgaMakeCurrent,
+ .UnbindContext = mgaUnbindContext,
+ .OpenFullScreen = mgaOpenCloseFullScreen,
+ .CloseFullScreen = mgaOpenCloseFullScreen,
+ .GetSwapInfo = getSwapInfo,
+ .GetMSC = driGetMSC32,
+ .WaitForMSC = driWaitForMSC32,
+ .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.
*/
+#ifndef _SOLO
+void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
+ int numConfigs, __GLXvisualConfig *config)
+{
+ __DRIscreenPrivate *psp;
+ psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &mgaAPI);
+ return (void *) psp;
+}
+#else
void *__driCreateScreen(struct DRIDriverRec *driver,
struct DRIDriverContextRec *driverContext)
{
@@ -614,3 +711,56 @@ void *__driCreateScreen(struct DRIDriverRec *driver,
psp = __driUtilCreateScreen(driver, driverContext, &mgaAPI);
return (void *) psp;
}
+#endif
+
+
+#ifndef _SOLO
+/* This function is called by libGL.so as soon as libGL.so is loaded.
+ * This is where we'd register new extension functions with the dispatcher.
+ */
+void
+__driRegisterExtensions( void )
+{
+ PFNGLXENABLEEXTENSIONPROC glx_enable_extension;
+
+
+ if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
+ glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC)
+ glXGetProcAddress( "__glXEnableExtension" );
+
+ if ( glx_enable_extension != NULL ) {
+ (*glx_enable_extension)( "GLX_SGI_swap_control", GL_FALSE );
+ (*glx_enable_extension)( "GLX_SGI_video_sync", GL_FALSE );
+ (*glx_enable_extension)( "GLX_MESA_swap_control", GL_FALSE );
+ (*glx_enable_extension)( "GLX_MESA_swap_frame_usage", GL_FALSE );
+ }
+ }
+}
+#endif
+
+/**
+ * Get information about previous buffer swaps.
+ */
+static int
+getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo )
+{
+ mgaContextPtr mmesa;
+
+ if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL)
+ || (dPriv->driContextPriv->driverPrivate == NULL)
+ || (sInfo == NULL) ) {
+ return -1;
+ }
+
+ mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
+ sInfo->swap_count = mmesa->swap_count;
+ sInfo->swap_ust = mmesa->swap_ust;
+ sInfo->swap_missed_count = mmesa->swap_missed_count;
+
+ sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
+ ? driCalculateSwapUsage( dPriv, 0, mmesa->swap_missed_ust )
+ : 0.0;
+
+ return 0;
+}
+#endif
diff --git a/src/mesa/drivers/dri/mga/mga_xmesa.h b/src/mesa/drivers/dri/mga/mga_xmesa.h
index eda996f5a4..de349da089 100644
--- a/src/mesa/drivers/dri/mga/mga_xmesa.h
+++ b/src/mesa/drivers/dri/mga/mga_xmesa.h
@@ -29,8 +29,9 @@
#ifndef _MGA_INIT_H_
#define _MGA_INIT_H_
+#ifdef GLX_DIRECT_RENDERING
+
#include <sys/time.h>
-#include <linux/types.h>
#include "dri_util.h"
#include "mtypes.h"
#include "mgaregs.h"
@@ -46,6 +47,9 @@ typedef struct mga_screen_private_s {
int cpp; /* for front and back buffers */
GLint agpMode;
unsigned int irq; /* IRQ number (0 means none) */
+ GLboolean linecomp_sane; /* GL_TRUE if line comp. programmed correctly
+ * by the DDX driver.
+ */
unsigned int mAccess;
@@ -136,8 +140,9 @@ do { \
#define MGA_BASE( reg ) ((unsigned long)(mmesa->mgaScreen->mmio.map))
#define MGA_ADDR( reg ) (MGA_BASE(reg) + reg)
-#define MGA_DEREF( reg ) *(volatile __u32 *)MGA_ADDR( reg )
+#define MGA_DEREF( reg ) *(volatile CARD32 *)MGA_ADDR( reg )
#define MGA_READ( reg ) MGA_DEREF( reg )
#define MGA_WRITE( reg, val ) do { MGA_DEREF( reg ) = val; } while (0)
#endif
+#endif
diff --git a/src/mesa/drivers/dri/mga/mgacontext.h b/src/mesa/drivers/dri/mga/mgacontext.h
index 3065ea9fd1..7188f6d955 100644
--- a/src/mesa/drivers/dri/mga/mgacontext.h
+++ b/src/mesa/drivers/dri/mga/mgacontext.h
@@ -29,14 +29,15 @@
#ifndef MGALIB_INC
#define MGALIB_INC
-/*#include <X11/Xlibint.h>*/
+#include <inttypes.h>
#include "dri_util.h"
#include "mtypes.h"
+#include "colormac.h"
#include "xf86drm.h"
#include "mm.h"
-/*#include "mem.h"*/
#include "mga_sarea.h"
-
+#include "texmem.h"
+#include "macros.h"
#define MGA_SET_FIELD(reg,mask,val) reg = ((reg) & (mask)) | ((val) & ~(mask))
#define MGA_FIELD(field,val) (((val) << (field ## _SHIFT)) & ~(field ## _MASK))
@@ -59,19 +60,9 @@
#define MGA_FALLBACK_RENDERMODE 0x10
#define MGA_FALLBACK_STENCIL 0x20
#define MGA_FALLBACK_DEPTH 0x40
+#define MGA_FALLBACK_BORDER_MODE 0x80
-/* For mgaCtx->new_state.
- */
-#define MGA_NEW_DEPTH 0x1
-#define MGA_NEW_ALPHA 0x2
-#define MGA_NEW_CLIP 0x8
-#define MGA_NEW_TEXTURE 0x20
-#define MGA_NEW_CULL 0x40
-#define MGA_NEW_WARP 0x80
-#define MGA_NEW_STENCIL 0x100
-#define MGA_NEW_CONTEXT 0x200
-
/* Use the templated vertex formats:
*/
#define TAG(x) mga##x
@@ -96,43 +87,103 @@ typedef void (*mga_point_func)( mgaContextPtr, mgaVertex * );
struct mga_texture_object_s;
struct mga_screen_private_s;
-#define MGA_TEX_MAXLEVELS 5
+#define G200_TEX_MAXLEVELS 5
+#define G400_TEX_MAXLEVELS 11
typedef struct mga_texture_object_s
{
- struct mga_texture_object_s *next;
- struct mga_texture_object_s *prev;
- struct gl_texture_object *tObj;
- struct mga_context_t *ctx;
- PMemBlock MemBlock;
- GLuint offsets[MGA_TEX_MAXLEVELS];
- int lastLevel;
- GLuint dirty_images;
- GLuint totalSize;
- int texelBytes;
- GLuint age;
- int bound;
- int heap; /* agp or card */
+ driTextureObject base;
+
+ /* The G200 only has the ability to use 5 mipmap levels (including the
+ * base level). The G400 does not have this restriction, but it still
+ * only has 5 offset pointers in the hardware. The trick on the G400 is
+ * upto the first 4 offset pointers point to mipmap levels. The last
+ * offset pointer tells how large the preceeding mipmap is. This value is
+ * then used to determine where the remaining mipmaps are.
+ *
+ * For example, if the first offsets[0] through offsets[2] are used as
+ * pointers, then offset[3] will be the size of the mipmap pointed to by
+ * offsets[2]. So mipmap level 3 will be at (offsets[2]+offsets[3]). For
+ * each successive mipmap level, offsets[3] is divided by 4 and added to
+ * the previous address. So mipmap level 4 will be at
+ * (offsets[2]+offsets[3]+(offsets[3] / 4)).
+ *
+ * The last pointer is selected by setting TO_texorgoffsetsel in its
+ * pointer. In the previous example, offset[2] would have
+ * TO_texorgoffsetsel or'ed in before writing it to the hardware.
+ *
+ * In the current driver all of the mipmaps are packed together linearly
+ * with mipmap level 0. Therefore offsets[0] points to the base of the
+ * texture (and has TO_texorgoffsetsel or'ed in), and offsets[1] is the
+ * size of the base texture.
+ *
+ * There is a possible optimization available here. At times the driver
+ * may not be able to allocate a single block of memory for the complete
+ * texture without ejecting some other textures from memory. It may be
+ * possible to put some of the lower mipmap levels (i.e., the larger
+ * mipmaps) in memory separate from the higher levels.
+ *
+ * The implementation should be fairly obvious, but getting "right" would
+ * likely be non-trivial. A first allocation for the entire texture would
+ * be attempted with a flag that says "don't eject other textures." If
+ * that failed, an additional allocation would be attmpted for just the
+ * base map. The process would repeat with the block of lower maps. The
+ * tricky parts would be in detecting when some of the levels had been
+ * ejected from texture memory by other textures and preventing the
+ * 4th allocation (for all the smallest mipmap levels) from kicking out
+ * any of the first three.
+ *
+ * This array holds G400_TEX_MAXLEVELS pointers to remove an if-statement
+ * in a loop in mgaSetTexImages. Values past G200_TEX_MAXLEVELS are not
+ * used.
+ */
+ GLuint offsets[G400_TEX_MAXLEVELS];
+
+ int texelBytes;
+ GLuint age;
mga_texture_regs_t setup;
+
+ /* If one texture dimension wraps with GL_CLAMP and the other with
+ * GL_CLAMP_TO_EDGE, we have to fallback to software. We would also have
+ * to fallback for GL_CLAMP_TO_BORDER.
+ */
+ GLboolean border_fallback;
} mgaTextureObject_t;
+struct mga_hw_state {
+ GLuint specen;
+ GLuint cull;
+ GLuint cull_dualtex;
+ GLuint stencil;
+ GLuint stencilctl;
+ GLuint stencil_enable;
+ GLuint zmode;
+ GLuint rop;
+ GLuint alpha_func;
+ GLuint alpha_func_enable;
+ GLuint blend_func;
+ GLuint blend_func_enable;
+ GLuint alpha_sel;
+};
+
struct mga_context_t {
GLcontext *glCtx;
- unsigned int lastStamp; /* fullscreen breaks dpriv->laststamp,
- * need to shadow it here. */
+ unsigned int lastStamp; /* fullscreen breaks dpriv->laststamp,
+ * need to shadow it here. */
+
+ /* Hardware state management
+ */
+ struct mga_hw_state hw;
/* Bookkeeping for texturing
*/
- int lastTexHeap;
- struct mga_texture_object_s TexObjList[MGA_NR_TEX_HEAPS];
- struct mga_texture_object_s SwappedOut;
+ unsigned nr_heaps;
+ driTexHeap * texture_heaps[ MGA_NR_TEX_HEAPS ];
+ driTextureObject swapped;
+
struct mga_texture_object_s *CurrentTexObj[2];
- memHeap_t *texHeap[MGA_NR_TEX_HEAPS];
- int c_texupload;
- int c_texusage;
- int tex_thrash;
/* Map GL texture units onto hardware.
@@ -166,7 +217,7 @@ struct mga_context_t {
GLenum raster_primitive;
GLenum render_primitive;
- char *verts;
+ GLubyte *verts;
GLint vertex_stride_shift;
GLuint vertex_format;
GLuint vertex_size;
@@ -180,8 +231,7 @@ struct mga_context_t {
/* Manage driver and hardware state
*/
- GLuint new_gl_state;
- GLuint new_state;
+ GLuint NewGLState;
GLuint dirty;
mga_context_regs_t setup;
@@ -205,13 +255,21 @@ struct mga_context_t {
/* VBI
*/
GLuint vbl_seq;
+ GLuint vblank_flags;
+
+ uint64_t swap_ust;
+ uint64_t swap_missed_ust;
+
+ GLuint swap_count;
+ GLuint swap_missed_count;
+
+ PFNGLXGETUSTPROC get_ust;
/* Drawable, cliprect and scissor information
*/
int dirty_cliprects; /* which sets of cliprects are uptodate? */
int draw_buffer; /* which buffer are we rendering to */
unsigned int drawOffset; /* draw buffer address in space */
- int read_buffer;
int readOffset;
int drawX, drawY; /* origin of drawable in draw buffer */
int lastX, lastY; /* detect DSTORG bug */
@@ -245,51 +303,38 @@ struct mga_context_t {
#define MGA_CONTEXT(ctx) ((mgaContextPtr)(ctx->DriverCtx))
-#define MGAPACKCOLOR555(r,g,b,a) \
- ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \
- ((a) ? 0x8000 : 0))
-#define MGAPACKCOLOR565(r,g,b) \
- ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3))
-#define MGAPACKCOLOR88(l, a) \
- (((l) << 8) | (a))
-
-#define MGAPACKCOLOR888(r,g,b) \
- (((r) << 16) | ((g) << 8) | (b))
-
-#define MGAPACKCOLOR8888(r,g,b,a) \
- (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-
-#define MGAPACKCOLOR4444(r,g,b,a) \
- ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4))
+/* ================================================================
+ * Debugging:
+ */
+#define DO_DEBUG 1
-#define MGA_DEBUG 0
-#ifndef MGA_DEBUG
+#if DO_DEBUG
extern int MGA_DEBUG;
+#else
+#define MGA_DEBUG 0
#endif
-#define DEBUG_ALWAYS_SYNC 0x1
-#define DEBUG_VERBOSE_MSG 0x2
-#define DEBUG_VERBOSE_LRU 0x4
-#define DEBUG_VERBOSE_DRI 0x8
-#define DEBUG_VERBOSE_IOCTL 0x10
-#define DEBUG_VERBOSE_2D 0x20
-#define DEBUG_VERBOSE_FALLBACK 0x40
+#define DEBUG_VERBOSE_MSG 0x01
+#define DEBUG_VERBOSE_DRI 0x02
+#define DEBUG_VERBOSE_IOCTL 0x04
+#define DEBUG_VERBOSE_TEXTURE 0x08
+#define DEBUG_VERBOSE_FALLBACK 0x10
static __inline__ GLuint mgaPackColor(GLuint cpp,
GLubyte r, GLubyte g,
GLubyte b, GLubyte a)
{
- switch (cpp) {
- case 2:
- return MGAPACKCOLOR565(r,g,b);
- case 4:
- return MGAPACKCOLOR8888(r,g,b,a);
- default:
- return 0;
- }
+ switch (cpp) {
+ case 2:
+ return PACK_COLOR_565( r, g, b );
+ case 4:
+ return PACK_COLOR_8888( a, r, g, b );
+ default:
+ return 0;
+ }
}
diff --git a/src/mesa/drivers/dri/mga/mgadd.c b/src/mesa/drivers/dri/mga/mgadd.c
index 6ce50e6726..d2f11d8d45 100644
--- a/src/mesa/drivers/dri/mga/mgadd.c
+++ b/src/mesa/drivers/dri/mga/mgadd.c
@@ -29,10 +29,6 @@
#include "mtypes.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
#include "mm.h"
#include "mgacontext.h"
#include "mgadd.h"
@@ -42,12 +38,9 @@
#include "mgatris.h"
#include "mgavb.h"
#include "mga_xmesa.h"
-#include "extensions.h"
-#if defined(USE_X86_ASM)
-#include "X86/common_x86_asm.h"
-#endif
+#include "utils.h"
-#define MGA_DATE "20020221"
+#define DRIVER_DATE "20030328"
/***************************************
@@ -59,52 +52,19 @@ static const GLubyte *mgaDDGetString( GLcontext *ctx, GLenum name )
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
static char buffer[128];
+ unsigned offset;
switch ( name ) {
case GL_VENDOR:
return (GLubyte *) "VA Linux Systems Inc.";
case GL_RENDERER:
- sprintf( buffer, "Mesa DRI %s " MGA_DATE,
- MGA_IS_G400(mmesa) ? "G400" :
- MGA_IS_G200(mmesa) ? "G200" : "MGA" );
-
- /* Append any AGP-specific information.
- */
- switch ( mmesa->mgaScreen->agpMode ) {
- case 1:
- strncat( buffer, " AGP 1x", 7 );
- break;
- case 2:
- strncat( buffer, " AGP 2x", 7 );
- break;
- case 4:
- strncat( buffer, " AGP 4x", 7 );
- break;
- }
-
- /* 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
+ offset = driGetRendererString( buffer,
+ MGA_IS_G400(mmesa) ? "G400" :
+ MGA_IS_G200(mmesa) ? "G200" : "MGA",
+ DRIVER_DATE,
+ mmesa->mgaScreen->agpMode );
+
return (GLubyte *)buffer;
default:
@@ -129,40 +89,6 @@ static void mgaBufferSize(GLframebuffer *buffer, GLuint *width, GLuint *height)
UNLOCK_HARDWARE( mmesa );
}
-void mgaDDExtensionsInit( GLcontext *ctx )
-{
- /* paletted_textures currently doesn't work, but we could fix them later */
- /*
- _mesa_enable_extension( ctx, "GL_EXT_shared_texture_palette" );
- _mesa_enable_extension( ctx, "GL_EXT_paletted_texture" );
- */
-
- _mesa_enable_extension( ctx, "GL_ARB_texture_compression" );
- _mesa_enable_extension( ctx, "GL_ARB_multisample" );
-
- _mesa_enable_extension( ctx, "GL_SGIS_generate_mipmap" );
-
- /* Turn on multitexture and texenv_add for the G400.
- */
- if (MGA_IS_G400(MGA_CONTEXT(ctx))) {
- _mesa_enable_extension( ctx, "GL_ARB_multitexture" );
- _mesa_enable_extension( ctx, "GL_ARB_texture_env_add" );
-
- _mesa_enable_extension( ctx, "GL_EXT_texture_env_add" );
-
-#if defined (MESA_packed_depth_stencil)
- _mesa_enable_extension( ctx, "GL_MESA_packed_depth_stencil" );
-#endif
-
-#if defined (MESA_experimetal_agp_allocator)
- if (!getenv("MGA_DISABLE_AGP_ALLOCATOR"))
- _mesa_enable_extension( ctx, "GL_MESA_experimental_agp_allocator" );
-#endif
- }
-}
-
-
-
void mgaDDInitDriverFuncs( GLcontext *ctx )
{
ctx->Driver.GetBufferSize = mgaBufferSize;
diff --git a/src/mesa/drivers/dri/mga/mgadd.h b/src/mesa/drivers/dri/mga/mgadd.h
index 6072e6cfc9..919fd742d6 100644
--- a/src/mesa/drivers/dri/mga/mgadd.h
+++ b/src/mesa/drivers/dri/mga/mgadd.h
@@ -32,6 +32,5 @@
#include "context.h"
void mgaDDInitDriverFuncs( GLcontext *ctx );
-void mgaDDExtensionsInit( GLcontext *ctx );
#endif
diff --git a/src/mesa/drivers/dri/mga/mgaioctl.c b/src/mesa/drivers/dri/mga/mgaioctl.c
index f88c878060..6b50af202a 100644
--- a/src/mesa/drivers/dri/mga/mgaioctl.c
+++ b/src/mesa/drivers/dri/mga/mgaioctl.c
@@ -27,7 +27,7 @@
*/
/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgaioctl.c,v 1.16 2002/12/16 16:18:52 dawes Exp $ */
-#include <stdio.h>
+#include <sched.h>
#include <errno.h>
#include "mtypes.h"
@@ -43,11 +43,10 @@
#include "mgavb.h"
#include "mgaioctl.h"
#include "mgatris.h"
-#include "mgabuffers.h"
+#include "mga_common.h"
+#include "vblank.h"
-#include "xf86drm.h"
-#include "mga_common.h"
static void mga_iload_dma_ioctl(mgaContextPtr mmesa,
unsigned long dest,
@@ -61,6 +60,13 @@ static void mga_iload_dma_ioctl(mgaContextPtr mmesa,
fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
buf->idx, (int) dest, length);
+ if ( (length & MGA_ILOAD_MASK) != 0 ) {
+ UNLOCK_HARDWARE( mmesa );
+ fprintf( stderr, "%s: Invalid ILOAD datasize (%d), must be "
+ "multiple of %u.\n", __FUNCTION__, length, MGA_ILOAD_ALIGN );
+ exit( 1 );
+ }
+
iload.idx = buf->idx;
iload.dstorg = dest;
iload.length = length;
@@ -278,65 +284,11 @@ mgaDDClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
}
-int nrswaps;
-
-
-void mgaWaitForVBlank( mgaContextPtr mmesa )
-{
-#if 0
- drmVBlank vbl;
- int ret;
-
- if ( !mmesa->mgaScreen->irq )
- return;
-
- if ( getenv("LIBGL_SYNC_REFRESH") ) {
- /* Wait for until the next vertical blank */
- vbl.request.type = DRM_VBLANK_RELATIVE;
- vbl.request.sequence = 1;
- } else if ( getenv("LIBGL_THROTTLE_REFRESH") ) {
- /* Wait for at least one vertical blank since the last call */
- vbl.request.type = DRM_VBLANK_ABSOLUTE;
- vbl.request.sequence = mmesa->vbl_seq + 1;
- } else {
- return;
- }
-
- if ((ret = drmWaitVBlank( mmesa->driFd, &vbl ))) {
- fprintf(stderr, "%s: drmWaitVBlank returned %d, IRQs don't seem to be"
- " working correctly.\nTry running with LIBGL_THROTTLE_REFRESH"
- " and LIBL_SYNC_REFRESH unset.\n", __FUNCTION__, ret);
- exit(1);
- }
-
- mmesa->vbl_seq = vbl.reply.sequence;
-#endif
-}
-
-
-/*
- * Copy the back buffer to the front buffer.
- */
-void mgaSwapBuffers(__DRIdrawablePrivate *dPriv)
+static void mgaWaitForFrameCompletion( mgaContextPtr mmesa )
{
- mgaContextPtr mmesa;
- XF86DRIClipRectPtr pbox;
- GLint nbox;
- GLint ret, wait = 0;
- GLint i;
+ unsigned wait = 0;
GLuint last_frame, last_wrap;
- assert(dPriv);
- assert(dPriv->driContextPriv);
- assert(dPriv->driContextPriv->driverPrivate);
-
- mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
-
- FLUSH_BATCH( mmesa );
-
- mgaWaitForVBlank( mmesa );
-
- LOCK_HARDWARE( mmesa );
last_frame = mmesa->sarea->last_frame.head;
last_wrap = mmesa->sarea->last_frame.wrap;
@@ -360,12 +312,46 @@ void mgaSwapBuffers(__DRIdrawablePrivate *dPriv)
}
UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
- for ( i = 0 ; i < 1024 ; i++ ) {
- /* Don't just hammer the register... */
- }
+ UNLOCK_HARDWARE( mmesa );
+ DO_USLEEP( 1 );
+ LOCK_HARDWARE( mmesa );
}
if ( wait )
fprintf( stderr, "\n" );
+}
+
+
+/*
+ * Copy the back buffer to the front buffer.
+ */
+void mgaSwapBuffers( __DRIdrawablePrivate *dPriv )
+{
+ mgaContextPtr mmesa;
+ XF86DRIClipRectPtr pbox;
+ GLint nbox;
+ GLint ret;
+ GLint i;
+ GLboolean missed_target;
+
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
+
+ FLUSH_BATCH( mmesa );
+
+ LOCK_HARDWARE( mmesa );
+ mgaWaitForFrameCompletion( mmesa );
+ UNLOCK_HARDWARE( mmesa );
+ driWaitForVBlank( dPriv, & mmesa->vbl_seq, mmesa->vblank_flags,
+ & missed_target );
+ if ( missed_target ) {
+ mmesa->swap_missed_count++;
+ (void) (*mmesa->get_ust)( & mmesa->swap_missed_ust );
+ }
+ LOCK_HARDWARE( mmesa );
/* Use the frontbuffer cliprects
*/
@@ -399,6 +385,8 @@ void mgaSwapBuffers(__DRIdrawablePrivate *dPriv)
UNLOCK_HARDWARE( mmesa );
mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
+ mmesa->swap_count++;
+ (void) (*mmesa->get_ust)( & mmesa->swap_ust );
}
@@ -442,18 +430,17 @@ void mgaWaitAge( mgaContextPtr mmesa, int age )
}
-static int intersect_rect( XF86DRIClipRectPtr out,
- XF86DRIClipRectPtr a,
- XF86DRIClipRectPtr b )
+static GLboolean 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;
+
+ return ((out->x1 < out->x2) && (out->y1 < out->y2));
}
@@ -559,7 +546,7 @@ void mgaFlushVerticesLocked( mgaContextPtr mmesa )
vertex.idx = buffer->idx;
vertex.used = buffer->used;
vertex.discard = discard;
- drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
+ drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
&vertex, sizeof(drmMGAVertex) );
age_mmesa(mmesa, mmesa->sarea->last_enqueue);
diff --git a/src/mesa/drivers/dri/mga/mgaioctl.h b/src/mesa/drivers/dri/mga/mgaioctl.h
index b7cf44d6ff..2d959d8246 100644
--- a/src/mesa/drivers/dri/mga/mgaioctl.h
+++ b/src/mesa/drivers/dri/mga/mgaioctl.h
@@ -34,6 +34,7 @@
#include "mga_xmesa.h"
void mgaSwapBuffers( __DRIdrawablePrivate *dPriv );
+void mgaWaitForVBlank( mgaContextPtr mmesa );
GLuint *mgaAllocVertexDwords( mgaContextPtr mmesa, int dwords );
@@ -41,7 +42,6 @@ GLuint *mgaAllocVertexDwords( mgaContextPtr mmesa, int dwords );
void mgaGetILoadBufferLocked( mgaContextPtr mmesa );
drmBufPtr mgaGetBufferLocked( mgaContextPtr mmesa );
-void mgaWaitForVBlank( mgaContextPtr mmesa );
void mgaFireILoadLocked( mgaContextPtr mmesa,
GLuint offset, GLuint length );
@@ -104,8 +104,9 @@ do { \
if ( ret < 0 ) { \
drmCommandNone( mmesa->driFd, DRM_MGA_RESET ); \
UNLOCK_HARDWARE( mmesa ); \
- fprintf( stderr, "%s: flush ret=%d\n", __FUNCTION__, ret ); \
- /*fprintf( stderr, "drmMGAFlushDMA: return = %d\n", ret );*/ \
+ fprintf( stderr, "%s: flush return = %s (%d), flags = 0x%08x\n", \
+ __FUNCTION__, strerror( -ret ), -ret, \
+ (unsigned)(flags) ); \
exit( 1 ); \
} \
} while (0)
diff --git a/src/mesa/drivers/dri/mga/mgapixel.c b/src/mesa/drivers/dri/mga/mgapixel.c
index 0bc4b3fac5..07e0c3a756 100644
--- a/src/mesa/drivers/dri/mga/mgapixel.c
+++ b/src/mesa/drivers/dri/mga/mgapixel.c
@@ -35,12 +35,12 @@
#include "mgacontext.h"
#include "mgaioctl.h"
#include "mgapixel.h"
-#include "mgabuffers.h"
+#include "mgastate.h"
-#include "xf86drm.h"
#include "mga_common.h"
#include "swrast/swrast.h"
+#include "imports.h"
#define IS_AGP_MEM( mmesa, p ) \
((unsigned long)mmesa->mgaScreen->buffers.map <= ((unsigned long)p) && \
@@ -134,7 +134,7 @@ check_color_per_fragment_ops( const GLcontext *ctx )
!ctx->Color.ColorMask[2] ||
!ctx->Color.ColorMask[3] ||
ctx->Color.ColorLogicOpEnabled ||
- ctx->Texture.Unit[0]._ReallyEnabled ||
+ ctx->Texture._EnabledUnits ||
ctx->Depth.OcclusionTest
) &&
ctx->Current.RasterPosValid &&
@@ -596,7 +596,7 @@ mgaTryDrawPixels( GLcontext *ctx,
}
}
#else
- memcpy( address, pixels, rows*bufferpitch );
+ MEMCPY( address, pixels, rows*bufferpitch );
#endif
do_draw_pix( ctx, x, y, width, rows,
@@ -639,42 +639,8 @@ mgaDDDrawPixels( GLcontext *ctx,
* the same block of agp space which isn't used for anything else at
* present.
*/
-#if defined(MESA_hacked_agp_allocator)
-static void mgaDDFreeAgpMemory( GLcontext *ctx, void *ptr )
-{
- (void) ptr;
-}
-
-static void *mgaDDAllocateAgpMemory( GLcontext *ctx, GLsizei size )
-{
- mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-
- if (size < mmesa->mgaScreen->textureSize[MGA_AGP_HEAP])
- return mmesa->mgaScreen->texVirtual[MGA_AGP_HEAP];
- else
- return 0;
-}
-
-static GLint mgaDDGetAgpOffset( GLcontext *ctx, const void *ptr )
-{
- mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-
- if (!IS_AGP_MEM(mmesa, ptr))
- return -1;
-
- return AGP_OFFSET(mmesa, ptr);
-}
-#endif
-
-
void mgaDDInitPixelFuncs( GLcontext *ctx )
{
-#if defined (MESA_experimetal_agp_allocator)
- ctx->Driver.AllocateAgpMemory = mgaDDAllocateAgpMemory;
- ctx->Driver.GetAgpOffset = mgaDDGetAgpOffset;
- ctx->Driver.FreeAgpMemory = mgaDDFreeAgpMemory;
-#endif
-
/* Pixel path fallbacks.
*/
ctx->Driver.Accum = _swrast_Accum;
diff --git a/src/mesa/drivers/dri/mga/mgaregs.h b/src/mesa/drivers/dri/mga/mgaregs.h
index f07dc2de0b..e1291ca01b 100644
--- a/src/mesa/drivers/dri/mga/mgaregs.h
+++ b/src/mesa/drivers/dri/mga/mgaregs.h
@@ -1052,6 +1052,7 @@
# define TMC_tformat_tw8a 0x7 /* val 7, shift 0 */
# define TMC_tformat_tw8al 0x8 /* val 8, shift 0 */
# define TMC_tformat_tw422 0xa /* val 10, shift 0 */
+# define TMC_tformat_tw422uyvy 0xb /* val 11, shift 0 */
# define TMC_tpitchlin_MASK 0xfffffeff /* bit 8 */
# define TMC_tpitchlin_disable 0x0
# define TMC_tpitchlin_enable 0x100
@@ -1137,6 +1138,13 @@
# define TF_magfilter_nrst 0x0 /* val 0, shift 4 */
# define TF_magfilter_bilin 0x20 /* val 2, shift 4 */
# define TF_magfilter_cnst 0x30 /* val 3, shift 4 */
+# define TF_uvoffset_SHIFT 17
+# define TF_uvoffset_OGL (0U << TF_uvoffset_SHIFT)
+# define TF_uvoffset_D3D (1U << TF_uvoffset_SHIFT)
+# define TF_uvoffset_MASK (~(1U << TF_uvoffset_SHIFT))
+# define TF_reserved_MASK (~0x1ff00) /* bits 8-16 */
+# define TF_mapnbhigh_SHIFT 18
+# define TF_mapnbhigh_MASK (~(1U << TF_mapnbhigh_SHIFT))
# define TF_avgstride_MASK 0xfff7ffff /* bit 19 */
# define TF_avgstride_disable 0x0
# define TF_avgstride_enable 0x80000
@@ -1377,5 +1385,11 @@
/**************** (END) AUTOMATICLY GENERATED REGISTER FILE ******************/
+/* Copied from mga_drv.h kernel file.
+ */
+
+#define MGA_ILOAD_ALIGN 64
+#define MGA_ILOAD_MASK (MGA_ILOAD_ALIGN - 1)
+
#endif /* _MGAREGS_H_ */
diff --git a/src/mesa/drivers/dri/mga/mgarender.c b/src/mesa/drivers/dri/mga/mgarender.c
index 53614c223f..516a99099f 100644
--- a/src/mesa/drivers/dri/mga/mgarender.c
+++ b/src/mesa/drivers/dri/mga/mgarender.c
@@ -42,9 +42,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "glheader.h"
#include "context.h"
#include "macros.h"
-/*//#include "mem.h"*/
+#include "imports.h"
#include "mtypes.h"
-/*#include "mmath.h" */
#include "tnl/t_context.h"
@@ -165,7 +164,7 @@ static GLboolean mga_run_render( GLcontext *ctx,
static void mga_check_render( GLcontext *ctx, struct gl_pipeline_stage *stage )
{
- GLuint inputs = VERT_BIT_POS | VERT_BIT_CLIP | VERT_BIT_COLOR0;
+ GLuint inputs = VERT_BIT_CLIP | VERT_BIT_COLOR0;
if (ctx->RenderMode == GL_RENDER) {
if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)
diff --git a/src/mesa/drivers/dri/mga/mgaspan.c b/src/mesa/drivers/dri/mga/mgaspan.c
index 8dc971cfc5..684239865f 100644
--- a/src/mesa/drivers/dri/mga/mgaspan.c
+++ b/src/mesa/drivers/dri/mga/mgaspan.c
@@ -116,7 +116,7 @@
#undef INIT_MONO_PIXEL
#define INIT_MONO_PIXEL(p, color) \
- p = MGAPACKCOLOR565( color[0], color[1], color[2] )
+ p = PACK_COLOR_565( color[0], color[1], color[2] )
#define WRITE_RGBA( _x, _y, r, g, b, a ) \
@@ -148,7 +148,7 @@ do { \
#undef INIT_MONO_PIXEL
#define INIT_MONO_PIXEL(p, color) \
- p = MGAPACKCOLOR8888( color[0], color[1], color[2], color[3] )
+ p = PACK_COLOR_8888( color[3], color[0], color[1], color[2] )
#define WRITE_RGBA(_x, _y, r, g, b, a) \
@@ -233,11 +233,38 @@ do { \
+/*
+ * This function is called to specify which buffer to read and write
+ * for software rasterization (swrast) fallbacks. This doesn't necessarily
+ * correspond to glDrawBuffer() or glReadBuffer() calls.
+ */
+static void mgaDDSetBuffer(GLcontext *ctx, GLframebuffer *buffer,
+ GLuint bufferBit)
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+
+ if (bufferBit == FRONT_LEFT_BIT)
+ {
+ mmesa->drawOffset = mmesa->mgaScreen->frontOffset;
+ mmesa->readOffset = mmesa->mgaScreen->frontOffset;
+ }
+ else if (bufferBit == BACK_LEFT_BIT)
+ {
+ mmesa->drawOffset = mmesa->mgaScreen->backOffset;
+ mmesa->readOffset = mmesa->mgaScreen->backOffset;
+ }
+ else {
+ assert(0);
+ }
+}
+
void mgaDDInitSpanFuncs( GLcontext *ctx )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx);
+ swdd->SetBuffer = mgaDDSetBuffer;
+
switch (mmesa->mgaScreen->cpp) {
case 2:
swdd->WriteRGBASpan = mgaWriteRGBASpan_565;
diff --git a/src/mesa/drivers/dri/mga/mgastate.c b/src/mesa/drivers/dri/mga/mgastate.c
index 02b98fdb76..0d304966d7 100644
--- a/src/mesa/drivers/dri/mga/mgastate.c
+++ b/src/mesa/drivers/dri/mga/mgastate.c
@@ -26,9 +26,9 @@
*/
/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgastate.c,v 1.13 2002/10/30 12:51:36 alanh Exp $ */
-#include <stdio.h>
#include "mtypes.h"
+#include "colormac.h"
#include "dd.h"
#include "mm.h"
@@ -40,19 +40,22 @@
#include "mgatris.h"
#include "mgaioctl.h"
#include "mgaregs.h"
-#include "mgabuffers.h"
#include "swrast/swrast.h"
#include "array_cache/acache.h"
#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
#include "swrast_setup/swrast_setup.h"
+static void updateSpecularLighting( GLcontext *ctx );
+
/* Some outstanding problems with accelerating logic ops...
*/
#if defined(ACCEL_ROP)
-static GLuint mgarop_NoBLK[16] = {
+static const GLuint mgarop_NoBLK[16] = {
DC_atype_rpl | 0x00000000, DC_atype_rstr | 0x00080000,
DC_atype_rstr | 0x00040000, DC_atype_rpl | 0x000c0000,
DC_atype_rstr | 0x00020000, DC_atype_rstr | 0x000a0000,
@@ -65,221 +68,57 @@ static GLuint mgarop_NoBLK[16] = {
#endif
-static void mgaUpdateStencil(const GLcontext *ctx)
-{
- mgaContextPtr mmesa = MGA_CONTEXT(ctx);
- GLuint stencil = 0, stencilctl = 0;
-
- if (ctx->Stencil.Enabled)
- {
- stencil = ctx->Stencil.Ref[0] |
- ( ctx->Stencil.ValueMask[0] << 8 ) |
- ( ctx->Stencil.WriteMask[0] << 16 );
-
- switch (ctx->Stencil.Function[0])
- {
- case GL_NEVER:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_snever);
- break;
- case GL_LESS:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_slt);
- break;
- case GL_LEQUAL:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_slte);
- break;
- case GL_GREATER:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sgt);
- break;
- case GL_GEQUAL:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sgte);
- break;
- case GL_NOTEQUAL:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sne);
- break;
- case GL_EQUAL:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_se);
- break;
- case GL_ALWAYS:
- MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_salways);
- default:
- break;
- }
-
- switch (ctx->Stencil.FailFunc[0])
- {
- case GL_KEEP:
- MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_keep);
- break;
- case GL_ZERO:
- MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_zero);
- break;
- case GL_REPLACE:
- MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_replace);
- break;
- case GL_INCR:
- MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_incrsat);
- break;
- case GL_DECR:
- MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_decrsat);
- break;
- case GL_INVERT:
- MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_invert);
- break;
- default:
- break;
- }
-
- switch (ctx->Stencil.ZFailFunc[0])
- {
- case GL_KEEP:
- MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_keep);
- break;
- case GL_ZERO:
- MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_zero);
- break;
- case GL_REPLACE:
- MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_replace);
- break;
- case GL_INCR:
- MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_incrsat);
- break;
- case GL_DECR:
- MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_decrsat);
- break;
- case GL_INVERT:
- MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_invert);
- break;
- default:
- break;
- }
-
- switch (ctx->Stencil.ZPassFunc[0])
- {
- case GL_KEEP:
- MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_keep);
- break;
- case GL_ZERO:
- MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_zero);
- break;
- case GL_REPLACE:
- MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_replace);
- break;
- case GL_INCR:
- MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_incrsat);
- break;
- case GL_DECR:
- MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_decrsat);
- break;
- case GL_INVERT:
- MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_invert);
- break;
- default:
- break;
- }
- }
-
- mmesa->setup.stencil = stencil;
- mmesa->setup.stencilctl = stencilctl;
- mmesa->dirty |= MGA_UPLOAD_CONTEXT;
-}
-
-static void mgaDDStencilFunc(GLcontext *ctx, GLenum func, GLint ref,
- GLuint mask)
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL;
-}
-
-static void mgaDDStencilMask(GLcontext *ctx, GLuint mask)
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL;
-}
-
-static void mgaDDStencilOp(GLcontext *ctx, GLenum fail, GLenum zfail,
- GLenum zpass)
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL;
-}
+/* =============================================================
+ * Alpha blending
+ */
-static void mgaDDClearDepth(GLcontext *ctx, GLclampd d)
+static void mgaDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ GLubyte refByte;
+ GLuint a;
- /* KW: should the ~ be there? */
- switch (mmesa->setup.maccess & ~MA_zwidth_MASK) {
- case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break;
- case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break;
- case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break;
- default: return;
- }
-}
-
-static void mgaUpdateZMode(const GLcontext *ctx)
-{
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- int zmode = 0;
-
- if (ctx->Depth.Test) {
- switch(ctx->Depth.Func) {
- case GL_NEVER:
- /* can't do this in h/w, we'll use a s/w fallback */
- zmode = DC_zmode_nozcmp;
- break;
- case GL_ALWAYS:
- zmode = DC_zmode_nozcmp; break;
- case GL_LESS:
- zmode = DC_zmode_zlt; break;
- case GL_LEQUAL:
- zmode = DC_zmode_zlte; break;
- case GL_EQUAL:
- zmode = DC_zmode_ze; break;
- case GL_GREATER:
- zmode = DC_zmode_zgt; break;
- case GL_GEQUAL:
- zmode = DC_zmode_zgte; break;
- case GL_NOTEQUAL:
- zmode = DC_zmode_zne; break;
- default:
- break;
- }
+ CLAMPED_FLOAT_TO_UBYTE(refByte, ref);
- if (ctx->Depth.Mask)
- zmode |= DC_atype_zi;
- else
- zmode |= DC_atype_i;
- }
- else {
- zmode |= DC_zmode_nozcmp;
- zmode |= DC_atype_i; /* don't write to zbuffer */
+ switch ( func ) {
+ case GL_NEVER:
+ a = AC_atmode_alt;
+ refByte = 0;
+ break;
+ case GL_LESS:
+ a = AC_atmode_alt;
+ break;
+ case GL_GEQUAL:
+ a = AC_atmode_agte;
+ break;
+ case GL_LEQUAL:
+ a = AC_atmode_alte;
+ break;
+ case GL_GREATER:
+ a = AC_atmode_agt;
+ break;
+ case GL_NOTEQUAL:
+ a = AC_atmode_ane;
+ break;
+ case GL_EQUAL:
+ a = AC_atmode_ae;
+ break;
+ case GL_ALWAYS:
+ a = AC_atmode_noacmp;
+ break;
+ default:
+ a = 0;
+ break;
}
-#if defined(ACCEL_ROP)
- mmesa->setup.dwgctl &= DC_bop_MASK;
- if (ctx->Color.ColorLogicOpEnabled)
- zmode |= mgarop_NoBLK[(ctx->Color.LogicOp)&0xf];
- else
- zmode |= mgarop_NoBLK[GL_COPY & 0xf];
-#endif
-
- mmesa->setup.dwgctl &= DC_zmode_MASK & DC_atype_MASK;
- mmesa->setup.dwgctl |= zmode;
+ FLUSH_BATCH( mmesa );
+ mmesa->hw.alpha_func = a | MGA_FIELD( AC_atref, refByte );
mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
-
-static void mgaDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref)
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
-}
-
-
static void mgaDDBlendEquation(GLcontext *ctx, GLenum mode)
{
FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
/* BlendEquation sets ColorLogicOpEnabled in an unexpected
* manner.
@@ -291,247 +130,169 @@ static void mgaDDBlendEquation(GLcontext *ctx, GLenum mode)
static void mgaDDBlendFunc(GLcontext *ctx, GLenum sfactor, GLenum dfactor)
{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ mgaScreenPrivate *mgaScreen = mmesa->mgaScreen;
+ GLuint src;
+ GLuint dst;
+
+ switch (ctx->Color.BlendSrcRGB) {
+ case GL_ZERO:
+ src = AC_src_zero; break;
+ case GL_SRC_ALPHA:
+ src = AC_src_src_alpha; break;
+ case GL_ONE:
+ default: /* never happens */
+ src = AC_src_one; break;
+ case GL_DST_COLOR:
+ src = AC_src_dst_color; break;
+ case GL_ONE_MINUS_DST_COLOR:
+ src = AC_src_om_dst_color; break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ src = AC_src_om_src_alpha; break;
+ case GL_DST_ALPHA:
+ src = (mgaScreen->cpp == 4)
+ ? AC_src_dst_alpha : AC_src_one;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ src = (mgaScreen->cpp == 4)
+ ? AC_src_om_dst_alpha : AC_src_zero;
+ break;
+ case GL_SRC_ALPHA_SATURATE:
+ src = (ctx->Visual.alphaBits > 0)
+ ? AC_src_src_alpha_sat : AC_src_zero;
+ break;
+ }
+
+ switch (ctx->Color.BlendDstRGB) {
+ case GL_SRC_ALPHA:
+ dst = AC_dst_src_alpha; break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ dst = AC_dst_om_src_alpha; break;
+ default: /* never happens */
+ case GL_ZERO:
+ dst = AC_dst_zero; break;
+ case GL_ONE:
+ dst = AC_dst_one; break;
+ case GL_SRC_COLOR:
+ dst = AC_dst_src_color; break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ dst = AC_dst_om_src_color; break;
+ case GL_DST_ALPHA:
+ dst = (mgaScreen->cpp == 4)
+ ? AC_dst_dst_alpha : AC_dst_one;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ dst = (mgaScreen->cpp == 4)
+ ? AC_dst_om_dst_alpha : AC_dst_zero;
+ break;
+ }
+
+ FLUSH_BATCH( mmesa );
+ mmesa->hw.blend_func = (src | dst);
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
static void mgaDDBlendFuncSeparate( GLcontext *ctx, GLenum sfactorRGB,
GLenum dfactorRGB, GLenum sfactorA,
GLenum dfactorA )
{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
+ mgaDDBlendFunc( ctx, sfactorRGB, dfactorRGB );
}
+/* =============================================================
+ * Depth testing
+ */
-static void mgaDDLightModelfv(GLcontext *ctx, GLenum pname,
- const GLfloat *param)
+static void mgaDDDepthFunc(GLcontext *ctx, GLenum func)
{
- if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) {
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE;
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ int zmode;
+
+ switch (func) {
+ case GL_NEVER:
+ /* can't do this in h/w, we'll use a s/w fallback */
+ FALLBACK (ctx, MGA_FALLBACK_DEPTH, ctx->Depth.Test);
+
+ /* FALLTHROUGH */
+ case GL_ALWAYS:
+ zmode = DC_zmode_nozcmp; break;
+ case GL_LESS:
+ zmode = DC_zmode_zlt; break;
+ case GL_LEQUAL:
+ zmode = DC_zmode_zlte; break;
+ case GL_EQUAL:
+ zmode = DC_zmode_ze; break;
+ case GL_GREATER:
+ zmode = DC_zmode_zgt; break;
+ case GL_GEQUAL:
+ zmode = DC_zmode_zgte; break;
+ case GL_NOTEQUAL:
+ zmode = DC_zmode_zne; break;
+ default:
+ zmode = 0; break;
}
-}
-
-static void mgaDDShadeModel(GLcontext *ctx, GLenum mode)
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE;
-}
-
-
-static void mgaDDDepthFunc(GLcontext *ctx, GLenum func)
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH;
+ FLUSH_BATCH( mmesa );
+ mmesa->hw.zmode &= DC_zmode_MASK;
+ mmesa->hw.zmode |= zmode;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
static void mgaDDDepthMask(GLcontext *ctx, GLboolean flag)
{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH;
-}
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
-#if defined(ACCEL_ROP)
-static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode )
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH;
-}
-#else
-static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode )
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- FALLBACK( ctx, MGA_FALLBACK_LOGICOP,
- (ctx->Color.ColorLogicOpEnabled && opcode != GL_COPY) );
-}
-#endif
+ FLUSH_BATCH( mmesa );
+ mmesa->hw.zmode &= DC_atype_MASK;
+ mmesa->hw.zmode |= (flag) ? DC_atype_zi : DC_atype_i;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+}
-static void mgaDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param)
+static void mgaDDClearDepth(GLcontext *ctx, GLclampd d)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
- if (pname == GL_FOG_COLOR) {
- GLuint color = MGAPACKCOLOR888((GLubyte)(ctx->Fog.Color[0]*255.0F),
- (GLubyte)(ctx->Fog.Color[1]*255.0F),
- (GLubyte)(ctx->Fog.Color[2]*255.0F));
-
- MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT);
- mmesa->setup.fogcolor = color;
+ /* Select the Z depth. The ~ is used because the _MASK values in the
+ * MGA driver are used to mask OFF the selected bits. In this case,
+ * we want to mask off everything except the MA_zwidth bits.
+ */
+ switch (mmesa->setup.maccess & ~MA_zwidth_MASK) {
+ case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break;
+ case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break;
+ case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break;
+ default: return;
}
}
-
-
/* =============================================================
- * Alpha blending
+ * Fog
*/
-static void mgaUpdateAlphaMode(GLcontext *ctx)
+static void mgaDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param)
{
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- mgaScreenPrivate *mgaScreen = mmesa->mgaScreen;
- int a = 0;
-
- /* determine source of alpha for blending and testing */
- if ( !ctx->Texture.Unit[0]._ReallyEnabled ) {
- a |= AC_alphasel_diffused;
- }
- else {
- /* G400: Regardless of texture env mode, we use the alpha from the
- * texture unit (AC_alphasel_fromtex) since it will have already
- * been modulated by the incoming fragment color, if needed.
- * We don't want (AC_alphasel_modulate) since that'll effectively
- * do the modulation twice.
- */
- if (MGA_IS_G400(mmesa)) {
- a |= AC_alphasel_fromtex;
- }
- else {
- /* G200 */
- switch (ctx->Texture.Unit[0].EnvMode) {
- case GL_DECAL:
- a |= AC_alphasel_diffused;
- case GL_REPLACE:
- a |= AC_alphasel_fromtex;
- break;
- case GL_BLEND:
- case GL_MODULATE:
- a |= AC_alphasel_modulated;
- break;
- default:
- break;
- }
- }
- }
-
-
- /* alpha test control.
- */
- if (ctx->Color.AlphaEnabled) {
- GLubyte ref = ctx->Color.AlphaRef;
- switch (ctx->Color.AlphaFunc) {
- case GL_NEVER:
- a |= AC_atmode_alt;
- ref = 0;
- break;
- case GL_LESS:
- a |= AC_atmode_alt;
- break;
- case GL_GEQUAL:
- a |= AC_atmode_agte;
- break;
- case GL_LEQUAL:
- a |= AC_atmode_alte;
- break;
- case GL_GREATER:
- a |= AC_atmode_agt;
- break;
- case GL_NOTEQUAL:
- a |= AC_atmode_ane;
- break;
- case GL_EQUAL:
- a |= AC_atmode_ae;
- break;
- case GL_ALWAYS:
- a |= AC_atmode_noacmp;
- break;
- default:
- break;
- }
- a |= MGA_FIELD(AC_atref,ref);
- }
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
- /* blending control */
- if (ctx->Color.BlendEnabled) {
- switch (ctx->Color.BlendSrcRGB) {
- case GL_ZERO:
- a |= AC_src_zero; break;
- case GL_SRC_ALPHA:
- a |= AC_src_src_alpha; break;
- case GL_ONE:
- a |= AC_src_one; break;
- case GL_DST_COLOR:
- a |= AC_src_dst_color; break;
- case GL_ONE_MINUS_DST_COLOR:
- a |= AC_src_om_dst_color; break;
- case GL_ONE_MINUS_SRC_ALPHA:
- a |= AC_src_om_src_alpha; break;
- case GL_DST_ALPHA:
- if (mgaScreen->cpp == 4)
- a |= AC_src_dst_alpha;
- else
- a |= AC_src_one;
- break;
- case GL_ONE_MINUS_DST_ALPHA:
- if (mgaScreen->cpp == 4)
- a |= AC_src_om_dst_alpha;
- else
- a |= AC_src_zero;
- break;
- case GL_SRC_ALPHA_SATURATE:
- if (ctx->Visual.alphaBits > 0)
- a |= AC_src_src_alpha_sat;
- else
- a |= AC_src_zero;
- break;
- default: /* never happens */
- break;
- }
+ if (pname == GL_FOG_COLOR) {
+ GLuint color = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F),
+ (GLubyte)(ctx->Fog.Color[1]*255.0F),
+ (GLubyte)(ctx->Fog.Color[2]*255.0F));
- switch (ctx->Color.BlendDstRGB) {
- case GL_SRC_ALPHA:
- a |= AC_dst_src_alpha; break;
- case GL_ONE_MINUS_SRC_ALPHA:
- a |= AC_dst_om_src_alpha; break;
- case GL_ZERO:
- a |= AC_dst_zero; break;
- case GL_ONE:
- a |= AC_dst_one; break;
- case GL_SRC_COLOR:
- a |= AC_dst_src_color; break;
- case GL_ONE_MINUS_SRC_COLOR:
- a |= AC_dst_om_src_color; break;
- case GL_DST_ALPHA:
- if (mgaScreen->cpp == 4)
- a |= AC_dst_dst_alpha;
- else
- a |= AC_dst_one;
- break;
- case GL_ONE_MINUS_DST_ALPHA:
- if (mgaScreen->cpp == 4)
- a |= AC_dst_om_dst_alpha;
- else
- a |= AC_dst_zero;
- break;
- default: /* never happens */
- break;
- }
- } else {
- a |= AC_src_one|AC_dst_zero;
+ MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT);
+ mmesa->setup.fogcolor = color;
}
-
- mmesa->setup.alphactrl = (AC_amode_alpha_channel |
- AC_astipple_disable |
- AC_aten_disable |
- AC_atmode_noacmp |
- a);
-
- mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
-
/* =============================================================
- * Hardware clipping
+ * Scissoring
*/
+
void mgaUpdateClipping(const GLcontext *ctx)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
@@ -554,13 +315,6 @@ void mgaUpdateClipping(const GLcontext *ctx)
mmesa->scissor_rect.x2 = x2;
mmesa->scissor_rect.y2 = y2;
- if (MGA_DEBUG&DEBUG_VERBOSE_2D)
- fprintf(stderr, "SET SCISSOR %d,%d-%d,%d\n",
- mmesa->scissor_rect.x1,
- mmesa->scissor_rect.y1,
- mmesa->scissor_rect.x2,
- mmesa->scissor_rect.y2);
-
mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
}
}
@@ -569,19 +323,10 @@ void mgaUpdateClipping(const GLcontext *ctx)
static void mgaDDScissor( GLcontext *ctx, GLint x, GLint y,
GLsizei w, GLsizei h )
{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_CLIP;
-}
-
-
-static void mgaDDClearColor(GLcontext *ctx,
- const GLfloat color[4] )
-{
- mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-
- mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp,
- color[0], color[1],
- color[2], color[3]);
+ if ( ctx->Scissor.Enabled ) {
+ FLUSH_BATCH( MGA_CONTEXT(ctx) ); /* don't pipeline cliprect changes */
+ mgaUpdateClipping( ctx );
+ }
}
@@ -589,46 +334,42 @@ static void mgaDDClearColor(GLcontext *ctx,
* Culling
*/
+
#define _CULL_DISABLE 0
#define _CULL_NEGATIVE ((1<<11)|(1<<5)|(1<<16))
#define _CULL_POSITIVE (1<<11)
-
-void mgaUpdateCull( GLcontext *ctx )
+static void mgaDDCullFaceFrontFace(GLcontext *ctx, GLenum unused)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
- GLuint mode = _CULL_DISABLE;
+
+ FLUSH_BATCH( mmesa );
if (ctx->Polygon.CullFlag &&
- mmesa->raster_primitive == GL_TRIANGLES &&
ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK)
{
- mode = _CULL_NEGATIVE;
+ mmesa->hw.cull = _CULL_NEGATIVE;
+
if (ctx->Polygon.CullFaceMode == GL_FRONT)
- mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
+ mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
+
if (ctx->Polygon.FrontFace != GL_CCW)
- mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
- if ((ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) &&
- (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT))
- mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */
+ mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
+
+ mmesa->hw.cull_dualtex = mmesa->hw.cull ^
+ (_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */
+ }
+ else {
+ mmesa->hw.cull = _CULL_DISABLE;
+ mmesa->hw.cull_dualtex = _CULL_DISABLE;
}
- mmesa->setup.wflag = mode;
mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
-static void mgaDDCullFaceFrontFace(GLcontext *ctx, GLenum mode)
-{
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_CULL;
-}
-
-
-
-
/* =============================================================
- * Color masks
+ * Masks
*/
static void mgaDDColorMask(GLcontext *ctx,
@@ -654,15 +395,11 @@ static void mgaDDColorMask(GLcontext *ctx,
}
}
+
/* =============================================================
- * Polygon stipple
- *
- * The mga supports a subset of possible 4x4 stipples natively, GL
- * wants 32x32. Fortunately stipple is usually a repeating pattern.
- *
- * Note: the fully opaque pattern (0xffff) has been disabled in order
- * to work around a conformance issue.
+ * Polygon state
*/
+
static int mgaStipples[16] = {
0xffff1, /* See above note */
0xa5a5,
@@ -682,6 +419,17 @@ static int mgaStipples[16] = {
0x0000
};
+/**
+ * The MGA supports a subset of possible 4x4 stipples natively, GL
+ * wants 32x32. Fortunately stipple is usually a repeating pattern.
+ *
+ * \param ctx GL rendering context to be affected
+ * \param mask Pointer to the 32x32 stipple mask
+ *
+ * \note the fully opaque pattern (0xffff) has been disabled in order
+ * to work around a conformance issue.
+ */
+
static void mgaDDPolygonStipple( GLcontext *ctx, const GLubyte *mask )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
@@ -730,93 +478,216 @@ static void mgaDDPolygonStipple( GLcontext *ctx, const GLubyte *mask )
}
}
+
/* =============================================================
+ * Rendering attributes
+ *
+ * We really don't want to recalculate all this every time we bind a
+ * texture. These things shouldn't change all that often, so it makes
+ * sense to break them out of the core texture state update routines.
*/
-static void mgaDDPrintDirty( const char *msg, GLuint state )
+static void updateSpecularLighting( GLcontext *ctx )
{
- fprintf(stderr, "%s (0x%x): %s%s%s%s%s%s%s\n",
- msg,
- (unsigned int) state,
- (state & MGA_WAIT_AGE) ? "wait-age, " : "",
- (state & MGA_UPLOAD_TEX0IMAGE) ? "upload-tex0-img, " : "",
- (state & MGA_UPLOAD_TEX1IMAGE) ? "upload-tex1-img, " : "",
- (state & MGA_UPLOAD_CONTEXT) ? "upload-ctx, " : "",
- (state & MGA_UPLOAD_TEX0) ? "upload-tex0, " : "",
- (state & MGA_UPLOAD_TEX1) ? "upload-tex1, " : "",
- (state & MGA_UPLOAD_PIPE) ? "upload-pipe, " : ""
- );
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ unsigned int specen;
+
+ specen = (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR &&
+ ctx->Light.Enabled) ? TMC_specen_enable : 0;
+
+ if ( specen != mmesa->hw.specen ) {
+ mmesa->hw.specen = specen;
+ mmesa->dirty |= MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1;
+
+ mgaChooseVertexState( ctx );
+ }
}
-/* Push the state into the sarea and/or texture memory.
+
+/* =============================================================
+ * Materials
*/
-void mgaEmitHwStateLocked( mgaContextPtr mmesa )
-{
- MGASAREAPrivPtr sarea = mmesa->sarea;
- if (MGA_DEBUG & DEBUG_VERBOSE_MSG)
- mgaDDPrintDirty( "mgaEmitHwStateLocked", mmesa->dirty );
- if ((mmesa->dirty & MGA_UPLOAD_TEX0IMAGE) && mmesa->CurrentTexObj[0])
- mgaUploadTexImages(mmesa, mmesa->CurrentTexObj[0]);
+static void mgaDDLightModelfv(GLcontext *ctx, GLenum pname,
+ const GLfloat *param)
+{
+ if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) {
+ FLUSH_BATCH( MGA_CONTEXT(ctx) );
+ updateSpecularLighting( ctx );
+ }
+}
- if ((mmesa->dirty & MGA_UPLOAD_TEX1IMAGE) && mmesa->CurrentTexObj[1])
- mgaUploadTexImages(mmesa, mmesa->CurrentTexObj[1]);
- if (mmesa->dirty & MGA_UPLOAD_CONTEXT) {
- memcpy( &sarea->ContextState, &mmesa->setup, sizeof(mmesa->setup));
- }
+static void mgaDDShadeModel(GLcontext *ctx, GLenum mode)
+{
+ /* FIXME: This used to FLUSH_BATCH and set MGA_NEW_TEXTURE in new_state,
+ * FIXME: so I'm not sure what to do here now.
+ */
+}
- if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) {
- memcpy(&sarea->TexState[0],
- &mmesa->CurrentTexObj[0]->setup,
- sizeof(sarea->TexState[0]));
- }
- if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) {
- memcpy(&sarea->TexState[1],
- &mmesa->CurrentTexObj[1]->setup,
- sizeof(sarea->TexState[1]));
- }
+/* =============================================================
+ * Stencil
+ */
- if (sarea->TexState[0].texctl2 !=
- sarea->TexState[1].texctl2) {
- memcpy(&sarea->TexState[1],
- &sarea->TexState[0],
- sizeof(sarea->TexState[0]));
- mmesa->dirty |= MGA_UPLOAD_TEX1|MGA_UPLOAD_TEX0;
- }
- if (mmesa->dirty & MGA_UPLOAD_PIPE) {
-/* mmesa->sarea->wacceptseq = mmesa->hw_primitive; */
- mmesa->sarea->WarpPipe = mmesa->vertex_format;
- mmesa->sarea->vertsize = mmesa->vertex_size;
+static void mgaDDStencilFunc(GLcontext *ctx, GLenum func, GLint ref,
+ GLuint mask)
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ GLuint stencil;
+ GLuint stencilctl;
+
+ stencil = (ref << S_sref_SHIFT) | (mask << S_smsk_SHIFT);
+ switch (func)
+ {
+ case GL_NEVER:
+ stencilctl = SC_smode_snever;
+ break;
+ case GL_LESS:
+ stencilctl = SC_smode_slt;
+ break;
+ case GL_LEQUAL:
+ stencilctl = SC_smode_slte;
+ break;
+ case GL_GREATER:
+ stencilctl = SC_smode_sgt;
+ break;
+ case GL_GEQUAL:
+ stencilctl = SC_smode_sgte;
+ break;
+ case GL_NOTEQUAL:
+ stencilctl = SC_smode_sne;
+ break;
+ case GL_EQUAL:
+ stencilctl = SC_smode_se;
+ break;
+ case GL_ALWAYS:
+ default:
+ stencilctl = SC_smode_salways;
+ break;
}
- mmesa->sarea->dirty |= mmesa->dirty;
+ FLUSH_BATCH( mmesa );
+ mmesa->hw.stencil &= (S_sref_MASK & S_smsk_MASK);
+ mmesa->hw.stencil |= stencil;
+ mmesa->hw.stencilctl &= SC_smode_MASK;
+ mmesa->hw.stencilctl |= stencilctl;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+}
- mmesa->dirty &= (MGA_UPLOAD_CLIPRECTS|MGA_WAIT_AGE);
+static void mgaDDStencilMask(GLcontext *ctx, GLuint mask)
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
- /* This is a bit of a hack but seems to be the best place to ensure
- * that separate specular is disabled when not needed.
- */
- if (mmesa->glCtx->Texture.Unit[0]._ReallyEnabled == 0 ||
- !mmesa->glCtx->Light.Enabled ||
- mmesa->glCtx->Light.Model.ColorControl == GL_SINGLE_COLOR) {
- sarea->TexState[0].texctl2 &= ~TMC_specen_enable;
- sarea->TexState[1].texctl2 &= ~TMC_specen_enable;
- }
+ FLUSH_BATCH( mmesa );
+ mmesa->hw.stencil &= S_swtmsk_MASK;
+ mmesa->hw.stencil |= (mask << S_swtmsk_SHIFT);
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
-/* Fallback to swrast for select and feedback.
- */
-static void mgaRenderMode( GLcontext *ctx, GLenum mode )
+static void mgaDDStencilOp(GLcontext *ctx, GLenum fail, GLenum zfail,
+ GLenum zpass)
{
- FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) );
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ GLuint stencilctl;
+
+ stencilctl = 0;
+ switch (ctx->Stencil.FailFunc[0])
+ {
+ case GL_KEEP:
+ stencilctl |= SC_sfailop_keep;
+ break;
+ case GL_ZERO:
+ stencilctl |= SC_sfailop_zero;
+ break;
+ case GL_REPLACE:
+ stencilctl |= SC_sfailop_replace;
+ break;
+ case GL_INCR:
+ stencilctl |= SC_sfailop_incrsat;
+ break;
+ case GL_DECR:
+ stencilctl |= SC_sfailop_decrsat;
+ break;
+ case GL_INCR_WRAP:
+ stencilctl |= SC_sfailop_incr;
+ break;
+ case GL_DECR_WRAP:
+ stencilctl |= SC_sfailop_decr;
+ break;
+ case GL_INVERT:
+ stencilctl |= SC_sfailop_invert;
+ break;
+ default:
+ break;
+ }
+
+ switch (ctx->Stencil.ZFailFunc[0])
+ {
+ case GL_KEEP:
+ stencilctl |= SC_szfailop_keep;
+ break;
+ case GL_ZERO:
+ stencilctl |= SC_szfailop_zero;
+ break;
+ case GL_REPLACE:
+ stencilctl |= SC_szfailop_replace;
+ break;
+ case GL_INCR:
+ stencilctl |= SC_szfailop_incrsat;
+ break;
+ case GL_DECR:
+ stencilctl |= SC_szfailop_decrsat;
+ break;
+ case GL_INCR_WRAP:
+ stencilctl |= SC_szfailop_incr;
+ break;
+ case GL_DECR_WRAP:
+ stencilctl |= SC_szfailop_decr;
+ break;
+ case GL_INVERT:
+ stencilctl |= SC_szfailop_invert;
+ break;
+ default:
+ break;
+ }
+
+ switch (ctx->Stencil.ZPassFunc[0])
+ {
+ case GL_KEEP:
+ stencilctl |= SC_szpassop_keep;
+ break;
+ case GL_ZERO:
+ stencilctl |= SC_szpassop_zero;
+ break;
+ case GL_REPLACE:
+ stencilctl |= SC_szpassop_replace;
+ break;
+ case GL_INCR:
+ stencilctl |= SC_szpassop_incrsat;
+ break;
+ case GL_DECR:
+ stencilctl |= SC_szpassop_decrsat;
+ break;
+ case GL_INVERT:
+ stencilctl |= SC_szpassop_invert;
+ break;
+ default:
+ break;
+ }
+
+ FLUSH_BATCH( mmesa );
+ mmesa->hw.stencilctl &= (SC_sfailop_MASK & SC_szfailop_MASK
+ & SC_szpassop_MASK);
+ mmesa->hw.stencilctl |= stencilctl;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
/* =============================================================
+ * Window position and viewport transformation
*/
void mgaCalcViewport( GLcontext *ctx )
@@ -850,8 +721,167 @@ static void mgaDepthRange( GLcontext *ctx,
mgaCalcViewport( ctx );
}
+
/* =============================================================
+ * Miscellaneous
+ */
+
+static void mgaDDClearColor(GLcontext *ctx,
+ const GLfloat color[4] )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ GLubyte c[4];
+ 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]);
+
+ mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp,
+ c[0], c[1], c[2], c[3]);
+}
+
+
+/* Fallback to swrast for select and feedback.
*/
+static void mgaRenderMode( GLcontext *ctx, GLenum mode )
+{
+ FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) );
+}
+
+
+static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+
+ FLUSH_BATCH( mmesa );
+#if defined(ACCEL_ROP)
+ mmesa->hw.rop = mgarop_NoBLK[ opcode & 0x0f ];
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+#else
+ FALLBACK( ctx, MGA_FALLBACK_LOGICOP,
+ (ctx->Color.ColorLogicOpEnabled && opcode != GL_COPY) );
+#endif
+}
+
+
+static void mgaXMesaSetFrontClipRects( mgaContextPtr mmesa )
+{
+ __DRIdrawablePrivate *driDrawable = mmesa->driDrawable;
+
+ if (driDrawable->numClipRects == 0) {
+ static XF86DRIClipRectRec zeroareacliprect = {0,0,0,0};
+ mmesa->numClipRects = 1;
+ mmesa->pClipRects = &zeroareacliprect;
+ } else {
+ mmesa->numClipRects = driDrawable->numClipRects;
+ mmesa->pClipRects = driDrawable->pClipRects;
+ }
+ mmesa->drawX = driDrawable->x;
+ mmesa->drawY = driDrawable->y;
+
+ mmesa->setup.dstorg = mmesa->drawOffset;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS;
+}
+
+
+static void mgaXMesaSetBackClipRects( mgaContextPtr mmesa )
+{
+ __DRIdrawablePrivate *driDrawable = mmesa->driDrawable;
+
+ if (driDrawable->numBackClipRects == 0)
+ {
+ if (driDrawable->numClipRects == 0) {
+ static XF86DRIClipRectRec zeroareacliprect = {0,0,0,0};
+ mmesa->numClipRects = 1;
+ mmesa->pClipRects = &zeroareacliprect;
+ } else {
+ mmesa->numClipRects = driDrawable->numClipRects;
+ mmesa->pClipRects = driDrawable->pClipRects;
+ }
+ mmesa->drawX = driDrawable->x;
+ mmesa->drawY = driDrawable->y;
+ } else {
+ mmesa->numClipRects = driDrawable->numBackClipRects;
+ mmesa->pClipRects = driDrawable->pBackClipRects;
+ mmesa->drawX = driDrawable->backX;
+ mmesa->drawY = driDrawable->backY;
+ }
+
+ mmesa->setup.dstorg = mmesa->drawOffset;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS;
+}
+
+
+void mgaUpdateRects( mgaContextPtr mmesa, GLuint buffers )
+{
+ __DRIdrawablePrivate *driDrawable = mmesa->driDrawable;
+ MGASAREAPrivPtr sarea = mmesa->sarea;
+
+
+ DRI_VALIDATE_DRAWABLE_INFO(mmesa->driScreen, driDrawable);
+ mmesa->dirty_cliprects = 0;
+
+ if (mmesa->draw_buffer == MGA_FRONT)
+ mgaXMesaSetFrontClipRects( mmesa );
+ else
+ mgaXMesaSetBackClipRects( mmesa );
+
+ sarea->req_draw_buffer = mmesa->draw_buffer;
+
+ mgaUpdateClipping( mmesa->glCtx );
+ mgaCalcViewport( mmesa->glCtx );
+
+ mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
+}
+
+
+static void mgaDDDrawBuffer(GLcontext *ctx, GLenum mode )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+
+ FLUSH_BATCH( mmesa );
+
+ /*
+ * _DrawDestMask is easier to cope with than <mode>.
+ */
+ switch ( ctx->Color._DrawDestMask ) {
+ case FRONT_LEFT_BIT:
+ mmesa->setup.dstorg = mmesa->mgaScreen->frontOffset;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+ mmesa->draw_buffer = MGA_FRONT;
+ mgaXMesaSetFrontClipRects( mmesa );
+ FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE );
+ break;
+ case BACK_LEFT_BIT:
+ mmesa->setup.dstorg = mmesa->mgaScreen->backOffset;
+ mmesa->draw_buffer = MGA_BACK;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+ mgaXMesaSetBackClipRects( mmesa );
+ FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE );
+ break;
+ default:
+ /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */
+ FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_TRUE );
+ return;
+ }
+
+ /* We want to update the s/w rast state too so that r200SetBuffer()
+ * gets called.
+ */
+ _swrast_DrawBuffer(ctx, mode);
+}
+
+
+static void mgaDDReadBuffer(GLcontext *ctx, GLenum mode )
+{
+ /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
+}
+
+
+/* =============================================================
+ * State enable/disable
+ */
+
static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
{
@@ -860,11 +890,11 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
switch(cap) {
case GL_ALPHA_TEST:
FLUSH_BATCH( mmesa );
- mmesa->new_state |= MGA_NEW_ALPHA;
+ mmesa->hw.alpha_func_enable = (state) ? ~0 : 0;
break;
case GL_BLEND:
FLUSH_BATCH( mmesa );
- mmesa->new_state |= MGA_NEW_ALPHA;
+ mmesa->hw.blend_func_enable = (state) ? ~0 : 0;
/* For some reason enable(GL_BLEND) affects ColorLogicOpEnabled.
*/
@@ -874,31 +904,31 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
break;
case GL_DEPTH_TEST:
FLUSH_BATCH( mmesa );
- mmesa->new_state |= MGA_NEW_DEPTH;
FALLBACK (ctx, MGA_FALLBACK_DEPTH,
ctx->Depth.Func == GL_NEVER && ctx->Depth.Test);
break;
+
case GL_SCISSOR_TEST:
FLUSH_BATCH( mmesa );
mmesa->scissor = state;
- mmesa->new_state |= MGA_NEW_CLIP;
+ mgaUpdateClipping( ctx );
break;
+
case GL_FOG:
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
if (ctx->Fog.Enabled)
mmesa->setup.maccess |= MA_fogen_enable;
else
mmesa->setup.maccess &= ~MA_fogen_enable;
+
+ mgaChooseVertexState( ctx );
break;
case GL_CULL_FACE:
- FLUSH_BATCH( mmesa );
- mmesa->new_state |= MGA_NEW_CULL;
+ mgaDDCullFaceFrontFace( ctx, 0 );
break;
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
case GL_TEXTURE_3D:
- FLUSH_BATCH( mmesa );
- mmesa->new_state |= (MGA_NEW_TEXTURE|MGA_NEW_ALPHA);
break;
case GL_POLYGON_STIPPLE:
if (mmesa->haveHwStipple && mmesa->raster_primitive == GL_TRIANGLES) {
@@ -914,16 +944,16 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
#if !defined(ACCEL_ROP)
FALLBACK( ctx, MGA_FALLBACK_LOGICOP,
(state && ctx->Color.LogicOp != GL_COPY));
-#else
- mmesa->new_state |= MGA_NEW_DEPTH;
#endif
break;
case GL_STENCIL_TEST:
FLUSH_BATCH( mmesa );
- if (mmesa->hw_stencil)
- mmesa->new_state |= MGA_NEW_STENCIL;
- else
+ if (mmesa->hw_stencil) {
+ mmesa->hw.stencil_enable = ( state ) ? ~0 : 0;
+ }
+ else {
FALLBACK( ctx, MGA_FALLBACK_STENCIL, state );
+ }
default:
break;
}
@@ -933,56 +963,150 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
/* =============================================================
*/
-
-
-/* =============================================================
- */
-
-static void mgaDDPrintState( const char *msg, GLuint state )
+static void mgaDDPrintDirty( const char *msg, GLuint state )
{
- fprintf(stderr, "%s (0x%x): %s%s%s%s%s%s\n",
+ fprintf(stderr, "%s (0x%03x): %s%s%s%s%s%s%s\n",
msg,
- state,
- (state & MGA_NEW_DEPTH) ? "depth, " : "",
- (state & MGA_NEW_ALPHA) ? "alpha, " : "",
- (state & MGA_NEW_CLIP) ? "clip, " : "",
- (state & MGA_NEW_CULL) ? "cull, " : "",
- (state & MGA_NEW_TEXTURE) ? "texture, " : "",
- (state & MGA_NEW_CONTEXT) ? "context, " : "");
+ (unsigned int) state,
+ (state & MGA_WAIT_AGE) ? "wait-age " : "",
+ (state & MGA_UPLOAD_TEX0IMAGE) ? "upload-tex0-img " : "",
+ (state & MGA_UPLOAD_TEX1IMAGE) ? "upload-tex1-img " : "",
+ (state & MGA_UPLOAD_CONTEXT) ? "upload-ctx " : "",
+ (state & MGA_UPLOAD_TEX0) ? "upload-tex0 " : "",
+ (state & MGA_UPLOAD_TEX1) ? "upload-tex1 " : "",
+ (state & MGA_UPLOAD_PIPE) ? "upload-pipe " : ""
+ );
}
-void mgaDDUpdateHwState( GLcontext *ctx )
+/* Push the state into the sarea and/or texture memory.
+ */
+void mgaEmitHwStateLocked( mgaContextPtr mmesa )
{
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- int new_state = mmesa->new_state;
+ MGASAREAPrivPtr sarea = mmesa->sarea;
+ GLcontext * ctx = mmesa->glCtx;
- if (new_state)
- {
- FLUSH_BATCH( mmesa );
+ if (MGA_DEBUG & DEBUG_VERBOSE_MSG)
+ mgaDDPrintDirty( __FUNCTION__, mmesa->dirty );
- mmesa->new_state = 0;
+ if (mmesa->dirty & MGA_UPLOAD_CONTEXT) {
+ mmesa->setup.wflag = _CULL_DISABLE;
+ if (mmesa->raster_primitive == GL_TRIANGLES) {
+ if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+ ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) {
+ mmesa->setup.wflag = mmesa->hw.cull_dualtex;
+ }
+ else {
+ mmesa->setup.wflag = mmesa->hw.cull;
+ }
+ }
- if (MESA_VERBOSE&VERBOSE_DRIVER)
- mgaDDPrintState("UpdateHwState", new_state);
+ mmesa->setup.stencil = mmesa->hw.stencil
+ & mmesa->hw.stencil_enable;
+ mmesa->setup.stencilctl = mmesa->hw.stencilctl
+ & mmesa->hw.stencil_enable;
- if (new_state & MGA_NEW_DEPTH)
- mgaUpdateZMode(ctx);
+ /* If depth testing is not enabled, then use the no Z-compare / no
+ * Z-write mode. Otherwise, use whatever is set in hw.zmode.
+ */
+ mmesa->setup.dwgctl &= (DC_zmode_MASK & DC_atype_MASK);
+ mmesa->setup.dwgctl |= (ctx->Depth.Test)
+ ? mmesa->hw.zmode : (DC_zmode_nozcmp | DC_atype_i);
- if (new_state & MGA_NEW_ALPHA)
- mgaUpdateAlphaMode(ctx);
+#if defined(ACCEL_ROP)
+ mmesa->setup.dwgctl &= DC_bop_MASK;
+ mmesa->setup.dwgctl |= (ctx->Color.ColorLogicOpEnabled)
+ ? mmesa->hw.rop : mgarop_NoBLK[ GL_COPY & 0x0f ];
+#endif
- if (new_state & MGA_NEW_CLIP)
- mgaUpdateClipping(ctx);
+ mmesa->setup.alphactrl &= AC_src_MASK & AC_dst_MASK & AC_atmode_MASK
+ & AC_atref_MASK & AC_alphasel_MASK;
+ mmesa->setup.alphactrl |=
+ ((mmesa->hw.alpha_func & mmesa->hw.alpha_func_enable)
+ | ((mmesa->hw.blend_func & mmesa->hw.blend_func_enable)
+ | ((AC_src_one | AC_dst_zero) & ~mmesa->hw.blend_func_enable))
+ | mmesa->hw.alpha_sel
+ | (AC_amode_alpha_channel
+ | AC_astipple_disable
+ | AC_aten_disable
+ | AC_atmode_noacmp));
- if (new_state & MGA_NEW_STENCIL)
- mgaUpdateStencil(ctx);
+ memcpy( &sarea->ContextState, &mmesa->setup, sizeof(mmesa->setup));
+ }
- if (new_state & (MGA_NEW_WARP|MGA_NEW_CULL))
- mgaUpdateCull(ctx);
+ if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) {
+ mmesa->CurrentTexObj[0]->setup.texctl2 &= ~TMC_specen_enable;
+ mmesa->CurrentTexObj[0]->setup.texctl2 |= mmesa->hw.specen;
- if (new_state & (MGA_NEW_WARP|MGA_NEW_TEXTURE))
- mgaUpdateTextureState(ctx);
+ memcpy(&sarea->TexState[0],
+ &mmesa->CurrentTexObj[0]->setup,
+ sizeof(sarea->TexState[0]));
}
+
+ if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) {
+ mmesa->CurrentTexObj[1]->setup.texctl2 &= ~TMC_specen_enable;
+ mmesa->CurrentTexObj[1]->setup.texctl2 |= mmesa->hw.specen;
+
+ memcpy(&sarea->TexState[1],
+ &mmesa->CurrentTexObj[1]->setup,
+ sizeof(sarea->TexState[1]));
+ }
+
+ if ( (sarea->TexState[0].texctl2 & TMC_borderen_MASK) !=
+ (sarea->TexState[1].texctl2 & TMC_borderen_MASK) ) {
+ const int borderen = sarea->TexState[1].texctl2 & ~TMC_borderen_MASK;
+
+ memcpy( &sarea->TexState[1], &sarea->TexState[0],
+ sizeof(sarea->TexState[0]) );
+ sarea->TexState[1].texctl2 |= borderen;
+ mmesa->dirty |= MGA_UPLOAD_TEX1|MGA_UPLOAD_TEX0;
+ }
+
+ if (mmesa->dirty & MGA_UPLOAD_PIPE) {
+/* mmesa->sarea->wacceptseq = mmesa->hw_primitive; */
+ mmesa->sarea->WarpPipe = mmesa->vertex_format;
+ mmesa->sarea->vertsize = mmesa->vertex_size;
+ }
+
+ mmesa->sarea->dirty |= mmesa->dirty;
+ mmesa->dirty &= MGA_UPLOAD_CLIPRECTS;
+
+ /* This is a bit of a hack but seems to be the best place to ensure
+ * that separate specular is disabled when not needed.
+ */
+ if (ctx->Texture._EnabledUnits == 0 ||
+ !ctx->Light.Enabled ||
+ ctx->Light.Model.ColorControl == GL_SINGLE_COLOR) {
+ sarea->TexState[0].texctl2 &= ~TMC_specen_enable;
+ sarea->TexState[1].texctl2 &= ~TMC_specen_enable;
+ }
+}
+
+
+/* =============================================================
+ */
+
+
+static void mgaDDValidateState( GLcontext *ctx )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ int new_state = mmesa->NewGLState;
+
+
+ FLUSH_BATCH( mmesa );
+
+ if (mmesa->NewGLState & _MGA_NEW_RASTERSETUP) {
+ mgaChooseVertexState( ctx );
+ }
+
+ if (mmesa->NewGLState & _MGA_NEW_RENDERSTATE) {
+ mgaChooseRenderState( ctx );
+ }
+
+ if (new_state & _NEW_TEXTURE) {
+ mgaUpdateTextureState(ctx);
+ }
+
+ mmesa->NewGLState = 0;
}
@@ -992,25 +1116,40 @@ static void mgaDDInvalidateState( GLcontext *ctx, GLuint new_state )
_swsetup_InvalidateState( ctx, new_state );
_ac_InvalidateState( ctx, new_state );
_tnl_InvalidateState( ctx, new_state );
- MGA_CONTEXT(ctx)->new_gl_state |= new_state;
+ MGA_CONTEXT(ctx)->NewGLState |= new_state;
}
+static void mgaRunPipeline( GLcontext *ctx )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+
+ if (mmesa->NewGLState) {
+ mgaDDValidateState( ctx );
+ }
+
+ if (mmesa->dirty) {
+ mgaEmitHwStateLocked( mmesa );
+ }
+
+ _tnl_run_pipeline( ctx );
+}
+
void mgaInitState( mgaContextPtr mmesa )
{
mgaScreenPrivate *mgaScreen = mmesa->mgaScreen;
GLcontext *ctx = mmesa->glCtx;
- if (ctx->Color._DrawDestMask == BACK_LEFT_BIT) {
+ if (ctx->Visual.doubleBufferMode) {
+ /* use back buffer by default */
mmesa->draw_buffer = MGA_BACK;
- mmesa->read_buffer = MGA_BACK;
mmesa->drawOffset = mmesa->mgaScreen->backOffset;
mmesa->readOffset = mmesa->mgaScreen->backOffset;
mmesa->setup.dstorg = mgaScreen->backOffset;
} else {
+ /* use front buffer by default */
mmesa->draw_buffer = MGA_FRONT;
- mmesa->read_buffer = MGA_FRONT;
mmesa->drawOffset = mmesa->mgaScreen->frontOffset;
mmesa->readOffset = mmesa->mgaScreen->frontOffset;
mmesa->setup.dstorg = mgaScreen->frontOffset;
@@ -1043,14 +1182,21 @@ void mgaInitState( mgaContextPtr mmesa )
mmesa->setup.maccess |= MA_zwidth_24;
break;
case 32:
- mmesa->setup.maccess |= MA_pwidth_32;
+ mmesa->setup.maccess |= MA_zwidth_32;
break;
}
+ mmesa->hw.zmode = DC_zmode_zlt | DC_atype_zi;
+ mmesa->hw.stencil = (0x0ff << S_smsk_SHIFT) | (0x0ff << S_swtmsk_SHIFT);
+ mmesa->hw.stencilctl = SC_smode_salways | SC_sfailop_keep
+ | SC_szfailop_keep | SC_szpassop_keep;
+ mmesa->hw.stencil_enable = 0;
+ mmesa->hw.cull = _CULL_NEGATIVE;
+ mmesa->hw.cull_dualtex = _CULL_POSITIVE;
+ mmesa->hw.specen = 0;
+
mmesa->setup.dwgctl = (DC_opcod_trap |
- DC_atype_i |
DC_linear_xy |
- DC_zmode_nozcmp |
DC_solid_disable |
DC_arzero_disable |
DC_sgnzero_disable |
@@ -1072,16 +1218,15 @@ void mgaInitState( mgaContextPtr mmesa )
AC_atmode_noacmp |
AC_alphasel_fromtex );
- mmesa->setup.fogcolor =
- MGAPACKCOLOR888((GLubyte)(ctx->Fog.Color[0]*255.0F),
- (GLubyte)(ctx->Fog.Color[1]*255.0F),
- (GLubyte)(ctx->Fog.Color[2]*255.0F));
+ mmesa->setup.fogcolor = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F),
+ (GLubyte)(ctx->Fog.Color[1]*255.0F),
+ (GLubyte)(ctx->Fog.Color[2]*255.0F));
mmesa->setup.wflag = 0;
mmesa->setup.tdualstage0 = 0;
mmesa->setup.tdualstage1 = 0;
mmesa->setup.fcol = 0;
- mmesa->new_state = ~0;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
@@ -1103,8 +1248,8 @@ void mgaDDInitStateFuncs( GLcontext *ctx )
ctx->Driver.FrontFace = mgaDDCullFaceFrontFace;
ctx->Driver.ColorMask = mgaDDColorMask;
- ctx->Driver.DrawBuffer = mgaDDSetDrawBuffer;
- ctx->Driver.ReadBuffer = mgaDDSetReadBuffer;
+ ctx->Driver.DrawBuffer = mgaDDDrawBuffer;
+ ctx->Driver.ReadBuffer = mgaDDReadBuffer;
ctx->Driver.ClearColor = mgaDDClearColor;
ctx->Driver.ClearDepth = mgaDDClearDepth;
ctx->Driver.LogicOpcode = mgaDDLogicOp;
@@ -1128,4 +1273,6 @@ void mgaDDInitStateFuncs( GLcontext *ctx )
ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
+
+ TNL_CONTEXT(ctx)->Driver.RunPipeline = mgaRunPipeline;
}
diff --git a/src/mesa/drivers/dri/mga/mgastate.h b/src/mesa/drivers/dri/mga/mgastate.h
index a9f1039d76..afbe0aaf90 100644
--- a/src/mesa/drivers/dri/mga/mgastate.h
+++ b/src/mesa/drivers/dri/mga/mgastate.h
@@ -29,14 +29,11 @@
#ifndef _MGA_STATE_H
#define _MGA_STATE_H
-
extern void mgaInitState( mgaContextPtr mmesa );
extern void mgaDDInitStateFuncs(GLcontext *ctx);
-extern void mgaDDUpdateHwState( GLcontext *ctx );
extern void mgaUpdateClipping(const GLcontext *ctx);
extern void mgaUpdateCull( GLcontext *ctx );
extern void mgaCalcViewport( GLcontext *ctx );
-
-
+extern void mgaUpdateRects( mgaContextPtr mmesa, GLuint buffers );
#endif
diff --git a/src/mesa/drivers/dri/mga/mgatex.c b/src/mesa/drivers/dri/mga/mgatex.c
index b4ee787e0b..82eccc8149 100644
--- a/src/mesa/drivers/dri/mga/mgatex.c
+++ b/src/mesa/drivers/dri/mga/mgatex.c
@@ -26,10 +26,7 @@
*/
/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatex.c,v 1.14 2002/10/30 12:51:36 alanh Exp $ */
-#include <stdlib.h>
-#include <stdio.h>
-#include <GL/gl.h>
-
+#include "glheader.h"
#include "mm.h"
#include "mgacontext.h"
#include "mgatex.h"
@@ -37,9 +34,11 @@
#include "mgatris.h"
#include "mgaioctl.h"
+#include "colormac.h"
+#include "context.h"
#include "enums.h"
#include "simple_list.h"
-/*#include "mem.h"*/
+#include "imports.h"
#include "macros.h"
#include "texformat.h"
#include "texstore.h"
@@ -47,67 +46,72 @@
#include "swrast/swrast.h"
-#define TEX_0 1
-#define TEX_1 2
-
-/*
- * mgaDestroyTexObj
- * Free all memory associated with a texture and NULL any pointers
- * to it.
+/**
+ * Set the texture wrap modes.
+ * Currently \c GL_REPEAT, \c GL_CLAMP and \c GL_CLAMP_TO_EDGE are supported.
+ *
+ * \param t Texture object whose wrap modes are to be set
+ * \param swrap Wrap mode for the \a s texture coordinate
+ * \param twrap Wrap mode for the \a t texture coordinate
*/
-void
-mgaDestroyTexObj( mgaContextPtr mmesa, mgaTextureObjectPtr t )
+
+static void
+mgaSetTexWrapping( mgaTextureObjectPtr t, GLenum swrap, GLenum twrap )
{
- if ( !t ) return;
+ GLboolean is_clamp = GL_FALSE;
+ GLboolean is_clamp_to_edge = GL_FALSE;
- /* free the texture memory */
- if (t->MemBlock) {
- mmFreeMem( t->MemBlock );
- t->MemBlock = 0;
+ t->setup.texctl &= (TMC_clampu_MASK & TMC_clampv_MASK);
+ t->setup.texctl2 &= (TMC_borderen_MASK);
- if (mmesa && t->age > mmesa->dirtyAge)
- mmesa->dirtyAge = t->age;
+ switch( swrap ) {
+ case GL_REPEAT:
+ break;
+ case GL_CLAMP:
+ t->setup.texctl |= TMC_clampu_enable;
+ is_clamp = GL_TRUE;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->setup.texctl |= TMC_clampu_enable;
+ is_clamp_to_edge = GL_TRUE;
+ break;
+ default:
+ _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
}
- /* free mesa's link */
- if (t->tObj)
- t->tObj->DriverData = NULL;
-
- /* see if it was the driver's current object */
- if (mmesa) {
- if (t->bound & TEX_0) mmesa->CurrentTexObj[0] = 0;
- if (t->bound & TEX_1) mmesa->CurrentTexObj[1] = 0;
+ switch( twrap ) {
+ case GL_REPEAT:
+ break;
+ case GL_CLAMP:
+ t->setup.texctl |= TMC_clampv_enable;
+ is_clamp = GL_TRUE;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->setup.texctl |= TMC_clampv_enable;
+ is_clamp_to_edge = GL_TRUE;
+ break;
+ default:
+ _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
}
-
- remove_from_list(t);
- free( t );
-}
+ if ( is_clamp ) {
+ t->setup.texctl2 |= TMC_borderen_enable;
+ }
-/*
- * mgaSetTexWrappings
- */
-static void mgaSetTexWrapping( mgaTextureObjectPtr t,
- GLenum sWrap,
- GLenum tWrap )
-{
- GLuint val = 0;
-
- if (sWrap != GL_REPEAT)
- val |= TMC_clampu_enable;
-
- if (tWrap != GL_REPEAT)
- val |= TMC_clampv_enable;
-
- t->setup.texctl &= ~(TMC_clampu_enable|TMC_clampv_enable);
- t->setup.texctl |= val;
+ t->border_fallback = (is_clamp && is_clamp_to_edge);
}
-/*
- * mgaSetTexFilter
+/**
+ * Set the texture magnification and minification modes.
+ *
+ * \param t Texture whose filter modes are to be set
+ * \param minf Texture minification mode
+ * \param magf Texture magnification mode
*/
-static void mgaSetTexFilter(mgaTextureObjectPtr t, GLenum minf, GLenum magf)
+
+static void
+mgaSetTexFilter( mgaTextureObjectPtr t, GLenum minf, GLenum magf )
{
GLuint val = 0;
@@ -136,123 +140,79 @@ static void mgaSetTexFilter(mgaTextureObjectPtr t, GLenum minf, GLenum magf)
}
- t->setup.texfilter &= (TF_minfilter_MASK |
- TF_magfilter_MASK |
+ /* Mask off the bits for the fields we are setting. Remember, the MGA mask
+ * defines have 0s for the bits in the named fields. This is the opposite
+ * of most of the other drivers.
+ */
+
+ t->setup.texfilter &= (TF_minfilter_MASK &
+ TF_magfilter_MASK &
TF_fthres_MASK);
t->setup.texfilter |= val;
}
-/*
- * mgaSetTexBorderColor
- */
static void mgaSetTexBorderColor(mgaTextureObjectPtr t, GLubyte color[4])
{
- t->setup.texbordercol = MGAPACKCOLOR8888(color[0],color[1],
- color[2],color[3]);
+ t->setup.texbordercol = PACK_COLOR_8888(color[3], color[0],
+ color[1], color[2] );
}
-static GLint mgaChooseTexFormat( mgaContextPtr mmesa,
- struct gl_texture_image *texImage,
- GLenum format, GLenum type )
+static const struct gl_texture_format *
+mgaChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+ GLenum format, GLenum type )
{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
const GLboolean do32bpt = mmesa->default32BitTextures;
- const struct gl_texture_format *texFormat;
- GLint ret;
-
- if ( 0 )
- fprintf( stderr, "internal=%s format=%s type=%s\n",
- texImage->IntFormat == 3 ? "GL_RGB (3)" :
- texImage->IntFormat == 4 ? "GL_RGBA (4)" :
- _mesa_lookup_enum_by_nr( texImage->IntFormat ),
- _mesa_lookup_enum_by_nr( format ),
- _mesa_lookup_enum_by_nr( type ) );
-
-#define SET_FORMAT( r, gl ) \
- do { \
- ret = (r); \
- texFormat = &(gl); \
- } while (0)
-
-#define SET_FORMAT_32BPT( r32, gl32, r16, gl16 ) \
- do { \
- if ( do32bpt ) { \
- ret = (r32); \
- texFormat = &(gl32); \
- } else { \
- ret = (r16); \
- texFormat = &(gl16); \
- } \
- } while (0)
-
- switch ( texImage->IntFormat ) {
- /* GH: Bias towards GL_RGB, GL_RGBA texture formats. This has
- * got to be better than sticking them way down the end of this
- * huge list.
- */
+
+ switch ( internalFormat ) {
case 4:
case GL_RGBA:
case GL_COMPRESSED_RGBA:
if ( format == GL_BGRA ) {
if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
- SET_FORMAT( TMC_tformat_tw32, _mesa_texformat_argb8888 );
- break;
- } else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
- SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 );
- break;
- } else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
- SET_FORMAT( TMC_tformat_tw15, _mesa_texformat_argb1555 );
- break;
+ return &_mesa_texformat_argb8888;
+ }
+ else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
+ return &_mesa_texformat_argb4444;
+ }
+ else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
+ return &_mesa_texformat_argb1555;
}
}
- SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888,
- TMC_tformat_tw12, _mesa_texformat_argb4444 );
- break;
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
case 3:
case GL_RGB:
case GL_COMPRESSED_RGB:
if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
- SET_FORMAT( TMC_tformat_tw16, _mesa_texformat_rgb565 );
- break;
+ return &_mesa_texformat_rgb565;
}
- SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888,
- TMC_tformat_tw16, _mesa_texformat_rgb565 );
- break;
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
- /* GH: Okay, keep checking as normal. Still test for GL_RGB,
- * GL_RGBA formats first.
- */
case GL_RGBA8:
case GL_RGB10_A2:
case GL_RGBA12:
case GL_RGBA16:
- SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888,
- TMC_tformat_tw12, _mesa_texformat_argb4444 );
- break;
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
case GL_RGBA4:
case GL_RGBA2:
- SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 );
- break;
+ return &_mesa_texformat_argb4444;
case GL_RGB5_A1:
- SET_FORMAT( TMC_tformat_tw15, _mesa_texformat_argb1555 );
- break;
+ return &_mesa_texformat_argb1555;
case GL_RGB8:
case GL_RGB10:
case GL_RGB12:
case GL_RGB16:
- SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888,
- TMC_tformat_tw16, _mesa_texformat_rgb565 );
- break;
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
case GL_RGB5:
case GL_RGB4:
case GL_R3_G3_B2:
- SET_FORMAT( TMC_tformat_tw16, _mesa_texformat_rgb565 );
- break;
+ return &_mesa_texformat_rgb565;
case GL_ALPHA:
case GL_ALPHA4:
@@ -261,8 +221,7 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa,
case GL_ALPHA16:
case GL_COMPRESSED_ALPHA:
/* FIXME: This will report incorrect component sizes... */
- SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 );
- break;
+ return &_mesa_texformat_argb4444;
case 1:
case GL_LUMINANCE:
@@ -272,8 +231,7 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa,
case GL_LUMINANCE16:
case GL_COMPRESSED_LUMINANCE:
/* FIXME: This will report incorrect component sizes... */
- SET_FORMAT( TMC_tformat_tw16, _mesa_texformat_rgb565 );
- break;
+ return &_mesa_texformat_rgb565;
case 2:
case GL_LUMINANCE_ALPHA:
@@ -285,8 +243,7 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa,
case GL_LUMINANCE16_ALPHA16:
case GL_COMPRESSED_LUMINANCE_ALPHA:
/* FIXME: This will report incorrect component sizes... */
- SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 );
- break;
+ return &_mesa_texformat_argb4444;
case GL_INTENSITY:
case GL_INTENSITY4:
@@ -295,8 +252,15 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa,
case GL_INTENSITY16:
case GL_COMPRESSED_INTENSITY:
/* FIXME: This will report incorrect component sizes... */
- SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 );
- break;
+ return &_mesa_texformat_argb4444;
+
+ case GL_YCBCR_MESA:
+ if (MGA_IS_G400(mmesa) &&
+ (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
+ type == GL_UNSIGNED_BYTE))
+ return &_mesa_texformat_ycbcr;
+ else
+ return &_mesa_texformat_ycbcr_rev;
case GL_COLOR_INDEX:
case GL_COLOR_INDEX1_EXT:
@@ -305,502 +269,78 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa,
case GL_COLOR_INDEX8_EXT:
case GL_COLOR_INDEX12_EXT:
case GL_COLOR_INDEX16_EXT:
- SET_FORMAT( TMC_tformat_tw8, _mesa_texformat_ci8 );
- break;
+ return &_mesa_texformat_ci8;
default:
- fprintf( stderr, "bad texture format in mgaChooseTexFormat() %d",
- texImage->IntFormat );
- return -1;
+ _mesa_problem( ctx, "unexpected texture format in %s", __FUNCTION__ );
+ return NULL;
}
- texImage->TexFormat = texFormat;
-
- return ret;
+ return NULL; /* never get here */
}
-/*
- * mgaCreateTexObj
+
+
+/**
* Allocate space for and load the mesa images into the texture memory block.
* This will happen before drawing with a new texture, or drawing with a
* texture after it was swapped out or teximaged again.
*/
-static void mgaCreateTexObj(mgaContextPtr mmesa,
- struct gl_texture_object *tObj)
-{
- const GLint baseLevel = tObj->BaseLevel;
- struct gl_texture_image *image = tObj->Image[baseLevel];
- mgaTextureObjectPtr t;
- int i, ofs;
- int LastLevel;
- int s, s2;
- int tformat;
-
- if (!image) return;
-
- tObj->DriverData = t = calloc( 1, sizeof( *t ) );
- if (!t) {
- fprintf(stderr, "mgaCreateTexObj: Failed to malloc mgaTextureObject\n" );
- return;
- }
-
- /* FIXME: Use the real DD interface...
- */
- tformat = mgaChooseTexFormat( mmesa, image, image->Format,
- GL_UNSIGNED_BYTE );
- t->texelBytes = image->TexFormat->TexelBytes;
-
- /* We are going to upload all levels that are present, even if
- * later levels wouldn't be used by the current filtering mode. This
- * allows the filtering mode to change without forcing another upload
- * of the images.
- */
- LastLevel = MGA_TEX_MAXLEVELS-1;
-
- ofs = 0;
- for ( i = 0 ; i <= LastLevel ; i++ ) {
- if ( !tObj->Image[i] ) {
- LastLevel = i - 1;
- break;
- }
-
- t->offsets[i] = ofs;
- t->dirty_images |= (1<<i);
-
- ofs += ((MAX2( tObj->Image[i]->Width, 8 ) *
- MAX2( tObj->Image[i]->Height, 8 ) *
- t->texelBytes) + 31) & ~31;
- }
- t->totalSize = ofs;
- t->lastLevel = LastLevel;
- t->tObj = tObj;
- t->ctx = mmesa;
- t->age = 0;
- t->bound = 0;
- t->MemBlock = 0;
-
- insert_at_tail(&(mmesa->SwappedOut), t);
-
-
- /* setup hardware register values */
- t->setup.texctl = TMC_takey_1 | TMC_tamask_0 | tformat;
-
- if (image->WidthLog2 >= 3)
- t->setup.texctl |= ((image->WidthLog2 - 3) << TMC_tpitch_SHIFT);
- else
- t->setup.texctl |= (TMC_tpitchlin_enable |
- (image->Width << TMC_tpitchext_SHIFT));
-
-
- t->setup.texctl2 = TMC_ckstransdis_enable;
-
- if ( mmesa->glCtx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR )
- t->setup.texctl2 |= TMC_specen_enable;
-
-
- t->setup.texfilter = (TF_minfilter_nrst |
- TF_magfilter_nrst |
- TF_filteralpha_enable |
- (0x10 << TF_fthres_SHIFT) |
- (LastLevel << TF_mapnb_SHIFT));
-
- /* warp texture registers */
- ofs = MGA_IS_G200(mmesa) ? 28 : 11;
- s = image->Width;
- s2 = image->WidthLog2;
- t->setup.texwidth = (MGA_FIELD(TW_twmask, s - 1) |
- MGA_FIELD(TW_rfw, (10 - s2 - 8) & 63 ) |
- MGA_FIELD(TW_tw, (s2 + ofs ) | 0x40 ));
-
- s = image->Height;
- s2 = image->HeightLog2;
- t->setup.texheight = (MGA_FIELD(TH_thmask, s - 1) |
- MGA_FIELD(TH_rfh, (10 - s2 - 8) & 63 ) |
- MGA_FIELD(TH_th, (s2 + ofs ) | 0x40 ));
-
-
- /* set all the register values for filtering, border, etc */
- mgaSetTexWrapping( t, tObj->WrapS, tObj->WrapT );
- mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
- mgaSetTexBorderColor( t, tObj->_BorderChan );
-}
-
-
-
-
-static void mgaUpdateTextureEnvG200( GLcontext *ctx )
+static mgaTextureObjectPtr
+mgaAllocTexObj( struct gl_texture_object *tObj )
{
- struct gl_texture_object *tObj = ctx->Texture.Unit[0]._Current;
mgaTextureObjectPtr t;
- if (!tObj || !tObj->DriverData)
- return;
-
- t = (mgaTextureObjectPtr)tObj->DriverData;
-
- t->setup.texctl2 &= ~TMC_decalblend_enable;
-
- switch (ctx->Texture.Unit[0].EnvMode) {
- case GL_REPLACE:
- t->setup.texctl &= ~TMC_tmodulate_enable;
- break;
- case GL_MODULATE:
- t->setup.texctl |= TMC_tmodulate_enable;
- break;
- case GL_DECAL:
- t->setup.texctl &= ~TMC_tmodulate_enable;
- t->setup.texctl2 |= TMC_decalblend_enable;
- break;
- case GL_BLEND:
- FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
- break;
- default:
- break;
- }
-}
-
-static void mgaUpdateTextureEnvG400( GLcontext *ctx, int unit )
-{
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- GLuint *reg = ((GLuint *)&mmesa->setup.tdualstage0 + unit);
- GLuint source = mmesa->tmu_source[unit];
- struct gl_texture_object *tObj = ctx->Texture.Unit[source]._Current;
- GLenum format;
-
- if ( tObj != ctx->Texture.Unit[source].Current2D || !tObj )
- return;
-
- format = tObj->Image[tObj->BaseLevel]->Format;
-
- switch (ctx->Texture.Unit[source].EnvMode) {
- case GL_REPLACE:
- if (format == GL_RGB || format == GL_LUMINANCE) {
- *reg = (TD0_color_sel_arg1 |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_arg2 );
- }
- else if (format == GL_ALPHA) {
- *reg = (TD0_color_sel_arg2 |
- TD0_color_arg2_diffuse |
- TD0_alpha_sel_arg1 );
- }
- else {
- *reg = (TD0_color_sel_arg1 |
- TD0_alpha_sel_arg1 );
- }
- break;
-
- case GL_MODULATE:
- if (unit == 0) {
- *reg = ( TD0_color_arg2_diffuse |
- TD0_color_sel_mul |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_mul);
- }
- else {
- *reg = ( TD0_color_arg2_prevstage |
- TD0_color_alpha_prevstage |
- TD0_color_sel_mul |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_sel_mul);
- }
- break;
- case GL_DECAL:
- if (format == GL_RGB) {
- if (unit == 0) {
- *reg = (TD0_color_sel_arg1 |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_arg2 );
- }
- else {
- *reg = (TD0_color_sel_arg1 |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_sel_arg2 );
- }
- }
- else if ( format == GL_RGBA ) {
-#if 0
- if (unit == 0) {
- /* this doesn't work */
- *reg = (TD0_color_arg2_diffuse |
- TD0_color_alpha_currtex |
- TD0_color_alpha2inv_enable |
- TD0_color_arg2mul_alpha2 |
- TD0_color_arg1mul_alpha1 |
- TD0_color_blend_enable |
- TD0_color_arg1add_mulout |
- TD0_color_arg2add_mulout |
- TD0_color_add_add |
- TD0_color_sel_mul |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_arg2 );
- }
- else {
- *reg = (TD0_color_arg2_prevstage |
- TD0_color_alpha_currtex |
- TD0_color_alpha2inv_enable |
- TD0_color_arg2mul_alpha2 |
- TD0_color_arg1mul_alpha1 |
- TD0_color_add_add |
- TD0_color_sel_add |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_sel_arg2 );
- }
-#else
- /* s/w fallback, pretty sure we can't do in h/w */
- FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
- if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
- fprintf( stderr, "FALLBACK: GL_DECAL RGBA texture, unit=%d\n",
- unit );
-#endif
- }
- else {
- if (unit == 0) {
- *reg = ( TD0_color_arg2_diffuse |
- TD0_color_sel_arg2 |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_arg2);
- }
- else {
- *reg = ( TD0_color_arg2_prevstage |
- TD0_color_sel_arg2 |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_sel_arg2);
- }
- }
- break;
-
- case GL_ADD:
- if (unit == 0) {
- if (format == GL_INTENSITY)
- *reg = ( TD0_color_arg2_diffuse |
- TD0_color_add_add |
- TD0_color_sel_add |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_add_enable |
- TD0_alpha_sel_add);
- else if (format == GL_ALPHA)
- *reg = ( TD0_color_arg2_diffuse |
- TD0_color_sel_mul |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_mul);
- else
- *reg = ( TD0_color_arg2_diffuse |
- TD0_color_add_add |
- TD0_color_sel_add |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_mul);
- }
- else {
- if (format == GL_INTENSITY) {
- *reg = ( TD0_color_arg2_prevstage |
- TD0_color_add_add |
- TD0_color_sel_add |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_add_enable |
- TD0_alpha_sel_add);
- }
- else if (format == GL_ALPHA) {
- *reg = ( TD0_color_arg2_prevstage |
- TD0_color_sel_mul |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_sel_mul);
- }
- else {
- *reg = ( TD0_color_arg2_prevstage |
- TD0_color_alpha_prevstage |
- TD0_color_add_add |
- TD0_color_sel_add |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_sel_mul);
- }
- }
- break;
-
- case GL_BLEND:
- if (format == GL_ALPHA) {
- *reg = ( TD0_color_arg2_diffuse |
- TD0_color_sel_mul |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_mul);
- }
- else {
- FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
- if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
- fprintf( stderr, "FALLBACK: GL_BLEND envcolor=0x%08x\n",
- mmesa->envcolor );
-
- /* Do singletexture GL_BLEND with 'all ones' env-color
- * by using both texture units. Multitexture gl_blend
- * is a fallback.
- */
- if (unit == 0) {
- /* Part 1: R1 = Rf ( 1 - Rt )
- * A1 = Af At
- */
- *reg = ( TD0_color_arg2_diffuse |
- TD0_color_arg1_inv_enable |
- TD0_color_sel_mul |
- TD0_alpha_arg2_diffuse |
- TD0_alpha_sel_arg1);
- } else {
- /* Part 2: R2 = R1 + Rt
- * A2 = A1
- */
- *reg = ( TD0_color_arg2_prevstage |
- TD0_color_add_add |
- TD0_color_sel_add |
- TD0_alpha_arg2_prevstage |
- TD0_alpha_sel_arg2);
- }
- }
- break;
- default:
- break;
- }
-}
-
-
-
-static void mgaUpdateTextureObject( GLcontext *ctx, int hw_unit )
-{
- mgaTextureObjectPtr t;
- struct gl_texture_object *tObj;
- GLuint enabled;
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- GLuint gl_unit = mmesa->tmu_source[hw_unit];
-
-
- enabled = ctx->Texture.Unit[gl_unit]._ReallyEnabled;
- tObj = ctx->Texture.Unit[gl_unit]._Current;
-
- if (enabled != TEXTURE_2D_BIT) {
- if (enabled)
- FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
- return;
- }
-
- if (tObj->Image[tObj->BaseLevel]->Border > 0) {
- FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
- if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
- fprintf( stderr, "FALLBACK: texture border\n" );
- return;
- }
-
- if ( !tObj->DriverData ) {
- mgaCreateTexObj( mmesa, tObj );
- if ( !tObj->DriverData ) {
- FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
- return;
- }
- }
-
- t = (mgaTextureObjectPtr)tObj->DriverData;
-
- if (t->dirty_images)
- mmesa->dirty |= (MGA_UPLOAD_TEX0IMAGE << hw_unit);
-
- mmesa->CurrentTexObj[hw_unit] = t;
- t->bound |= hw_unit+1;
-
-/* if (t->MemBlock) */
-/* mgaUpdateTexLRU( mmesa, t ); */
-
- t->setup.texctl2 &= ~TMC_dualtex_enable;
- if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) &&
- (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT))
- t->setup.texctl2 |= TMC_dualtex_enable;
-
- t->setup.texctl2 &= ~TMC_specen_enable;
- if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
- t->setup.texctl2 |= TMC_specen_enable;
-}
-
-
+ t = CALLOC( sizeof( *t ) );
+ tObj->DriverData = t;
+ if ( t != NULL ) {
+ /* Initialize non-image-dependent parts of the state:
+ */
+ t->base.tObj = tObj;
+ t->setup.texctl = TMC_takey_1 | TMC_tamask_0;
+ t->setup.texctl2 = TMC_ckstransdis_enable;
+ t->setup.texfilter = (TF_minfilter_nrst
+ | TF_magfilter_nrst
+ | TF_filteralpha_enable
+ | TF_uvoffset_OGL);
+ t->border_fallback = GL_FALSE;
-/* The G400 is now programmed quite differently wrt texture environment.
- */
-void mgaUpdateTextureState( GLcontext *ctx )
-{
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_FALSE );
+ make_empty_list( & t->base );
- if (mmesa->CurrentTexObj[0]) {
- mmesa->CurrentTexObj[0]->bound = 0;
- mmesa->CurrentTexObj[0] = 0;
- }
-
- if (mmesa->CurrentTexObj[1]) {
- mmesa->CurrentTexObj[1]->bound = 0;
- mmesa->CurrentTexObj[1] = 0;
- }
-
- if (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) {
- mmesa->tmu_source[0] = 1;
- } else {
- mmesa->tmu_source[0] = 0;
- }
-
- if (MGA_IS_G400(mmesa)) {
- mgaUpdateTextureObject( ctx, 0 );
- mgaUpdateTextureEnvG400( ctx, 0 );
-
- mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0;
-
- if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) &&
- (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) {
- mgaUpdateTextureObject( ctx, 1 );
- mgaUpdateTextureEnvG400( ctx, 1 );
- mmesa->dirty |= MGA_UPLOAD_TEX1;
- }
- } else {
- mgaUpdateTextureObject( ctx, 0 );
- mgaUpdateTextureEnvG200( ctx );
+ mgaSetTexWrapping( t, tObj->WrapS, tObj->WrapT );
+ mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
+ mgaSetTexBorderColor( t, tObj->_BorderChan );
}
- mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_TEX0;
-
- mmesa->setup.dwgctl &= DC_opcod_MASK;
- mmesa->setup.dwgctl |= (ctx->Texture.Unit[0]._ReallyEnabled
- ? DC_opcod_texture_trap
- : DC_opcod_trap);
+ return( t );
}
-
-
static void mgaDDTexEnv( GLcontext *ctx, GLenum target,
GLenum pname, const GLfloat *param )
{
+ GLuint unit = ctx->Texture.CurrentUnit;
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
- if (pname == GL_TEXTURE_ENV_MODE) {
- /* force the texture state to be updated */
- FLUSH_BATCH( MGA_CONTEXT(ctx) );
- MGA_CONTEXT(ctx)->new_state |= (MGA_NEW_TEXTURE |
- MGA_NEW_ALPHA);
- }
- else if (pname == GL_TEXTURE_ENV_COLOR)
- {
- struct gl_texture_unit *texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- GLfloat *fc = texUnit->EnvColor;
+ switch( pname ) {
+ case GL_TEXTURE_ENV_COLOR: {
GLubyte c[4];
- GLuint col;
+ GLuint envColor;
- COPY_4V(c, fc);
- col = mgaPackColor( mmesa->mgaScreen->cpp, c[0], c[1], c[2], c[3] );
- mmesa->envcolor = (c[3]<<24) | (c[0]<<16) | (c[1]<<8) | (c[2]);
+ UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
+ envColor = mgaPackColor( mmesa->mgaScreen->cpp, c[0], c[1], c[2], c[3] );
+ mmesa->envcolor = PACK_COLOR_8888( c[3], c[0], c[1], c[2] );
- if (mmesa->setup.fcol != col) {
+ if (mmesa->setup.fcol != envColor) {
FLUSH_BATCH(mmesa);
- mmesa->setup.fcol = col;
+ mmesa->setup.fcol = envColor;
mmesa->dirty |= MGA_UPLOAD_CONTEXT;
mmesa->blend_flags &= ~MGA_BLEND_ENV_COLOR;
@@ -814,6 +354,8 @@ static void mgaDDTexEnv( GLcontext *ctx, GLenum target,
if (mmesa->envcolor != 0x0 && mmesa->envcolor != 0xffffffff)
mmesa->blend_flags |= MGA_BLEND_ENV_COLOR;
}
+ break;
+ }
}
}
@@ -826,14 +368,26 @@ static void mgaTexImage2D( GLcontext *ctx, GLenum target, GLint level,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage )
{
- mgaTextureObjectPtr t = (mgaTextureObjectPtr) texObj->DriverData;
- if (t) {
- mgaDestroyTexObj( MGA_CONTEXT(ctx), t );
- texObj->DriverData = 0;
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+
+ if ( t != NULL ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) mgaAllocTexObj( texObj );
+ if ( t == NULL ) {
+ _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
+ return;
+ }
}
+
_mesa_store_teximage2d( ctx, target, level, internalFormat,
width, height, border, format, type,
pixels, packing, texObj, texImage );
+ level -= t->firstLevel;
+ if (level >= 0)
+ t->dirty_images[0] |= (1UL << level);
}
static void mgaTexSubImage2D( GLcontext *ctx,
@@ -847,44 +401,59 @@ static void mgaTexSubImage2D( GLcontext *ctx,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage )
{
- mgaTextureObjectPtr t = (mgaTextureObjectPtr) texObj->DriverData;
- if (t) {
- mgaDestroyTexObj( MGA_CONTEXT(ctx), t );
- texObj->DriverData = 0;
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+
+ assert( t != NULL ); /* this _should_ be true */
+ if ( t != NULL ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) mgaAllocTexObj( texObj );
+ if ( t == NULL ) {
+ _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
+ return;
+ }
}
+
_mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
height, format, type, pixels, packing, texObj,
texImage);
-
+ level -= t->firstLevel;
+ if (level >= 0)
+ t->dirty_images[0] |= (1UL << level);
}
-
-
-/*
- * mgaTexParameter
- * This just changes variables and flags for a state update, which
- * will happen at the next mgaUpdateTextureState
+/**
+ * Changes variables and flags for a state update, which will happen at the
+ * next UpdateTextureState
*/
+
static void
mgaDDTexParameter( GLcontext *ctx, GLenum target,
struct gl_texture_object *tObj,
GLenum pname, const GLfloat *params )
{
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
mgaTextureObjectPtr t;
t = (mgaTextureObjectPtr) tObj->DriverData;
- /* if we don't have a hardware texture, it will be automatically
- created with current state before it is used, so we don't have
- to do anything now */
- if ( !t || !t->bound || target != GL_TEXTURE_2D ) {
+ /* If we don't have a hardware texture, it will be automatically
+ * created with current state before it is used, so we don't have
+ * to do anything now
+ */
+
+ if ( (t == NULL)
+ || (target != GL_TEXTURE_2D) ) {
return;
}
switch (pname) {
case GL_TEXTURE_MIN_FILTER:
+ driSwapOutTextureObject( (driTextureObject *) t );
+ /* FALLTHROUGH */
case GL_TEXTURE_MAG_FILTER:
FLUSH_BATCH(mmesa);
mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
@@ -898,14 +467,24 @@ mgaDDTexParameter( GLcontext *ctx, GLenum target,
case GL_TEXTURE_BORDER_COLOR:
FLUSH_BATCH(mmesa);
- mgaSetTexBorderColor(t,tObj->_BorderChan);
+ mgaSetTexBorderColor(t, tObj->_BorderChan);
+ break;
+
+ case GL_TEXTURE_BASE_LEVEL:
+ case GL_TEXTURE_MAX_LEVEL:
+ case GL_TEXTURE_MIN_LOD:
+ case GL_TEXTURE_MAX_LOD:
+ /* This isn't the most efficient solution but there doesn't appear to
+ * be a nice alternative. Since there's no LOD clamping,
+ * we just have to rely on loading the right subset of mipmap levels
+ * to simulate a clamped LOD.
+ */
+ driSwapOutTextureObject( (driTextureObject *) t );
break;
default:
return;
}
-
- mmesa->new_state |= MGA_NEW_TEXTURE;
}
@@ -913,19 +492,11 @@ static void
mgaDDBindTexture( GLcontext *ctx, GLenum target,
struct gl_texture_object *tObj )
{
- mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- int unit = ctx->Texture.CurrentUnit;
-
- FLUSH_BATCH(mmesa);
-
- if (mmesa->CurrentTexObj[unit]) {
- mmesa->CurrentTexObj[unit]->bound &= ~(unit+1);
- mmesa->CurrentTexObj[unit] = 0;
+ if ( target == GL_TEXTURE_2D ) {
+ if ( tObj->DriverData == NULL ) {
+ mgaAllocTexObj( tObj );
+ }
}
-
- /* force the texture state to be updated
- */
- MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE;
}
@@ -933,53 +504,48 @@ static void
mgaDDDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
- mgaTextureObjectPtr t = (mgaTextureObjectPtr)tObj->DriverData;
+ driTextureObject * t = (driTextureObject *) tObj->DriverData;
if ( t ) {
- if (mmesa) {
- if (t->bound) {
- FLUSH_BATCH(mmesa);
- if (t->bound & TEX_0) mmesa->CurrentTexObj[0] = 0;
- if (t->bound & TEX_1) mmesa->CurrentTexObj[1] = 0;
- }
- mmesa->new_state |= MGA_NEW_TEXTURE;
+ if ( mmesa ) {
+ FLUSH_BATCH( mmesa );
}
- mgaDestroyTexObj( mmesa, t );
+ driDestroyTextureObject( t );
}
}
-static GLboolean
-mgaDDIsTextureResident( GLcontext *ctx, struct gl_texture_object *t )
-{
- mgaTextureObjectPtr mt = (mgaTextureObjectPtr)t->DriverData;
- return mt && mt->MemBlock;
-}
-
-
void
mgaDDInitTextureFuncs( GLcontext *ctx )
{
- ctx->Driver.TexEnv = mgaDDTexEnv;
-
- ctx->Driver.ChooseTextureFormat = _mesa_choose_tex_format;
- ctx->Driver.TexImage1D = _mesa_store_teximage1d;
- ctx->Driver.TexImage2D = mgaTexImage2D;
- ctx->Driver.TexImage3D = _mesa_store_teximage3d;
- ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
- ctx->Driver.TexSubImage2D = mgaTexSubImage2D;
- 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.BindTexture = mgaDDBindTexture;
- ctx->Driver.DeleteTexture = mgaDDDeleteTexture;
- ctx->Driver.TexParameter = mgaDDTexParameter;
- ctx->Driver.UpdateTexturePalette = 0;
- ctx->Driver.IsTextureResident = mgaDDIsTextureResident;
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+
+
+ ctx->Driver.ChooseTextureFormat = mgaChooseTextureFormat;
+ ctx->Driver.TexImage1D = _mesa_store_teximage1d;
+ ctx->Driver.TexImage2D = mgaTexImage2D;
+ ctx->Driver.TexImage3D = _mesa_store_teximage3d;
+ ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
+ ctx->Driver.TexSubImage2D = mgaTexSubImage2D;
+ 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.BindTexture = mgaDDBindTexture;
+ ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */
+ ctx->Driver.DeleteTexture = mgaDDDeleteTexture;
+ ctx->Driver.IsTextureResident = driIsTextureResident;
+ ctx->Driver.PrioritizeTexture = NULL;
+ ctx->Driver.ActiveTexture = NULL;
+ ctx->Driver.UpdateTexturePalette = NULL;
+
+ ctx->Driver.TexEnv = mgaDDTexEnv;
+ ctx->Driver.TexParameter = mgaDDTexParameter;
+
+ driInitTextureObjects( ctx, & mmesa->swapped, DRI_TEXMGR_DO_TEXTURE_2D );
}
diff --git a/src/mesa/drivers/dri/mga/mgatex.h b/src/mesa/drivers/dri/mga/mgatex.h
index c9f87d997e..282577e9f8 100644
--- a/src/mesa/drivers/dri/mga/mgatex.h
+++ b/src/mesa/drivers/dri/mga/mgatex.h
@@ -40,23 +40,10 @@ typedef struct mga_texture_object_s *mgaTextureObjectPtr;
*/
void mgaUpdateTextureState( GLcontext *ctx );
-void mgaConvertTexture( GLuint *dest, int texelBytes,
- struct gl_texture_image *image,
- int x, int y, int width, int height );
-
-
-void mgaUploadSubImageLocked( mgaContextPtr mmesa,
- mgaTextureObjectPtr t,
- int level,
- int x, int y, int width, int height );
-
int mgaUploadTexImages( mgaContextPtr mmesa, mgaTextureObjectPtr t );
void mgaDestroyTexObj( mgaContextPtr mmesa, mgaTextureObjectPtr t );
-void mgaAgeTextures( mgaContextPtr mmesa, int heap );
-
void mgaDDInitTextureFuncs( GLcontext *ctx );
-
#endif
diff --git a/src/mesa/drivers/dri/mga/mgatexmem.c b/src/mesa/drivers/dri/mga/mgatexmem.c
index 7dbdbc582f..4e7fd6b24b 100644
--- a/src/mesa/drivers/dri/mga/mgatexmem.c
+++ b/src/mesa/drivers/dri/mga/mgatexmem.c
@@ -26,539 +26,257 @@
*/
/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatexmem.c,v 1.7 2002/10/30 12:51:36 alanh Exp $ */
-#include <stdlib.h>
-#include <stdio.h>
-#include <GL/gl.h>
+#include "glheader.h"
#include "mm.h"
#include "mgacontext.h"
#include "mgatex.h"
#include "mgaregs.h"
#include "mgaioctl.h"
+#include "mga_xmesa.h"
-/*#include "mem.h" */
+#include "imports.h"
#include "simple_list.h"
-static void
-mgaSwapOutTexObj(mgaContextPtr mmesa, mgaTextureObjectPtr t)
-{
- if (t->MemBlock) {
- mmFreeMem(t->MemBlock);
- t->MemBlock = 0;
-
- if (t->age > mmesa->dirtyAge)
- mmesa->dirtyAge = t->age;
- }
-
- t->dirty_images = ~0;
- move_to_tail(&(mmesa->SwappedOut), t);
-}
-
-static void
-mgaPrintLocalLRU( mgaContextPtr mmesa, int heap )
-{
- mgaTextureObjectPtr t;
- int sz = 1 << (mmesa->mgaScreen->logTextureGranularity[heap]);
-
- fprintf(stderr, "\nLocal LRU, heap %d:\n", heap);
-
- foreach( t, &(mmesa->TexObjList[heap]) ) {
- if (!t->tObj)
- fprintf(stderr, "Placeholder %d at %x sz %x\n",
- t->MemBlock->ofs / sz,
- t->MemBlock->ofs,
- t->MemBlock->size);
- else
- fprintf(stderr, "Texture (bound %d) at %x sz %x\n",
- t->bound,
- t->MemBlock->ofs,
- t->MemBlock->size);
- }
-
- fprintf(stderr, "\n\n");
-}
-
-static void
-mgaPrintGlobalLRU( mgaContextPtr mmesa, int heap )
+/**
+ * Destroy any device-dependent state associated with the texture. This may
+ * include NULLing out hardware state that points to the texture.
+ */
+void
+mgaDestroyTexObj( mgaContextPtr mmesa, mgaTextureObjectPtr t )
{
- int i, j;
- drmTextureRegion *list = mmesa->sarea->texList[heap];
+ unsigned i;
- fprintf(stderr, "\nGlobal LRU, heap %d list %p:\n", heap, list);
- for (i = 0, j = MGA_NR_TEX_REGIONS ; i < MGA_NR_TEX_REGIONS ; i++) {
- fprintf(stderr, "list[%d] age %d next %d prev %d\n",
- j, list[j].age, list[j].next, list[j].prev);
- j = list[j].next;
- if (j == MGA_NR_TEX_REGIONS) break;
- }
+ /* See if it was the driver's current object.
+ */
- if (j != MGA_NR_TEX_REGIONS) {
- fprintf(stderr, "Loop detected in global LRU\n\n\n");
- for (i = 0 ; i < MGA_NR_TEX_REGIONS ; i++) {
- fprintf(stderr, "list[%d] age %d next %d prev %d\n",
- i, list[i].age, list[i].next, list[i].prev);
- }
- }
+ if ( mmesa != NULL )
+ {
+ if ( t->age > mmesa->dirtyAge )
+ mmesa->dirtyAge = t->age;
- fprintf(stderr, "\n\n");
+ for ( i = 0 ; i < mmesa->glCtx->Const.MaxTextureUnits ; i++ )
+ {
+ if ( t == mmesa->CurrentTexObj[ i ] ) {
+ mmesa->CurrentTexObj[ i ] = NULL;
+ }
+ }
+ }
}
-static void mgaResetGlobalLRU( mgaContextPtr mmesa, GLuint heap )
+/**
+ * Upload a texture image from system memory to either on-card or AGP
+ * memory. Uploads to on-card memory are performed using an ILOAD operation.
+ * This is used for both initial loading of the entire image, and texSubImage
+ * updates.
+ *
+ * Performed with the hardware lock held.
+ *
+ * Even though this function is named "upload subimage," the entire image
+ * is uploaded.
+ *
+ * \param mmesa Driver context.
+ * \param t Texture to be uploaded.
+ * \param hwlevel Mipmap level of the texture to be uploaded.
+ *
+ * \bug As mentioned above, this fuction actually copies the entier mipmap
+ * level. There should be a version of this function that performs
+ * sub-rectangle uploads. This will perform quite a bit better if only
+ * a small portion of a larger texture has been updated. Care would
+ * need to be take with such an implementation once glCopyTexImage has
+ * been hardware accelerated.
+ */
+static void mgaUploadSubImage( mgaContextPtr mmesa,
+ mgaTextureObjectPtr t, GLint hwlevel )
{
- drmTextureRegion *list = mmesa->sarea->texList[heap];
- int sz = 1 << mmesa->mgaScreen->logTextureGranularity[heap];
- int i;
-
- mmesa->texAge[heap] = ++mmesa->sarea->texAge[heap];
+ struct gl_texture_image * texImage;
+ unsigned offset;
+ unsigned texelBytes;
+ unsigned length;
+ const int level = hwlevel + t->base.firstLevel;
- if (0) fprintf(stderr, "mgaResetGlobalLRU %d\n", (int)heap);
- /* (Re)initialize the global circular LRU list. The last element
- * in the array (MGA_NR_TEX_REGIONS) is the sentinal. Keeping it
- * at the end of the array allows it to be addressed rationally
- * when looking up objects at a particular location in texture
- * memory.
- */
- for (i = 0 ; (i+1) * sz <= mmesa->mgaScreen->textureSize[heap] ; i++) {
- list[i].prev = i-1;
- list[i].next = i+1;
- list[i].age = mmesa->sarea->texAge[heap];
+ if ( (hwlevel < 0)
+ || (hwlevel >= (MGA_IS_G200(mmesa)
+ ? G200_TEX_MAXLEVELS : G400_TEX_MAXLEVELS)) ) {
+ fprintf( stderr, "[%s:%d] level = %d\n", __FILE__, __LINE__, level );
+ return;
}
- i--;
- list[0].prev = MGA_NR_TEX_REGIONS;
- list[i].prev = i-1;
- list[i].next = MGA_NR_TEX_REGIONS;
- list[MGA_NR_TEX_REGIONS].prev = i;
- list[MGA_NR_TEX_REGIONS].next = 0;
-
-}
-
-
-static void mgaUpdateTexLRU( mgaContextPtr mmesa, mgaTextureObjectPtr t )
-{
- int i;
- int heap = t->heap;
- int logsz = mmesa->mgaScreen->logTextureGranularity[heap];
- int start = t->MemBlock->ofs >> logsz;
- int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz;
- drmTextureRegion *list = mmesa->sarea->texList[heap];
-
- mmesa->texAge[heap] = ++mmesa->sarea->texAge[heap];
-
- if (!t->MemBlock) {
- fprintf(stderr, "no memblock\n\n");
+ texImage = t->base.tObj->Image[level];
+ if ( texImage == NULL ) {
+ fprintf( stderr, "[%s:%d] Image[%d] = NULL\n", __FILE__, __LINE__,
+ level );
return;
}
- /* Update our local LRU
- */
- move_to_head( &(mmesa->TexObjList[heap]), t );
-
-
- if (0)
- fprintf(stderr, "mgaUpdateTexLRU heap %d list %p\n", heap, list);
-
- /* Update the global LRU
- */
- for (i = start ; i <= end ; i++) {
-
- list[i].in_use = 1;
- list[i].age = mmesa->texAge[heap];
-
- /* remove_from_list(i)
- */
- list[(unsigned)list[i].next].prev = list[i].prev;
- list[(unsigned)list[i].prev].next = list[i].next;
-
- /* insert_at_head(list, i)
- */
- list[i].prev = MGA_NR_TEX_REGIONS;
- list[i].next = list[MGA_NR_TEX_REGIONS].next;
- list[(unsigned)list[MGA_NR_TEX_REGIONS].next].prev = i;
- list[MGA_NR_TEX_REGIONS].next = i;
- }
-
- if (0) {
- mgaPrintGlobalLRU(mmesa, t->heap);
- mgaPrintLocalLRU(mmesa, t->heap);
+ if (texImage->Data == NULL) {
+ fprintf(stderr, "null texture image data tObj %p level %d\n",
+ t->base.tObj, level);
+ return;
}
-}
-
-/* Called for every shared texture region which has increased in age
- * since we last held the lock.
- *
- * Figures out which of our textures have been ejected by other clients,
- * and pushes a placeholder texture onto the LRU list to represent
- * the other client's textures.
- */
-static void mgaTexturesGone( mgaContextPtr mmesa,
- GLuint heap,
- GLuint offset,
- GLuint size,
- GLuint in_use )
-{
- mgaTextureObjectPtr t, tmp;
-
-
- foreach_s ( t, tmp, &(mmesa->TexObjList[heap]) ) {
- if (t->MemBlock->ofs >= offset + size ||
- t->MemBlock->ofs + t->MemBlock->size <= offset)
- continue;
-
-
-
-
- /* It overlaps - kick it off. Need to hold onto the currently bound
- * objects, however.
- */
- if (t->bound)
- mgaSwapOutTexObj( mmesa, t );
- else
- mgaDestroyTexObj( mmesa, t );
+ /* find the proper destination offset for this level */
+ if ( MGA_IS_G200(mmesa) ) {
+ offset = (t->base.memBlock->ofs + t->offsets[hwlevel]);
}
+ else {
+ unsigned i;
-
- if (in_use) {
- t = (mgaTextureObjectPtr) calloc(1, sizeof(*t));
- if (!t) return;
-
- t->heap = heap;
- t->MemBlock = mmAllocMem( mmesa->texHeap[heap], size, 0, offset);
- if (!t->MemBlock) {
- fprintf(stderr, "Couldn't alloc placeholder sz %x ofs %x\n",
- (int)size, (int)offset);
- mmDumpMemInfo( mmesa->texHeap[heap]);
- return;
+ offset = t->base.memBlock->ofs;
+ for ( i = 0 ; i < hwlevel ; i++ ) {
+ offset += (t->offsets[1] >> (i * 2));
}
- insert_at_head( &(mmesa->TexObjList[heap]), t );
- }
-}
-
-
-void mgaAgeTextures( mgaContextPtr mmesa, int heap )
-{
- MGASAREAPrivPtr sarea = mmesa->sarea;
- int sz = 1 << (mmesa->mgaScreen->logTextureGranularity[heap]);
- int idx, nr = 0;
- /* Have to go right round from the back to ensure stuff ends up
- * LRU in our local list... Fix with a cursor pointer.
- */
- for (idx = sarea->texList[heap][MGA_NR_TEX_REGIONS].prev ;
- idx != MGA_NR_TEX_REGIONS && nr < MGA_NR_TEX_REGIONS ;
- idx = sarea->texList[heap][idx].prev, nr++)
- {
- /* If switching texturing schemes, then the SAREA might not
- * have been properly cleared, so we need to reset the
- * global texture LRU.
+ /* Each mipmap must be DWORD aligned.
*/
- if ( idx * sz > mmesa->mgaScreen->textureSize[heap] ) {
- nr = MGA_NR_TEX_REGIONS;
- break;
- }
-
- if (sarea->texList[heap][idx].age > mmesa->texAge[heap]) {
- mgaTexturesGone(mmesa, heap, idx * sz, sz,
- sarea->texList[heap][idx].in_use);
- }
- }
-
- if (nr == MGA_NR_TEX_REGIONS) {
- mgaTexturesGone(mmesa, heap, 0,
- mmesa->mgaScreen->textureSize[heap], 0);
- mgaResetGlobalLRU( mmesa, heap );
+ offset &= ~0x03;
}
- if (0) {
- mgaPrintGlobalLRU( mmesa, heap );
- mgaPrintLocalLRU( mmesa, heap );
- }
-
- mmesa->texAge[heap] = sarea->texAge[heap];
- mmesa->dirty |= MGA_UPLOAD_TEX0IMAGE | MGA_UPLOAD_TEX1IMAGE;
-}
-
-/*
- * mgaUploadSubImageLocked
- *
- * Perform an iload based update of a resident buffer. This is used for
- * both initial loading of the entire image, and texSubImage updates.
- *
- * Performed with the hardware lock held.
- */
-void mgaUploadSubImageLocked( mgaContextPtr mmesa,
- mgaTextureObjectPtr t,
- int level,
- int x, int y, int width, int height )
-{
- int x2;
- int dwords;
- int offset;
- struct gl_texture_image *image;
- int texelBytes, texelsPerDword, texelMaccess, length;
-
- if ( level < 0 || level >= MGA_TEX_MAXLEVELS )
- return;
+ /* Copy the texture from system memory to a memory space that can be
+ * directly used by the hardware for texturing.
+ */
- image = t->tObj->Image[level];
- if ( !image ) return;
+ texelBytes = texImage->TexFormat->TexelBytes;
+ length = texImage->Width * texImage->Height * texelBytes;
+ if ( t->base.heap->heapId == MGA_CARD_HEAP ) {
+ unsigned tex_offset = 0;
+ unsigned to_copy;
- if (image->Data == 0) {
- fprintf(stderr, "null texture image data tObj %p level %d\n",
- t->tObj, level);
- return;
- }
+ /* We may not be able to upload the entire texture in one batch due to
+ * register limits or dma buffer limits. Split the copy up into maximum
+ * sized chunks.
+ */
+ offset += mmesa->mgaScreen->textureOffset[ t->base.heap->heapId ];
+ while ( length != 0 ) {
+ mgaGetILoadBufferLocked( mmesa );
- /* find the proper destination offset for this level */
- offset = (t->MemBlock->ofs +
- t->offsets[level]);
-
-
- texelBytes = t->texelBytes;
- switch( texelBytes ) {
- case 1:
- texelsPerDword = 4;
- texelMaccess = 0;
- break;
- case 2:
- texelsPerDword = 2;
- texelMaccess = 1;
- break;
- case 4:
- texelsPerDword = 1;
- texelMaccess = 2;
- break;
- default:
- return;
- }
+ /* The kernel ILOAD ioctl requires that the lenght be an even multiple
+ * of MGA_ILOAD_ALIGN.
+ */
+ length = ((length) + MGA_ILOAD_MASK) & ~MGA_ILOAD_MASK;
+ to_copy = MIN2( length, MGA_BUFFER_SIZE );
+ (void) memcpy( mmesa->iload_buffer->address,
+ (GLubyte *) texImage->Data + tex_offset, to_copy );
- /* We can't do a subimage update if pitch is < 32 texels due
- * to hardware XY addressing limits, so we will need to
- * linearly upload all modified rows.
- */
- if ( image->Width < 32 ) {
- x = 0;
- width = image->Width * height;
- height = 1;
-
- /* Assume that 1x1 textures aren't going to cause a
- * bus error if we read up to four texels from that
- * location:
- */
-/* if ( width < texelsPerDword ) { */
-/* width = texelsPerDword; */
-/* } */
- } else {
- /* pad the size out to dwords. The image is a pointer
- to the entire image, so we can safely reference
- outside the x,y,width,height bounds if we need to */
- x2 = x + width;
- x2 = (x2 + (texelsPerDword-1)) & ~(texelsPerDword-1);
- x = (x + (texelsPerDword-1)) & ~(texelsPerDword-1);
- width = x2 - x;
- }
+ if ( MGA_DEBUG & DEBUG_VERBOSE_TEXTURE )
+ fprintf(stderr, "[%s:%d] address/size = 0x%08lx/%d\n",
+ __FILE__, __LINE__,
+ (long) (offset + tex_offset),
+ to_copy );
- /* we may not be able to upload the entire texture in one
- batch due to register limits or dma buffer limits.
- Recursively split it up. */
- while ( 1 ) {
- dwords = height * width / texelsPerDword;
- if ( dwords * 4 <= MGA_BUFFER_SIZE ) {
- break;
+ mgaFireILoadLocked( mmesa, offset + tex_offset, to_copy );
+ tex_offset += to_copy;
+ length -= to_copy;
}
-
- mgaUploadSubImageLocked( mmesa, t, level, x, y,
- width, height >> 1 );
- y += ( height >> 1 );
- height -= ( height >> 1 );
- }
-
- length = dwords * 4;
-
- /* Fill in the secondary buffer with properly converted texels
- * from the mesa buffer. */
- /* FIXME: the sync for direct copy reduces speed.. */
- if(t->heap == MGA_CARD_HEAP ) {
- mgaGetILoadBufferLocked( mmesa );
- mgaConvertTexture( (GLuint *)mmesa->iload_buffer->address,
- texelBytes, image, x, y, width, height );
- if(length < 64) length = 64;
-
- if (0)
- fprintf(stderr, "TexelBytes : %d, offset: %d, length : %d\n",
- texelBytes,
- mmesa->mgaScreen->textureOffset[t->heap] +
- offset +
- y * width * 4/texelsPerDword,
- length);
-
- mgaFireILoadLocked( mmesa,
- mmesa->mgaScreen->textureOffset[t->heap] +
- offset +
- y * width * 4/texelsPerDword,
- length);
} else {
+ /* FIXME: the sync for direct copy reduces speed.. */
/* This works, is slower for uploads to card space and needs
* additional synchronization with the dma stream.
*/
UPDATE_LOCK(mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT);
- mgaConvertTexture( (GLuint *)
- (mmesa->mgaScreen->texVirtual[t->heap] +
- offset +
- y * width * 4/texelsPerDword),
- texelBytes, image, x, y, width, height );
- }
-}
-
-
-static void mgaUploadTexLevel( mgaContextPtr mmesa,
- mgaTextureObjectPtr t,
- int l )
-{
- mgaUploadSubImageLocked( mmesa,
- t,
- l,
- 0, 0,
- t->tObj->Image[l]->Width,
- t->tObj->Image[l]->Height);
-}
-
-
-
-
-#if 0
-static void mgaMigrateTexture( mgaContextPtr mmesa, mgaTextureObjectPtr t )
-{
- /* NOT DONE */
-}
-#endif
-
-
-static int mgaChooseTexHeap( mgaContextPtr mmesa, mgaTextureObjectPtr t )
-{
- int freeagp, freecard;
- int fitincard, fitinagp;
- int totalcard, totalagp;
- TMemBlock *b;
-
- totalcard = totalagp = fitincard = fitinagp = freeagp = freecard = 0;
-
- b = mmesa->texHeap[0];
- while(b)
- {
- totalcard += b->size;
- if(b->free) if(t->totalSize <= b->size)fitincard = 1;
- b = b->next;
- }
-
- b = mmesa->texHeap[1];
- while(b)
- {
- totalagp += b->size;
- if(b->free) if(t->totalSize <= b->size)fitinagp = 1;
- b = b->next;
- }
- if(fitincard)return 0;
- if(fitinagp)return 1;
+ memcpy( mmesa->mgaScreen->texVirtual[t->base.heap->heapId] + offset,
+ texImage->Data, length );
- if(totalcard && totalagp)
- {
- int ages;
- int ratio = (totalcard > totalagp) ? totalcard / totalagp : totalagp / totalcard;
- ages = mmesa->sarea->texAge[0] + mmesa->sarea->texAge[1];
- if( (ages % ratio) == 0)return totalcard > totalagp ? 1 : 0;
- else return totalcard > totalagp ? 0 : 1;
+ if ( MGA_DEBUG & DEBUG_VERBOSE_TEXTURE )
+ fprintf(stderr, "[%s:%d] address/size = 0x%08lx/%d\n",
+ __FILE__, __LINE__,
+ (long) (mmesa->mgaScreen->texVirtual[t->base.heap->heapId]
+ + offset),
+ length);
}
-
- if(totalagp) return 1;
- return 0;
}
+/**
+ * Upload the texture images associated with texture \a t. This might
+ * require the allocation of texture memory.
+ *
+ * \param mmesa Context pointer
+ * \param t Texture to be uploaded
+ */
+
int mgaUploadTexImages( mgaContextPtr mmesa, mgaTextureObjectPtr t )
{
- int heap;
int i;
int ofs;
- heap = t->heap = mgaChooseTexHeap( mmesa, t );
- /* Do we need to eject LRU texture objects?
- */
- if (!t->MemBlock) {
- while (1)
- {
- mgaTextureObjectPtr tmp = mmesa->TexObjList[heap].prev;
-
- t->MemBlock = mmAllocMem( mmesa->texHeap[heap],
- t->totalSize,
- 6, 0 );
- if (t->MemBlock)
- break;
-
- if (mmesa->TexObjList[heap].prev->bound) {
- fprintf(stderr, "Hit bound texture in upload\n");
- return -1;
- }
+ if ( (t == NULL) || (t->base.totalSize == 0) )
+ return 0;
- if (mmesa->TexObjList[heap].prev ==
- &(mmesa->TexObjList[heap]))
- {
- fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize);
- mmDumpMemInfo( mmesa->texHeap[heap] );
- return -1;
- }
+ LOCK_HARDWARE( mmesa );
- mgaDestroyTexObj( mmesa, tmp );
+ if (t->base.memBlock == NULL ) {
+ int heap;
+
+ heap = driAllocateTexture( mmesa->texture_heaps, mmesa->nr_heaps,
+ (driTextureObject *) t );
+ if ( heap == -1 ) {
+ UNLOCK_HARDWARE( mmesa );
+ return -1;
}
- ofs = t->MemBlock->ofs
- + mmesa->mgaScreen->textureOffset[heap]
- ;
+ ofs = mmesa->mgaScreen->textureOffset[ heap ]
+ + t->base.memBlock->ofs;
- t->setup.texorg = ofs;
- t->setup.texorg1 = ofs + t->offsets[1];
- t->setup.texorg2 = ofs + t->offsets[2];
- t->setup.texorg3 = ofs + t->offsets[3];
- t->setup.texorg4 = ofs + t->offsets[4];
+ if ( MGA_IS_G200(mmesa) ) {
+ t->setup.texorg = ofs;
+ t->setup.texorg1 = ofs + t->offsets[1];
+ t->setup.texorg2 = ofs + t->offsets[2];
+ t->setup.texorg3 = ofs + t->offsets[3];
+ t->setup.texorg4 = ofs + t->offsets[4];
+ }
+ else {
+ t->setup.texorg = ofs | TO_texorgoffsetsel;
+ t->setup.texorg1 = t->offsets[1];
+ t->setup.texorg2 = 0;
+ t->setup.texorg3 = 0;
+ t->setup.texorg4 = 0;
+ }
mmesa->dirty |= MGA_UPLOAD_CONTEXT;
}
/* Let the world know we've used this memory recently.
*/
- mgaUpdateTexLRU( mmesa, t );
-
+ driUpdateTextureLRU( (driTextureObject *) t );
- if (MGA_DEBUG&DEBUG_VERBOSE_LRU)
- fprintf(stderr, "dispatch age: %d age freed memory: %d\n",
+ if (MGA_DEBUG&DEBUG_VERBOSE_TEXTURE)
+ fprintf(stderr, "[%s:%d] dispatch age: %d age freed memory: %d\n",
+ __FILE__, __LINE__,
GET_DISPATCH_AGE(mmesa), mmesa->dirtyAge);
if (mmesa->dirtyAge >= GET_DISPATCH_AGE(mmesa))
mgaWaitAgeLocked( mmesa, mmesa->dirtyAge );
- if (t->dirty_images) {
- if (MGA_DEBUG&DEBUG_VERBOSE_LRU)
- fprintf(stderr, "*");
+ if (t->base.dirty_images[0]) {
+ const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
- for (i = 0 ; i <= t->lastLevel ; i++)
- if (t->dirty_images & (1<<i))
- mgaUploadTexLevel( mmesa, t, i );
+ if (MGA_DEBUG&DEBUG_VERBOSE_TEXTURE)
+ fprintf(stderr, "[%s:%d] dirty_images[0] = 0x%04x\n",
+ __FILE__, __LINE__, t->base.dirty_images[0] );
+
+ for (i = 0 ; i < numLevels ; i++) {
+ if ( (t->base.dirty_images[0] & (1U << i)) != 0 ) {
+ mgaUploadSubImage( mmesa, t, i );
+ }
+ }
+ t->base.dirty_images[0] = 0;
}
- t->dirty_images = 0;
+ UNLOCK_HARDWARE( mmesa );
+
return 0;
}
diff --git a/src/mesa/drivers/dri/mga/mgatris.c b/src/mesa/drivers/dri/mga/mgatris.c
index e47cfc171f..054c7f0635 100644
--- a/src/mesa/drivers/dri/mga/mgatris.c
+++ b/src/mesa/drivers/dri/mga/mgatris.c
@@ -26,9 +26,6 @@
*/
/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatris.c,v 1.10 2002/10/30 12:51:36 alanh Exp $ */
-#include <stdio.h>
-#include <math.h>
-
#include "mtypes.h"
#include "macros.h"
#include "colormac.h"
@@ -676,15 +673,6 @@ static void mgaFastRenderClippedPoly( GLcontext *ctx, const GLuint *elts,
/**********************************************************************/
-
-#define _MGA_NEW_RENDERSTATE (_DD_NEW_LINE_STIPPLE | \
- _DD_NEW_TRI_UNFILLED | \
- _DD_NEW_TRI_LIGHT_TWOSIDE | \
- _DD_NEW_TRI_OFFSET | \
- _DD_NEW_TRI_STIPPLE | \
- _NEW_POLYGONSTIPPLE)
-
-
#define POINT_FALLBACK (DD_POINT_SMOOTH)
#define LINE_FALLBACK (DD_LINE_SMOOTH | DD_LINE_STIPPLE)
#define TRI_FALLBACK (DD_TRI_SMOOTH | DD_TRI_UNFILLED)
@@ -693,7 +681,7 @@ static void mgaFastRenderClippedPoly( GLcontext *ctx, const GLuint *elts,
#define ANY_RASTER_FLAGS (DD_FLATSHADE|DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET| \
DD_TRI_UNFILLED)
-static void mgaChooseRenderState(GLcontext *ctx)
+void mgaChooseRenderState(GLcontext *ctx)
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
@@ -759,36 +747,6 @@ static void mgaChooseRenderState(GLcontext *ctx)
/**********************************************************************/
-static void mgaRunPipeline( GLcontext *ctx )
-{
- mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-
- if (mmesa->new_state) {
- mgaDDUpdateHwState( ctx );
- }
-
- if (!mmesa->Fallback && mmesa->new_gl_state) {
- if (mmesa->new_gl_state & _MGA_NEW_RASTERSETUP)
- mgaChooseVertexState( ctx );
-
- if (mmesa->new_gl_state & _MGA_NEW_RENDERSTATE)
- mgaChooseRenderState( ctx );
-
- mmesa->new_gl_state = 0;
-
- /* Circularity: mgaDDUpdateHwState can affect mmesa->Fallback,
- * but mgaChooseVertexState can affect mmesa->new_state. Hence
- * the second check. (Fix this...)
- */
- if (mmesa->new_state) {
- mgaDDUpdateHwState( ctx );
- }
- }
-
- _tnl_run_pipeline( ctx );
-}
-
-
static GLenum reduced_prim[GL_POLYGON+1] = {
GL_POINTS,
GL_LINES,
@@ -812,10 +770,14 @@ void mgaRasterPrimitive( GLcontext *ctx, GLenum prim, GLuint hwprim )
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
FLUSH_BATCH( mmesa );
+
+ /* Update culling */
+ if (mmesa->raster_primitive != prim)
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+
mmesa->raster_primitive = prim;
/* mmesa->hw_primitive = hwprim; */
mmesa->hw_primitive = MGA_WA_TRIANGLES; /* disable mgarender.c for now */
- mgaUpdateCull(ctx);
if (ctx->Polygon.StippleFlag && mmesa->haveHwStipple)
{
@@ -864,6 +826,28 @@ static void mgaRenderFinish( GLcontext *ctx )
/* Manage total rasterization fallbacks */
/**********************************************************************/
+static const char * const fallbackStrings[] = {
+ "Texture mode",
+ "glDrawBuffer(GL_FRONT_AND_BACK)",
+ "read buffer",
+ "LogicOp != GL_COPY",
+ "glRenderMode(selection or feedback)",
+ "No hardware stencil",
+ "glDepthFunc( GL_NEVER )",
+ "Mixing GL_CLAMP_TO_EDGE and GL_CLAMP"
+};
+
+static const char *getFallbackString(GLuint bit)
+{
+ int i = 0;
+ while (bit > 1) {
+ i++;
+ bit >>= 1;
+ }
+ return fallbackStrings[i];
+}
+
+
void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
@@ -876,6 +860,10 @@ void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
FLUSH_BATCH(mmesa);
_swsetup_Wakeup( ctx );
mmesa->RenderIndex = ~0;
+ if (MGA_DEBUG & DEBUG_VERBOSE_FALLBACK) {
+ fprintf(stderr, "MGA begin rasterization fallback: 0x%x %s\n",
+ bit, getFallbackString(bit));
+ }
}
}
else {
@@ -886,8 +874,12 @@ void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
tnl->Driver.Render.PrimitiveNotify = mgaRenderPrimitive;
tnl->Driver.Render.Finish = mgaRenderFinish;
tnl->Driver.Render.BuildVertices = mgaBuildVertices;
- mmesa->new_gl_state |= (_MGA_NEW_RENDERSTATE |
- _MGA_NEW_RASTERSETUP);
+ mmesa->NewGLState |= (_MGA_NEW_RENDERSTATE |
+ _MGA_NEW_RASTERSETUP);
+ if (MGA_DEBUG & DEBUG_VERBOSE_FALLBACK) {
+ fprintf(stderr, "MGA end rasterization fallback: 0x%x %s\n",
+ bit, getFallbackString(bit));
+ }
}
}
}
@@ -905,7 +897,6 @@ void mgaDDInitTriFuncs( GLcontext *ctx )
mmesa->RenderIndex = ~0;
- tnl->Driver.RunPipeline = mgaRunPipeline;
tnl->Driver.Render.Start = mgaCheckTexSizes;
tnl->Driver.Render.Finish = mgaRenderFinish;
tnl->Driver.Render.PrimitiveNotify = mgaRenderPrimitive;
diff --git a/src/mesa/drivers/dri/mga/mgatris.h b/src/mesa/drivers/dri/mga/mgatris.h
index 88eda91e13..a8c0b8936b 100644
--- a/src/mesa/drivers/dri/mga/mgatris.h
+++ b/src/mesa/drivers/dri/mga/mgatris.h
@@ -32,12 +32,17 @@
#include "mtypes.h"
extern void mgaDDInitTriFuncs( GLcontext *ctx );
-
+extern void mgaChooseRenderState( GLcontext *ctx );
extern void mgaRasterPrimitive( GLcontext *ctx, GLenum prim, GLuint hwprim );
extern void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode );
#define FALLBACK( ctx, bit, mode ) mgaFallback( ctx, bit, mode )
-
+#define _MGA_NEW_RENDERSTATE (_DD_NEW_LINE_STIPPLE | \
+ _DD_NEW_TRI_UNFILLED | \
+ _DD_NEW_TRI_LIGHT_TWOSIDE | \
+ _DD_NEW_TRI_OFFSET | \
+ _DD_NEW_TRI_STIPPLE | \
+ _NEW_POLYGONSTIPPLE)
#endif
diff --git a/src/mesa/drivers/dri/mga/mgavb.c b/src/mesa/drivers/dri/mga/mgavb.c
index d354fa43d2..34906865e8 100644
--- a/src/mesa/drivers/dri/mga/mgavb.c
+++ b/src/mesa/drivers/dri/mga/mgavb.c
@@ -24,7 +24,7 @@
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
-/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgavb.c,v 1.15 2003/03/26 20:43:49 tsi Exp $ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgavb.c,v 1.14 2002/10/30 12:51:36 alanh Exp $ */
#include "mgacontext.h"
#include "mgavb.h"
@@ -34,18 +34,14 @@
#include "glheader.h"
#include "mtypes.h"
-/*#include "mem.h" */
+#include "imports.h"
#include "macros.h"
#include "colormac.h"
-/*#include "mmath.h"*/
#include "tnl/t_context.h"
#include "swrast_setup/swrast_setup.h"
#include "swrast/swrast.h"
-#include <stdio.h>
-#include <stdlib.h>
-
#define MGA_TEX1_BIT 0x1
#define MGA_TEX0_BIT 0x2
@@ -93,7 +89,7 @@ static struct {
#define GET_VIEWPORT_MAT() mmesa->hw_viewport
#define GET_TEXSOURCE(n) mmesa->tmu_source[n]
#define GET_VERTEX_FORMAT() mmesa->vertex_format
-#define GET_VERTEX_STORE() ((GLubyte *)mmesa->verts)
+#define GET_VERTEX_STORE() mmesa->verts
#define GET_VERTEX_STRIDE_SHIFT() mmesa->vertex_stride_shift
#define GET_UBYTE_COLOR_STORE() &mmesa->UbyteColor
#define GET_UBYTE_SPEC_COLOR_STORE() &mmesa->UbyteSecondaryColor
@@ -407,15 +403,18 @@ void mgaChooseVertexState( GLcontext *ctx )
if (ctx->Fog.Enabled)
ind |= MGA_FOG_BIT;
- if (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
- if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
+ if (ctx->Texture._EnabledUnits & 0x2) {
+ /* unit 1 enabled */
+ if (ctx->Texture._EnabledUnits & 0x1) {
+ /* unit 0 enabled */
ind |= MGA_TEX1_BIT|MGA_TEX0_BIT;
}
else {
ind |= MGA_TEX0_BIT;
}
}
- else if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
+ else if (ctx->Texture._EnabledUnits & 0x1) {
+ /* unit 0 enabled */
ind |= MGA_TEX0_BIT;
}
@@ -431,7 +430,6 @@ void mgaChooseVertexState( GLcontext *ctx )
if (setup_tab[ind].vertex_format != mmesa->vertex_format) {
FLUSH_BATCH(mmesa);
- mmesa->new_state |= MGA_NEW_WARP;
mmesa->dirty |= MGA_UPLOAD_PIPE;
mmesa->vertex_format = setup_tab[ind].vertex_format;
mmesa->vertex_size = setup_tab[ind].vertex_size;
@@ -458,7 +456,7 @@ void mgaInitVB( GLcontext *ctx )
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
GLuint size = TNL_CONTEXT(ctx)->vb.Size;
- mmesa->verts = (char *)ALIGN_MALLOC(size * sizeof(mgaVertex), 32);
+ mmesa->verts = ALIGN_MALLOC(size * sizeof(mgaVertex), 32);
{
static int firsttime = 1;
@@ -468,7 +466,6 @@ void mgaInitVB( GLcontext *ctx )
}
}
- mmesa->new_state |= MGA_NEW_WARP;
mmesa->dirty |= MGA_UPLOAD_PIPE;
mmesa->vertex_format = setup_tab[0].vertex_format;
mmesa->vertex_size = setup_tab[0].vertex_size;
diff --git a/src/mesa/drivers/dri/mga/server/mga_common.h b/src/mesa/drivers/dri/mga/server/mga_common.h
index 90f6b37f4e..dcc260a1a5 100644
--- a/src/mesa/drivers/dri/mga/server/mga_common.h
+++ b/src/mesa/drivers/dri/mga/server/mga_common.h
@@ -146,7 +146,7 @@ typedef struct {
typedef struct {
int param;
- int *value;
+ void *value;
} drmMGAGetParam;
#endif
diff --git a/src/mesa/drivers/dri/r128/Makefile.X11 b/src/mesa/drivers/dri/r128/Makefile.X11
new file mode 100644
index 0000000000..8ae146af91
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/Makefile.X11
@@ -0,0 +1,116 @@
+# $Id: Makefile.X11,v 1.1 2003/08/22 20:11:44 brianp Exp $
+
+# 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
+
+MINIGLX_SOURCES = server/r128_dri.c
+
+DRIVER_SOURCES = \
+ r128_context.c \
+ r128_lock.c \
+ r128_state.c \
+ r128_texstate.c \
+ r128_dd.c \
+ r128_screen.c \
+ r128_tex.c \
+ r128_tris.c \
+ r128_ioctl.c \
+ r128_span.c \
+ r128_texmem.c \
+ r128_vb.c \
+ ../common/mm.c \
+ ../common/utils.c \
+ ../common/texmem.c \
+ ../common/vblank.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)
+
+### 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 r128_dri.so
+
+r128_dri.so: $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11
+ rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc $(GL_LIB_DEPS)
+ rm -f $(TOP)/lib/r128_dri.so && \
+ install r128_dri.so $(TOP)/lib/r128_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
+
+
+include $(TOP)/Make-config
+
+include depend
diff --git a/src/mesa/drivers/dri/r128/r128_context.c b/src/mesa/drivers/dri/r128/r128_context.c
new file mode 100644
index 0000000000..f7f6d7141d
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_context.c
@@ -0,0 +1,335 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_context.c,v 1.8 2002/10/30 12:51:38 alanh Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "simple_list.h"
+#include "imports.h"
+#include "matrix.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"
+
+#include "r128_context.h"
+#include "r128_ioctl.h"
+#include "r128_dd.h"
+#include "r128_state.h"
+#include "r128_span.h"
+#include "r128_tex.h"
+#include "r128_tris.h"
+#include "r128_vb.h"
+
+#include "vblank.h"
+#include "utils.h"
+#include "texmem.h"
+
+#ifndef R128_DEBUG
+int R128_DEBUG = 0;
+#endif
+
+static const char * const card_extensions[] =
+{
+ "GL_ARB_multitexture",
+ "GL_ARB_texture_env_add",
+ "GL_ARB_texture_mirrored_repeat",
+ "GL_EXT_texture_edge_clamp",
+ "GL_EXT_texture_env_add",
+ "GL_IBM_texture_mirrored_repeat",
+ "GL_SGIS_generate_mipmap",
+ "GL_SGIS_texture_edge_clamp",
+ NULL
+};
+
+static const struct dri_debug_control debug_control[] =
+{
+ { "ioctl", DEBUG_VERBOSE_IOCTL },
+ { "verb", DEBUG_VERBOSE_MSG },
+ { "dri", DEBUG_VERBOSE_DRI },
+ { "2d", DEBUG_VERBOSE_2D },
+ { "sync", DEBUG_ALWAYS_SYNC },
+ { "api", DEBUG_VERBOSE_API },
+ { NULL, 0 }
+};
+
+/* Create the device specific context.
+ */
+GLboolean r128CreateContext( const __GLcontextModes *glVisual,
+ __DRIcontextPrivate *driContextPriv,
+ void *sharedContextPrivate )
+{
+ GLcontext *ctx, *shareCtx;
+ __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
+ r128ContextPtr rmesa;
+ r128ScreenPtr r128scrn;
+ int i;
+
+ /* Allocate the r128 context */
+ rmesa = (r128ContextPtr) CALLOC( sizeof(*rmesa) );
+ if ( !rmesa )
+ return GL_FALSE;
+
+ /* Allocate the Mesa context */
+ if (sharedContextPrivate)
+ shareCtx = ((r128ContextPtr) sharedContextPrivate)->glCtx;
+ else
+ shareCtx = NULL;
+ rmesa->glCtx = _mesa_create_context(glVisual, shareCtx, (void *) rmesa, GL_TRUE);
+ if (!rmesa->glCtx) {
+ FREE(rmesa);
+ return GL_FALSE;
+ }
+ driContextPriv->driverPrivate = rmesa;
+ ctx = rmesa->glCtx;
+
+ rmesa->driContext = driContextPriv;
+ rmesa->driScreen = sPriv;
+ rmesa->driDrawable = NULL;
+ rmesa->hHWContext = driContextPriv->hHWContext;
+ rmesa->driHwLock = &sPriv->pSAREA->lock;
+ rmesa->driFd = sPriv->fd;
+
+ r128scrn = rmesa->r128Screen = (r128ScreenPtr)(sPriv->private);
+
+ rmesa->sarea = (R128SAREAPrivPtr)((char *)sPriv->pSAREA +
+ r128scrn->sarea_priv_offset);
+
+ rmesa->CurrentTexObj[0] = NULL;
+ rmesa->CurrentTexObj[1] = NULL;
+
+ (void) memset( rmesa->texture_heaps, 0, sizeof( rmesa->texture_heaps ) );
+ make_empty_list( & rmesa->swapped );
+
+ rmesa->nr_heaps = r128scrn->numTexHeaps;
+ for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
+ rmesa->texture_heaps[i] = driCreateTextureHeap( i, rmesa,
+ r128scrn->texSize[i],
+ 12,
+ R128_NR_TEX_REGIONS,
+ rmesa->sarea->texList[i],
+ & rmesa->sarea->texAge[i],
+ & rmesa->swapped,
+ sizeof( r128TexObj ),
+ (destroy_texture_object_t *) r128DestroyTexObj );
+
+ driSetTextureSwapCounterLocation( rmesa->texture_heaps[i],
+ & rmesa->c_textureSwaps );
+ }
+
+
+ rmesa->RenderIndex = -1; /* Impossible value */
+ rmesa->vert_buf = NULL;
+ rmesa->num_verts = 0;
+
+ /* Set the maximum texture size small enough that we can guarentee that
+ * all texture units can bind a maximal texture and have them both in
+ * texturable memory at once.
+ */
+
+ ctx->Const.MaxTextureUnits = 2;
+
+ driCalculateMaxTextureLevels( rmesa->texture_heaps,
+ rmesa->nr_heaps,
+ & ctx->Const,
+ 4,
+ 10, /* max 2D texture size is 1024x1024 */
+ 0, /* 3D textures unsupported. */
+ 0, /* cube textures unsupported. */
+ 0, /* texture rectangles unsupported. */
+ 11,
+ GL_FALSE );
+
+ /* No wide points.
+ */
+ ctx->Const.MinPointSize = 1.0;
+ ctx->Const.MinPointSizeAA = 1.0;
+ ctx->Const.MaxPointSize = 1.0;
+ ctx->Const.MaxPointSizeAA = 1.0;
+
+ /* No wide lines.
+ */
+ 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;
+
+#if ENABLE_PERF_BOXES
+ rmesa->boxes = (getenv( "LIBGL_PERFORMANCE_BOXES" ) != NULL);
+#endif
+
+ /* 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, r128_pipeline ); */
+
+ /* Configure swrast to match hardware characteristics:
+ */
+ _swrast_allow_pixel_fog( ctx, GL_FALSE );
+ _swrast_allow_vertex_fog( ctx, GL_TRUE );
+
+ driInitExtensions( ctx, card_extensions, GL_TRUE );
+ if (sPriv->drmMinor >= 4)
+ _mesa_enable_extension( ctx, "GL_MESA_ycbcr_texture" );
+
+ r128InitVB( ctx );
+ r128InitTriFuncs( ctx );
+ r128DDInitDriverFuncs( ctx );
+ r128DDInitIoctlFuncs( ctx );
+ r128DDInitStateFuncs( ctx );
+ r128DDInitSpanFuncs( ctx );
+ r128DDInitTextureFuncs( ctx );
+ r128DDInitState( rmesa );
+
+ rmesa->do_irqs = (rmesa->r128Screen->irq && !getenv("R128_NO_IRQS"));
+
+ rmesa->vblank_flags = (rmesa->do_irqs)
+ ? driGetDefaultVBlankFlags() : VBLANK_FLAG_NO_IRQ;
+
+ driContextPriv->driverPrivate = (void *)rmesa;
+
+#if DO_DEBUG
+ R128_DEBUG = driParseDebugString( getenv( "R128_DEBUG" ),
+ debug_control );
+#endif
+
+ return GL_TRUE;
+}
+
+/* Destroy the device specific context.
+ */
+void r128DestroyContext( __DRIcontextPrivate *driContextPriv )
+{
+ r128ContextPtr rmesa = (r128ContextPtr) driContextPriv->driverPrivate;
+
+ assert(rmesa); /* should never be null */
+ if ( rmesa ) {
+ GLboolean release_texture_heaps;
+
+
+ release_texture_heaps = (rmesa->glCtx->Shared->RefCount == 1);
+
+ _swsetup_DestroyContext( rmesa->glCtx );
+ _tnl_DestroyContext( rmesa->glCtx );
+ _ac_DestroyContext( rmesa->glCtx );
+ _swrast_DestroyContext( rmesa->glCtx );
+
+ r128FreeVB( rmesa->glCtx );
+
+ /* free the Mesa context */
+ rmesa->glCtx->DriverCtx = NULL;
+ _mesa_destroy_context(rmesa->glCtx);
+
+ if ( release_texture_heaps ) {
+ /* This share group is about to go away, free our private
+ * texture object data.
+ */
+ int i;
+
+ assert( is_empty_list( & rmesa->swapped ) );
+
+ for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
+ driDestroyTextureHeap( rmesa->texture_heaps[ i ] );
+ rmesa->texture_heaps[ i ] = NULL;
+ }
+ }
+
+ FREE( rmesa );
+ }
+
+#if 0
+ /* Use this to force shared object profiling. */
+ glx_fini_prof();
+#endif
+}
+
+
+/* Force the context `c' to be the current context and associate with it
+ * buffer `b'.
+ */
+GLboolean
+r128MakeCurrent( __DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv )
+{
+ if ( driContextPriv ) {
+ GET_CURRENT_CONTEXT(ctx);
+ r128ContextPtr oldR128Ctx = ctx ? R128_CONTEXT(ctx) : NULL;
+ r128ContextPtr newR128Ctx = (r128ContextPtr) driContextPriv->driverPrivate;
+
+ if ( newR128Ctx != oldR128Ctx ) {
+ newR128Ctx->new_state |= R128_NEW_CONTEXT;
+ newR128Ctx->dirty = R128_UPLOAD_ALL;
+ }
+
+ newR128Ctx->driDrawable = driDrawPriv;
+
+ _mesa_make_current2( newR128Ctx->glCtx,
+ (GLframebuffer *) driDrawPriv->driverPrivate,
+ (GLframebuffer *) driReadPriv->driverPrivate );
+
+
+ newR128Ctx->new_state |= R128_NEW_WINDOW | R128_NEW_CLIP;
+
+ if ( !newR128Ctx->glCtx->Viewport.Width ) {
+ _mesa_set_viewport(newR128Ctx->glCtx, 0, 0,
+ driDrawPriv->w, driDrawPriv->h);
+ }
+ } else {
+ _mesa_make_current( 0, 0 );
+ }
+
+ return GL_TRUE;
+}
+
+
+/* Force the context `c' to be unbound from its buffer.
+ */
+GLboolean
+r128UnbindContext( __DRIcontextPrivate *driContextPriv )
+{
+ return GL_TRUE;
+}
diff --git a/src/mesa/drivers/dri/r128/r128_context.h b/src/mesa/drivers/dri/r128/r128_context.h
new file mode 100644
index 0000000000..9c93012eb0
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_context.h
@@ -0,0 +1,270 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_context.h,v 1.12 2002/12/16 16:18:52 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __R128_CONTEXT_H__
+#define __R128_CONTEXT_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "dri_util.h"
+
+#include "xf86drm.h"
+#include "r128_common.h"
+
+#include "mtypes.h"
+
+#include "r128_reg.h"
+
+#include "texmem.h"
+
+struct r128_context;
+typedef struct r128_context r128ContextRec;
+typedef struct r128_context *r128ContextPtr;
+
+#include "r128_lock.h"
+#include "r128_texobj.h"
+#include "r128_screen.h"
+
+/* Flags for what context state needs to be updated:
+ */
+#define R128_NEW_ALPHA 0x0001
+#define R128_NEW_DEPTH 0x0002
+#define R128_NEW_FOG 0x0004
+#define R128_NEW_CLIP 0x0008
+#define R128_NEW_CULL 0x0010
+#define R128_NEW_MASKS 0x0020
+#define R128_NEW_RENDER_NOT 0x0040
+#define R128_NEW_WINDOW 0x0080
+#define R128_NEW_CONTEXT 0x0100
+#define R128_NEW_ALL 0x01ff
+
+/* Flags for software fallback cases:
+ */
+#define R128_FALLBACK_TEXTURE 0x0001
+#define R128_FALLBACK_DRAW_BUFFER 0x0002
+#define R128_FALLBACK_READ_BUFFER 0x0004
+#define R128_FALLBACK_STENCIL 0x0008
+#define R128_FALLBACK_RENDER_MODE 0x0010
+#define R128_FALLBACK_MULTIDRAW 0x0020
+#define R128_FALLBACK_LOGICOP 0x0040
+#define R128_FALLBACK_SEP_SPECULAR 0x0080
+#define R128_FALLBACK_BLEND_EQ 0x0100
+#define R128_FALLBACK_BLEND_FUNC 0x0200
+
+
+/* Use the templated vertex format:
+ */
+#define TAG(x) r128##x
+#include "tnl_dd/t_dd_vertex.h"
+#undef TAG
+
+/* Reasons why the GL_BLEND fallback mightn't work:
+ */
+#define R128_BLEND_ENV_COLOR 0x1
+#define R128_BLEND_MULTITEX 0x2
+
+/* Subpixel offsets for window coordinates (triangles):
+ */
+#define SUBPIXEL_X (0.0F)
+#define SUBPIXEL_Y (0.125F)
+
+
+typedef void (*r128_tri_func)( r128ContextPtr,
+ r128Vertex *,
+ r128Vertex *,
+ r128Vertex * );
+
+typedef void (*r128_line_func)( r128ContextPtr,
+ r128Vertex *,
+ r128Vertex * );
+
+typedef void (*r128_point_func)( r128ContextPtr,
+ r128Vertex * );
+
+
+struct r128_context {
+ GLcontext *glCtx; /* Mesa context */
+
+ /* Driver and hardware state management
+ */
+ GLuint new_state;
+ GLuint dirty; /* Hardware state to be updated */
+ r128_context_regs_t setup;
+
+ /* Temporaries for translating away float colors:
+ */
+ struct gl_client_array UbyteColor;
+ struct gl_client_array UbyteSecondaryColor;
+
+ GLuint NewGLState;
+ GLuint Fallback;
+ GLuint SetupIndex;
+ GLuint SetupNewInputs;
+ GLuint RenderIndex;
+ GLfloat hw_viewport[16];
+ GLfloat depth_scale;
+ GLuint vertex_size;
+ GLuint vertex_stride_shift;
+ GLuint vertex_format;
+ GLuint num_verts;
+ GLubyte *verts;
+
+ CARD32 ClearColor; /* Color used to clear color buffer */
+ CARD32 ClearDepth; /* Value used to clear depth buffer */
+ CARD32 ClearStencil; /* Value used to clear stencil */
+
+ /* Map GL texture units onto hardware
+ */
+ GLint multitex;
+ GLint tmu_source[2];
+ GLuint tex_combine[2];
+ GLuint blend_flags;
+ GLuint env_color;
+
+ /* Texture object bookkeeping
+ */
+ unsigned nr_heaps;
+ driTexHeap * texture_heaps[ R128_NR_TEX_HEAPS ];
+ driTextureObject swapped;
+
+ r128TexObjPtr CurrentTexObj[2];
+
+ /* Fallback rasterization functions
+ */
+ r128_point_func draw_point;
+ r128_line_func draw_line;
+ r128_tri_func draw_tri;
+
+ /* Vertex buffers
+ */
+ drmBufPtr vert_buf;
+
+ GLuint hw_primitive;
+ GLenum render_primitive;
+
+ /* Page flipping
+ */
+ GLuint doPageFlip;
+
+ /* Busy waiting
+ */
+ GLuint do_irqs;
+
+ /* Drawable, cliprect and scissor information
+ */
+ GLint drawOffset, drawPitch;
+ GLint readOffset, readPitch;
+
+ GLuint numClipRects; /* Cliprects for the draw buffer */
+ XF86DRIClipRectPtr pClipRects;
+
+ GLuint scissor;
+ XF86DRIClipRectRec ScissorRect; /* Current software scissor */
+
+ /* Mirrors of some DRI state
+ */
+ __DRIcontextPrivate *driContext; /* DRI context */
+ __DRIscreenPrivate *driScreen; /* DRI screen */
+ __DRIdrawablePrivate *driDrawable; /* DRI drawable bound to this ctx */
+
+ unsigned int lastStamp; /* mirror driDrawable->lastStamp */
+
+ drmContext hHWContext;
+ drmLock *driHwLock;
+ int driFd;
+
+ r128ScreenPtr r128Screen; /* Screen private DRI data */
+ R128SAREAPrivPtr sarea; /* Private SAREA data */
+
+ /* Performance counters
+ */
+ GLuint boxes; /* Draw performance boxes */
+ GLuint hardwareWentIdle;
+ GLuint c_clears;
+ GLuint c_drawWaits;
+ GLuint c_textureSwaps;
+ GLuint c_textureBytes;
+ GLuint c_vertexBuffers;
+
+ /* VBI
+ */
+ GLuint vbl_seq;
+ GLuint vblank_flags;
+};
+
+#define R128_CONTEXT(ctx) ((r128ContextPtr)(ctx->DriverCtx))
+
+#define R128_IS_PLAIN( rmesa ) \
+ (rmesa->r128Screen->chipset == R128_CARD_TYPE_R128)
+#define R128_IS_PRO( rmesa ) \
+ (rmesa->r128Screen->chipset == R128_CARD_TYPE_R128_PRO)
+#define R128_IS_MOBILITY( rmesa ) \
+ (rmesa->r128Screen->chipset == R128_CARD_TYPE_R128_MOBILITY)
+
+
+extern GLboolean r128CreateContext( const __GLcontextModes *glVisual,
+ __DRIcontextPrivate *driContextPriv,
+ void *sharedContextPrivate );
+
+extern void r128DestroyContext( __DRIcontextPrivate * );
+
+extern GLboolean r128MakeCurrent( __DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv );
+
+extern GLboolean r128UnbindContext( __DRIcontextPrivate *driContextPriv );
+
+/* ================================================================
+ * Debugging:
+ */
+#define DO_DEBUG 0
+#define ENABLE_PERF_BOXES 0
+
+#if DO_DEBUG
+extern int R128_DEBUG;
+#else
+#define R128_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
+#endif /* __R128_CONTEXT_H__ */
diff --git a/src/mesa/drivers/dri/r128/r128_dd.c b/src/mesa/drivers/dri/r128/r128_dd.c
new file mode 100644
index 0000000000..b64c26b4bd
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_dd.c
@@ -0,0 +1,148 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_dd.c,v 1.15 2002/10/30 12:51:38 alanh Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#include "r128_context.h"
+#include "r128_ioctl.h"
+#include "r128_state.h"
+#include "r128_vb.h"
+#include "r128_dd.h"
+
+#include "context.h"
+
+#include "utils.h"
+
+#define DRIVER_DATE "20030328"
+
+
+/* Return the width and height of the current color buffer.
+ */
+static void r128DDGetBufferSize( GLframebuffer *buffer,
+ GLuint *width, GLuint *height )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ LOCK_HARDWARE( rmesa );
+ *width = rmesa->driDrawable->w;
+ *height = rmesa->driDrawable->h;
+ UNLOCK_HARDWARE( rmesa );
+}
+
+/* Return various strings for glGetString().
+ */
+static const GLubyte *r128DDGetString( GLcontext *ctx, GLenum name )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ static char buffer[128];
+ unsigned offset;
+ const char * card_name = "Rage 128";
+ GLuint agp_mode = rmesa->r128Screen->IsPCI ? 0 :
+ rmesa->r128Screen->AGPMode;
+
+ switch ( name ) {
+ case GL_VENDOR:
+ return (GLubyte *)"VA Linux Systems, Inc.";
+
+ case GL_RENDERER:
+ /* Select the spefic chipset.
+ */
+ if ( R128_IS_PRO( rmesa ) ) {
+ card_name = "Rage 128 Pro";
+ }
+ else if ( R128_IS_MOBILITY( rmesa ) ) {
+ card_name = "Rage 128 Mobility";
+ }
+
+ offset = driGetRendererString( buffer, card_name, DRIVER_DATE,
+ agp_mode );
+
+ return (GLubyte *)buffer;
+
+ default:
+ return NULL;
+ }
+}
+
+/* Send all commands to the hardware. If vertex buffers or indirect
+ * buffers are in use, then we need to make sure they are sent to the
+ * hardware. All commands that are normally sent to the ring are
+ * already considered `flushed'.
+ */
+static void r128DDFlush( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+
+#if ENABLE_PERF_BOXES
+ if ( rmesa->boxes ) {
+ LOCK_HARDWARE( rmesa );
+ r128PerformanceBoxesLocked( rmesa );
+ UNLOCK_HARDWARE( rmesa );
+ }
+
+ /* Log the performance counters if necessary */
+ r128PerformanceCounters( rmesa );
+#endif
+}
+
+/* Make sure all commands have been sent to the hardware and have
+ * completed processing.
+ */
+static void r128DDFinish( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+#if ENABLE_PERF_BOXES
+ /* Bump the performance counter */
+ rmesa->c_drawWaits++;
+#endif
+
+ r128DDFlush( ctx );
+ r128WaitForIdle( rmesa );
+}
+
+
+/* Initialize the driver's misc functions.
+ */
+void r128DDInitDriverFuncs( GLcontext *ctx )
+{
+ ctx->Driver.GetBufferSize = r128DDGetBufferSize;
+ ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
+ ctx->Driver.GetString = r128DDGetString;
+ ctx->Driver.Finish = r128DDFinish;
+ ctx->Driver.Flush = r128DDFlush;
+ ctx->Driver.Error = NULL;
+}
diff --git a/src/mesa/drivers/dri/r128/r128_dd.h b/src/mesa/drivers/dri/r128/r128_dd.h
new file mode 100644
index 0000000000..b8fc7ad9bf
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_dd.h
@@ -0,0 +1,44 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_dd.h,v 1.3 2001/01/08 01:07:20 martin Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef __R128_DD_H__
+#define __R128_DD_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void r128DDInitDriverFuncs( GLcontext *ctx );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/r128/r128_ioctl.c b/src/mesa/drivers/dri/r128/r128_ioctl.c
new file mode 100644
index 0000000000..c5843473e1
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_ioctl.c
@@ -0,0 +1,812 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_ioctl.c,v 1.10 2002/12/16 16:18:53 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+#include <errno.h>
+
+#include "r128_context.h"
+#include "r128_state.h"
+#include "r128_ioctl.h"
+#include "r128_macros.h"
+
+#include "imports.h"
+#include "macros.h"
+
+#include "swrast/swrast.h"
+
+#include "vblank.h"
+
+#define R128_TIMEOUT 2048
+#define R128_IDLE_RETRY 32
+
+
+/* =============================================================
+ * Hardware vertex buffer handling
+ */
+
+/* Get a new VB from the pool of vertex buffers in AGP space.
+ */
+drmBufPtr r128GetBufferLocked( r128ContextPtr rmesa )
+{
+ int fd = rmesa->r128Screen->driScreen->fd;
+ int index = 0;
+ int size = 0;
+ drmDMAReq dma;
+ drmBufPtr buf = NULL;
+ int to = 0;
+ int ret;
+
+ dma.context = rmesa->hHWContext;
+ dma.send_count = 0;
+ dma.send_list = NULL;
+ dma.send_sizes = NULL;
+ dma.flags = 0;
+ dma.request_count = 1;
+ dma.request_size = R128_BUFFER_SIZE;
+ dma.request_list = &index;
+ dma.request_sizes = &size;
+ dma.granted_count = 0;
+
+ while ( !buf && ( to++ < R128_TIMEOUT ) ) {
+ ret = drmDMA( fd, &dma );
+
+ if ( ret == 0 ) {
+ buf = &rmesa->r128Screen->buffers->list[index];
+ buf->used = 0;
+#if ENABLE_PERF_BOXES
+ /* Bump the performance counter */
+ rmesa->c_vertexBuffers++;
+#endif
+ return buf;
+ }
+ }
+
+ if ( !buf ) {
+ drmCommandNone( fd, DRM_R128_CCE_RESET);
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "Error: Could not get new VB... exiting\n" );
+ exit( -1 );
+ }
+
+ return buf;
+}
+
+void r128FlushVerticesLocked( r128ContextPtr rmesa )
+{
+ XF86DRIClipRectPtr pbox = rmesa->pClipRects;
+ int nbox = rmesa->numClipRects;
+ drmBufPtr buffer = rmesa->vert_buf;
+ int count = rmesa->num_verts;
+ int prim = rmesa->hw_primitive;
+ int fd = rmesa->driScreen->fd;
+ drmR128Vertex vertex;
+ int i;
+
+ rmesa->num_verts = 0;
+ rmesa->vert_buf = NULL;
+
+ if ( !buffer )
+ return;
+
+ if ( rmesa->dirty & ~R128_UPLOAD_CLIPRECTS )
+ r128EmitHwStateLocked( rmesa );
+
+ if ( !nbox )
+ count = 0;
+
+ if ( nbox >= R128_NR_SAREA_CLIPRECTS )
+ rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
+
+ if ( !count || !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
+ {
+ if ( nbox < 3 ) {
+ rmesa->sarea->nbox = 0;
+ } else {
+ rmesa->sarea->nbox = nbox;
+ }
+
+ vertex.prim = prim;
+ vertex.idx = buffer->idx;
+ vertex.count = count;
+ vertex.discard = 1;
+ drmCommandWrite( fd, DRM_R128_VERTEX, &vertex, sizeof(drmR128Vertex) );
+ }
+ else
+ {
+ for ( i = 0 ; i < nbox ; ) {
+ int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+ int discard = 0;
+
+ rmesa->sarea->nbox = nr - i;
+ for ( ; i < nr ; i++ ) {
+ *b++ = pbox[i];
+ }
+
+ /* Finished with the buffer?
+ */
+ if ( nr == nbox ) {
+ discard = 1;
+ }
+
+ rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
+
+ vertex.prim = prim;
+ vertex.idx = buffer->idx;
+ vertex.count = count;
+ vertex.discard = discard;
+ drmCommandWrite( fd, DRM_R128_VERTEX, &vertex, sizeof(drmR128Vertex) );
+ }
+ }
+
+ rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
+}
+
+
+
+
+
+/* ================================================================
+ * Texture uploads
+ */
+
+void r128FireBlitLocked( r128ContextPtr rmesa, drmBufPtr buffer,
+ GLint offset, GLint pitch, GLint format,
+ GLint x, GLint y, GLint width, GLint height )
+{
+ drmR128Blit blit;
+ GLint ret;
+
+ blit.idx = buffer->idx;
+ blit.offset = offset;
+ blit.pitch = pitch;
+ blit.format = format;
+ blit.x = x;
+ blit.y = y;
+ blit.width = width;
+ blit.height = height;
+
+ ret = drmCommandWrite( rmesa->driFd, DRM_R128_BLIT,
+ &blit, sizeof(drmR128Blit) );
+
+ if ( ret ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "DRM_R128_BLIT: return = %d\n", ret );
+ exit( 1 );
+ }
+}
+
+
+/* ================================================================
+ * SwapBuffers with client-side throttling
+ */
+
+static void delay( void ) {
+/* Prevent an optimizing compiler from removing a spin loop */
+}
+
+#define R128_MAX_OUTSTANDING 2
+
+/* Throttle the frame rate -- only allow one pending swap buffers
+ * request at a time.
+ * GH: We probably don't want a timeout here, as we can wait as
+ * long as we want for a frame to complete. If it never does, then
+ * the card has locked.
+ */
+static int r128WaitForFrameCompletion( r128ContextPtr rmesa )
+{
+ unsigned char *R128MMIO = rmesa->r128Screen->mmio.map;
+ CARD32 frame;
+ int i;
+ int wait = 0;
+
+ while ( 1 ) {
+ frame = INREG( R128_LAST_FRAME_REG );
+ if ( rmesa->sarea->last_frame - frame <= R128_MAX_OUTSTANDING ) {
+ break;
+ }
+
+ /* Spin in place a bit so we aren't hammering the register */
+ wait++;
+ for ( i = 0 ; i < 1024 ; i++ ) {
+ delay();
+ }
+ }
+
+ return wait;
+}
+
+/* Copy the back color buffer to the front color buffer.
+ */
+void r128CopyBuffer( const __DRIdrawablePrivate *dPriv )
+{
+ r128ContextPtr rmesa;
+ GLint nbox, i, ret;
+ GLboolean missed_target;
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "\n********************************\n" );
+ fprintf( stderr, "\n%s( %p )\n\n",
+ __FUNCTION__, rmesa->glCtx );
+ fflush( stderr );
+ }
+
+ FLUSH_BATCH( rmesa );
+
+ LOCK_HARDWARE( rmesa );
+
+ /* Throttle the frame rate -- only allow one pending swap buffers
+ * request at a time.
+ */
+ if ( !r128WaitForFrameCompletion( rmesa ) ) {
+ rmesa->hardwareWentIdle = 1;
+ } else {
+ rmesa->hardwareWentIdle = 0;
+ }
+
+ UNLOCK_HARDWARE( rmesa );
+ driWaitForVBlank( dPriv, &rmesa->vbl_seq, rmesa->vblank_flags, &missed_target );
+ LOCK_HARDWARE( rmesa );
+
+ nbox = dPriv->numClipRects; /* must be in locked region */
+
+ for ( i = 0 ; i < nbox ; ) {
+ GLint nr = MIN2( i + R128_NR_SAREA_CLIPRECTS , nbox );
+ XF86DRIClipRectPtr box = dPriv->pClipRects;
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+ GLint n = 0;
+
+ for ( ; i < nr ; i++ ) {
+ *b++ = *(XF86DRIClipRectRec *)&box[i];
+ n++;
+ }
+ rmesa->sarea->nbox = n;
+
+ ret = drmCommandNone( rmesa->driFd, DRM_R128_SWAP );
+
+ if ( ret ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "DRM_R128_SWAP: return = %d\n", ret );
+ exit( 1 );
+ }
+ }
+
+ if ( R128_DEBUG & DEBUG_ALWAYS_SYNC ) {
+ i = 0;
+ do {
+ ret = drmCommandNone(rmesa->driFd, DRM_R128_CCE_IDLE);
+ } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY );
+ }
+
+ UNLOCK_HARDWARE( rmesa );
+
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ rmesa->dirty |= (R128_UPLOAD_CONTEXT |
+ R128_UPLOAD_MASKS |
+ R128_UPLOAD_CLIPRECTS);
+
+#if ENABLE_PERF_BOXES
+ /* Log the performance counters if necessary */
+ r128PerformanceCounters( rmesa );
+#endif
+}
+
+void r128PageFlip( const __DRIdrawablePrivate *dPriv )
+{
+ r128ContextPtr rmesa;
+ GLint ret;
+ GLboolean missed_target;
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "\n%s( %p ): page=%d\n\n",
+ __FUNCTION__, rmesa->glCtx, rmesa->sarea->pfCurrentPage );
+ }
+
+ FLUSH_BATCH( rmesa );
+
+ LOCK_HARDWARE( rmesa );
+
+ /* Throttle the frame rate -- only allow one pending swap buffers
+ * request at a time.
+ */
+ if ( !r128WaitForFrameCompletion( rmesa ) ) {
+ rmesa->hardwareWentIdle = 1;
+ } else {
+ rmesa->hardwareWentIdle = 0;
+ }
+
+ UNLOCK_HARDWARE( rmesa );
+ driWaitForVBlank( dPriv, &rmesa->vbl_seq, rmesa->vblank_flags, &missed_target );
+ LOCK_HARDWARE( rmesa );
+
+ /* The kernel will have been initialized to perform page flipping
+ * on a swapbuffers ioctl.
+ */
+ ret = drmCommandNone( rmesa->driFd, DRM_R128_FLIP );
+
+ UNLOCK_HARDWARE( rmesa );
+
+ if ( ret ) {
+ fprintf( stderr, "DRM_R128_FLIP: return = %d\n", ret );
+ exit( 1 );
+ }
+
+ if ( rmesa->sarea->pfCurrentPage == 1 ) {
+ rmesa->drawOffset = rmesa->r128Screen->frontOffset;
+ rmesa->drawPitch = rmesa->r128Screen->frontPitch;
+ } else {
+ rmesa->drawOffset = rmesa->r128Screen->backOffset;
+ rmesa->drawPitch = rmesa->r128Screen->backPitch;
+ }
+
+ rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) |
+ (rmesa->drawOffset >> 5));
+ rmesa->new_state |= R128_NEW_WINDOW;
+
+ /* FIXME: Do we need this anymore? */
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ rmesa->dirty |= (R128_UPLOAD_CONTEXT |
+ R128_UPLOAD_MASKS |
+ R128_UPLOAD_CLIPRECTS);
+
+#if ENABLE_PERF_BOXES
+ /* Log the performance counters if necessary */
+ r128PerformanceCounters( rmesa );
+#endif
+}
+
+
+/* ================================================================
+ * Buffer clear
+ */
+
+static void r128DDClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
+ GLint cx, GLint cy, GLint cw, GLint ch )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ __DRIdrawablePrivate *dPriv = rmesa->driDrawable;
+ drmR128Clear clear;
+ GLuint flags = 0;
+ GLint i;
+ GLint ret;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s:\n", __FUNCTION__ );
+ }
+
+ FLUSH_BATCH( rmesa );
+
+ /* The only state change we care about here is the RGBA colormask
+ * We'll just update that state, if needed. If we do more then
+ * there's some strange side-effects that the conformance tests find.
+ */
+ if ( rmesa->new_state & R128_NEW_MASKS) {
+ const GLuint save_state = rmesa->new_state;
+ rmesa->new_state = R128_NEW_MASKS;
+ r128DDUpdateHWState( ctx );
+ rmesa->new_state = save_state & ~R128_NEW_MASKS;
+ }
+
+ if ( mask & DD_FRONT_LEFT_BIT ) {
+ flags |= DRM_R128_FRONT_BUFFER;
+ mask &= ~DD_FRONT_LEFT_BIT;
+ }
+
+ if ( mask & DD_BACK_LEFT_BIT ) {
+ flags |= DRM_R128_BACK_BUFFER;
+ mask &= ~DD_BACK_LEFT_BIT;
+ }
+
+ if ( ( mask & DD_DEPTH_BIT ) && ctx->Depth.Mask ) {
+ flags |= DRM_R128_DEPTH_BUFFER;
+ mask &= ~DD_DEPTH_BIT;
+ }
+#if 0
+ /* FIXME: Add stencil support */
+ if ( mask & DD_STENCIL_BIT ) {
+ flags |= DRM_R128_DEPTH_BUFFER;
+ mask &= ~DD_STENCIL_BIT;
+ }
+#endif
+
+ if ( flags ) {
+
+ /* Flip top to bottom */
+ cx += dPriv->x;
+ cy = dPriv->y + dPriv->h - cy - ch;
+
+ LOCK_HARDWARE( rmesa );
+
+ /* FIXME: Do we actually need this?
+ */
+ if ( rmesa->dirty & ~R128_UPLOAD_CLIPRECTS ) {
+ r128EmitHwStateLocked( rmesa );
+ }
+
+ for ( i = 0 ; i < rmesa->numClipRects ; ) {
+ GLint nr = MIN2( i + R128_NR_SAREA_CLIPRECTS , rmesa->numClipRects );
+ XF86DRIClipRectPtr box = rmesa->pClipRects;
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+ GLint n = 0;
+
+ if ( !all ) {
+ for ( ; i < nr ; i++ ) {
+ GLint x = box[i].x1;
+ GLint y = box[i].y1;
+ GLint w = box[i].x2 - x;
+ GLint h = box[i].y2 - y;
+
+ if ( x < cx ) w -= cx - x, x = cx;
+ if ( y < cy ) h -= cy - y, y = cy;
+ if ( x + w > cx + cw ) w = cx + cw - x;
+ if ( y + h > cy + ch ) h = cy + ch - y;
+ if ( w <= 0 ) continue;
+ if ( h <= 0 ) continue;
+
+ b->x1 = x;
+ b->y1 = y;
+ b->x2 = x + w;
+ b->y2 = y + h;
+ b++;
+ n++;
+ }
+ } else {
+ for ( ; i < nr ; i++ ) {
+ *b++ = *(XF86DRIClipRectPtr)&box[i];
+ n++;
+ }
+ }
+
+ rmesa->sarea->nbox = n;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_IOCTL ) {
+ fprintf( stderr,
+ "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
+ flags,
+ (GLuint)rmesa->ClearColor,
+ (GLuint)rmesa->ClearDepth,
+ rmesa->sarea->nbox );
+ }
+
+ clear.flags = flags;
+ clear.clear_color = rmesa->ClearColor;
+ clear.clear_depth = rmesa->ClearDepth;
+ clear.color_mask = rmesa->setup.plane_3d_mask_c;
+ clear.depth_mask = ~0;
+
+ ret = drmCommandWrite( rmesa->driFd, DRM_R128_CLEAR,
+ &clear, sizeof(drmR128Clear) );
+
+ if ( ret ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "DRM_R128_CLEAR: return = %d\n", ret );
+ exit( 1 );
+ }
+ }
+
+ UNLOCK_HARDWARE( rmesa );
+
+ rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
+ }
+
+ if ( mask )
+ _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
+}
+
+
+/* ================================================================
+ * Depth spans, pixels
+ */
+
+void r128WriteDepthSpanLocked( r128ContextPtr rmesa,
+ GLuint n, GLint x, GLint y,
+ const GLdepth depth[],
+ const GLubyte mask[] )
+{
+ XF86DRIClipRectPtr pbox = rmesa->pClipRects;
+ drmR128Depth d;
+ int nbox = rmesa->numClipRects;
+ int fd = rmesa->driScreen->fd;
+ int i;
+
+ if ( !nbox || !n ) {
+ return;
+ }
+ if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
+ rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
+ }
+
+ if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
+ {
+ if ( nbox < 3 ) {
+ rmesa->sarea->nbox = 0;
+ } else {
+ rmesa->sarea->nbox = nbox;
+ }
+
+ d.func = DRM_R128_WRITE_SPAN;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = (unsigned int *)depth;
+ d.mask = (unsigned char *)mask;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+
+ }
+ else
+ {
+ for (i = 0 ; i < nbox ; ) {
+ int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+
+ rmesa->sarea->nbox = nr - i;
+ for ( ; i < nr ; i++) {
+ *b++ = pbox[i];
+ }
+
+ rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
+
+ d.func = DRM_R128_WRITE_SPAN;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = (unsigned int *)depth;
+ d.mask = (unsigned char *)mask;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+ }
+ }
+
+ rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
+}
+
+void r128WriteDepthPixelsLocked( r128ContextPtr rmesa, GLuint n,
+ const GLint x[], const GLint y[],
+ const GLdepth depth[],
+ const GLubyte mask[] )
+{
+ XF86DRIClipRectPtr pbox = rmesa->pClipRects;
+ drmR128Depth d;
+ int nbox = rmesa->numClipRects;
+ int fd = rmesa->driScreen->fd;
+ int i;
+
+ if ( !nbox || !n ) {
+ return;
+ }
+ if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
+ rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
+ }
+
+ if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
+ {
+ if ( nbox < 3 ) {
+ rmesa->sarea->nbox = 0;
+ } else {
+ rmesa->sarea->nbox = nbox;
+ }
+
+ d.func = DRM_R128_WRITE_PIXELS;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = (unsigned int *)depth;
+ d.mask = (unsigned char *)mask;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+ }
+ else
+ {
+ for (i = 0 ; i < nbox ; ) {
+ int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+
+ rmesa->sarea->nbox = nr - i;
+ for ( ; i < nr ; i++) {
+ *b++ = pbox[i];
+ }
+
+ rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
+
+ d.func = DRM_R128_WRITE_PIXELS;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = (unsigned int *)depth;
+ d.mask = (unsigned char *)mask;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+ }
+ }
+
+ rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
+}
+
+void r128ReadDepthSpanLocked( r128ContextPtr rmesa,
+ GLuint n, GLint x, GLint y )
+{
+ XF86DRIClipRectPtr pbox = rmesa->pClipRects;
+ drmR128Depth d;
+ int nbox = rmesa->numClipRects;
+ int fd = rmesa->driScreen->fd;
+ int i;
+
+ if ( !nbox || !n ) {
+ return;
+ }
+ if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
+ rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
+ }
+
+ if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
+ {
+ if ( nbox < 3 ) {
+ rmesa->sarea->nbox = 0;
+ } else {
+ rmesa->sarea->nbox = nbox;
+ }
+
+ d.func = DRM_R128_READ_SPAN;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = NULL;
+ d.mask = NULL;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+ }
+ else
+ {
+ for (i = 0 ; i < nbox ; ) {
+ int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+
+ rmesa->sarea->nbox = nr - i;
+ for ( ; i < nr ; i++) {
+ *b++ = pbox[i];
+ }
+
+ rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
+
+ d.func = DRM_R128_READ_SPAN;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = NULL;
+ d.mask = NULL;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+ }
+ }
+
+ rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
+}
+
+void r128ReadDepthPixelsLocked( r128ContextPtr rmesa, GLuint n,
+ const GLint x[], const GLint y[] )
+{
+ XF86DRIClipRectPtr pbox = rmesa->pClipRects;
+ drmR128Depth d;
+ int nbox = rmesa->numClipRects;
+ int fd = rmesa->driScreen->fd;
+ int i;
+
+ if ( !nbox || !n ) {
+ return;
+ }
+ if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
+ rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
+ }
+
+ if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
+ {
+ if ( nbox < 3 ) {
+ rmesa->sarea->nbox = 0;
+ } else {
+ rmesa->sarea->nbox = nbox;
+ }
+
+ d.func = DRM_R128_READ_PIXELS;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = NULL;
+ d.mask = NULL;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+ }
+ else
+ {
+ for (i = 0 ; i < nbox ; ) {
+ int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+
+ rmesa->sarea->nbox = nr - i;
+ for ( ; i < nr ; i++) {
+ *b++ = pbox[i];
+ }
+
+ rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
+
+ d.func = DRM_R128_READ_PIXELS;
+ d.n = n;
+ d.x = (int*)&x;
+ d.y = (int*)&y;
+ d.buffer = NULL;
+ d.mask = NULL;
+
+ drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth));
+ }
+ }
+
+ rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
+}
+
+
+void r128WaitForIdleLocked( r128ContextPtr rmesa )
+{
+ int fd = rmesa->r128Screen->driScreen->fd;
+ int to = 0;
+ int ret, i;
+
+ do {
+ i = 0;
+ do {
+ ret = drmCommandNone( fd, DRM_R128_CCE_IDLE);
+ } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY );
+ } while ( ( ret == -EBUSY ) && ( to++ < R128_TIMEOUT ) );
+
+ if ( ret < 0 ) {
+ drmCommandNone( fd, DRM_R128_CCE_RESET);
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "Error: Rage 128 timed out... exiting\n" );
+ exit( -1 );
+ }
+}
+
+void r128DDInitIoctlFuncs( GLcontext *ctx )
+{
+ ctx->Driver.Clear = r128DDClear;
+}
diff --git a/src/mesa/drivers/dri/r128/r128_ioctl.h b/src/mesa/drivers/dri/r128/r128_ioctl.h
new file mode 100644
index 0000000000..b0f6b363a5
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_ioctl.h
@@ -0,0 +1,146 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_ioctl.h,v 1.6 2002/12/16 16:18:53 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __R128_IOCTL_H__
+#define __R128_IOCTL_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "r128_dri.h"
+#include "r128_reg.h"
+#include "r128_lock.h"
+
+#include "xf86drm.h"
+#include "r128_common.h"
+
+#define R128_BUFFER_MAX_DWORDS (R128_BUFFER_SIZE / sizeof(CARD32))
+
+
+extern drmBufPtr r128GetBufferLocked( r128ContextPtr rmesa );
+extern void r128FlushVerticesLocked( r128ContextPtr rmesa );
+
+static __inline void *r128AllocDmaLow( r128ContextPtr rmesa, int bytes )
+{
+ CARD32 *head;
+
+ if ( !rmesa->vert_buf ) {
+ LOCK_HARDWARE( rmesa );
+ rmesa->vert_buf = r128GetBufferLocked( rmesa );
+ UNLOCK_HARDWARE( rmesa );
+ } else if ( rmesa->vert_buf->used + bytes > rmesa->vert_buf->total ) {
+ LOCK_HARDWARE( rmesa );
+ r128FlushVerticesLocked( rmesa );
+ rmesa->vert_buf = r128GetBufferLocked( rmesa );
+ UNLOCK_HARDWARE( rmesa );
+ }
+
+ head = (CARD32 *)((char *)rmesa->vert_buf->address + rmesa->vert_buf->used);
+ rmesa->vert_buf->used += bytes;
+ return head;
+}
+
+extern void r128FireBlitLocked( r128ContextPtr rmesa, drmBufPtr buffer,
+ GLint offset, GLint pitch, GLint format,
+ GLint x, GLint y, GLint width, GLint height );
+
+extern void r128WriteDepthSpanLocked( r128ContextPtr rmesa,
+ GLuint n, GLint x, GLint y,
+ const GLdepth depth[],
+ const GLubyte mask[] );
+extern void r128WriteDepthPixelsLocked( r128ContextPtr rmesa, GLuint n,
+ const GLint x[], const GLint y[],
+ const GLdepth depth[],
+ const GLubyte mask[] );
+extern void r128ReadDepthSpanLocked( r128ContextPtr rmesa,
+ GLuint n, GLint x, GLint y );
+extern void r128ReadDepthPixelsLocked( r128ContextPtr rmesa, GLuint n,
+ const GLint x[], const GLint y[] );
+
+extern void r128CopyBuffer( const __DRIdrawablePrivate *dPriv );
+extern void r128PageFlip( const __DRIdrawablePrivate *dPriv );
+void r128WaitForVBlank( r128ContextPtr rmesa );
+
+extern void r128WaitForIdleLocked( r128ContextPtr rmesa );
+
+
+extern void r128DDInitIoctlFuncs( GLcontext *ctx );
+
+
+/* ================================================================
+ * Helper macros:
+ */
+
+#define FLUSH_BATCH( rmesa ) \
+do { \
+ if ( R128_DEBUG & DEBUG_VERBOSE_IOCTL ) \
+ fprintf( stderr, "FLUSH_BATCH in %s\n", __FUNCTION__ ); \
+ if ( rmesa->vert_buf ) { \
+ r128FlushVertices( rmesa ); \
+ } \
+} while (0)
+
+/* 64-bit align the next element address, and then make room for the
+ * next indexed prim packet header.
+ */
+#define ALIGN_NEXT_ELT( rmesa ) \
+do { \
+ rmesa->next_elt = (GLushort *) \
+ (((GLuint)rmesa->next_elt + 7) & ~0x7); \
+ rmesa->next_elt = (GLushort *) \
+ ((GLubyte *)rmesa->next_elt + R128_INDEX_PRIM_OFFSET); \
+} while (0)
+
+#define r128FlushVertices( rmesa ) \
+do { \
+ LOCK_HARDWARE( rmesa ); \
+ r128FlushVerticesLocked( rmesa ); \
+ UNLOCK_HARDWARE( rmesa ); \
+} while (0)
+
+#define r128FlushElts( rmesa ) \
+do { \
+ LOCK_HARDWARE( rmesa ); \
+ r128FlushEltsLocked( rmesa ); \
+ UNLOCK_HARDWARE( rmesa ); \
+} while (0)
+
+#define r128WaitForIdle( rmesa ) \
+ do { \
+ LOCK_HARDWARE( rmesa ); \
+ r128WaitForIdleLocked( rmesa ); \
+ UNLOCK_HARDWARE( rmesa ); \
+ } while (0)
+
+#endif
+#endif /* __R128_IOCTL_H__ */
diff --git a/src/mesa/drivers/dri/r128/r128_lock.c b/src/mesa/drivers/dri/r128/r128_lock.c
new file mode 100644
index 0000000000..12eb0128b0
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_lock.c
@@ -0,0 +1,123 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_lock.c,v 1.5 2002/10/30 12:51:38 alanh Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include "r128_context.h"
+#include "r128_lock.h"
+#include "r128_tex.h"
+#include "r128_state.h"
+
+#if DEBUG_LOCKING
+char *prevLockFile = NULL;
+int prevLockLine = 0;
+#endif
+
+
+/* Turn on/off page flipping according to the flags in the sarea:
+ */
+static void
+r128UpdatePageFlipping( r128ContextPtr rmesa )
+{
+ int use_back;
+
+ rmesa->doPageFlip = rmesa->sarea->pfAllowPageFlip;
+
+ use_back = (rmesa->glCtx->Color._DrawDestMask == BACK_LEFT_BIT);
+ use_back ^= (rmesa->sarea->pfCurrentPage == 1);
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API )
+ fprintf(stderr, "%s allow %d current %d\n", __FUNCTION__,
+ rmesa->doPageFlip,
+ rmesa->sarea->pfCurrentPage );
+
+ if ( use_back ) {
+ rmesa->drawOffset = rmesa->r128Screen->backOffset;
+ rmesa->drawPitch = rmesa->r128Screen->backPitch;
+ } else {
+ rmesa->drawOffset = rmesa->r128Screen->frontOffset;
+ rmesa->drawPitch = rmesa->r128Screen->frontPitch;
+ }
+
+ rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) |
+ (rmesa->drawOffset >> 5));
+ rmesa->new_state |= R128_NEW_WINDOW;
+}
+
+/* Update the hardware state. This is called if another context has
+ * grabbed the hardware lock, which includes the X server. This
+ * function also updates the driver's window state after the X server
+ * moves, resizes or restacks a window -- the change will be reflected
+ * in the drawable position and clip rects. Since the X server grabs
+ * the hardware lock when it changes the window state, this routine will
+ * automatically be called after such a change.
+ */
+void r128GetLock( r128ContextPtr rmesa, GLuint flags )
+{
+ __DRIdrawablePrivate *dPriv = rmesa->driDrawable;
+ __DRIscreenPrivate *sPriv = rmesa->driScreen;
+ R128SAREAPrivPtr sarea = rmesa->sarea;
+ int i;
+
+ drmGetLock( rmesa->driFd, rmesa->hHWContext, flags );
+
+ /* The window might have moved, so we might need to get new clip
+ * rects.
+ *
+ * NOTE: This releases and regrabs the hw lock to allow the X server
+ * to respond to the DRI protocol request for new drawable info.
+ * Since the hardware state depends on having the latest drawable
+ * clip rects, all state checking must be done _after_ this call.
+ */
+ DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv );
+
+ if ( rmesa->lastStamp != dPriv->lastStamp ) {
+ r128UpdatePageFlipping( rmesa );
+ rmesa->lastStamp = dPriv->lastStamp;
+ rmesa->new_state |= R128_NEW_CLIP;
+ rmesa->SetupNewInputs = ~0;
+ }
+
+ rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_CLIPRECTS;
+
+ rmesa->numClipRects = dPriv->numClipRects;
+ rmesa->pClipRects = dPriv->pClipRects;
+
+ if ( sarea->ctxOwner != rmesa->hHWContext ) {
+ sarea->ctxOwner = rmesa->hHWContext;
+ rmesa->dirty = R128_UPLOAD_ALL;
+ }
+
+ for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
+ DRI_AGE_TEXTURES( rmesa->texture_heaps[i] );
+ }
+}
diff --git a/src/mesa/drivers/dri/r128/r128_lock.h b/src/mesa/drivers/dri/r128/r128_lock.h
new file mode 100644
index 0000000000..e734ba29de
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_lock.h
@@ -0,0 +1,111 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_lock.h,v 1.4 2001/01/08 01:07:21 martin Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __R128_LOCK_H__
+#define __R128_LOCK_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void r128GetLock( r128ContextPtr rmesa, GLuint flags );
+
+/* Turn DEBUG_LOCKING 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
+
+/*
+ * !!! 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 !!!
+ */
+
+/* Lock the hardware and validate our state.
+ */
+#define LOCK_HARDWARE( rmesa ) \
+ do { \
+ char __ret = 0; \
+ DEBUG_CHECK_LOCK(); \
+ DRM_CAS( rmesa->driHwLock, rmesa->hHWContext, \
+ (DRM_LOCK_HELD | rmesa->hHWContext), __ret ); \
+ if ( __ret ) \
+ r128GetLock( rmesa, 0 ); \
+ DEBUG_LOCK(); \
+ } while (0)
+
+/* Unlock the hardware.
+ */
+#define UNLOCK_HARDWARE( rmesa ) \
+ do { \
+ DRM_UNLOCK( rmesa->driFd, \
+ rmesa->driHwLock, \
+ rmesa->hHWContext ); \
+ DEBUG_RESET(); \
+ } while (0)
+
+#endif
+#endif /* __R128_LOCK_H__ */
diff --git a/src/mesa/drivers/dri/r128/r128_screen.c b/src/mesa/drivers/dri/r128/r128_screen.c
new file mode 100644
index 0000000000..8a8fc25217
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_screen.c
@@ -0,0 +1,357 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_screen.c,v 1.8 2002/12/16 16:18:53 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#include "r128_dri.h"
+
+#include "r128_context.h"
+#include "r128_ioctl.h"
+#include "r128_tris.h"
+#include "r128_vb.h"
+
+#include "context.h"
+#include "imports.h"
+
+#include "utils.h"
+#include "vblank.h"
+
+#ifndef _SOLO
+#include "glxextensions.h"
+#endif
+
+#if 1
+/* Including xf86PciInfo.h introduces a bunch of errors...
+ */
+#define PCI_CHIP_RAGE128LE 0x4C45
+#define PCI_CHIP_RAGE128LF 0x4C46
+#define PCI_CHIP_RAGE128PD 0x5044
+#define PCI_CHIP_RAGE128PF 0x5046
+#define PCI_CHIP_RAGE128PR 0x5052
+#define PCI_CHIP_RAGE128RE 0x5245
+#define PCI_CHIP_RAGE128RF 0x5246
+#define PCI_CHIP_RAGE128RK 0x524B
+#define PCI_CHIP_RAGE128RL 0x524C
+#endif
+
+
+/* Create the device specific screen private data struct.
+ */
+static r128ScreenPtr
+r128CreateScreen( __DRIscreenPrivate *sPriv )
+{
+ r128ScreenPtr r128Screen;
+ R128DRIPtr r128DRIPriv = (R128DRIPtr)sPriv->pDevPriv;
+
+ if ( ! driCheckDriDdxDrmVersions( sPriv, "Rage128", 4, 0, 4, 0, 2, 2 ) )
+ return NULL;
+
+ /* Allocate the private area */
+ r128Screen = (r128ScreenPtr) CALLOC( sizeof(*r128Screen) );
+ if ( !r128Screen ) return NULL;
+
+ /* This is first since which regions we map depends on whether or
+ * not we are using a PCI card.
+ */
+ r128Screen->IsPCI = r128DRIPriv->IsPCI;
+ r128Screen->sarea_priv_offset = r128DRIPriv->sarea_priv_offset;
+
+ if (sPriv->drmMinor >= 3) {
+ drmR128GetParam gp;
+ int ret;
+
+ gp.param = R128_PARAM_IRQ_NR;
+ gp.value = &r128Screen->irq;
+
+ ret = drmCommandWriteRead( sPriv->fd, DRM_R128_GETPARAM,
+ &gp, sizeof(gp));
+ if (ret) {
+ fprintf(stderr, "drmR128GetParam (R128_PARAM_IRQ_NR): %d\n", ret);
+ FREE( r128Screen );
+ return NULL;
+ }
+ }
+
+ r128Screen->mmio.handle = r128DRIPriv->registerHandle;
+ r128Screen->mmio.size = r128DRIPriv->registerSize;
+ if ( drmMap( sPriv->fd,
+ r128Screen->mmio.handle,
+ r128Screen->mmio.size,
+ (drmAddressPtr)&r128Screen->mmio.map ) ) {
+ FREE( r128Screen );
+ return NULL;
+ }
+
+ r128Screen->buffers = drmMapBufs( sPriv->fd );
+ if ( !r128Screen->buffers ) {
+ drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
+ FREE( r128Screen );
+ return NULL;
+ }
+
+ if ( !r128Screen->IsPCI ) {
+ r128Screen->agpTextures.handle = r128DRIPriv->agpTexHandle;
+ r128Screen->agpTextures.size = r128DRIPriv->agpTexMapSize;
+ if ( drmMap( sPriv->fd,
+ r128Screen->agpTextures.handle,
+ r128Screen->agpTextures.size,
+ (drmAddressPtr)&r128Screen->agpTextures.map ) ) {
+ drmUnmapBufs( r128Screen->buffers );
+ drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
+ FREE( r128Screen );
+ return NULL;
+ }
+ }
+
+ switch ( r128DRIPriv->deviceID ) {
+ case PCI_CHIP_RAGE128RE:
+ case PCI_CHIP_RAGE128RF:
+ case PCI_CHIP_RAGE128RK:
+ case PCI_CHIP_RAGE128RL:
+ r128Screen->chipset = R128_CARD_TYPE_R128;
+ break;
+ case PCI_CHIP_RAGE128PD:
+ case PCI_CHIP_RAGE128PF:
+ r128Screen->chipset = R128_CARD_TYPE_R128_PRO;
+ break;
+ case PCI_CHIP_RAGE128LE:
+ case PCI_CHIP_RAGE128LF:
+ r128Screen->chipset = R128_CARD_TYPE_R128_MOBILITY;
+ break;
+ default:
+ r128Screen->chipset = R128_CARD_TYPE_R128;
+ break;
+ }
+
+ r128Screen->cpp = r128DRIPriv->bpp / 8;
+ r128Screen->AGPMode = r128DRIPriv->AGPMode;
+
+ r128Screen->frontOffset = r128DRIPriv->frontOffset;
+ r128Screen->frontPitch = r128DRIPriv->frontPitch;
+ r128Screen->backOffset = r128DRIPriv->backOffset;
+ r128Screen->backPitch = r128DRIPriv->backPitch;
+ r128Screen->depthOffset = r128DRIPriv->depthOffset;
+ r128Screen->depthPitch = r128DRIPriv->depthPitch;
+ r128Screen->spanOffset = r128DRIPriv->spanOffset;
+
+ r128Screen->texOffset[R128_CARD_HEAP] = r128DRIPriv->textureOffset;
+ r128Screen->texSize[R128_CARD_HEAP] = r128DRIPriv->textureSize;
+ r128Screen->logTexGranularity[R128_CARD_HEAP] = r128DRIPriv->log2TexGran;
+
+ if ( r128Screen->IsPCI ) {
+ r128Screen->numTexHeaps = R128_NR_TEX_HEAPS - 1;
+ r128Screen->texOffset[R128_AGP_HEAP] = 0;
+ r128Screen->texSize[R128_AGP_HEAP] = 0;
+ r128Screen->logTexGranularity[R128_AGP_HEAP] = 0;
+ } else {
+ r128Screen->numTexHeaps = R128_NR_TEX_HEAPS;
+ r128Screen->texOffset[R128_AGP_HEAP] =
+ r128DRIPriv->agpTexOffset + R128_AGP_TEX_OFFSET;
+ r128Screen->texSize[R128_AGP_HEAP] = r128DRIPriv->agpTexMapSize;
+ r128Screen->logTexGranularity[R128_AGP_HEAP] =
+ r128DRIPriv->log2AGPTexGran;
+ }
+
+ r128Screen->driScreen = sPriv;
+
+ return r128Screen;
+}
+
+/* Destroy the device specific screen private data struct.
+ */
+static void
+r128DestroyScreen( __DRIscreenPrivate *sPriv )
+{
+ r128ScreenPtr r128Screen = (r128ScreenPtr)sPriv->private;
+
+ if ( !r128Screen )
+ return;
+
+ if ( !r128Screen->IsPCI ) {
+ drmUnmap( (drmAddress)r128Screen->agpTextures.map,
+ r128Screen->agpTextures.size );
+ }
+ drmUnmapBufs( r128Screen->buffers );
+ drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size );
+
+ FREE( r128Screen );
+ sPriv->private = NULL;
+}
+
+
+/* Initialize the fullscreen mode.
+ */
+static GLboolean
+r128OpenCloseFullScreen( __DRIcontextPrivate *driContextPriv )
+{
+ return GL_TRUE;
+}
+
+
+/* Create and initialize the Mesa and driver specific pixmap buffer
+ * data.
+ */
+static GLboolean
+r128CreateBuffer( __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,
+ mesaVis->alphaBits > 0 );
+ return (driDrawPriv->driverPrivate != NULL);
+ }
+}
+
+
+static void
+r128DestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
+{
+ _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
+}
+
+
+/* Copy the back color buffer to the front color buffer */
+static void
+r128SwapBuffers(__DRIdrawablePrivate *dPriv)
+{
+ if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+ r128ContextPtr rmesa;
+ GLcontext *ctx;
+ rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate;
+ ctx = rmesa->glCtx;
+ if (ctx->Visual.doubleBufferMode) {
+ _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
+ if ( rmesa->doPageFlip ) {
+ r128PageFlip( dPriv );
+ }
+ else {
+ r128CopyBuffer( dPriv );
+ }
+ }
+ }
+ else {
+ /* XXX this shouldn't be an error but we can't handle it for now */
+ _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
+ }
+}
+
+
+/* Initialize the driver specific screen private data.
+ */
+static GLboolean
+r128InitDriver( __DRIscreenPrivate *sPriv )
+{
+ sPriv->private = (void *) r128CreateScreen( sPriv );
+
+ if ( !sPriv->private ) {
+ r128DestroyScreen( sPriv );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+#ifndef _SOLO
+/* This function is called by libGL.so as soon as libGL.so is loaded.
+ * This is where we register new extension functions with the dispatcher.
+ */
+void __driRegisterExtensions( void )
+{
+ PFNGLXENABLEEXTENSIONPROC glx_enable_extension;
+
+ if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
+ glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC)
+ glXGetProcAddress( "__glXEnableExtension" );
+
+ if ( glx_enable_extension != NULL ) {
+ glx_enable_extension( "GLX_SGI_swap_control", GL_FALSE );
+ glx_enable_extension( "GLX_SGI_video_sync", GL_FALSE );
+ glx_enable_extension( "GLX_MESA_swap_control", GL_FALSE );
+ }
+ }
+}
+#endif
+
+static struct __DriverAPIRec r128API = {
+ .InitDriver = r128InitDriver,
+ .DestroyScreen = r128DestroyScreen,
+ .CreateContext = r128CreateContext,
+ .DestroyContext = r128DestroyContext,
+ .CreateBuffer = r128CreateBuffer,
+ .DestroyBuffer = r128DestroyBuffer,
+ .SwapBuffers = r128SwapBuffers,
+ .MakeCurrent = r128MakeCurrent,
+ .UnbindContext = r128UnbindContext,
+ .OpenFullScreen = r128OpenCloseFullScreen,
+ .CloseFullScreen = r128OpenCloseFullScreen,
+ .GetSwapInfo = NULL,
+ .GetMSC = driGetMSC32,
+ .WaitForMSC = driWaitForMSC32,
+ .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.
+ */
+#ifndef _SOLO
+void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
+ int numConfigs, __GLXvisualConfig *config)
+{
+ __DRIscreenPrivate *psp;
+ psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &r128API);
+ return (void *) psp;
+}
+#else
+void *__driCreateScreen(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext)
+{
+ __DRIscreenPrivate *psp;
+ psp = __driUtilCreateScreen(driver, driverContext, &r128API);
+ return (void *) psp;
+}
+#endif
diff --git a/src/mesa/drivers/dri/r128/r128_screen.h b/src/mesa/drivers/dri/r128/r128_screen.h
new file mode 100644
index 0000000000..4b1a57292d
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_screen.h
@@ -0,0 +1,84 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_screen.h,v 1.7 2002/12/16 16:18:53 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef __R128_SCREEN_H__
+#define __R128_SCREEN_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "r128_sarea.h"
+
+typedef struct {
+ drmHandle handle; /* Handle to the DRM region */
+ drmSize size; /* Size of the DRM region */
+ unsigned char *map; /* Mapping of the DRM region */
+} r128RegionRec, *r128RegionPtr;
+
+typedef struct {
+
+ GLint chipset;
+ GLint cpp;
+ GLint IsPCI; /* Current card is a PCI card */
+ GLint AGPMode;
+ unsigned int irq; /* IRQ number (0 means none) */
+
+ GLuint frontOffset;
+ GLuint frontPitch;
+ GLuint backOffset;
+ GLuint backPitch;
+
+ GLuint depthOffset;
+ GLuint depthPitch;
+ GLuint spanOffset;
+
+ /* Shared texture data */
+ GLint numTexHeaps;
+ GLint texOffset[R128_NR_TEX_HEAPS];
+ GLint texSize[R128_NR_TEX_HEAPS];
+ GLint logTexGranularity[R128_NR_TEX_HEAPS];
+
+ r128RegionRec mmio;
+ r128RegionRec agpTextures;
+
+ drmBufMapPtr buffers;
+
+ __DRIscreenPrivate *driScreen;
+ unsigned int sarea_priv_offset;
+
+} r128ScreenRec, *r128ScreenPtr;
+
+
+#endif
+#endif /* __R128_SCREEN_H__ */
diff --git a/src/mesa/drivers/dri/r128/r128_span.c b/src/mesa/drivers/dri/r128/r128_span.c
new file mode 100644
index 0000000000..c6f3195942
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_span.c
@@ -0,0 +1,475 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_span.c,v 1.8 2002/10/30 12:51:39 alanh Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#include "r128_context.h"
+#include "r128_ioctl.h"
+#include "r128_state.h"
+#include "r128_span.h"
+#include "r128_tex.h"
+
+#include "swrast/swrast.h"
+
+#define DBG 0
+
+#define HAVE_HW_DEPTH_SPANS 1
+#define HAVE_HW_DEPTH_PIXELS 1
+
+#define LOCAL_VARS \
+ r128ContextPtr rmesa = R128_CONTEXT(ctx); \
+ r128ScreenPtr r128scrn = rmesa->r128Screen; \
+ __DRIscreenPrivate *sPriv = rmesa->driScreen; \
+ __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \
+ GLuint pitch = r128scrn->frontPitch * r128scrn->cpp; \
+ GLuint height = dPriv->h; \
+ char *buf = (char *)(sPriv->pFB + \
+ rmesa->drawOffset + \
+ (dPriv->x * r128scrn->cpp) + \
+ (dPriv->y * pitch)); \
+ char *read_buf = (char *)(sPriv->pFB + \
+ rmesa->readOffset + \
+ (dPriv->x * r128scrn->cpp) + \
+ (dPriv->y * pitch)); \
+ GLuint p; \
+ (void) read_buf; (void) buf; (void) p
+
+#define LOCAL_DEPTH_VARS \
+ r128ContextPtr rmesa = R128_CONTEXT(ctx); \
+ r128ScreenPtr r128scrn = rmesa->r128Screen; \
+ __DRIscreenPrivate *sPriv = rmesa->driScreen; \
+ __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \
+ GLuint height = dPriv->h; \
+ (void) r128scrn; (void) sPriv; (void) height
+
+#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS
+
+
+#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_LOCK() \
+ r128ContextPtr rmesa = R128_CONTEXT(ctx); \
+ FLUSH_BATCH( rmesa ); \
+ LOCK_HARDWARE( rmesa ); \
+ r128WaitForIdleLocked( rmesa );
+
+#define HW_CLIPLOOP() \
+ do { \
+ __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \
+ int _nc = dPriv->numClipRects; \
+ \
+ while ( _nc-- ) { \
+ int minx = dPriv->pClipRects[_nc].x1 - dPriv->x; \
+ int miny = dPriv->pClipRects[_nc].y1 - dPriv->y; \
+ int maxx = dPriv->pClipRects[_nc].x2 - dPriv->x; \
+ int maxy = dPriv->pClipRects[_nc].y2 - dPriv->y;
+
+#define HW_ENDCLIPLOOP() \
+ } \
+ } while (0)
+
+#define HW_UNLOCK() \
+ UNLOCK_HARDWARE( rmesa )
+
+
+
+/* ================================================================
+ * Color buffer
+ */
+
+/* 16 bit, RGB565 color spanline and pixel functions
+ */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+ p = R128PACKCOLOR565( 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 *)(read_buf + _x*2 + _y*pitch); \
+ rgba[0] = (p >> 8) & 0xf8; \
+ rgba[1] = (p >> 3) & 0xfc; \
+ rgba[2] = (p << 3) & 0xf8; \
+ rgba[3] = 0xff; \
+ if ( rgba[0] & 0x08 ) rgba[0] |= 0x07; \
+ if ( rgba[1] & 0x04 ) rgba[1] |= 0x03; \
+ if ( rgba[2] & 0x08 ) rgba[2] |= 0x07; \
+ } while (0)
+
+#define TAG(x) r128##x##_RGB565
+#include "spantmp.h"
+
+#define READ_DEPTH(d, _x, _y) \
+ d = *(GLushort *)(buf + _x*2 + _y*pitch)
+
+/* 32 bit, ARGB8888 color spanline and pixel functions
+ */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+ p = R128PACKCOLOR8888( 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 *)(read_buf + _x*4 + _y*pitch); \
+ rgba[0] = (p >> 16) & 0xff; \
+ rgba[1] = (p >> 8) & 0xff; \
+ rgba[2] = (p >> 0) & 0xff; \
+ rgba[3] = 0xff;/*(p >> 24) & 0xff;*/ \
+} while (0)
+
+#define TAG(x) r128##x##_ARGB8888
+#include "spantmp.h"
+
+
+/* 24 bit, RGB888 color spanline and pixel functions */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+ p = R128PACKCOLOR888( color[0], color[1], color[2] )
+
+#define WRITE_RGBA(_x, _y, r, g, b, a) \
+ *(GLuint *)(buf + _x*3 + _y*pitch) = ((r << 16) | \
+ (g << 8) | \
+ (b << 0))
+
+#define WRITE_PIXEL(_x, _y, p) \
+ *(GLuint *)(buf + _x*3 + _y*pitch) = p
+
+#define READ_RGBA(rgba, _x, _y) \
+ do { \
+ GLuint p = *(GLuint *)(read_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)
+
+/* ================================================================
+ * Depth buffer
+ */
+
+/* 16-bit depth buffer functions
+ */
+#define WRITE_DEPTH_SPAN() \
+ r128WriteDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y, \
+ depth, mask );
+
+#define WRITE_DEPTH_PIXELS() \
+do { \
+ GLint ox[MAX_WIDTH]; \
+ GLint oy[MAX_WIDTH]; \
+ for ( i = 0 ; i < n ; i++ ) { \
+ ox[i] = x[i] + dPriv->x; \
+ } \
+ for ( i = 0 ; i < n ; i++ ) { \
+ oy[i] = Y_FLIP( y[i] ) + dPriv->y; \
+ } \
+ r128WriteDepthPixelsLocked( rmesa, n, ox, oy, depth, mask ); \
+} while (0)
+
+#define READ_DEPTH_SPAN() \
+do { \
+ GLushort *buf = (GLushort *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ GLint i; \
+ \
+ r128ReadDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y ); \
+ r128WaitForIdleLocked( rmesa ); \
+ \
+ for ( i = 0 ; i < n ; i++ ) { \
+ depth[i] = buf[i]; \
+ } \
+} while (0)
+
+#define READ_DEPTH_PIXELS() \
+do { \
+ GLushort *buf = (GLushort *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ GLint i, remaining = n; \
+ \
+ while ( remaining > 0 ) { \
+ GLint ox[MAX_WIDTH]; \
+ GLint oy[MAX_WIDTH]; \
+ GLint count; \
+ \
+ if ( remaining <= 128 ) { \
+ count = remaining; \
+ } else { \
+ count = 128; \
+ } \
+ for ( i = 0 ; i < count ; i++ ) { \
+ ox[i] = x[i] + dPriv->x; \
+ } \
+ for ( i = 0 ; i < count ; i++ ) { \
+ oy[i] = Y_FLIP( y[i] ) + dPriv->y; \
+ } \
+ \
+ r128ReadDepthPixelsLocked( rmesa, count, ox, oy ); \
+ r128WaitForIdleLocked( rmesa ); \
+ \
+ for ( i = 0 ; i < count ; i++ ) { \
+ depth[i] = buf[i]; \
+ } \
+ depth += count; \
+ x += count; \
+ y += count; \
+ remaining -= count; \
+ } \
+} while (0)
+
+#define TAG(x) r128##x##_16
+#include "depthtmp.h"
+
+
+/* 24-bit depth, 8-bit stencil buffer functions
+ */
+#define WRITE_DEPTH_SPAN() \
+ r128WriteDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y, \
+ depth, mask );
+
+#define WRITE_DEPTH_PIXELS() \
+do { \
+ GLint ox[MAX_WIDTH]; \
+ GLint oy[MAX_WIDTH]; \
+ for ( i = 0 ; i < n ; i++ ) { \
+ ox[i] = x[i] + dPriv->x; \
+ } \
+ for ( i = 0 ; i < n ; i++ ) { \
+ oy[i] = Y_FLIP( y[i] ) + dPriv->y; \
+ } \
+ r128WriteDepthPixelsLocked( rmesa, n, ox, oy, depth, mask ); \
+} while (0)
+
+#define READ_DEPTH_SPAN() \
+do { \
+ GLuint *buf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ GLint i; \
+ \
+ r128ReadDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y ); \
+ r128WaitForIdleLocked( rmesa ); \
+ \
+ for ( i = 0 ; i < n ; i++ ) { \
+ depth[i] = buf[i] & 0x00ffffff; \
+ } \
+} while (0)
+
+#define READ_DEPTH_PIXELS() \
+do { \
+ GLuint *buf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ GLint i, remaining = n; \
+ \
+ while ( remaining > 0 ) { \
+ GLint ox[MAX_WIDTH]; \
+ GLint oy[MAX_WIDTH]; \
+ GLint count; \
+ \
+ if ( remaining <= 128 ) { \
+ count = remaining; \
+ } else { \
+ count = 128; \
+ } \
+ for ( i = 0 ; i < count ; i++ ) { \
+ ox[i] = x[i] + dPriv->x; \
+ } \
+ for ( i = 0 ; i < count ; i++ ) { \
+ oy[i] = Y_FLIP( y[i] ) + dPriv->y; \
+ } \
+ \
+ r128ReadDepthPixelsLocked( rmesa, count, ox, oy ); \
+ r128WaitForIdleLocked( rmesa ); \
+ \
+ for ( i = 0 ; i < count ; i++ ) { \
+ depth[i] = buf[i] & 0x00ffffff; \
+ } \
+ depth += count; \
+ x += count; \
+ y += count; \
+ remaining -= count; \
+ } \
+} while (0)
+
+#define TAG(x) r128##x##_24_8
+#include "depthtmp.h"
+
+
+
+/* ================================================================
+ * Stencil buffer
+ */
+
+/* FIXME: Add support for hardware stencil buffers.
+ */
+
+
+/* 32 bit depthbuffer functions */
+#define WRITE_DEPTH(_x, _y, d) \
+ *(GLuint *)(buf + _x*4 + _y*pitch) = d
+
+
+
+/*
+ * This function is called to specify which buffer to read and write
+ * for software rasterization (swrast) fallbacks. This doesn't necessarily
+ * correspond to glDrawBuffer() or glReadBuffer() calls.
+ */
+static void r128DDSetBuffer( GLcontext *ctx,
+ GLframebuffer *colorBuffer,
+ GLuint bufferBit )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ switch ( bufferBit ) {
+ case FRONT_LEFT_BIT:
+ if ( rmesa->sarea->pfCurrentPage == 1 ) {
+ rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->backOffset;
+ rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->backPitch;
+ } else {
+ rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->frontOffset;
+ rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->frontPitch;
+ }
+ break;
+ case BACK_LEFT_BIT:
+ if ( rmesa->sarea->pfCurrentPage == 1 ) {
+ rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->frontOffset;
+ rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->frontPitch;
+ } else {
+ rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->backOffset;
+ rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->backPitch;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+void r128DDInitSpanFuncs( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx);
+
+ swdd->SetBuffer = r128DDSetBuffer;
+
+ switch ( rmesa->r128Screen->cpp ) {
+ case 2:
+ swdd->WriteRGBASpan = r128WriteRGBASpan_RGB565;
+ swdd->WriteRGBSpan = r128WriteRGBSpan_RGB565;
+ swdd->WriteMonoRGBASpan = r128WriteMonoRGBASpan_RGB565;
+ swdd->WriteRGBAPixels = r128WriteRGBAPixels_RGB565;
+ swdd->WriteMonoRGBAPixels = r128WriteMonoRGBAPixels_RGB565;
+ swdd->ReadRGBASpan = r128ReadRGBASpan_RGB565;
+ swdd->ReadRGBAPixels = r128ReadRGBAPixels_RGB565;
+ break;
+
+ case 4:
+ swdd->WriteRGBASpan = r128WriteRGBASpan_ARGB8888;
+ swdd->WriteRGBSpan = r128WriteRGBSpan_ARGB8888;
+ swdd->WriteMonoRGBASpan = r128WriteMonoRGBASpan_ARGB8888;
+ swdd->WriteRGBAPixels = r128WriteRGBAPixels_ARGB8888;
+ swdd->WriteMonoRGBAPixels = r128WriteMonoRGBAPixels_ARGB8888;
+ swdd->ReadRGBASpan = r128ReadRGBASpan_ARGB8888;
+ swdd->ReadRGBAPixels = r128ReadRGBAPixels_ARGB8888;
+ break;
+
+ default:
+ break;
+ }
+
+ switch ( rmesa->glCtx->Visual.depthBits ) {
+ case 16:
+ swdd->ReadDepthSpan = r128ReadDepthSpan_16;
+ swdd->WriteDepthSpan = r128WriteDepthSpan_16;
+ swdd->ReadDepthPixels = r128ReadDepthPixels_16;
+ swdd->WriteDepthPixels = r128WriteDepthPixels_16;
+ break;
+
+ case 24:
+ swdd->ReadDepthSpan = r128ReadDepthSpan_24_8;
+ swdd->WriteDepthSpan = r128WriteDepthSpan_24_8;
+ swdd->ReadDepthPixels = r128ReadDepthPixels_24_8;
+ swdd->WriteDepthPixels = r128WriteDepthPixels_24_8;
+ break;
+
+ default:
+ break;
+ }
+
+ swdd->WriteCI8Span = NULL;
+ swdd->WriteCI32Span = NULL;
+ swdd->WriteMonoCISpan = NULL;
+ swdd->WriteCI32Pixels = NULL;
+ swdd->WriteMonoCIPixels = NULL;
+ swdd->ReadCI32Span = NULL;
+ swdd->ReadCI32Pixels = NULL;
+}
diff --git a/src/mesa/drivers/dri/r128/r128_span.h b/src/mesa/drivers/dri/r128/r128_span.h
new file mode 100644
index 0000000000..44356c5b24
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_span.h
@@ -0,0 +1,44 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_span.h,v 1.3 2001/01/08 01:07:21 martin Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef __R128_SPAN_H__
+#define __R128_SPAN_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void r128DDInitSpanFuncs( GLcontext *ctx );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/r128/r128_state.c b/src/mesa/drivers/dri/r128/r128_state.c
new file mode 100644
index 0000000000..85b3b68402
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_state.c
@@ -0,0 +1,1239 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_state.c,v 1.11 2002/10/30 12:51:39 alanh Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#include "r128_context.h"
+#include "r128_state.h"
+#include "r128_ioctl.h"
+#include "r128_tris.h"
+#include "r128_vb.h"
+#include "r128_tex.h"
+
+#include "context.h"
+#include "enums.h"
+#include "colormac.h"
+#include "swrast/swrast.h"
+#include "array_cache/acache.h"
+#include "tnl/tnl.h"
+#include "swrast_setup/swrast_setup.h"
+
+#include "tnl/t_pipeline.h"
+
+
+/* =============================================================
+ * Alpha blending
+ */
+
+static void r128UpdateAlphaMode( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint a = rmesa->setup.misc_3d_state_cntl_reg;
+ GLuint t = rmesa->setup.tex_cntl_c;
+
+ if ( ctx->Color.AlphaEnabled ) {
+ GLubyte ref;
+
+ CLAMPED_FLOAT_TO_UBYTE(ref, ctx->Color.AlphaRef);
+
+ a &= ~(R128_ALPHA_TEST_MASK | R128_REF_ALPHA_MASK);
+
+ switch ( ctx->Color.AlphaFunc ) {
+ case GL_NEVER:
+ a |= R128_ALPHA_TEST_NEVER;
+ break;
+ case GL_LESS:
+ a |= R128_ALPHA_TEST_LESS;
+ break;
+ case GL_LEQUAL:
+ a |= R128_ALPHA_TEST_LESSEQUAL;
+ break;
+ case GL_EQUAL:
+ a |= R128_ALPHA_TEST_EQUAL;
+ break;
+ case GL_GEQUAL:
+ a |= R128_ALPHA_TEST_GREATEREQUAL;
+ break;
+ case GL_GREATER:
+ a |= R128_ALPHA_TEST_GREATER;
+ break;
+ case GL_NOTEQUAL:
+ a |= R128_ALPHA_TEST_NEQUAL;
+ break;
+ case GL_ALWAYS:
+ a |= R128_ALPHA_TEST_ALWAYS;
+ break;
+ }
+
+ a |= ref & R128_REF_ALPHA_MASK;
+ t |= R128_ALPHA_TEST_ENABLE;
+ } else {
+ t &= ~R128_ALPHA_TEST_ENABLE;
+ }
+
+ FALLBACK( rmesa, R128_FALLBACK_BLEND_FUNC, GL_FALSE );
+
+ if ( ctx->Color.BlendEnabled ) {
+ a &= ~(R128_ALPHA_BLEND_SRC_MASK | R128_ALPHA_BLEND_DST_MASK);
+
+ switch ( ctx->Color.BlendSrcRGB ) {
+ case GL_ZERO:
+ a |= R128_ALPHA_BLEND_SRC_ZERO;
+ break;
+ case GL_ONE:
+ a |= R128_ALPHA_BLEND_SRC_ONE;
+ break;
+ case GL_DST_COLOR:
+ a |= R128_ALPHA_BLEND_SRC_DESTCOLOR;
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ a |= R128_ALPHA_BLEND_SRC_INVDESTCOLOR;
+ break;
+ case GL_SRC_ALPHA:
+ a |= R128_ALPHA_BLEND_SRC_SRCALPHA;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ a |= R128_ALPHA_BLEND_SRC_INVSRCALPHA;
+ break;
+ case GL_DST_ALPHA:
+ a |= R128_ALPHA_BLEND_SRC_DESTALPHA;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ a |= R128_ALPHA_BLEND_SRC_INVDESTALPHA;
+ break;
+ case GL_SRC_ALPHA_SATURATE:
+ a |= R128_ALPHA_BLEND_SRC_SRCALPHASAT;
+ break;
+ default:
+ FALLBACK( rmesa, R128_FALLBACK_BLEND_FUNC, GL_TRUE );
+ }
+
+ switch ( ctx->Color.BlendDstRGB ) {
+ case GL_ZERO:
+ a |= R128_ALPHA_BLEND_DST_ZERO;
+ break;
+ case GL_ONE:
+ a |= R128_ALPHA_BLEND_DST_ONE;
+ break;
+ case GL_SRC_COLOR:
+ a |= R128_ALPHA_BLEND_DST_SRCCOLOR;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ a |= R128_ALPHA_BLEND_DST_INVSRCCOLOR;
+ break;
+ case GL_SRC_ALPHA:
+ a |= R128_ALPHA_BLEND_DST_SRCALPHA;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ a |= R128_ALPHA_BLEND_DST_INVSRCALPHA;
+ break;
+ case GL_DST_ALPHA:
+ a |= R128_ALPHA_BLEND_DST_DESTALPHA;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ a |= R128_ALPHA_BLEND_DST_INVDESTALPHA;
+ break;
+ default:
+ FALLBACK( rmesa, R128_FALLBACK_BLEND_FUNC, GL_TRUE );
+ }
+
+ t |= R128_ALPHA_ENABLE;
+ } else {
+ t &= ~R128_ALPHA_ENABLE;
+ }
+
+ if ( rmesa->setup.misc_3d_state_cntl_reg != a ) {
+ rmesa->setup.misc_3d_state_cntl_reg = a;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
+ }
+ if ( rmesa->setup.tex_cntl_c != t ) {
+ rmesa->setup.tex_cntl_c = t;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
+ }
+}
+
+static void r128DDAlphaFunc( GLcontext *ctx, GLenum func, GLfloat ref )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_ALPHA;
+}
+
+static void r128DDBlendEquation( GLcontext *ctx, GLenum mode )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+
+ /* BlendEquation sets ColorLogicOpEnabled in an unexpected
+ * manner.
+ */
+ FALLBACK( R128_CONTEXT(ctx), R128_FALLBACK_LOGICOP,
+ (ctx->Color.ColorLogicOpEnabled &&
+ ctx->Color.LogicOp != GL_COPY));
+
+ /* Can only do blend addition, not min, max, subtract, etc. */
+ FALLBACK( R128_CONTEXT(ctx), R128_FALLBACK_BLEND_EQ,
+ mode != GL_FUNC_ADD_EXT);
+
+ rmesa->new_state |= R128_NEW_ALPHA;
+}
+
+static void r128DDBlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_ALPHA;
+}
+
+static void r128DDBlendFuncSeparate( GLcontext *ctx,
+ GLenum sfactorRGB, GLenum dfactorRGB,
+ GLenum sfactorA, GLenum dfactorA )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_ALPHA;
+}
+
+
+/* =============================================================
+ * Depth testing
+ */
+
+static void r128UpdateZMode( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint z = rmesa->setup.z_sten_cntl_c;
+ GLuint t = rmesa->setup.tex_cntl_c;
+
+ if ( ctx->Depth.Test ) {
+ z &= ~R128_Z_TEST_MASK;
+
+ switch ( ctx->Depth.Func ) {
+ case GL_NEVER:
+ z |= R128_Z_TEST_NEVER;
+ break;
+ case GL_ALWAYS:
+ z |= R128_Z_TEST_ALWAYS;
+ break;
+ case GL_LESS:
+ z |= R128_Z_TEST_LESS;
+ break;
+ case GL_LEQUAL:
+ z |= R128_Z_TEST_LESSEQUAL;
+ break;
+ case GL_EQUAL:
+ z |= R128_Z_TEST_EQUAL;
+ break;
+ case GL_GEQUAL:
+ z |= R128_Z_TEST_GREATEREQUAL;
+ break;
+ case GL_GREATER:
+ z |= R128_Z_TEST_GREATER;
+ break;
+ case GL_NOTEQUAL:
+ z |= R128_Z_TEST_NEQUAL;
+ break;
+ }
+
+ t |= R128_Z_ENABLE;
+ } else {
+ t &= ~R128_Z_ENABLE;
+ }
+
+ if ( ctx->Depth.Mask ) {
+ t |= R128_Z_WRITE_ENABLE;
+ } else {
+ t &= ~R128_Z_WRITE_ENABLE;
+ }
+
+ if ( rmesa->setup.z_sten_cntl_c != z ) {
+ rmesa->setup.z_sten_cntl_c = z;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+ if ( rmesa->setup.tex_cntl_c != t ) {
+ rmesa->setup.tex_cntl_c = t;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+}
+
+static void r128DDDepthFunc( GLcontext *ctx, GLenum func )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_DEPTH;
+}
+
+static void r128DDDepthMask( GLcontext *ctx, GLboolean flag )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_DEPTH;
+}
+
+static void r128DDClearDepth( GLcontext *ctx, GLclampd d )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ switch ( rmesa->setup.z_sten_cntl_c & R128_Z_PIX_WIDTH_MASK ) {
+ case R128_Z_PIX_WIDTH_16:
+ rmesa->ClearDepth = d * 0x0000ffff;
+ break;
+ case R128_Z_PIX_WIDTH_24:
+ rmesa->ClearDepth = d * 0x00ffffff;
+ break;
+ case R128_Z_PIX_WIDTH_32:
+ rmesa->ClearDepth = d * 0xffffffff;
+ break;
+ }
+}
+
+
+/* =============================================================
+ * Fog
+ */
+
+static void r128UpdateFogAttrib( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint t = rmesa->setup.tex_cntl_c;
+ GLubyte c[4];
+ GLuint col;
+
+ if ( ctx->Fog.Enabled ) {
+ t |= R128_FOG_ENABLE;
+ } else {
+ t &= ~R128_FOG_ENABLE;
+ }
+
+ c[0] = FLOAT_TO_UBYTE( ctx->Fog.Color[0] );
+ c[1] = FLOAT_TO_UBYTE( ctx->Fog.Color[1] );
+ c[2] = FLOAT_TO_UBYTE( ctx->Fog.Color[2] );
+
+ col = r128PackColor( 4, c[0], c[1], c[2], 0 );
+
+ if ( rmesa->setup.fog_color_c != col ) {
+ rmesa->setup.fog_color_c = col;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+ if ( rmesa->setup.tex_cntl_c != t ) {
+ rmesa->setup.tex_cntl_c = t;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+}
+
+static void r128DDFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_FOG;
+}
+
+
+/* =============================================================
+ * Clipping
+ */
+
+static void r128UpdateClipping( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ if ( rmesa->driDrawable ) {
+ __DRIdrawablePrivate *drawable = rmesa->driDrawable;
+ int x1 = 0;
+ int y1 = 0;
+ int x2 = drawable->w - 1;
+ int y2 = drawable->h - 1;
+
+ if ( ctx->Scissor.Enabled ) {
+ if ( ctx->Scissor.X > x1 ) {
+ x1 = ctx->Scissor.X;
+ }
+ if ( drawable->h - ctx->Scissor.Y - ctx->Scissor.Height > y1 ) {
+ y1 = drawable->h - ctx->Scissor.Y - ctx->Scissor.Height;
+ }
+ if ( ctx->Scissor.X + ctx->Scissor.Width - 1 < x2 ) {
+ x2 = ctx->Scissor.X + ctx->Scissor.Width - 1;
+ }
+ if ( drawable->h - ctx->Scissor.Y - 1 < y2 ) {
+ y2 = drawable->h - ctx->Scissor.Y - 1;
+ }
+ }
+
+ x1 += drawable->x;
+ y1 += drawable->y;
+ x2 += drawable->x;
+ y2 += drawable->y;
+
+ rmesa->setup.sc_top_left_c = ((y1 << 16) | x1);
+ rmesa->setup.sc_bottom_right_c = ((y2 << 16) | x2);
+
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+}
+
+static void r128DDScissor( GLcontext *ctx,
+ GLint x, GLint y, GLsizei w, GLsizei h )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_CLIP;
+}
+
+
+/* =============================================================
+ * Culling
+ */
+
+static void r128UpdateCull( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint f = rmesa->setup.pm4_vc_fpu_setup;
+
+ f &= ~R128_FRONT_DIR_MASK;
+
+ switch ( ctx->Polygon.FrontFace ) {
+ case GL_CW:
+ f |= R128_FRONT_DIR_CW;
+ break;
+ case GL_CCW:
+ f |= R128_FRONT_DIR_CCW;
+ break;
+ }
+
+ f |= R128_BACKFACE_SOLID | R128_FRONTFACE_SOLID;
+
+ if ( ctx->Polygon.CullFlag ) {
+ switch ( ctx->Polygon.CullFaceMode ) {
+ case GL_FRONT:
+ f &= ~R128_FRONTFACE_SOLID;
+ break;
+ case GL_BACK:
+ f &= ~R128_BACKFACE_SOLID;
+ break;
+ case GL_FRONT_AND_BACK:
+ f &= ~(R128_BACKFACE_SOLID |
+ R128_FRONTFACE_SOLID);
+ break;
+ }
+ }
+
+ if ( 1 || rmesa->setup.pm4_vc_fpu_setup != f ) {
+ rmesa->setup.pm4_vc_fpu_setup = f;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_SETUP;
+ }
+}
+
+static void r128DDCullFace( GLcontext *ctx, GLenum mode )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_CULL;
+}
+
+static void r128DDFrontFace( GLcontext *ctx, GLenum mode )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_CULL;
+}
+
+
+/* =============================================================
+ * Masks
+ */
+
+static void r128UpdateMasks( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ GLuint mask = r128PackColor( rmesa->r128Screen->cpp,
+ ctx->Color.ColorMask[RCOMP],
+ ctx->Color.ColorMask[GCOMP],
+ ctx->Color.ColorMask[BCOMP],
+ ctx->Color.ColorMask[ACOMP] );
+
+ if ( rmesa->setup.plane_3d_mask_c != mask ) {
+ rmesa->setup.plane_3d_mask_c = mask;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
+ }
+}
+
+static void r128DDColorMask( GLcontext *ctx,
+ GLboolean r, GLboolean g,
+ GLboolean b, GLboolean a )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_MASKS;
+}
+
+
+/* =============================================================
+ * Rendering attributes
+ *
+ * We really don't want to recalculate all this every time we bind a
+ * texture. These things shouldn't change all that often, so it makes
+ * sense to break them out of the core texture state update routines.
+ */
+
+static void updateSpecularLighting( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint t = rmesa->setup.tex_cntl_c;
+
+ if ( ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR &&
+ ctx->Light.Enabled) {
+ /* XXX separate specular color just doesn't seem to work as it should.
+ * For now, we fall back to s/w rendering whenever separate specular
+ * is enabled.
+ */
+#if 0
+ if (ctx->Light.ShadeModel == GL_FLAT) {
+ /* R128 can't do flat-shaded separate specular */
+ t &= ~R128_SPEC_LIGHT_ENABLE;
+ FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_TRUE );
+ /*printf("%s fallback sep spec\n", __FUNCTION__);*/
+ }
+ else {
+ t |= R128_SPEC_LIGHT_ENABLE;
+ FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_FALSE );
+ /*printf("%s enable sep spec\n", __FUNCTION__);*/
+ }
+#else
+ t &= ~R128_SPEC_LIGHT_ENABLE;
+ FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_TRUE );
+ /*printf("%s fallback sep spec\n", __FUNCTION__);*/
+#endif
+ }
+ else {
+ t &= ~R128_SPEC_LIGHT_ENABLE;
+ FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_FALSE );
+ /*printf("%s disable sep spec\n", __FUNCTION__);*/
+ }
+
+ if ( rmesa->setup.tex_cntl_c != t ) {
+ rmesa->setup.tex_cntl_c = t;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ rmesa->dirty |= R128_UPLOAD_SETUP;
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ }
+}
+
+
+static void r128DDLightModelfv( GLcontext *ctx, GLenum pname,
+ const GLfloat *param )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ if ( pname == GL_LIGHT_MODEL_COLOR_CONTROL ) {
+ FLUSH_BATCH( rmesa );
+ updateSpecularLighting(ctx);
+ }
+}
+
+static void r128DDShadeModel( GLcontext *ctx, GLenum mode )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint s = rmesa->setup.pm4_vc_fpu_setup;
+
+ s &= ~R128_FPU_COLOR_MASK;
+
+ switch ( mode ) {
+ case GL_FLAT:
+ s |= R128_FPU_COLOR_FLAT;
+ break;
+ case GL_SMOOTH:
+ s |= R128_FPU_COLOR_GOURAUD;
+ break;
+ default:
+ return;
+ }
+
+ updateSpecularLighting(ctx);
+
+ if ( rmesa->setup.pm4_vc_fpu_setup != s ) {
+ FLUSH_BATCH( rmesa );
+ rmesa->setup.pm4_vc_fpu_setup = s;
+
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ rmesa->dirty |= R128_UPLOAD_SETUP;
+ }
+}
+
+
+/* =============================================================
+ * Window position
+ */
+
+void r128UpdateWindow( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ int x = rmesa->driDrawable->x;
+ int y = rmesa->driDrawable->y;
+
+ rmesa->setup.window_xy_offset = ((y << R128_WINDOW_Y_SHIFT) |
+ (x << R128_WINDOW_X_SHIFT));
+
+ rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_WINDOW;
+}
+
+/* =============================================================
+ * Viewport
+ */
+
+
+static void r128CalcViewport( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ const GLfloat *v = ctx->Viewport._WindowMap.m;
+ GLfloat *m = rmesa->hw_viewport;
+
+ /* See also r128_translate_vertex.
+ */
+ m[MAT_SX] = v[MAT_SX];
+ m[MAT_TX] = v[MAT_TX] + SUBPIXEL_X;
+ m[MAT_SY] = - v[MAT_SY];
+ m[MAT_TY] = - v[MAT_TY] + rmesa->driDrawable->h + SUBPIXEL_Y;
+ m[MAT_SZ] = v[MAT_SZ] * rmesa->depth_scale;
+ m[MAT_TZ] = v[MAT_TZ] * rmesa->depth_scale;
+}
+
+static void r128Viewport( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height )
+{
+ r128CalcViewport( ctx );
+}
+
+static void r128DepthRange( GLcontext *ctx,
+ GLclampd nearval, GLclampd farval )
+{
+ r128CalcViewport( ctx );
+}
+
+
+/* =============================================================
+ * Miscellaneous
+ */
+
+static void r128DDClearColor( GLcontext *ctx,
+ const GLfloat color[4] )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLubyte c[4];
+
+ 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]);
+
+ rmesa->ClearColor = r128PackColor( rmesa->r128Screen->cpp,
+ c[0], c[1], c[2], c[3] );
+}
+
+static void r128DDLogicOpCode( GLcontext *ctx, GLenum opcode )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ if ( ctx->Color.ColorLogicOpEnabled ) {
+ FLUSH_BATCH( rmesa );
+
+ FALLBACK( rmesa, R128_FALLBACK_LOGICOP, opcode != GL_COPY );
+ }
+}
+
+static void r128DDDrawBuffer( GLcontext *ctx, GLenum mode )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+
+ /*
+ * _DrawDestMask is easier to cope with than <mode>.
+ */
+ switch ( ctx->Color._DrawDestMask ) {
+ case FRONT_LEFT_BIT:
+ FALLBACK( rmesa, R128_FALLBACK_DRAW_BUFFER, GL_FALSE );
+ break;
+ case BACK_LEFT_BIT:
+ FALLBACK( rmesa, R128_FALLBACK_DRAW_BUFFER, GL_FALSE );
+ break;
+ default:
+ /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */
+ FALLBACK( rmesa, R128_FALLBACK_DRAW_BUFFER, GL_TRUE );
+ break;
+ }
+
+ /* We want to update the s/w rast state too so that r200SetBuffer()
+ * gets called.
+ */
+ _swrast_DrawBuffer(ctx, mode);
+
+ rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) |
+ (rmesa->drawOffset >> 5));
+ rmesa->new_state |= R128_NEW_WINDOW;
+}
+
+static void r128DDReadBuffer( GLcontext *ctx, GLenum mode )
+{
+ /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
+}
+
+
+/* =============================================================
+ * Polygon stipple
+ */
+
+static void r128DDPolygonStipple( GLcontext *ctx, const GLubyte *mask )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint stipple[32], i;
+ drmR128Stipple stippleRec;
+
+ for (i = 0; i < 32; i++) {
+ stipple[31 - i] = ((mask[i*4+0] << 24) |
+ (mask[i*4+1] << 16) |
+ (mask[i*4+2] << 8) |
+ (mask[i*4+3]));
+ }
+
+ FLUSH_BATCH( rmesa );
+ LOCK_HARDWARE( rmesa );
+
+ stippleRec.mask = stipple;
+ drmCommandWrite( rmesa->driFd, DRM_R128_STIPPLE,
+ &stippleRec, sizeof(drmR128Stipple) );
+
+ UNLOCK_HARDWARE( rmesa );
+
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+}
+
+
+/* =============================================================
+ * Render mode
+ */
+
+static void r128DDRenderMode( GLcontext *ctx, GLenum mode )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ FALLBACK( rmesa, R128_FALLBACK_RENDER_MODE, (mode != GL_RENDER) );
+}
+
+
+
+/* =============================================================
+ * State enable/disable
+ */
+
+static void r128DDEnable( GLcontext *ctx, GLenum cap, GLboolean state )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s( %s = %s )\n",
+ __FUNCTION__, _mesa_lookup_enum_by_nr( cap ),
+ state ? "GL_TRUE" : "GL_FALSE" );
+ }
+
+ switch ( cap ) {
+ case GL_ALPHA_TEST:
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_ALPHA;
+ break;
+
+ case GL_BLEND:
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_ALPHA;
+
+ /* For some reason enable(GL_BLEND) affects ColorLogicOpEnabled.
+ */
+ FALLBACK( rmesa, R128_FALLBACK_LOGICOP,
+ (ctx->Color.ColorLogicOpEnabled &&
+ ctx->Color.LogicOp != GL_COPY));
+ break;
+
+ case GL_CULL_FACE:
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_CULL;
+ break;
+
+ case GL_DEPTH_TEST:
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_DEPTH;
+ break;
+
+ case GL_DITHER:
+ do {
+ GLuint t = rmesa->setup.tex_cntl_c;
+ FLUSH_BATCH( rmesa );
+
+ if ( ctx->Color.DitherFlag ) {
+ t |= R128_DITHER_ENABLE;
+ } else {
+ t &= ~R128_DITHER_ENABLE;
+ }
+
+ if ( rmesa->setup.tex_cntl_c != t ) {
+ rmesa->setup.tex_cntl_c = t;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+ } while (0);
+ break;
+
+ case GL_FOG:
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_FOG;
+ break;
+
+ case GL_COLOR_LOGIC_OP:
+ FLUSH_BATCH( rmesa );
+ FALLBACK( rmesa, R128_FALLBACK_LOGICOP,
+ state && ctx->Color.LogicOp != GL_COPY );
+ break;
+
+ case GL_LIGHTING:
+ updateSpecularLighting(ctx);
+ break;
+
+ case GL_SCISSOR_TEST:
+ FLUSH_BATCH( rmesa );
+ rmesa->scissor = state;
+ rmesa->new_state |= R128_NEW_CLIP;
+ break;
+
+ case GL_STENCIL_TEST:
+ FLUSH_BATCH( rmesa );
+ FALLBACK( rmesa, R128_FALLBACK_STENCIL, state );
+ break;
+
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_3D:
+ FLUSH_BATCH( rmesa );
+ break;
+
+ case GL_POLYGON_STIPPLE:
+ if ( rmesa->render_primitive == GL_TRIANGLES ) {
+ FLUSH_BATCH( rmesa );
+ rmesa->setup.dp_gui_master_cntl_c &= ~R128_GMC_BRUSH_NONE;
+ if ( state ) {
+ rmesa->setup.dp_gui_master_cntl_c |=
+ R128_GMC_BRUSH_32x32_MONO_FG_LA;
+ } else {
+ rmesa->setup.dp_gui_master_cntl_c |=
+ R128_GMC_BRUSH_SOLID_COLOR;
+ }
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+ break;
+
+ default:
+ return;
+ }
+}
+
+
+/* =============================================================
+ * State initialization, management
+ */
+
+static void r128DDPrintDirty( const char *msg, GLuint state )
+{
+ fprintf( stderr,
+ "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n",
+ msg,
+ state,
+ (state & R128_UPLOAD_CORE) ? "core, " : "",
+ (state & R128_UPLOAD_CONTEXT) ? "context, " : "",
+ (state & R128_UPLOAD_SETUP) ? "setup, " : "",
+ (state & R128_UPLOAD_TEX0) ? "tex0, " : "",
+ (state & R128_UPLOAD_TEX1) ? "tex1, " : "",
+ (state & R128_UPLOAD_MASKS) ? "masks, " : "",
+ (state & R128_UPLOAD_WINDOW) ? "window, " : "",
+ (state & R128_UPLOAD_CLIPRECTS) ? "cliprects, " : "",
+ (state & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "" );
+}
+
+/*
+ * Load the current context's state into the hardware.
+ *
+ * NOTE: Be VERY careful about ensuring the context state is marked for
+ * upload, the only place it shouldn't be uploaded is when the setup
+ * state has changed in ReducedPrimitiveChange as this comes right after
+ * a state update.
+ *
+ * Blits of any type should always upload the context and masks after
+ * they are done.
+ */
+void r128EmitHwStateLocked( r128ContextPtr rmesa )
+{
+ R128SAREAPrivPtr sarea = rmesa->sarea;
+ r128_context_regs_t *regs = &(rmesa->setup);
+ const r128TexObjPtr t0 = rmesa->CurrentTexObj[0];
+ const r128TexObjPtr t1 = rmesa->CurrentTexObj[1];
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_MSG ) {
+ r128DDPrintDirty( "r128EmitHwStateLocked", rmesa->dirty );
+ }
+
+ if ( rmesa->dirty & (R128_UPLOAD_CONTEXT |
+ R128_UPLOAD_SETUP |
+ R128_UPLOAD_MASKS |
+ R128_UPLOAD_WINDOW |
+ R128_UPLOAD_CORE) ) {
+ memcpy( &sarea->ContextState, regs, sizeof(sarea->ContextState) );
+ }
+
+ if ( (rmesa->dirty & R128_UPLOAD_TEX0) && t0 ) {
+ r128_texture_regs_t *tex = &sarea->TexState[0];
+
+ tex->tex_cntl = t0->setup.tex_cntl;
+ tex->tex_combine_cntl = rmesa->tex_combine[0];
+ tex->tex_size_pitch = t0->setup.tex_size_pitch;
+ memcpy( &tex->tex_offset[0], &t0->setup.tex_offset[0],
+ sizeof(tex->tex_offset ) );
+ tex->tex_border_color = t0->setup.tex_border_color;
+ }
+
+ if ( (rmesa->dirty & R128_UPLOAD_TEX1) && t1 ) {
+ r128_texture_regs_t *tex = &sarea->TexState[1];
+
+ tex->tex_cntl = t1->setup.tex_cntl;
+ tex->tex_combine_cntl = rmesa->tex_combine[1];
+ tex->tex_size_pitch = t1->setup.tex_size_pitch;
+ memcpy( &tex->tex_offset[0], &t1->setup.tex_offset[0],
+ sizeof(tex->tex_offset ) );
+ tex->tex_border_color = t1->setup.tex_border_color;
+ }
+
+ sarea->vertsize = rmesa->vertex_size;
+ sarea->vc_format = rmesa->vertex_format;
+
+ /* Turn off the texture cache flushing */
+ rmesa->setup.tex_cntl_c &= ~R128_TEX_CACHE_FLUSH;
+
+ sarea->dirty |= rmesa->dirty;
+ rmesa->dirty &= R128_UPLOAD_CLIPRECTS;
+}
+
+static void r128DDPrintState( const char *msg, GLuint flags )
+{
+ fprintf( stderr,
+ "%s: (0x%x) %s%s%s%s%s%s%s%s\n",
+ msg,
+ flags,
+ (flags & R128_NEW_CONTEXT) ? "context, " : "",
+ (flags & R128_NEW_ALPHA) ? "alpha, " : "",
+ (flags & R128_NEW_DEPTH) ? "depth, " : "",
+ (flags & R128_NEW_FOG) ? "fog, " : "",
+ (flags & R128_NEW_CLIP) ? "clip, " : "",
+ (flags & R128_NEW_CULL) ? "cull, " : "",
+ (flags & R128_NEW_MASKS) ? "masks, " : "",
+ (flags & R128_NEW_WINDOW) ? "window, " : "" );
+}
+
+void r128DDUpdateHWState( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ int new_state = rmesa->new_state;
+
+ if ( new_state || rmesa->NewGLState & _NEW_TEXTURE )
+ {
+ FLUSH_BATCH( rmesa );
+
+ rmesa->new_state = 0;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_MSG )
+ r128DDPrintState( "r128UpdateHwState", new_state );
+
+ /* Update the various parts of the context's state.
+ */
+ if ( new_state & R128_NEW_ALPHA )
+ r128UpdateAlphaMode( ctx );
+
+ if ( new_state & R128_NEW_DEPTH )
+ r128UpdateZMode( ctx );
+
+ if ( new_state & R128_NEW_FOG )
+ r128UpdateFogAttrib( ctx );
+
+ if ( new_state & R128_NEW_CLIP )
+ r128UpdateClipping( ctx );
+
+ if ( new_state & R128_NEW_CULL )
+ r128UpdateCull( ctx );
+
+ if ( new_state & R128_NEW_MASKS )
+ r128UpdateMasks( ctx );
+
+ if ( new_state & R128_NEW_WINDOW )
+ r128UpdateWindow( ctx );
+
+ if ( rmesa->NewGLState & _NEW_TEXTURE ) {
+ r128UpdateTextureState( ctx );
+ }
+ }
+}
+
+
+static void r128DDInvalidateState( 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 );
+ R128_CONTEXT(ctx)->NewGLState |= new_state;
+}
+
+
+
+/* Initialize the context's hardware state.
+ */
+void r128DDInitState( r128ContextPtr rmesa )
+{
+ int dst_bpp, depth_bpp;
+
+ switch ( rmesa->r128Screen->cpp ) {
+ case 2:
+ dst_bpp = R128_GMC_DST_16BPP;
+ break;
+ case 4:
+ dst_bpp = R128_GMC_DST_32BPP;
+ break;
+ default:
+ fprintf( stderr, "Error: Unsupported pixel depth... exiting\n" );
+ exit( -1 );
+ }
+
+ rmesa->ClearColor = 0x00000000;
+
+ switch ( rmesa->glCtx->Visual.depthBits ) {
+ case 16:
+ rmesa->ClearDepth = 0x0000ffff;
+ depth_bpp = R128_Z_PIX_WIDTH_16;
+ rmesa->depth_scale = 1.0 / (GLfloat)0xffff;
+ break;
+ case 24:
+ rmesa->ClearDepth = 0x00ffffff;
+ depth_bpp = R128_Z_PIX_WIDTH_24;
+ rmesa->depth_scale = 1.0 / (GLfloat)0xffffff;
+ break;
+ default:
+ fprintf( stderr, "Error: Unsupported depth %d... exiting\n",
+ rmesa->glCtx->Visual.depthBits );
+ exit( -1 );
+ }
+
+ rmesa->Fallback = 0;
+
+ if ( rmesa->glCtx->Visual.doubleBufferMode && rmesa->sarea->pfCurrentPage == 0 ) {
+ rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->backOffset;
+ rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->backPitch;
+ } else {
+ rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->frontOffset;
+ rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->frontPitch;
+ }
+
+ /* Harware state:
+ */
+ rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) |
+ (rmesa->drawOffset >> 5));
+
+ rmesa->setup.dp_gui_master_cntl_c = (R128_GMC_DST_PITCH_OFFSET_CNTL |
+ R128_GMC_DST_CLIPPING |
+ R128_GMC_BRUSH_SOLID_COLOR |
+ dst_bpp |
+ R128_GMC_SRC_DATATYPE_COLOR |
+ R128_GMC_BYTE_MSB_TO_LSB |
+ R128_GMC_CONVERSION_TEMP_6500 |
+ R128_ROP3_S |
+ R128_DP_SRC_SOURCE_MEMORY |
+ R128_GMC_3D_FCN_EN |
+ R128_GMC_CLR_CMP_CNTL_DIS |
+ R128_GMC_AUX_CLIP_DIS |
+ R128_GMC_WR_MSK_DIS);
+
+ rmesa->setup.sc_top_left_c = 0x00000000;
+ rmesa->setup.sc_bottom_right_c = 0x1fff1fff;
+
+ rmesa->setup.z_offset_c = rmesa->r128Screen->depthOffset;
+ rmesa->setup.z_pitch_c = ((rmesa->r128Screen->depthPitch >> 3) |
+ R128_Z_TILE);
+
+ rmesa->setup.z_sten_cntl_c = (depth_bpp |
+ R128_Z_TEST_LESS |
+ R128_STENCIL_TEST_ALWAYS |
+ R128_STENCIL_S_FAIL_KEEP |
+ R128_STENCIL_ZPASS_KEEP |
+ R128_STENCIL_ZFAIL_KEEP);
+
+ rmesa->setup.tex_cntl_c = (R128_Z_WRITE_ENABLE |
+ R128_SHADE_ENABLE |
+ R128_DITHER_ENABLE |
+ R128_ALPHA_IN_TEX_COMPLETE_A |
+ R128_LIGHT_DIS |
+ R128_ALPHA_LIGHT_DIS |
+ R128_TEX_CACHE_FLUSH |
+ (0x3f << R128_LOD_BIAS_SHIFT));
+
+ rmesa->setup.misc_3d_state_cntl_reg = (R128_MISC_SCALE_3D_TEXMAP_SHADE |
+ R128_MISC_SCALE_PIX_REPLICATE |
+ R128_ALPHA_COMB_ADD_CLAMP |
+ R128_FOG_VERTEX |
+ R128_ALPHA_BLEND_SRC_ONE |
+ R128_ALPHA_BLEND_DST_ZERO |
+ R128_ALPHA_TEST_ALWAYS);
+
+ rmesa->setup.texture_clr_cmp_clr_c = 0x00000000;
+ rmesa->setup.texture_clr_cmp_msk_c = 0xffffffff;
+
+ rmesa->setup.fog_color_c = 0x00000000;
+
+ rmesa->setup.pm4_vc_fpu_setup = (R128_FRONT_DIR_CCW |
+ R128_BACKFACE_SOLID |
+ R128_FRONTFACE_SOLID |
+ R128_FPU_COLOR_GOURAUD |
+ R128_FPU_SUB_PIX_4BITS |
+ R128_FPU_MODE_3D |
+ R128_TRAP_BITS_DISABLE |
+ R128_XFACTOR_2 |
+ R128_YFACTOR_2 |
+ R128_FLAT_SHADE_VERTEX_OGL |
+ R128_FPU_ROUND_TRUNCATE |
+ R128_WM_SEL_8DW);
+
+ rmesa->setup.setup_cntl = (R128_COLOR_GOURAUD |
+ R128_PRIM_TYPE_TRI |
+ R128_TEXTURE_ST_MULT_W |
+ R128_STARTING_VERTEX_1 |
+ R128_ENDING_VERTEX_3 |
+ R128_SU_POLY_LINE_NOT_LAST |
+ R128_SUB_PIX_4BITS);
+
+ rmesa->setup.tex_size_pitch_c = 0x00000000;
+ rmesa->setup.constant_color_c = 0x00ffffff;
+
+ rmesa->setup.dp_write_mask = 0xffffffff;
+ rmesa->setup.sten_ref_mask_c = 0xffff0000;
+ rmesa->setup.plane_3d_mask_c = 0xffffffff;
+
+ rmesa->setup.window_xy_offset = 0x00000000;
+
+ rmesa->setup.scale_3d_cntl = (R128_SCALE_DITHER_TABLE |
+ R128_TEX_CACHE_SIZE_FULL |
+ R128_DITHER_INIT_RESET |
+ R128_SCALE_3D_TEXMAP_SHADE |
+ R128_SCALE_PIX_REPLICATE |
+ R128_ALPHA_COMB_ADD_CLAMP |
+ R128_FOG_VERTEX |
+ R128_ALPHA_BLEND_SRC_ONE |
+ R128_ALPHA_BLEND_DST_ZERO |
+ R128_ALPHA_TEST_ALWAYS |
+ R128_COMPOSITE_SHADOW_CMP_EQUAL |
+ R128_TEX_MAP_ALPHA_IN_TEXTURE |
+ R128_TEX_CACHE_LINE_SIZE_4QW);
+
+ rmesa->new_state = R128_NEW_ALL;
+}
+
+/* Initialize the driver's state functions.
+ */
+void r128DDInitStateFuncs( GLcontext *ctx )
+{
+ ctx->Driver.UpdateState = r128DDInvalidateState;
+
+ ctx->Driver.ClearIndex = NULL;
+ ctx->Driver.ClearColor = r128DDClearColor;
+ ctx->Driver.DrawBuffer = r128DDDrawBuffer;
+ ctx->Driver.ReadBuffer = r128DDReadBuffer;
+
+ ctx->Driver.IndexMask = NULL;
+ ctx->Driver.ColorMask = r128DDColorMask;
+ ctx->Driver.AlphaFunc = r128DDAlphaFunc;
+ ctx->Driver.BlendEquation = r128DDBlendEquation;
+ ctx->Driver.BlendFunc = r128DDBlendFunc;
+ ctx->Driver.BlendFuncSeparate = r128DDBlendFuncSeparate;
+ ctx->Driver.ClearDepth = r128DDClearDepth;
+ ctx->Driver.CullFace = r128DDCullFace;
+ ctx->Driver.FrontFace = r128DDFrontFace;
+ ctx->Driver.DepthFunc = r128DDDepthFunc;
+ ctx->Driver.DepthMask = r128DDDepthMask;
+ ctx->Driver.Enable = r128DDEnable;
+ ctx->Driver.Fogfv = r128DDFogfv;
+ ctx->Driver.Hint = NULL;
+ ctx->Driver.Lightfv = NULL;
+ ctx->Driver.LightModelfv = r128DDLightModelfv;
+ ctx->Driver.LogicOpcode = r128DDLogicOpCode;
+ ctx->Driver.PolygonMode = NULL;
+ ctx->Driver.PolygonStipple = r128DDPolygonStipple;
+ ctx->Driver.RenderMode = r128DDRenderMode;
+ ctx->Driver.Scissor = r128DDScissor;
+ ctx->Driver.ShadeModel = r128DDShadeModel;
+ ctx->Driver.ClearStencil = NULL;
+ ctx->Driver.StencilFunc = NULL;
+ ctx->Driver.StencilMask = NULL;
+ ctx->Driver.StencilOp = NULL;
+
+ ctx->Driver.DepthRange = r128DepthRange;
+ ctx->Driver.Viewport = r128Viewport;
+
+ /* 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;
+
+ /* 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/r128/r128_state.h b/src/mesa/drivers/dri/r128/r128_state.h
new file mode 100644
index 0000000000..c51ac23942
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_state.h
@@ -0,0 +1,54 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_state.h,v 1.3 2001/01/08 01:07:21 martin Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef __R128_STATE_H__
+#define __R128_STATE_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "r128_context.h"
+
+extern void r128DDInitState( r128ContextPtr rmesa );
+extern void r128DDInitStateFuncs( GLcontext *ctx );
+
+extern void r128DDUpdateState( GLcontext *ctx );
+extern void r128DDUpdateHWState( GLcontext *ctx );
+
+extern void r128UpdateWindow( GLcontext *ctx );
+
+extern void r128EmitHwStateLocked( r128ContextPtr rmesa );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/r128/r128_tex.c b/src/mesa/drivers/dri/r128/r128_tex.c
new file mode 100644
index 0000000000..2793a793a0
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_tex.c
@@ -0,0 +1,598 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.c,v 1.14 2002/11/05 17:46:08 tsi Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ * Brian Paul <brianp@valinux.com>
+ */
+
+#include "r128_context.h"
+#include "r128_state.h"
+#include "r128_ioctl.h"
+#include "r128_vb.h"
+#include "r128_tris.h"
+#include "r128_tex.h"
+#include "r128_texobj.h"
+
+#include "context.h"
+#include "macros.h"
+#include "simple_list.h"
+#include "enums.h"
+#include "texstore.h"
+#include "texformat.h"
+#include "teximage.h"
+#include "imports.h"
+#include "colormac.h"
+
+#define TEX_0 1
+#define TEX_1 2
+
+
+static void r128SetTexWrap( r128TexObjPtr t, GLenum swrap, GLenum twrap )
+{
+ t->setup.tex_cntl &= ~(R128_TEX_CLAMP_S_MASK | R128_TEX_CLAMP_T_MASK);
+
+ switch ( swrap ) {
+ case GL_CLAMP:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_S_BORDER_COLOR;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_S_CLAMP;
+ break;
+ case GL_REPEAT:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_S_WRAP;
+ break;
+ case GL_CLAMP_TO_BORDER:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_S_BORDER_COLOR;
+ break;
+ case GL_MIRRORED_REPEAT:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_S_MIRROR;
+ break;
+ }
+
+ switch ( twrap ) {
+ case GL_CLAMP:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_T_BORDER_COLOR;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_T_CLAMP;
+ break;
+ case GL_REPEAT:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_T_WRAP;
+ break;
+ case GL_CLAMP_TO_BORDER:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_T_BORDER_COLOR;
+ break;
+ case GL_MIRRORED_REPEAT:
+ t->setup.tex_cntl |= R128_TEX_CLAMP_T_MIRROR;
+ break;
+ }
+}
+
+static void r128SetTexFilter( r128TexObjPtr t, GLenum minf, GLenum magf )
+{
+ t->setup.tex_cntl &= ~(R128_MIN_BLEND_MASK | R128_MAG_BLEND_MASK);
+
+ switch ( minf ) {
+ case GL_NEAREST:
+ t->setup.tex_cntl |= R128_MIN_BLEND_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->setup.tex_cntl |= R128_MIN_BLEND_LINEAR;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ t->setup.tex_cntl |= R128_MIN_BLEND_MIPNEAREST;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ t->setup.tex_cntl |= R128_MIN_BLEND_MIPLINEAR;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ t->setup.tex_cntl |= R128_MIN_BLEND_LINEARMIPNEAREST;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ t->setup.tex_cntl |= R128_MIN_BLEND_LINEARMIPLINEAR;
+ break;
+ }
+
+ switch ( magf ) {
+ case GL_NEAREST:
+ t->setup.tex_cntl |= R128_MAG_BLEND_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->setup.tex_cntl |= R128_MAG_BLEND_LINEAR;
+ break;
+ }
+}
+
+static void r128SetTexBorderColor( r128TexObjPtr t, GLubyte c[4] )
+{
+ t->setup.tex_border_color = r128PackColor( 4, c[0], c[1], c[2], c[3] );
+}
+
+
+static r128TexObjPtr r128AllocTexObj( struct gl_texture_object *texObj )
+{
+ r128TexObjPtr t;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s( %p )\n", __FUNCTION__, texObj );
+ }
+
+ t = (r128TexObjPtr) CALLOC_STRUCT( r128_tex_obj );
+ texObj->DriverData = t;
+ if ( t != NULL ) {
+
+ /* Initialize non-image-dependent parts of the state:
+ */
+ t->base.tObj = texObj;
+
+ /* FIXME Something here to set initial values for other parts of
+ * FIXME t->setup?
+ */
+
+ make_empty_list( (driTextureObject *) t );
+
+ r128SetTexWrap( t, texObj->WrapS, texObj->WrapT );
+ r128SetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
+ r128SetTexBorderColor( t, texObj->_BorderChan );
+ }
+
+ return t;
+}
+
+
+/* Called by the _mesa_store_teximage[123]d() functions. */
+static const struct gl_texture_format *
+r128ChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+ GLenum format, GLenum type )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ (void) format;
+ (void) type;
+
+ switch ( internalFormat ) {
+ case GL_ALPHA:
+ case GL_ALPHA4:
+ case GL_ALPHA8:
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ case GL_COMPRESSED_ALPHA:
+ 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:
+ case GL_COMPRESSED_LUMINANCE_ALPHA:
+ case 4:
+ case GL_RGBA:
+ case GL_COMPRESSED_RGBA:
+ case GL_RGBA2:
+ case GL_RGB5_A1:
+ case GL_RGBA8:
+ case GL_RGB10_A2:
+ case GL_RGBA12:
+ case GL_RGBA16:
+ if (rmesa->r128Screen->cpp == 4)
+ return &_mesa_texformat_argb8888;
+ else
+ return &_mesa_texformat_argb4444;
+ case GL_RGBA4:
+ return &_mesa_texformat_argb4444;
+
+ case 3:
+ case GL_RGB:
+ case GL_COMPRESSED_RGB:
+ case GL_R3_G3_B2:
+ case GL_RGB4:
+ case GL_RGB5:
+ case GL_RGB8:
+ case GL_RGB10:
+ case GL_RGB12:
+ case GL_RGB16:
+ if (rmesa->r128Screen->cpp == 4)
+ return &_mesa_texformat_argb8888;
+ else
+ return &_mesa_texformat_rgb565;
+
+ case 1:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE4:
+ case GL_LUMINANCE8:
+ case GL_LUMINANCE12:
+ case GL_LUMINANCE16:
+ case GL_COMPRESSED_LUMINANCE:
+ if (rmesa->r128Screen->cpp == 4)
+ return &_mesa_texformat_argb8888; /* inefficient but accurate */
+ else
+ return &_mesa_texformat_rgb565;
+
+ case GL_INTENSITY4:
+ return &_mesa_texformat_argb4444;
+ case GL_INTENSITY:
+ case GL_INTENSITY8:
+ case GL_INTENSITY12:
+ case GL_INTENSITY16:
+ case GL_COMPRESSED_INTENSITY:
+ if (rmesa->r128Screen->cpp == 4)
+ return &_mesa_texformat_argb8888; /* inefficient but accurate */
+ else
+ return &_mesa_texformat_argb4444;
+
+ 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;
+
+ case GL_YCBCR_MESA:
+ if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
+ type == GL_UNSIGNED_BYTE)
+ return &_mesa_texformat_ycbcr;
+ else
+ return &_mesa_texformat_ycbcr_rev;
+
+ default:
+ _mesa_problem( ctx, "unexpected format in %s", __FUNCTION__ );
+ return NULL;
+ }
+}
+
+
+static void r128TexImage1D( GLcontext *ctx, GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, 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 )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+ if ( t ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) r128AllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
+ return;
+ }
+ }
+
+ /* Note, this will call r128ChooseTextureFormat */
+ _mesa_store_teximage1d( ctx, target, level, internalFormat,
+ width, border, format, type,
+ pixels, packing, texObj, texImage );
+
+ t->dirty_images[0] |= (1 << level);
+}
+
+
+static void r128TexSubImage1D( GLcontext *ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLsizei width,
+ GLenum format, GLenum type,
+ const GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+ assert( t ); /* this _should_ be true */
+ if ( t ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) r128AllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
+ return;
+ }
+ }
+
+ _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
+ format, type, pixels, packing, texObj,
+ texImage);
+
+ t->dirty_images[0] |= (1 << level);
+}
+
+
+static void r128TexImage2D( 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 )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+ if ( t ) {
+ driSwapOutTextureObject( (driTextureObject *) t );
+ }
+ else {
+ t = (driTextureObject *) r128AllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+ return;
+ }
+ }
+
+ /* Note, this will call r128ChooseTextureFormat */
+ _mesa_store_teximage2d(ctx, target, level, internalFormat,
+ width, height, border, format, type, pixels,
+ &ctx->Unpack, texObj, texImage);
+
+ t->dirty_images[0] |= (1 << level);
+}
+
+
+static void r128TexSubImage2D( 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 )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+ assert( t ); /* this _should_ be true */
+ if ( t ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) r128AllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+ return;
+ }
+ }
+
+ _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
+ height, format, type, pixels, packing, texObj,
+ texImage);
+ t->dirty_images[0] |= (1 << level);
+}
+
+
+static void r128DDTexEnv( GLcontext *ctx, GLenum target,
+ GLenum pname, const GLfloat *param )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit;
+ GLubyte c[4];
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s( %s )\n",
+ __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
+ }
+
+ switch ( pname ) {
+ case GL_TEXTURE_ENV_MODE:
+ FLUSH_BATCH( rmesa );
+ rmesa->new_state |= R128_NEW_ALPHA;
+ break;
+
+ case GL_TEXTURE_ENV_COLOR:
+ texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ CLAMPED_FLOAT_TO_UBYTE( c[0], texUnit->EnvColor[0] );
+ CLAMPED_FLOAT_TO_UBYTE( c[1], texUnit->EnvColor[1] );
+ CLAMPED_FLOAT_TO_UBYTE( c[2], texUnit->EnvColor[2] );
+ CLAMPED_FLOAT_TO_UBYTE( c[3], texUnit->EnvColor[3] );
+ rmesa->env_color = r128PackColor( 4, c[0], c[1], c[2], c[3] );
+ if ( rmesa->setup.constant_color_c != rmesa->env_color ) {
+ FLUSH_BATCH( rmesa );
+ rmesa->setup.constant_color_c = rmesa->env_color;
+
+ /* More complex multitexture/multipass fallbacks for GL_BLEND
+ * can be done later, but this allows a single pass GL_BLEND
+ * in some cases (ie. Performer town demo). This is only
+ * applicable to the regular Rage 128, as the Pro and M3 can
+ * handle true single-pass GL_BLEND texturing.
+ */
+ rmesa->blend_flags &= ~R128_BLEND_ENV_COLOR;
+ if ( R128_IS_PLAIN( rmesa ) &&
+ rmesa->env_color != 0x00000000 &&
+ rmesa->env_color != 0xff000000 &&
+ rmesa->env_color != 0x00ffffff &&
+ rmesa->env_color != 0xffffffff ) {
+ rmesa->blend_flags |= R128_BLEND_ENV_COLOR;
+ }
+ }
+ break;
+
+ case GL_TEXTURE_LOD_BIAS_EXT:
+ do {
+ CARD32 t = rmesa->setup.tex_cntl_c;
+ GLint bias;
+ CARD32 b;
+
+ /* GTH: This isn't exactly correct, but gives good results up to a
+ * certain point. It is better than completely ignoring the LOD
+ * bias. Unfortunately there isn't much range in the bias, the
+ * spec mentions strides that vary between 0.5 and 2.0 but these
+ * numbers don't seem to relate the the GL LOD bias value at all.
+ */
+ if ( param[0] >= 1.0 ) {
+ bias = -128;
+ } else if ( param[0] >= 0.5 ) {
+ bias = -64;
+ } else if ( param[0] >= 0.25 ) {
+ bias = 0;
+ } else if ( param[0] >= 0.0 ) {
+ bias = 63;
+ } else {
+ bias = 127;
+ }
+
+ b = (CARD32)bias & 0xff;
+ t &= ~R128_LOD_BIAS_MASK;
+ t |= (b << R128_LOD_BIAS_SHIFT);
+
+ if ( rmesa->setup.tex_cntl_c != t ) {
+ FLUSH_BATCH( rmesa );
+ rmesa->setup.tex_cntl_c = t;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+ } while (0);
+ break;
+
+ default:
+ return;
+ }
+}
+
+
+static void r128DDTexParameter( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *tObj,
+ GLenum pname, const GLfloat *params )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ r128TexObjPtr t = (r128TexObjPtr)tObj->DriverData;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s( %s )\n",
+ __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
+ }
+
+ if ( ( target != GL_TEXTURE_2D ) && ( target != GL_TEXTURE_1D ) )
+ return;
+
+ switch ( pname ) {
+ case GL_TEXTURE_MIN_FILTER:
+ case GL_TEXTURE_MAG_FILTER:
+ if ( t->base.bound ) FLUSH_BATCH( rmesa );
+ r128SetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
+ break;
+
+ case GL_TEXTURE_WRAP_S:
+ case GL_TEXTURE_WRAP_T:
+ if ( t->base.bound ) FLUSH_BATCH( rmesa );
+ r128SetTexWrap( t, tObj->WrapS, tObj->WrapT );
+ break;
+
+ case GL_TEXTURE_BORDER_COLOR:
+ if ( t->base.bound ) FLUSH_BATCH( rmesa );
+ r128SetTexBorderColor( t, tObj->_BorderChan );
+ break;
+
+ case GL_TEXTURE_BASE_LEVEL:
+ case GL_TEXTURE_MAX_LEVEL:
+ case GL_TEXTURE_MIN_LOD:
+ case GL_TEXTURE_MAX_LOD:
+ /* This isn't the most efficient solution but there doesn't appear to
+ * be a nice alternative for R128. Since there's no LOD clamping,
+ * we just have to rely on loading the right subset of mipmap levels
+ * to simulate a clamped LOD.
+ */
+ if ( t->base.bound ) FLUSH_BATCH( rmesa );
+ driSwapOutTextureObject( (driTextureObject *) t );
+ break;
+
+ default:
+ return;
+ }
+}
+
+static void r128DDBindTexture( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *tObj )
+{
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, tObj,
+ ctx->Texture.CurrentUnit );
+ }
+
+ if ( target == GL_TEXTURE_2D || target == GL_TEXTURE_1D ) {
+ if ( tObj->DriverData == NULL ) {
+ r128AllocTexObj( tObj );
+ }
+ }
+}
+
+static void r128DDDeleteTexture( GLcontext *ctx,
+ struct gl_texture_object *tObj )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ driTextureObject * t = (driTextureObject *) tObj->DriverData;
+
+ if ( t ) {
+ if ( t->bound && rmesa ) {
+ FLUSH_BATCH( rmesa );
+ }
+
+ driDestroyTextureObject( t );
+ }
+}
+
+void r128DDInitTextureFuncs( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+
+ ctx->Driver.TexEnv = r128DDTexEnv;
+ ctx->Driver.ChooseTextureFormat = r128ChooseTextureFormat;
+ ctx->Driver.TexImage1D = r128TexImage1D;
+ ctx->Driver.TexSubImage1D = r128TexSubImage1D;
+ ctx->Driver.TexImage2D = r128TexImage2D;
+ ctx->Driver.TexSubImage2D = r128TexSubImage2D;
+ ctx->Driver.TexImage3D = _mesa_store_teximage3d;
+ 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.TexParameter = r128DDTexParameter;
+ ctx->Driver.BindTexture = r128DDBindTexture;
+ ctx->Driver.DeleteTexture = r128DDDeleteTexture;
+ ctx->Driver.UpdateTexturePalette = NULL;
+ ctx->Driver.ActiveTexture = NULL;
+ ctx->Driver.IsTextureResident = driIsTextureResident;
+ ctx->Driver.PrioritizeTexture = NULL;
+
+ driInitTextureObjects( ctx, & rmesa->swapped,
+ DRI_TEXMGR_DO_TEXTURE_1D
+ | DRI_TEXMGR_DO_TEXTURE_2D );
+}
diff --git a/src/mesa/drivers/dri/r128/r128_tex.h b/src/mesa/drivers/dri/r128/r128_tex.h
new file mode 100644
index 0000000000..2e3d954fbb
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_tex.h
@@ -0,0 +1,88 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.h,v 1.7 2002/02/22 21:44:58 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef __R128_TEX_H__
+#define __R128_TEX_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void r128UpdateTextureState( GLcontext *ctx );
+
+extern void r128UploadTexImages( r128ContextPtr rmesa, r128TexObjPtr t );
+
+extern void r128DestroyTexObj( r128ContextPtr rmesa, r128TexObjPtr t );
+
+extern void r128DDInitTextureFuncs( GLcontext *ctx );
+
+
+/* ================================================================
+ * Color conversion macros:
+ */
+
+#define R128PACKCOLOR332( r, g, b ) \
+ (((r) & 0xe0) | (((g) & 0xe0) >> 3) | (((b) & 0xc0) >> 6))
+
+#define R128PACKCOLOR1555( r, g, b, a ) \
+ ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \
+ ((a) ? 0x8000 : 0))
+
+#define R128PACKCOLOR565( r, g, b ) \
+ ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3))
+
+#define R128PACKCOLOR888( r, g, b ) \
+ (((r) << 16) | ((g) << 8) | (b))
+
+#define R128PACKCOLOR8888( r, g, b, a ) \
+ (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+
+#define R128PACKCOLOR4444( r, g, b, a ) \
+ ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4))
+
+static __inline__ CARD32 r128PackColor( GLuint cpp,
+ GLubyte r, GLubyte g,
+ GLubyte b, GLubyte a )
+{
+ switch ( cpp ) {
+ case 2:
+ return R128PACKCOLOR565( r, g, b );
+ case 4:
+ return R128PACKCOLOR8888( r, g, b, a );
+ default:
+ return 0;
+ }
+}
+
+#endif
+#endif /* __R128_TEX_H__ */
diff --git a/src/mesa/drivers/dri/r128/r128_texmem.c b/src/mesa/drivers/dri/r128/r128_texmem.c
new file mode 100644
index 0000000000..f6a5dfbbcf
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_texmem.c
@@ -0,0 +1,302 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.c,v 1.7 2001/01/08 01:07:21 martin Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ * Brian Paul <brianp@valinux.com>
+ */
+
+#include "r128_context.h"
+#include "r128_state.h"
+#include "r128_ioctl.h"
+#include "r128_vb.h"
+#include "r128_tris.h"
+#include "r128_tex.h"
+
+#include "context.h"
+#include "macros.h"
+#include "simple_list.h"
+#include "texformat.h"
+#include "imports.h"
+
+#define TEX_0 1
+#define TEX_1 2
+
+
+/* Destroy hardware state associated with texture `t'.
+ */
+void r128DestroyTexObj( r128ContextPtr rmesa, r128TexObjPtr t )
+{
+ unsigned i;
+
+
+ /* See if it was the driver's current object.
+ */
+
+ if ( rmesa != NULL )
+ {
+ for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ )
+ {
+ if ( t == rmesa->CurrentTexObj[ i ] ) {
+ assert( t->base.bound & (1 << i) );
+ rmesa->CurrentTexObj[ i ] = NULL;
+ }
+ }
+ }
+}
+
+
+/**
+ * Upload the texture image associated with texture \a t at the specified
+ * level at the address relative to \a start.
+ */
+static void uploadSubImage( r128ContextPtr rmesa, r128TexObjPtr t,
+ GLint level,
+ GLint x, GLint y, GLint width, GLint height )
+{
+ struct gl_texture_image *image;
+ int texelsPerDword = 0;
+ int imageWidth, imageHeight;
+ int remaining, rows;
+ int format, dwords;
+ CARD32 pitch, offset;
+ int i;
+
+ /* Ensure we have a valid texture to upload */
+ if ( ( level < 0 ) || ( level > R128_MAX_TEXTURE_LEVELS ) )
+ return;
+
+ image = t->base.tObj->Image[level];
+ if ( !image )
+ return;
+
+ switch ( image->TexFormat->TexelBytes ) {
+ case 1: texelsPerDword = 4; break;
+ case 2: texelsPerDword = 2; break;
+ case 4: texelsPerDword = 1; break;
+ }
+
+#if 1
+ /* FIXME: The subimage index calcs are wrong... */
+ x = 0;
+ y = 0;
+ width = image->Width;
+ height = image->Height;
+#endif
+
+ imageWidth = image->Width;
+ imageHeight = image->Height;
+
+ format = t->textureFormat >> 16;
+
+ /* The texel upload routines have a minimum width, so force the size
+ * if needed.
+ */
+ if ( imageWidth < texelsPerDword ) {
+ int factor;
+
+ factor = texelsPerDword / imageWidth;
+ imageWidth = texelsPerDword;
+ imageHeight /= factor;
+ if ( imageHeight == 0 ) {
+ /* In this case, the texel converter will actually walk a
+ * texel or two off the end of the image, but normal malloc
+ * alignment should prevent it from ever causing a fault.
+ */
+ imageHeight = 1;
+ }
+ }
+
+ /* We can't upload to a pitch less than 8 texels so we will need to
+ * linearly upload all modified rows for textures smaller than this.
+ * This makes the x/y/width/height different for the blitter and the
+ * texture walker.
+ */
+ if ( imageWidth >= 8 ) {
+ /* The texture walker and the blitter look identical */
+ pitch = imageWidth >> 3;
+ } else {
+ int factor;
+ int y2;
+ int start, end;
+
+ start = (y * imageWidth) & ~7;
+ end = (y + height) * imageWidth;
+
+ if ( end - start < 8 ) {
+ /* Handle the case where the total number of texels
+ * uploaded is < 8.
+ */
+ x = 0;
+ y = start / 8;
+ width = end - start;
+ height = 1;
+ } else {
+ /* Upload some number of full 8 texel blit rows */
+ factor = 8 / imageWidth;
+
+ y2 = y + height - 1;
+ y /= factor;
+ y2 /= factor;
+
+ x = 0;
+ width = 8;
+ height = y2 - y + 1;
+ }
+
+ /* Fixed pitch of 8 */
+ pitch = 1;
+ }
+
+ dwords = width * height / texelsPerDword;
+ offset = t->bufAddr + t->image[level - t->base.firstLevel].offset;
+
+#if ENABLE_PERF_BOXES
+ /* Bump the performace counter */
+ rmesa->c_textureBytes += (dwords << 2);
+#endif
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "r128UploadSubImage: %d,%d of %d,%d at %d,%d\n",
+ width, height, image->Width, image->Height, x, y );
+ fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d "
+ "level: %d format: %x\n",
+ (GLuint)offset, (GLuint)pitch, dwords, level, format );
+ }
+
+ /* Subdivide the texture if required */
+ if ( dwords <= R128_BUFFER_MAX_DWORDS / 2 ) {
+ rows = height;
+ } else {
+ rows = (R128_BUFFER_MAX_DWORDS * texelsPerDword) / (2 * width);
+ }
+
+ for ( i = 0, remaining = height ;
+ remaining > 0 ;
+ remaining -= rows, y += rows, i++ )
+ {
+ CARD32 *dst;
+ drmBufPtr buffer;
+
+ assert(image->Data);
+
+ height = MIN2(remaining, rows);
+
+ /* Grab the indirect buffer for the texture blit */
+ LOCK_HARDWARE( rmesa );
+ buffer = r128GetBufferLocked( rmesa );
+
+ dst = (CARD32 *)((char *)buffer->address + R128_HOSTDATA_BLIT_OFFSET);
+
+ /* Copy the next chunck of the texture image into the blit buffer */
+ {
+ const GLubyte *src = (const GLubyte *) image->Data +
+ (y * image->Width + x) * image->TexFormat->TexelBytes;
+ const GLuint bytes = width * height * image->TexFormat->TexelBytes;
+ memcpy(dst, src, bytes);
+ }
+
+ r128FireBlitLocked( rmesa, buffer,
+ offset, pitch, format,
+ x, y, width, height );
+ UNLOCK_HARDWARE( rmesa );
+ }
+
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
+}
+
+
+/* Upload the texture images associated with texture `t'. This might
+ * require removing our own and/or other client's texture objects to
+ * make room for these images.
+ */
+void r128UploadTexImages( r128ContextPtr rmesa, r128TexObjPtr t )
+{
+ const GLint numLevels = t->base.lastLevel - t->base.firstLevel + 1;
+ GLint i;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s( %p, %p )\n",
+ __FUNCTION__, rmesa->glCtx, t );
+ }
+
+ assert(t);
+
+ LOCK_HARDWARE( rmesa );
+
+ if ( !t->base.memBlock ) {
+ int heap;
+
+
+ heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps,
+ (driTextureObject *) t );
+ if ( heap == -1 ) {
+ UNLOCK_HARDWARE( rmesa );
+ return;
+ }
+
+ /* Set the base offset of the texture image */
+ t->bufAddr = rmesa->r128Screen->texOffset[heap]
+ + t->base.memBlock->ofs;
+
+ /* Set texture offsets for each mipmap level */
+ if ( t->setup.tex_cntl & R128_MIP_MAP_DISABLE ) {
+ for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) {
+ t->setup.tex_offset[i] = t->bufAddr;
+ }
+ } else {
+ for ( i = 0; i < numLevels; i++ ) {
+ const int j = numLevels - i - 1;
+ t->setup.tex_offset[j] = t->bufAddr + t->image[i].offset;
+ }
+ }
+ }
+
+ /* Let the world know we've used this memory recently.
+ */
+ driUpdateTextureLRU( (driTextureObject *) t );
+ UNLOCK_HARDWARE( rmesa );
+
+ /* Upload any images that are new */
+ if ( t->base.dirty_images[0] ) {
+ for ( i = 0 ; i < numLevels; i++ ) {
+ const GLint j = t->base.firstLevel + i; /* the texObj's level */
+ if ( t->base.dirty_images[0] & (1 << j) ) {
+ uploadSubImage( rmesa, t, j, 0, 0,
+ t->image[i].width, t->image[i].height );
+ }
+ }
+
+ rmesa->setup.tex_cntl_c |= R128_TEX_CACHE_FLUSH;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ t->base.dirty_images[0] = 0;
+ }
+}
diff --git a/src/mesa/drivers/dri/r128/r128_texobj.h b/src/mesa/drivers/dri/r128/r128_texobj.h
new file mode 100644
index 0000000000..e2ff1ac24d
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_texobj.h
@@ -0,0 +1,69 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_texobj.h,v 1.5 2002/02/22 21:44:58 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef _R128_TEXOBJ_H_
+#define _R128_TEXOBJ_H_
+
+#include "r128_sarea.h"
+#include "mm.h"
+
+/* Individual texture image information.
+ */
+typedef struct {
+ GLuint offset; /* Relative to local texture space */
+ GLuint width;
+ GLuint height;
+} r128TexImage;
+
+typedef struct r128_tex_obj r128TexObj, *r128TexObjPtr;
+
+/* Texture object in locally shared texture space.
+ */
+struct r128_tex_obj {
+ driTextureObject base;
+
+ CARD32 bufAddr; /* Offset to start of locally
+ shared texture block */
+
+ GLuint age;
+ r128TexImage image[R128_MAX_TEXTURE_LEVELS]; /* Image data for all
+ mipmap levels */
+
+ CARD32 textureFormat; /* Actual hardware format */
+
+ r128_texture_regs_t setup; /* Setup regs for texture */
+};
+
+#endif /* _R128_TEXOBJ_H_ */
diff --git a/src/mesa/drivers/dri/r128/r128_texstate.c b/src/mesa/drivers/dri/r128/r128_texstate.c
new file mode 100644
index 0000000000..3f4347b02e
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_texstate.c
@@ -0,0 +1,652 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.c,v 1.7 2001/01/08 01:07:21 martin Exp $ */
+/**************************************************************************
+
+Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
+ Cedar Park, Texas.
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ * Brian Paul <brianp@valinux.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "macros.h"
+#include "texformat.h"
+
+#include "r128_context.h"
+#include "r128_state.h"
+#include "r128_ioctl.h"
+#include "r128_vb.h"
+#include "r128_tris.h"
+#include "r128_tex.h"
+
+
+static void r128SetTexImages( r128ContextPtr rmesa,
+ const struct gl_texture_object *tObj )
+{
+ r128TexObjPtr t = (r128TexObjPtr) tObj->DriverData;
+ struct gl_texture_image *baseImage = tObj->Image[tObj->BaseLevel];
+ int log2Pitch, log2Height, log2Size, log2MinSize;
+ int totalSize;
+ int i;
+ GLint firstLevel, lastLevel;
+
+ assert(t);
+ assert(baseImage);
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API )
+ fprintf( stderr, "%s( %p )\n", __FUNCTION__, tObj );
+
+ switch (baseImage->TexFormat->MesaFormat) {
+ case MESA_FORMAT_ARGB8888:
+ t->textureFormat = R128_DATATYPE_ARGB8888;
+ break;
+ case MESA_FORMAT_ARGB4444:
+ t->textureFormat = R128_DATATYPE_ARGB4444;
+ break;
+ case MESA_FORMAT_RGB565:
+ t->textureFormat = R128_DATATYPE_RGB565;
+ break;
+ case MESA_FORMAT_RGB332:
+ t->textureFormat = R128_DATATYPE_RGB8;
+ break;
+ case MESA_FORMAT_CI8:
+ t->textureFormat = R128_DATATYPE_CI8;
+ break;
+ case MESA_FORMAT_YCBCR:
+ t->textureFormat = R128_DATATYPE_YVYU422;
+ break;
+ case MESA_FORMAT_YCBCR_REV:
+ t->textureFormat = R128_DATATYPE_VYUY422;
+ break;
+ default:
+ _mesa_problem(rmesa->glCtx, "Bad texture format in %s", __FUNCTION__);
+ };
+
+ /* Compute which mipmap levels we really want to send to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ * Yes, this looks overly complicated, but it's all needed.
+ */
+ firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5);
+ firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ lastLevel = tObj->BaseLevel + (GLint) (tObj->MaxLod + 0.5);
+ lastLevel = MAX2(lastLevel, tObj->BaseLevel);
+ lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = MIN2(lastLevel, tObj->MaxLevel);
+ lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
+
+ log2Pitch = tObj->Image[firstLevel]->WidthLog2;
+ log2Height = tObj->Image[firstLevel]->HeightLog2;
+ log2Size = MAX2(log2Pitch, log2Height);
+ log2MinSize = log2Size;
+
+ t->base.dirty_images[0] = 0;
+ totalSize = 0;
+ for ( i = firstLevel; i <= lastLevel; i++ ) {
+ const struct gl_texture_image *texImage;
+
+ texImage = tObj->Image[i];
+ if ( !texImage || !texImage->Data ) {
+ lastLevel = i - 1;
+ break;
+ }
+
+ log2MinSize = texImage->MaxLog2;
+
+ t->image[i - firstLevel].offset = totalSize;
+ t->image[i - firstLevel].width = tObj->Image[i]->Width;
+ t->image[i - firstLevel].height = tObj->Image[i]->Height;
+
+ t->base.dirty_images[0] |= (1 << i);
+
+ totalSize += (tObj->Image[i]->Height *
+ tObj->Image[i]->Width *
+ tObj->Image[i]->TexFormat->TexelBytes);
+
+ /* Offsets must be 32-byte aligned for host data blits and tiling */
+ totalSize = (totalSize + 31) & ~31;
+ }
+
+ t->base.totalSize = totalSize;
+ t->base.firstLevel = firstLevel;
+ t->base.lastLevel = lastLevel;
+
+ /* Set the texture format */
+ t->setup.tex_cntl &= ~(0xf << 16);
+ t->setup.tex_cntl |= t->textureFormat;
+
+ t->setup.tex_combine_cntl = 0x00000000; /* XXX is this right? */
+
+ t->setup.tex_size_pitch = ((log2Pitch << R128_TEX_PITCH_SHIFT) |
+ (log2Size << R128_TEX_SIZE_SHIFT) |
+ (log2Height << R128_TEX_HEIGHT_SHIFT) |
+ (log2MinSize << R128_TEX_MIN_SIZE_SHIFT));
+
+ for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) {
+ t->setup.tex_offset[i] = 0x00000000;
+ }
+
+ if (firstLevel == lastLevel)
+ t->setup.tex_cntl |= R128_MIP_MAP_DISABLE;
+ else
+ t->setup.tex_cntl &= ~R128_MIP_MAP_DISABLE;
+
+ /* FYI: r128UploadTexImages( rmesa, t ); used to be called here */
+}
+
+
+/* ================================================================
+ * Texture combine functions
+ */
+
+#define COLOR_COMB_DISABLE (R128_COMB_DIS | \
+ R128_COLOR_FACTOR_TEX)
+#define COLOR_COMB_COPY_INPUT (R128_COMB_COPY_INP | \
+ R128_COLOR_FACTOR_TEX)
+#define COLOR_COMB_MODULATE (R128_COMB_MODULATE | \
+ R128_COLOR_FACTOR_TEX)
+#define COLOR_COMB_MODULATE_NTEX (R128_COMB_MODULATE | \
+ R128_COLOR_FACTOR_NTEX)
+#define COLOR_COMB_ADD (R128_COMB_ADD | \
+ R128_COLOR_FACTOR_TEX)
+#define COLOR_COMB_BLEND_TEX (R128_COMB_BLEND_TEXTURE | \
+ R128_COLOR_FACTOR_TEX)
+/* Rage 128 Pro/M3 only! */
+#define COLOR_COMB_BLEND_COLOR (R128_COMB_MODULATE2X | \
+ R128_COMB_FCN_MSB | \
+ R128_COLOR_FACTOR_CONST_COLOR)
+
+#define ALPHA_COMB_DISABLE (R128_COMB_ALPHA_DIS | \
+ R128_ALPHA_FACTOR_TEX_ALPHA)
+#define ALPHA_COMB_COPY_INPUT (R128_COMB_ALPHA_COPY_INP | \
+ R128_ALPHA_FACTOR_TEX_ALPHA)
+#define ALPHA_COMB_MODULATE (R128_COMB_ALPHA_MODULATE | \
+ R128_ALPHA_FACTOR_TEX_ALPHA)
+#define ALPHA_COMB_MODULATE_NTEX (R128_COMB_ALPHA_MODULATE | \
+ R128_ALPHA_FACTOR_NTEX_ALPHA)
+#define ALPHA_COMB_ADD (R128_COMB_ALPHA_ADD | \
+ R128_ALPHA_FACTOR_TEX_ALPHA)
+
+#define INPUT_INTERP (R128_INPUT_FACTOR_INT_COLOR | \
+ R128_INP_FACTOR_A_INT_ALPHA)
+#define INPUT_PREVIOUS (R128_INPUT_FACTOR_PREV_COLOR | \
+ R128_INP_FACTOR_A_PREV_ALPHA)
+
+static GLboolean r128UpdateTextureEnv( GLcontext *ctx, int unit )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLint source = rmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ const GLenum format = tObj->Image[tObj->BaseLevel]->Format;
+ GLuint combine;
+
+ if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
+ fprintf( stderr, "%s( %p, %d )\n",
+ __FUNCTION__, ctx, unit );
+ }
+
+ if ( unit == 0 ) {
+ combine = INPUT_INTERP;
+ } else {
+ combine = INPUT_PREVIOUS;
+ }
+
+ /* Set the texture environment state */
+ switch ( texUnit->EnvMode ) {
+ case GL_REPLACE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ combine |= (COLOR_COMB_DISABLE | /* C = Ct */
+ ALPHA_COMB_DISABLE); /* A = At */
+ break;
+ case GL_RGB:
+ case GL_LUMINANCE:
+ combine |= (COLOR_COMB_DISABLE | /* C = Ct */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ break;
+ case GL_ALPHA:
+ combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */
+ ALPHA_COMB_DISABLE); /* A = At */
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_MODULATE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ combine |= (COLOR_COMB_MODULATE | /* C = CfCt */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ break;
+ case GL_RGB:
+ case GL_LUMINANCE:
+ combine |= (COLOR_COMB_MODULATE | /* C = CfCt */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ break;
+ case GL_ALPHA:
+ combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_DECAL:
+ switch ( format ) {
+ case GL_RGBA:
+ combine |= (COLOR_COMB_BLEND_TEX | /* C = Cf(1-At)+CtAt */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ break;
+ case GL_RGB:
+ combine |= (COLOR_COMB_DISABLE | /* C = Ct */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ break;
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ /* Undefined behaviour - just copy the incoming fragment */
+ combine |= (COLOR_COMB_COPY_INPUT | /* C = undefined */
+ ALPHA_COMB_COPY_INPUT); /* A = undefined */
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_BLEND:
+ /* Rage 128 Pro and M3 can handle GL_BLEND texturing.
+ */
+ if ( !R128_IS_PLAIN( rmesa ) ) {
+ /* XXX this hasn't been fully tested, I don't have a Pro card. -BP */
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_LUMINANCE_ALPHA:
+ combine |= (COLOR_COMB_BLEND_COLOR | /* C = Cf(1-Ct)+CcCt */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ break;
+
+ case GL_RGB:
+ case GL_LUMINANCE:
+ combine |= (COLOR_COMB_BLEND_COLOR | /* C = Cf(1-Ct)+CcCt */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ break;
+
+ case GL_ALPHA:
+ combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ break;
+
+ case GL_INTENSITY:
+ /* GH: We could be smarter about this... */
+ switch ( rmesa->env_color & 0xff000000 ) {
+ case 0x00000000:
+ combine |= (COLOR_COMB_BLEND_COLOR | /* C = Cf(1-It)+CcIt */
+ ALPHA_COMB_MODULATE_NTEX); /* A = Af(1-It) */
+ default:
+ combine |= (COLOR_COMB_MODULATE | /* C = fallback */
+ ALPHA_COMB_MODULATE); /* A = fallback */
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+ }
+
+ /* Rage 128 has to fake some cases of GL_BLEND, otherwise fallback
+ * to software rendering.
+ */
+ if ( rmesa->blend_flags ) {
+ return GL_FALSE;
+ }
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_LUMINANCE_ALPHA:
+ switch ( rmesa->env_color & 0x00ffffff ) {
+ case 0x00000000:
+ combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ break;
+#if 0
+ /* This isn't right - BP */
+ case 0x00ffffff:
+ if ( unit == 0 ) {
+ combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ } else {
+ combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ }
+ break;
+#endif
+ default:
+ combine |= (COLOR_COMB_MODULATE | /* C = fallback */
+ ALPHA_COMB_MODULATE); /* A = fallback */
+ return GL_FALSE;
+ }
+ break;
+ case GL_RGB:
+ case GL_LUMINANCE:
+ switch ( rmesa->env_color & 0x00ffffff ) {
+ case 0x00000000:
+ combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ break;
+#if 0
+ /* This isn't right - BP */
+ case 0x00ffffff:
+ if ( unit == 0 ) {
+ combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ } else {
+ combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ }
+ break;
+#endif
+ default:
+ combine |= (COLOR_COMB_MODULATE | /* C = fallback */
+ ALPHA_COMB_COPY_INPUT); /* A = fallback */
+ return GL_FALSE;
+ }
+ break;
+ case GL_ALPHA:
+ if ( unit == 0 ) {
+ combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ } else {
+ combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ }
+ break;
+ case GL_INTENSITY:
+ switch ( rmesa->env_color & 0x00ffffff ) {
+ case 0x00000000:
+ combine |= COLOR_COMB_MODULATE_NTEX; /* C = Cf(1-It) */
+ break;
+#if 0
+ /* This isn't right - BP */
+ case 0x00ffffff:
+ if ( unit == 0 ) {
+ combine |= COLOR_COMB_MODULATE_NTEX; /* C = Cf(1-It) */
+ } else {
+ combine |= COLOR_COMB_ADD; /* C = Cf+It */
+ }
+ break;
+#endif
+ default:
+ combine |= (COLOR_COMB_MODULATE | /* C = fallback */
+ ALPHA_COMB_MODULATE); /* A = fallback */
+ return GL_FALSE;
+ }
+ switch ( rmesa->env_color & 0xff000000 ) {
+ case 0x00000000:
+ combine |= ALPHA_COMB_MODULATE_NTEX; /* A = Af(1-It) */
+ break;
+#if 0
+ /* This isn't right - BP */
+ case 0xff000000:
+ if ( unit == 0 ) {
+ combine |= ALPHA_COMB_MODULATE_NTEX; /* A = Af(1-It) */
+ } else {
+ combine |= ALPHA_COMB_ADD; /* A = Af+It */
+ }
+ break;
+#endif
+ default:
+ combine |= (COLOR_COMB_MODULATE | /* C = fallback */
+ ALPHA_COMB_MODULATE); /* A = fallback */
+ return GL_FALSE;
+ }
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_ADD:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_LUMINANCE_ALPHA:
+ combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ break;
+ case GL_RGB:
+ case GL_LUMINANCE:
+ combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */
+ ALPHA_COMB_COPY_INPUT); /* A = Af */
+ break;
+ case GL_ALPHA:
+ combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */
+ ALPHA_COMB_MODULATE); /* A = AfAt */
+ break;
+ case GL_INTENSITY:
+ combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */
+ ALPHA_COMB_ADD); /* A = Af+At */
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ default:
+ return GL_FALSE;
+ }
+
+ if ( rmesa->tex_combine[unit] != combine ) {
+ rmesa->tex_combine[unit] = combine;
+ rmesa->dirty |= R128_UPLOAD_TEX0 << unit;
+ }
+ return GL_TRUE;
+}
+
+static void disable_tex( GLcontext *ctx, int unit )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ FLUSH_BATCH( rmesa );
+
+ if ( rmesa->CurrentTexObj[unit] ) {
+ rmesa->CurrentTexObj[unit]->base.bound &= ~(1 << unit);
+ rmesa->CurrentTexObj[unit] = NULL;
+ }
+
+ rmesa->setup.tex_cntl_c &= ~(R128_TEXMAP_ENABLE << unit);
+ rmesa->setup.tex_size_pitch_c &= ~(R128_TEX_SIZE_PITCH_MASK <<
+ (R128_SEC_TEX_SIZE_PITCH_SHIFT * unit));
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+
+ /* If either texture unit is disabled, then multitexturing is not
+ * happening.
+ */
+
+ rmesa->blend_flags &= ~R128_BLEND_MULTITEX;
+}
+
+static GLboolean enable_tex_2d( GLcontext *ctx, int unit )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ const int source = rmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ r128TexObjPtr t = (r128TexObjPtr) tObj->DriverData;
+
+ /* Need to load the 2d images associated with this unit.
+ */
+ if ( t->base.dirty_images[0] ) {
+ /* FIXME: For Radeon, RADEON_FIREVERTICES is called here. Should
+ * FIXME: something similar be done for R128?
+ */
+ /* FLUSH_BATCH( rmesa ); */
+
+ r128SetTexImages( rmesa, tObj );
+ r128UploadTexImages( rmesa, t );
+ if ( !t->base.memBlock )
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean update_tex_common( GLcontext *ctx, int unit )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ const int source = rmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ r128TexObjPtr t = (r128TexObjPtr) tObj->DriverData;
+
+
+ /* Fallback if there's a texture border */
+ if ( tObj->Image[tObj->BaseLevel]->Border > 0 ) {
+ return GL_FALSE;
+ }
+
+
+ /* Update state if this is a different texture object to last
+ * time.
+ */
+ if ( rmesa->CurrentTexObj[unit] != t ) {
+ if ( rmesa->CurrentTexObj[unit] != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ rmesa->CurrentTexObj[unit]->base.bound &=
+ ~(1UL << unit);
+ }
+
+ rmesa->CurrentTexObj[unit] = t;
+ t->base.bound |= (1UL << unit);
+ rmesa->dirty |= R128_UPLOAD_TEX0 << unit;
+
+ driUpdateTextureLRU( (driTextureObject *) t ); /* XXX: should be locked! */
+ }
+
+ /* FIXME: We need to update the texture unit if any texture parameters have
+ * changed, but this texture was already bound. This could be changed to
+ * work like the Radeon driver where the texture object has it's own
+ * dirty state flags
+ */
+ rmesa->dirty |= R128_UPLOAD_TEX0 << unit;
+
+ /* register setup */
+ rmesa->setup.tex_size_pitch_c &= ~(R128_TEX_SIZE_PITCH_MASK <<
+ (R128_SEC_TEX_SIZE_PITCH_SHIFT * unit));
+
+ if ( unit == 0 ) {
+ rmesa->setup.tex_cntl_c |= R128_TEXMAP_ENABLE;
+ rmesa->setup.tex_size_pitch_c |= t->setup.tex_size_pitch << 0;
+ rmesa->setup.scale_3d_cntl &= ~R128_TEX_CACHE_SPLIT;
+ t->setup.tex_cntl &= ~R128_SEC_SELECT_SEC_ST;
+ }
+ else {
+ rmesa->setup.tex_cntl_c |= R128_SEC_TEXMAP_ENABLE;
+ rmesa->setup.tex_size_pitch_c |= t->setup.tex_size_pitch << 16;
+ rmesa->setup.scale_3d_cntl |= R128_TEX_CACHE_SPLIT;
+ t->setup.tex_cntl |= R128_SEC_SELECT_SEC_ST;
+
+ /* If the second TMU is enabled, then multitexturing is happening.
+ */
+ if ( R128_IS_PLAIN( rmesa ) )
+ rmesa->blend_flags |= R128_BLEND_MULTITEX;
+ }
+
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+
+
+ /* FIXME: The Radeon has some cached state so that it can avoid calling
+ * FIXME: UpdateTextureEnv in some cases. Is that possible here?
+ */
+ return r128UpdateTextureEnv( ctx, unit );
+}
+
+static GLboolean updateTextureUnit( GLcontext *ctx, int unit )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ const int source = rmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+
+
+ if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) {
+ return (enable_tex_2d( ctx, unit ) &&
+ update_tex_common( ctx, unit ));
+ }
+ else if ( texUnit->_ReallyEnabled ) {
+ return GL_FALSE;
+ }
+ else {
+ disable_tex( ctx, unit );
+ return GL_TRUE;
+ }
+}
+
+
+void r128UpdateTextureState( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLboolean ok;
+
+
+ /* This works around a quirk with the R128 hardware. If only OpenGL
+ * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The
+ * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used.
+ */
+
+ rmesa->tmu_source[0] = 0;
+ rmesa->tmu_source[1] = 1;
+
+ if ((ctx->Texture._EnabledUnits & 0x03) == 0x02) {
+ /* only texture 1 enabled */
+ rmesa->tmu_source[0] = 1;
+ rmesa->tmu_source[1] = 0;
+ }
+
+ ok = (updateTextureUnit( ctx, 0 ) &&
+ updateTextureUnit( ctx, 1 ));
+
+ FALLBACK( rmesa, R128_FALLBACK_TEXTURE, !ok );
+}
diff --git a/src/mesa/drivers/dri/r128/r128_tris.c b/src/mesa/drivers/dri/r128/r128_tris.c
new file mode 100644
index 0000000000..4e2860288e
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_tris.c
@@ -0,0 +1,721 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tris.c,v 1.8 2002/10/30 12:51:43 alanh Exp $ */ /* -*- c-basic-offset: 3 -*- */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "colormac.h"
+#include "macros.h"
+
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
+
+#include "r128_tris.h"
+#include "r128_state.h"
+#include "r128_tex.h"
+#include "r128_vb.h"
+#include "r128_ioctl.h"
+
+static const GLuint hw_prim[GL_POLYGON+1] = {
+ R128_CCE_VC_CNTL_PRIM_TYPE_POINT,
+ R128_CCE_VC_CNTL_PRIM_TYPE_LINE,
+ R128_CCE_VC_CNTL_PRIM_TYPE_LINE,
+ R128_CCE_VC_CNTL_PRIM_TYPE_LINE,
+ R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST,
+};
+
+static void r128RasterPrimitive( GLcontext *ctx, GLuint hwprim );
+static void r128RenderPrimitive( GLcontext *ctx, GLenum prim );
+
+
+/***********************************************************************
+ * Emit primitives as inline vertices *
+ ***********************************************************************/
+
+#if defined(USE_X86_ASM)
+#define COPY_DWORDS( j, vb, vertsize, v ) \
+do { \
+ int __tmp; \
+ __asm__ __volatile__( "rep ; movsl" \
+ : "=%c" (j), "=D" (vb), "=S" (__tmp) \
+ : "0" (vertsize), \
+ "D" ((long)vb), \
+ "S" ((long)v) ); \
+} while (0)
+#else
+#define COPY_DWORDS( j, vb, vertsize, v ) \
+do { \
+ for ( j = 0 ; j < vertsize ; j++ ) \
+ vb[j] = CPU_TO_LE32(((GLuint *)v)[j]); \
+ vb += vertsize; \
+} while (0)
+#endif
+
+static __inline void r128_draw_quad( r128ContextPtr rmesa,
+ r128VertexPtr v0,
+ r128VertexPtr v1,
+ r128VertexPtr v2,
+ r128VertexPtr v3 )
+{
+ GLuint vertsize = rmesa->vertex_size;
+ GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, 6 * vertsize * 4 );
+ GLuint j;
+
+ rmesa->num_verts += 6;
+ COPY_DWORDS( j, vb, vertsize, v0 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+ COPY_DWORDS( j, vb, vertsize, v3 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+ COPY_DWORDS( j, vb, vertsize, v2 );
+ COPY_DWORDS( j, vb, vertsize, v3 );
+}
+
+
+static __inline void r128_draw_triangle( r128ContextPtr rmesa,
+ r128VertexPtr v0,
+ r128VertexPtr v1,
+ r128VertexPtr v2 )
+{
+ GLuint vertsize = rmesa->vertex_size;
+ GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, 3 * vertsize * 4 );
+ GLuint j;
+
+ rmesa->num_verts += 3;
+ COPY_DWORDS( j, vb, vertsize, v0 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+ COPY_DWORDS( j, vb, vertsize, v2 );
+}
+
+static __inline void r128_draw_line( r128ContextPtr rmesa,
+ r128VertexPtr v0,
+ r128VertexPtr v1 )
+{
+ GLuint vertsize = rmesa->vertex_size;
+ GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, 2 * vertsize * 4 );
+ GLuint j;
+
+ rmesa->num_verts += 2;
+ COPY_DWORDS( j, vb, vertsize, v0 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+}
+
+static __inline void r128_draw_point( r128ContextPtr rmesa,
+ r128VertexPtr v0 )
+{
+ int vertsize = rmesa->vertex_size;
+ GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, vertsize * 4 );
+ int j;
+
+ rmesa->num_verts += 1;
+ COPY_DWORDS( j, vb, vertsize, v0 );
+}
+
+/***********************************************************************
+ * Macros for t_dd_tritmp.h to draw basic primitives *
+ ***********************************************************************/
+
+#define TRI( a, b, c ) \
+do { \
+ if (DO_FALLBACK) \
+ rmesa->draw_tri( rmesa, a, b, c ); \
+ else \
+ r128_draw_triangle( rmesa, a, b, c ); \
+} while (0)
+
+#define QUAD( a, b, c, d ) \
+do { \
+ if (DO_FALLBACK) { \
+ rmesa->draw_tri( rmesa, a, b, d ); \
+ rmesa->draw_tri( rmesa, b, c, d ); \
+ } else \
+ r128_draw_quad( rmesa, a, b, c, d ); \
+} while (0)
+
+#define LINE( v0, v1 ) \
+do { \
+ if (DO_FALLBACK) \
+ rmesa->draw_line( rmesa, v0, v1 ); \
+ else \
+ r128_draw_line( rmesa, v0, v1 ); \
+} while (0)
+
+#define POINT( v0 ) \
+do { \
+ if (DO_FALLBACK) \
+ rmesa->draw_point( rmesa, v0 ); \
+ else \
+ r128_draw_point( rmesa, v0 ); \
+} while (0)
+
+
+/***********************************************************************
+ * Build render functions from dd templates *
+ ***********************************************************************/
+
+#define R128_OFFSET_BIT 0x01
+#define R128_TWOSIDE_BIT 0x02
+#define R128_UNFILLED_BIT 0x04
+#define R128_FALLBACK_BIT 0x08
+#define R128_MAX_TRIFUNC 0x10
+
+
+static struct {
+ points_func points;
+ line_func line;
+ triangle_func triangle;
+ quad_func quad;
+} rast_tab[R128_MAX_TRIFUNC];
+
+
+#define DO_FALLBACK (IND & R128_FALLBACK_BIT)
+#define DO_OFFSET (IND & R128_OFFSET_BIT)
+#define DO_UNFILLED (IND & R128_UNFILLED_BIT)
+#define DO_TWOSIDE (IND & R128_TWOSIDE_BIT)
+#define DO_FLAT 0
+#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 1
+#define HAVE_BACK_COLORS 0
+#define HAVE_HW_FLATSHADE 1
+#define VERTEX r128Vertex
+#define TAB rast_tab
+
+#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) (rmesa->verts + (e<<rmesa->vertex_stride_shift))
+
+#define VERT_SET_RGBA( v, c ) do { \
+ r128_color_t *vc = (r128_color_t *)&(v)->ui[coloroffset]; \
+ vc->blue = (c)[2]; \
+ vc->green = (c)[1]; \
+ vc->red = (c)[0]; \
+ vc->alpha = (c)[3]; \
+ } while (0)
+#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 VERT_SET_SPEC( v0, c ) if (havespec) { \
+ (v0)->v.specular.red = (c)[0];\
+ (v0)->v.specular.green = (c)[1];\
+ (v0)->v.specular.blue = (c)[2]; }
+#define VERT_COPY_SPEC( v0, v1 ) if (havespec) { \
+ (v0)->v.specular.red = v1->v.specular.red; \
+ (v0)->v.specular.green = v1->v.specular.green; \
+ (v0)->v.specular.blue = v1->v.specular.blue; }
+
+#define VERT_SAVE_SPEC( idx ) if (havespec) spec[idx] = v[idx]->ui[5]
+#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[5] = spec[idx]
+
+#define LOCAL_VARS(n) \
+ r128ContextPtr rmesa = R128_CONTEXT(ctx); \
+ GLuint color[n], spec[n]; \
+ GLuint coloroffset = (rmesa->vertex_size == 4 ? 3 : 4); \
+ GLboolean havespec = (rmesa->vertex_size == 4 ? 0 : 1); \
+ (void) color; (void) spec; (void) coloroffset; (void) havespec;
+
+/***********************************************************************
+ * Helpers for rendering unfilled primitives *
+ ***********************************************************************/
+
+#define RASTERIZE(x) if (rmesa->hw_primitive != hw_prim[x]) \
+ r128RasterPrimitive( ctx, hw_prim[x] )
+#define RENDER_PRIMITIVE rmesa->render_primitive
+#define IND R128_FALLBACK_BIT
+#define TAG(x) x
+#include "tnl_dd/t_dd_unfilled.h"
+#undef IND
+
+
+/***********************************************************************
+ * Generate GL render functions *
+ ***********************************************************************/
+
+
+#define IND (0)
+#define TAG(x) x
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_OFFSET_BIT)
+#define TAG(x) x##_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT)
+#define TAG(x) x##_twoside
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT)
+#define TAG(x) x##_twoside_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_UNFILLED_BIT)
+#define TAG(x) x##_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_OFFSET_BIT|R128_UNFILLED_BIT)
+#define TAG(x) x##_offset_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT|R128_UNFILLED_BIT)
+#define TAG(x) x##_twoside_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT|R128_UNFILLED_BIT)
+#define TAG(x) x##_twoside_offset_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_FALLBACK_BIT)
+#define TAG(x) x##_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_OFFSET_BIT|R128_FALLBACK_BIT)
+#define TAG(x) x##_offset_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT|R128_FALLBACK_BIT)
+#define TAG(x) x##_twoside_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT|R128_FALLBACK_BIT)
+#define TAG(x) x##_twoside_offset_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_UNFILLED_BIT|R128_FALLBACK_BIT)
+#define TAG(x) x##_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_OFFSET_BIT|R128_UNFILLED_BIT|R128_FALLBACK_BIT)
+#define TAG(x) x##_offset_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT|R128_UNFILLED_BIT|R128_FALLBACK_BIT)
+#define TAG(x) x##_twoside_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT|R128_UNFILLED_BIT| \
+ R128_FALLBACK_BIT)
+#define TAG(x) x##_twoside_offset_unfilled_fallback
+#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();
+}
+
+
+
+/***********************************************************************
+ * Rasterization fallback helpers *
+ ***********************************************************************/
+
+
+/* This code is hit only when a mix of accelerated and unaccelerated
+ * primitives are being drawn, and only for the unaccelerated
+ * primitives.
+ */
+static void
+r128_fallback_tri( r128ContextPtr rmesa,
+ r128Vertex *v0,
+ r128Vertex *v1,
+ r128Vertex *v2 )
+{
+ GLcontext *ctx = rmesa->glCtx;
+ SWvertex v[3];
+ r128_translate_vertex( ctx, v0, &v[0] );
+ r128_translate_vertex( ctx, v1, &v[1] );
+ r128_translate_vertex( ctx, v2, &v[2] );
+ _swrast_Triangle( ctx, &v[0], &v[1], &v[2] );
+}
+
+
+static void
+r128_fallback_line( r128ContextPtr rmesa,
+ r128Vertex *v0,
+ r128Vertex *v1 )
+{
+ GLcontext *ctx = rmesa->glCtx;
+ SWvertex v[2];
+ r128_translate_vertex( ctx, v0, &v[0] );
+ r128_translate_vertex( ctx, v1, &v[1] );
+ _swrast_Line( ctx, &v[0], &v[1] );
+}
+
+
+static void
+r128_fallback_point( r128ContextPtr rmesa,
+ r128Vertex *v0 )
+{
+ GLcontext *ctx = rmesa->glCtx;
+ SWvertex v[1];
+ r128_translate_vertex( ctx, v0, &v[0] );
+ _swrast_Point( ctx, &v[0] );
+}
+
+
+
+/**********************************************************************/
+/* Render unclipped begin/end objects */
+/**********************************************************************/
+
+#define VERT(x) (r128Vertex *)(r128verts + (x << shift))
+#define RENDER_POINTS( start, count ) \
+ for ( ; start < count ; start++) \
+ r128_draw_point( rmesa, VERT(start) )
+#define RENDER_LINE( v0, v1 ) \
+ r128_draw_line( rmesa, VERT(v0), VERT(v1) )
+#define RENDER_TRI( v0, v1, v2 ) \
+ r128_draw_triangle( rmesa, VERT(v0), VERT(v1), VERT(v2) )
+#define RENDER_QUAD( v0, v1, v2, v3 ) \
+ r128_draw_quad( rmesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) )
+#define INIT(x) do { \
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__); \
+ r128RenderPrimitive( ctx, x ); \
+} while (0)
+#undef LOCAL_VARS
+#define LOCAL_VARS \
+ r128ContextPtr rmesa = R128_CONTEXT(ctx); \
+ const GLuint shift = rmesa->vertex_stride_shift; \
+ const char *r128verts = (char *)rmesa->verts; \
+ const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \
+ (void) elt;
+#define RESET_STIPPLE
+#define RESET_OCCLUSION
+#define PRESERVE_VB_DEFS
+#define ELT(x) (x)
+#define TAG(x) r128_##x##_verts
+#include "tnl/t_vb_rendertmp.h"
+#undef ELT
+#undef TAG
+#define TAG(x) r128_##x##_elts
+#define ELT(x) elt[x]
+#include "tnl/t_vb_rendertmp.h"
+
+
+/**********************************************************************/
+/* Render clipped primitives */
+/**********************************************************************/
+
+static void r128RenderClippedPoly( GLcontext *ctx, const GLuint *elts,
+ GLuint n )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ /* 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;
+ }
+}
+
+static void r128RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->Driver.Render.Line( ctx, ii, jj );
+}
+
+static void r128FastRenderClippedPoly( GLcontext *ctx, const GLuint *elts,
+ GLuint n )
+{
+ r128ContextPtr rmesa = R128_CONTEXT( ctx );
+ GLuint vertsize = rmesa->vertex_size;
+ GLuint *vb = r128AllocDmaLow( rmesa, (n-2) * 3 * 4 * vertsize );
+ GLubyte *r128verts = (GLubyte *)rmesa->verts;
+ const GLuint shift = rmesa->vertex_stride_shift;
+ const GLuint *start = (const GLuint *)VERT(elts[0]);
+ int i,j;
+
+ rmesa->num_verts += (n-2) * 3;
+
+ for (i = 2 ; i < n ; i++) {
+ COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) VERT(elts[i-1]) );
+ COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) VERT(elts[i]) );
+ COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) start );
+ }
+}
+
+
+
+
+/**********************************************************************/
+/* Choose render functions */
+/**********************************************************************/
+
+#define _R128_NEW_RENDER_STATE (_DD_NEW_LINE_STIPPLE | \
+ _DD_NEW_LINE_SMOOTH | \
+ _DD_NEW_POINT_SMOOTH | \
+ _DD_NEW_TRI_SMOOTH | \
+ _DD_NEW_TRI_UNFILLED | \
+ _DD_NEW_TRI_LIGHT_TWOSIDE | \
+ _DD_NEW_TRI_OFFSET) \
+
+
+#define POINT_FALLBACK (DD_POINT_SMOOTH)
+#define LINE_FALLBACK (DD_LINE_STIPPLE|DD_LINE_SMOOTH)
+#define TRI_FALLBACK (DD_TRI_SMOOTH)
+#define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)
+#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED)
+
+
+static void r128ChooseRenderState(GLcontext *ctx)
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint flags = ctx->_TriangleCaps;
+ GLuint index = 0;
+
+ if (flags & (ANY_RASTER_FLAGS|ANY_FALLBACK_FLAGS)) {
+ rmesa->draw_point = r128_draw_point;
+ rmesa->draw_line = r128_draw_line;
+ rmesa->draw_tri = r128_draw_triangle;
+
+ if (flags & ANY_RASTER_FLAGS) {
+ if (flags & DD_TRI_LIGHT_TWOSIDE) index |= R128_TWOSIDE_BIT;
+ if (flags & DD_TRI_OFFSET) index |= R128_OFFSET_BIT;
+ if (flags & DD_TRI_UNFILLED) index |= R128_UNFILLED_BIT;
+ }
+
+ /* Hook in fallbacks for specific primitives.
+ */
+ if (flags & (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)) {
+ if (flags & POINT_FALLBACK) rmesa->draw_point = r128_fallback_point;
+ if (flags & LINE_FALLBACK) rmesa->draw_line = r128_fallback_line;
+ if (flags & TRI_FALLBACK) rmesa->draw_tri = r128_fallback_tri;
+ index |= R128_FALLBACK_BIT;
+ }
+ }
+
+ if (index != rmesa->RenderIndex) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ 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 = r128_render_tab_verts;
+ tnl->Driver.Render.PrimTabElts = r128_render_tab_elts;
+ tnl->Driver.Render.ClippedLine = rast_tab[index].line;
+ tnl->Driver.Render.ClippedPolygon = r128FastRenderClippedPoly;
+ } else {
+ tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
+ tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
+ tnl->Driver.Render.ClippedLine = r128RenderClippedLine;
+ tnl->Driver.Render.ClippedPolygon = r128RenderClippedPoly;
+ }
+
+ rmesa->RenderIndex = index;
+ }
+}
+
+/**********************************************************************/
+/* Validate state at pipeline start */
+/**********************************************************************/
+
+static void r128RunPipeline( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ if (rmesa->new_state || rmesa->NewGLState & _NEW_TEXTURE)
+ r128DDUpdateHWState( ctx );
+
+ if (!rmesa->Fallback && rmesa->NewGLState) {
+ if (rmesa->NewGLState & _R128_NEW_VERTEX_STATE)
+ r128ChooseVertexState( ctx );
+
+ if (rmesa->NewGLState & _R128_NEW_RENDER_STATE)
+ r128ChooseRenderState( ctx );
+
+ rmesa->NewGLState = 0;
+ }
+
+ _tnl_run_pipeline( ctx );
+}
+
+/**********************************************************************/
+/* High level hooks for t_vb_render.c */
+/**********************************************************************/
+
+/* This is called when Mesa switches between rendering triangle
+ * primitives (such as GL_POLYGON, GL_QUADS, GL_TRIANGLE_STRIP, etc),
+ * and lines, points and bitmaps.
+ *
+ * As the r128 uses triangles to render lines and points, it is
+ * necessary to turn off hardware culling when rendering these
+ * primitives.
+ */
+
+static void r128RasterPrimitive( GLcontext *ctx, GLuint hwprim )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ rmesa->setup.dp_gui_master_cntl_c &= ~R128_GMC_BRUSH_NONE;
+
+ if ( ctx->Polygon.StippleFlag && hwprim == GL_TRIANGLES ) {
+ rmesa->setup.dp_gui_master_cntl_c |= R128_GMC_BRUSH_32x32_MONO_FG_LA;
+ }
+ else {
+ rmesa->setup.dp_gui_master_cntl_c |= R128_GMC_BRUSH_SOLID_COLOR;
+ }
+
+ rmesa->new_state |= R128_NEW_CONTEXT;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+
+ if (rmesa->hw_primitive != hwprim) {
+ FLUSH_BATCH( rmesa );
+ rmesa->hw_primitive = hwprim;
+ }
+}
+
+static void r128RenderPrimitive( GLcontext *ctx, GLenum prim )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint hw = hw_prim[prim];
+ rmesa->render_primitive = prim;
+ if (prim >= GL_TRIANGLES && (ctx->_TriangleCaps & DD_TRI_UNFILLED))
+ return;
+ r128RasterPrimitive( ctx, hw );
+}
+
+
+static void r128RenderStart( GLcontext *ctx )
+{
+ /* Check for projective texturing. Make sure all texcoord
+ * pointers point to something. (fix in mesa?)
+ */
+ r128CheckTexSizes( ctx );
+}
+
+static void r128RenderFinish( GLcontext *ctx )
+{
+ if (R128_CONTEXT(ctx)->RenderIndex & R128_FALLBACK_BIT)
+ _swrast_flush( ctx );
+}
+
+
+/**********************************************************************/
+/* Transition to/from hardware rasterization. */
+/**********************************************************************/
+
+void r128Fallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint oldfallback = rmesa->Fallback;
+
+ if (mode) {
+ rmesa->Fallback |= bit;
+ if (oldfallback == 0) {
+ FLUSH_BATCH( rmesa );
+ _swsetup_Wakeup( ctx );
+ rmesa->RenderIndex = ~0;
+ }
+ }
+ else {
+ rmesa->Fallback &= ~bit;
+ if (oldfallback == bit) {
+ _swrast_flush( ctx );
+ tnl->Driver.Render.Start = r128RenderStart;
+ tnl->Driver.Render.PrimitiveNotify = r128RenderPrimitive;
+ tnl->Driver.Render.Finish = r128RenderFinish;
+ tnl->Driver.Render.BuildVertices = r128BuildVertices;
+ rmesa->NewGLState |= (_R128_NEW_RENDER_STATE|
+ _R128_NEW_VERTEX_STATE);
+ }
+ }
+}
+
+
+/**********************************************************************/
+/* Initialization. */
+/**********************************************************************/
+
+void r128InitTriFuncs( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ static int firsttime = 1;
+
+ if (firsttime) {
+ init_rast_tab();
+ firsttime = 0;
+ }
+
+ tnl->Driver.RunPipeline = r128RunPipeline;
+ tnl->Driver.Render.Start = r128RenderStart;
+ tnl->Driver.Render.Finish = r128RenderFinish;
+ tnl->Driver.Render.PrimitiveNotify = r128RenderPrimitive;
+ tnl->Driver.Render.ResetLineStipple = _swrast_ResetLineStipple;
+ tnl->Driver.Render.BuildVertices = r128BuildVertices;
+ rmesa->NewGLState |= (_R128_NEW_RENDER_STATE|
+ _R128_NEW_VERTEX_STATE);
+
+/* r128Fallback( ctx, 0x100000, 1 ); */
+}
diff --git a/src/mesa/drivers/dri/r128/r128_tris.h b/src/mesa/drivers/dri/r128/r128_tris.h
new file mode 100644
index 0000000000..755d3320b0
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_tris.h
@@ -0,0 +1,48 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tris.h,v 1.8 2002/10/30 12:51:43 alanh Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef __R128_TRIS_H__
+#define __R128_TRIS_H__
+
+#include "mtypes.h"
+
+extern void r128InitTriFuncs( GLcontext *ctx );
+
+
+extern void r128Fallback( GLcontext *ctx, GLuint bit, GLboolean mode );
+#define FALLBACK( rmesa, bit, mode ) r128Fallback( rmesa->glCtx, bit, mode )
+
+
+#endif /* __R128_TRIS_H__ */
diff --git a/src/mesa/drivers/dri/r128/r128_vb.c b/src/mesa/drivers/dri/r128/r128_vb.c
new file mode 100644
index 0000000000..7738901648
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_vb.c
@@ -0,0 +1,522 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_vb.c,v 1.15 2002/10/30 12:51:43 alanh Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "imports.h"
+#include "macros.h"
+#include "colormac.h"
+
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/t_context.h"
+
+#include "r128_context.h"
+#include "r128_vb.h"
+#include "r128_ioctl.h"
+#include "r128_tris.h"
+#include "r128_state.h"
+
+
+#define R128_TEX1_BIT 0x1
+#define R128_TEX0_BIT 0x2
+#define R128_RGBA_BIT 0x4
+#define R128_SPEC_BIT 0x8
+#define R128_FOG_BIT 0x10
+#define R128_XYZW_BIT 0x20
+#define R128_PTEX_BIT 0x40
+#define R128_MAX_SETUP 0x80
+
+static struct {
+ void (*emit)( GLcontext *, GLuint, GLuint, void *, GLuint );
+ 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[R128_MAX_SETUP];
+
+#define TINY_VERTEX_FORMAT (R128_CCE_VC_FRMT_DIFFUSE_ARGB)
+
+#define NOTEX_VERTEX_FORMAT (R128_CCE_VC_FRMT_RHW | \
+ R128_CCE_VC_FRMT_DIFFUSE_ARGB |\
+ R128_CCE_VC_FRMT_SPEC_FRGB)
+
+#define TEX0_VERTEX_FORMAT (R128_CCE_VC_FRMT_RHW | \
+ R128_CCE_VC_FRMT_DIFFUSE_ARGB |\
+ R128_CCE_VC_FRMT_SPEC_FRGB | \
+ R128_CCE_VC_FRMT_S_T)
+
+#define TEX1_VERTEX_FORMAT (R128_CCE_VC_FRMT_RHW | \
+ R128_CCE_VC_FRMT_DIFFUSE_ARGB |\
+ R128_CCE_VC_FRMT_SPEC_FRGB | \
+ R128_CCE_VC_FRMT_S_T | \
+ R128_CCE_VC_FRMT_S2_T2)
+
+
+#define PROJ_TEX1_VERTEX_FORMAT 0
+#define TEX2_VERTEX_FORMAT 0
+#define TEX3_VERTEX_FORMAT 0
+#define PROJ_TEX3_VERTEX_FORMAT 0
+
+#define DO_XYZW (IND & R128_XYZW_BIT)
+#define DO_RGBA (IND & R128_RGBA_BIT)
+#define DO_SPEC (IND & R128_SPEC_BIT)
+#define DO_FOG (IND & R128_FOG_BIT)
+#define DO_TEX0 (IND & R128_TEX0_BIT)
+#define DO_TEX1 (IND & R128_TEX1_BIT)
+#define DO_TEX2 0
+#define DO_TEX3 0
+#define DO_PTEX (IND & R128_PTEX_BIT)
+
+#define VERTEX r128Vertex
+#define VERTEX_COLOR r128_color_t
+#define LOCALVARS r128ContextPtr rmesa = R128_CONTEXT(ctx);
+#define GET_VIEWPORT_MAT() rmesa->hw_viewport
+#define GET_TEXSOURCE(n) rmesa->tmu_source[n]
+#define GET_VERTEX_FORMAT() rmesa->vertex_format
+#define GET_VERTEX_STORE() rmesa->verts
+#define GET_VERTEX_STRIDE_SHIFT() rmesa->vertex_stride_shift
+#define INVALIDATE_STORED_VERTICES()
+#define GET_UBYTE_COLOR_STORE() &rmesa->UbyteColor
+#define GET_UBYTE_SPEC_COLOR_STORE() &rmesa->UbyteSecondaryColor
+
+#define HAVE_HW_VIEWPORT 0
+#define HAVE_HW_DIVIDE 0
+#define HAVE_RGBA_COLOR 0
+#define HAVE_TINY_VERTICES 1
+#define HAVE_NOTEX_VERTICES 1
+#define HAVE_TEX0_VERTICES 1
+#define HAVE_TEX1_VERTICES 1
+#define HAVE_TEX2_VERTICES 0
+#define HAVE_TEX3_VERTICES 0
+#define HAVE_PTEX_VERTICES 0 /* r128 rhw2 not supported by template */
+
+#define UNVIEWPORT_VARS GLfloat h = R128_CONTEXT(ctx)->driDrawable->h
+#define UNVIEWPORT_X(x) x - SUBPIXEL_X
+#define UNVIEWPORT_Y(y) - y + h + SUBPIXEL_Y
+#define UNVIEWPORT_Z(z) z / rmesa->depth_scale
+
+#define PTEX_FALLBACK() FALLBACK(R128_CONTEXT(ctx), R128_FALLBACK_TEXTURE, 1)
+
+#define IMPORT_FLOAT_COLORS r128_import_float_colors
+#define IMPORT_FLOAT_SPEC_COLORS r128_import_float_spec_colors
+
+#define INTERP_VERTEX setup_tab[rmesa->SetupIndex].interp
+#define COPY_PV_VERTEX setup_tab[rmesa->SetupIndex].copy_pv
+
+/***********************************************************************
+ * Generate pv-copying and translation functions *
+ ***********************************************************************/
+
+#define TAG(x) r128_##x
+#include "tnl_dd/t_dd_vb.c"
+
+/***********************************************************************
+ * Generate vertex emit and interp functions *
+ ***********************************************************************/
+
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT)
+#define TAG(x) x##_wg
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT)
+#define TAG(x) x##_wgs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_wgt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_TEX0_BIT|R128_TEX1_BIT)
+#define TAG(x) x##_wgt0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_TEX0_BIT|R128_PTEX_BIT)
+#define TAG(x) x##_wgpt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_wgst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT|\
+ R128_TEX1_BIT)
+#define TAG(x) x##_wgst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT|\
+ R128_PTEX_BIT)
+#define TAG(x) x##_wgspt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT)
+#define TAG(x) x##_wgf
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT)
+#define TAG(x) x##_wgfs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_wgft0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT|\
+ R128_TEX1_BIT)
+#define TAG(x) x##_wgft0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT|\
+ R128_PTEX_BIT)
+#define TAG(x) x##_wgfpt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|\
+ R128_TEX0_BIT)
+#define TAG(x) x##_wgfst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|\
+ R128_TEX0_BIT|R128_TEX1_BIT)
+#define TAG(x) x##_wgfst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|\
+ R128_TEX0_BIT|R128_PTEX_BIT)
+#define TAG(x) x##_wgfspt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_TEX0_BIT)
+#define TAG(x) x##_t0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_TEX0_BIT|R128_TEX1_BIT)
+#define TAG(x) x##_t0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_FOG_BIT)
+#define TAG(x) x##_f
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_FOG_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_ft0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_FOG_BIT|R128_TEX0_BIT|R128_TEX1_BIT)
+#define TAG(x) x##_ft0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT)
+#define TAG(x) x##_g
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_SPEC_BIT)
+#define TAG(x) x##_gs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_gt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_TEX0_BIT|R128_TEX1_BIT)
+#define TAG(x) x##_gt0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_gst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT|R128_TEX1_BIT)
+#define TAG(x) x##_gst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_FOG_BIT)
+#define TAG(x) x##_gf
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT)
+#define TAG(x) x##_gfs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_gft0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT|R128_TEX1_BIT)
+#define TAG(x) x##_gft0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|R128_TEX0_BIT)
+#define TAG(x) x##_gfst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|R128_TEX0_BIT|\
+ R128_TEX1_BIT)
+#define TAG(x) x##_gfst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+
+static void init_setup_tab( void )
+{
+ init_wg();
+ init_wgs();
+ init_wgt0();
+ init_wgt0t1();
+ init_wgpt0();
+ init_wgst0();
+ init_wgst0t1();
+ init_wgspt0();
+ init_wgf();
+ init_wgfs();
+ init_wgft0();
+ init_wgft0t1();
+ init_wgfpt0();
+ init_wgfst0();
+ init_wgfst0t1();
+ init_wgfspt0();
+ init_t0();
+ init_t0t1();
+ init_f();
+ init_ft0();
+ init_ft0t1();
+ init_g();
+ init_gs();
+ init_gt0();
+ init_gt0t1();
+ init_gst0();
+ init_gst0t1();
+ init_gf();
+ init_gfs();
+ init_gft0();
+ init_gft0t1();
+ init_gfst0();
+ init_gfst0t1();
+}
+
+
+
+void r128PrintSetupFlags(char *msg, GLuint flags )
+{
+ fprintf(stderr, "%s(%x): %s%s%s%s%s%s\n",
+ msg,
+ (int)flags,
+ (flags & R128_XYZW_BIT) ? " xyzw," : "",
+ (flags & R128_RGBA_BIT) ? " rgba," : "",
+ (flags & R128_SPEC_BIT) ? " spec," : "",
+ (flags & R128_FOG_BIT) ? " fog," : "",
+ (flags & R128_TEX0_BIT) ? " tex-0," : "",
+ (flags & R128_TEX1_BIT) ? " tex-1," : "");
+}
+
+
+
+void r128CheckTexSizes( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT( ctx );
+
+ if (!setup_tab[rmesa->SetupIndex].check_tex_sizes(ctx)) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* Invalidate stored verts
+ */
+ rmesa->SetupNewInputs = ~0;
+ rmesa->SetupIndex |= R128_PTEX_BIT;
+
+ if (!rmesa->Fallback &&
+ !(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+ tnl->Driver.Render.Interp = setup_tab[rmesa->SetupIndex].interp;
+ tnl->Driver.Render.CopyPV = setup_tab[rmesa->SetupIndex].copy_pv;
+ }
+ }
+}
+
+void r128BuildVertices( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint newinputs )
+{
+ r128ContextPtr rmesa = R128_CONTEXT( ctx );
+ GLubyte *v = ((GLubyte *)rmesa->verts + (start<<rmesa->vertex_stride_shift));
+ GLuint stride = 1<<rmesa->vertex_stride_shift;
+
+ newinputs |= rmesa->SetupNewInputs;
+ rmesa->SetupNewInputs = 0;
+
+ if (!newinputs)
+ return;
+
+ if (newinputs & VERT_BIT_CLIP) {
+ setup_tab[rmesa->SetupIndex].emit( ctx, start, count, v, stride );
+ } else {
+ GLuint ind = 0;
+
+ if (newinputs & VERT_BIT_COLOR0)
+ ind |= R128_RGBA_BIT;
+
+ if (newinputs & VERT_BIT_COLOR1)
+ ind |= R128_SPEC_BIT;
+
+ if (newinputs & VERT_BIT_TEX0)
+ ind |= R128_TEX0_BIT;
+
+ if (newinputs & VERT_BIT_TEX1)
+ ind |= R128_TEX1_BIT;
+
+ if (newinputs & VERT_BIT_FOG)
+ ind |= R128_FOG_BIT;
+
+ if (rmesa->SetupIndex & R128_PTEX_BIT)
+ ind = ~0;
+
+ ind &= rmesa->SetupIndex;
+
+ if (ind) {
+ setup_tab[ind].emit( ctx, start, count, v, stride );
+ }
+ }
+}
+
+void r128ChooseVertexState( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ r128ContextPtr rmesa = R128_CONTEXT( ctx );
+ GLuint ind = R128_XYZW_BIT|R128_RGBA_BIT;
+
+ if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)
+ ind |= R128_SPEC_BIT;
+
+ if (ctx->Fog.Enabled)
+ ind |= R128_FOG_BIT;
+
+ if (ctx->Texture._EnabledUnits) {
+ ind |= R128_TEX0_BIT;
+ if (ctx->Texture.Unit[0]._ReallyEnabled &&
+ ctx->Texture.Unit[1]._ReallyEnabled)
+ ind |= R128_TEX1_BIT;
+ }
+
+ rmesa->SetupIndex = ind;
+
+ if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) {
+ tnl->Driver.Render.Interp = r128_interp_extras;
+ tnl->Driver.Render.CopyPV = r128_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 != rmesa->vertex_format) {
+ FLUSH_BATCH(rmesa);
+ rmesa->vertex_format = setup_tab[ind].vertex_format;
+ rmesa->vertex_size = setup_tab[ind].vertex_size;
+ rmesa->vertex_stride_shift = setup_tab[ind].vertex_stride_shift;
+ }
+}
+
+
+
+void r128_emit_contiguous_verts( GLcontext *ctx,
+ GLuint start,
+ GLuint count )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint vertex_size = rmesa->vertex_size * 4;
+ GLuint *dest = r128AllocDmaLow( rmesa, (count-start) * vertex_size);
+ setup_tab[rmesa->SetupIndex].emit( ctx, start, count, dest, vertex_size );
+}
+
+
+#if 0
+void r128_emit_indexed_verts( GLcontext *ctx, GLuint start, GLuint count )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint vertex_size = rmesa->vertex_size * 4;
+ GLuint bufsz = (count-start) * vertex_size;
+ CARD32 *dest;
+
+ rmesa->vertex_low = (rmesa->vertex_low + 63) & ~63; /* alignment */
+ rmesa->vertex_last_prim = rmesa->vertex_low;
+
+ dest = r128AllocDmaLow( rmesa, bufsz, __FUNCTION__);
+ setup_tab[rmesa->SetupIndex].emit( ctx, start, count, dest, vertex_size );
+
+ rmesa->retained_buffer = rmesa->vertex_buffer;
+ rmesa->vb_offset = (rmesa->vertex_buffer->idx * R128_BUFFER_SIZE +
+ rmesa->vertex_low - bufsz);
+
+ rmesa->vertex_low = (rmesa->vertex_low + 0x7) & ~0x7; /* alignment */
+ rmesa->vertex_last_prim = rmesa->vertex_low;
+}
+#endif
+
+
+void r128InitVB( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint size = TNL_CONTEXT(ctx)->vb.Size;
+
+ rmesa->verts = ALIGN_MALLOC(size * 4 * 16, 32);
+
+ {
+ static int firsttime = 1;
+ if (firsttime) {
+ init_setup_tab();
+ firsttime = 0;
+ }
+ }
+}
+
+
+void r128FreeVB( GLcontext *ctx )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ if (rmesa->verts) {
+ ALIGN_FREE(rmesa->verts);
+ rmesa->verts = 0;
+ }
+
+
+ if (rmesa->UbyteSecondaryColor.Ptr) {
+ ALIGN_FREE(rmesa->UbyteSecondaryColor.Ptr);
+ rmesa->UbyteSecondaryColor.Ptr = 0;
+ }
+
+ if (rmesa->UbyteColor.Ptr) {
+ ALIGN_FREE(rmesa->UbyteColor.Ptr);
+ rmesa->UbyteColor.Ptr = 0;
+ }
+}
diff --git a/src/mesa/drivers/dri/r128/r128_vb.h b/src/mesa/drivers/dri/r128/r128_vb.h
new file mode 100644
index 0000000000..31afa74f1c
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/r128_vb.h
@@ -0,0 +1,74 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_vb.h,v 1.8 2002/10/30 12:51:46 alanh Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef R128VB_INC
+#define R128VB_INC
+
+#include "mtypes.h"
+#include "swrast/swrast.h"
+#include "r128_context.h"
+
+#define _R128_NEW_VERTEX_STATE (_DD_NEW_SEPARATE_SPECULAR | \
+ _DD_NEW_TRI_LIGHT_TWOSIDE | \
+ _DD_NEW_TRI_UNFILLED | \
+ _NEW_TEXTURE | \
+ _NEW_FOG)
+
+extern void r128CheckTexSizes( GLcontext *ctx );
+extern void r128ChooseVertexState( GLcontext *ctx );
+
+extern void r128BuildVertices( GLcontext *ctx, GLuint start, GLuint count,
+ GLuint newinputs );
+
+extern void r128PrintSetupFlags(char *msg, GLuint flags );
+
+extern void r128InitVB( GLcontext *ctx );
+extern void r128FreeVB( GLcontext *ctx );
+
+extern void r128_emit_contiguous_verts( GLcontext *ctx,
+ GLuint start,
+ GLuint count );
+
+extern void r128_emit_indexed_verts( GLcontext *ctx,
+ GLuint start,
+ GLuint count );
+
+extern void r128_translate_vertex( GLcontext *ctx,
+ const r128Vertex *src,
+ SWvertex *dst );
+
+extern void r128_print_vertex( GLcontext *ctx, const r128Vertex *v );
+
+#endif
diff --git a/src/mesa/drivers/dri/r128/server/r128.h b/src/mesa/drivers/dri/r128/server/r128.h
new file mode 100644
index 0000000000..fba01d6d60
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128.h
@@ -0,0 +1,566 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128.h,v 1.24 2002/12/16 16:19:10 dawes Exp $ */
+/*
+ * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
+ * Precision Insight, Inc., Cedar Park, Texas, and
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
+ * SYSTEMS AND/OR THEIR SUPPLIERS 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:
+ * Rickard E. Faith <faith@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef _R128_H_
+#define _R128_H_
+
+#include "dri_util.h"
+#ifndef _SOLO
+#include "xf86str.h"
+
+ /* PCI support */
+#include "xf86Pci.h"
+
+ /* XAA and Cursor Support */
+#include "xaa.h"
+#include "xf86Cursor.h"
+
+ /* DDC support */
+#include "xf86DDC.h"
+
+ /* Xv support */
+#include "xf86xv.h"
+
+ /* DRI support */
+#ifdef XF86DRI
+#define _XF86DRI_SERVER_
+#include "r128_dripriv.h"
+#include "dri.h"
+#include "GL/glxint.h"
+#endif
+#endif
+#ifdef _SOLO
+#define XF86DRI
+#endif
+
+#define R128_DEBUG 0 /* Turn off debugging output */
+#define R128_IDLE_RETRY 32 /* Fall out of idle loops after this count */
+#define R128_TIMEOUT 2000000 /* Fall out of wait loops after this count */
+#define R128_MMIOSIZE 0x4000
+
+#define R128_VBIOS_SIZE 0x00010000
+
+#if R128_DEBUG
+#define R128TRACE(x) \
+ do { \
+ ErrorF("(**) %s(%d): ", R128_NAME, pScrn->scrnIndex); \
+ ErrorF x; \
+ } while (0);
+#else
+#define R128TRACE(x)
+#endif
+
+
+/* Other macros */
+#define R128_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define R128_ALIGN(x,bytes) (((x) + ((bytes) - 1)) & ~((bytes) - 1))
+#define R128PTR(pScrn) ((R128InfoPtr)(pScrn)->driverPrivate)
+
+/**
+ * \brief Chip families.
+ */
+typedef enum {
+ CHIP_FAMILY_UNKNOWN,
+ CHIP_FAMILY_R128_PCI,
+ CHIP_FAMILY_R128_AGP,
+} R128ChipFamily;
+
+typedef struct { /* All values in XCLKS */
+ int ML; /* Memory Read Latency */
+ int MB; /* Memory Burst Length */
+ int Trcd; /* RAS to CAS delay */
+ int Trp; /* RAS percentage */
+ int Twr; /* Write Recovery */
+ int CL; /* CAS Latency */
+ int Tr2w; /* Read to Write Delay */
+ int Rloop; /* Loop Latency */
+ int Rloop_fudge; /* Add to ML to get Rloop */
+ char *name;
+} R128RAMRec, *R128RAMPtr;
+
+typedef struct {
+ /* Common registers */
+ CARD32 ovr_clr;
+ CARD32 ovr_wid_left_right;
+ CARD32 ovr_wid_top_bottom;
+ CARD32 ov0_scale_cntl;
+ CARD32 mpp_tb_config;
+ CARD32 mpp_gp_config;
+ CARD32 subpic_cntl;
+ CARD32 viph_control;
+ CARD32 i2c_cntl_1;
+ CARD32 gen_int_cntl;
+ CARD32 cap0_trig_cntl;
+ CARD32 cap1_trig_cntl;
+ CARD32 bus_cntl;
+ CARD32 config_cntl;
+
+ /* Other registers to save for VT switches */
+ CARD32 dp_datatype;
+ CARD32 gen_reset_cntl;
+ CARD32 clock_cntl_index;
+ CARD32 amcgpio_en_reg;
+ CARD32 amcgpio_mask;
+
+ /* CRTC registers */
+ CARD32 crtc_gen_cntl;
+ CARD32 crtc_ext_cntl;
+ CARD32 dac_cntl;
+ CARD32 crtc_h_total_disp;
+ CARD32 crtc_h_sync_strt_wid;
+ CARD32 crtc_v_total_disp;
+ CARD32 crtc_v_sync_strt_wid;
+ CARD32 crtc_offset;
+ CARD32 crtc_offset_cntl;
+ CARD32 crtc_pitch;
+
+ /* CRTC2 registers */
+ CARD32 crtc2_gen_cntl;
+
+ /* Flat panel registers */
+ CARD32 fp_crtc_h_total_disp;
+ CARD32 fp_crtc_v_total_disp;
+ CARD32 fp_gen_cntl;
+ CARD32 fp_h_sync_strt_wid;
+ CARD32 fp_horz_stretch;
+ CARD32 fp_panel_cntl;
+ CARD32 fp_v_sync_strt_wid;
+ CARD32 fp_vert_stretch;
+ CARD32 lvds_gen_cntl;
+ CARD32 tmds_crc;
+ CARD32 tmds_transmitter_cntl;
+
+ /* Computed values for PLL */
+ CARD32 dot_clock_freq;
+ CARD32 pll_output_freq;
+ int feedback_div;
+ int post_div;
+
+ /* PLL registers */
+ CARD32 ppll_ref_div;
+ CARD32 ppll_div_3;
+ CARD32 htotal_cntl;
+
+ /* DDA register */
+ CARD32 dda_config;
+ CARD32 dda_on_off;
+
+ /* Pallet */
+ GLboolean palette_valid;
+ CARD32 palette[256];
+} R128SaveRec, *R128SavePtr;
+
+#ifndef _SOLO
+typedef struct {
+ CARD16 reference_freq;
+ CARD16 reference_div;
+ CARD32 min_pll_freq;
+ CARD32 max_pll_freq;
+ CARD16 xclk;
+} R128PLLRec, *R128PLLPtr;
+
+typedef struct {
+ int bitsPerPixel;
+ int depth;
+ int displayWidth;
+ int pixel_code;
+ int pixel_bytes;
+ DisplayModePtr mode;
+} R128FBLayout;
+#endif
+
+typedef struct {
+#ifndef _SOLO
+ EntityInfoPtr pEnt;
+ pciVideoPtr PciInfo;
+ PCITAG PciTag;
+#endif
+ int Chipset;
+ GLboolean Primary;
+
+ GLboolean FBDev;
+
+ unsigned long LinearAddr; /* Frame buffer physical address */
+ unsigned long BIOSAddr; /* BIOS physical address */
+
+ unsigned char *MMIO; /* Map of MMIO region */
+ unsigned char *FB; /* Map of frame buffer */
+
+ CARD32 MemCntl;
+ CARD32 BusCntl;
+ unsigned long FbMapSize; /* Size of frame buffer, in bytes */
+ int Flags; /* Saved copy of mode flags */
+
+#ifndef _SOLO
+ CARD8 BIOSDisplay; /* Device the BIOS is set to display to */
+
+ GLboolean HasPanelRegs; /* Current chip can connect to a FP */
+ CARD8 *VBIOS; /* Video BIOS for mode validation on FPs */
+ int FPBIOSstart; /* Start of the flat panel info */
+#endif
+ /* Computed values for FPs */
+ int PanelXRes;
+ int PanelYRes;
+ int HOverPlus;
+ int HSyncWidth;
+ int HBlank;
+ int VOverPlus;
+ int VSyncWidth;
+ int VBlank;
+ int PanelPwrDly;
+#ifndef _SOLO
+ R128PLLRec pll;
+ R128RAMPtr ram;
+
+ R128SaveRec SavedReg; /* Original (text) mode */
+ R128SaveRec ModeReg; /* Current mode */
+ GLboolean (*CloseScreen)(int, ScreenPtr);
+ void (*BlockHandler)(int, pointer, pointer, pointer);
+
+ GLboolean PaletteSavedOnVT; /* Palette saved on last VT switch */
+
+ XAAInfoRecPtr accel;
+ GLboolean accelOn;
+ xf86CursorInfoPtr cursor;
+#endif
+ unsigned long cursor_start;
+ unsigned long cursor_end;
+
+ /*
+ * XAAForceTransBlit is used to change the behavior of the XAA
+ * SetupForScreenToScreenCopy function, to make it DGA-friendly.
+ */
+ GLboolean XAAForceTransBlit;
+
+ int fifo_slots; /* Free slots in the FIFO (64 max) */
+ int pix24bpp; /* Depth of pixmap for 24bpp framebuffer */
+ GLboolean dac6bits; /* Use 6 bit DAC? */
+
+ /* Computed values for Rage 128 */
+ int pitch;
+ int datatype;
+ CARD32 dp_gui_master_cntl;
+
+ /* Saved values for ScreenToScreenCopy */
+ int xdir;
+ int ydir;
+
+ /* ScanlineScreenToScreenColorExpand support */
+ unsigned char *scratch_buffer[1];
+ unsigned char *scratch_save;
+ int scanline_x;
+ int scanline_y;
+ int scanline_w;
+ int scanline_h;
+#ifdef XF86DRI
+ int scanline_hpass;
+ int scanline_x1clip;
+ int scanline_x2clip;
+ int scanline_rop;
+ int scanline_fg;
+ int scanline_bg;
+#endif /* XF86DRI */
+ int scanline_words;
+ int scanline_direct;
+ int scanline_bpp; /* Only used for ImageWrite */
+
+#ifndef _SOLO
+ DGAModePtr DGAModes;
+ int numDGAModes;
+ GLboolean DGAactive;
+ int DGAViewportStatus;
+ DGAFunctionRec DGAFuncs;
+
+ R128FBLayout CurrentLayout;
+#endif
+#ifdef XF86DRI
+ drmContext drmCtx;
+#ifndef _SOLO
+ DRIInfoPtr pDRIInfo;
+ int numVisualConfigs;
+ __GLXvisualConfig *pVisualConfigs;
+ R128ConfigPrivPtr pVisualConfigsPriv;
+#endif
+
+ drmSize registerSize;
+ drmHandle registerHandle;
+
+ GLboolean IsPCI; /* Current card is a PCI card */
+ drmSize pciSize;
+ drmHandle pciMemHandle;
+ unsigned char *PCI; /* Map */
+
+ GLboolean allowPageFlip; /* Enable 3d page flipping */
+ GLboolean have3DWindows; /* Are there any 3d clients? */
+ int drmMinor;
+
+ drmSize agpSize;
+ drmHandle agpMemHandle; /* Handle from drmAgpAlloc */
+ unsigned long agpOffset;
+ unsigned char *AGP; /* Map */
+ int agpMode;
+
+ GLboolean CCEInUse; /* CCE is currently active */
+ int CCEMode; /* CCE mode that server/clients use */
+ int CCEFifoSize; /* Size of the CCE command FIFO */
+ GLboolean CCESecure; /* CCE security enabled */
+ int CCEusecTimeout; /* CCE timeout in usecs */
+
+ /* CCE ring buffer data */
+ unsigned long ringStart; /* Offset into AGP space */
+ drmHandle ringHandle; /* Handle from drmAddMap */
+ drmSize ringMapSize; /* Size of map */
+ int ringSize; /* Size of ring (in MB) */
+ unsigned char *ring; /* Map */
+ int ringSizeLog2QW;
+
+ unsigned long ringReadOffset; /* Offset into AGP space */
+ drmHandle ringReadPtrHandle; /* Handle from drmAddMap */
+ drmSize ringReadMapSize; /* Size of map */
+ unsigned char *ringReadPtr; /* Map */
+
+ /* CCE vertex/indirect buffer data */
+ unsigned long bufStart; /* Offset into AGP space */
+ drmHandle bufHandle; /* Handle from drmAddMap */
+ drmSize bufMapSize; /* Size of map */
+ int bufSize; /* Size of buffers (in MB) */
+ unsigned char *buf; /* Map */
+ int bufNumBufs; /* Number of buffers */
+ drmBufMapPtr buffers; /* Buffer map */
+
+ /* CCE AGP Texture data */
+ unsigned long agpTexStart; /* Offset into AGP space */
+ drmHandle agpTexHandle; /* Handle from drmAddMap */
+ drmSize agpTexMapSize; /* Size of map */
+ int agpTexSize; /* Size of AGP tex space (in MB) */
+ unsigned char *agpTex; /* Map */
+ int log2AGPTexGran;
+
+ /* CCE 2D accleration */
+ drmBufPtr indirectBuffer;
+ int indirectStart;
+
+ /* DRI screen private data */
+ int fbX;
+ int fbY;
+ int backX;
+ int backY;
+ int depthX;
+ int depthY;
+
+ int frontOffset;
+ int frontPitch;
+ int backOffset;
+ int backPitch;
+ int depthOffset;
+ int depthPitch;
+ int spanOffset;
+ int textureOffset;
+ int textureSize;
+ int log2TexGran;
+
+ /* Saved scissor values */
+ CARD32 sc_left;
+ CARD32 sc_right;
+ CARD32 sc_top;
+ CARD32 sc_bottom;
+
+ CARD32 re_top_left;
+ CARD32 re_width_height;
+
+ CARD32 aux_sc_cntl;
+
+ int irq;
+ CARD32 gen_int_cntl;
+
+ GLboolean DMAForXv;
+#endif
+
+#ifndef _SOLO
+ XF86VideoAdaptorPtr adaptor;
+ void (*VideoTimerCallback)(ScrnInfoPtr, Time);
+ int videoKey;
+ GLboolean showCache;
+ OptionInfoPtr Options;
+
+ GLboolean isDFP;
+ GLboolean isPro2;
+ I2CBusPtr pI2CBus;
+ CARD32 DDCReg;
+#endif
+} R128InfoRec, *R128InfoPtr;
+
+#define R128WaitForFifo(pScrn, entries) \
+do { \
+ if (info->fifo_slots < entries) R128WaitForFifoFunction(pScrn, entries); \
+ info->fifo_slots -= entries; \
+} while (0)
+
+extern void r128WaitForFifoFunction(const DRIDriverContext *ctx, int entries);
+extern void r128WaitForIdle(const DRIDriverContext *ctx);
+
+extern void r128WaitForVerticalSync(const DRIDriverContext *ctx);
+
+extern GLboolean r128AccelInit(const DRIDriverContext *ctx);
+extern void r128EngineInit(const DRIDriverContext *ctx);
+extern GLboolean r128CursorInit(const DRIDriverContext *ctx);
+extern GLboolean r128DGAInit(const DRIDriverContext *ctx);
+
+extern void r128InitVideo(const DRIDriverContext *ctx);
+
+extern GLboolean r128DRIScreenInit(const DRIDriverContext *ctx);
+extern void r128DRICloseScreen(const DRIDriverContext *ctx);
+extern GLboolean r128DRIFinishScreenInit(const DRIDriverContext *ctx);
+
+#define R128CCE_START(ctx, info) \
+do { \
+ int _ret = drmCommandNone(ctx->drmFD, DRM_R128_CCE_START); \
+ if (_ret) { \
+ fprintf(stderr, \
+ "%s: CCE start %d\n", __FUNCTION__, _ret); \
+ } \
+} while (0)
+
+#define R128CCE_STOP(ctx, info) \
+do { \
+ int _ret = R128CCEStop(ctx); \
+ if (_ret) { \
+ fprintf(stderr, \
+ "%s: CCE stop %d\n", __FUNCTION__, _ret); \
+ } \
+} while (0)
+
+#define R128CCE_RESET(ctx, info) \
+do { \
+ if (info->directRenderingEnabled \
+ && R128CCE_USE_RING_BUFFER(info->CCEMode)) { \
+ int _ret = drmCommandNone(info->drmFD, DRM_R128_CCE_RESET); \
+ if (_ret) { \
+ fprintf(stderr, \
+ "%s: CCE reset %d\n", __FUNCTION__, _ret); \
+ } \
+ } \
+} while (0)
+
+
+#define CCE_PACKET0( reg, n ) \
+ (R128_CCE_PACKET0 | ((n) << 16) | ((reg) >> 2))
+#define CCE_PACKET1( reg0, reg1 ) \
+ (R128_CCE_PACKET1 | (((reg1) >> 2) << 11) | ((reg0) >> 2))
+#define CCE_PACKET2() \
+ (R128_CCE_PACKET2)
+#define CCE_PACKET3( pkt, n ) \
+ (R128_CCE_PACKET3 | (pkt) | ((n) << 16))
+
+
+#define R128_VERBOSE 0
+
+#define RING_LOCALS CARD32 *__head; int __count;
+
+#define R128CCE_REFRESH(pScrn, info) \
+do { \
+ if ( R128_VERBOSE ) { \
+ fprintf(stderr, "REFRESH( %d ) in %s\n", \
+ !info->CCEInUse , __FUNCTION__ ); \
+ } \
+ if ( !info->CCEInUse ) { \
+ R128CCEWaitForIdle(pScrn); \
+ BEGIN_RING( 6 ); \
+ OUT_RING_REG( R128_RE_TOP_LEFT, info->re_top_left ); \
+ OUT_RING_REG( R128_RE_WIDTH_HEIGHT, info->re_width_height ); \
+ OUT_RING_REG( R128_AUX_SC_CNTL, info->aux_sc_cntl ); \
+ ADVANCE_RING(); \
+ info->CCEInUse = TRUE; \
+ } \
+} while (0)
+
+#define BEGIN_RING( n ) do { \
+ if ( R128_VERBOSE ) { \
+ fprintf(stderr, \
+ "BEGIN_RING( %d ) in %s\n", n, __FUNCTION__ ); \
+ } \
+ if ( !info->indirectBuffer ) { \
+ info->indirectBuffer = R128CCEGetBuffer( pScrn ); \
+ info->indirectStart = 0; \
+ } else if ( (info->indirectBuffer->used + 4*(n)) > \
+ info->indirectBuffer->total ) { \
+ R128CCEFlushIndirect( pScrn, 1 ); \
+ } \
+ __head = (pointer)((char *)info->indirectBuffer->address + \
+ info->indirectBuffer->used); \
+ __count = 0; \
+} while (0)
+
+#define ADVANCE_RING() do { \
+ if ( R128_VERBOSE ) { \
+ fprintf(stderr, \
+ "ADVANCE_RING() used: %d+%d=%d/%d\n", \
+ info->indirectBuffer->used - info->indirectStart, \
+ __count * sizeof(CARD32), \
+ info->indirectBuffer->used - info->indirectStart + \
+ __count * sizeof(CARD32), \
+ info->indirectBuffer->total - info->indirectStart ); \
+ } \
+ info->indirectBuffer->used += __count * (int)sizeof(CARD32); \
+} while (0)
+
+#define OUT_RING( x ) do { \
+ if ( R128_VERBOSE ) { \
+ fprintf(stderr, \
+ " OUT_RING( 0x%08x )\n", (unsigned int)(x) ); \
+ } \
+ MMIO_OUT32(&__head[__count++], 0, (x)); \
+} while (0)
+
+#define OUT_RING_REG( reg, val ) \
+do { \
+ OUT_RING( CCE_PACKET0( reg, 0 ) ); \
+ OUT_RING( val ); \
+} while (0)
+
+#define FLUSH_RING() \
+do { \
+ if ( R128_VERBOSE ) \
+ fprintf(stderr, \
+ "FLUSH_RING in %s\n", __FUNCTION__ ); \
+ if ( info->indirectBuffer ) { \
+ R128CCEFlushIndirect( pScrn, 0 ); \
+ } \
+} while (0)
+
+
+#endif
diff --git a/src/mesa/drivers/dri/r128/server/r128_common.h b/src/mesa/drivers/dri/r128/server/r128_common.h
new file mode 100644
index 0000000000..fa81360ea5
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128_common.h
@@ -0,0 +1,169 @@
+/* r128_common.h -- common header definitions for R128 2D/3D/DRM suite
+ * Created: Sun Apr 9 18:16:28 2000 by kevin@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+ *
+ * Author:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
+ * Converted to common header format:
+ * Jens Owen <jens@tungstengraphics.com>
+ *
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drmR128.h,v 3.11 2001/04/16 15:02:13 tsi Exp $
+ *
+ */
+
+#ifndef _R128_COMMON_H_
+#define _R128_COMMON_H_
+
+/*
+ * WARNING: If you change any of these defines, make sure to change
+ * the kernel include file as well (r128_drm.h)
+ */
+
+/* Driver specific DRM command indices
+ * NOTE: these are not OS specific, but they are driver specific
+ */
+#define DRM_R128_INIT 0x00
+#define DRM_R128_CCE_START 0x01
+#define DRM_R128_CCE_STOP 0x02
+#define DRM_R128_CCE_RESET 0x03
+#define DRM_R128_CCE_IDLE 0x04
+#define DRM_R128_UNDEFINED1 0x05
+#define DRM_R128_RESET 0x06
+#define DRM_R128_SWAP 0x07
+#define DRM_R128_CLEAR 0x08
+#define DRM_R128_VERTEX 0x09
+#define DRM_R128_INDICES 0x0a
+#define DRM_R128_BLIT 0x0b
+#define DRM_R128_DEPTH 0x0c
+#define DRM_R128_STIPPLE 0x0d
+#define DRM_R128_UNDEFINED2 0x0e
+#define DRM_R128_INDIRECT 0x0f
+#define DRM_R128_FULLSCREEN 0x10
+#define DRM_R128_CLEAR2 0x11
+#define DRM_R128_GETPARAM 0x12
+#define DRM_R128_FLIP 0x13
+
+#define DRM_R128_FRONT_BUFFER 0x1
+#define DRM_R128_BACK_BUFFER 0x2
+#define DRM_R128_DEPTH_BUFFER 0x4
+
+typedef struct {
+ enum {
+ DRM_R128_INIT_CCE = 0x01,
+ DRM_R128_CLEANUP_CCE = 0x02
+ } func;
+ unsigned long sarea_priv_offset;
+ int is_pci;
+ int cce_mode;
+ int cce_secure; /* FIXME: Deprecated, we should remove this */
+ int ring_size;
+ int usec_timeout;
+
+ unsigned int fb_bpp;
+ unsigned int front_offset, front_pitch;
+ unsigned int back_offset, back_pitch;
+ unsigned int depth_bpp;
+ unsigned int depth_offset, depth_pitch;
+ unsigned int span_offset;
+
+ unsigned long fb_offset;
+ unsigned long mmio_offset;
+ unsigned long ring_offset;
+ unsigned long ring_rptr_offset;
+ unsigned long buffers_offset;
+ unsigned long agp_textures_offset;
+} drmR128Init;
+
+typedef struct {
+ int flush;
+ int idle;
+} drmR128CCEStop;
+
+typedef struct {
+ int idx;
+ int start;
+ int end;
+ int discard;
+} drmR128Indirect;
+
+typedef struct {
+ int idx;
+ int pitch;
+ int offset;
+ int format;
+ unsigned short x, y;
+ unsigned short width, height;
+} drmR128Blit;
+
+typedef struct {
+ enum {
+ DRM_R128_WRITE_SPAN = 0x01,
+ DRM_R128_WRITE_PIXELS = 0x02,
+ DRM_R128_READ_SPAN = 0x03,
+ DRM_R128_READ_PIXELS = 0x04
+ } func;
+ int n;
+ int *x;
+ int *y;
+ unsigned int *buffer;
+ unsigned char *mask;
+} drmR128Depth;
+
+typedef struct {
+ int prim;
+ int idx; /* Index of vertex buffer */
+ int count; /* Number of vertices in buffer */
+ int discard; /* Client finished with buffer? */
+} drmR128Vertex;
+
+typedef struct {
+ unsigned int *mask;
+} drmR128Stipple;
+
+typedef struct {
+ unsigned int flags;
+ unsigned int clear_color;
+ unsigned int clear_depth;
+ unsigned int color_mask;
+ unsigned int depth_mask;
+} drmR128Clear;
+
+typedef struct {
+ enum {
+ DRM_R128_INIT_FULLSCREEN = 0x01,
+ DRM_R128_CLEANUP_FULLSCREEN = 0x02
+ } func;
+} drmR128Fullscreen;
+
+typedef struct drm_r128_getparam {
+ int param;
+ void *value;
+} drmR128GetParam;
+
+#define R128_PARAM_IRQ_NR 1
+
+#endif
diff --git a/src/mesa/drivers/dri/r128/server/r128_dri.c b/src/mesa/drivers/dri/r128/server/r128_dri.c
new file mode 100644
index 0000000000..aa8f49f9c7
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128_dri.c
@@ -0,0 +1,1165 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dri.c,v 1.28 2003/02/07 20:41:14 martin Exp $ */
+/*
+ * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
+ * Precision Insight, Inc., Cedar Park, Texas, and
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
+ * SYSTEMS AND/OR THEIR SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Rickard E. Faith <faith@valinux.com>
+ * Daryll Strauss <daryll@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include "sarea.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <linux/pci_ids.h>
+
+#include "driver.h"
+#include "drm.h"
+
+#include "sarea.h"
+#include "r128.h"
+#include "r128_dri.h"
+#include "r128_macros.h"
+#include "r128_reg.h"
+#include "r128_sarea.h"
+#include "r128_version.h"
+
+
+/* ?? HACK - for now, put this here... */
+/* ?? Alpha - this may need to be a variable to handle UP1x00 vs TITAN */
+#if defined(__alpha__)
+# define DRM_PAGE_SIZE 8192
+#elif defined(__ia64__)
+# define DRM_PAGE_SIZE getpagesize()
+#else
+# define DRM_PAGE_SIZE 4096
+#endif
+
+/**
+ * \brief Establish the set of modes available for the display.
+ *
+ * \param ctx display handle.
+ * \param numModes will receive the number of supported modes.
+ * \param modes will point to the list of supported modes.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Allocates a single visual and fills it with information according to the
+ * display bit depth. Supports only 16 and 32 bpp bit depths, aborting
+ * otherwise.
+ */
+const __GLcontextModes __glModes[] = {
+
+ /* 32 bit, RGBA Depth=24 Stencil=8 */
+ {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE,
+ .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_TRUE,
+ .redBits = 8, .greenBits = 8, .blueBits = 8, .alphaBits = 8,
+ .redMask = 0xff0000, .greenMask = 0xff00, .blueMask = 0xff, .alphaMask = 0xff000000,
+ .rgbBits = 32, .indexBits = 0,
+ .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0,
+ .depthBits = 24, .stencilBits = 8,
+ .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, },
+
+ /* 16 bit, RGB Depth=16 */
+ {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE,
+ .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_FALSE,
+ .redBits = 5, .greenBits = 6, .blueBits = 5, .alphaBits = 0,
+ .redMask = 0xf800, .greenMask = 0x07e0, .blueMask = 0x001f, .alphaMask = 0x0,
+ .rgbBits = 16, .indexBits = 0,
+ .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0,
+ .depthBits = 16, .stencilBits = 0,
+ .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, },
+};
+static int R128InitContextModes( const DRIDriverContext *ctx,
+ int *numModes, const __GLcontextModes **modes)
+{
+ *numModes = sizeof(__glModes)/sizeof(__GLcontextModes *);
+ *modes = &__glModes[0];
+ return 1;
+}
+
+/* Compute log base 2 of val. */
+static int R128MinBits(int val)
+{
+ int bits;
+
+ if (!val) return 1;
+ for (bits = 0; val; val >>= 1, ++bits);
+ return bits;
+}
+
+/* Initialize the AGP state. Request memory for use in AGP space, and
+ initialize the Rage 128 registers to point to that memory. */
+static GLboolean R128DRIAgpInit(const DRIDriverContext *ctx)
+{
+ unsigned char *R128MMIO = ctx->MMIOAddress;
+ R128InfoPtr info = ctx->driverPrivate;
+ unsigned long mode;
+ unsigned int vendor, device;
+ int ret;
+ unsigned long cntl, chunk;
+ int s, l;
+ int flags;
+ unsigned long agpBase;
+
+ if (drmAgpAcquire(ctx->drmFD) < 0) {
+ fprintf(stderr, "[agp] AGP not available\n");
+ return GL_FALSE;
+ }
+
+ /* Modify the mode if the default mode is
+ not appropriate for this particular
+ combination of graphics card and AGP
+ chipset. */
+
+ mode = drmAgpGetMode(ctx->drmFD); /* Default mode */
+ vendor = drmAgpVendorId(ctx->drmFD);
+ device = drmAgpDeviceId(ctx->drmFD);
+
+ mode &= ~R128_AGP_MODE_MASK;
+ switch (info->agpMode) {
+ case 4: mode |= R128_AGP_4X_MODE;
+ case 2: mode |= R128_AGP_2X_MODE;
+ case 1: default: mode |= R128_AGP_1X_MODE;
+ }
+
+ fprintf(stderr,
+ "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n",
+ mode, vendor, device,
+ 0x1002,
+ info->Chipset);
+
+ if (drmAgpEnable(ctx->drmFD, mode) < 0) {
+ fprintf(stderr, "[agp] AGP not enabled\n");
+ drmAgpRelease(ctx->drmFD);
+ return GL_FALSE;
+ }
+
+ info->agpOffset = 0;
+
+ if ((ret = drmAgpAlloc(ctx->drmFD, info->agpSize*1024*1024, 0, NULL,
+ &info->agpMemHandle)) < 0) {
+ fprintf(stderr, "[agp] Out of memory (%d)\n", ret);
+ drmAgpRelease(ctx->drmFD);
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] %d kB allocated with handle 0x%08x\n",
+ info->agpSize*1024, info->agpMemHandle);
+
+ if (drmAgpBind(ctx->drmFD, info->agpMemHandle, info->agpOffset) < 0) {
+ fprintf(stderr, "[agp] Could not bind\n");
+ drmAgpFree(ctx->drmFD, info->agpMemHandle);
+ drmAgpRelease(ctx->drmFD);
+ return GL_FALSE;
+ }
+
+ /* Initialize the CCE ring buffer data */
+ info->ringStart = info->agpOffset;
+ info->ringMapSize = info->ringSize*1024*1024 + DRM_PAGE_SIZE;
+ info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1;
+
+ info->ringReadOffset = info->ringStart + info->ringMapSize;
+ info->ringReadMapSize = DRM_PAGE_SIZE;
+
+ /* Reserve space for vertex/indirect buffers */
+ info->bufStart = info->ringReadOffset + info->ringReadMapSize;
+ info->bufMapSize = info->bufSize*1024*1024;
+
+ /* Reserve the rest for AGP textures */
+ info->agpTexStart = info->bufStart + info->bufMapSize;
+ s = (info->agpSize*1024*1024 - info->agpTexStart);
+ l = R128MinBits((s-1) / R128_NR_TEX_REGIONS);
+ if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY;
+ info->agpTexMapSize = (s >> l) << l;
+ info->log2AGPTexGran = l;
+
+ if (info->CCESecure) flags = DRM_READ_ONLY;
+ else flags = 0;
+
+ if (drmAddMap(ctx->drmFD, info->ringStart, info->ringMapSize,
+ DRM_AGP, flags, &info->ringHandle) < 0) {
+ fprintf(stderr,
+ "[agp] Could not add ring mapping\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] ring handle = 0x%08lx\n", info->ringHandle);
+
+ if (drmMap(ctx->drmFD, info->ringHandle, info->ringMapSize,
+ (drmAddressPtr)&info->ring) < 0) {
+ fprintf(stderr, "[agp] Could not map ring\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] Ring mapped at 0x%08lx\n",
+ (unsigned long)info->ring);
+
+ if (drmAddMap(ctx->drmFD, info->ringReadOffset, info->ringReadMapSize,
+ DRM_AGP, flags, &info->ringReadPtrHandle) < 0) {
+ fprintf(stderr,
+ "[agp] Could not add ring read ptr mapping\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] ring read ptr handle = 0x%08lx\n",
+ info->ringReadPtrHandle);
+
+ if (drmMap(ctx->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
+ (drmAddressPtr)&info->ringReadPtr) < 0) {
+ fprintf(stderr,
+ "[agp] Could not map ring read ptr\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] Ring read ptr mapped at 0x%08lx\n",
+ (unsigned long)info->ringReadPtr);
+
+ if (drmAddMap(ctx->drmFD, info->bufStart, info->bufMapSize,
+ DRM_AGP, 0, &info->bufHandle) < 0) {
+ fprintf(stderr,
+ "[agp] Could not add vertex/indirect buffers mapping\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] vertex/indirect buffers handle = 0x%08lx\n",
+ info->bufHandle);
+
+ if (drmMap(ctx->drmFD, info->bufHandle, info->bufMapSize,
+ (drmAddressPtr)&info->buf) < 0) {
+ fprintf(stderr,
+ "[agp] Could not map vertex/indirect buffers\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] Vertex/indirect buffers mapped at 0x%08lx\n",
+ (unsigned long)info->buf);
+
+ if (drmAddMap(ctx->drmFD, info->agpTexStart, info->agpTexMapSize,
+ DRM_AGP, 0, &info->agpTexHandle) < 0) {
+ fprintf(stderr,
+ "[agp] Could not add AGP texture map mapping\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] AGP texture map handle = 0x%08lx\n",
+ info->agpTexHandle);
+
+ if (drmMap(ctx->drmFD, info->agpTexHandle, info->agpTexMapSize,
+ (drmAddressPtr)&info->agpTex) < 0) {
+ fprintf(stderr,
+ "[agp] Could not map AGP texture map\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[agp] AGP Texture map mapped at 0x%08lx\n",
+ (unsigned long)info->agpTex);
+
+ /* Initialize Rage 128's AGP registers */
+ cntl = INREG(R128_AGP_CNTL);
+ cntl &= ~R128_AGP_APER_SIZE_MASK;
+ switch (info->agpSize) {
+ case 256: cntl |= R128_AGP_APER_SIZE_256MB; break;
+ case 128: cntl |= R128_AGP_APER_SIZE_128MB; break;
+ case 64: cntl |= R128_AGP_APER_SIZE_64MB; break;
+ case 32: cntl |= R128_AGP_APER_SIZE_32MB; break;
+ case 16: cntl |= R128_AGP_APER_SIZE_16MB; break;
+ case 8: cntl |= R128_AGP_APER_SIZE_8MB; break;
+ case 4: cntl |= R128_AGP_APER_SIZE_4MB; break;
+ default:
+ fprintf(stderr,
+ "[agp] Illegal aperture size %d kB\n",
+ info->agpSize*1024);
+ return GL_FALSE;
+ }
+ agpBase = drmAgpBase(ctx->drmFD);
+ OUTREG(R128_AGP_BASE, agpBase);
+ OUTREG(R128_AGP_CNTL, cntl);
+
+ /* Disable Rage 128's PCIGART registers */
+ chunk = INREG(R128_BM_CHUNK_0_VAL);
+ chunk &= ~(R128_BM_PTR_FORCE_TO_PCI |
+ R128_BM_PM4_RD_FORCE_TO_PCI |
+ R128_BM_GLOBAL_FORCE_TO_PCI);
+ OUTREG(R128_BM_CHUNK_0_VAL, chunk);
+
+ OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */
+
+ return GL_TRUE;
+}
+
+static GLboolean R128DRIPciInit(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ unsigned char *R128MMIO = ctx->MMIOAddress;
+ CARD32 chunk;
+ int ret;
+ int flags;
+
+ info->agpOffset = 0;
+
+ ret = drmScatterGatherAlloc(ctx->drmFD, info->agpSize*1024*1024,
+ &info->pciMemHandle);
+ if (ret < 0) {
+ fprintf(stderr, "[pci] Out of memory (%d)\n", ret);
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[pci] %d kB allocated with handle 0x%08x\n",
+ info->agpSize*1024, info->pciMemHandle);
+
+ /* Initialize the CCE ring buffer data */
+ info->ringStart = info->agpOffset;
+ info->ringMapSize = info->ringSize*1024*1024 + DRM_PAGE_SIZE;
+ info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1;
+
+ info->ringReadOffset = info->ringStart + info->ringMapSize;
+ info->ringReadMapSize = DRM_PAGE_SIZE;
+
+ /* Reserve space for vertex/indirect buffers */
+ info->bufStart = info->ringReadOffset + info->ringReadMapSize;
+ info->bufMapSize = info->bufSize*1024*1024;
+
+ flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL;
+
+ if (drmAddMap(ctx->drmFD, info->ringStart, info->ringMapSize,
+ DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add ring mapping\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[pci] ring handle = 0x%08lx\n", info->ringHandle);
+
+ if (drmMap(ctx->drmFD, info->ringHandle, info->ringMapSize,
+ (drmAddressPtr)&info->ring) < 0) {
+ fprintf(stderr, "[pci] Could not map ring\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[pci] Ring mapped at 0x%08lx\n",
+ (unsigned long)info->ring);
+ fprintf(stderr,
+ "[pci] Ring contents 0x%08lx\n",
+ *(unsigned long *)info->ring);
+
+ if (drmAddMap(ctx->drmFD, info->ringReadOffset, info->ringReadMapSize,
+ DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add ring read ptr mapping\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[pci] ring read ptr handle = 0x%08lx\n",
+ info->ringReadPtrHandle);
+
+ if (drmMap(ctx->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
+ (drmAddressPtr)&info->ringReadPtr) < 0) {
+ fprintf(stderr,
+ "[pci] Could not map ring read ptr\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[pci] Ring read ptr mapped at 0x%08lx\n",
+ (unsigned long)info->ringReadPtr);
+ fprintf(stderr,
+ "[pci] Ring read ptr contents 0x%08lx\n",
+ *(unsigned long *)info->ringReadPtr);
+
+ if (drmAddMap(ctx->drmFD, info->bufStart, info->bufMapSize,
+ DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add vertex/indirect buffers mapping\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[pci] vertex/indirect buffers handle = 0x%08lx\n",
+ info->bufHandle);
+
+ if (drmMap(ctx->drmFD, info->bufHandle, info->bufMapSize,
+ (drmAddressPtr)&info->buf) < 0) {
+ fprintf(stderr,
+ "[pci] Could not map vertex/indirect buffers\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[pci] Vertex/indirect buffers mapped at 0x%08lx\n",
+ (unsigned long)info->buf);
+ fprintf(stderr,
+ "[pci] Vertex/indirect buffers contents 0x%08lx\n",
+ *(unsigned long *)info->buf);
+
+ if (!info->IsPCI) {
+ /* This is really an AGP card, force PCI GART mode */
+ chunk = INREG(R128_BM_CHUNK_0_VAL);
+ chunk |= (R128_BM_PTR_FORCE_TO_PCI |
+ R128_BM_PM4_RD_FORCE_TO_PCI |
+ R128_BM_GLOBAL_FORCE_TO_PCI);
+ OUTREG(R128_BM_CHUNK_0_VAL, chunk);
+ OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */
+ }
+
+ return GL_TRUE;
+}
+
+/* Add a map for the MMIO registers that will be accessed by any
+ DRI-based clients. */
+static GLboolean R128DRIMapInit(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ int flags;
+
+ if (info->CCESecure) flags = DRM_READ_ONLY;
+ else flags = 0;
+
+ /* Map registers */
+ if (drmAddMap(ctx->drmFD, ctx->MMIOStart, ctx->MMIOSize,
+ DRM_REGISTERS, flags, &info->registerHandle) < 0) {
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[drm] register handle = 0x%08lx\n", info->registerHandle);
+
+ return GL_TRUE;
+}
+
+/* Initialize the kernel data structures. */
+static int R128DRIKernelInit(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ drmR128Init drmInfo;
+
+ memset( &drmInfo, 0, sizeof(drmR128Init) );
+
+ drmInfo.func = DRM_R128_INIT_CCE;
+ drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
+ drmInfo.is_pci = info->IsPCI;
+ drmInfo.cce_mode = info->CCEMode;
+ drmInfo.cce_secure = info->CCESecure;
+ drmInfo.ring_size = info->ringSize*1024*1024;
+ drmInfo.usec_timeout = info->CCEusecTimeout;
+
+ drmInfo.fb_bpp = ctx->bpp;
+ drmInfo.depth_bpp = ctx->bpp;
+
+ drmInfo.front_offset = info->frontOffset;
+ drmInfo.front_pitch = info->frontPitch;
+
+ drmInfo.back_offset = info->backOffset;
+ drmInfo.back_pitch = info->backPitch;
+
+ drmInfo.depth_offset = info->depthOffset;
+ drmInfo.depth_pitch = info->depthPitch;
+ drmInfo.span_offset = info->spanOffset;
+
+ drmInfo.fb_offset = info->LinearAddr;
+ drmInfo.mmio_offset = info->registerHandle;
+ drmInfo.ring_offset = info->ringHandle;
+ drmInfo.ring_rptr_offset = info->ringReadPtrHandle;
+ drmInfo.buffers_offset = info->bufHandle;
+ drmInfo.agp_textures_offset = info->agpTexHandle;
+
+ if (drmCommandWrite(ctx->drmFD, DRM_R128_INIT,
+ &drmInfo, sizeof(drmR128Init)) < 0)
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+/* Add a map for the vertex buffers that will be accessed by any
+ DRI-based clients. */
+static GLboolean R128DRIBufInit(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ /* Initialize vertex buffers */
+ if (info->IsPCI) {
+ info->bufNumBufs = drmAddBufs(ctx->drmFD,
+ info->bufMapSize / R128_BUFFER_SIZE,
+ R128_BUFFER_SIZE,
+ DRM_SG_BUFFER,
+ info->bufStart);
+ } else {
+ info->bufNumBufs = drmAddBufs(ctx->drmFD,
+ info->bufMapSize / R128_BUFFER_SIZE,
+ R128_BUFFER_SIZE,
+ DRM_AGP_BUFFER,
+ info->bufStart);
+ }
+ if (info->bufNumBufs <= 0) {
+ fprintf(stderr,
+ "[drm] Could not create vertex/indirect buffers list\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[drm] Added %d %d byte vertex/indirect buffers\n",
+ info->bufNumBufs, R128_BUFFER_SIZE);
+
+ if (!(info->buffers = drmMapBufs(ctx->drmFD))) {
+ fprintf(stderr,
+ "[drm] Failed to map vertex/indirect buffers list\n");
+ return GL_FALSE;
+ }
+ fprintf(stderr,
+ "[drm] Mapped %d vertex/indirect buffers\n",
+ info->buffers->count);
+
+ return GL_TRUE;
+}
+
+static void R128DRIIrqInit(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ unsigned char *R128MMIO = ctx->MMIOAddress;
+
+ if (!info->irq) {
+ info->irq = drmGetInterruptFromBusID(
+ ctx->drmFD,
+ ctx->pciBus,
+ ctx->pciDevice,
+ ctx->pciFunc);
+
+ if((drmCtlInstHandler(ctx->drmFD, info->irq)) != 0) {
+ fprintf(stderr,
+ "[drm] failure adding irq handler, "
+ "there is a device already using that irq\n"
+ "[drm] falling back to irq-free operation\n");
+ info->irq = 0;
+ } else {
+ info->gen_int_cntl = INREG( R128_GEN_INT_CNTL );
+ }
+ }
+
+ if (info->irq)
+ fprintf(stderr,
+ "[drm] dma control initialized, using IRQ %d\n",
+ info->irq);
+}
+
+static int R128CCEStop(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ drmR128CCEStop stop;
+ int ret, i;
+
+ stop.flush = 1;
+ stop.idle = 1;
+
+ ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP,
+ &stop, sizeof(drmR128CCEStop) );
+
+ if ( ret == 0 ) {
+ return 0;
+ } else if ( errno != EBUSY ) {
+ return -errno;
+ }
+
+ stop.flush = 0;
+
+ i = 0;
+ do {
+ ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP,
+ &stop, sizeof(drmR128CCEStop) );
+ } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY );
+
+ if ( ret == 0 ) {
+ return 0;
+ } else if ( errno != EBUSY ) {
+ return -errno;
+ }
+
+ stop.idle = 0;
+
+ if ( drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP,
+ &stop, sizeof(drmR128CCEStop) )) {
+ return -errno;
+ } else {
+ return 0;
+ }
+}
+
+/* Initialize the CCE state, and start the CCE (if used by the X server) */
+static void R128DRICCEInit(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+
+ /* Turn on bus mastering */
+ info->BusCntl &= ~R128_BUS_MASTER_DIS;
+
+ /* CCEMode is initialized in r128_driver.c */
+ switch (info->CCEMode) {
+ case R128_PM4_NONPM4: info->CCEFifoSize = 0; break;
+ case R128_PM4_192PIO: info->CCEFifoSize = 192; break;
+ case R128_PM4_192BM: info->CCEFifoSize = 192; break;
+ case R128_PM4_128PIO_64INDBM: info->CCEFifoSize = 128; break;
+ case R128_PM4_128BM_64INDBM: info->CCEFifoSize = 128; break;
+ case R128_PM4_64PIO_128INDBM: info->CCEFifoSize = 64; break;
+ case R128_PM4_64BM_128INDBM: info->CCEFifoSize = 64; break;
+ case R128_PM4_64PIO_64VCBM_64INDBM: info->CCEFifoSize = 64; break;
+ case R128_PM4_64BM_64VCBM_64INDBM: info->CCEFifoSize = 64; break;
+ case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64; break;
+ }
+
+ /* Make sure the CCE is on for the X server */
+ R128CCE_START(ctx, info);
+}
+
+
+static int R128MemoryInit(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ int width_bytes = ctx->shared.virtualWidth * ctx->cpp;
+ int cpp = ctx->cpp;
+ int bufferSize = ((ctx->shared.virtualHeight * width_bytes
+ + R128_BUFFER_ALIGN)
+ & ~R128_BUFFER_ALIGN);
+ int depthSize = ((((ctx->shared.virtualHeight+15) & ~15) * width_bytes
+ + R128_BUFFER_ALIGN)
+ & ~R128_BUFFER_ALIGN);
+ int l;
+
+ info->frontOffset = 0;
+ info->frontPitch = ctx->shared.virtualWidth;
+
+ fprintf(stderr,
+ "Using %d MB AGP aperture\n", info->agpSize);
+ fprintf(stderr,
+ "Using %d MB for the ring buffer\n", info->ringSize);
+ fprintf(stderr,
+ "Using %d MB for vertex/indirect buffers\n", info->bufSize);
+ fprintf(stderr,
+ "Using %d MB for AGP textures\n", info->agpTexSize);
+
+ /* Front, back and depth buffers - everything else texture??
+ */
+ info->textureSize = ctx->shared.fbSize - 2 * bufferSize - depthSize;
+
+ if (info->textureSize < 0)
+ return 0;
+
+ l = R128MinBits((info->textureSize-1) / R128_NR_TEX_REGIONS);
+ if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY;
+
+ /* Round the texture size up to the nearest whole number of
+ * texture regions. Again, be greedy about this, don't
+ * round down.
+ */
+ info->log2TexGran = l;
+ info->textureSize = (info->textureSize >> l) << l;
+
+ /* Set a minimum usable local texture heap size. This will fit
+ * two 256x256x32bpp textures.
+ */
+ if (info->textureSize < 512 * 1024) {
+ info->textureOffset = 0;
+ info->textureSize = 0;
+ }
+
+ /* Reserve space for textures */
+ info->textureOffset = ((ctx->shared.fbSize - info->textureSize +
+ R128_BUFFER_ALIGN) &
+ ~R128_BUFFER_ALIGN);
+
+ /* Reserve space for the shared depth
+ * buffer.
+ */
+ info->depthOffset = ((info->textureOffset - depthSize +
+ R128_BUFFER_ALIGN) &
+ ~R128_BUFFER_ALIGN);
+ info->depthPitch = ctx->shared.virtualWidth;
+
+ info->backOffset = ((info->depthOffset - bufferSize +
+ R128_BUFFER_ALIGN) &
+ ~R128_BUFFER_ALIGN);
+ info->backPitch = ctx->shared.virtualWidth;
+
+
+ fprintf(stderr,
+ "Will use back buffer at offset 0x%x\n",
+ info->backOffset);
+ fprintf(stderr,
+ "Will use depth buffer at offset 0x%x\n",
+ info->depthOffset);
+ fprintf(stderr,
+ "Will use %d kb for textures at offset 0x%x\n",
+ info->textureSize/1024, info->textureOffset);
+
+ return 1;
+}
+
+
+/* Initialize the screen-specific data structures for the DRI and the
+ Rage 128. This is the main entry point to the device-specific
+ initialization code. It calls device-independent DRI functions to
+ create the DRI data structures and initialize the DRI state. */
+static GLboolean R128DRIScreenInit(DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ R128DRIPtr pR128DRI;
+ int err, major, minor, patch;
+ drmVersionPtr version;
+
+ switch (ctx->bpp) {
+ case 8:
+ /* These modes are not supported (yet). */
+ case 15:
+ case 24:
+ fprintf(stderr,
+ "[dri] R128DRIScreenInit failed (depth %d not supported). "
+ "[dri] Disabling DRI.\n", ctx->bpp);
+ return GL_FALSE;
+
+ /* Only 16 and 32 color depths are supports currently. */
+ case 16:
+ case 32:
+ break;
+ }
+
+ info->registerSize = ctx->MMIOSize;
+ ctx->shared.SAREASize = DRM_PAGE_SIZE;
+
+ /* Note that drmOpen will try to load the kernel module, if needed. */
+ ctx->drmFD = drmOpen("r128", NULL );
+ if (ctx->drmFD < 0) {
+ fprintf(stderr, "[drm] drmOpen failed\n");
+ return 0;
+ }
+
+ /* Check the r128 DRM version */
+ version = drmGetVersion(ctx->drmFD);
+ if (version) {
+ if (version->version_major != 2 ||
+ version->version_minor < 2) {
+ /* incompatible drm version */
+ fprintf(stderr,
+ "[dri] R128DRIScreenInit failed because of a version mismatch.\n"
+ "[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n"
+ "[dri] Disabling the DRI.\n",
+ version->version_major,
+ version->version_minor,
+ version->version_patchlevel);
+ drmFreeVersion(version);
+ return GL_FALSE;
+ }
+ info->drmMinor = version->version_minor;
+ drmFreeVersion(version);
+ }
+
+ if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) {
+ fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n",
+ ctx->drmFD, ctx->pciBusID, strerror(-err));
+ return 0;
+ }
+
+ if (drmAddMap( ctx->drmFD,
+ 0,
+ ctx->shared.SAREASize,
+ DRM_SHM,
+ DRM_CONTAINS_LOCK,
+ &ctx->shared.hSAREA) < 0)
+ {
+ fprintf(stderr, "[drm] drmAddMap failed\n");
+ return 0;
+ }
+ fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n",
+ ctx->shared.SAREASize, ctx->shared.hSAREA);
+
+ if (drmMap( ctx->drmFD,
+ ctx->shared.hSAREA,
+ ctx->shared.SAREASize,
+ (drmAddressPtr)(&ctx->pSAREA)) < 0)
+ {
+ fprintf(stderr, "[drm] drmMap failed\n");
+ return 0;
+ }
+ memset(ctx->pSAREA, 0, ctx->shared.SAREASize);
+ fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
+ ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize);
+
+ /* Need to AddMap the framebuffer and mmio regions here:
+ */
+ if (drmAddMap( ctx->drmFD,
+ (drmHandle)ctx->FBStart,
+ ctx->FBSize,
+ DRM_FRAME_BUFFER,
+ 0,
+ &ctx->shared.hFrameBuffer) < 0)
+ {
+ fprintf(stderr, "[drm] drmAddMap framebuffer failed\n");
+ return 0;
+ }
+
+ fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n",
+ ctx->shared.hFrameBuffer);
+
+ if (!R128MemoryInit(ctx))
+ return GL_FALSE;
+
+ /* Initialize AGP */
+ if (!info->IsPCI && !R128DRIAgpInit(ctx)) {
+ info->IsPCI = GL_TRUE;
+ fprintf(stderr,
+ "[agp] AGP failed to initialize -- falling back to PCI mode.\n");
+ fprintf(stderr,
+ "[agp] Make sure you have the agpgart kernel module loaded.\n");
+ }
+
+ /* Initialize PCIGART */
+ if (info->IsPCI && !R128DRIPciInit(ctx)) {
+ return GL_FALSE;
+ }
+
+ /* DRIScreenInit doesn't add all the
+ common mappings. Add additional
+ mappings here. */
+ if (!R128DRIMapInit(ctx)) {
+ return GL_FALSE;
+ }
+
+ /* Create a 'server' context so we can grab the lock for
+ * initialization ioctls.
+ */
+ if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) {
+ fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+ DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0);
+
+ /* Initialize the kernel data structures */
+ if (!R128DRIKernelInit(ctx)) {
+ return GL_FALSE;
+ }
+
+ /* Initialize the vertex buffers list */
+ if (!R128DRIBufInit(ctx)) {
+ return GL_FALSE;
+ }
+
+ /* Initialize IRQ */
+ R128DRIIrqInit(ctx);
+
+ /* Initialize and start the CCE if required */
+ R128DRICCEInit(ctx);
+
+ /* Quick hack to clear the front & back buffers. Could also use
+ * the clear ioctl to do this, but would need to setup hw state
+ * first.
+ */
+ memset((char *)ctx->FBAddress + info->frontOffset,
+ 0,
+ info->frontPitch * ctx->cpp * ctx->shared.virtualHeight );
+
+ memset((char *)ctx->FBAddress + info->backOffset,
+ 0,
+ info->backPitch * ctx->cpp * ctx->shared.virtualHeight );
+
+ R128SAREAPrivPtr pSAREAPriv;
+ pSAREAPriv = (R128SAREAPrivPtr)(((char*)ctx->pSAREA) +
+ sizeof(XF86DRISAREARec));
+ memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
+
+ /* This is the struct passed to radeon_dri.so for its initialization */
+ ctx->driverClientMsg = malloc(sizeof(R128DRIRec));
+ ctx->driverClientMsgSize = sizeof(R128DRIRec);
+
+ pR128DRI = (R128DRIPtr)ctx->driverClientMsg;
+ pR128DRI->deviceID = info->Chipset;
+ pR128DRI->width = ctx->shared.virtualWidth;
+ pR128DRI->height = ctx->shared.virtualHeight;
+ pR128DRI->depth = ctx->bpp;
+ pR128DRI->bpp = ctx->bpp;
+
+ pR128DRI->IsPCI = info->IsPCI;
+ pR128DRI->AGPMode = info->agpMode;
+
+ pR128DRI->frontOffset = info->frontOffset;
+ pR128DRI->frontPitch = info->frontPitch;
+ pR128DRI->backOffset = info->backOffset;
+ pR128DRI->backPitch = info->backPitch;
+ pR128DRI->depthOffset = info->depthOffset;
+ pR128DRI->depthPitch = info->depthPitch;
+ pR128DRI->spanOffset = info->spanOffset;
+ pR128DRI->textureOffset = info->textureOffset;
+ pR128DRI->textureSize = info->textureSize;
+ pR128DRI->log2TexGran = info->log2TexGran;
+
+ pR128DRI->registerHandle = info->registerHandle;
+ pR128DRI->registerSize = info->registerSize;
+
+ pR128DRI->agpTexHandle = info->agpTexHandle;
+ pR128DRI->agpTexMapSize = info->agpTexMapSize;
+ pR128DRI->log2AGPTexGran = info->log2AGPTexGran;
+ pR128DRI->agpTexOffset = info->agpTexStart;
+ pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
+
+ return GL_TRUE;
+}
+
+/* The screen is being closed, so clean up any state and free any
+ resources used by the DRI. */
+void R128DRICloseScreen(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+ drmR128Init drmInfo;
+
+ /* Stop the CCE if it is still in use */
+ R128CCE_STOP(ctx, info);
+
+ if (info->irq) {
+ drmCtlUninstHandler(ctx->drmFD);
+ info->irq = 0;
+ }
+
+ /* De-allocate vertex buffers */
+ if (info->buffers) {
+ drmUnmapBufs(info->buffers);
+ info->buffers = NULL;
+ }
+
+ /* De-allocate all kernel resources */
+ memset(&drmInfo, 0, sizeof(drmR128Init));
+ drmInfo.func = DRM_R128_CLEANUP_CCE;
+ drmCommandWrite(ctx->drmFD, DRM_R128_INIT,
+ &drmInfo, sizeof(drmR128Init));
+
+ /* De-allocate all AGP resources */
+ if (info->agpTex) {
+ drmUnmap(info->agpTex, info->agpTexMapSize);
+ info->agpTex = NULL;
+ }
+ if (info->buf) {
+ drmUnmap(info->buf, info->bufMapSize);
+ info->buf = NULL;
+ }
+ if (info->ringReadPtr) {
+ drmUnmap(info->ringReadPtr, info->ringReadMapSize);
+ info->ringReadPtr = NULL;
+ }
+ if (info->ring) {
+ drmUnmap(info->ring, info->ringMapSize);
+ info->ring = NULL;
+ }
+ if (info->agpMemHandle != DRM_AGP_NO_HANDLE) {
+ drmAgpUnbind(ctx->drmFD, info->agpMemHandle);
+ drmAgpFree(ctx->drmFD, info->agpMemHandle);
+ info->agpMemHandle = 0;
+ drmAgpRelease(ctx->drmFD);
+ }
+ if (info->pciMemHandle) {
+ drmScatterGatherFree(ctx->drmFD, info->pciMemHandle);
+ info->pciMemHandle = 0;
+ }
+}
+
+static GLboolean R128PreInitDRI(const DRIDriverContext *ctx)
+{
+ R128InfoPtr info = ctx->driverPrivate;
+
+ /*info->CCEMode = R128_DEFAULT_CCE_PIO_MODE;*/
+ info->CCEMode = R128_DEFAULT_CCE_BM_MODE;
+ info->CCESecure = GL_TRUE;
+
+ info->agpMode = R128_DEFAULT_AGP_MODE;
+ info->agpSize = R128_DEFAULT_AGP_SIZE;
+ info->ringSize = R128_DEFAULT_RING_SIZE;
+ info->bufSize = R128_DEFAULT_BUFFER_SIZE;
+ info->agpTexSize = R128_DEFAULT_AGP_TEX_SIZE;
+
+ info->CCEusecTimeout = R128_DEFAULT_CCE_TIMEOUT;
+
+ return GL_TRUE;
+}
+
+/**
+ * \brief Initialize the framebuffer device mode
+ *
+ * \param ctx display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Fills in \p info with some default values and some information from \p ctx
+ * and then calls R128ScreenInit() for the screen initialization.
+ *
+ * Before exiting clears the framebuffer memory accessing it directly.
+ */
+static int R128InitFBDev( DRIDriverContext *ctx )
+{
+ R128InfoPtr info = calloc(1, sizeof(*info));
+
+ {
+ int dummy = ctx->shared.virtualWidth;
+
+ switch (ctx->bpp / 8) {
+ case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break;
+ case 2: dummy = (ctx->shared.virtualWidth + 31) & ~31; break;
+ case 3:
+ case 4: dummy = (ctx->shared.virtualWidth + 15) & ~15; break;
+ }
+
+ ctx->shared.virtualWidth = dummy;
+ }
+
+ ctx->driverPrivate = (void *)info;
+
+ info->Chipset = ctx->chipset;
+
+ switch (info->Chipset) {
+ case PCI_DEVICE_ID_ATI_RAGE128_LE:
+ case PCI_DEVICE_ID_ATI_RAGE128_RE:
+ case PCI_DEVICE_ID_ATI_RAGE128_RK:
+ case PCI_DEVICE_ID_ATI_RAGE128_PD:
+ case PCI_DEVICE_ID_ATI_RAGE128_PP:
+ case PCI_DEVICE_ID_ATI_RAGE128_PR:
+ /* This is a PCI card */
+ info->IsPCI = GL_TRUE;
+ break;
+ default:
+ /* This is an AGP card */
+ info->IsPCI = GL_FALSE;
+ break;
+ }
+
+ info->frontPitch = ctx->shared.virtualWidth;
+ info->LinearAddr = ctx->FBStart & 0xfc000000;
+
+ if (!R128PreInitDRI(ctx))
+ return 0;
+
+ if (!R128DRIScreenInit(ctx))
+ return 0;
+
+ return 1;
+}
+
+
+/**
+ * \brief The screen is being closed, so clean up any state and free any
+ * resources used by the DRI.
+ *
+ * \param ctx display handle.
+ *
+ * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
+ * private data.
+ */
+static void R128HaltFBDev( DRIDriverContext *ctx )
+{
+ drmUnmap( ctx->pSAREA, ctx->shared.SAREASize );
+ drmClose(ctx->drmFD);
+
+ if (ctx->driverPrivate) {
+ free(ctx->driverPrivate);
+ ctx->driverPrivate = 0;
+ }
+}
+
+
+/**
+ * \brief Validate the fbdev mode.
+ *
+ * \param ctx display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Saves some registers and returns 1.
+ *
+ * \sa R128PostValidateMode().
+ */
+static int R128ValidateMode( const DRIDriverContext *ctx )
+{
+ return 1;
+}
+
+
+/**
+ * \brief Examine mode returned by fbdev.
+ *
+ * \param ctx display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Restores registers that fbdev has clobbered and returns 1.
+ *
+ * \sa R128ValidateMode().
+ */
+static int R128PostValidateMode( const DRIDriverContext *ctx )
+{
+ return 1;
+}
+
+
+/**
+ * \brief Shutdown the drawing engine.
+ *
+ * \param ctx display handle
+ *
+ * Turns off the command processor engine & restores the graphics card
+ * to a state that fbdev understands.
+ */
+static int R128EngineShutdown( const DRIDriverContext *ctx )
+{
+ return 1;
+}
+
+/**
+ * \brief Restore the drawing engine.
+ *
+ * \param ctx display handle
+ *
+ * Resets the graphics card and sets initial values for several registers of
+ * the card's drawing engine.
+ *
+ * Turns on the R128 command processor engine (i.e., the ringbuffer).
+ */
+static int R128EngineRestore( const DRIDriverContext *ctx )
+{
+ return 1;
+}
+
+
+/**
+ * \brief Exported driver interface for Mini GLX.
+ *
+ * \sa DRIDriverRec.
+ */
+const struct DRIDriverRec __driDriver = {
+ R128InitContextModes,
+ R128ValidateMode,
+ R128PostValidateMode,
+ R128InitFBDev,
+ R128HaltFBDev,
+ R128EngineShutdown,
+ R128EngineRestore,
+ 0,
+};
diff --git a/src/mesa/drivers/dri/r128/server/r128_dri.h b/src/mesa/drivers/dri/r128/server/r128_dri.h
new file mode 100644
index 0000000000..80f94ded68
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128_dri.h
@@ -0,0 +1,103 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dri.h,v 1.7 2002/10/30 12:52:12 alanh Exp $ */
+/*
+ * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
+ * Precision Insight, Inc., Cedar Park, Texas, and
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
+ * SYSTEMS AND/OR THEIR SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Rickard E. Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef _R128_DRI_
+#define _R128_DRI_
+
+#include "xf86drm.h"
+#include "r128_common.h"
+
+/* DRI Driver defaults */
+#define R128_DEFAULT_CCE_PIO_MODE R128_PM4_64PIO_64VCBM_64INDBM
+#define R128_DEFAULT_CCE_BM_MODE R128_PM4_64BM_64VCBM_64INDBM
+#define R128_DEFAULT_AGP_MODE 1
+#define R128_DEFAULT_AGP_SIZE 8 /* MB (must be a power of 2 and > 4MB) */
+#define R128_DEFAULT_RING_SIZE 1 /* MB (must be page aligned) */
+#define R128_DEFAULT_BUFFER_SIZE 2 /* MB (must be page aligned) */
+#define R128_DEFAULT_AGP_TEX_SIZE 1 /* MB (must be page aligned) */
+
+#define R128_DEFAULT_CCE_TIMEOUT 10000 /* usecs */
+
+#define R128_AGP_MAX_MODE 4
+#define R128_BUFFER_ALIGN 0x00000fff
+
+#define R128_CARD_TYPE_R128 1
+#define R128_CARD_TYPE_R128_PRO 2
+#define R128_CARD_TYPE_R128_MOBILITY 3
+
+#define R128CCE_USE_RING_BUFFER(m) \
+(((m) == R128_PM4_192BM) || \
+ ((m) == R128_PM4_128BM_64INDBM) || \
+ ((m) == R128_PM4_64BM_128INDBM) || \
+ ((m) == R128_PM4_64BM_64VCBM_64INDBM))
+
+typedef struct {
+ /* DRI screen private data */
+ int deviceID; /* PCI device ID */
+ int width; /* Width in pixels of display */
+ int height; /* Height in scanlines of display */
+ int depth; /* Depth of display (8, 15, 16, 24) */
+ int bpp; /* Bit depth of display (8, 16, 24, 32) */
+
+ int IsPCI; /* Current card is a PCI card */
+ int AGPMode;
+
+ int frontOffset; /* Start of front buffer */
+ int frontPitch;
+ int backOffset; /* Start of shared back buffer */
+ int backPitch;
+ int depthOffset; /* Start of shared depth buffer */
+ int depthPitch;
+ int spanOffset; /* Start of scratch spanline */
+ int textureOffset;/* Start of texture data in frame buffer */
+ int textureSize;
+ int log2TexGran;
+
+ /* MMIO register data */
+ drmHandle registerHandle;
+ drmSize registerSize;
+
+ /* CCE AGP Texture data */
+ drmHandle agpTexHandle;
+ drmSize agpTexMapSize;
+ int log2AGPTexGran;
+ int agpTexOffset;
+ unsigned int sarea_priv_offset;
+} R128DRIRec, *R128DRIPtr;
+
+#endif
diff --git a/src/mesa/drivers/dri/r128/server/r128_macros.h b/src/mesa/drivers/dri/r128/server/r128_macros.h
new file mode 100644
index 0000000000..93b7feb02c
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128_macros.h
@@ -0,0 +1,135 @@
+/**
+ * \file server/R128_macros.h
+ * \brief Macros for R128 MMIO operation.
+ *
+ * \authors Kevin E. Martin <martin@xfree86.org>
+ * \authors Rickard E. Faith <faith@valinux.com>
+ * \authors Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS 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/programs/Xserver/hw/xfree86/drivers/ati/R128_reg.h,v 1.20 2002/10/12 01:38:07 martin Exp $ */
+
+#ifndef _R128_MACROS_H_
+#define _R128_MACROS_H_
+
+
+
+# define MMIO_IN8(base, offset) \
+ *(volatile unsigned char *)(((unsigned char*)(base)) + (offset))
+# define MMIO_IN16(base, offset) \
+ *(volatile unsigned short *)(void *)(((unsigned char*)(base)) + (offset))
+# define MMIO_IN32(base, offset) \
+ *(volatile unsigned int *)(void *)(((unsigned char*)(base)) + (offset))
+# define MMIO_OUT8(base, offset, val) \
+ *(volatile unsigned char *)(((unsigned char*)(base)) + (offset)) = (val)
+# define MMIO_OUT16(base, offset, val) \
+ *(volatile unsigned short *)(void *)(((unsigned char*)(base)) + (offset)) = (val)
+# define MMIO_OUT32(base, offset, val) \
+ *(volatile unsigned int *)(void *)(((unsigned char*)(base)) + (offset)) = (val)
+
+
+ /* Memory mapped register access macros */
+#define INREG8(addr) MMIO_IN8(R128MMIO, addr)
+#define INREG16(addr) MMIO_IN16(R128MMIO, addr)
+#define INREG(addr) MMIO_IN32(R128MMIO, addr)
+#define OUTREG8(addr, val) MMIO_OUT8(R128MMIO, addr, val)
+#define OUTREG16(addr, val) MMIO_OUT16(R128MMIO, addr, val)
+#define OUTREG(addr, val) MMIO_OUT32(R128MMIO, addr, val)
+
+#define ADDRREG(addr) ((volatile GLuint *)(pointer)(R128MMIO + (addr)))
+
+
+#define OUTREGP(addr, val, mask) \
+do { \
+ GLuint tmp = INREG(addr); \
+ tmp &= (mask); \
+ tmp |= (val); \
+ OUTREG(addr, tmp); \
+} while (0)
+
+#define INPLL(dpy, addr) r128INPLL(dpy, addr)
+
+#define OUTPLL(addr, val) \
+do { \
+ OUTREG8(R128_CLOCK_CNTL_INDEX, (((addr) & 0x3f) | \
+ R128_PLL_WR_EN)); \
+ OUTREG(R128_CLOCK_CNTL_DATA, val); \
+} while (0)
+
+#define OUTPLLP(dpy, addr, val, mask) \
+do { \
+ GLuint tmp = INPLL(dpy, addr); \
+ tmp &= (mask); \
+ tmp |= (val); \
+ OUTPLL(addr, tmp); \
+} while (0)
+
+#define OUTPAL_START(idx) \
+do { \
+ OUTREG8(R128_PALETTE_INDEX, (idx)); \
+} while (0)
+
+#define OUTPAL_NEXT(r, g, b) \
+do { \
+ OUTREG(R128_PALETTE_DATA, ((r) << 16) | ((g) << 8) | (b)); \
+} while (0)
+
+#define OUTPAL_NEXT_CARD32(v) \
+do { \
+ OUTREG(R128_PALETTE_DATA, (v & 0x00ffffff)); \
+} while (0)
+
+#define OUTPAL(idx, r, g, b) \
+do { \
+ OUTPAL_START((idx)); \
+ OUTPAL_NEXT((r), (g), (b)); \
+} while (0)
+
+#define INPAL_START(idx) \
+do { \
+ OUTREG(R128_PALETTE_INDEX, (idx) << 16); \
+} while (0)
+
+#define INPAL_NEXT() INREG(R128_PALETTE_DATA)
+
+#define PAL_SELECT(idx) \
+do { \
+ if (!idx) { \
+ OUTREG(R128_DAC_CNTL2, INREG(R128_DAC_CNTL2) & \
+ (GLuint)~R128_DAC2_PALETTE_ACC_CTL); \
+ } else { \
+ OUTREG(R128_DAC_CNTL2, INREG(R128_DAC_CNTL2) | \
+ R128_DAC2_PALETTE_ACC_CTL); \
+ } \
+} while (0)
+
+
+#endif
diff --git a/src/mesa/drivers/dri/r128/server/r128_reg.h b/src/mesa/drivers/dri/r128/server/r128_reg.h
new file mode 100644
index 0000000000..7ec4004492
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128_reg.h
@@ -0,0 +1,1431 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_reg.h,v 1.15 2002/12/16 16:19:11 dawes Exp $ */
+/*
+ * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
+ * Precision Insight, Inc., Cedar Park, Texas, and
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
+ * SYSTEMS AND/OR THEIR SUPPLIERS 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:
+ * Rickard E. Faith <faith@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ * References:
+ *
+ * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
+ * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
+ * 1999.
+ *
+ * RAGE 128 Software Development Manual (Technical Reference Manual P/N
+ * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
+ *
+ */
+
+#ifndef _R128_REG_H_
+#define _R128_REG_H_
+
+#define R128_ADAPTER_ID 0x0f2c /* PCI */
+#define R128_AGP_APER_OFFSET 0x0178
+#define R128_AGP_BASE 0x0170
+#define R128_AGP_CNTL 0x0174
+# define R128_AGP_APER_SIZE_256MB (0x00 << 0)
+# define R128_AGP_APER_SIZE_128MB (0x20 << 0)
+# define R128_AGP_APER_SIZE_64MB (0x30 << 0)
+# define R128_AGP_APER_SIZE_32MB (0x38 << 0)
+# define R128_AGP_APER_SIZE_16MB (0x3c << 0)
+# define R128_AGP_APER_SIZE_8MB (0x3e << 0)
+# define R128_AGP_APER_SIZE_4MB (0x3f << 0)
+# define R128_AGP_APER_SIZE_MASK (0x3f << 0)
+#define R128_AGP_CNTL_B 0x0b44
+#define R128_AGP_COMMAND 0x0f58 /* PCI */
+#define R128_AGP_PLL_CNTL 0x0010 /* PLL */
+#define R128_AGP_STATUS 0x0f54 /* PCI */
+# define R128_AGP_1X_MODE 0x01
+# define R128_AGP_2X_MODE 0x02
+# define R128_AGP_4X_MODE 0x04
+# define R128_AGP_MODE_MASK 0x07
+#define R128_AMCGPIO_A_REG 0x01a0
+#define R128_AMCGPIO_EN_REG 0x01a8
+#define R128_AMCGPIO_MASK 0x0194
+#define R128_AMCGPIO_Y_REG 0x01a4
+#define R128_ATTRDR 0x03c1 /* VGA */
+#define R128_ATTRDW 0x03c0 /* VGA */
+#define R128_ATTRX 0x03c0 /* VGA */
+#define R128_AUX_SC_CNTL 0x1660
+# define R128_AUX1_SC_EN (1 << 0)
+# define R128_AUX1_SC_MODE_OR (0 << 1)
+# define R128_AUX1_SC_MODE_NAND (1 << 1)
+# define R128_AUX2_SC_EN (1 << 2)
+# define R128_AUX2_SC_MODE_OR (0 << 3)
+# define R128_AUX2_SC_MODE_NAND (1 << 3)
+# define R128_AUX3_SC_EN (1 << 4)
+# define R128_AUX3_SC_MODE_OR (0 << 5)
+# define R128_AUX3_SC_MODE_NAND (1 << 5)
+#define R128_AUX1_SC_BOTTOM 0x1670
+#define R128_AUX1_SC_LEFT 0x1664
+#define R128_AUX1_SC_RIGHT 0x1668
+#define R128_AUX1_SC_TOP 0x166c
+#define R128_AUX2_SC_BOTTOM 0x1680
+#define R128_AUX2_SC_LEFT 0x1674
+#define R128_AUX2_SC_RIGHT 0x1678
+#define R128_AUX2_SC_TOP 0x167c
+#define R128_AUX3_SC_BOTTOM 0x1690
+#define R128_AUX3_SC_LEFT 0x1684
+#define R128_AUX3_SC_RIGHT 0x1688
+#define R128_AUX3_SC_TOP 0x168c
+#define R128_AUX_WINDOW_HORZ_CNTL 0x02d8
+#define R128_AUX_WINDOW_VERT_CNTL 0x02dc
+
+#define R128_BASE_CODE 0x0f0b
+#define R128_BIOS_0_SCRATCH 0x0010
+#define R128_BIOS_1_SCRATCH 0x0014
+#define R128_BIOS_2_SCRATCH 0x0018
+#define R128_BIOS_3_SCRATCH 0x001c
+#define R128_BIOS_4_SCRATCH 0x0020
+#define R128_BIOS_5_SCRATCH 0x0024
+# define R128_BIOS_DISPLAY_FP (1 << 0)
+# define R128_BIOS_DISPLAY_CRT (2 << 0)
+# define R128_BIOS_DISPLAY_FP_CRT (3 << 0)
+#define R128_BIOS_6_SCRATCH 0x0028
+#define R128_BIOS_7_SCRATCH 0x002c
+#define R128_BIOS_ROM 0x0f30 /* PCI */
+#define R128_BIST 0x0f0f /* PCI */
+#define R128_BM_CHUNK_0_VAL 0x0a18
+# define R128_BM_PTR_FORCE_TO_PCI (1 << 21)
+# define R128_BM_PM4_RD_FORCE_TO_PCI (1 << 22)
+# define R128_BM_GLOBAL_FORCE_TO_PCI (1 << 23)
+#define R128_BRUSH_DATA0 0x1480
+#define R128_BRUSH_DATA1 0x1484
+#define R128_BRUSH_DATA10 0x14a8
+#define R128_BRUSH_DATA11 0x14ac
+#define R128_BRUSH_DATA12 0x14b0
+#define R128_BRUSH_DATA13 0x14b4
+#define R128_BRUSH_DATA14 0x14b8
+#define R128_BRUSH_DATA15 0x14bc
+#define R128_BRUSH_DATA16 0x14c0
+#define R128_BRUSH_DATA17 0x14c4
+#define R128_BRUSH_DATA18 0x14c8
+#define R128_BRUSH_DATA19 0x14cc
+#define R128_BRUSH_DATA2 0x1488
+#define R128_BRUSH_DATA20 0x14d0
+#define R128_BRUSH_DATA21 0x14d4
+#define R128_BRUSH_DATA22 0x14d8
+#define R128_BRUSH_DATA23 0x14dc
+#define R128_BRUSH_DATA24 0x14e0
+#define R128_BRUSH_DATA25 0x14e4
+#define R128_BRUSH_DATA26 0x14e8
+#define R128_BRUSH_DATA27 0x14ec
+#define R128_BRUSH_DATA28 0x14f0
+#define R128_BRUSH_DATA29 0x14f4
+#define R128_BRUSH_DATA3 0x148c
+#define R128_BRUSH_DATA30 0x14f8
+#define R128_BRUSH_DATA31 0x14fc
+#define R128_BRUSH_DATA32 0x1500
+#define R128_BRUSH_DATA33 0x1504
+#define R128_BRUSH_DATA34 0x1508
+#define R128_BRUSH_DATA35 0x150c
+#define R128_BRUSH_DATA36 0x1510
+#define R128_BRUSH_DATA37 0x1514
+#define R128_BRUSH_DATA38 0x1518
+#define R128_BRUSH_DATA39 0x151c
+#define R128_BRUSH_DATA4 0x1490
+#define R128_BRUSH_DATA40 0x1520
+#define R128_BRUSH_DATA41 0x1524
+#define R128_BRUSH_DATA42 0x1528
+#define R128_BRUSH_DATA43 0x152c
+#define R128_BRUSH_DATA44 0x1530
+#define R128_BRUSH_DATA45 0x1534
+#define R128_BRUSH_DATA46 0x1538
+#define R128_BRUSH_DATA47 0x153c
+#define R128_BRUSH_DATA48 0x1540
+#define R128_BRUSH_DATA49 0x1544
+#define R128_BRUSH_DATA5 0x1494
+#define R128_BRUSH_DATA50 0x1548
+#define R128_BRUSH_DATA51 0x154c
+#define R128_BRUSH_DATA52 0x1550
+#define R128_BRUSH_DATA53 0x1554
+#define R128_BRUSH_DATA54 0x1558
+#define R128_BRUSH_DATA55 0x155c
+#define R128_BRUSH_DATA56 0x1560
+#define R128_BRUSH_DATA57 0x1564
+#define R128_BRUSH_DATA58 0x1568
+#define R128_BRUSH_DATA59 0x156c
+#define R128_BRUSH_DATA6 0x1498
+#define R128_BRUSH_DATA60 0x1570
+#define R128_BRUSH_DATA61 0x1574
+#define R128_BRUSH_DATA62 0x1578
+#define R128_BRUSH_DATA63 0x157c
+#define R128_BRUSH_DATA7 0x149c
+#define R128_BRUSH_DATA8 0x14a0
+#define R128_BRUSH_DATA9 0x14a4
+#define R128_BRUSH_SCALE 0x1470
+#define R128_BRUSH_Y_X 0x1474
+#define R128_BUS_CNTL 0x0030
+# define R128_BUS_MASTER_DIS (1 << 6)
+# define R128_BUS_RD_DISCARD_EN (1 << 24)
+# define R128_BUS_RD_ABORT_EN (1 << 25)
+# define R128_BUS_MSTR_DISCONNECT_EN (1 << 28)
+# define R128_BUS_WRT_BURST (1 << 29)
+# define R128_BUS_READ_BURST (1 << 30)
+#define R128_BUS_CNTL1 0x0034
+# define R128_BUS_WAIT_ON_LOCK_EN (1 << 4)
+
+#define R128_CACHE_CNTL 0x1724
+#define R128_CACHE_LINE 0x0f0c /* PCI */
+#define R128_CAP0_TRIG_CNTL 0x0950 /* ? */
+#define R128_CAP1_TRIG_CNTL 0x09c0 /* ? */
+#define R128_CAPABILITIES_ID 0x0f50 /* PCI */
+#define R128_CAPABILITIES_PTR 0x0f34 /* PCI */
+#define R128_CLK_PIN_CNTL 0x0001 /* PLL */
+#define R128_CLOCK_CNTL_DATA 0x000c
+#define R128_CLOCK_CNTL_INDEX 0x0008
+# define R128_PLL_WR_EN (1 << 7)
+# define R128_PLL_DIV_SEL (3 << 8)
+#define R128_CLR_CMP_CLR_3D 0x1a24
+#define R128_CLR_CMP_CLR_DST 0x15c8
+#define R128_CLR_CMP_CLR_SRC 0x15c4
+#define R128_CLR_CMP_CNTL 0x15c0
+# define R128_SRC_CMP_EQ_COLOR (4 << 0)
+# define R128_SRC_CMP_NEQ_COLOR (5 << 0)
+# define R128_CLR_CMP_SRC_SOURCE (1 << 24)
+#define R128_CLR_CMP_MASK 0x15cc
+# define R128_CLR_CMP_MSK 0xffffffff
+#define R128_CLR_CMP_MASK_3D 0x1A28
+#define R128_COMMAND 0x0f04 /* PCI */
+#define R128_COMPOSITE_SHADOW_ID 0x1a0c
+#define R128_CONFIG_APER_0_BASE 0x0100
+#define R128_CONFIG_APER_1_BASE 0x0104
+#define R128_CONFIG_APER_SIZE 0x0108
+#define R128_CONFIG_BONDS 0x00e8
+#define R128_CONFIG_CNTL 0x00e0
+# define APER_0_BIG_ENDIAN_16BPP_SWAP (1 << 0)
+# define APER_0_BIG_ENDIAN_32BPP_SWAP (2 << 0)
+#define R128_CONFIG_MEMSIZE 0x00f8
+#define R128_CONFIG_MEMSIZE_EMBEDDED 0x0114
+#define R128_CONFIG_REG_1_BASE 0x010c
+#define R128_CONFIG_REG_APER_SIZE 0x0110
+#define R128_CONFIG_XSTRAP 0x00e4
+#define R128_CONSTANT_COLOR_C 0x1d34
+# define R128_CONSTANT_COLOR_MASK 0x00ffffff
+# define R128_CONSTANT_COLOR_ONE 0x00ffffff
+# define R128_CONSTANT_COLOR_ZERO 0x00000000
+#define R128_CRC_CMDFIFO_ADDR 0x0740
+#define R128_CRC_CMDFIFO_DOUT 0x0744
+#define R128_CRTC_CRNT_FRAME 0x0214
+#define R128_CRTC_DEBUG 0x021c
+#define R128_CRTC_EXT_CNTL 0x0054
+# define R128_CRTC_VGA_XOVERSCAN (1 << 0)
+# define R128_VGA_ATI_LINEAR (1 << 3)
+# define R128_XCRT_CNT_EN (1 << 6)
+# define R128_CRTC_HSYNC_DIS (1 << 8)
+# define R128_CRTC_VSYNC_DIS (1 << 9)
+# define R128_CRTC_DISPLAY_DIS (1 << 10)
+# define R128_CRTC_CRT_ON (1 << 15)
+# define R128_FP_OUT_EN (1 << 22)
+# define R128_FP_ACTIVE (1 << 23)
+#define R128_CRTC_EXT_CNTL_DPMS_BYTE 0x0055
+# define R128_CRTC_HSYNC_DIS_BYTE (1 << 0)
+# define R128_CRTC_VSYNC_DIS_BYTE (1 << 1)
+# define R128_CRTC_DISPLAY_DIS_BYTE (1 << 2)
+#define R128_CRTC_GEN_CNTL 0x0050
+# define R128_CRTC_DBL_SCAN_EN (1 << 0)
+# define R128_CRTC_INTERLACE_EN (1 << 1)
+# define R128_CRTC_CSYNC_EN (1 << 4)
+# define R128_CRTC_CUR_EN (1 << 16)
+# define R128_CRTC_CUR_MODE_MASK (7 << 17)
+# define R128_CRTC_ICON_EN (1 << 20)
+# define R128_CRTC_EXT_DISP_EN (1 << 24)
+# define R128_CRTC_EN (1 << 25)
+# define R128_CRTC_DISP_REQ_EN_B (1 << 26)
+#define R128_CRTC_GUI_TRIG_VLINE 0x0218
+#define R128_CRTC_H_SYNC_STRT_WID 0x0204
+# define R128_CRTC_H_SYNC_STRT_PIX (0x07 << 0)
+# define R128_CRTC_H_SYNC_STRT_CHAR (0x1ff << 3)
+# define R128_CRTC_H_SYNC_STRT_CHAR_SHIFT 3
+# define R128_CRTC_H_SYNC_WID (0x3f << 16)
+# define R128_CRTC_H_SYNC_WID_SHIFT 16
+# define R128_CRTC_H_SYNC_POL (1 << 23)
+#define R128_CRTC_H_TOTAL_DISP 0x0200
+# define R128_CRTC_H_TOTAL (0x01ff << 0)
+# define R128_CRTC_H_TOTAL_SHIFT 0
+# define R128_CRTC_H_DISP (0x00ff << 16)
+# define R128_CRTC_H_DISP_SHIFT 16
+#define R128_CRTC_OFFSET 0x0224
+#define R128_CRTC_OFFSET_CNTL 0x0228
+#define R128_CRTC_PITCH 0x022c
+#define R128_CRTC_STATUS 0x005c
+# define R128_CRTC_VBLANK_SAVE (1 << 1)
+#define R128_CRTC_V_SYNC_STRT_WID 0x020c
+# define R128_CRTC_V_SYNC_STRT (0x7ff << 0)
+# define R128_CRTC_V_SYNC_STRT_SHIFT 0
+# define R128_CRTC_V_SYNC_WID (0x1f << 16)
+# define R128_CRTC_V_SYNC_WID_SHIFT 16
+# define R128_CRTC_V_SYNC_POL (1 << 23)
+#define R128_CRTC_V_TOTAL_DISP 0x0208
+# define R128_CRTC_V_TOTAL (0x07ff << 0)
+# define R128_CRTC_V_TOTAL_SHIFT 0
+# define R128_CRTC_V_DISP (0x07ff << 16)
+# define R128_CRTC_V_DISP_SHIFT 16
+#define R128_CRTC_VLINE_CRNT_VLINE 0x0210
+# define R128_CRTC_CRNT_VLINE_MASK (0x7ff << 16)
+#define R128_CRTC2_CRNT_FRAME 0x0314
+#define R128_CRTC2_DEBUG 0x031c
+#define R128_CRTC2_GEN_CNTL 0x03f8
+#define R128_CRTC2_GUI_TRIG_VLINE 0x0318
+#define R128_CRTC2_H_SYNC_STRT_WID 0x0304
+#define R128_CRTC2_H_TOTAL_DISP 0x0300
+#define R128_CRTC2_OFFSET 0x0324
+#define R128_CRTC2_OFFSET_CNTL 0x0328
+#define R128_CRTC2_PITCH 0x032c
+#define R128_CRTC2_STATUS 0x03fc
+#define R128_CRTC2_V_SYNC_STRT_WID 0x030c
+#define R128_CRTC2_V_TOTAL_DISP 0x0308
+#define R128_CRTC2_VLINE_CRNT_VLINE 0x0310
+#define R128_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */
+#define R128_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */
+#define R128_CUR_CLR0 0x026c
+#define R128_CUR_CLR1 0x0270
+#define R128_CUR_HORZ_VERT_OFF 0x0268
+#define R128_CUR_HORZ_VERT_POSN 0x0264
+#define R128_CUR_OFFSET 0x0260
+# define R128_CUR_LOCK (1 << 31)
+
+#define R128_DAC_CNTL 0x0058
+# define R128_DAC_RANGE_CNTL (3 << 0)
+# define R128_DAC_BLANKING (1 << 2)
+# define R128_DAC_CRT_SEL_CRTC2 (1 << 4)
+# define R128_DAC_PALETTE_ACC_CTL (1 << 5)
+# define R128_DAC_8BIT_EN (1 << 8)
+# define R128_DAC_VGA_ADR_EN (1 << 13)
+# define R128_DAC_MASK_ALL (0xff << 24)
+#define R128_DAC_CRC_SIG 0x02cc
+#define R128_DAC_DATA 0x03c9 /* VGA */
+#define R128_DAC_MASK 0x03c6 /* VGA */
+#define R128_DAC_R_INDEX 0x03c7 /* VGA */
+#define R128_DAC_W_INDEX 0x03c8 /* VGA */
+#define R128_DDA_CONFIG 0x02e0
+#define R128_DDA_ON_OFF 0x02e4
+#define R128_DEFAULT_OFFSET 0x16e0
+#define R128_DEFAULT_PITCH 0x16e4
+#define R128_DEFAULT_SC_BOTTOM_RIGHT 0x16e8
+# define R128_DEFAULT_SC_RIGHT_MAX (0x1fff << 0)
+# define R128_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16)
+#define R128_DESTINATION_3D_CLR_CMP_VAL 0x1820
+#define R128_DESTINATION_3D_CLR_CMP_MSK 0x1824
+#define R128_DEVICE_ID 0x0f02 /* PCI */
+#define R128_DP_BRUSH_BKGD_CLR 0x1478
+#define R128_DP_BRUSH_FRGD_CLR 0x147c
+#define R128_DP_CNTL 0x16c0
+# define R128_DST_X_LEFT_TO_RIGHT (1 << 0)
+# define R128_DST_Y_TOP_TO_BOTTOM (1 << 1)
+#define R128_DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0
+# define R128_DST_Y_MAJOR (1 << 2)
+# define R128_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15)
+# define R128_DST_X_DIR_LEFT_TO_RIGHT (1 << 31)
+#define R128_DP_DATATYPE 0x16c4
+# define R128_HOST_BIG_ENDIAN_EN (1 << 29)
+#define R128_DP_GUI_MASTER_CNTL 0x146c
+# define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
+# define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
+# define R128_GMC_SRC_CLIPPING (1 << 2)
+# define R128_GMC_DST_CLIPPING (1 << 3)
+# define R128_GMC_BRUSH_DATATYPE_MASK (0x0f << 4)
+# define R128_GMC_BRUSH_8X8_MONO_FG_BG (0 << 4)
+# define R128_GMC_BRUSH_8X8_MONO_FG_LA (1 << 4)
+# define R128_GMC_BRUSH_1X8_MONO_FG_BG (4 << 4)
+# define R128_GMC_BRUSH_1X8_MONO_FG_LA (5 << 4)
+# define R128_GMC_BRUSH_32x1_MONO_FG_BG (6 << 4)
+# define R128_GMC_BRUSH_32x1_MONO_FG_LA (7 << 4)
+# define R128_GMC_BRUSH_32x32_MONO_FG_BG (8 << 4)
+# define R128_GMC_BRUSH_32x32_MONO_FG_LA (9 << 4)
+# define R128_GMC_BRUSH_8x8_COLOR (10 << 4)
+# define R128_GMC_BRUSH_1X8_COLOR (12 << 4)
+# define R128_GMC_BRUSH_SOLID_COLOR (13 << 4)
+# define R128_GMC_BRUSH_NONE (15 << 4)
+# define R128_GMC_DST_8BPP_CI (2 << 8)
+# define R128_GMC_DST_15BPP (3 << 8)
+# define R128_GMC_DST_16BPP (4 << 8)
+# define R128_GMC_DST_24BPP (5 << 8)
+# define R128_GMC_DST_32BPP (6 << 8)
+# define R128_GMC_DST_8BPP_RGB (7 << 8)
+# define R128_GMC_DST_Y8 (8 << 8)
+# define R128_GMC_DST_RGB8 (9 << 8)
+# define R128_GMC_DST_VYUY (11 << 8)
+# define R128_GMC_DST_YVYU (12 << 8)
+# define R128_GMC_DST_AYUV444 (14 << 8)
+# define R128_GMC_DST_ARGB4444 (15 << 8)
+# define R128_GMC_DST_DATATYPE_MASK (0x0f << 8)
+# define R128_GMC_DST_DATATYPE_SHIFT 8
+# define R128_GMC_SRC_DATATYPE_MASK (3 << 12)
+# define R128_GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12)
+# define R128_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12)
+# define R128_GMC_SRC_DATATYPE_COLOR (3 << 12)
+# define R128_GMC_BYTE_PIX_ORDER (1 << 14)
+# define R128_GMC_BYTE_MSB_TO_LSB (0 << 14)
+# define R128_GMC_BYTE_LSB_TO_MSB (1 << 14)
+# define R128_GMC_CONVERSION_TEMP (1 << 15)
+# define R128_GMC_CONVERSION_TEMP_6500 (0 << 15)
+# define R128_GMC_CONVERSION_TEMP_9300 (1 << 15)
+# define R128_GMC_ROP3_MASK (0xff << 16)
+# define R128_DP_SRC_SOURCE_MASK (7 << 24)
+# define R128_DP_SRC_SOURCE_MEMORY (2 << 24)
+# define R128_DP_SRC_SOURCE_HOST_DATA (3 << 24)
+# define R128_GMC_3D_FCN_EN (1 << 27)
+# define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28)
+# define R128_GMC_AUX_CLIP_DIS (1 << 29)
+# define R128_GMC_WR_MSK_DIS (1 << 30)
+# define R128_GMC_LD_BRUSH_Y_X (1 << 31)
+# define R128_ROP3_ZERO 0x00000000
+# define R128_ROP3_DSa 0x00880000
+# define R128_ROP3_SDna 0x00440000
+# define R128_ROP3_S 0x00cc0000
+# define R128_ROP3_DSna 0x00220000
+# define R128_ROP3_D 0x00aa0000
+# define R128_ROP3_DSx 0x00660000
+# define R128_ROP3_DSo 0x00ee0000
+# define R128_ROP3_DSon 0x00110000
+# define R128_ROP3_DSxn 0x00990000
+# define R128_ROP3_Dn 0x00550000
+# define R128_ROP3_SDno 0x00dd0000
+# define R128_ROP3_Sn 0x00330000
+# define R128_ROP3_DSno 0x00bb0000
+# define R128_ROP3_DSan 0x00770000
+# define R128_ROP3_ONE 0x00ff0000
+# define R128_ROP3_DPa 0x00a00000
+# define R128_ROP3_PDna 0x00500000
+# define R128_ROP3_P 0x00f00000
+# define R128_ROP3_DPna 0x000a0000
+# define R128_ROP3_D 0x00aa0000
+# define R128_ROP3_DPx 0x005a0000
+# define R128_ROP3_DPo 0x00fa0000
+# define R128_ROP3_DPon 0x00050000
+# define R128_ROP3_PDxn 0x00a50000
+# define R128_ROP3_PDno 0x00f50000
+# define R128_ROP3_Pn 0x000f0000
+# define R128_ROP3_DPno 0x00af0000
+# define R128_ROP3_DPan 0x005f0000
+
+
+#define R128_DP_GUI_MASTER_CNTL_C 0x1c84
+#define R128_DP_MIX 0x16c8
+#define R128_DP_SRC_BKGD_CLR 0x15dc
+#define R128_DP_SRC_FRGD_CLR 0x15d8
+#define R128_DP_WRITE_MASK 0x16cc
+#define R128_DST_BRES_DEC 0x1630
+#define R128_DST_BRES_ERR 0x1628
+#define R128_DST_BRES_INC 0x162c
+#define R128_DST_BRES_LNTH 0x1634
+#define R128_DST_BRES_LNTH_SUB 0x1638
+#define R128_DST_HEIGHT 0x1410
+#define R128_DST_HEIGHT_WIDTH 0x143c
+#define R128_DST_HEIGHT_WIDTH_8 0x158c
+#define R128_DST_HEIGHT_WIDTH_BW 0x15b4
+#define R128_DST_HEIGHT_Y 0x15a0
+#define R128_DST_OFFSET 0x1404
+#define R128_DST_PITCH 0x1408
+#define R128_DST_PITCH_OFFSET 0x142c
+#define R128_DST_PITCH_OFFSET_C 0x1c80
+# define R128_PITCH_SHIFT 21
+# define R128_DST_TILE (1 << 31)
+#define R128_DST_WIDTH 0x140c
+#define R128_DST_WIDTH_HEIGHT 0x1598
+#define R128_DST_WIDTH_X 0x1588
+#define R128_DST_WIDTH_X_INCY 0x159c
+#define R128_DST_X 0x141c
+#define R128_DST_X_SUB 0x15a4
+#define R128_DST_X_Y 0x1594
+#define R128_DST_Y 0x1420
+#define R128_DST_Y_SUB 0x15a8
+#define R128_DST_Y_X 0x1438
+
+#define R128_EXT_MEM_CNTL 0x0144
+
+#define R128_FCP_CNTL 0x0012 /* PLL */
+#define R128_FLUSH_1 0x1704
+#define R128_FLUSH_2 0x1708
+#define R128_FLUSH_3 0x170c
+#define R128_FLUSH_4 0x1710
+#define R128_FLUSH_5 0x1714
+#define R128_FLUSH_6 0x1718
+#define R128_FLUSH_7 0x171c
+#define R128_FOG_3D_TABLE_START 0x1810
+#define R128_FOG_3D_TABLE_END 0x1814
+#define R128_FOG_3D_TABLE_DENSITY 0x181c
+#define R128_FOG_TABLE_INDEX 0x1a14
+#define R128_FOG_TABLE_DATA 0x1a18
+#define R128_FP_CRTC_H_TOTAL_DISP 0x0250
+#define R128_FP_CRTC_V_TOTAL_DISP 0x0254
+#define R128_FP_GEN_CNTL 0x0284
+# define R128_FP_FPON (1 << 0)
+# define R128_FP_BLANK_DIS (1 << 1)
+# define R128_FP_TDMS_EN (1 << 2)
+# define R128_FP_DETECT_SENSE (1 << 8)
+# define R128_FP_SEL_CRTC2 (1 << 13)
+# define R128_FP_CRTC_DONT_SHADOW_VPAR (1 << 16)
+# define R128_FP_CRTC_DONT_SHADOW_HEND (1 << 17)
+# define R128_FP_CRTC_USE_SHADOW_VEND (1 << 18)
+# define R128_FP_CRTC_USE_SHADOW_ROWCUR (1 << 19)
+# define R128_FP_CRTC_HORZ_DIV2_EN (1 << 20)
+# define R128_FP_CRTC_HOR_CRT_DIV2_DIS (1 << 21)
+# define R128_FP_CRT_SYNC_SEL (1 << 23)
+# define R128_FP_USE_SHADOW_EN (1 << 24)
+#define R128_FP_H_SYNC_STRT_WID 0x02c4
+#define R128_FP_HORZ_STRETCH 0x028c
+# define R128_HORZ_STRETCH_RATIO_MASK 0xffff
+# define R128_HORZ_STRETCH_RATIO_SHIFT 0
+# define R128_HORZ_STRETCH_RATIO_MAX 4096
+# define R128_HORZ_PANEL_SIZE (0xff << 16)
+# define R128_HORZ_PANEL_SHIFT 16
+# define R128_AUTO_HORZ_RATIO (0 << 24)
+# define R128_HORZ_STRETCH_PIXREP (0 << 25)
+# define R128_HORZ_STRETCH_BLEND (1 << 25)
+# define R128_HORZ_STRETCH_ENABLE (1 << 26)
+# define R128_HORZ_FP_LOOP_STRETCH (0x7 << 27)
+# define R128_HORZ_STRETCH_RESERVED (1 << 30)
+# define R128_HORZ_AUTO_RATIO_FIX_EN (1 << 31)
+
+#define R128_FP_PANEL_CNTL 0x0288
+# define R128_FP_DIGON (1 << 0)
+# define R128_FP_BLON (1 << 1)
+#define R128_FP_V_SYNC_STRT_WID 0x02c8
+#define R128_FP_VERT_STRETCH 0x0290
+# define R128_VERT_PANEL_SIZE (0x7ff << 0)
+# define R128_VERT_PANEL_SHIFT 0
+# define R128_VERT_STRETCH_RATIO_MASK 0x3ff
+# define R128_VERT_STRETCH_RATIO_SHIFT 11
+# define R128_VERT_STRETCH_RATIO_MAX 1024
+# define R128_VERT_STRETCH_ENABLE (1 << 24)
+# define R128_VERT_STRETCH_LINEREP (0 << 25)
+# define R128_VERT_STRETCH_BLEND (1 << 25)
+# define R128_VERT_AUTO_RATIO_EN (1 << 26)
+# define R128_VERT_STRETCH_RESERVED 0xf8e00000
+
+#define R128_GEN_INT_CNTL 0x0040
+#define R128_GEN_INT_STATUS 0x0044
+# define R128_VSYNC_INT_AK (1 << 2)
+# define R128_VSYNC_INT (1 << 2)
+#define R128_GEN_RESET_CNTL 0x00f0
+# define R128_SOFT_RESET_GUI (1 << 0)
+# define R128_SOFT_RESET_VCLK (1 << 8)
+# define R128_SOFT_RESET_PCLK (1 << 9)
+# define R128_SOFT_RESET_DISPENG_XCLK (1 << 11)
+# define R128_SOFT_RESET_MEMCTLR_XCLK (1 << 12)
+#define R128_GENENB 0x03c3 /* VGA */
+#define R128_GENFC_RD 0x03ca /* VGA */
+#define R128_GENFC_WT 0x03da /* VGA, 0x03ba */
+#define R128_GENMO_RD 0x03cc /* VGA */
+#define R128_GENMO_WT 0x03c2 /* VGA */
+#define R128_GENS0 0x03c2 /* VGA */
+#define R128_GENS1 0x03da /* VGA, 0x03ba */
+#define R128_GPIO_MONID 0x0068
+# define R128_GPIO_MONID_A_0 (1 << 0)
+# define R128_GPIO_MONID_A_1 (1 << 1)
+# define R128_GPIO_MONID_A_2 (1 << 2)
+# define R128_GPIO_MONID_A_3 (1 << 3)
+# define R128_GPIO_MONID_Y_0 (1 << 8)
+# define R128_GPIO_MONID_Y_1 (1 << 9)
+# define R128_GPIO_MONID_Y_2 (1 << 10)
+# define R128_GPIO_MONID_Y_3 (1 << 11)
+# define R128_GPIO_MONID_EN_0 (1 << 16)
+# define R128_GPIO_MONID_EN_1 (1 << 17)
+# define R128_GPIO_MONID_EN_2 (1 << 18)
+# define R128_GPIO_MONID_EN_3 (1 << 19)
+# define R128_GPIO_MONID_MASK_0 (1 << 24)
+# define R128_GPIO_MONID_MASK_1 (1 << 25)
+# define R128_GPIO_MONID_MASK_2 (1 << 26)
+# define R128_GPIO_MONID_MASK_3 (1 << 27)
+#define R128_GPIO_MONIDB 0x006c
+#define R128_GRPH8_DATA 0x03cf /* VGA */
+#define R128_GRPH8_IDX 0x03ce /* VGA */
+#define R128_GUI_DEBUG0 0x16a0
+#define R128_GUI_DEBUG1 0x16a4
+#define R128_GUI_DEBUG2 0x16a8
+#define R128_GUI_DEBUG3 0x16ac
+#define R128_GUI_DEBUG4 0x16b0
+#define R128_GUI_DEBUG5 0x16b4
+#define R128_GUI_DEBUG6 0x16b8
+#define R128_GUI_PROBE 0x16bc
+#define R128_GUI_SCRATCH_REG0 0x15e0
+#define R128_GUI_SCRATCH_REG1 0x15e4
+#define R128_GUI_SCRATCH_REG2 0x15e8
+#define R128_GUI_SCRATCH_REG3 0x15ec
+#define R128_GUI_SCRATCH_REG4 0x15f0
+#define R128_GUI_SCRATCH_REG5 0x15f4
+#define R128_GUI_STAT 0x1740
+# define R128_GUI_FIFOCNT_MASK 0x0fff
+# define R128_GUI_ACTIVE (1 << 31)
+
+#define R128_HEADER 0x0f0e /* PCI */
+#define R128_HOST_DATA0 0x17c0
+#define R128_HOST_DATA1 0x17c4
+#define R128_HOST_DATA2 0x17c8
+#define R128_HOST_DATA3 0x17cc
+#define R128_HOST_DATA4 0x17d0
+#define R128_HOST_DATA5 0x17d4
+#define R128_HOST_DATA6 0x17d8
+#define R128_HOST_DATA7 0x17dc
+#define R128_HOST_DATA_LAST 0x17e0
+#define R128_HOST_PATH_CNTL 0x0130
+#define R128_HTOTAL_CNTL 0x0009 /* PLL */
+#define R128_HW_DEBUG 0x0128
+#define R128_HW_DEBUG2 0x011c
+
+#define R128_I2C_CNTL_1 0x0094 /* ? */
+#define R128_INTERRUPT_LINE 0x0f3c /* PCI */
+#define R128_INTERRUPT_PIN 0x0f3d /* PCI */
+#define R128_IO_BASE 0x0f14 /* PCI */
+
+#define R128_LATENCY 0x0f0d /* PCI */
+#define R128_LEAD_BRES_DEC 0x1608
+#define R128_LEAD_BRES_ERR 0x1600
+#define R128_LEAD_BRES_INC 0x1604
+#define R128_LEAD_BRES_LNTH 0x161c
+#define R128_LEAD_BRES_LNTH_SUB 0x1624
+#define R128_LVDS_GEN_CNTL 0x02d0
+# define R128_LVDS_ON (1 << 0)
+# define R128_LVDS_DISPLAY_DIS (1 << 1)
+# define R128_LVDS_EN (1 << 7)
+# define R128_LVDS_DIGON (1 << 18)
+# define R128_LVDS_BLON (1 << 19)
+# define R128_LVDS_SEL_CRTC2 (1 << 23)
+# define R128_HSYNC_DELAY_SHIFT 28
+# define R128_HSYNC_DELAY_MASK (0xf << 28)
+
+#define R128_MAX_LATENCY 0x0f3f /* PCI */
+#define R128_MCLK_CNTL 0x000f /* PLL */
+# define R128_FORCE_GCP (1 << 16)
+# define R128_FORCE_PIPE3D_CP (1 << 17)
+# define R128_FORCE_RCP (1 << 18)
+#define R128_MDGPIO_A_REG 0x01ac
+#define R128_MDGPIO_EN_REG 0x01b0
+#define R128_MDGPIO_MASK 0x0198
+#define R128_MDGPIO_Y_REG 0x01b4
+#define R128_MEM_ADDR_CONFIG 0x0148
+#define R128_MEM_BASE 0x0f10 /* PCI */
+#define R128_MEM_CNTL 0x0140
+#define R128_MEM_INIT_LAT_TIMER 0x0154
+#define R128_MEM_INTF_CNTL 0x014c
+#define R128_MEM_SDRAM_MODE_REG 0x0158
+#define R128_MEM_STR_CNTL 0x0150
+#define R128_MEM_VGA_RP_SEL 0x003c
+#define R128_MEM_VGA_WP_SEL 0x0038
+#define R128_MIN_GRANT 0x0f3e /* PCI */
+#define R128_MM_DATA 0x0004
+#define R128_MM_INDEX 0x0000
+#define R128_MPLL_CNTL 0x000e /* PLL */
+#define R128_MPP_TB_CONFIG 0x01c0 /* ? */
+#define R128_MPP_GP_CONFIG 0x01c8 /* ? */
+
+#define R128_N_VIF_COUNT 0x0248
+
+#define R128_OVR_CLR 0x0230
+#define R128_OVR_WID_LEFT_RIGHT 0x0234
+#define R128_OVR_WID_TOP_BOTTOM 0x0238
+
+/* first overlay unit (there is only one) */
+
+#define R128_OV0_Y_X_START 0x0400
+#define R128_OV0_Y_X_END 0x0404
+#define R128_OV0_EXCLUSIVE_HORZ 0x0408
+# define R128_EXCL_HORZ_START_MASK 0x000000ff
+# define R128_EXCL_HORZ_END_MASK 0x0000ff00
+# define R128_EXCL_HORZ_BACK_PORCH_MASK 0x00ff0000
+# define R128_EXCL_HORZ_EXCLUSIVE_EN 0x80000000
+#define R128_OV0_EXCLUSIVE_VERT 0x040C
+# define R128_EXCL_VERT_START_MASK 0x000003ff
+# define R128_EXCL_VERT_END_MASK 0x03ff0000
+#define R128_OV0_REG_LOAD_CNTL 0x0410
+# define R128_REG_LD_CTL_LOCK 0x00000001L
+# define R128_REG_LD_CTL_VBLANK_DURING_LOCK 0x00000002L
+# define R128_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L
+# define R128_REG_LD_CTL_LOCK_READBACK 0x00000008L
+#define R128_OV0_SCALE_CNTL 0x0420
+# define R128_SCALER_PIX_EXPAND 0x00000001L
+# define R128_SCALER_Y2R_TEMP 0x00000002L
+# define R128_SCALER_HORZ_PICK_NEAREST 0x00000003L
+# define R128_SCALER_VERT_PICK_NEAREST 0x00000004L
+# define R128_SCALER_SIGNED_UV 0x00000010L
+# define R128_SCALER_GAMMA_SEL_MASK 0x00000060L
+# define R128_SCALER_GAMMA_SEL_BRIGHT 0x00000000L
+# define R128_SCALER_GAMMA_SEL_G22 0x00000020L
+# define R128_SCALER_GAMMA_SEL_G18 0x00000040L
+# define R128_SCALER_GAMMA_SEL_G14 0x00000060L
+# define R128_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L
+# define R128_SCALER_SURFAC_FORMAT 0x00000f00L
+# define R128_SCALER_SOURCE_15BPP 0x00000300L
+# define R128_SCALER_SOURCE_16BPP 0x00000400L
+# define R128_SCALER_SOURCE_32BPP 0x00000600L
+# define R128_SCALER_SOURCE_YUV9 0x00000900L
+# define R128_SCALER_SOURCE_YUV12 0x00000A00L
+# define R128_SCALER_SOURCE_VYUY422 0x00000B00L
+# define R128_SCALER_SOURCE_YVYU422 0x00000C00L
+# define R128_SCALER_SMART_SWITCH 0x00008000L
+# define R128_SCALER_BURST_PER_PLANE 0x00ff0000L
+# define R128_SCALER_DOUBLE_BUFFER 0x01000000L
+# define R128_SCALER_DIS_LIMIT 0x08000000L
+# define R128_SCALER_PRG_LOAD_START 0x10000000L
+# define R128_SCALER_INT_EMU 0x20000000L
+# define R128_SCALER_ENABLE 0x40000000L
+# define R128_SCALER_SOFT_RESET 0x80000000L
+#define R128_OV0_V_INC 0x0424
+#define R128_OV0_P1_V_ACCUM_INIT 0x0428
+# define R128_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L
+# define R128_OV0_P1_V_ACCUM_INIT_MASK 0x01ff8000L
+#define R128_OV0_P23_V_ACCUM_INIT 0x042C
+#define R128_OV0_P1_BLANK_LINES_AT_TOP 0x0430
+# define R128_P1_BLNK_LN_AT_TOP_M1_MASK 0x00000fffL
+# define R128_P1_ACTIVE_LINES_M1 0x0fff0000L
+#define R128_OV0_P23_BLANK_LINES_AT_TOP 0x0434
+# define R128_P23_BLNK_LN_AT_TOP_M1_MASK 0x000007ffL
+# define R128_P23_ACTIVE_LINES_M1 0x07ff0000L
+#define R128_OV0_VID_BUF0_BASE_ADRS 0x0440
+# define R128_VIF_BUF0_PITCH_SEL 0x00000001L
+# define R128_VIF_BUF0_TILE_ADRS 0x00000002L
+# define R128_VIF_BUF0_BASE_ADRS_MASK 0x03fffff0L
+# define R128_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L
+#define R128_OV0_VID_BUF1_BASE_ADRS 0x0444
+# define R128_VIF_BUF1_PITCH_SEL 0x00000001L
+# define R128_VIF_BUF1_TILE_ADRS 0x00000002L
+# define R128_VIF_BUF1_BASE_ADRS_MASK 0x03fffff0L
+# define R128_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L
+#define R128_OV0_VID_BUF2_BASE_ADRS 0x0448
+# define R128_VIF_BUF2_PITCH_SEL 0x00000001L
+# define R128_VIF_BUF2_TILE_ADRS 0x00000002L
+# define R128_VIF_BUF2_BASE_ADRS_MASK 0x03fffff0L
+# define R128_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L
+#define R128_OV0_VID_BUF3_BASE_ADRS 0x044C
+#define R128_OV0_VID_BUF4_BASE_ADRS 0x0450
+#define R128_OV0_VID_BUF5_BASE_ADRS 0x0454
+#define R128_OV0_VID_BUF_PITCH0_VALUE 0x0460
+#define R128_OV0_VID_BUF_PITCH1_VALUE 0x0464
+#define R128_OV0_AUTO_FLIP_CNTL 0x0470
+#define R128_OV0_DEINTERLACE_PATTERN 0x0474
+#define R128_OV0_H_INC 0x0480
+#define R128_OV0_STEP_BY 0x0484
+#define R128_OV0_P1_H_ACCUM_INIT 0x0488
+#define R128_OV0_P23_H_ACCUM_INIT 0x048C
+#define R128_OV0_P1_X_START_END 0x0494
+#define R128_OV0_P2_X_START_END 0x0498
+#define R128_OV0_P3_X_START_END 0x049C
+#define R128_OV0_FILTER_CNTL 0x04A0
+#define R128_OV0_FOUR_TAP_COEF_0 0x04B0
+#define R128_OV0_FOUR_TAP_COEF_1 0x04B4
+#define R128_OV0_FOUR_TAP_COEF_2 0x04B8
+#define R128_OV0_FOUR_TAP_COEF_3 0x04BC
+#define R128_OV0_FOUR_TAP_COEF_4 0x04C0
+#define R128_OV0_COLOUR_CNTL 0x04E0
+#define R128_OV0_VIDEO_KEY_CLR 0x04E4
+#define R128_OV0_VIDEO_KEY_MSK 0x04E8
+#define R128_OV0_GRAPHICS_KEY_CLR 0x04EC
+#define R128_OV0_GRAPHICS_KEY_MSK 0x04F0
+#define R128_OV0_KEY_CNTL 0x04F4
+# define R128_VIDEO_KEY_FN_MASK 0x00000007L
+# define R128_VIDEO_KEY_FN_FALSE 0x00000000L
+# define R128_VIDEO_KEY_FN_TRUE 0x00000001L
+# define R128_VIDEO_KEY_FN_EQ 0x00000004L
+# define R128_VIDEO_KEY_FN_NE 0x00000005L
+# define R128_GRAPHIC_KEY_FN_MASK 0x00000070L
+# define R128_GRAPHIC_KEY_FN_FALSE 0x00000000L
+# define R128_GRAPHIC_KEY_FN_TRUE 0x00000010L
+# define R128_GRAPHIC_KEY_FN_EQ 0x00000040L
+# define R128_GRAPHIC_KEY_FN_NE 0x00000050L
+# define R128_CMP_MIX_MASK 0x00000100L
+# define R128_CMP_MIX_OR 0x00000000L
+# define R128_CMP_MIX_AND 0x00000100L
+#define R128_OV0_TEST 0x04F8
+
+
+#define R128_PALETTE_DATA 0x00b4
+#define R128_PALETTE_INDEX 0x00b0
+#define R128_PC_DEBUG_MODE 0x1760
+#define R128_PC_GUI_CTLSTAT 0x1748
+#define R128_PC_GUI_MODE 0x1744
+# define R128_PC_IGNORE_UNIFY (1 << 5)
+#define R128_PC_MISC_CNTL 0x0188
+#define R128_PC_NGUI_CTLSTAT 0x0184
+# define R128_PC_FLUSH_GUI (3 << 0)
+# define R128_PC_RI_GUI (1 << 2)
+# define R128_PC_FLUSH_ALL 0x00ff
+# define R128_PC_BUSY (1 << 31)
+#define R128_PC_NGUI_MODE 0x0180
+#define R128_PCI_GART_PAGE 0x017c
+#define R128_PLANE_3D_MASK_C 0x1d44
+#define R128_PLL_TEST_CNTL 0x0013 /* PLL */
+#define R128_PMI_CAP_ID 0x0f5c /* PCI */
+#define R128_PMI_DATA 0x0f63 /* PCI */
+#define R128_PMI_NXT_CAP_PTR 0x0f5d /* PCI */
+#define R128_PMI_PMC_REG 0x0f5e /* PCI */
+#define R128_PMI_PMCSR_REG 0x0f60 /* PCI */
+#define R128_PMI_REGISTER 0x0f5c /* PCI */
+#define R128_PPLL_CNTL 0x0002 /* PLL */
+# define R128_PPLL_RESET (1 << 0)
+# define R128_PPLL_SLEEP (1 << 1)
+# define R128_PPLL_ATOMIC_UPDATE_EN (1 << 16)
+# define R128_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
+#define R128_PPLL_DIV_0 0x0004 /* PLL */
+#define R128_PPLL_DIV_1 0x0005 /* PLL */
+#define R128_PPLL_DIV_2 0x0006 /* PLL */
+#define R128_PPLL_DIV_3 0x0007 /* PLL */
+# define R128_PPLL_FB3_DIV_MASK 0x07ff
+# define R128_PPLL_POST3_DIV_MASK 0x00070000
+#define R128_PPLL_REF_DIV 0x0003 /* PLL */
+# define R128_PPLL_REF_DIV_MASK 0x03ff
+# define R128_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */
+# define R128_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */
+#define R128_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */
+#define R128_REG_BASE 0x0f18 /* PCI */
+#define R128_REGPROG_INF 0x0f09 /* PCI */
+#define R128_REVISION_ID 0x0f08 /* PCI */
+
+#define R128_SC_BOTTOM 0x164c
+#define R128_SC_BOTTOM_RIGHT 0x16f0
+#define R128_SC_BOTTOM_RIGHT_C 0x1c8c
+#define R128_SC_LEFT 0x1640
+#define R128_SC_RIGHT 0x1644
+#define R128_SC_TOP 0x1648
+#define R128_SC_TOP_LEFT 0x16ec
+#define R128_SC_TOP_LEFT_C 0x1c88
+#define R128_SEQ8_DATA 0x03c5 /* VGA */
+#define R128_SEQ8_IDX 0x03c4 /* VGA */
+#define R128_SNAPSHOT_F_COUNT 0x0244
+#define R128_SNAPSHOT_VH_COUNTS 0x0240
+#define R128_SNAPSHOT_VIF_COUNT 0x024c
+#define R128_SRC_OFFSET 0x15ac
+#define R128_SRC_PITCH 0x15b0
+#define R128_SRC_PITCH_OFFSET 0x1428
+#define R128_SRC_SC_BOTTOM 0x165c
+#define R128_SRC_SC_BOTTOM_RIGHT 0x16f4
+#define R128_SRC_SC_RIGHT 0x1654
+#define R128_SRC_X 0x1414
+#define R128_SRC_X_Y 0x1590
+#define R128_SRC_Y 0x1418
+#define R128_SRC_Y_X 0x1434
+#define R128_STATUS 0x0f06 /* PCI */
+#define R128_SUBPIC_CNTL 0x0540 /* ? */
+#define R128_SUB_CLASS 0x0f0a /* PCI */
+#define R128_SURFACE_DELAY 0x0b00
+#define R128_SURFACE0_INFO 0x0b0c
+#define R128_SURFACE0_LOWER_BOUND 0x0b04
+#define R128_SURFACE0_UPPER_BOUND 0x0b08
+#define R128_SURFACE1_INFO 0x0b1c
+#define R128_SURFACE1_LOWER_BOUND 0x0b14
+#define R128_SURFACE1_UPPER_BOUND 0x0b18
+#define R128_SURFACE2_INFO 0x0b2c
+#define R128_SURFACE2_LOWER_BOUND 0x0b24
+#define R128_SURFACE2_UPPER_BOUND 0x0b28
+#define R128_SURFACE3_INFO 0x0b3c
+#define R128_SURFACE3_LOWER_BOUND 0x0b34
+#define R128_SURFACE3_UPPER_BOUND 0x0b38
+#define R128_SW_SEMAPHORE 0x013c
+
+#define R128_TEST_DEBUG_CNTL 0x0120
+#define R128_TEST_DEBUG_MUX 0x0124
+#define R128_TEST_DEBUG_OUT 0x012c
+#define R128_TMDS_CRC 0x02a0
+#define R128_TMDS_TRANSMITTER_CNTL 0x02a4
+# define R128_TMDS_PLLEN (1 << 0)
+# define R128_TMDS_PLLRST (1 << 1)
+#define R128_TRAIL_BRES_DEC 0x1614
+#define R128_TRAIL_BRES_ERR 0x160c
+#define R128_TRAIL_BRES_INC 0x1610
+#define R128_TRAIL_X 0x1618
+#define R128_TRAIL_X_SUB 0x1620
+
+#define R128_VCLK_ECP_CNTL 0x0008 /* PLL */
+#define R128_VENDOR_ID 0x0f00 /* PCI */
+#define R128_VGA_DDA_CONFIG 0x02e8
+#define R128_VGA_DDA_ON_OFF 0x02ec
+#define R128_VID_BUFFER_CONTROL 0x0900
+#define R128_VIDEOMUX_CNTL 0x0190
+#define R128_VIPH_CONTROL 0x01D0 /* ? */
+
+#define R128_WAIT_UNTIL 0x1720
+
+#define R128_X_MPLL_REF_FB_DIV 0x000a /* PLL */
+#define R128_XCLK_CNTL 0x000d /* PLL */
+#define R128_XDLL_CNTL 0x000c /* PLL */
+#define R128_XPLL_CNTL 0x000b /* PLL */
+
+ /* Registers for CCE and Microcode Engine */
+#define R128_PM4_MICROCODE_ADDR 0x07d4
+#define R128_PM4_MICROCODE_RADDR 0x07d8
+#define R128_PM4_MICROCODE_DATAH 0x07dc
+#define R128_PM4_MICROCODE_DATAL 0x07e0
+
+#define R128_PM4_BUFFER_OFFSET 0x0700
+#define R128_PM4_BUFFER_CNTL 0x0704
+# define R128_PM4_NONPM4 (0 << 28)
+# define R128_PM4_192PIO (1 << 28)
+# define R128_PM4_192BM (2 << 28)
+# define R128_PM4_128PIO_64INDBM (3 << 28)
+# define R128_PM4_128BM_64INDBM (4 << 28)
+# define R128_PM4_64PIO_128INDBM (5 << 28)
+# define R128_PM4_64BM_128INDBM (6 << 28)
+# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28)
+# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28)
+# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28)
+#define R128_PM4_BUFFER_WM_CNTL 0x0708
+# define R128_WMA_SHIFT 0
+# define R128_WMB_SHIFT 8
+# define R128_WMC_SHIFT 16
+# define R128_WB_WM_SHIFT 24
+#define R128_PM4_BUFFER_DL_RPTR_ADDR 0x070c
+#define R128_PM4_BUFFER_DL_RPTR 0x0710
+#define R128_PM4_BUFFER_DL_WPTR 0x0714
+# define R128_PM4_BUFFER_DL_DONE (1 << 31)
+#define R128_PM4_BUFFER_DL_WPTR_DELAY 0x0718
+# define R128_PRE_WRITE_TIMER_SHIFT 0
+# define R128_PRE_WRITE_LIMIT_SHIFT 23
+#define R128_PM4_VC_FPU_SETUP 0x071c
+# define R128_FRONT_DIR_CW (0 << 0)
+# define R128_FRONT_DIR_CCW (1 << 0)
+# define R128_FRONT_DIR_MASK (1 << 0)
+# define R128_BACKFACE_CULL (0 << 1)
+# define R128_BACKFACE_POINTS (1 << 1)
+# define R128_BACKFACE_LINES (2 << 1)
+# define R128_BACKFACE_SOLID (3 << 1)
+# define R128_BACKFACE_MASK (3 << 1)
+# define R128_FRONTFACE_CULL (0 << 3)
+# define R128_FRONTFACE_POINTS (1 << 3)
+# define R128_FRONTFACE_LINES (2 << 3)
+# define R128_FRONTFACE_SOLID (3 << 3)
+# define R128_FRONTFACE_MASK (3 << 3)
+# define R128_FPU_COLOR_SOLID (0 << 5)
+# define R128_FPU_COLOR_FLAT (1 << 5)
+# define R128_FPU_COLOR_GOURAUD (2 << 5)
+# define R128_FPU_COLOR_GOURAUD2 (3 << 5)
+# define R128_FPU_COLOR_MASK (3 << 5)
+# define R128_FPU_SUB_PIX_2BITS (0 << 7)
+# define R128_FPU_SUB_PIX_4BITS (1 << 7)
+# define R128_FPU_MODE_2D (0 << 8)
+# define R128_FPU_MODE_3D (1 << 8)
+# define R128_TRAP_BITS_DISABLE (1 << 9)
+# define R128_EDGE_ANTIALIAS (1 << 10)
+# define R128_SUPERSAMPLE (1 << 11)
+# define R128_XFACTOR_2 (0 << 12)
+# define R128_XFACTOR_4 (1 << 12)
+# define R128_YFACTOR_2 (0 << 13)
+# define R128_YFACTOR_4 (1 << 13)
+# define R128_FLAT_SHADE_VERTEX_D3D (0 << 14)
+# define R128_FLAT_SHADE_VERTEX_OGL (1 << 14)
+# define R128_FPU_ROUND_TRUNCATE (0 << 15)
+# define R128_FPU_ROUND_NEAREST (1 << 15)
+# define R128_WM_SEL_8DW (0 << 16)
+# define R128_WM_SEL_16DW (1 << 16)
+# define R128_WM_SEL_32DW (2 << 16)
+#define R128_PM4_VC_DEBUG_CONFIG 0x07a4
+#define R128_PM4_VC_STAT 0x07a8
+#define R128_PM4_VC_TIMESTAMP0 0x07b0
+#define R128_PM4_VC_TIMESTAMP1 0x07b4
+#define R128_PM4_STAT 0x07b8
+# define R128_PM4_FIFOCNT_MASK 0x0fff
+# define R128_PM4_BUSY (1 << 16)
+# define R128_PM4_GUI_ACTIVE (1 << 31)
+#define R128_PM4_BUFFER_ADDR 0x07f0
+#define R128_PM4_MICRO_CNTL 0x07fc
+# define R128_PM4_MICRO_FREERUN (1 << 30)
+#define R128_PM4_FIFO_DATA_EVEN 0x1000
+#define R128_PM4_FIFO_DATA_ODD 0x1004
+
+#define R128_SCALE_3D_CNTL 0x1a00
+# define R128_SCALE_DITHER_ERR_DIFF (0 << 1)
+# define R128_SCALE_DITHER_TABLE (1 << 1)
+# define R128_TEX_CACHE_SIZE_FULL (0 << 2)
+# define R128_TEX_CACHE_SIZE_HALF (1 << 2)
+# define R128_DITHER_INIT_CURR (0 << 3)
+# define R128_DITHER_INIT_RESET (1 << 3)
+# define R128_ROUND_24BIT (1 << 4)
+# define R128_TEX_CACHE_DISABLE (1 << 5)
+# define R128_SCALE_3D_NOOP (0 << 6)
+# define R128_SCALE_3D_SCALE (1 << 6)
+# define R128_SCALE_3D_TEXMAP_SHADE (2 << 6)
+# define R128_SCALE_PIX_BLEND (0 << 8)
+# define R128_SCALE_PIX_REPLICATE (1 << 8)
+# define R128_TEX_CACHE_SPLIT (1 << 9)
+# define R128_APPLE_YUV_MODE (1 << 10)
+# define R128_TEX_CACHE_PALLETE_MODE (1 << 11)
+# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12)
+# define R128_ALPHA_COMB_ADD_NCLAMP (1 << 12)
+# define R128_ALPHA_COMB_SUB_DST_SRC_CLAMP (2 << 12)
+# define R128_ALPHA_COMB_SUB_DST_SRC_NCLAMP (3 << 12)
+# define R128_FOG_TABLE (1 << 14)
+# define R128_SIGNED_DST_CLAMP (1 << 15)
+# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16)
+# define R128_ALPHA_BLEND_SRC_ONE (1 << 16)
+# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16)
+# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16)
+# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16)
+# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16)
+# define R128_ALPHA_BLEND_SRC_DSTALPHA (6 << 16)
+# define R128_ALPHA_BLEND_SRC_INVDSTALPHA (7 << 16)
+# define R128_ALPHA_BLEND_SRC_DSTCOLOR (8 << 16)
+# define R128_ALPHA_BLEND_SRC_INVDSTCOLOR (9 << 16)
+# define R128_ALPHA_BLEND_SRC_SAT (10 << 16)
+# define R128_ALPHA_BLEND_SRC_BLEND (11 << 16)
+# define R128_ALPHA_BLEND_SRC_INVBLEND (12 << 16)
+# define R128_ALPHA_BLEND_DST_ZERO (0 << 20)
+# define R128_ALPHA_BLEND_DST_ONE (1 << 20)
+# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20)
+# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20)
+# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20)
+# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20)
+# define R128_ALPHA_BLEND_DST_DSTALPHA (6 << 20)
+# define R128_ALPHA_BLEND_DST_INVDSTALPHA (7 << 20)
+# define R128_ALPHA_BLEND_DST_DSTCOLOR (8 << 20)
+# define R128_ALPHA_BLEND_DST_INVDSTCOLOR (9 << 20)
+# define R128_ALPHA_TEST_NEVER (0 << 24)
+# define R128_ALPHA_TEST_LESS (1 << 24)
+# define R128_ALPHA_TEST_LESSEQUAL (2 << 24)
+# define R128_ALPHA_TEST_EQUAL (3 << 24)
+# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24)
+# define R128_ALPHA_TEST_GREATER (5 << 24)
+# define R128_ALPHA_TEST_NEQUAL (6 << 24)
+# define R128_ALPHA_TEST_ALWAYS (7 << 24)
+# define R128_COMPOSITE_SHADOW_CMP_EQUAL (0 << 28)
+# define R128_COMPOSITE_SHADOW_CMP_NEQUAL (1 << 28)
+# define R128_COMPOSITE_SHADOW (1 << 29)
+# define R128_TEX_MAP_ALPHA_IN_TEXTURE (1 << 30)
+# define R128_TEX_CACHE_LINE_SIZE_8QW (0 << 31)
+# define R128_TEX_CACHE_LINE_SIZE_4QW (1 << 31)
+#define R128_SCALE_3D_DATATYPE 0x1a20
+
+#define R128_SETUP_CNTL 0x1bc4
+# define R128_DONT_START_TRIANGLE (1 << 0)
+# define R128_Z_BIAS (0 << 1)
+# define R128_DONT_START_ANY_ON (1 << 2)
+# define R128_COLOR_SOLID_COLOR (0 << 3)
+# define R128_COLOR_FLAT_VERT_1 (1 << 3)
+# define R128_COLOR_FLAT_VERT_2 (2 << 3)
+# define R128_COLOR_FLAT_VERT_3 (3 << 3)
+# define R128_COLOR_GOURAUD (4 << 3)
+# define R128_PRIM_TYPE_TRI (0 << 7)
+# define R128_PRIM_TYPE_LINE (1 << 7)
+# define R128_PRIM_TYPE_POINT (2 << 7)
+# define R128_PRIM_TYPE_POLY_EDGE (3 << 7)
+# define R128_TEXTURE_ST_MULT_W (0 << 9)
+# define R128_TEXTURE_ST_DIRECT (1 << 9)
+# define R128_STARTING_VERTEX_1 (1 << 14)
+# define R128_STARTING_VERTEX_2 (2 << 14)
+# define R128_STARTING_VERTEX_3 (3 << 14)
+# define R128_ENDING_VERTEX_1 (1 << 16)
+# define R128_ENDING_VERTEX_2 (2 << 16)
+# define R128_ENDING_VERTEX_3 (3 << 16)
+# define R128_SU_POLY_LINE_LAST (0 << 18)
+# define R128_SU_POLY_LINE_NOT_LAST (1 << 18)
+# define R128_SUB_PIX_2BITS (0 << 19)
+# define R128_SUB_PIX_4BITS (1 << 19)
+# define R128_SET_UP_CONTINUE (1 << 31)
+
+#define R128_WINDOW_XY_OFFSET 0x1bcc
+# define R128_WINDOW_Y_SHIFT 4
+# define R128_WINDOW_X_SHIFT 20
+
+#define R128_Z_OFFSET_C 0x1c90
+#define R128_Z_PITCH_C 0x1c94
+# define R128_Z_TILE (1 << 16)
+#define R128_Z_STEN_CNTL_C 0x1c98
+# define R128_Z_PIX_WIDTH_16 (0 << 1)
+# define R128_Z_PIX_WIDTH_24 (1 << 1)
+# define R128_Z_PIX_WIDTH_32 (2 << 1)
+# define R128_Z_PIX_WIDTH_MASK (3 << 1)
+# define R128_Z_TEST_NEVER (0 << 4)
+# define R128_Z_TEST_LESS (1 << 4)
+# define R128_Z_TEST_LESSEQUAL (2 << 4)
+# define R128_Z_TEST_EQUAL (3 << 4)
+# define R128_Z_TEST_GREATEREQUAL (4 << 4)
+# define R128_Z_TEST_GREATER (5 << 4)
+# define R128_Z_TEST_NEQUAL (6 << 4)
+# define R128_Z_TEST_ALWAYS (7 << 4)
+# define R128_Z_TEST_MASK (7 << 4)
+# define R128_STENCIL_TEST_NEVER (0 << 12)
+# define R128_STENCIL_TEST_LESS (1 << 12)
+# define R128_STENCIL_TEST_LESSEQUAL (2 << 12)
+# define R128_STENCIL_TEST_EQUAL (3 << 12)
+# define R128_STENCIL_TEST_GREATEREQUAL (4 << 12)
+# define R128_STENCIL_TEST_GREATER (5 << 12)
+# define R128_STENCIL_TEST_NEQUAL (6 << 12)
+# define R128_STENCIL_TEST_ALWAYS (7 << 12)
+# define R128_STENCIL_S_FAIL_KEEP (0 << 16)
+# define R128_STENCIL_S_FAIL_ZERO (1 << 16)
+# define R128_STENCIL_S_FAIL_REPLACE (2 << 16)
+# define R128_STENCIL_S_FAIL_INC (3 << 16)
+# define R128_STENCIL_S_FAIL_DEC (4 << 16)
+# define R128_STENCIL_S_FAIL_INV (5 << 16)
+# define R128_STENCIL_ZPASS_KEEP (0 << 20)
+# define R128_STENCIL_ZPASS_ZERO (1 << 20)
+# define R128_STENCIL_ZPASS_REPLACE (2 << 20)
+# define R128_STENCIL_ZPASS_INC (3 << 20)
+# define R128_STENCIL_ZPASS_DEC (4 << 20)
+# define R128_STENCIL_ZPASS_INV (5 << 20)
+# define R128_STENCIL_ZFAIL_KEEP (0 << 24)
+# define R128_STENCIL_ZFAIL_ZERO (1 << 24)
+# define R128_STENCIL_ZFAIL_REPLACE (2 << 24)
+# define R128_STENCIL_ZFAIL_INC (3 << 24)
+# define R128_STENCIL_ZFAIL_DEC (4 << 24)
+# define R128_STENCIL_ZFAIL_INV (5 << 24)
+#define R128_TEX_CNTL_C 0x1c9c
+# define R128_Z_ENABLE (1 << 0)
+# define R128_Z_WRITE_ENABLE (1 << 1)
+# define R128_STENCIL_ENABLE (1 << 3)
+# define R128_SHADE_ENABLE (0 << 4)
+# define R128_TEXMAP_ENABLE (1 << 4)
+# define R128_SEC_TEXMAP_ENABLE (1 << 5)
+# define R128_FOG_ENABLE (1 << 7)
+# define R128_DITHER_ENABLE (1 << 8)
+# define R128_ALPHA_ENABLE (1 << 9)
+# define R128_ALPHA_TEST_ENABLE (1 << 10)
+# define R128_SPEC_LIGHT_ENABLE (1 << 11)
+# define R128_TEX_CHROMA_KEY_ENABLE (1 << 12)
+# define R128_ALPHA_IN_TEX_COMPLETE_A (0 << 13)
+# define R128_ALPHA_IN_TEX_LSB_A (1 << 13)
+# define R128_LIGHT_DIS (0 << 14)
+# define R128_LIGHT_COPY (1 << 14)
+# define R128_LIGHT_MODULATE (2 << 14)
+# define R128_LIGHT_ADD (3 << 14)
+# define R128_LIGHT_BLEND_CONSTANT (4 << 14)
+# define R128_LIGHT_BLEND_TEXTURE (5 << 14)
+# define R128_LIGHT_BLEND_VERTEX (6 << 14)
+# define R128_LIGHT_BLEND_CONST_COLOR (7 << 14)
+# define R128_ALPHA_LIGHT_DIS (0 << 18)
+# define R128_ALPHA_LIGHT_COPY (1 << 18)
+# define R128_ALPHA_LIGHT_MODULATE (2 << 18)
+# define R128_ALPHA_LIGHT_ADD (3 << 18)
+# define R128_ANTI_ALIAS (1 << 21)
+# define R128_TEX_CACHE_FLUSH (1 << 23)
+# define R128_LOD_BIAS_SHIFT 24
+# define R128_LOD_BIAS_MASK (0xff << 24)
+#define R128_MISC_3D_STATE_CNTL_REG 0x1ca0
+# define R128_REF_ALPHA_MASK 0xff
+# define R128_MISC_SCALE_3D_NOOP (0 << 8)
+# define R128_MISC_SCALE_3D_SCALE (1 << 8)
+# define R128_MISC_SCALE_3D_TEXMAP_SHADE (2 << 8)
+# define R128_MISC_SCALE_PIX_BLEND (0 << 10)
+# define R128_MISC_SCALE_PIX_REPLICATE (1 << 10)
+# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12)
+# define R128_ALPHA_COMB_ADD_NO_CLAMP (1 << 12)
+# define R128_ALPHA_COMB_SUB_SRC_DST_CLAMP (2 << 12)
+# define R128_ALPHA_COMB_SUB_SRC_DST_NO_CLAMP (3 << 12)
+# define R128_FOG_VERTEX (0 << 14)
+# define R128_FOG_TABLE (1 << 14)
+# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16)
+# define R128_ALPHA_BLEND_SRC_ONE (1 << 16)
+# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16)
+# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16)
+# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16)
+# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16)
+# define R128_ALPHA_BLEND_SRC_DESTALPHA (6 << 16)
+# define R128_ALPHA_BLEND_SRC_INVDESTALPHA (7 << 16)
+# define R128_ALPHA_BLEND_SRC_DESTCOLOR (8 << 16)
+# define R128_ALPHA_BLEND_SRC_INVDESTCOLOR (9 << 16)
+# define R128_ALPHA_BLEND_SRC_SRCALPHASAT (10 << 16)
+# define R128_ALPHA_BLEND_SRC_BOTHSRCALPHA (11 << 16)
+# define R128_ALPHA_BLEND_SRC_BOTHINVSRCALPHA (12 << 16)
+# define R128_ALPHA_BLEND_SRC_MASK (15 << 16)
+# define R128_ALPHA_BLEND_DST_ZERO (0 << 20)
+# define R128_ALPHA_BLEND_DST_ONE (1 << 20)
+# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20)
+# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20)
+# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20)
+# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20)
+# define R128_ALPHA_BLEND_DST_DESTALPHA (6 << 20)
+# define R128_ALPHA_BLEND_DST_INVDESTALPHA (7 << 20)
+# define R128_ALPHA_BLEND_DST_DESTCOLOR (8 << 20)
+# define R128_ALPHA_BLEND_DST_INVDESTCOLOR (9 << 20)
+# define R128_ALPHA_BLEND_DST_SRCALPHASAT (10 << 20)
+# define R128_ALPHA_BLEND_DST_MASK (15 << 20)
+# define R128_ALPHA_TEST_NEVER (0 << 24)
+# define R128_ALPHA_TEST_LESS (1 << 24)
+# define R128_ALPHA_TEST_LESSEQUAL (2 << 24)
+# define R128_ALPHA_TEST_EQUAL (3 << 24)
+# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24)
+# define R128_ALPHA_TEST_GREATER (5 << 24)
+# define R128_ALPHA_TEST_NEQUAL (6 << 24)
+# define R128_ALPHA_TEST_ALWAYS (7 << 24)
+# define R128_ALPHA_TEST_MASK (7 << 24)
+#define R128_TEXTURE_CLR_CMP_CLR_C 0x1ca4
+#define R128_TEXTURE_CLR_CMP_MSK_C 0x1ca8
+#define R128_FOG_COLOR_C 0x1cac
+# define R128_FOG_BLUE_SHIFT 0
+# define R128_FOG_GREEN_SHIFT 8
+# define R128_FOG_RED_SHIFT 16
+#define R128_PRIM_TEX_CNTL_C 0x1cb0
+# define R128_MIN_BLEND_NEAREST (0 << 1)
+# define R128_MIN_BLEND_LINEAR (1 << 1)
+# define R128_MIN_BLEND_MIPNEAREST (2 << 1)
+# define R128_MIN_BLEND_MIPLINEAR (3 << 1)
+# define R128_MIN_BLEND_LINEARMIPNEAREST (4 << 1)
+# define R128_MIN_BLEND_LINEARMIPLINEAR (5 << 1)
+# define R128_MIN_BLEND_MASK (7 << 1)
+# define R128_MAG_BLEND_NEAREST (0 << 4)
+# define R128_MAG_BLEND_LINEAR (1 << 4)
+# define R128_MAG_BLEND_MASK (7 << 4)
+# define R128_MIP_MAP_DISABLE (1 << 7)
+# define R128_TEX_CLAMP_S_WRAP (0 << 8)
+# define R128_TEX_CLAMP_S_MIRROR (1 << 8)
+# define R128_TEX_CLAMP_S_CLAMP (2 << 8)
+# define R128_TEX_CLAMP_S_BORDER_COLOR (3 << 8)
+# define R128_TEX_CLAMP_S_MASK (3 << 8)
+# define R128_TEX_WRAP_S (1 << 10)
+# define R128_TEX_CLAMP_T_WRAP (0 << 11)
+# define R128_TEX_CLAMP_T_MIRROR (1 << 11)
+# define R128_TEX_CLAMP_T_CLAMP (2 << 11)
+# define R128_TEX_CLAMP_T_BORDER_COLOR (3 << 11)
+# define R128_TEX_CLAMP_T_MASK (3 << 11)
+# define R128_TEX_WRAP_T (1 << 13)
+# define R128_TEX_PERSPECTIVE_DISABLE (1 << 14)
+# define R128_DATATYPE_VQ (0 << 16)
+# define R128_DATATYPE_CI4 (1 << 16)
+# define R128_DATATYPE_CI8 (2 << 16)
+# define R128_DATATYPE_ARGB1555 (3 << 16)
+# define R128_DATATYPE_RGB565 (4 << 16)
+# define R128_DATATYPE_RGB888 (5 << 16)
+# define R128_DATATYPE_ARGB8888 (6 << 16)
+# define R128_DATATYPE_RGB332 (7 << 16)
+# define R128_DATATYPE_Y8 (8 << 16)
+# define R128_DATATYPE_RGB8 (9 << 16)
+# define R128_DATATYPE_CI16 (10 << 16)
+# define R128_DATATYPE_YVYU422 (11 << 16)
+# define R128_DATATYPE_VYUY422 (12 << 16)
+# define R128_DATATYPE_AYUV444 (14 << 16)
+# define R128_DATATYPE_ARGB4444 (15 << 16)
+# define R128_PALLETE_EITHER (0 << 20)
+# define R128_PALLETE_1 (1 << 20)
+# define R128_PALLETE_2 (2 << 20)
+# define R128_PSEUDOCOLOR_DT_RGB565 (0 << 24)
+# define R128_PSEUDOCOLOR_DT_ARGB1555 (1 << 24)
+# define R128_PSEUDOCOLOR_DT_ARGB4444 (2 << 24)
+#define R128_PRIM_TEXTURE_COMBINE_CNTL_C 0x1cb4
+# define R128_COMB_DIS (0 << 0)
+# define R128_COMB_COPY (1 << 0)
+# define R128_COMB_COPY_INP (2 << 0)
+# define R128_COMB_MODULATE (3 << 0)
+# define R128_COMB_MODULATE2X (4 << 0)
+# define R128_COMB_MODULATE4X (5 << 0)
+# define R128_COMB_ADD (6 << 0)
+# define R128_COMB_ADD_SIGNED (7 << 0)
+# define R128_COMB_BLEND_VERTEX (8 << 0)
+# define R128_COMB_BLEND_TEXTURE (9 << 0)
+# define R128_COMB_BLEND_CONST (10 << 0)
+# define R128_COMB_BLEND_PREMULT (11 << 0)
+# define R128_COMB_BLEND_PREV (12 << 0)
+# define R128_COMB_BLEND_PREMULT_INV (13 << 0)
+# define R128_COMB_ADD_SIGNED2X (14 << 0)
+# define R128_COMB_BLEND_CONST_COLOR (15 << 0)
+# define R128_COMB_MASK (15 << 0)
+# define R128_COLOR_FACTOR_CONST_COLOR (0 << 4)
+# define R128_COLOR_FACTOR_NCONST_COLOR (1 << 4)
+# define R128_COLOR_FACTOR_TEX (4 << 4)
+# define R128_COLOR_FACTOR_NTEX (5 << 4)
+# define R128_COLOR_FACTOR_ALPHA (6 << 4)
+# define R128_COLOR_FACTOR_NALPHA (7 << 4)
+# define R128_COLOR_FACTOR_PREV_COLOR (8 << 4)
+# define R128_COLOR_FACTOR_MASK (15 << 4)
+# define R128_COMB_FCN_MSB (1 << 8)
+# define R128_INPUT_FACTOR_CONST_COLOR (2 << 10)
+# define R128_INPUT_FACTOR_CONST_ALPHA (3 << 10)
+# define R128_INPUT_FACTOR_INT_COLOR (4 << 10)
+# define R128_INPUT_FACTOR_INT_ALPHA (5 << 10)
+# define R128_INPUT_FACTOR_MASK (15 << 10)
+# define R128_COMB_ALPHA_DIS (0 << 14)
+# define R128_COMB_ALPHA_COPY (1 << 14)
+# define R128_COMB_ALPHA_COPY_INP (2 << 14)
+# define R128_COMB_ALPHA_MODULATE (3 << 14)
+# define R128_COMB_ALPHA_MODULATE2X (4 << 14)
+# define R128_COMB_ALPHA_MODULATE4X (5 << 14)
+# define R128_COMB_ALPHA_ADD (6 << 14)
+# define R128_COMB_ALPHA_ADD_SIGNED (7 << 14)
+# define R128_COMB_ALPHA_ADD_SIGNED2X (14 << 14)
+# define R128_COMB_ALPHA_MASK (15 << 14)
+# define R128_ALPHA_FACTOR_TEX_ALPHA (6 << 18)
+# define R128_ALPHA_FACTOR_NTEX_ALPHA (7 << 18)
+# define R128_ALPHA_FACTOR_MASK (15 << 18)
+# define R128_INP_FACTOR_A_CONST_ALPHA (1 << 25)
+# define R128_INP_FACTOR_A_INT_ALPHA (2 << 25)
+# define R128_INP_FACTOR_A_MASK (7 << 25)
+#define R128_TEX_SIZE_PITCH_C 0x1cb8
+# define R128_TEX_PITCH_SHIFT 0
+# define R128_TEX_SIZE_SHIFT 4
+# define R128_TEX_HEIGHT_SHIFT 8
+# define R128_TEX_MIN_SIZE_SHIFT 12
+# define R128_SEC_TEX_PITCH_SHIFT 16
+# define R128_SEC_TEX_SIZE_SHIFT 20
+# define R128_SEC_TEX_HEIGHT_SHIFT 24
+# define R128_SEC_TEX_MIN_SIZE_SHIFT 28
+# define R128_TEX_PITCH_MASK (0x0f << 0)
+# define R128_TEX_SIZE_MASK (0x0f << 4)
+# define R128_TEX_HEIGHT_MASK (0x0f << 8)
+# define R128_TEX_MIN_SIZE_MASK (0x0f << 12)
+# define R128_SEC_TEX_PITCH_MASK (0x0f << 16)
+# define R128_SEC_TEX_SIZE_MASK (0x0f << 20)
+# define R128_SEC_TEX_HEIGHT_MASK (0x0f << 24)
+# define R128_SEC_TEX_MIN_SIZE_MASK (0x0f << 28)
+# define R128_TEX_SIZE_PITCH_SHIFT 0
+# define R128_SEC_TEX_SIZE_PITCH_SHIFT 16
+# define R128_TEX_SIZE_PITCH_MASK (0xffff << 0)
+# define R128_SEC_TEX_SIZE_PITCH_MASK (0xffff << 16)
+#define R128_PRIM_TEX_0_OFFSET_C 0x1cbc
+#define R128_PRIM_TEX_1_OFFSET_C 0x1cc0
+#define R128_PRIM_TEX_2_OFFSET_C 0x1cc4
+#define R128_PRIM_TEX_3_OFFSET_C 0x1cc8
+#define R128_PRIM_TEX_4_OFFSET_C 0x1ccc
+#define R128_PRIM_TEX_5_OFFSET_C 0x1cd0
+#define R128_PRIM_TEX_6_OFFSET_C 0x1cd4
+#define R128_PRIM_TEX_7_OFFSET_C 0x1cd8
+#define R128_PRIM_TEX_8_OFFSET_C 0x1cdc
+#define R128_PRIM_TEX_9_OFFSET_C 0x1ce0
+#define R128_PRIM_TEX_10_OFFSET_C 0x1ce4
+# define R128_TEX_NO_TILE (0 << 30)
+# define R128_TEX_TILED_BY_HOST (1 << 30)
+# define R128_TEX_TILED_BY_STORAGE (2 << 30)
+# define R128_TEX_TILED_BY_STORAGE2 (3 << 30)
+
+#define R128_SEC_TEX_CNTL_C 0x1d00
+# define R128_SEC_SELECT_PRIM_ST (0 << 0)
+# define R128_SEC_SELECT_SEC_ST (1 << 0)
+#define R128_SEC_TEX_COMBINE_CNTL_C 0x1d04
+# define R128_INPUT_FACTOR_PREV_COLOR (8 << 10)
+# define R128_INPUT_FACTOR_PREV_ALPHA (9 << 10)
+# define R128_INP_FACTOR_A_PREV_ALPHA (4 << 25)
+#define R128_SEC_TEX_0_OFFSET_C 0x1d08
+#define R128_SEC_TEX_1_OFFSET_C 0x1d0c
+#define R128_SEC_TEX_2_OFFSET_C 0x1d10
+#define R128_SEC_TEX_3_OFFSET_C 0x1d14
+#define R128_SEC_TEX_4_OFFSET_C 0x1d18
+#define R128_SEC_TEX_5_OFFSET_C 0x1d1c
+#define R128_SEC_TEX_6_OFFSET_C 0x1d20
+#define R128_SEC_TEX_7_OFFSET_C 0x1d24
+#define R128_SEC_TEX_8_OFFSET_C 0x1d28
+#define R128_SEC_TEX_9_OFFSET_C 0x1d2c
+#define R128_SEC_TEX_10_OFFSET_C 0x1d30
+#define R128_CONSTANT_COLOR_C 0x1d34
+# define R128_CONSTANT_BLUE_SHIFT 0
+# define R128_CONSTANT_GREEN_SHIFT 8
+# define R128_CONSTANT_RED_SHIFT 16
+# define R128_CONSTANT_ALPHA_SHIFT 24
+#define R128_PRIM_TEXTURE_BORDER_COLOR_C 0x1d38
+# define R128_PRIM_TEX_BORDER_BLUE_SHIFT 0
+# define R128_PRIM_TEX_BORDER_GREEN_SHIFT 8
+# define R128_PRIM_TEX_BORDER_RED_SHIFT 16
+# define R128_PRIM_TEX_BORDER_ALPHA_SHIFT 24
+#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c
+# define R128_SEC_TEX_BORDER_BLUE_SHIFT 0
+# define R128_SEC_TEX_BORDER_GREEN_SHIFT 8
+# define R128_SEC_TEX_BORDER_RED_SHIFT 16
+# define R128_SEC_TEX_BORDER_ALPHA_SHIFT 24
+#define R128_STEN_REF_MASK_C 0x1d40
+# define R128_STEN_REFERENCE_SHIFT 0
+# define R128_STEN_MASK_SHIFT 16
+# define R128_STEN_WRITE_MASK_SHIFT 24
+#define R128_PLANE_3D_MASK_C 0x1d44
+#define R128_TEX_CACHE_STAT_COUNT 0x1974
+
+
+ /* Constants */
+#define R128_AGP_TEX_OFFSET 0x02000000
+
+#define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0
+
+ /* CCE packet types */
+#define R128_CCE_PACKET0 0x00000000
+#define R128_CCE_PACKET0_ONE_REG_WR 0x00008000
+#define R128_CCE_PACKET1 0x40000000
+#define R128_CCE_PACKET2 0x80000000
+#define R128_CCE_PACKET3 0xC0000000
+#define R128_CCE_PACKET3_NOP 0xC0001000
+#define R128_CCE_PACKET3_PAINT 0xC0001100
+#define R128_CCE_PACKET3_BITBLT 0xC0001200
+#define R128_CCE_PACKET3_SMALLTEXT 0xC0001300
+#define R128_CCE_PACKET3_HOSTDATA_BLT 0xC0001400
+#define R128_CCE_PACKET3_POLYLINE 0xC0001500
+#define R128_CCE_PACKET3_SCALING 0xC0001600
+#define R128_CCE_PACKET3_TRANS_SCALING 0xC0001700
+#define R128_CCE_PACKET3_POLYSCANLINES 0xC0001800
+#define R128_CCE_PACKET3_NEXT_CHAR 0xC0001900
+#define R128_CCE_PACKET3_PAINT_MULTI 0xC0001A00
+#define R128_CCE_PACKET3_BITBLT_MULTI 0xC0001B00
+#define R128_CCE_PACKET3_PLY_NEXTSCAN 0xC0001D00
+#define R128_CCE_PACKET3_SET_SCISSORS 0xC0001E00
+#define R128_CCE_PACKET3_SET_MODE24BPP 0xC0001F00
+#define R128_CCE_PACKET3_CNTL_PAINT 0xC0009100
+#define R128_CCE_PACKET3_CNTL_BITBLT 0xC0009200
+#define R128_CCE_PACKET3_CNTL_SMALLTEXT 0xC0009300
+#define R128_CCE_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400
+#define R128_CCE_PACKET3_CNTL_POLYLINE 0xC0009500
+#define R128_CCE_PACKET3_CNTL_SCALING 0xC0009600
+#define R128_CCE_PACKET3_CNTL_TRANS_SCALING 0xC0009700
+#define R128_CCE_PACKET3_CNTL_POLYSCANLINES 0xC0009800
+#define R128_CCE_PACKET3_CNTL_NEXT_CHAR 0xC0009900
+#define R128_CCE_PACKET3_CNTL_PAINT_MULTI 0xC0009A00
+#define R128_CCE_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00
+#define R128_CCE_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00
+#define R128_CCE_PACKET3_3D_SAVE_CONTEXT 0xC0002000
+#define R128_CCE_PACKET3_3D_PLAY_CONTEXT 0xC0002100
+#define R128_CCE_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300
+#define R128_CCE_PACKET3_3D_RNDR_GEN_PRIM 0xC0002500
+#define R128_CCE_PACKET3_LOAD_PALETTE 0xC0002C00
+#define R128_CCE_PACKET3_PURGE 0xC0002D00
+#define R128_CCE_PACKET3_NEXT_VERTEX_BUNDLE 0xC0002E00
+# define R128_CCE_PACKET_MASK 0xC0000000
+# define R128_CCE_PACKET_COUNT_MASK 0x3fff0000
+# define R128_CCE_PACKET_MAX_DWORDS (1 << 12)
+# define R128_CCE_PACKET0_REG_MASK 0x000007ff
+# define R128_CCE_PACKET1_REG0_MASK 0x000007ff
+# define R128_CCE_PACKET1_REG1_MASK 0x003ff800
+
+#define R128_CCE_VC_FRMT_RHW 0x00000001
+#define R128_CCE_VC_FRMT_DIFFUSE_BGR 0x00000002
+#define R128_CCE_VC_FRMT_DIFFUSE_A 0x00000004
+#define R128_CCE_VC_FRMT_DIFFUSE_ARGB 0x00000008
+#define R128_CCE_VC_FRMT_SPEC_BGR 0x00000010
+#define R128_CCE_VC_FRMT_SPEC_F 0x00000020
+#define R128_CCE_VC_FRMT_SPEC_FRGB 0x00000040
+#define R128_CCE_VC_FRMT_S_T 0x00000080
+#define R128_CCE_VC_FRMT_S2_T2 0x00000100
+#define R128_CCE_VC_FRMT_RHW2 0x00000200
+
+#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000
+#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001
+#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002
+#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007
+#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010
+#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020
+#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030
+#define R128_CCE_VC_CNTL_NUM_SHIFT 16
+
+/* hmm copyed blindly (no specs) from radeon.h ... */
+#define R128_RE_TOP_LEFT 0x26c0
+# define R128_RE_LEFT_SHIFT 0
+# define R128_RE_TOP_SHIFT 16
+#define R128_RE_WIDTH_HEIGHT 0x1c44
+# define R128_RE_WIDTH_SHIFT 0
+# define R128_RE_HEIGHT_SHIFT 16
+
+#endif
diff --git a/src/mesa/drivers/dri/r128/server/r128_sarea.h b/src/mesa/drivers/dri/r128/server/r128_sarea.h
new file mode 100644
index 0000000000..8a9f3a4176
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128_sarea.h
@@ -0,0 +1,195 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_sarea.h,v 1.7 2002/02/16 21:26:35 herrb Exp $ */
+/*
+ * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
+ * Precision Insight, Inc., Cedar Park, Texas, and
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
+ * SYSTEMS AND/OR THEIR SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef _R128_SAREA_H_
+#define _R128_SAREA_H_
+
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the kernel file (r128_drm.h)
+ */
+#ifndef __R128_SAREA_DEFINES__
+#define __R128_SAREA_DEFINES__
+
+/* What needs to be changed for the current vertex buffer?
+ */
+#define R128_UPLOAD_CONTEXT 0x001
+#define R128_UPLOAD_SETUP 0x002
+#define R128_UPLOAD_TEX0 0x004
+#define R128_UPLOAD_TEX1 0x008
+#define R128_UPLOAD_TEX0IMAGES 0x010
+#define R128_UPLOAD_TEX1IMAGES 0x020
+#define R128_UPLOAD_CORE 0x040
+#define R128_UPLOAD_MASKS 0x080
+#define R128_UPLOAD_WINDOW 0x100
+#define R128_UPLOAD_CLIPRECTS 0x200 /* handled client-side */
+#define R128_REQUIRE_QUIESCENCE 0x400
+#define R128_UPLOAD_ALL 0x7ff
+
+#define R128_FRONT 0x1
+#define R128_BACK 0x2
+#define R128_DEPTH 0x4
+
+/* Primitive types
+ */
+#define R128_POINTS 0x1
+#define R128_LINES 0x2
+#define R128_LINE_STRIP 0x3
+#define R128_TRIANGLES 0x4
+#define R128_TRIANGLE_FAN 0x5
+#define R128_TRIANGLE_STRIP 0x6
+
+/* Vertex/indirect buffer size
+ */
+#define R128_BUFFER_SIZE 16384
+
+/* Byte offsets for indirect buffer data
+ */
+#define R128_INDEX_PRIM_OFFSET 20
+#define R128_HOSTDATA_BLIT_OFFSET 32
+
+/* Keep these small for testing
+ */
+#define R128_NR_SAREA_CLIPRECTS 12
+
+/* There are 2 heaps (local/AGP). Each region within a heap is a
+ * minimum of 64k, and there are at most 64 of them per heap.
+ */
+#define R128_CARD_HEAP 0
+#define R128_AGP_HEAP 1
+#define R128_NR_TEX_HEAPS 2
+#define R128_NR_TEX_REGIONS 64
+#define R128_LOG_TEX_GRANULARITY 16
+
+#define R128_NR_CONTEXT_REGS 12
+
+#define R128_MAX_TEXTURE_LEVELS 11
+#define R128_MAX_TEXTURE_UNITS 2
+
+#endif /* __R128_SAREA_DEFINES__ */
+
+typedef struct {
+ /* Context state - can be written in one large chunk */
+ unsigned int dst_pitch_offset_c;
+ unsigned int dp_gui_master_cntl_c;
+ unsigned int sc_top_left_c;
+ unsigned int sc_bottom_right_c;
+ unsigned int z_offset_c;
+ unsigned int z_pitch_c;
+ unsigned int z_sten_cntl_c;
+ unsigned int tex_cntl_c;
+ unsigned int misc_3d_state_cntl_reg;
+ unsigned int texture_clr_cmp_clr_c;
+ unsigned int texture_clr_cmp_msk_c;
+ unsigned int fog_color_c;
+
+ /* Texture state */
+ unsigned int tex_size_pitch_c;
+ unsigned int constant_color_c;
+
+ /* Setup state */
+ unsigned int pm4_vc_fpu_setup;
+ unsigned int setup_cntl;
+
+ /* Mask state */
+ unsigned int dp_write_mask;
+ unsigned int sten_ref_mask_c;
+ unsigned int plane_3d_mask_c;
+
+ /* Window state */
+ unsigned int window_xy_offset;
+
+ /* Core state */
+ unsigned int scale_3d_cntl;
+} r128_context_regs_t;
+
+/* Setup registers for each texture unit
+ */
+typedef struct {
+ unsigned int tex_cntl;
+ unsigned int tex_combine_cntl;
+ unsigned int tex_size_pitch;
+ unsigned int tex_offset[R128_MAX_TEXTURE_LEVELS];
+ unsigned int tex_border_color;
+} r128_texture_regs_t;
+
+typedef struct {
+ /* The channel for communication of state information to the kernel
+ * on firing a vertex buffer.
+ */
+ r128_context_regs_t ContextState;
+ r128_texture_regs_t TexState[R128_MAX_TEXTURE_UNITS];
+ unsigned int dirty;
+ unsigned int vertsize;
+ unsigned int vc_format;
+
+#if defined(XF86DRI) | defined(_SOLO)
+ /* The current cliprects, or a subset thereof.
+ */
+ XF86DRIClipRectRec boxes[R128_NR_SAREA_CLIPRECTS];
+ unsigned int nbox;
+#endif
+
+ /* Counters for throttling of rendering clients.
+ */
+ unsigned int last_frame;
+ unsigned int last_dispatch;
+
+ /* Maintain an LRU of contiguous regions of texture space. If you
+ * think you own a region of texture memory, and it has an age
+ * different to the one you set, then you are mistaken and it has
+ * been stolen by another client. If global texAge hasn't changed,
+ * there is no need to walk the list.
+ *
+ * These regions can be used as a proxy for the fine-grained texture
+ * information of other clients - by maintaining them in the same
+ * lru which is used to age their own textures, clients have an
+ * approximate lru for the whole of global texture space, and can
+ * make informed decisions as to which areas to kick out. There is
+ * no need to choose whether to kick out your own texture or someone
+ * else's - simply eject them all in LRU order.
+ */
+ /* Last elt is sentinal */
+ drmTextureRegion texList[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1];
+ /* last time texture was uploaded */
+ unsigned int texAge[R128_NR_TEX_HEAPS];
+
+ int ctxOwner; /* last context to upload state */
+ int pfAllowPageFlip; /* set by the 2d driver, read by the client */
+ int pfCurrentPage; /* set by kernel, read by others */
+} R128SAREAPriv, *R128SAREAPrivPtr;
+
+#endif
diff --git a/src/mesa/drivers/dri/r128/server/r128_version.h b/src/mesa/drivers/dri/r128/server/r128_version.h
new file mode 100644
index 0000000000..589d8d40bc
--- /dev/null
+++ b/src/mesa/drivers/dri/r128/server/r128_version.h
@@ -0,0 +1,60 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_version.h,v 1.6 2003/01/01 19:16:35 tsi Exp $ */
+/*
+ * Copyright 2000 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _R128_VERSION_H_
+#define _R128_VERSION_H_ 1
+
+#undef R128_NAME
+#undef R128_DRIVER_NAME
+#undef R128_VERSION_MAJOR
+#undef R128_VERSION_MINOR
+#undef R128_VERSION_PATCH
+#undef R128_VERSION_CURRENT
+#undef R128_VERSION_EVALUATE
+#undef R128_VERSION_STRINGIFY
+#undef R128_VERSION_NAME
+
+#define R128_NAME "R128"
+#define R128_DRIVER_NAME "r128"
+
+#define R128_VERSION_MAJOR 4
+#define R128_VERSION_MINOR 0
+#define R128_VERSION_PATCH 1
+
+#ifndef R128_VERSION_EXTRA
+#define R128_VERSION_EXTRA ""
+#endif
+
+#define R128_VERSION_CURRENT \
+ ((R128_VERSION_MAJOR << 20) | \
+ (R128_VERSION_MINOR << 10) | \
+ (R128_VERSION_PATCH))
+
+#define R128_VERSION_EVALUATE(__x) #__x
+#define R128_VERSION_STRINGIFY(_x) R128_VERSION_EVALUATE(_x)
+#define R128_VERSION_NAME \
+ R128_VERSION_STRINGIFY(R128_VERSION_MAJOR) "." \
+ R128_VERSION_STRINGIFY(R128_VERSION_MINOR) "." \
+ R128_VERSION_STRINGIFY(R128_VERSION_MINOR) R128_VERSION_EXTRA
+
+#endif /* _R128_VERSION_H_ */
diff --git a/src/mesa/drivers/dri/r200/Makefile.X11 b/src/mesa/drivers/dri/r200/Makefile.X11
index b182ba559a..f1887b5914 100644
--- a/src/mesa/drivers/dri/r200/Makefile.X11
+++ b/src/mesa/drivers/dri/r200/Makefile.X11
@@ -1,4 +1,4 @@
-# $Id: Makefile.X11,v 1.1 2003/08/06 17:59:57 keithw Exp $
+# $Id: Makefile.X11,v 1.2 2003/08/22 20:11:45 brianp Exp $
# Mesa 3-D graphics library
# Version: 5.0
@@ -6,8 +6,10 @@
TOP = ../../../../..
+default: linux-solo
+
SHARED_INCLUDES = $(INCLUDE_DIRS) -I. -I../common -Iserver
-MINIGLX_INCLUDES = -I$(TOP)/src/miniglx
+MINIGLX_INCLUDES = -I$(TOP)/src/glx/mini
DEFINES += \
-D_HAVE_SWRAST=1 \
@@ -62,7 +64,7 @@ WINOBJ=$(MESABUILDDIR)/dri/dri.a
WINLIB=
else
WINOBJ=
-WINLIB=-L$(MESA)/src/miniglx
+WINLIB=-L$(MESA)/src/glx/mini
endif
ASM_SOURCES =
@@ -107,7 +109,7 @@ INCLUDE_DIRS = \
##### TARGETS #####
-targets: r200_dri.so
+targets: depend r200_dri.so
r200_dri.so: $(SYMLINKS) $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11
rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc $(GL_LIB_DEPS)
@@ -116,8 +118,8 @@ r200_dri.so: $(SYMLINKS) $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11
# Run 'make -f Makefile.X11 dep' to update the dependencies if you change
# what's included by any source file.
-dep: $(C_SOURCES) $(ASM_SOURCES)
- makedepend -fdepend -Y $(SHARED_INCLUDES) \
+depend: $(C_SOURCES) $(ASM_SOURCES)
+ makedepend -fdepend -Y $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) \
$(C_SOURCES) $(ASM_SOURCES)
@@ -128,7 +130,7 @@ tags:
# Remove .o and backup files
clean:
- -rm -f *.o *~ *.o *~ *.so
+ -rm -f *.o */*.o *~ *.o *~ *.so server/*.o
include $(TOP)/Make-config
diff --git a/src/mesa/drivers/dri/r200/r200_context.c b/src/mesa/drivers/dri/r200/r200_context.c
index c5f23effab..ec95f05e6e 100644
--- a/src/mesa/drivers/dri/r200/r200_context.c
+++ b/src/mesa/drivers/dri/r200/r200_context.c
@@ -492,8 +492,9 @@ void r200DestroyContext( __DRIcontextPrivate *driContextPriv )
* texture object data.
*/
int i;
-
- assert( is_empty_list( & rmesa->swapped ) );
+
+ /* this assert is wrong. The default textures are always on swap list
+ assert( is_empty_list( & rmesa->swapped ) ); */
for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
driDestroyTextureHeap( rmesa->texture_heaps[ i ] );
diff --git a/src/mesa/drivers/dri/r200/r200_context.h b/src/mesa/drivers/dri/r200/r200_context.h
index 3802deead9..9e00d7a358 100644
--- a/src/mesa/drivers/dri/r200/r200_context.h
+++ b/src/mesa/drivers/dri/r200/r200_context.h
@@ -615,7 +615,7 @@ struct r200_swtcl_info {
GLuint vertex_size;
GLuint vertex_stride_shift;
GLuint vertex_format;
- char *verts;
+ GLubyte *verts;
/* Fallback rasterization functions
*/
diff --git a/src/mesa/drivers/dri/r200/r200_ioctl.c b/src/mesa/drivers/dri/r200/r200_ioctl.c
index ea67216238..480121a094 100644
--- a/src/mesa/drivers/dri/r200/r200_ioctl.c
+++ b/src/mesa/drivers/dri/r200/r200_ioctl.c
@@ -320,7 +320,7 @@ static CARD32 r200GetLastFrame(r200ContextPtr rmesa)
CARD32 frame;
gp.param = RADEON_PARAM_LAST_FRAME;
- gp.value = (int *)&frame;
+ gp.value = &frame;
ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_GETPARAM,
&gp, sizeof(gp) );
if ( ret ) {
@@ -404,7 +404,7 @@ void r200CopyBuffer( const __DRIdrawablePrivate *dPriv )
r200ContextPtr rmesa;
GLint nbox, i, ret;
GLboolean missed_target;
- int64_t ust;
+ uint64_t ust;
assert(dPriv);
assert(dPriv->driContextPriv);
@@ -616,7 +616,7 @@ static void r200Clear( GLcontext *ctx, GLbitfield mask, GLboolean all,
int clear;
gp.param = RADEON_PARAM_LAST_CLEAR;
- gp.value = (int *)&clear;
+ gp.value = &clear;
ret = drmCommandWriteRead( rmesa->dri.fd,
DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
diff --git a/src/mesa/drivers/dri/r200/r200_swtcl.c b/src/mesa/drivers/dri/r200/r200_swtcl.c
index 6a436509a0..dd4025235b 100644
--- a/src/mesa/drivers/dri/r200/r200_swtcl.c
+++ b/src/mesa/drivers/dri/r200/r200_swtcl.c
@@ -446,7 +446,7 @@ static __inline void *r200AllocDmaLowVerts( r200ContextPtr rmesa,
{
- GLubyte *head = rmesa->dma.current.address + rmesa->dma.current.ptr;
+ char *head = rmesa->dma.current.address + rmesa->dma.current.ptr;
rmesa->dma.current.ptr += bytes;
rmesa->swtcl.numverts += nverts;
return head;
@@ -1260,7 +1260,7 @@ void r200InitSwtcl( GLcontext *ctx )
tnl->Driver.Render.ResetLineStipple = r200ResetLineStipple;
tnl->Driver.Render.BuildVertices = r200BuildVertices;
- rmesa->swtcl.verts = (char *)ALIGN_MALLOC( size * 16 * 4, 32 );
+ rmesa->swtcl.verts = (GLubyte *)ALIGN_MALLOC( size * 16 * 4, 32 );
rmesa->swtcl.RenderIndex = ~0;
rmesa->swtcl.render_primitive = GL_TRIANGLES;
rmesa->swtcl.hw_primitive = 0;
diff --git a/src/mesa/drivers/dri/r200/r200_tcl.c b/src/mesa/drivers/dri/r200/r200_tcl.c
index 994221d80c..9869ad6196 100644
--- a/src/mesa/drivers/dri/r200/r200_tcl.c
+++ b/src/mesa/drivers/dri/r200/r200_tcl.c
@@ -102,33 +102,23 @@ static GLboolean discrete_prim[0x10] = {
};
-#define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx);rmesa = rmesa
-#define ELTS_VARS GLushort *dest
+#define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx)
+#define ELT_TYPE GLushort
#define ELT_INIT(prim, hw_prim) \
r200TclPrimitive( ctx, prim, hw_prim | R200_VF_PRIM_WALK_IND )
-#define GET_ELTS() rmesa->tcl.Elts
+#define GET_MESA_ELTS() rmesa->tcl.Elts
-#define NEW_PRIMITIVE() R200_NEWPRIM( rmesa )
-#define NEW_BUFFER() r200RefillCurrentDmaRegion( rmesa )
-
/* Don't really know how many elts will fit in what's left of cmdbuf,
* as there is state to emit, etc:
*/
-#if 0
-#define GET_CURRENT_VB_MAX_ELTS() \
- ((R200_CMD_BUF_SZ - (rmesa->store.cmd_used + 16)) / 2)
-#define GET_SUBSEQUENT_VB_MAX_ELTS() ((R200_CMD_BUF_SZ - 16) / 2)
-#else
/* Testing on isosurf shows a maximum around here. Don't know if it's
* the card or driver or kernel module that is causing the behaviour.
*/
-#define GET_CURRENT_VB_MAX_ELTS() 300
-#define GET_SUBSEQUENT_VB_MAX_ELTS() 300
-#endif
+#define GET_MAX_HW_ELTS() 300
#define RESET_STIPPLE() do { \
R200_STATECHANGE( rmesa, lin ); \
@@ -147,32 +137,22 @@ static GLboolean discrete_prim[0x10] = {
} while (0)
-/* How do you extend an existing primitive?
- */
-#define ALLOC_ELTS(nr) \
-do { \
- if (rmesa->dma.flush == r200FlushElts && \
- rmesa->store.cmd_used + nr*2 < R200_CMD_BUF_SZ) { \
- \
- dest = (GLushort *)(rmesa->store.cmd_buf + \
- rmesa->store.cmd_used); \
- rmesa->store.cmd_used += nr*2; \
- } \
- else { \
- if (rmesa->dma.flush) \
- rmesa->dma.flush( rmesa ); \
- \
- r200EmitAOS( rmesa, \
- rmesa->tcl.aos_components, \
- rmesa->tcl.nr_aos_components, \
- 0 ); \
- \
- dest = r200AllocEltsOpenEnded( rmesa, \
- rmesa->tcl.hw_primitive, \
- nr ); \
- } \
-} while (0)
+#define ALLOC_ELTS(nr) r200AllocElts( rmesa, nr )
+static GLushort *r200AllocElts( r200ContextPtr rmesa, GLuint nr )
+{
+ if (rmesa->dma.flush)
+ rmesa->dma.flush( rmesa );
+
+ r200EmitAOS( rmesa,
+ rmesa->tcl.aos_components,
+ rmesa->tcl.nr_aos_components, 0 );
+
+ return r200AllocEltsOpenEnded( rmesa, rmesa->tcl.hw_primitive, nr );
+}
+
+
+#define CLOSE_ELTS() R200_NEWPRIM( rmesa )
/* TODO: Try to extend existing primitive if both are identical,
@@ -217,17 +197,15 @@ static void EMIT_PRIM( GLcontext *ctx,
#ifdef MESA_BIG_ENDIAN
/* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */
-#define EMIT_ELT(offset, x) do { \
+#define EMIT_ELT(dest, offset, x) do { \
int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \
GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \
(des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0)
#else
-#define EMIT_ELT(offset, x) (dest)[offset] = (GLushort) (x)
+#define EMIT_ELT(dest, offset, x) (dest)[offset] = (GLushort) (x)
#endif
-#define EMIT_TWO_ELTS(offset, x, y) *(GLuint *)(dest+offset) = ((y)<<16)|(x);
-#define INCR_ELTS( nr ) dest += nr
-#define RELEASE_ELT_VERTS() \
- r200ReleaseArrays( ctx, ~0 )
+
+#define EMIT_TWO_ELTS(dest, offset, x, y) *(GLuint *)((dest)+offset) = ((y)<<16)|(x);
diff --git a/src/mesa/drivers/dri/radeon/Makefile.X11 b/src/mesa/drivers/dri/radeon/Makefile.X11
new file mode 100644
index 0000000000..b73abe8f51
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/Makefile.X11
@@ -0,0 +1,154 @@
+# $Id: Makefile.X11,v 1.1 2003/08/22 20:11:45 brianp Exp $
+
+# 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
+
+ifeq ($(EMBEDDED),true)
+TARGET = radeon_es_dri.so
+DEFINES += \
+ -D_EMBEDDED \
+ -D_HAVE_SWRAST=0 \
+ -D_HAVE_SWTNL=0 \
+ -D_HAVE_SANITY=0 \
+ -D_HAVE_CODEGEN=0 \
+ -D_HAVE_LIGHTING=0 \
+ -D_HAVE_TEXGEN=0 \
+ -D_HAVE_USERCLIP=0 \
+ -DGLX_DIRECT_RENDERING
+else
+TARGET = radeon_dri.so
+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
+endif
+
+MESA_MODULES = $(TOP)/src/mesa/mesa.a
+
+MINIGLX_SOURCES = server/radeon_dri.c
+
+DRIVER_SOURCES = radeon_context.c \
+ radeon_ioctl.c \
+ radeon_lock.c \
+ radeon_screen.c \
+ radeon_state.c \
+ radeon_state_init.c \
+ ../common/mm.c \
+ ../common/utils.c \
+ ../common/texmem.c \
+ ../common/vblank.c
+
+SUBSET_DRIVER_SOURCES = \
+ radeon_subset_bitmap.c \
+ radeon_subset_readpix.c \
+ radeon_subset_select.c \
+ radeon_subset_tex.c \
+ radeon_subset_vtx.c
+
+FULL_DRIVER_SOURCES = \
+ radeon_tex.c \
+ radeon_texmem.c \
+ radeon_texstate.c \
+ radeon_tcl.c \
+ radeon_swtcl.c \
+ radeon_span.c \
+ radeon_maos.c \
+ radeon_sanity.c \
+ radeon_compat.c \
+ radeon_vtxfmt.c \
+ radeon_vtxfmt_c.c \
+ radeon_vtxfmt_sse.c \
+ radeon_vtxfmt_x86.c
+
+
+INCLUDES = $(MINIGLX_INCLUDES) \
+ $(SHARED_INCLUDES)
+
+
+ifeq ($(EMBEDDED),true)
+C_SOURCES = $(DRIVER_SOURCES) \
+ $(SUBSET_DRIVER_SOURCES) \
+ $(MINIGLX_SOURCES)
+else
+C_SOURCES = $(DRIVER_SOURCES) \
+ $(FULL_DRIVER_SOURCES) \
+ $(MINIGLX_SOURCES)
+endif
+
+
+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)
+
+### 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 $(TARGET)
+
+$(TARGET): $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11
+ rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc -lm
+ rm -f $(TOP)/lib/$(TARGET) && \
+ install $(TARGET) $(TOP)/lib/$(TARGET)
+
+# 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 *~ *.so server/*.o
+
+
+include $(TOP)/Make-config
+
+include depend
diff --git a/src/mesa/drivers/dri/radeon/radeon_compat.c b/src/mesa/drivers/dri/radeon/radeon_compat.c
new file mode 100644
index 0000000000..0c32641530
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_compat.c
@@ -0,0 +1,304 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2002 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Austin, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#include "glheader.h"
+#include "imports.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+
+
+static struct {
+ int start;
+ int len;
+ const char *name;
+} packet[RADEON_MAX_STATE_PACKETS] = {
+ { RADEON_PP_MISC,7,"RADEON_PP_MISC" },
+ { RADEON_PP_CNTL,3,"RADEON_PP_CNTL" },
+ { RADEON_RB3D_COLORPITCH,1,"RADEON_RB3D_COLORPITCH" },
+ { RADEON_RE_LINE_PATTERN,2,"RADEON_RE_LINE_PATTERN" },
+ { RADEON_SE_LINE_WIDTH,1,"RADEON_SE_LINE_WIDTH" },
+ { RADEON_PP_LUM_MATRIX,1,"RADEON_PP_LUM_MATRIX" },
+ { RADEON_PP_ROT_MATRIX_0,2,"RADEON_PP_ROT_MATRIX_0" },
+ { RADEON_RB3D_STENCILREFMASK,3,"RADEON_RB3D_STENCILREFMASK" },
+ { RADEON_SE_VPORT_XSCALE,6,"RADEON_SE_VPORT_XSCALE" },
+ { RADEON_SE_CNTL,2,"RADEON_SE_CNTL" },
+ { RADEON_SE_CNTL_STATUS,1,"RADEON_SE_CNTL_STATUS" },
+ { RADEON_RE_MISC,1,"RADEON_RE_MISC" },
+ { RADEON_PP_TXFILTER_0,6,"RADEON_PP_TXFILTER_0" },
+ { RADEON_PP_BORDER_COLOR_0,1,"RADEON_PP_BORDER_COLOR_0" },
+ { RADEON_PP_TXFILTER_1,6,"RADEON_PP_TXFILTER_1" },
+ { RADEON_PP_BORDER_COLOR_1,1,"RADEON_PP_BORDER_COLOR_1" },
+ { RADEON_PP_TXFILTER_2,6,"RADEON_PP_TXFILTER_2" },
+ { RADEON_PP_BORDER_COLOR_2,1,"RADEON_PP_BORDER_COLOR_2" },
+ { RADEON_SE_ZBIAS_FACTOR,2,"RADEON_SE_ZBIAS_FACTOR" },
+ { RADEON_SE_TCL_OUTPUT_VTX_FMT,11,"RADEON_SE_TCL_OUTPUT_VTX_FMT" },
+ { RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED,17,"RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED" },
+};
+
+
+static void radeonCompatEmitPacket( radeonContextPtr rmesa,
+ struct radeon_state_atom *state )
+{
+ RADEONSAREAPrivPtr sarea = rmesa->sarea;
+ radeon_context_regs_t *ctx = &sarea->ContextState;
+ radeon_texture_regs_t *tex0 = &sarea->TexState[0];
+ radeon_texture_regs_t *tex1 = &sarea->TexState[1];
+ int i;
+ int *buf = state->cmd;
+
+ for ( i = 0 ; i < state->cmd_size ; ) {
+ drmRadeonCmdHeader *header = (drmRadeonCmdHeader *)&buf[i++];
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s %d: %s\n", __FUNCTION__, header->packet.packet_id,
+ packet[(int)header->packet.packet_id].name);
+
+ switch (header->packet.packet_id) {
+ case RADEON_EMIT_PP_MISC:
+ ctx->pp_misc = buf[i++];
+ ctx->pp_fog_color = buf[i++];
+ ctx->re_solid_color = buf[i++];
+ ctx->rb3d_blendcntl = buf[i++];
+ ctx->rb3d_depthoffset = buf[i++];
+ ctx->rb3d_depthpitch = buf[i++];
+ ctx->rb3d_zstencilcntl = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_CONTEXT;
+ break;
+ case RADEON_EMIT_PP_CNTL:
+ ctx->pp_cntl = buf[i++];
+ ctx->rb3d_cntl = buf[i++];
+ ctx->rb3d_coloroffset = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_CONTEXT;
+ break;
+ case RADEON_EMIT_RB3D_COLORPITCH:
+ ctx->rb3d_colorpitch = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_CONTEXT;
+ break;
+ case RADEON_EMIT_RE_LINE_PATTERN:
+ ctx->re_line_pattern = buf[i++];
+ ctx->re_line_state = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_LINE;
+ break;
+ case RADEON_EMIT_SE_LINE_WIDTH:
+ ctx->se_line_width = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_LINE;
+ break;
+ case RADEON_EMIT_PP_LUM_MATRIX:
+ ctx->pp_lum_matrix = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_BUMPMAP;
+ break;
+ case RADEON_EMIT_PP_ROT_MATRIX_0:
+ ctx->pp_rot_matrix_0 = buf[i++];
+ ctx->pp_rot_matrix_1 = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_BUMPMAP;
+ break;
+ case RADEON_EMIT_RB3D_STENCILREFMASK:
+ ctx->rb3d_stencilrefmask = buf[i++];
+ ctx->rb3d_ropcntl = buf[i++];
+ ctx->rb3d_planemask = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_MASKS;
+ break;
+ case RADEON_EMIT_SE_VPORT_XSCALE:
+ ctx->se_vport_xscale = buf[i++];
+ ctx->se_vport_xoffset = buf[i++];
+ ctx->se_vport_yscale = buf[i++];
+ ctx->se_vport_yoffset = buf[i++];
+ ctx->se_vport_zscale = buf[i++];
+ ctx->se_vport_zoffset = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_VIEWPORT;
+ break;
+ case RADEON_EMIT_SE_CNTL:
+ ctx->se_cntl = buf[i++];
+ ctx->se_coord_fmt = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_VERTFMT;
+ break;
+ case RADEON_EMIT_SE_CNTL_STATUS:
+ ctx->se_cntl_status = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_SETUP;
+ break;
+ case RADEON_EMIT_RE_MISC:
+ ctx->re_misc = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_MISC;
+ break;
+ case RADEON_EMIT_PP_TXFILTER_0:
+ tex0->pp_txfilter = buf[i++];
+ tex0->pp_txformat = buf[i++];
+ tex0->pp_txoffset = buf[i++];
+ tex0->pp_txcblend = buf[i++];
+ tex0->pp_txablend = buf[i++];
+ tex0->pp_tfactor = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_TEX0;
+ break;
+ case RADEON_EMIT_PP_BORDER_COLOR_0:
+ tex0->pp_border_color = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_TEX0;
+ break;
+ case RADEON_EMIT_PP_TXFILTER_1:
+ tex1->pp_txfilter = buf[i++];
+ tex1->pp_txformat = buf[i++];
+ tex1->pp_txoffset = buf[i++];
+ tex1->pp_txcblend = buf[i++];
+ tex1->pp_txablend = buf[i++];
+ tex1->pp_tfactor = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_TEX1;
+ break;
+ case RADEON_EMIT_PP_BORDER_COLOR_1:
+ tex1->pp_border_color = buf[i++];
+ sarea->dirty |= RADEON_UPLOAD_TEX1;
+ break;
+
+ case RADEON_EMIT_SE_ZBIAS_FACTOR:
+ i++;
+ i++;
+ break;
+
+ case RADEON_EMIT_PP_TXFILTER_2:
+ case RADEON_EMIT_PP_BORDER_COLOR_2:
+ case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
+ case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
+ default:
+ /* These states aren't understood by radeon drm 1.1 */
+ fprintf(stderr, "Tried to emit unsupported state\n");
+ return;
+ }
+ }
+}
+
+
+
+static void radeonCompatEmitStateLocked( radeonContextPtr rmesa )
+{
+ struct radeon_state_atom *state, *tmp;
+
+ if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS))
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (rmesa->lost_context) {
+ if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS|DEBUG_IOCTL))
+ fprintf(stderr, "%s - lost context\n", __FUNCTION__);
+
+ foreach_s( state, tmp, &(rmesa->hw.clean) )
+ move_to_tail(&(rmesa->hw.dirty), state );
+
+ rmesa->lost_context = 0;
+ }
+
+ foreach_s( state, tmp, &(rmesa->hw.dirty) ) {
+ if (!state->is_tcl)
+ radeonCompatEmitPacket( rmesa, state );
+ move_to_head( &(rmesa->hw.clean), state );
+ }
+}
+
+
+
+static void radeonCompatEmitPrimitiveLocked( radeonContextPtr rmesa,
+ GLuint hw_primitive,
+ GLuint nverts,
+ XF86DRIClipRectPtr pbox,
+ GLuint nbox )
+{
+ int i;
+
+ for ( i = 0 ; i < nbox ; ) {
+ int nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, nbox );
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+ drmRadeonVertex vtx;
+
+ rmesa->sarea->dirty |= RADEON_UPLOAD_CLIPRECTS;
+ rmesa->sarea->nbox = nr - i;
+
+ for ( ; i < nr ; i++)
+ *b++ = pbox[i];
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr,
+ "RadeonFlushVertexBuffer: prim %x buf %d verts %d "
+ "disc %d nbox %d\n",
+ hw_primitive,
+ rmesa->dma.current.buf->buf->idx,
+ nverts,
+ nr == nbox,
+ rmesa->sarea->nbox );
+
+ vtx.prim = hw_primitive;
+ vtx.idx = rmesa->dma.current.buf->buf->idx;
+ vtx.count = nverts;
+ vtx.discard = (nr == nbox);
+
+ drmCommandWrite( rmesa->dri.fd,
+ DRM_RADEON_VERTEX,
+ &vtx, sizeof(vtx));
+ }
+}
+
+
+
+/* No 'start' for 1.1 vertices ioctl: only one vertex prim/buffer!
+ */
+void radeonCompatEmitPrimitive( radeonContextPtr rmesa,
+ GLuint vertex_format,
+ GLuint hw_primitive,
+ GLuint nrverts )
+{
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ LOCK_HARDWARE( rmesa );
+
+ radeonCompatEmitStateLocked( rmesa );
+ rmesa->sarea->vc_format = vertex_format;
+
+ if (rmesa->state.scissor.enabled) {
+ radeonCompatEmitPrimitiveLocked( rmesa,
+ hw_primitive,
+ nrverts,
+ rmesa->state.scissor.pClipRects,
+ rmesa->state.scissor.numClipRects );
+ }
+ else {
+ radeonCompatEmitPrimitiveLocked( rmesa,
+ hw_primitive,
+ nrverts,
+ rmesa->pClipRects,
+ rmesa->numClipRects );
+ }
+
+
+ UNLOCK_HARDWARE( rmesa );
+}
+
diff --git a/src/mesa/drivers/dri/radeon/radeon_context.c b/src/mesa/drivers/dri/radeon/radeon_context.c
new file mode 100644
index 0000000000..835cecbc3a
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_context.c
@@ -0,0 +1,598 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_context.c,v 1.7 2003/02/08 21:26:45 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "api_arrayelt.h"
+#include "context.h"
+#include "simple_list.h"
+#include "imports.h"
+#include "matrix.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"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_span.h"
+#include "radeon_tex.h"
+#include "radeon_swtcl.h"
+#include "radeon_tcl.h"
+#include "radeon_vtxfmt.h"
+#include "radeon_maos.h"
+
+#define DRIVER_DATE "20030328"
+
+#include "vblank.h"
+#include "utils.h"
+#ifndef RADEON_DEBUG
+int RADEON_DEBUG = (0);
+#endif
+
+
+
+/* Return the width and height of the given buffer.
+ */
+static void radeonGetBufferSize( GLframebuffer *buffer,
+ GLuint *width, GLuint *height )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ LOCK_HARDWARE( rmesa );
+ *width = rmesa->dri.drawable->w;
+ *height = rmesa->dri.drawable->h;
+ UNLOCK_HARDWARE( rmesa );
+}
+
+/* Return various strings for glGetString().
+ */
+static const GLubyte *radeonGetString( GLcontext *ctx, GLenum name )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ static char buffer[128];
+ unsigned offset;
+ GLuint agp_mode = rmesa->radeonScreen->IsPCI ? 0 :
+ rmesa->radeonScreen->AGPMode;
+
+ switch ( name ) {
+ case GL_VENDOR:
+ return (GLubyte *)"Tungsten Graphics, Inc.";
+
+ case GL_RENDERER:
+ offset = driGetRendererString( buffer, "Radeon", DRIVER_DATE,
+ agp_mode );
+
+ sprintf( & buffer[ offset ], "%s %sTCL",
+ ( rmesa->dri.drmMinor < 3 ) ? " DRM-COMPAT" : "",
+ !(rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE)
+ ? "" : "NO-" );
+
+ return (GLubyte *)buffer;
+
+ default:
+ return NULL;
+ }
+}
+
+
+/* Extension strings exported by the R100 driver.
+ */
+static const char * const card_extensions[] =
+{
+ "GL_ARB_multisample",
+ "GL_ARB_multitexture",
+ "GL_ARB_texture_border_clamp",
+ "GL_ARB_texture_compression",
+ "GL_ARB_texture_env_add",
+ "GL_ARB_texture_env_combine",
+ "GL_ARB_texture_env_dot3",
+ "GL_ARB_texture_mirrored_repeat",
+ "GL_EXT_blend_logic_op",
+ "GL_EXT_blend_subtract",
+ "GL_EXT_secondary_color",
+ "GL_EXT_texture_edge_clamp",
+ "GL_EXT_texture_env_add",
+ "GL_EXT_texture_env_combine",
+ "GL_EXT_texture_env_dot3",
+ "GL_EXT_texture_filter_anisotropic",
+ "GL_EXT_texture_lod_bias",
+ "GL_ATI_texture_env_combine3",
+ "GL_ATI_texture_mirror_once",
+ "GL_IBM_texture_mirrored_repeat",
+ "GL_MESA_ycbcr_texture",
+ "GL_NV_blend_square",
+ "GL_SGIS_generate_mipmap",
+ "GL_SGIS_texture_border_clamp",
+ "GL_SGIS_texture_edge_clamp",
+ NULL
+};
+
+extern const struct gl_pipeline_stage _radeon_texrect_stage;
+extern const struct gl_pipeline_stage _radeon_render_stage;
+extern const struct gl_pipeline_stage _radeon_tcl_stage;
+
+static const struct gl_pipeline_stage *radeon_pipeline[] = {
+
+ /* Try and go straight to t&l
+ */
+ &_radeon_tcl_stage,
+
+ /* Catch any t&l fallbacks
+ */
+ &_tnl_vertex_transform_stage,
+ &_tnl_normal_transform_stage,
+ &_tnl_lighting_stage,
+ &_tnl_fog_coordinate_stage,
+ &_tnl_texgen_stage,
+ &_tnl_texture_transform_stage,
+
+ /* Scale texture rectangle to 0..1.
+ */
+ &_radeon_texrect_stage,
+
+ &_radeon_render_stage,
+ &_tnl_render_stage, /* FALLBACK: */
+ 0,
+};
+
+
+
+/* Initialize the driver's misc functions.
+ */
+static void radeonInitDriverFuncs( GLcontext *ctx )
+{
+ ctx->Driver.GetBufferSize = radeonGetBufferSize;
+ ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
+ ctx->Driver.GetString = radeonGetString;
+
+ ctx->Driver.Error = NULL;
+ ctx->Driver.DrawPixels = NULL;
+ ctx->Driver.Bitmap = NULL;
+}
+
+static const struct dri_debug_control debug_control[] =
+{
+ { "fall", DEBUG_FALLBACKS },
+ { "tex", DEBUG_TEXTURE },
+ { "ioctl", DEBUG_IOCTL },
+ { "prim", DEBUG_PRIMS },
+ { "vert", DEBUG_VERTS },
+ { "state", DEBUG_STATE },
+ { "code", DEBUG_CODEGEN },
+ { "vfmt", DEBUG_VFMT },
+ { "vtxf", DEBUG_VFMT },
+ { "verb", DEBUG_VERBOSE },
+ { "dri", DEBUG_DRI },
+ { "dma", DEBUG_DMA },
+ { "san", DEBUG_SANITY },
+ { NULL, 0 }
+};
+
+
+static int
+get_ust_nop( uint64_t * ust )
+{
+ *ust = 1;
+ return 0;
+}
+
+
+/* Create the device specific context.
+ */
+GLboolean
+radeonCreateContext( const __GLcontextModes *glVisual,
+ __DRIcontextPrivate *driContextPriv,
+ void *sharedContextPrivate)
+{
+ __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
+ radeonScreenPtr screen = (radeonScreenPtr)(sPriv->private);
+ radeonContextPtr rmesa;
+ GLcontext *ctx, *shareCtx;
+ int i;
+
+ assert(glVisual);
+ assert(driContextPriv);
+ assert(screen);
+
+ /* Allocate the Radeon context */
+ rmesa = (radeonContextPtr) CALLOC( sizeof(*rmesa) );
+ if ( !rmesa )
+ return GL_FALSE;
+
+ /* Allocate the Mesa context */
+ if (sharedContextPrivate)
+ shareCtx = ((radeonContextPtr) sharedContextPrivate)->glCtx;
+ else
+ shareCtx = NULL;
+ rmesa->glCtx = _mesa_create_context(glVisual, shareCtx, (void *) rmesa, GL_TRUE);
+ if (!rmesa->glCtx) {
+ FREE(rmesa);
+ return GL_FALSE;
+ }
+ driContextPriv->driverPrivate = rmesa;
+
+ /* Init radeon context data */
+ rmesa->dri.context = driContextPriv;
+ rmesa->dri.screen = sPriv;
+ rmesa->dri.drawable = NULL; /* Set by XMesaMakeCurrent */
+ rmesa->dri.hwContext = driContextPriv->hHWContext;
+ rmesa->dri.hwLock = &sPriv->pSAREA->lock;
+ rmesa->dri.fd = sPriv->fd;
+
+ /* If we don't have 1.3, fallback to the 1.1 interfaces.
+ */
+ if (getenv("RADEON_COMPAT") || sPriv->drmMinor < 3 )
+ rmesa->dri.drmMinor = 1;
+ else
+ rmesa->dri.drmMinor = sPriv->drmMinor;
+
+ rmesa->radeonScreen = screen;
+ rmesa->sarea = (RADEONSAREAPrivPtr)((GLubyte *)sPriv->pSAREA +
+ screen->sarea_priv_offset);
+
+
+ rmesa->dma.buf0_address = rmesa->radeonScreen->buffers->list[0].address;
+
+ (void) memset( rmesa->texture_heaps, 0, sizeof( rmesa->texture_heaps ) );
+ make_empty_list( & rmesa->swapped );
+
+ rmesa->nr_heaps = screen->numTexHeaps;
+ for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
+ rmesa->texture_heaps[i] = driCreateTextureHeap( i, rmesa,
+ screen->texSize[i],
+ 12,
+ RADEON_NR_TEX_REGIONS,
+ rmesa->sarea->texList[i],
+ & rmesa->sarea->texAge[i],
+ & rmesa->swapped,
+ sizeof( radeonTexObj ),
+ (destroy_texture_object_t *) radeonDestroyTexObj );
+
+ driSetTextureSwapCounterLocation( rmesa->texture_heaps[i],
+ & rmesa->c_textureSwaps );
+ }
+
+ rmesa->swtcl.RenderIndex = ~0;
+ rmesa->lost_context = 1;
+
+ /* Set the maximum texture size small enough that we can guarentee that
+ * all texture units can bind a maximal texture and have them both in
+ * texturable memory at once.
+ */
+
+ ctx = rmesa->glCtx;
+ ctx->Const.MaxTextureUnits = 2;
+
+ driCalculateMaxTextureLevels( rmesa->texture_heaps,
+ rmesa->nr_heaps,
+ & ctx->Const,
+ 4,
+ 11, /* max 2D texture size is 2048x2048 */
+ 0, /* 3D textures unsupported. */
+ 0, /* cube textures unsupported. */
+ 11, /* max rect texture size is 2048x2048. */
+ 12,
+ GL_FALSE );
+
+ ctx->Const.MaxTextureMaxAnisotropy = 16.0;
+
+ /* No wide points.
+ */
+ ctx->Const.MinPointSize = 1.0;
+ ctx->Const.MinPointSizeAA = 1.0;
+ ctx->Const.MaxPointSize = 1.0;
+ ctx->Const.MaxPointSizeAA = 1.0;
+
+ ctx->Const.MinLineWidth = 1.0;
+ ctx->Const.MinLineWidthAA = 1.0;
+ ctx->Const.MaxLineWidth = 10.0;
+ ctx->Const.MaxLineWidthAA = 10.0;
+ ctx->Const.LineWidthGranularity = 0.0625;
+
+ /* Set maxlocksize (and hence vb size) small enough to avoid
+ * fallbacks in radeon_tcl.c. ie. guarentee that all vertices can
+ * fit in a single dma buffer for indexed rendering of quad strips,
+ * etc.
+ */
+ ctx->Const.MaxArrayLockSize =
+ MIN2( ctx->Const.MaxArrayLockSize,
+ RADEON_BUFFER_SIZE / RADEON_MAX_TCL_VERTSIZE );
+
+ rmesa->boxes = (getenv("LIBGL_PERFORMANCE_BOXES") != NULL);
+
+ /* Initialize the software rasterizer and helper modules.
+ */
+ _swrast_CreateContext( ctx );
+ _ac_CreateContext( ctx );
+ _tnl_CreateContext( ctx );
+ _swsetup_CreateContext( ctx );
+ _ae_create_context( ctx );
+
+ /* Install the customized pipeline:
+ */
+ _tnl_destroy_pipeline( ctx );
+ _tnl_install_pipeline( ctx, radeon_pipeline );
+ ctx->Driver.FlushVertices = radeonFlushVertices;
+
+ /* Try and keep materials and vertices separate:
+ */
+ _tnl_isolate_materials( ctx, GL_TRUE );
+
+
+/* _mesa_allow_light_in_model( ctx, GL_FALSE ); */
+
+ /* Try and keep materials and vertices separate:
+ */
+ _tnl_isolate_materials( ctx, GL_TRUE );
+
+
+ /* Configure swrast to match hardware characteristics:
+ */
+ _swrast_allow_pixel_fog( ctx, GL_FALSE );
+ _swrast_allow_vertex_fog( ctx, GL_TRUE );
+
+
+ _math_matrix_ctr( &rmesa->TexGenMatrix[0] );
+ _math_matrix_ctr( &rmesa->TexGenMatrix[1] );
+ _math_matrix_ctr( &rmesa->tmpmat );
+ _math_matrix_set_identity( &rmesa->TexGenMatrix[0] );
+ _math_matrix_set_identity( &rmesa->TexGenMatrix[1] );
+ _math_matrix_set_identity( &rmesa->tmpmat );
+
+ driInitExtensions( ctx, card_extensions, GL_TRUE );
+
+ if (rmesa->dri.drmMinor >= 9)
+ _mesa_enable_extension( ctx, "GL_NV_texture_rectangle");
+
+ radeonInitDriverFuncs( ctx );
+ radeonInitIoctlFuncs( ctx );
+ radeonInitStateFuncs( ctx );
+ radeonInitSpanFuncs( ctx );
+ radeonInitTextureFuncs( ctx );
+ radeonInitState( rmesa );
+ radeonInitSwtcl( ctx );
+
+ rmesa->iw.irq_seq = -1;
+ rmesa->irqsEmitted = 0;
+ rmesa->do_irqs = (rmesa->radeonScreen->irq && !getenv("RADEON_NO_IRQS"));
+
+ rmesa->do_usleeps = !getenv("RADEON_NO_USLEEPS");
+
+ rmesa->vblank_flags = (rmesa->do_irqs)
+ ? driGetDefaultVBlankFlags() : VBLANK_FLAG_NO_IRQ;
+
+#ifndef _SOLO
+ rmesa->get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( "__glXGetUST" );
+ if ( rmesa->get_ust == NULL )
+#endif
+ {
+ rmesa->get_ust = get_ust_nop;
+ }
+
+ (*rmesa->get_ust)( & rmesa->swap_ust );
+
+
+#if DO_DEBUG
+ RADEON_DEBUG = driParseDebugString( getenv( "RADEON_DEBUG" ),
+ debug_control );
+#endif
+
+ if (getenv("RADEON_NO_RAST")) {
+ fprintf(stderr, "disabling 3D acceleration\n");
+ FALLBACK(rmesa, RADEON_FALLBACK_DISABLE, 1);
+ }
+ else if (getenv("RADEON_TCL_FORCE_ENABLE")) {
+ fprintf(stderr, "Enabling TCL support... this will probably crash\n");
+ fprintf(stderr, " your card if it isn't capable of TCL!\n");
+ rmesa->radeonScreen->chipset |= RADEON_CHIPSET_TCL;
+ } else if (getenv("RADEON_TCL_FORCE_DISABLE") ||
+ rmesa->dri.drmMinor < 3 ||
+ !(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) {
+ rmesa->radeonScreen->chipset &= ~RADEON_CHIPSET_TCL;
+ fprintf(stderr, "disabling TCL support\n");
+ TCL_FALLBACK(rmesa->glCtx, RADEON_TCL_FALLBACK_TCL_DISABLE, 1);
+ }
+
+ if (rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL) {
+ if (!getenv("RADEON_NO_VTXFMT"))
+ radeonVtxfmtInit( ctx );
+
+ _tnl_need_dlist_norm_lengths( ctx, GL_FALSE );
+ }
+ return GL_TRUE;
+}
+
+
+/* Destroy the device specific context.
+ */
+/* Destroy the Mesa and driver specific context data.
+ */
+void radeonDestroyContext( __DRIcontextPrivate *driContextPriv )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate;
+ radeonContextPtr current = ctx ? RADEON_CONTEXT(ctx) : NULL;
+
+ /* check if we're deleting the currently bound context */
+ if (rmesa == current) {
+ RADEON_FIREVERTICES( rmesa );
+ _mesa_make_current2(NULL, NULL, NULL);
+ }
+
+ /* Free radeon context resources */
+ assert(rmesa); /* should never be null */
+ if ( rmesa ) {
+ GLboolean release_texture_heaps;
+
+
+ release_texture_heaps = (rmesa->glCtx->Shared->RefCount == 1);
+ _swsetup_DestroyContext( rmesa->glCtx );
+ _tnl_DestroyContext( rmesa->glCtx );
+ _ac_DestroyContext( rmesa->glCtx );
+ _swrast_DestroyContext( rmesa->glCtx );
+
+ radeonDestroySwtcl( rmesa->glCtx );
+ radeonReleaseArrays( rmesa->glCtx, ~0 );
+ if (rmesa->dma.current.buf) {
+ radeonReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ );
+ radeonFlushCmdBuf( rmesa, __FUNCTION__ );
+ }
+
+ if (!rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE)
+ if (!getenv("RADEON_NO_VTXFMT"))
+ radeonVtxfmtDestroy( rmesa->glCtx );
+
+ /* free the Mesa context */
+ rmesa->glCtx->DriverCtx = NULL;
+ _mesa_destroy_context( rmesa->glCtx );
+
+ if (rmesa->state.scissor.pClipRects) {
+ FREE(rmesa->state.scissor.pClipRects);
+ rmesa->state.scissor.pClipRects = 0;
+ }
+
+ if ( release_texture_heaps ) {
+ /* This share group is about to go away, free our private
+ * texture object data.
+ */
+ int i;
+
+ /* this assert is not correct, default textures are always on swap list
+ assert( is_empty_list( & rmesa->swapped ) ); */
+
+ for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
+ driDestroyTextureHeap( rmesa->texture_heaps[ i ] );
+ rmesa->texture_heaps[ i ] = NULL;
+ }
+ }
+
+ FREE( rmesa );
+ }
+}
+
+
+
+
+void
+radeonSwapBuffers( __DRIdrawablePrivate *dPriv )
+{
+
+ if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+ radeonContextPtr rmesa;
+ GLcontext *ctx;
+ rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
+ ctx = rmesa->glCtx;
+ if (ctx->Visual.doubleBufferMode) {
+ _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
+
+ if ( rmesa->doPageFlip ) {
+ radeonPageFlip( dPriv );
+ }
+ else {
+ radeonCopyBuffer( dPriv );
+ }
+ }
+ }
+ else {
+ /* XXX this shouldn't be an error but we can't handle it for now */
+ _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
+ }
+}
+
+
+/* Force the context `c' to be the current context and associate with it
+ * buffer `b'.
+ */
+GLboolean
+radeonMakeCurrent( __DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv )
+{
+ if ( driContextPriv ) {
+ radeonContextPtr newCtx =
+ (radeonContextPtr) driContextPriv->driverPrivate;
+
+ if (RADEON_DEBUG & DEBUG_DRI)
+ fprintf(stderr, "%s ctx %p\n", __FUNCTION__, newCtx->glCtx);
+
+ if ( newCtx->dri.drawable != driDrawPriv ) {
+ newCtx->dri.drawable = driDrawPriv;
+ radeonUpdateWindow( newCtx->glCtx );
+ radeonUpdateViewportOffset( newCtx->glCtx );
+ }
+
+ _mesa_make_current2( newCtx->glCtx,
+ (GLframebuffer *) driDrawPriv->driverPrivate,
+ (GLframebuffer *) driReadPriv->driverPrivate );
+
+ if ( !newCtx->glCtx->Viewport.Width ) {
+ _mesa_set_viewport( newCtx->glCtx, 0, 0,
+ driDrawPriv->w, driDrawPriv->h );
+ }
+
+ if (newCtx->vb.enabled)
+ radeonVtxfmtMakeCurrent( newCtx->glCtx );
+
+ } else {
+ if (RADEON_DEBUG & DEBUG_DRI)
+ fprintf(stderr, "%s ctx is null\n", __FUNCTION__);
+ _mesa_make_current( 0, 0 );
+ }
+
+ if (RADEON_DEBUG & DEBUG_DRI)
+ fprintf(stderr, "End %s\n", __FUNCTION__);
+ return GL_TRUE;
+}
+
+/* Force the context `c' to be unbound from its buffer.
+ */
+GLboolean
+radeonUnbindContext( __DRIcontextPrivate *driContextPriv )
+{
+ radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate;
+
+ if (RADEON_DEBUG & DEBUG_DRI)
+ fprintf(stderr, "%s ctx %p\n", __FUNCTION__, rmesa->glCtx);
+
+ return GL_TRUE;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_context.h b/src/mesa/drivers/dri/radeon/radeon_context.h
new file mode 100644
index 0000000000..5f1f9659e8
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_context.h
@@ -0,0 +1,839 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_context.h,v 1.6 2002/12/16 16:18:58 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#ifndef __RADEON_CONTEXT_H__
+#define __RADEON_CONTEXT_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <inttypes.h>
+#include "dri_util.h"
+#include "radeon_common.h"
+#include "texmem.h"
+
+#include "macros.h"
+#include "mtypes.h"
+#include "colormac.h"
+
+struct radeon_context;
+typedef struct radeon_context radeonContextRec;
+typedef struct radeon_context *radeonContextPtr;
+
+#include "radeon_lock.h"
+#include "radeon_screen.h"
+#include "mm.h"
+
+/* Flags for software fallback cases */
+/* See correponding strings in radeon_swtcl.c */
+#define RADEON_FALLBACK_TEXTURE 0x0001
+#define RADEON_FALLBACK_DRAW_BUFFER 0x0002
+#define RADEON_FALLBACK_STENCIL 0x0004
+#define RADEON_FALLBACK_RENDER_MODE 0x0008
+#define RADEON_FALLBACK_BLEND_EQ 0x0010
+#define RADEON_FALLBACK_BLEND_FUNC 0x0020
+#define RADEON_FALLBACK_DISABLE 0x0040
+#define RADEON_FALLBACK_BORDER_MODE 0x0080
+
+/* The blit width for texture uploads
+ */
+#define BLIT_WIDTH_BYTES 1024
+
+/* Use the templated vertex format:
+ */
+#define COLOR_IS_RGBA
+#define TAG(x) radeon##x
+#include "tnl_dd/t_dd_vertex.h"
+#undef TAG
+
+typedef void (*radeon_tri_func)( radeonContextPtr,
+ radeonVertex *,
+ radeonVertex *,
+ radeonVertex * );
+
+typedef void (*radeon_line_func)( radeonContextPtr,
+ radeonVertex *,
+ radeonVertex * );
+
+typedef void (*radeon_point_func)( radeonContextPtr,
+ radeonVertex * );
+
+
+struct radeon_colorbuffer_state {
+ GLuint clear;
+ GLint drawOffset, drawPitch;
+};
+
+
+struct radeon_depthbuffer_state {
+ GLuint clear;
+ GLfloat scale;
+};
+
+struct radeon_pixel_state {
+ GLint readOffset, readPitch;
+};
+
+struct radeon_scissor_state {
+ XF86DRIClipRectRec rect;
+ GLboolean enabled;
+
+ GLuint numClipRects; /* Cliprects active */
+ GLuint numAllocedClipRects; /* Cliprects available */
+ XF86DRIClipRectPtr pClipRects;
+};
+
+struct radeon_stencilbuffer_state {
+ GLboolean hwBuffer;
+ GLuint clear; /* rb3d_stencilrefmask value */
+};
+
+struct radeon_stipple_state {
+ GLuint mask[32];
+};
+
+
+
+#define TEX_0 0x1
+#define TEX_1 0x2
+#define TEX_ALL 0x3
+
+typedef struct radeon_tex_obj radeonTexObj, *radeonTexObjPtr;
+
+/* Texture object in locally shared texture space.
+ */
+struct radeon_tex_obj {
+ driTextureObject base;
+
+ GLuint bufAddr; /* Offset to start of locally
+ shared texture block */
+
+ GLuint dirty_state; /* Flags (1 per texunit) for
+ whether or not this texobj
+ has dirty hardware state
+ (pp_*) that needs to be
+ brought into the
+ texunit. */
+
+ drmRadeonTexImage image[6][RADEON_MAX_TEXTURE_LEVELS];
+ /* Six, for the cube faces */
+
+ GLuint pp_txfilter; /* hardware register values */
+ GLuint pp_txformat;
+ GLuint pp_txoffset; /* Image location in texmem.
+ All cube faces follow. */
+ GLuint pp_txsize; /* npot only */
+ GLuint pp_txpitch; /* npot only */
+ GLuint pp_border_color;
+ GLuint pp_cubic_faces; /* cube face 1,2,3,4 log2 sizes */
+
+ GLboolean border_fallback;
+};
+
+
+struct radeon_texture_env_state {
+ radeonTexObjPtr texobj;
+ GLenum format;
+ GLenum envMode;
+};
+
+struct radeon_texture_state {
+ struct radeon_texture_env_state unit[RADEON_MAX_TEXTURE_UNITS];
+};
+
+
+struct radeon_state_atom {
+ struct radeon_state_atom *next, *prev;
+ const char *name; /* for debug */
+ int cmd_size; /* size in bytes */
+ GLuint is_tcl;
+ int *cmd; /* one or more cmd's */
+ int *lastcmd; /* one or more cmd's */
+ GLboolean (*check)( GLcontext * ); /* is this state active? */
+};
+
+
+
+/* Trying to keep these relatively short as the variables are becoming
+ * extravagently long. Drop the driver name prefix off the front of
+ * everything - I think we know which driver we're in by now, and keep the
+ * prefix to 3 letters unless absolutely impossible.
+ */
+
+#define CTX_CMD_0 0
+#define CTX_PP_MISC 1
+#define CTX_PP_FOG_COLOR 2
+#define CTX_RE_SOLID_COLOR 3
+#define CTX_RB3D_BLENDCNTL 4
+#define CTX_RB3D_DEPTHOFFSET 5
+#define CTX_RB3D_DEPTHPITCH 6
+#define CTX_RB3D_ZSTENCILCNTL 7
+#define CTX_CMD_1 8
+#define CTX_PP_CNTL 9
+#define CTX_RB3D_CNTL 10
+#define CTX_RB3D_COLOROFFSET 11
+#define CTX_CMD_2 12
+#define CTX_RB3D_COLORPITCH 13
+#define CTX_STATE_SIZE 14
+
+#define SET_CMD_0 0
+#define SET_SE_CNTL 1
+#define SET_SE_COORDFMT 2
+#define SET_CMD_1 3
+#define SET_SE_CNTL_STATUS 4
+#define SET_STATE_SIZE 5
+
+#define LIN_CMD_0 0
+#define LIN_RE_LINE_PATTERN 1
+#define LIN_RE_LINE_STATE 2
+#define LIN_CMD_1 3
+#define LIN_SE_LINE_WIDTH 4
+#define LIN_STATE_SIZE 5
+
+#define MSK_CMD_0 0
+#define MSK_RB3D_STENCILREFMASK 1
+#define MSK_RB3D_ROPCNTL 2
+#define MSK_RB3D_PLANEMASK 3
+#define MSK_STATE_SIZE 4
+
+#define VPT_CMD_0 0
+#define VPT_SE_VPORT_XSCALE 1
+#define VPT_SE_VPORT_XOFFSET 2
+#define VPT_SE_VPORT_YSCALE 3
+#define VPT_SE_VPORT_YOFFSET 4
+#define VPT_SE_VPORT_ZSCALE 5
+#define VPT_SE_VPORT_ZOFFSET 6
+#define VPT_STATE_SIZE 7
+
+#define MSC_CMD_0 0
+#define MSC_RE_MISC 1
+#define MSC_STATE_SIZE 2
+
+#define TEX_CMD_0 0
+#define TEX_PP_TXFILTER 1
+#define TEX_PP_TXFORMAT 2
+#define TEX_PP_TXOFFSET 3
+#define TEX_PP_TXCBLEND 4
+#define TEX_PP_TXABLEND 5
+#define TEX_PP_TFACTOR 6
+#define TEX_CMD_1 7
+#define TEX_PP_BORDER_COLOR 8
+#define TEX_STATE_SIZE 9
+
+#define TXR_CMD_0 0 /* rectangle textures */
+#define TXR_PP_TEX_SIZE 1 /* 0x1d04, 0x1d0c for NPOT! */
+#define TXR_PP_TEX_PITCH 2 /* 0x1d08, 0x1d10 for NPOT! */
+#define TXR_STATE_SIZE 3
+
+#define ZBS_CMD_0 0
+#define ZBS_SE_ZBIAS_FACTOR 1
+#define ZBS_SE_ZBIAS_CONSTANT 2
+#define ZBS_STATE_SIZE 3
+
+#define TCL_CMD_0 0
+#define TCL_OUTPUT_VTXFMT 1
+#define TCL_OUTPUT_VTXSEL 2
+#define TCL_MATRIX_SELECT_0 3
+#define TCL_MATRIX_SELECT_1 4
+#define TCL_UCP_VERT_BLEND_CTL 5
+#define TCL_TEXTURE_PROC_CTL 6
+#define TCL_LIGHT_MODEL_CTL 7
+#define TCL_PER_LIGHT_CTL_0 8
+#define TCL_PER_LIGHT_CTL_1 9
+#define TCL_PER_LIGHT_CTL_2 10
+#define TCL_PER_LIGHT_CTL_3 11
+#define TCL_STATE_SIZE 12
+
+#define MTL_CMD_0 0
+#define MTL_EMMISSIVE_RED 1
+#define MTL_EMMISSIVE_GREEN 2
+#define MTL_EMMISSIVE_BLUE 3
+#define MTL_EMMISSIVE_ALPHA 4
+#define MTL_AMBIENT_RED 5
+#define MTL_AMBIENT_GREEN 6
+#define MTL_AMBIENT_BLUE 7
+#define MTL_AMBIENT_ALPHA 8
+#define MTL_DIFFUSE_RED 9
+#define MTL_DIFFUSE_GREEN 10
+#define MTL_DIFFUSE_BLUE 11
+#define MTL_DIFFUSE_ALPHA 12
+#define MTL_SPECULAR_RED 13
+#define MTL_SPECULAR_GREEN 14
+#define MTL_SPECULAR_BLUE 15
+#define MTL_SPECULAR_ALPHA 16
+#define MTL_SHININESS 17
+#define MTL_STATE_SIZE 18
+
+#define VTX_CMD_0 0
+#define VTX_SE_COORD_FMT 1
+#define VTX_STATE_SIZE 2
+
+#define MAT_CMD_0 0
+#define MAT_ELT_0 1
+#define MAT_STATE_SIZE 17
+
+#define GRD_CMD_0 0
+#define GRD_VERT_GUARD_CLIP_ADJ 1
+#define GRD_VERT_GUARD_DISCARD_ADJ 2
+#define GRD_HORZ_GUARD_CLIP_ADJ 3
+#define GRD_HORZ_GUARD_DISCARD_ADJ 4
+#define GRD_STATE_SIZE 5
+
+/* position changes frequently when lighting in modelpos - separate
+ * out to new state item?
+ */
+#define LIT_CMD_0 0
+#define LIT_AMBIENT_RED 1
+#define LIT_AMBIENT_GREEN 2
+#define LIT_AMBIENT_BLUE 3
+#define LIT_AMBIENT_ALPHA 4
+#define LIT_DIFFUSE_RED 5
+#define LIT_DIFFUSE_GREEN 6
+#define LIT_DIFFUSE_BLUE 7
+#define LIT_DIFFUSE_ALPHA 8
+#define LIT_SPECULAR_RED 9
+#define LIT_SPECULAR_GREEN 10
+#define LIT_SPECULAR_BLUE 11
+#define LIT_SPECULAR_ALPHA 12
+#define LIT_POSITION_X 13
+#define LIT_POSITION_Y 14
+#define LIT_POSITION_Z 15
+#define LIT_POSITION_W 16
+#define LIT_DIRECTION_X 17
+#define LIT_DIRECTION_Y 18
+#define LIT_DIRECTION_Z 19
+#define LIT_DIRECTION_W 20
+#define LIT_ATTEN_CONST 21
+#define LIT_ATTEN_LINEAR 22
+#define LIT_ATTEN_QUADRATIC 23
+#define LIT_ATTEN_XXX 24
+#define LIT_CMD_1 25
+#define LIT_SPOT_DCD 26
+#define LIT_SPOT_EXPONENT 27
+#define LIT_SPOT_CUTOFF 28
+#define LIT_SPECULAR_THRESH 29
+#define LIT_RANGE_CUTOFF 30 /* ? */
+#define LIT_RANGE_ATTEN 31 /* ? */
+#define LIT_STATE_SIZE 32
+
+/* Fog
+ */
+#define FOG_CMD_0 0
+#define FOG_R 1
+#define FOG_C 2
+#define FOG_D 3
+#define FOG_PAD 4
+#define FOG_STATE_SIZE 5
+
+/* UCP
+ */
+#define UCP_CMD_0 0
+#define UCP_X 1
+#define UCP_Y 2
+#define UCP_Z 3
+#define UCP_W 4
+#define UCP_STATE_SIZE 5
+
+/* GLT - Global ambient
+ */
+#define GLT_CMD_0 0
+#define GLT_RED 1
+#define GLT_GREEN 2
+#define GLT_BLUE 3
+#define GLT_ALPHA 4
+#define GLT_STATE_SIZE 5
+
+/* EYE
+ */
+#define EYE_CMD_0 0
+#define EYE_X 1
+#define EYE_Y 2
+#define EYE_Z 3
+#define EYE_RESCALE_FACTOR 4
+#define EYE_STATE_SIZE 5
+
+#define SHN_CMD_0 0
+#define SHN_SHININESS 1
+#define SHN_STATE_SIZE 2
+
+
+
+
+
+struct radeon_hw_state {
+ /* All state should be on one of these lists:
+ */
+ struct radeon_state_atom dirty; /* dirty list head placeholder */
+ struct radeon_state_atom clean; /* clean list head placeholder */
+
+ /* Hardware state, stored as cmdbuf commands:
+ * -- Need to doublebuffer for
+ * - reviving state after loss of context
+ * - eliding noop statechange loops? (except line stipple count)
+ */
+ struct radeon_state_atom ctx;
+ struct radeon_state_atom set;
+ struct radeon_state_atom lin;
+ struct radeon_state_atom msk;
+ struct radeon_state_atom vpt;
+ struct radeon_state_atom tcl;
+ struct radeon_state_atom msc;
+ struct radeon_state_atom tex[2];
+ struct radeon_state_atom zbs;
+ struct radeon_state_atom mtl;
+ struct radeon_state_atom mat[5];
+ struct radeon_state_atom lit[8]; /* includes vec, scl commands */
+ struct radeon_state_atom ucp[6];
+ struct radeon_state_atom eye; /* eye pos */
+ struct radeon_state_atom grd; /* guard band clipping */
+ struct radeon_state_atom fog;
+ struct radeon_state_atom glt;
+ struct radeon_state_atom txr[2]; /* for NPOT */
+};
+
+struct radeon_state {
+ /* Derived state for internal purposes:
+ */
+ struct radeon_colorbuffer_state color;
+ struct radeon_depthbuffer_state depth;
+ struct radeon_pixel_state pixel;
+ struct radeon_scissor_state scissor;
+ struct radeon_stencilbuffer_state stencil;
+ struct radeon_stipple_state stipple;
+ struct radeon_texture_state texture;
+};
+
+
+/* Need refcounting on dma buffers:
+ */
+struct radeon_dma_buffer {
+ int refcount; /* the number of retained regions in buf */
+ drmBufPtr buf;
+};
+
+#define GET_START(rvb) (rmesa->radeonScreen->agp_buffer_offset + \
+ (rvb)->address - rmesa->dma.buf0_address + \
+ (rvb)->start)
+
+/* A retained region, eg vertices for indexed vertices.
+ */
+struct radeon_dma_region {
+ struct radeon_dma_buffer *buf;
+ char *address; /* == buf->address */
+ int start, end, ptr; /* offsets from start of buf */
+ int aos_start;
+ int aos_stride;
+ int aos_size;
+};
+
+
+struct radeon_dma {
+ /* Active dma region. Allocations for vertices and retained
+ * regions come from here. Also used for emitting random vertices,
+ * these may be flushed by calling flush_current();
+ */
+ struct radeon_dma_region current;
+
+ void (*flush)( radeonContextPtr );
+
+ char *buf0_address; /* start of buf[0], for index calcs */
+ GLuint nr_released_bufs; /* flush after so many buffers released */
+};
+
+struct radeon_dri_mirror {
+ __DRIcontextPrivate *context; /* DRI context */
+ __DRIscreenPrivate *screen; /* DRI screen */
+ __DRIdrawablePrivate *drawable; /* DRI drawable bound to this ctx */
+
+ drmContext hwContext;
+ drmLock *hwLock;
+ int fd;
+ int drmMinor;
+};
+
+
+#define RADEON_CMD_BUF_SZ (8*1024)
+
+struct radeon_store {
+ GLuint statenr;
+ GLuint primnr;
+ char cmd_buf[RADEON_CMD_BUF_SZ];
+ int cmd_used;
+ int elts_start;
+};
+
+
+/* radeon_tcl.c
+ */
+struct radeon_tcl_info {
+ GLuint vertex_format;
+ GLint last_offset;
+ GLuint hw_primitive;
+
+ struct radeon_dma_region *aos_components[8];
+ GLuint nr_aos_components;
+
+ GLuint *Elts;
+
+ struct radeon_dma_region indexed_verts;
+ struct radeon_dma_region obj;
+ struct radeon_dma_region rgba;
+ struct radeon_dma_region spec;
+ struct radeon_dma_region fog;
+ struct radeon_dma_region tex[RADEON_MAX_TEXTURE_UNITS];
+ struct radeon_dma_region norm;
+};
+
+
+/* radeon_swtcl.c
+ */
+struct radeon_swtcl_info {
+ GLuint SetupIndex;
+ GLuint SetupNewInputs;
+ GLuint RenderIndex;
+ GLuint vertex_size;
+ GLuint vertex_stride_shift;
+ GLuint vertex_format;
+ GLubyte *verts;
+
+ /* Fallback rasterization functions
+ */
+ radeon_point_func draw_point;
+ radeon_line_func draw_line;
+ radeon_tri_func draw_tri;
+
+ GLuint hw_primitive;
+ GLenum render_primitive;
+ GLuint numverts;
+
+ struct radeon_dma_region indexed_verts;
+};
+
+
+struct radeon_ioctl {
+ GLuint vertex_offset;
+ GLuint vertex_size;
+};
+
+
+
+#define RADEON_MAX_PRIMS 64
+
+
+/* Want to keep a cache of these around. Each is parameterized by
+ * only a single value which has only a small range. Only expect a
+ * few, so just rescan the list each time?
+ */
+struct dynfn {
+ struct dynfn *next, *prev;
+ int key;
+ char *code;
+};
+
+struct dfn_lists {
+ struct dynfn Vertex2f;
+ struct dynfn Vertex2fv;
+ struct dynfn Vertex3f;
+ struct dynfn Vertex3fv;
+ struct dynfn Color4ub;
+ struct dynfn Color4ubv;
+ struct dynfn Color3ub;
+ struct dynfn Color3ubv;
+ struct dynfn Color4f;
+ struct dynfn Color4fv;
+ struct dynfn Color3f;
+ struct dynfn Color3fv;
+ struct dynfn SecondaryColor3ubEXT;
+ struct dynfn SecondaryColor3ubvEXT;
+ struct dynfn SecondaryColor3fEXT;
+ struct dynfn SecondaryColor3fvEXT;
+ struct dynfn Normal3f;
+ struct dynfn Normal3fv;
+ struct dynfn TexCoord2f;
+ struct dynfn TexCoord2fv;
+ struct dynfn TexCoord1f;
+ struct dynfn TexCoord1fv;
+ struct dynfn MultiTexCoord2fARB;
+ struct dynfn MultiTexCoord2fvARB;
+ struct dynfn MultiTexCoord1fARB;
+ struct dynfn MultiTexCoord1fvARB;
+};
+
+struct dfn_generators {
+ struct dynfn *(*Vertex2f)( GLcontext *, int );
+ struct dynfn *(*Vertex2fv)( GLcontext *, int );
+ struct dynfn *(*Vertex3f)( GLcontext *, int );
+ struct dynfn *(*Vertex3fv)( GLcontext *, int );
+ struct dynfn *(*Color4ub)( GLcontext *, int );
+ struct dynfn *(*Color4ubv)( GLcontext *, int );
+ struct dynfn *(*Color3ub)( GLcontext *, int );
+ struct dynfn *(*Color3ubv)( GLcontext *, int );
+ struct dynfn *(*Color4f)( GLcontext *, int );
+ struct dynfn *(*Color4fv)( GLcontext *, int );
+ struct dynfn *(*Color3f)( GLcontext *, int );
+ struct dynfn *(*Color3fv)( GLcontext *, int );
+ struct dynfn *(*SecondaryColor3ubEXT)( GLcontext *, int );
+ struct dynfn *(*SecondaryColor3ubvEXT)( GLcontext *, int );
+ struct dynfn *(*SecondaryColor3fEXT)( GLcontext *, int );
+ struct dynfn *(*SecondaryColor3fvEXT)( GLcontext *, int );
+ struct dynfn *(*Normal3f)( GLcontext *, int );
+ struct dynfn *(*Normal3fv)( GLcontext *, int );
+ struct dynfn *(*TexCoord2f)( GLcontext *, int );
+ struct dynfn *(*TexCoord2fv)( GLcontext *, int );
+ struct dynfn *(*TexCoord1f)( GLcontext *, int );
+ struct dynfn *(*TexCoord1fv)( GLcontext *, int );
+ struct dynfn *(*MultiTexCoord2fARB)( GLcontext *, int );
+ struct dynfn *(*MultiTexCoord2fvARB)( GLcontext *, int );
+ struct dynfn *(*MultiTexCoord1fARB)( GLcontext *, int );
+ struct dynfn *(*MultiTexCoord1fvARB)( GLcontext *, int );
+};
+
+
+
+struct radeon_prim {
+ GLuint start;
+ GLuint end;
+ GLuint prim;
+};
+
+struct radeon_vbinfo {
+ GLint counter, initial_counter;
+ GLint *dmaptr;
+ void (*notify)( void );
+ GLint vertex_size;
+
+ /* A maximum total of 15 elements per vertex: 3 floats for position, 3
+ * floats for normal, 4 floats for color, 4 bytes for secondary color,
+ * 2 floats for each texture unit (4 floats total).
+ *
+ * As soon as the 3rd TMU is supported or cube maps (or 3D textures) are
+ * supported, this value will grow.
+ *
+ * The position data is never actually stored here, so 3 elements could be
+ * trimmed out of the buffer.
+ */
+ union { float f; int i; radeon_color_t color; } vertex[15];
+
+ GLfloat *normalptr;
+ GLfloat *floatcolorptr;
+ radeon_color_t *colorptr;
+ GLfloat *floatspecptr;
+ radeon_color_t *specptr;
+ GLfloat *texcoordptr[2];
+
+ GLenum *prim; /* &ctx->Driver.CurrentExecPrimitive */
+ GLuint primflags;
+ GLboolean enabled; /* *_NO_VTXFMT / *_NO_TCL env vars */
+ GLboolean installed;
+ GLboolean fell_back;
+ GLboolean recheck;
+ GLint nrverts;
+ GLuint vertex_format;
+
+ GLuint installed_vertex_format;
+ GLuint installed_color_3f_sz;
+
+ struct radeon_prim primlist[RADEON_MAX_PRIMS];
+ int nrprims;
+
+ struct dfn_lists dfn_cache;
+ struct dfn_generators codegen;
+ GLvertexformat vtxfmt;
+};
+
+
+
+
+struct radeon_context {
+ GLcontext *glCtx; /* Mesa context */
+
+ /* Driver and hardware state management
+ */
+ struct radeon_hw_state hw;
+ struct radeon_state state;
+
+ /* Texture object bookkeeping
+ */
+ unsigned nr_heaps;
+ driTexHeap * texture_heaps[ RADEON_NR_TEX_HEAPS ];
+ driTextureObject swapped;
+
+
+ /* Rasterization and vertex state:
+ */
+ GLuint TclFallback;
+ GLuint Fallback;
+ GLuint NewGLState;
+
+
+ /* Temporaries for translating away float colors:
+ */
+ struct gl_client_array UbyteColor;
+ struct gl_client_array UbyteSecondaryColor;
+
+ /* Vertex buffers
+ */
+ struct radeon_ioctl ioctl;
+ struct radeon_dma dma;
+ struct radeon_store store;
+
+ /* Page flipping
+ */
+ GLuint doPageFlip;
+
+ /* Busy waiting
+ */
+ GLuint do_usleeps;
+ GLuint do_irqs;
+ GLuint irqsEmitted;
+ drmRadeonIrqWait iw;
+
+ /* Drawable, cliprect and scissor information
+ */
+ GLuint numClipRects; /* Cliprects for the draw buffer */
+ XF86DRIClipRectPtr pClipRects;
+ unsigned int lastStamp;
+ GLboolean lost_context;
+ radeonScreenPtr radeonScreen; /* Screen private DRI data */
+ RADEONSAREAPrivPtr sarea; /* Private SAREA data */
+
+ /* TCL stuff
+ */
+ GLmatrix TexGenMatrix[RADEON_MAX_TEXTURE_UNITS];
+ GLboolean recheck_texgen[RADEON_MAX_TEXTURE_UNITS];
+ GLboolean TexGenNeedNormals[RADEON_MAX_TEXTURE_UNITS];
+ GLuint TexMatEnabled;
+ GLuint TexGenEnabled;
+ GLmatrix tmpmat;
+ GLuint last_ReallyEnabled;
+
+ /* VBI
+ */
+ GLuint vbl_seq;
+ GLuint vblank_flags;
+
+ uint64_t swap_ust;
+ uint64_t swap_missed_ust;
+
+ GLuint swap_count;
+ GLuint swap_missed_count;
+
+ PFNGLXGETUSTPROC get_ust;
+
+ /* radeon_tcl.c
+ */
+ struct radeon_tcl_info tcl;
+
+ /* radeon_swtcl.c
+ */
+ struct radeon_swtcl_info swtcl;
+
+ /* radeon_vtxfmt.c
+ */
+ struct radeon_vbinfo vb;
+
+ /* Mirrors of some DRI state
+ */
+ struct radeon_dri_mirror dri;
+
+
+ /* Performance counters
+ */
+ GLuint boxes; /* Draw performance boxes */
+ GLuint hardwareWentIdle;
+ GLuint c_clears;
+ GLuint c_drawWaits;
+ GLuint c_textureSwaps;
+ GLuint c_textureBytes;
+ GLuint c_vertexBuffers;
+};
+
+#define RADEON_CONTEXT(ctx) ((radeonContextPtr)(ctx->DriverCtx))
+
+
+static __inline GLuint radeonPackColor( GLuint cpp,
+ GLubyte r, GLubyte g,
+ GLubyte b, GLubyte a )
+{
+ switch ( cpp ) {
+ case 2:
+ return PACK_COLOR_565( r, g, b );
+ case 4:
+ return PACK_COLOR_8888( a, r, g, b );
+ default:
+ return 0;
+ }
+}
+
+#define RADEON_OLD_PACKETS 1
+
+
+extern void radeonDestroyContext( __DRIcontextPrivate *driContextPriv );
+extern GLboolean radeonCreateContext(const __GLcontextModes *glVisual,
+ __DRIcontextPrivate *driContextPriv,
+ void *sharedContextPrivate);
+extern void radeonSwapBuffers( __DRIdrawablePrivate *dPriv );
+extern GLboolean radeonMakeCurrent( __DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv );
+extern GLboolean radeonUnbindContext( __DRIcontextPrivate *driContextPriv );
+
+/* ================================================================
+ * Debugging:
+ */
+#define DO_DEBUG 1
+
+#if DO_DEBUG
+extern int RADEON_DEBUG;
+#else
+#define RADEON_DEBUG 0
+#endif
+
+#define DEBUG_TEXTURE 0x001
+#define DEBUG_STATE 0x002
+#define DEBUG_IOCTL 0x004
+#define DEBUG_PRIMS 0x008
+#define DEBUG_VERTS 0x010
+#define DEBUG_FALLBACKS 0x020
+#define DEBUG_VFMT 0x040
+#define DEBUG_CODEGEN 0x080
+#define DEBUG_VERBOSE 0x100
+#define DEBUG_DRI 0x200
+#define DEBUG_DMA 0x400
+#define DEBUG_SANITY 0x800
+
+#endif
+#endif /* __RADEON_CONTEXT_H__ */
diff --git a/src/mesa/drivers/dri/radeon/radeon_ioctl.c b/src/mesa/drivers/dri/radeon/radeon_ioctl.c
new file mode 100644
index 0000000000..a388720aba
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_ioctl.c
@@ -0,0 +1,1191 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c,v 1.11 2003/01/29 22:04:59 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+#include <sched.h>
+#include <errno.h>
+
+#include "glheader.h"
+#include "imports.h"
+#include "simple_list.h"
+#include "swrast/swrast.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_tcl.h"
+#include "radeon_sanity.h"
+
+#include "radeon_macros.h" /* for INREG() */
+
+#include "vblank.h"
+
+#define RADEON_TIMEOUT 512
+#define RADEON_IDLE_RETRY 16
+
+
+static void radeonWaitForIdle( radeonContextPtr rmesa );
+
+/* =============================================================
+ * Kernel command buffer handling
+ */
+
+static void print_state_atom( struct radeon_state_atom *state )
+{
+ int i;
+
+ fprintf(stderr, "emit %s/%d\n", state->name, state->cmd_size);
+
+ if (RADEON_DEBUG & DEBUG_VERBOSE)
+ for (i = 0 ; i < state->cmd_size ; i++)
+ fprintf(stderr, "\t%s[%d]: %x\n", state->name, i, state->cmd[i]);
+
+}
+
+static void radeon_emit_state_list( radeonContextPtr rmesa,
+ struct radeon_state_atom *list )
+{
+ struct radeon_state_atom *state, *tmp;
+ char *dest;
+
+ /* From Felix Kuhling: similar to some other lockups, glaxium will
+ * lock with what we believe to be a normal command stream, but
+ * sprinkling some magic waits arounds allows it to run
+ * uninterrupted. This has a slight effect on q3 framerates, but
+ * it might now be possible to remove the zbs hack, below.
+ *
+ * Felix reports that this can be narrowed down to just
+ * tcl,tex0,tex1 state, but that's pretty much every statechange,
+ * so let's just put the wait in always (unless Felix wants to
+ * narrow it down further...)
+ */
+ if (1) {
+ drmRadeonCmdHeader *cmd;
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, sizeof(*cmd),
+ __FUNCTION__ );
+ cmd->wait.cmd_type = RADEON_CMD_WAIT;
+ cmd->wait.flags = RADEON_WAIT_3D;
+ }
+
+ foreach_s( state, tmp, list ) {
+ if (state->check( rmesa->glCtx )) {
+ dest = radeonAllocCmdBuf( rmesa, state->cmd_size * 4, __FUNCTION__);
+ memcpy( dest, state->cmd, state->cmd_size * 4);
+ move_to_head( &(rmesa->hw.clean), state );
+ if (RADEON_DEBUG & DEBUG_STATE)
+ print_state_atom( state );
+ }
+ else if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "skip state %s\n", state->name);
+ }
+}
+
+
+void radeonEmitState( radeonContextPtr rmesa )
+{
+ struct radeon_state_atom *state, *tmp;
+
+ if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS))
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ /* Somewhat overkill:
+ */
+ if (rmesa->lost_context) {
+ if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS|DEBUG_IOCTL))
+ fprintf(stderr, "%s - lost context\n", __FUNCTION__);
+
+ foreach_s( state, tmp, &(rmesa->hw.clean) )
+ move_to_tail(&(rmesa->hw.dirty), state );
+
+ rmesa->lost_context = 0;
+ }
+ else if (1) {
+ /* This is a darstardly kludge to work around a lockup that I
+ * haven't otherwise figured out.
+ */
+ move_to_tail(&(rmesa->hw.dirty), &(rmesa->hw.zbs) );
+ }
+
+ if (!(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) {
+ foreach_s( state, tmp, &(rmesa->hw.dirty) ) {
+ if (state->is_tcl) {
+ move_to_head( &(rmesa->hw.clean), state );
+ }
+ }
+ }
+
+ radeon_emit_state_list( rmesa, &rmesa->hw.dirty );
+}
+
+
+
+/* Fire a section of the retained (indexed_verts) buffer as a regular
+ * primtive.
+ */
+extern void radeonEmitVbufPrim( radeonContextPtr rmesa,
+ GLuint vertex_format,
+ GLuint primitive,
+ GLuint vertex_nr )
+{
+ drmRadeonCmdHeader *cmd;
+
+
+ assert(rmesa->dri.drmMinor >= 3);
+ assert(!(primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND));
+
+ radeonEmitState( rmesa );
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s cmd_used/4: %d\n", __FUNCTION__,
+ rmesa->store.cmd_used/4);
+
+#if RADEON_OLD_PACKETS
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 6 * sizeof(*cmd),
+ __FUNCTION__ );
+ cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
+ cmd[1].i = RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM | (3 << 16);
+ cmd[2].i = rmesa->ioctl.vertex_offset;
+ cmd[3].i = vertex_nr;
+ cmd[4].i = vertex_format;
+ cmd[5].i = (primitive |
+ RADEON_CP_VC_CNTL_PRIM_WALK_LIST |
+ RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
+ RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE |
+ (vertex_nr << RADEON_CP_VC_CNTL_NUM_SHIFT));
+
+ if (RADEON_DEBUG & DEBUG_PRIMS)
+ fprintf(stderr, "%s: header 0x%x offt 0x%x vfmt 0x%x vfcntl %x \n",
+ __FUNCTION__,
+ cmd[1].i, cmd[2].i, cmd[4].i, cmd[5].i);
+#else
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 4 * sizeof(*cmd),
+ __FUNCTION__ );
+ cmd[0].i = 0;
+ cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
+ cmd[1].i = RADEON_CP_PACKET3_3D_DRAW_VBUF | (1 << 16);
+ cmd[2].i = vertex_format;
+ cmd[3].i = (primitive |
+ RADEON_CP_VC_CNTL_PRIM_WALK_LIST |
+ RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
+ RADEON_CP_VC_CNTL_MAOS_ENABLE |
+ RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE |
+ (vertex_nr << RADEON_CP_VC_CNTL_NUM_SHIFT));
+
+
+ if (RADEON_DEBUG & DEBUG_PRIMS)
+ fprintf(stderr, "%s: header 0x%x vfmt 0x%x vfcntl %x \n",
+ __FUNCTION__,
+ cmd[1].i, cmd[2].i, cmd[3].i);
+#endif
+}
+
+
+void radeonFlushElts( radeonContextPtr rmesa )
+{
+ int *cmd = (int *)(rmesa->store.cmd_buf + rmesa->store.elts_start);
+ int dwords;
+#if RADEON_OLD_PACKETS
+ int nr = (rmesa->store.cmd_used - (rmesa->store.elts_start + 24)) / 2;
+#else
+ int nr = (rmesa->store.cmd_used - (rmesa->store.elts_start + 16)) / 2;
+#endif
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ assert( rmesa->dma.flush == radeonFlushElts );
+ rmesa->dma.flush = 0;
+
+ /* Cope with odd number of elts:
+ */
+ rmesa->store.cmd_used = (rmesa->store.cmd_used + 2) & ~2;
+ dwords = (rmesa->store.cmd_used - rmesa->store.elts_start) / 4;
+
+#if RADEON_OLD_PACKETS
+ cmd[1] |= (dwords - 3) << 16;
+ cmd[5] |= nr << RADEON_CP_VC_CNTL_NUM_SHIFT;
+#else
+ cmd[1] |= (dwords - 3) << 16;
+ cmd[3] |= nr << RADEON_CP_VC_CNTL_NUM_SHIFT;
+#endif
+}
+
+
+GLushort *radeonAllocEltsOpenEnded( radeonContextPtr rmesa,
+ GLuint vertex_format,
+ GLuint primitive,
+ GLuint min_nr )
+{
+ drmRadeonCmdHeader *cmd;
+ GLushort *retval;
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s %d\n", __FUNCTION__, min_nr);
+
+ assert(rmesa->dri.drmMinor >= 3);
+ assert((primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND));
+
+ radeonEmitState( rmesa );
+
+#if RADEON_OLD_PACKETS
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa,
+ 24 + min_nr*2,
+ __FUNCTION__ );
+ cmd[0].i = 0;
+ cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
+ cmd[1].i = RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM;
+ cmd[2].i = rmesa->ioctl.vertex_offset;
+ cmd[3].i = 0xffff;
+ cmd[4].i = vertex_format;
+ cmd[5].i = (primitive |
+ RADEON_CP_VC_CNTL_PRIM_WALK_IND |
+ RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
+ RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE);
+
+ retval = (GLushort *)(cmd+6);
+#else
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa,
+ 16 + min_nr*2,
+ __FUNCTION__ );
+ cmd[0].i = 0;
+ cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
+ cmd[1].i = RADEON_CP_PACKET3_3D_DRAW_INDX;
+ cmd[2].i = vertex_format;
+ cmd[3].i = (primitive |
+ RADEON_CP_VC_CNTL_PRIM_WALK_IND |
+ RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
+ RADEON_CP_VC_CNTL_MAOS_ENABLE |
+ RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE);
+
+ retval = (GLushort *)(cmd+4);
+#endif
+
+ if (RADEON_DEBUG & DEBUG_PRIMS)
+ fprintf(stderr, "%s: header 0x%x vfmt 0x%x prim %x \n",
+ __FUNCTION__,
+ cmd[1].i, vertex_format, primitive);
+
+ assert(!rmesa->dma.flush);
+ rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ rmesa->dma.flush = radeonFlushElts;
+
+ rmesa->store.elts_start = ((char *)cmd) - rmesa->store.cmd_buf;
+
+ return retval;
+}
+
+
+
+void radeonEmitVertexAOS( radeonContextPtr rmesa,
+ GLuint vertex_size,
+ GLuint offset )
+{
+#if RADEON_OLD_PACKETS
+ rmesa->ioctl.vertex_size = vertex_size;
+ rmesa->ioctl.vertex_offset = offset;
+#else
+ drmRadeonCmdHeader *cmd;
+ assert(rmesa->dri.drmMinor >= 3);
+
+ if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_IOCTL))
+ fprintf(stderr, "%s: vertex_size 0x%x offset 0x%x \n",
+ __FUNCTION__, vertex_size, offset);
+
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 5 * sizeof(int),
+ __FUNCTION__ );
+
+ cmd[0].i = 0;
+ cmd[0].header.cmd_type = RADEON_CMD_PACKET3;
+ cmd[1].i = RADEON_CP_PACKET3_3D_LOAD_VBPNTR | (2 << 16);
+ cmd[2].i = 1;
+ cmd[3].i = vertex_size | (vertex_size << 8);
+ cmd[4].i = offset;
+#endif
+}
+
+
+void radeonEmitAOS( radeonContextPtr rmesa,
+ struct radeon_dma_region **component,
+ GLuint nr,
+ GLuint offset )
+{
+#if RADEON_OLD_PACKETS
+ assert( nr == 1 );
+ assert( component[0]->aos_size == component[0]->aos_stride );
+ rmesa->ioctl.vertex_size = component[0]->aos_size;
+ rmesa->ioctl.vertex_offset =
+ (component[0]->aos_start + offset * component[0]->aos_stride * 4);
+#else
+ drmRadeonCmdHeader *cmd;
+ int sz = 3 + (nr/2 * 3) + (nr & 1) * 2;
+ int i;
+ int *tmp;
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ assert(rmesa->dri.drmMinor >= 3);
+
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, sz * sizeof(int),
+ __FUNCTION__ );
+ cmd[0].i = 0;
+ cmd[0].header.cmd_type = RADEON_CMD_PACKET3;
+ cmd[1].i = RADEON_CP_PACKET3_3D_LOAD_VBPNTR | ((sz-3) << 16);
+ cmd[2].i = nr;
+ tmp = &cmd[0].i;
+ cmd += 3;
+
+ for (i = 0 ; i < nr ; i++) {
+ if (i & 1) {
+ cmd[0].i |= ((component[i]->aos_stride << 24) |
+ (component[i]->aos_size << 16));
+ cmd[2].i = (component[i]->aos_start +
+ offset * component[i]->aos_stride * 4);
+ cmd += 3;
+ }
+ else {
+ cmd[0].i = ((component[i]->aos_stride << 8) |
+ (component[i]->aos_size << 0));
+ cmd[1].i = (component[i]->aos_start +
+ offset * component[i]->aos_stride * 4);
+ }
+ }
+
+ if (RADEON_DEBUG & DEBUG_VERTS) {
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ for (i = 0 ; i < sz ; i++)
+ fprintf(stderr, " %d: %x\n", i, tmp[i]);
+ }
+#endif
+}
+
+/* using already shifted color_fmt! */
+void radeonEmitBlit( radeonContextPtr rmesa, /* FIXME: which drmMinor is required? */
+ GLuint color_fmt,
+ GLuint src_pitch,
+ GLuint src_offset,
+ GLuint dst_pitch,
+ GLuint dst_offset,
+ GLint srcx, GLint srcy,
+ GLint dstx, GLint dsty,
+ GLuint w, GLuint h )
+{
+ drmRadeonCmdHeader *cmd;
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s src %x/%x %d,%d dst: %x/%x %d,%d sz: %dx%d\n",
+ __FUNCTION__,
+ src_pitch, src_offset, srcx, srcy,
+ dst_pitch, dst_offset, dstx, dsty,
+ w, h);
+
+ assert( (src_pitch & 63) == 0 );
+ assert( (dst_pitch & 63) == 0 );
+ assert( (src_offset & 1023) == 0 );
+ assert( (dst_offset & 1023) == 0 );
+ assert( w < (1<<16) );
+ assert( h < (1<<16) );
+
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 8 * sizeof(int),
+ __FUNCTION__ );
+
+
+ cmd[0].i = 0;
+ cmd[0].header.cmd_type = RADEON_CMD_PACKET3;
+ cmd[1].i = RADEON_CP_PACKET3_CNTL_BITBLT_MULTI | (5 << 16);
+ cmd[2].i = (RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+ RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+ RADEON_GMC_BRUSH_NONE |
+ color_fmt |
+ RADEON_GMC_SRC_DATATYPE_COLOR |
+ RADEON_ROP3_S |
+ RADEON_DP_SRC_SOURCE_MEMORY |
+ RADEON_GMC_CLR_CMP_CNTL_DIS |
+ RADEON_GMC_WR_MSK_DIS );
+
+ cmd[3].i = ((src_pitch/64)<<22) | (src_offset >> 10);
+ cmd[4].i = ((dst_pitch/64)<<22) | (dst_offset >> 10);
+ cmd[5].i = (srcx << 16) | srcy;
+ cmd[6].i = (dstx << 16) | dsty; /* dst */
+ cmd[7].i = (w << 16) | h;
+}
+
+
+void radeonEmitWait( radeonContextPtr rmesa, GLuint flags )
+{
+ if (rmesa->dri.drmMinor >= 6) {
+ drmRadeonCmdHeader *cmd;
+
+ assert( !(flags & ~(RADEON_WAIT_2D|RADEON_WAIT_3D)) );
+
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 1 * sizeof(int),
+ __FUNCTION__ );
+ cmd[0].i = 0;
+ cmd[0].wait.cmd_type = RADEON_CMD_WAIT;
+ cmd[0].wait.flags = flags;
+ }
+}
+
+
+static int radeonFlushCmdBufLocked( radeonContextPtr rmesa,
+ const char * caller )
+{
+ int ret, i;
+ drmRadeonCmdBuffer cmd;
+
+ if (RADEON_DEBUG & DEBUG_IOCTL) {
+ fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
+
+ if (RADEON_DEBUG & DEBUG_VERBOSE)
+ for (i = 0 ; i < rmesa->store.cmd_used ; i += 4 )
+ fprintf(stderr, "%d: %x\n", i/4,
+ *(int *)(&rmesa->store.cmd_buf[i]));
+ }
+
+ if (RADEON_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "%s: Releasing %d buffers\n", __FUNCTION__,
+ rmesa->dma.nr_released_bufs);
+
+
+ if (RADEON_DEBUG & DEBUG_SANITY) {
+ if (rmesa->state.scissor.enabled)
+ ret = radeonSanityCmdBuffer( rmesa,
+ rmesa->state.scissor.numClipRects,
+ rmesa->state.scissor.pClipRects);
+ else
+ ret = radeonSanityCmdBuffer( rmesa,
+ rmesa->numClipRects,
+ rmesa->pClipRects);
+ if (ret) {
+ fprintf(stderr, "drmSanityCommandWrite: %d\n", ret);
+ goto out;
+ }
+ }
+
+
+ cmd.bufsz = rmesa->store.cmd_used;
+ cmd.buf = rmesa->store.cmd_buf;
+
+ if (rmesa->state.scissor.enabled) {
+ cmd.nbox = rmesa->state.scissor.numClipRects;
+ cmd.boxes = (drmClipRect *)rmesa->state.scissor.pClipRects;
+ } else {
+ cmd.nbox = rmesa->numClipRects;
+ cmd.boxes = (drmClipRect *)rmesa->pClipRects;
+ }
+
+ ret = drmCommandWrite( rmesa->dri.fd,
+ DRM_RADEON_CMDBUF,
+ &cmd, sizeof(cmd) );
+
+ if (ret)
+ fprintf(stderr, "drmCommandWrite: %d\n", ret);
+
+ out:
+ rmesa->store.primnr = 0;
+ rmesa->store.statenr = 0;
+ rmesa->store.cmd_used = 0;
+ rmesa->dma.nr_released_bufs = 0;
+ rmesa->lost_context = 1;
+ return ret;
+}
+
+
+/* Note: does not emit any commands to avoid recursion on
+ * radeonAllocCmdBuf.
+ */
+void radeonFlushCmdBuf( radeonContextPtr rmesa, const char *caller )
+{
+ int ret;
+
+
+ assert (rmesa->dri.drmMinor >= 3);
+
+ LOCK_HARDWARE( rmesa );
+
+ ret = radeonFlushCmdBufLocked( rmesa, caller );
+
+ UNLOCK_HARDWARE( rmesa );
+
+ if (ret) {
+ fprintf(stderr, "drmRadeonCmdBuffer: %d (exiting)\n", ret);
+ exit(ret);
+ }
+}
+
+/* =============================================================
+ * Hardware vertex buffer handling
+ */
+
+
+void radeonRefillCurrentDmaRegion( radeonContextPtr rmesa )
+{
+ struct radeon_dma_buffer *dmabuf;
+ int fd = rmesa->dri.fd;
+ int index = 0;
+ int size = 0;
+ drmDMAReq dma;
+ int ret;
+
+ if (RADEON_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (rmesa->dma.flush) {
+ rmesa->dma.flush( rmesa );
+ }
+
+ if (rmesa->dma.current.buf)
+ radeonReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ );
+
+ if (rmesa->dma.nr_released_bufs > 4)
+ radeonFlushCmdBuf( rmesa, __FUNCTION__ );
+
+ dma.context = rmesa->dri.hwContext;
+ dma.send_count = 0;
+ dma.send_list = NULL;
+ dma.send_sizes = NULL;
+ dma.flags = 0;
+ dma.request_count = 1;
+ dma.request_size = RADEON_BUFFER_SIZE;
+ dma.request_list = &index;
+ dma.request_sizes = &size;
+ dma.granted_count = 0;
+
+ LOCK_HARDWARE(rmesa); /* no need to validate */
+
+ ret = drmDMA( fd, &dma );
+
+ if (ret != 0) {
+ /* Free some up this way?
+ */
+ if (rmesa->dma.nr_released_bufs) {
+ radeonFlushCmdBufLocked( rmesa, __FUNCTION__ );
+ }
+
+ if (RADEON_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "Waiting for buffers\n");
+
+ radeonWaitForIdleLocked( rmesa );
+ ret = drmDMA( fd, &dma );
+
+ if ( ret != 0 ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "Error: Could not get dma buffer... exiting\n" );
+ exit( -1 );
+ }
+ }
+
+ UNLOCK_HARDWARE(rmesa);
+
+ if (RADEON_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "Allocated buffer %d\n", index);
+
+ dmabuf = CALLOC_STRUCT( radeon_dma_buffer );
+ dmabuf->buf = &rmesa->radeonScreen->buffers->list[index];
+ dmabuf->refcount = 1;
+
+ rmesa->dma.current.buf = dmabuf;
+ rmesa->dma.current.address = dmabuf->buf->address;
+ rmesa->dma.current.end = dmabuf->buf->total;
+ rmesa->dma.current.start = 0;
+ rmesa->dma.current.ptr = 0;
+
+ rmesa->c_vertexBuffers++;
+}
+
+void radeonReleaseDmaRegion( radeonContextPtr rmesa,
+ struct radeon_dma_region *region,
+ const char *caller )
+{
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
+
+ if (!region->buf)
+ return;
+
+ if (rmesa->dma.flush)
+ rmesa->dma.flush( rmesa );
+
+ if (--region->buf->refcount == 0) {
+ drmRadeonCmdHeader *cmd;
+
+ if (RADEON_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
+ fprintf(stderr, "%s -- DISCARD BUF %d\n", __FUNCTION__,
+ region->buf->buf->idx);
+
+ cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, sizeof(*cmd),
+ __FUNCTION__ );
+ cmd->dma.cmd_type = RADEON_CMD_DMA_DISCARD;
+ cmd->dma.buf_idx = region->buf->buf->idx;
+ FREE(region->buf);
+ rmesa->dma.nr_released_bufs++;
+ }
+
+ region->buf = 0;
+ region->start = 0;
+}
+
+/* Allocates a region from rmesa->dma.current. If there isn't enough
+ * space in current, grab a new buffer (and discard what was left of current)
+ */
+void radeonAllocDmaRegion( radeonContextPtr rmesa,
+ struct radeon_dma_region *region,
+ int bytes,
+ int alignment )
+{
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s %d\n", __FUNCTION__, bytes);
+
+ if (rmesa->dma.flush)
+ rmesa->dma.flush( rmesa );
+
+ if (region->buf)
+ radeonReleaseDmaRegion( rmesa, region, __FUNCTION__ );
+
+ alignment--;
+ rmesa->dma.current.start = rmesa->dma.current.ptr =
+ (rmesa->dma.current.ptr + alignment) & ~alignment;
+
+ if ( rmesa->dma.current.ptr + bytes > rmesa->dma.current.end )
+ radeonRefillCurrentDmaRegion( rmesa );
+
+ region->start = rmesa->dma.current.start;
+ region->ptr = rmesa->dma.current.start;
+ region->end = rmesa->dma.current.start + bytes;
+ region->address = rmesa->dma.current.address;
+ region->buf = rmesa->dma.current.buf;
+ region->buf->refcount++;
+
+ rmesa->dma.current.ptr += bytes; /* bug - if alignment > 7 */
+ rmesa->dma.current.start =
+ rmesa->dma.current.ptr = (rmesa->dma.current.ptr + 0x7) & ~0x7;
+
+ if ( rmesa->dri.drmMinor < 3 )
+ radeonRefillCurrentDmaRegion( rmesa );
+}
+
+void radeonAllocDmaRegionVerts( radeonContextPtr rmesa,
+ struct radeon_dma_region *region,
+ int numverts,
+ int vertsize,
+ int alignment )
+{
+ radeonAllocDmaRegion( rmesa, region, vertsize * numverts, alignment );
+}
+
+/* ================================================================
+ * SwapBuffers with client-side throttling
+ */
+
+static CARD32 radeonGetLastFrame (radeonContextPtr rmesa)
+{
+ unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map;
+ int ret;
+ CARD32 frame;
+
+ if (rmesa->dri.screen->drmMinor >= 4) {
+ drmRadeonGetParam gp;
+
+ gp.param = RADEON_PARAM_LAST_FRAME;
+ gp.value = &frame;
+ ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_GETPARAM,
+ &gp, sizeof(gp) );
+ }
+ else
+ ret = -EINVAL;
+
+#ifndef __alpha__
+ if ( ret == -EINVAL ) {
+ frame = INREG( RADEON_LAST_FRAME_REG );
+ ret = 0;
+ }
+#endif
+ if ( ret ) {
+ fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
+ exit(1);
+ }
+
+ return frame;
+}
+
+static void radeonEmitIrqLocked( radeonContextPtr rmesa )
+{
+ drmRadeonIrqEmit ie;
+ int ret;
+
+ ie.irq_seq = &rmesa->iw.irq_seq;
+ ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_IRQ_EMIT,
+ &ie, sizeof(ie) );
+ if ( ret ) {
+ fprintf( stderr, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__, ret );
+ exit(1);
+ }
+}
+
+
+static void radeonWaitIrq( radeonContextPtr rmesa )
+{
+ int ret;
+
+ do {
+ ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_IRQ_WAIT,
+ &rmesa->iw, sizeof(rmesa->iw) );
+ } while (ret && (errno == EINTR || errno == EAGAIN));
+
+ if ( ret ) {
+ fprintf( stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__, ret );
+ exit(1);
+ }
+}
+
+
+static void radeonWaitForFrameCompletion( radeonContextPtr rmesa )
+{
+ RADEONSAREAPrivPtr sarea = rmesa->sarea;
+
+ if (rmesa->do_irqs) {
+ if (radeonGetLastFrame(rmesa) < sarea->last_frame) {
+ if (!rmesa->irqsEmitted) {
+ while (radeonGetLastFrame (rmesa) < sarea->last_frame)
+ ;
+ }
+ else {
+ UNLOCK_HARDWARE( rmesa );
+ radeonWaitIrq( rmesa );
+ LOCK_HARDWARE( rmesa );
+ }
+ rmesa->irqsEmitted = 10;
+ }
+
+ if (rmesa->irqsEmitted) {
+ radeonEmitIrqLocked( rmesa );
+ rmesa->irqsEmitted--;
+ }
+ }
+ else {
+ while (radeonGetLastFrame (rmesa) < sarea->last_frame) {
+ UNLOCK_HARDWARE( rmesa );
+ if (rmesa->do_usleeps)
+ DO_USLEEP( 1 );
+ LOCK_HARDWARE( rmesa );
+ }
+ }
+}
+
+/* Copy the back color buffer to the front color buffer.
+ */
+void radeonCopyBuffer( const __DRIdrawablePrivate *dPriv )
+{
+ radeonContextPtr rmesa;
+ GLint nbox, i, ret;
+ GLboolean missed_target;
+ uint64_t ust;
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
+
+ if ( RADEON_DEBUG & DEBUG_IOCTL ) {
+ fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, rmesa->glCtx );
+ }
+
+ RADEON_FIREVERTICES( rmesa );
+ LOCK_HARDWARE( rmesa );
+
+ /* Throttle the frame rate -- only allow one pending swap buffers
+ * request at a time.
+ */
+ radeonWaitForFrameCompletion( rmesa );
+ UNLOCK_HARDWARE( rmesa );
+ driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
+ LOCK_HARDWARE( rmesa );
+
+ nbox = dPriv->numClipRects; /* must be in locked region */
+
+ for ( i = 0 ; i < nbox ; ) {
+ GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox );
+ XF86DRIClipRectPtr box = dPriv->pClipRects;
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+ GLint n = 0;
+
+ for ( ; i < nr ; i++ ) {
+ *b++ = box[i];
+ n++;
+ }
+ rmesa->sarea->nbox = n;
+
+ ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_SWAP );
+
+ if ( ret ) {
+ fprintf( stderr, "DRM_RADEON_SWAP_BUFFERS: return = %d\n", ret );
+ UNLOCK_HARDWARE( rmesa );
+ exit( 1 );
+ }
+ }
+
+ UNLOCK_HARDWARE( rmesa );
+ rmesa->swap_count++;
+ (*rmesa->get_ust)( & ust );
+ if ( missed_target ) {
+ rmesa->swap_missed_count++;
+ rmesa->swap_missed_ust = ust - rmesa->swap_ust;
+ }
+
+ rmesa->swap_ust = ust;
+}
+
+void radeonPageFlip( const __DRIdrawablePrivate *dPriv )
+{
+ radeonContextPtr rmesa;
+ GLint ret;
+ GLboolean missed_target;
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
+
+ if ( RADEON_DEBUG & DEBUG_IOCTL ) {
+ fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
+ rmesa->sarea->pfCurrentPage);
+ }
+
+ RADEON_FIREVERTICES( rmesa );
+ LOCK_HARDWARE( rmesa );
+
+ /* Need to do this for the perf box placement:
+ */
+ if (dPriv->numClipRects)
+ {
+ XF86DRIClipRectPtr box = dPriv->pClipRects;
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+ b[0] = box[0];
+ rmesa->sarea->nbox = 1;
+ }
+
+ /* Throttle the frame rate -- only allow a few pending swap buffers
+ * request at a time.
+ */
+ radeonWaitForFrameCompletion( rmesa );
+ UNLOCK_HARDWARE( rmesa );
+ driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
+ if ( missed_target ) {
+ rmesa->swap_missed_count++;
+ (void) (*rmesa->get_ust)( & rmesa->swap_missed_ust );
+ }
+ LOCK_HARDWARE( rmesa );
+
+ ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_FLIP );
+
+ UNLOCK_HARDWARE( rmesa );
+
+ if ( ret ) {
+ fprintf( stderr, "DRM_RADEON_FLIP: return = %d\n", ret );
+ exit( 1 );
+ }
+
+ rmesa->swap_count++;
+ (void) (*rmesa->get_ust)( & rmesa->swap_ust );
+
+ if ( rmesa->sarea->pfCurrentPage == 1 ) {
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch;
+ } else {
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch;
+ }
+
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset;
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch;
+}
+
+
+/* ================================================================
+ * Buffer clear
+ */
+#define RADEON_MAX_CLEARS 256
+
+static void radeonClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
+ GLint cx, GLint cy, GLint cw, GLint ch )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
+ RADEONSAREAPrivPtr sarea = rmesa->sarea;
+ unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map;
+ CARD32 clear;
+ GLuint flags = 0;
+ GLuint color_mask = 0;
+ GLint ret, i;
+
+ if ( RADEON_DEBUG & DEBUG_IOCTL ) {
+ fprintf( stderr, "%s: all=%d cx=%d cy=%d cw=%d ch=%d\n",
+ __FUNCTION__, all, cx, cy, cw, ch );
+ }
+
+ radeonEmitState( rmesa );
+
+ /* Need to cope with lostcontext here as kernel relies on
+ * some residual state:
+ */
+ RADEON_FIREVERTICES( rmesa );
+
+ if ( mask & DD_FRONT_LEFT_BIT ) {
+ flags |= RADEON_FRONT;
+ color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
+ mask &= ~DD_FRONT_LEFT_BIT;
+ }
+
+ if ( mask & DD_BACK_LEFT_BIT ) {
+ flags |= RADEON_BACK;
+ color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
+ mask &= ~DD_BACK_LEFT_BIT;
+ }
+
+ if ( mask & DD_DEPTH_BIT ) {
+ if ( ctx->Depth.Mask ) flags |= RADEON_DEPTH; /* FIXME: ??? */
+ mask &= ~DD_DEPTH_BIT;
+ }
+
+ if ( (mask & DD_STENCIL_BIT) && rmesa->state.stencil.hwBuffer ) {
+ flags |= RADEON_STENCIL;
+ mask &= ~DD_STENCIL_BIT;
+ }
+
+ if ( mask ) {
+ if (RADEON_DEBUG & DEBUG_FALLBACKS)
+ fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
+ _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
+ }
+
+ if ( !flags )
+ return;
+
+
+ /* Flip top to bottom */
+ cx += dPriv->x;
+ cy = dPriv->y + dPriv->h - cy - ch;
+
+ LOCK_HARDWARE( rmesa );
+
+ /* Throttle the number of clear ioctls we do.
+ */
+ while ( 1 ) {
+ int ret;
+
+ if (rmesa->dri.screen->drmMinor >= 4) {
+ drmRadeonGetParam gp;
+
+ gp.param = RADEON_PARAM_LAST_CLEAR;
+ gp.value = &clear;
+ ret = drmCommandWriteRead( rmesa->dri.fd,
+ DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
+ } else
+ ret = -EINVAL;
+
+#ifndef __alpha__
+ if ( ret == -EINVAL ) {
+ clear = INREG( RADEON_LAST_CLEAR_REG );
+ ret = 0;
+ }
+#endif
+ if ( ret ) {
+ fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
+ exit(1);
+ }
+ if ( RADEON_DEBUG & DEBUG_IOCTL ) {
+ fprintf( stderr, "%s( %d )\n", __FUNCTION__, (int)clear );
+ if ( ret ) fprintf( stderr, " ( RADEON_LAST_CLEAR register read directly )\n" );
+ }
+
+ if ( sarea->last_clear - clear <= RADEON_MAX_CLEARS ) {
+ break;
+ }
+
+ if ( rmesa->do_usleeps ) {
+ UNLOCK_HARDWARE( rmesa );
+ DO_USLEEP( 1 );
+ LOCK_HARDWARE( rmesa );
+ }
+ }
+
+ for ( i = 0 ; i < dPriv->numClipRects ; ) {
+ GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects );
+ XF86DRIClipRectPtr box = dPriv->pClipRects;
+ XF86DRIClipRectPtr b = rmesa->sarea->boxes;
+ drmRadeonClearType clear;
+ drmRadeonClearRect depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
+ GLint n = 0;
+
+ if ( !all ) {
+ for ( ; i < nr ; i++ ) {
+ GLint x = box[i].x1;
+ GLint y = box[i].y1;
+ GLint w = box[i].x2 - x;
+ GLint h = box[i].y2 - y;
+
+ if ( x < cx ) w -= cx - x, x = cx;
+ if ( y < cy ) h -= cy - y, y = cy;
+ if ( x + w > cx + cw ) w = cx + cw - x;
+ if ( y + h > cy + ch ) h = cy + ch - y;
+ if ( w <= 0 ) continue;
+ if ( h <= 0 ) continue;
+
+ b->x1 = x;
+ b->y1 = y;
+ b->x2 = x + w;
+ b->y2 = y + h;
+ b++;
+ n++;
+ }
+ } else {
+ for ( ; i < nr ; i++ ) {
+ *b++ = box[i];
+ n++;
+ }
+ }
+
+ rmesa->sarea->nbox = n;
+
+ clear.flags = flags;
+ clear.clear_color = rmesa->state.color.clear;
+ clear.clear_depth = rmesa->state.depth.clear;
+ clear.color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
+ clear.depth_mask = rmesa->state.stencil.clear;
+ clear.depth_boxes = depth_boxes;
+
+ n--;
+ b = rmesa->sarea->boxes;
+ for ( ; n >= 0 ; n-- ) {
+ depth_boxes[n].f[RADEON_CLEAR_X1] = (float)b[n].x1;
+ depth_boxes[n].f[RADEON_CLEAR_Y1] = (float)b[n].y1;
+ depth_boxes[n].f[RADEON_CLEAR_X2] = (float)b[n].x2;
+ depth_boxes[n].f[RADEON_CLEAR_Y2] = (float)b[n].y2;
+ depth_boxes[n].f[RADEON_CLEAR_DEPTH] =
+ (float)rmesa->state.depth.clear;
+ }
+
+ ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_CLEAR,
+ &clear, sizeof(drmRadeonClearType));
+
+ if ( ret ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret );
+ exit( 1 );
+ }
+ }
+
+ UNLOCK_HARDWARE( rmesa );
+}
+
+
+void radeonWaitForIdleLocked( radeonContextPtr rmesa )
+{
+ int fd = rmesa->dri.fd;
+ int to = 0;
+ int ret, i = 0;
+
+ rmesa->c_drawWaits++;
+
+ do {
+ do {
+ ret = drmCommandNone( fd, DRM_RADEON_CP_IDLE);
+ } while ( ret && errno == EBUSY && i++ < RADEON_IDLE_RETRY );
+ } while ( ( ret == -EBUSY ) && ( to++ < RADEON_TIMEOUT ) );
+
+ if ( ret < 0 ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "Error: Radeon timed out... exiting\n" );
+ exit( -1 );
+ }
+}
+
+
+static void radeonWaitForIdle( radeonContextPtr rmesa )
+{
+ LOCK_HARDWARE(rmesa);
+ radeonWaitForIdleLocked( rmesa );
+ UNLOCK_HARDWARE(rmesa);
+}
+
+
+void radeonFlush( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (rmesa->dma.flush)
+ rmesa->dma.flush( rmesa );
+
+ if (rmesa->dri.drmMinor >= 3) {
+ if (!is_empty_list(&rmesa->hw.dirty))
+ radeonEmitState( rmesa );
+
+ if (rmesa->store.cmd_used)
+ radeonFlushCmdBuf( rmesa, __FUNCTION__ );
+ }
+}
+
+/* Make sure all commands have been sent to the hardware and have
+ * completed processing.
+ */
+void radeonFinish( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeonFlush( ctx );
+
+ if (rmesa->do_irqs) {
+ LOCK_HARDWARE( rmesa );
+ radeonEmitIrqLocked( rmesa );
+ UNLOCK_HARDWARE( rmesa );
+ radeonWaitIrq( rmesa );
+ }
+ else
+ radeonWaitForIdle( rmesa );
+}
+
+
+void radeonInitIoctlFuncs( GLcontext *ctx )
+{
+ ctx->Driver.Clear = radeonClear;
+ ctx->Driver.Finish = radeonFinish;
+ ctx->Driver.Flush = radeonFlush;
+}
+
diff --git a/src/mesa/drivers/dri/radeon/radeon_ioctl.h b/src/mesa/drivers/dri/radeon/radeon_ioctl.h
new file mode 100644
index 0000000000..3f6e1751cf
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_ioctl.h
@@ -0,0 +1,188 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.h,v 1.6 2002/12/16 16:18:58 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __RADEON_IOCTL_H__
+#define __RADEON_IOCTL_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "simple_list.h"
+#include "radeon_lock.h"
+
+
+extern void radeonEmitState( radeonContextPtr rmesa );
+extern void radeonEmitVertexAOS( radeonContextPtr rmesa,
+ GLuint vertex_size,
+ GLuint offset );
+
+extern void radeonEmitVbufPrim( radeonContextPtr rmesa,
+ GLuint vertex_format,
+ GLuint primitive,
+ GLuint vertex_nr );
+
+extern void radeonFlushElts( radeonContextPtr rmesa );
+
+extern GLushort *radeonAllocEltsOpenEnded( radeonContextPtr rmesa,
+ GLuint vertex_format,
+ GLuint primitive,
+ GLuint min_nr );
+
+extern void radeonEmitAOS( radeonContextPtr rmesa,
+ struct radeon_dma_region **regions,
+ GLuint n,
+ GLuint offset );
+
+extern void radeonEmitBlit( radeonContextPtr rmesa,
+ GLuint color_fmt,
+ GLuint src_pitch,
+ GLuint src_offset,
+ GLuint dst_pitch,
+ GLuint dst_offset,
+ GLint srcx, GLint srcy,
+ GLint dstx, GLint dsty,
+ GLuint w, GLuint h );
+
+extern void radeonEmitWait( radeonContextPtr rmesa, GLuint flags );
+
+extern void radeonFlushCmdBuf( radeonContextPtr rmesa, const char * );
+extern void radeonRefillCurrentDmaRegion( radeonContextPtr rmesa );
+
+extern void radeonAllocDmaRegion( radeonContextPtr rmesa,
+ struct radeon_dma_region *region,
+ int bytes,
+ int alignment );
+
+extern void radeonAllocDmaRegionVerts( radeonContextPtr rmesa,
+ struct radeon_dma_region *region,
+ int numverts,
+ int vertsize,
+ int alignment );
+
+extern void radeonReleaseDmaRegion( radeonContextPtr rmesa,
+ struct radeon_dma_region *region,
+ const char *caller );
+
+extern void radeonCopyBuffer( const __DRIdrawablePrivate *drawable );
+extern void radeonPageFlip( const __DRIdrawablePrivate *drawable );
+extern void radeonFlush( GLcontext *ctx );
+extern void radeonFinish( GLcontext *ctx );
+extern void radeonWaitForIdleLocked( radeonContextPtr rmesa );
+extern void radeonWaitForVBlank( radeonContextPtr rmesa );
+extern void radeonInitIoctlFuncs( GLcontext *ctx );
+extern void radeonGetAllParams( radeonContextPtr rmesa );
+
+/* radeon_compat.c:
+ */
+extern void radeonCompatEmitPrimitive( radeonContextPtr rmesa,
+ GLuint vertex_format,
+ GLuint hw_primitive,
+ GLuint nrverts );
+
+
+/* ================================================================
+ * Helper macros:
+ */
+
+/* Close off the last primitive, if it exists.
+ */
+#define RADEON_NEWPRIM( rmesa ) \
+do { \
+ if ( rmesa->dma.flush ) \
+ rmesa->dma.flush( rmesa ); \
+} while (0)
+
+/* Can accomodate several state changes and primitive changes without
+ * actually firing the buffer.
+ */
+#define RADEON_STATECHANGE( rmesa, ATOM ) \
+do { \
+ RADEON_NEWPRIM( rmesa ); \
+ move_to_head( &(rmesa->hw.dirty), &(rmesa->hw.ATOM)); \
+} while (0)
+
+#define RADEON_DB_STATE( ATOM ) \
+ memcpy( rmesa->hw.ATOM.lastcmd, rmesa->hw.ATOM.cmd, \
+ rmesa->hw.ATOM.cmd_size * 4)
+
+static __inline int RADEON_DB_STATECHANGE(
+ radeonContextPtr rmesa,
+ struct radeon_state_atom *atom )
+{
+ if (memcmp(atom->cmd, atom->lastcmd, atom->cmd_size*4)) {
+ int *tmp;
+ RADEON_NEWPRIM( rmesa );
+ move_to_head( &(rmesa->hw.dirty), atom );
+ tmp = atom->cmd;
+ atom->cmd = atom->lastcmd;
+ atom->lastcmd = tmp;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+/* Fire the buffered vertices no matter what.
+ */
+#define RADEON_FIREVERTICES( rmesa ) \
+do { \
+ if ( rmesa->store.cmd_used || rmesa->dma.flush ) { \
+ radeonFlush( rmesa->glCtx ); \
+ } \
+} while (0)
+
+/* Alloc space in the command buffer
+ */
+static __inline char *radeonAllocCmdBuf( radeonContextPtr rmesa,
+ int bytes, const char *where )
+{
+ if (rmesa->store.cmd_used + bytes > RADEON_CMD_BUF_SZ)
+ radeonFlushCmdBuf( rmesa, __FUNCTION__ );
+
+ assert(rmesa->dri.drmMinor >= 3);
+
+ {
+ char *head = rmesa->store.cmd_buf + rmesa->store.cmd_used;
+ rmesa->store.cmd_used += bytes;
+ return head;
+ }
+}
+
+
+
+
+#endif
+#endif /* __RADEON_IOCTL_H__ */
diff --git a/src/mesa/drivers/dri/radeon/radeon_lighting.c b/src/mesa/drivers/dri/radeon/radeon_lighting.c
new file mode 100644
index 0000000000..b00c9cb6de
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_lighting.c
@@ -0,0 +1,682 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.c,v 1.5 2002/09/16 18:05:20 eich Exp $ */
+/*
+ * Copyright 2000, 2001 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "api_arrayelt.h"
+/* #include "mmath.h" */
+#include "enums.h"
+#include "colormac.h"
+
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_tcl.h"
+#include "radeon_tex.h"
+#include "radeon_vtxfmt.h"
+
+
+
+/* =============================================================
+ * Materials
+ */
+
+
+/* Update on colormaterial, material emmissive/ambient,
+ * lightmodel.globalambient
+ */
+void update_global_ambient( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ float *fcmd = (float *)RADEON_DB_STATE( glt );
+
+ /* Need to do more if both emmissive & ambient are PREMULT:
+ */
+ if ((rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &
+ ((3 << RADEON_EMISSIVE_SOURCE_SHIFT) |
+ (3 << RADEON_AMBIENT_SOURCE_SHIFT))) == 0)
+ {
+ COPY_3V( &fcmd[GLT_RED],
+ ctx->Light.Material[0].Emission);
+ ACC_SCALE_3V( &fcmd[GLT_RED],
+ ctx->Light.Model.Ambient,
+ ctx->Light.Material[0].Ambient);
+ }
+ else
+ {
+ COPY_3V( &fcmd[GLT_RED], ctx->Light.Model.Ambient );
+ }
+
+ RADEON_DB_STATECHANGE(rmesa, &rmesa->hw.glt);
+}
+
+/* Update on change to
+ * - light[p].colors
+ * - light[p].enabled
+ * - material,
+ * - colormaterial enabled
+ * - colormaterial bitmask
+ */
+void update_light_colors( GLcontext *ctx, GLuint p )
+{
+ struct gl_light *l = &ctx->Light.Light[p];
+
+/* fprintf(stderr, "%s\n", __FUNCTION__); */
+
+ if (l->Enabled) {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ float *fcmd = (float *)RADEON_DB_STATE( lit[p] );
+ GLuint bitmask = ctx->Light.ColorMaterialBitmask;
+ struct gl_material *mat = &ctx->Light.Material[0];
+
+ COPY_4V( &fcmd[LIT_AMBIENT_RED], l->Ambient );
+ COPY_4V( &fcmd[LIT_DIFFUSE_RED], l->Diffuse );
+ COPY_4V( &fcmd[LIT_SPECULAR_RED], l->Specular );
+
+ if (!ctx->Light.ColorMaterialEnabled)
+ bitmask = 0;
+
+ if ((bitmask & FRONT_AMBIENT_BIT) == 0)
+ SELF_SCALE_3V( &fcmd[LIT_AMBIENT_RED], mat->Ambient );
+
+ if ((bitmask & FRONT_DIFFUSE_BIT) == 0)
+ SELF_SCALE_3V( &fcmd[LIT_DIFFUSE_RED], mat->Diffuse );
+
+ if ((bitmask & FRONT_SPECULAR_BIT) == 0)
+ SELF_SCALE_3V( &fcmd[LIT_SPECULAR_RED], mat->Specular );
+
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] );
+ }
+}
+
+/* Also fallback for asym colormaterial mode in twoside lighting...
+ */
+void check_twoside_fallback( GLcontext *ctx )
+{
+ GLboolean fallback = GL_FALSE;
+
+ if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) {
+ if (memcmp( &ctx->Light.Material[0],
+ &ctx->Light.Material[1],
+ sizeof(struct gl_material)) != 0)
+ fallback = GL_TRUE;
+ else if (ctx->Light.ColorMaterialEnabled &&
+ (ctx->Light.ColorMaterialBitmask & BACK_MATERIAL_BITS) !=
+ ((ctx->Light.ColorMaterialBitmask & FRONT_MATERIAL_BITS)<<1))
+ fallback = GL_TRUE;
+ }
+
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_LIGHT_TWOSIDE, fallback );
+}
+
+void radeonColorMaterial( GLcontext *ctx, GLenum face, GLenum mode )
+{
+ if (ctx->Light.ColorMaterialEnabled) {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint light_model_ctl = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL];
+ GLuint mask = ctx->Light.ColorMaterialBitmask;
+
+ /* Default to PREMULT:
+ */
+ light_model_ctl &= ~((3 << RADEON_EMISSIVE_SOURCE_SHIFT) |
+ (3 << RADEON_AMBIENT_SOURCE_SHIFT) |
+ (3 << RADEON_DIFFUSE_SOURCE_SHIFT) |
+ (3 << RADEON_SPECULAR_SOURCE_SHIFT));
+
+ if (mask & FRONT_EMISSION_BIT) {
+ light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE <<
+ RADEON_EMISSIVE_SOURCE_SHIFT);
+ }
+
+ if (mask & FRONT_AMBIENT_BIT) {
+ light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE <<
+ RADEON_AMBIENT_SOURCE_SHIFT);
+ }
+
+ if (mask & FRONT_DIFFUSE_BIT) {
+ light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE <<
+ RADEON_DIFFUSE_SOURCE_SHIFT);
+ }
+
+ if (mask & FRONT_SPECULAR_BIT) {
+ light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE <<
+ RADEON_SPECULAR_SOURCE_SHIFT);
+ }
+
+ if (light_model_ctl != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) {
+ GLuint p;
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = light_model_ctl;
+
+ for (p = 0 ; p < MAX_LIGHTS; p++)
+ update_light_colors( ctx, p );
+ update_global_ambient( ctx );
+ }
+ }
+
+ check_twoside_fallback( ctx );
+}
+
+void radeonUpdateMaterial( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( mtl );
+ GLuint p;
+ GLuint mask = ~0;
+
+ if (ctx->Light.ColorMaterialEnabled)
+ mask &= ~ctx->Light.ColorMaterialBitmask;
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+
+ if (mask & FRONT_EMISSION_BIT) {
+ fcmd[MTL_EMMISSIVE_RED] = ctx->Light.Material[0].Emission[0];
+ fcmd[MTL_EMMISSIVE_GREEN] = ctx->Light.Material[0].Emission[1];
+ fcmd[MTL_EMMISSIVE_BLUE] = ctx->Light.Material[0].Emission[2];
+ fcmd[MTL_EMMISSIVE_ALPHA] = ctx->Light.Material[0].Emission[3];
+ }
+ if (mask & FRONT_AMBIENT_BIT) {
+ fcmd[MTL_AMBIENT_RED] = ctx->Light.Material[0].Ambient[0];
+ fcmd[MTL_AMBIENT_GREEN] = ctx->Light.Material[0].Ambient[1];
+ fcmd[MTL_AMBIENT_BLUE] = ctx->Light.Material[0].Ambient[2];
+ fcmd[MTL_AMBIENT_ALPHA] = ctx->Light.Material[0].Ambient[3];
+ }
+ if (mask & FRONT_DIFFUSE_BIT) {
+ fcmd[MTL_DIFFUSE_RED] = ctx->Light.Material[0].Diffuse[0];
+ fcmd[MTL_DIFFUSE_GREEN] = ctx->Light.Material[0].Diffuse[1];
+ fcmd[MTL_DIFFUSE_BLUE] = ctx->Light.Material[0].Diffuse[2];
+ fcmd[MTL_DIFFUSE_ALPHA] = ctx->Light.Material[0].Diffuse[3];
+ }
+ if (mask & FRONT_SPECULAR_BIT) {
+ fcmd[MTL_SPECULAR_RED] = ctx->Light.Material[0].Specular[0];
+ fcmd[MTL_SPECULAR_GREEN] = ctx->Light.Material[0].Specular[1];
+ fcmd[MTL_SPECULAR_BLUE] = ctx->Light.Material[0].Specular[2];
+ fcmd[MTL_SPECULAR_ALPHA] = ctx->Light.Material[0].Specular[3];
+ }
+ if (mask & FRONT_SHININESS_BIT) {
+ fcmd[MTL_SHININESS] = ctx->Light.Material[0].Shininess;
+ }
+
+ if (RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mtl )) {
+ for (p = 0 ; p < MAX_LIGHTS; p++)
+ update_light_colors( ctx, p );
+
+ check_twoside_fallback( ctx );
+ update_global_ambient( ctx );
+ }
+ else if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_STATE))
+ fprintf(stderr, "%s: Elided noop material call\n", __FUNCTION__);
+}
+
+/* _NEW_LIGHT
+ * _NEW_MODELVIEW
+ * _MESA_NEW_NEED_EYE_COORDS
+ *
+ * Uses derived state from mesa:
+ * _VP_inf_norm
+ * _h_inf_norm
+ * _Position
+ * _NormDirection
+ * _ModelViewInvScale
+ * _NeedEyeCoords
+ * _EyeZDir
+ *
+ * which are calculated in light.c and are correct for the current
+ * lighting space (model or eye), hence dependencies on _NEW_MODELVIEW
+ * and _MESA_NEW_NEED_EYE_COORDS.
+ */
+void radeonUpdateLighting( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ /* Have to check these, or have an automatic shortcircuit mechanism
+ * to remove noop statechanges. (Or just do a better job on the
+ * front end).
+ */
+ {
+ GLuint tmp = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL];
+
+ if (ctx->_NeedEyeCoords)
+ tmp &= ~RADEON_LIGHT_IN_MODELSPACE;
+ else
+ tmp |= RADEON_LIGHT_IN_MODELSPACE;
+
+
+ /* Leave this test disabled: (unexplained q3 lockup) (even with
+ new packets)
+ */
+ if (tmp != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL])
+ {
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = tmp;
+ }
+ }
+
+ {
+ GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( eye );
+ fcmd[EYE_X] = ctx->_EyeZDir[0];
+ fcmd[EYE_Y] = ctx->_EyeZDir[1];
+ fcmd[EYE_Z] = - ctx->_EyeZDir[2];
+ fcmd[EYE_RESCALE_FACTOR] = ctx->_ModelViewInvScale;
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.eye );
+ }
+
+
+/* RADEON_STATECHANGE( rmesa, glt ); */
+
+ if (ctx->Light.Enabled) {
+ GLint p;
+ for (p = 0 ; p < MAX_LIGHTS; p++) {
+ if (ctx->Light.Light[p].Enabled) {
+ struct gl_light *l = &ctx->Light.Light[p];
+ GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( lit[p] );
+
+ if (l->EyePosition[3] == 0.0) {
+ COPY_3FV( &fcmd[LIT_POSITION_X], l->_VP_inf_norm );
+ COPY_3FV( &fcmd[LIT_DIRECTION_X], l->_h_inf_norm );
+ fcmd[LIT_POSITION_W] = 0;
+ fcmd[LIT_DIRECTION_W] = 0;
+ } else {
+ COPY_4V( &fcmd[LIT_POSITION_X], l->_Position );
+ fcmd[LIT_DIRECTION_X] = -l->_NormDirection[0];
+ fcmd[LIT_DIRECTION_Y] = -l->_NormDirection[1];
+ fcmd[LIT_DIRECTION_Z] = -l->_NormDirection[2];
+ fcmd[LIT_DIRECTION_W] = 0;
+ }
+
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] );
+ }
+ }
+ }
+}
+
+
+void radeonLightfv( GLcontext *ctx, GLenum light,
+ GLenum pname, const GLfloat *params )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLint p = light - GL_LIGHT0;
+ struct gl_light *l = &ctx->Light.Light[p];
+ GLfloat *fcmd = (GLfloat *)rmesa->hw.lit[p].cmd;
+
+
+ switch (pname) {
+ case GL_AMBIENT:
+ case GL_DIFFUSE:
+ case GL_SPECULAR:
+ update_light_colors( ctx, p );
+ break;
+
+ case GL_SPOT_DIRECTION:
+ /* picked up in update_light */
+ break;
+
+ case GL_POSITION: {
+ /* positions picked up in update_light, but can do flag here */
+ GLuint flag = (p&1)? RADEON_LIGHT_1_IS_LOCAL : RADEON_LIGHT_0_IS_LOCAL;
+ GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2;
+
+ RADEON_STATECHANGE(rmesa, tcl);
+ if (l->EyePosition[3] != 0.0F)
+ rmesa->hw.tcl.cmd[idx] |= flag;
+ else
+ rmesa->hw.tcl.cmd[idx] &= ~flag;
+ break;
+ }
+
+ case GL_SPOT_EXPONENT:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_SPOT_EXPONENT] = params[0];
+ break;
+
+ case GL_SPOT_CUTOFF: {
+ GLuint flag = (p&1) ? RADEON_LIGHT_1_IS_SPOT : RADEON_LIGHT_0_IS_SPOT;
+ GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2;
+
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_SPOT_CUTOFF] = l->_CosCutoff;
+
+ RADEON_STATECHANGE(rmesa, tcl);
+ if (l->SpotCutoff != 180.0F)
+ rmesa->hw.tcl.cmd[idx] |= flag;
+ else
+ rmesa->hw.tcl.cmd[idx] &= ~flag;
+ break;
+ }
+
+ case GL_CONSTANT_ATTENUATION:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_ATTEN_CONST] = params[0];
+ break;
+ case GL_LINEAR_ATTENUATION:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_ATTEN_LINEAR] = params[0];
+ break;
+ case GL_QUADRATIC_ATTENUATION:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_ATTEN_QUADRATIC] = params[0];
+ break;
+ default:
+ return;
+ }
+
+}
+
+
+
+
+void radeonLightModelfv( GLcontext *ctx, GLenum pname,
+ const GLfloat *param )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ switch (pname) {
+ case GL_LIGHT_MODEL_AMBIENT:
+ update_global_ambient( ctx );
+ break;
+
+ case GL_LIGHT_MODEL_LOCAL_VIEWER:
+ RADEON_STATECHANGE( rmesa, tcl );
+ if (ctx->Light.Model.LocalViewer)
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LOCAL_VIEWER;
+ else
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LOCAL_VIEWER;
+ break;
+
+ case GL_LIGHT_MODEL_TWO_SIDE:
+ RADEON_STATECHANGE( rmesa, tcl );
+ if (ctx->Light.Model.TwoSide)
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_LIGHT_TWOSIDE;
+ else
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_LIGHT_TWOSIDE;
+
+ check_twoside_fallback( ctx );
+
+#if _HAVE_SWTNL
+ if (rmesa->TclFallback) {
+ radeonChooseRenderState( ctx );
+ radeonChooseVertexState( ctx );
+ }
+#endif
+ break;
+
+ case GL_LIGHT_MODEL_COLOR_CONTROL:
+ radeonUpdateSpecular(ctx);
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &=
+ ~RADEON_DIFFUSE_SPECULAR_COMBINE;
+ else
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |=
+ RADEON_DIFFUSE_SPECULAR_COMBINE;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* =============================================================
+ * Fog
+ */
+
+
+static void radeonFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ union { int i; float f; } c, d;
+ GLchan col[4];
+
+ c.i = rmesa->hw.fog.cmd[FOG_C];
+ d.i = rmesa->hw.fog.cmd[FOG_D];
+
+ switch (pname) {
+ case GL_FOG_MODE:
+ if (!ctx->Fog.Enabled)
+ return;
+ RADEON_STATECHANGE(rmesa, tcl);
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK;
+ switch (ctx->Fog.Mode) {
+ case GL_LINEAR:
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_LINEAR;
+ if (ctx->Fog.Start == ctx->Fog.End) {
+ c.f = 1.0F;
+ d.f = 1.0F;
+ }
+ else {
+ c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start);
+ d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start);
+ }
+ break;
+ case GL_EXP:
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP;
+ c.f = 0.0;
+ d.f = ctx->Fog.Density;
+ break;
+ case GL_EXP2:
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP2;
+ c.f = 0.0;
+ d.f = -(ctx->Fog.Density * ctx->Fog.Density);
+ break;
+ default:
+ return;
+ }
+ break;
+ case GL_FOG_DENSITY:
+ switch (ctx->Fog.Mode) {
+ case GL_EXP:
+ c.f = 0.0;
+ d.f = ctx->Fog.Density;
+ break;
+ case GL_EXP2:
+ c.f = 0.0;
+ d.f = -(ctx->Fog.Density * ctx->Fog.Density);
+ break;
+ default:
+ break;
+ }
+ break;
+ case GL_FOG_START:
+ case GL_FOG_END:
+ if (ctx->Fog.Mode == GL_LINEAR) {
+ if (ctx->Fog.Start == ctx->Fog.End) {
+ c.f = 1.0F;
+ d.f = 1.0F;
+ } else {
+ c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start);
+ d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start);
+ }
+ }
+ break;
+ case GL_FOG_COLOR:
+ RADEON_STATECHANGE( rmesa, ctx );
+ UNCLAMPED_FLOAT_TO_RGB_CHAN( col, ctx->Fog.Color );
+ rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] =
+ radeonPackColor( 4, col[0], col[1], col[2], 0 );
+ break;
+ case GL_FOG_COORDINATE_SOURCE_EXT:
+ /* What to do?
+ */
+ break;
+ default:
+ return;
+ }
+
+ if (c.i != rmesa->hw.fog.cmd[FOG_C] || d.i != rmesa->hw.fog.cmd[FOG_D]) {
+ RADEON_STATECHANGE( rmesa, fog );
+ rmesa->hw.fog.cmd[FOG_C] = c.i;
+ rmesa->hw.fog.cmd[FOG_D] = d.i;
+ }
+}
+
+/* Examine lighting and texture state to determine if separate specular
+ * should be enabled.
+ */
+void radeonUpdateSpecular( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint p = rmesa->hw.ctx.cmd[CTX_PP_CNTL];
+
+ if ( ctx->_TriangleCaps & DD_SEPARATE_SPECULAR ) {
+ p |= RADEON_SPECULAR_ENABLE;
+ } else {
+ p &= ~RADEON_SPECULAR_ENABLE;
+ }
+
+ if ( rmesa->hw.ctx.cmd[CTX_PP_CNTL] != p ) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] = p;
+ }
+
+ /* Bizzare: have to leave lighting enabled to get fog.
+ */
+ RADEON_STATECHANGE( rmesa, tcl );
+ if ((ctx->Light.Enabled &&
+ ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE;
+ }
+ else if (ctx->Fog.Enabled) {
+ if (ctx->Light.Enabled) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE;
+ } else {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE;
+ }
+ }
+ else if (ctx->Light.Enabled) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE;
+ } else if (ctx->Fog.ColorSumEnabled ) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE;
+ } else {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE;
+ }
+
+#if _HAVE_SWTNL
+ /* Update vertex/render formats
+ */
+ if (rmesa->TclFallback) {
+ radeonChooseRenderState( ctx );
+ radeonChooseVertexState( ctx );
+ }
+#endif
+}
+
+
+
+static void radeonLightingSpaceChange( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLboolean tmp;
+ RADEON_STATECHANGE( rmesa, tcl );
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s %d\n", __FUNCTION__, ctx->_NeedEyeCoords);
+
+ if (ctx->_NeedEyeCoords)
+ tmp = ctx->Transform.RescaleNormals;
+ else
+ tmp = !ctx->Transform.RescaleNormals;
+
+ if ( tmp ) {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS;
+ } else {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS;
+ }
+}
+
+void radeonInitLightStateFuncs( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ int i;
+
+ ctx->Driver.LightModelfv = radeonLightModelfv;
+ ctx->Driver.Lightfv = radeonLightfv;
+ ctx->Driver.Fogfv = radeonFogfv;
+ ctx->Driver.LightingSpaceChange = radeonLightingSpaceChange;
+
+ for (i = 0 ; i < 8; i++) {
+ struct gl_light *l = &ctx->Light.Light[i];
+ GLenum p = GL_LIGHT0 + i;
+ *(float *)&(rmesa->hw.lit[i].cmd[LIT_RANGE_CUTOFF]) = FLT_MAX;
+
+ ctx->Driver.Lightfv( ctx, p, GL_AMBIENT, l->Ambient );
+ ctx->Driver.Lightfv( ctx, p, GL_DIFFUSE, l->Diffuse );
+ ctx->Driver.Lightfv( ctx, p, GL_SPECULAR, l->Specular );
+ ctx->Driver.Lightfv( ctx, p, GL_POSITION, 0 );
+ ctx->Driver.Lightfv( ctx, p, GL_SPOT_DIRECTION, 0 );
+ ctx->Driver.Lightfv( ctx, p, GL_SPOT_EXPONENT, &l->SpotExponent );
+ ctx->Driver.Lightfv( ctx, p, GL_SPOT_CUTOFF, &l->SpotCutoff );
+ ctx->Driver.Lightfv( ctx, p, GL_CONSTANT_ATTENUATION,
+ &l->ConstantAttenuation );
+ ctx->Driver.Lightfv( ctx, p, GL_LINEAR_ATTENUATION,
+ &l->LinearAttenuation );
+ ctx->Driver.Lightfv( ctx, p, GL_QUADRATIC_ATTENUATION,
+ &l->QuadraticAttenuation );
+ }
+
+ ctx->Driver.LightModelfv( ctx, GL_LIGHT_MODEL_AMBIENT,
+ ctx->Light.Model.Ambient );
+
+ ctx->Driver.Fogfv( ctx, GL_FOG_MODE, 0 );
+ ctx->Driver.Fogfv( ctx, GL_FOG_DENSITY, &ctx->Fog.Density );
+ ctx->Driver.Fogfv( ctx, GL_FOG_START, &ctx->Fog.Start );
+ ctx->Driver.Fogfv( ctx, GL_FOG_END, &ctx->Fog.End );
+ ctx->Driver.Fogfv( ctx, GL_FOG_COLOR, ctx->Fog.Color );
+ ctx->Driver.Fogfv( ctx, GL_FOG_COORDINATE_SOURCE_EXT, 0 );
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_lock.c b/src/mesa/drivers/dri/radeon/radeon_lock.c
new file mode 100644
index 0000000000..96a4f9d112
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_lock.c
@@ -0,0 +1,128 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c,v 1.5 2002/10/30 12:51:55 alanh Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#include "glheader.h"
+#include "radeon_context.h"
+#include "radeon_lock.h"
+#include "radeon_tex.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+
+#if DEBUG_LOCKING
+char *prevLockFile = NULL;
+int prevLockLine = 0;
+#endif
+
+/* Turn on/off page flipping according to the flags in the sarea:
+ */
+static void
+radeonUpdatePageFlipping( radeonContextPtr rmesa )
+{
+ int use_back;
+
+ if (rmesa->dri.drmMinor < 3)
+ return;
+
+ rmesa->doPageFlip = rmesa->sarea->pfAllowPageFlip;
+
+ use_back = (rmesa->glCtx->Color._DrawDestMask == BACK_LEFT_BIT);
+ use_back ^= (rmesa->sarea->pfCurrentPage == 1);
+
+ if ( RADEON_DEBUG & DEBUG_VERBOSE )
+ fprintf(stderr, "%s allow %d current %d\n", __FUNCTION__,
+ rmesa->doPageFlip,
+ rmesa->sarea->pfCurrentPage );
+
+ if ( use_back ) {
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch;
+ } else {
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch;
+ }
+
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset;
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch;
+}
+
+
+
+/* Update the hardware state. This is called if another context has
+ * grabbed the hardware lock, which includes the X server. This
+ * function also updates the driver's window state after the X server
+ * moves, resizes or restacks a window -- the change will be reflected
+ * in the drawable position and clip rects. Since the X server grabs
+ * the hardware lock when it changes the window state, this routine will
+ * automatically be called after such a change.
+ */
+void radeonGetLock( radeonContextPtr rmesa, GLuint flags )
+{
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
+ __DRIscreenPrivate *sPriv = rmesa->dri.screen;
+ RADEONSAREAPrivPtr sarea = rmesa->sarea;
+
+ drmGetLock( rmesa->dri.fd, rmesa->dri.hwContext, flags );
+
+ /* The window might have moved, so we might need to get new clip
+ * rects.
+ *
+ * NOTE: This releases and regrabs the hw lock to allow the X server
+ * to respond to the DRI protocol request for new drawable info.
+ * Since the hardware state depends on having the latest drawable
+ * clip rects, all state checking must be done _after_ this call.
+ */
+ DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv );
+
+ if ( rmesa->lastStamp != dPriv->lastStamp ) {
+ radeonUpdatePageFlipping( rmesa );
+ if (rmesa->glCtx->Color._DrawDestMask == BACK_LEFT_BIT)
+ radeonSetCliprects( rmesa, GL_BACK_LEFT );
+ else
+ radeonSetCliprects( rmesa, GL_FRONT_LEFT );
+ radeonUpdateViewportOffset( rmesa->glCtx );
+ rmesa->lastStamp = dPriv->lastStamp;
+ }
+
+ if ( sarea->ctxOwner != rmesa->dri.hwContext ) {
+ int i;
+ sarea->ctxOwner = rmesa->dri.hwContext;
+
+ for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
+ DRI_AGE_TEXTURES( rmesa->texture_heaps[ i ] );
+ }
+ }
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_lock.h b/src/mesa/drivers/dri/radeon/radeon_lock.h
new file mode 100644
index 0000000000..783db7e92a
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_lock.h
@@ -0,0 +1,113 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_lock.h,v 1.3 2002/10/30 12:51:55 alanh Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __RADEON_LOCK_H__
+#define __RADEON_LOCK_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void radeonGetLock( radeonContextPtr rmesa, GLuint flags );
+
+/* Turn DEBUG_LOCKING 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
+
+/*
+ * !!! 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 !!!
+ */
+
+
+/* Lock the hardware and validate our state.
+ */
+#define LOCK_HARDWARE( rmesa ) \
+ do { \
+ char __ret = 0; \
+ DEBUG_CHECK_LOCK(); \
+ DRM_CAS( rmesa->dri.hwLock, rmesa->dri.hwContext, \
+ (DRM_LOCK_HELD | rmesa->dri.hwContext), __ret ); \
+ if ( __ret ) \
+ radeonGetLock( rmesa, 0 ); \
+ DEBUG_LOCK(); \
+ } while (0)
+
+/* Unlock the hardware.
+ */
+#define UNLOCK_HARDWARE( rmesa ) \
+ do { \
+ DRM_UNLOCK( rmesa->dri.fd, \
+ rmesa->dri.hwLock, \
+ rmesa->dri.hwContext ); \
+ DEBUG_RESET(); \
+ } while (0)
+
+#endif
+#endif /* __RADEON_LOCK_H__ */
diff --git a/src/mesa/drivers/dri/radeon/radeon_maos.c b/src/mesa/drivers/dri/radeon/radeon_maos.c
new file mode 100644
index 0000000000..c62edd715c
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_maos.c
@@ -0,0 +1,12 @@
+
+
+/* If using new packets, can choose either verts or arrays.
+ * Otherwise, must use verts.
+ */
+#include "radeon_context.h"
+#define RADEON_MAOS_VERTS 1
+#if (RADEON_MAOS_VERTS) || (RADEON_OLD_PACKETS)
+#include "radeon_maos_verts.c"
+#else
+#include "radeon_maos_arrays.c"
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_maos.h b/src/mesa/drivers/dri/radeon/radeon_maos.h
new file mode 100644
index 0000000000..7e2bd643d3
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_maos.h
@@ -0,0 +1,47 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Grahpics Inc., Austin, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#ifndef __RADEON_MAOS_H__
+#define __RADEON_MAOS_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "radeon_context.h"
+
+extern void radeonEmitArrays( GLcontext *ctx, GLuint inputs );
+extern void radeonReleaseArrays( GLcontext *ctx, GLuint newinputs );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_maos_arrays.c b/src/mesa/drivers/dri/radeon/radeon_maos_arrays.c
new file mode 100644
index 0000000000..cec05a89d7
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_maos_arrays.c
@@ -0,0 +1,591 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Cedar Park, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "mtypes.h"
+#include "mmath.h"
+#include "macros.h"
+
+#include "swrast_setup/swrast_setup.h"
+#include "math/m_translate.h"
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_imm_debug.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_swtcl.h"
+#include "radeon_maos.h"
+
+/* Usage:
+ * - from radeon_tcl_render
+ * - call radeonEmitArrays to ensure uptodate arrays in dma
+ * - emit primitives (new type?) which reference the data
+ * -- need to use elts for lineloop, quads, quadstrip/flat
+ * -- other primitives are all well-formed (need tristrip-1,fake-poly)
+ *
+ */
+static void emit_ubyte_rgba3( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int stride,
+ int count )
+{
+ int i;
+ radeon_color_t *out = (radeon_color_t *)(rvb->start + rvb->address);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d stride %d out %p\n",
+ __FUNCTION__, count, stride, out);
+
+ for (i = 0; i < count; i++) {
+ out->red = *data;
+ out->green = *(data+1);
+ out->blue = *(data+2);
+ out->alpha = 0xFF;
+ out++;
+ data += stride;
+ }
+}
+
+
+#if defined(USE_X86_ASM)
+#define COPY_DWORDS( dst, src, nr ) \
+do { \
+ int __tmp; \
+ __asm__ __volatile__( "rep ; movsl" \
+ : "=%c" (__tmp), "=D" (dst), "=S" (__tmp) \
+ : "0" (nr), \
+ "D" ((long)dst), \
+ "S" ((long)src) ); \
+} while (0)
+#else
+#define COPY_DWORDS( dst, src, nr ) \
+do { \
+ int j; \
+ for ( j = 0 ; j < nr ; j++ ) \
+ dst[j] = ((int *)src)[j]; \
+ dst += nr; \
+} while (0)
+#endif
+
+
+
+static void emit_ubyte_rgba4( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int stride,
+ int count )
+{
+ int i;
+ int *out = (int *)(rvb->address + rvb->start);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d stride %d\n",
+ __FUNCTION__, count, stride);
+
+ if (stride == 4)
+ COPY_DWORDS( out, data, count );
+ else
+ for (i = 0; i < count; i++) {
+ *out++ = LE32_TO_CPU(*(int *)data);
+ data += stride;
+ }
+}
+
+
+static void emit_ubyte_rgba( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int size,
+ int stride,
+ int count )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s %d/%d\n", __FUNCTION__, count, size);
+
+ assert (!rvb->buf);
+
+ if (stride == 0) {
+ radeonAllocDmaRegion( rmesa, rvb, 4, 4 );
+ count = 1;
+ rvb->aos_start = GET_START(rvb);
+ rvb->aos_stride = 0;
+ rvb->aos_size = 1;
+ }
+ else {
+ radeonAllocDmaRegion( rmesa, rvb, 4 * count, 4 ); /* alignment? */
+ rvb->aos_start = GET_START(rvb);
+ rvb->aos_stride = 1;
+ rvb->aos_size = 1;
+ }
+
+ /* Emit the data
+ */
+ switch (size) {
+ case 3:
+ emit_ubyte_rgba3( ctx, rvb, data, stride, count );
+ break;
+ case 4:
+ emit_ubyte_rgba4( ctx, rvb, data, stride, count );
+ break;
+ default:
+ assert(0);
+ exit(1);
+ break;
+ }
+}
+
+
+
+
+static void emit_vec8( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int stride,
+ int count )
+{
+ int i;
+ int *out = (int *)(rvb->address + rvb->start);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d stride %d\n",
+ __FUNCTION__, count, stride);
+
+ if (stride == 8)
+ COPY_DWORDS( out, data, count*2 );
+ else
+ for (i = 0; i < count; i++) {
+ out[0] = *(int *)data;
+ out[1] = *(int *)(data+4);
+ out += 2;
+ data += stride;
+ }
+}
+
+static void emit_vec12( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int stride,
+ int count )
+{
+ int i;
+ int *out = (int *)(rvb->address + rvb->start);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d stride %d out %p data %p\n",
+ __FUNCTION__, count, stride, out, data);
+
+ if (stride == 12)
+ COPY_DWORDS( out, data, count*3 );
+ else
+ for (i = 0; i < count; i++) {
+ out[0] = *(int *)data;
+ out[1] = *(int *)(data+4);
+ out[2] = *(int *)(data+8);
+ out += 3;
+ data += stride;
+ }
+}
+
+static void emit_vec16( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int stride,
+ int count )
+{
+ int i;
+ int *out = (int *)(rvb->address + rvb->start);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d stride %d\n",
+ __FUNCTION__, count, stride);
+
+ if (stride == 16)
+ COPY_DWORDS( out, data, count*4 );
+ else
+ for (i = 0; i < count; i++) {
+ out[0] = *(int *)data;
+ out[1] = *(int *)(data+4);
+ out[2] = *(int *)(data+8);
+ out[3] = *(int *)(data+12);
+ out += 4;
+ data += stride;
+ }
+}
+
+
+static void emit_vector( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int size,
+ int stride,
+ int count )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d size %d stride %d\n",
+ __FUNCTION__, count, size, stride);
+
+ assert (!rvb->buf);
+
+ if (stride == 0) {
+ radeonAllocDmaRegion( rmesa, rvb, size * 4, 4 );
+ count = 1;
+ rvb->aos_start = GET_START(rvb);
+ rvb->aos_stride = 0;
+ rvb->aos_size = size;
+ }
+ else {
+ radeonAllocDmaRegion( rmesa, rvb, size * count * 4, 4 ); /* alignment? */
+ rvb->aos_start = GET_START(rvb);
+ rvb->aos_stride = size;
+ rvb->aos_size = size;
+ }
+
+ /* Emit the data
+ */
+ switch (size) {
+ case 2:
+ emit_vec8( ctx, rvb, data, stride, count );
+ break;
+ case 3:
+ emit_vec12( ctx, rvb, data, stride, count );
+ break;
+ case 4:
+ emit_vec16( ctx, rvb, data, stride, count );
+ break;
+ default:
+ assert(0);
+ exit(1);
+ break;
+ }
+
+}
+
+
+
+static void emit_s0_vec( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int stride,
+ int count )
+{
+ int i;
+ int *out = (int *)(rvb->address + rvb->start);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d stride %d\n",
+ __FUNCTION__, count, stride);
+
+ for (i = 0; i < count; i++) {
+ out[0] = *(int *)data;
+ out[1] = 0;
+ out += 2;
+ data += stride;
+ }
+}
+
+static void emit_stq_vec( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int stride,
+ int count )
+{
+ int i;
+ int *out = (int *)(rvb->address + rvb->start);
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s count %d stride %d\n",
+ __FUNCTION__, count, stride);
+
+ for (i = 0; i < count; i++) {
+ out[0] = *(int *)data;
+ out[1] = *(int *)(data+4);
+ out[2] = *(int *)(data+12);
+ out += 3;
+ data += stride;
+ }
+}
+
+
+
+
+static void emit_tex_vector( GLcontext *ctx,
+ struct radeon_dma_region *rvb,
+ char *data,
+ int size,
+ int stride,
+ int count )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ int emitsize;
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s %d/%d\n", __FUNCTION__, count, size);
+
+ assert (!rvb->buf);
+
+ switch (size) {
+ case 4: emitsize = 3; break;
+ default: emitsize = 2; break;
+ }
+
+
+ if (stride == 0) {
+ radeonAllocDmaRegion( rmesa, rvb, 4 * emitsize, 4 );
+ count = 1;
+ rvb->aos_start = GET_START(rvb);
+ rvb->aos_stride = 0;
+ rvb->aos_size = emitsize;
+ }
+ else {
+ radeonAllocDmaRegion( rmesa, rvb, 4 * emitsize * count, 4 );
+ rvb->aos_start = GET_START(rvb);
+ rvb->aos_stride = emitsize;
+ rvb->aos_size = emitsize;
+ }
+
+
+ /* Emit the data
+ */
+ switch (size) {
+ case 1:
+ emit_s0_vec( ctx, rvb, data, stride, count );
+ break;
+ case 2:
+ emit_vec8( ctx, rvb, data, stride, count );
+ break;
+ case 3:
+ emit_vec8( ctx, rvb, data, stride, count );
+ break;
+ case 4:
+ emit_stq_vec( ctx, rvb, data, stride, count );
+ break;
+ default:
+ assert(0);
+ exit(1);
+ break;
+ }
+}
+
+
+
+
+/* Emit any changed arrays to new agp memory, re-emit a packet to
+ * update the arrays.
+ */
+void radeonEmitArrays( GLcontext *ctx, GLuint inputs )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb;
+ struct radeon_dma_region **component = rmesa->tcl.aos_components;
+ GLuint nr = 0;
+ GLuint vfmt = 0;
+ GLuint count = VB->Count;
+ GLuint vtx;
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ _tnl_print_vert_flags( __FUNCTION__, inputs );
+
+ if (1) {
+ if (!rmesa->tcl.obj.buf)
+ emit_vector( ctx,
+ &rmesa->tcl.obj,
+ (char *)VB->ObjPtr->data,
+ VB->ObjPtr->size,
+ VB->ObjPtr->stride,
+ count);
+
+ switch( VB->ObjPtr->size ) {
+ case 4: vfmt |= RADEON_CP_VC_FRMT_W0;
+ case 3: vfmt |= RADEON_CP_VC_FRMT_Z;
+ case 2: vfmt |= RADEON_CP_VC_FRMT_XY;
+ default:
+ }
+ component[nr++] = &rmesa->tcl.obj;
+ }
+
+
+ if (inputs & VERT_BIT_NORMAL) {
+ if (!rmesa->tcl.norm.buf)
+ emit_vector( ctx,
+ &(rmesa->tcl.norm),
+ (char *)VB->NormalPtr->data,
+ 3,
+ VB->NormalPtr->stride,
+ count);
+
+ vfmt |= RADEON_CP_VC_FRMT_N0;
+ component[nr++] = &rmesa->tcl.norm;
+ }
+
+ if (inputs & VERT_BIT_COLOR0) {
+ if (VB->ColorPtr[0]->Type == GL_UNSIGNED_BYTE) {
+ if (!rmesa->tcl.rgba.buf)
+ emit_ubyte_rgba( ctx,
+ &rmesa->tcl.rgba,
+ (char *)VB->ColorPtr[0]->Ptr,
+ VB->ColorPtr[0]->Size,
+ VB->ColorPtr[0]->StrideB,
+ count);
+
+ vfmt |= RADEON_CP_VC_FRMT_PKCOLOR;
+ }
+ else {
+ int emitsize;
+
+ if (VB->ColorPtr[0]->Size == 4 &&
+ (VB->ColorPtr[0]->StrideB != 0 ||
+ ((GLfloat *)VB->ColorPtr[0]->Ptr)[3] != 1.0)) {
+ vfmt |= RADEON_CP_VC_FRMT_FPCOLOR | RADEON_CP_VC_FRMT_FPALPHA;
+ emitsize = 4;
+ }
+ else {
+ vfmt |= RADEON_CP_VC_FRMT_FPCOLOR;
+ emitsize = 3;
+ }
+
+ if (!rmesa->tcl.rgba.buf)
+ emit_vector( ctx,
+ &(rmesa->tcl.rgba),
+ (char *)VB->ColorPtr[0]->Ptr,
+ emitsize,
+ VB->ColorPtr[0]->StrideB,
+ count);
+ }
+
+ component[nr++] = &rmesa->tcl.rgba;
+ }
+
+
+ if (inputs & VERT_BIT_COLOR1) {
+ if (!rmesa->tcl.spec.buf) {
+ if (VB->SecondaryColorPtr[0]->Type != GL_UNSIGNED_BYTE)
+ radeon_import_float_spec_colors( ctx );
+
+ emit_ubyte_rgba( ctx,
+ &rmesa->tcl.spec,
+ (char *)VB->SecondaryColorPtr[0]->Ptr,
+ 3,
+ VB->SecondaryColorPtr[0]->StrideB,
+ count);
+ }
+
+ vfmt |= RADEON_CP_VC_FRMT_PKSPEC;
+ component[nr++] = &rmesa->tcl.spec;
+ }
+
+ vtx = (rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &
+ ~(RADEON_TCL_VTX_Q0|RADEON_TCL_VTX_Q1));
+
+ if (inputs & VERT_BIT_TEX0) {
+ if (!rmesa->tcl.tex[0].buf)
+ emit_tex_vector( ctx,
+ &(rmesa->tcl.tex[0]),
+ (char *)VB->TexCoordPtr[0]->data,
+ VB->TexCoordPtr[0]->size,
+ VB->TexCoordPtr[0]->stride,
+ count );
+
+ switch( VB->TexCoordPtr[0]->size ) {
+ case 4:
+ vtx |= RADEON_TCL_VTX_Q0;
+ vfmt |= RADEON_CP_VC_FRMT_Q0;
+ default:
+ vfmt |= RADEON_CP_VC_FRMT_ST0;
+ }
+ component[nr++] = &rmesa->tcl.tex[0];
+ }
+
+ if (inputs & VERT_BIT_TEX1) {
+ if (!rmesa->tcl.tex[1].buf)
+ emit_tex_vector( ctx,
+ &(rmesa->tcl.tex[1]),
+ (char *)VB->TexCoordPtr[1]->data,
+ VB->TexCoordPtr[1]->size,
+ VB->TexCoordPtr[1]->stride,
+ count );
+
+ switch( VB->TexCoordPtr[1]->size ) {
+ case 4:
+ vtx |= RADEON_TCL_VTX_Q1;
+ vfmt |= RADEON_CP_VC_FRMT_Q1;
+ default:
+ vfmt |= RADEON_CP_VC_FRMT_ST1;
+ }
+ component[nr++] = &rmesa->tcl.tex[1];
+ }
+
+ if (vtx != rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT]) {
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] = vtx;
+ }
+
+ rmesa->tcl.nr_aos_components = nr;
+ rmesa->tcl.vertex_format = vfmt;
+}
+
+
+void radeonReleaseArrays( GLcontext *ctx, GLuint newinputs )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ _tnl_print_vert_flags( __FUNCTION__, newinputs );
+
+ if (newinputs & VERT_BIT_POS)
+ radeonReleaseDmaRegion( rmesa, &rmesa->tcl.obj, __FUNCTION__ );
+
+ if (newinputs & VERT_BIT_NORMAL)
+ radeonReleaseDmaRegion( rmesa, &rmesa->tcl.norm, __FUNCTION__ );
+
+ if (newinputs & VERT_BIT_COLOR0)
+ radeonReleaseDmaRegion( rmesa, &rmesa->tcl.rgba, __FUNCTION__ );
+
+ if (newinputs & VERT_BIT_COLOR1)
+ radeonReleaseDmaRegion( rmesa, &rmesa->tcl.spec, __FUNCTION__ );
+
+ if (newinputs & VERT_BIT_TEX0)
+ radeonReleaseDmaRegion( rmesa, &rmesa->tcl.tex[0], __FUNCTION__ );
+
+ if (newinputs & VERT_BIT_TEX1)
+ radeonReleaseDmaRegion( rmesa, &rmesa->tcl.tex[1], __FUNCTION__ );
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_maos_vbtmp.h b/src/mesa/drivers/dri/radeon/radeon_maos_vbtmp.h
new file mode 100644
index 0000000000..b379bad985
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_maos_vbtmp.h
@@ -0,0 +1,368 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.1
+ *
+ * Copyright (C) 1999-2002 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#ifndef LOCALVARS
+#define LOCALVARS
+#endif
+
+#undef TCL_DEBUG
+#ifndef TCL_DEBUG
+#define TCL_DEBUG 0
+#endif
+
+static void TAG(emit)( GLcontext *ctx,
+ GLuint start, GLuint end,
+ void *dest )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLuint (*tc0)[4], (*tc1)[4], (*tc2)[4];
+ GLfloat (*fog)[4];
+ GLuint (*norm)[4];
+ GLubyte (*col)[4], (*spec)[4];
+ GLuint tc0_stride, tc1_stride, col_stride, spec_stride, fog_stride;
+ GLuint tc2_stride, norm_stride;
+ GLuint (*coord)[4];
+ GLuint coord_stride; /* object coordinates */
+ GLubyte dummy[4];
+ int i;
+
+ union emit_union *v = (union emit_union *)dest;
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ /* The vertex code expects Obj to be clean to element 3. To fix
+ * this, add more vertex code (for obj-2, obj-3) or preferably move
+ * to maos.
+ */
+ if (VB->ObjPtr->size < 3) {
+ if (VB->ObjPtr->flags & VEC_NOT_WRITEABLE) {
+ VB->import_data( ctx, VERT_BIT_POS, VEC_NOT_WRITEABLE );
+ }
+ _mesa_vector4f_clean_elem( VB->ObjPtr, VB->Count, 2 );
+ }
+
+ if (DO_W && VB->ObjPtr->size < 4) {
+ if (VB->ObjPtr->flags & VEC_NOT_WRITEABLE) {
+ VB->import_data( ctx, VERT_BIT_POS, VEC_NOT_WRITEABLE );
+ }
+ _mesa_vector4f_clean_elem( VB->ObjPtr, VB->Count, 3 );
+ }
+
+ coord = (GLuint (*)[4])VB->ObjPtr->data;
+ coord_stride = VB->ObjPtr->stride;
+
+ if (DO_TEX2) {
+ const GLuint t2 = GET_TEXSOURCE(2);
+ tc2 = (GLuint (*)[4])VB->TexCoordPtr[t2]->data;
+ tc2_stride = VB->TexCoordPtr[t2]->stride;
+ if (DO_PTEX && VB->TexCoordPtr[t2]->size < 4) {
+ if (VB->TexCoordPtr[t2]->flags & VEC_NOT_WRITEABLE) {
+ VB->import_data( ctx, VERT_BIT_TEX2, VEC_NOT_WRITEABLE );
+ }
+ _mesa_vector4f_clean_elem( VB->TexCoordPtr[t2], VB->Count, 3 );
+ }
+ }
+
+ if (DO_TEX1) {
+ if (VB->TexCoordPtr[1]) {
+ const GLuint t1 = GET_TEXSOURCE(1);
+ tc1 = (GLuint (*)[4])VB->TexCoordPtr[t1]->data;
+ tc1_stride = VB->TexCoordPtr[t1]->stride;
+ if (DO_PTEX && VB->TexCoordPtr[t1]->size < 4) {
+ if (VB->TexCoordPtr[t1]->flags & VEC_NOT_WRITEABLE) {
+ VB->import_data( ctx, VERT_BIT_TEX1, VEC_NOT_WRITEABLE );
+ }
+ _mesa_vector4f_clean_elem( VB->TexCoordPtr[t1], VB->Count, 3 );
+ }
+ } else {
+ tc1 = (GLuint (*)[4])&ctx->Current.Attrib[VERT_ATTRIB_TEX1]; /* could be anything, really */
+ tc1_stride = 0;
+ }
+ }
+
+ if (DO_TEX0) {
+ if (VB->TexCoordPtr[0]) {
+ const GLuint t0 = GET_TEXSOURCE(0);
+ tc0_stride = VB->TexCoordPtr[t0]->stride;
+ tc0 = (GLuint (*)[4])VB->TexCoordPtr[t0]->data;
+ if (DO_PTEX && VB->TexCoordPtr[t0]->size < 4) {
+ if (VB->TexCoordPtr[t0]->flags & VEC_NOT_WRITEABLE) {
+ VB->import_data( ctx, VERT_BIT_TEX0, VEC_NOT_WRITEABLE );
+ }
+ _mesa_vector4f_clean_elem( VB->TexCoordPtr[t0], VB->Count, 3 );
+ }
+ } else {
+ tc0 = (GLuint (*)[4])&ctx->Current.Attrib[VERT_ATTRIB_TEX0]; /* could be anything, really */
+ tc0_stride = 0;
+ }
+
+ }
+
+ if (DO_NORM) {
+ if (VB->NormalPtr) {
+ norm_stride = VB->NormalPtr->stride;
+ norm = (GLuint (*)[4])VB->NormalPtr->data;
+ } else {
+ norm_stride = 0;
+ norm = (GLuint (*)[4])&ctx->Current.Attrib[VERT_ATTRIB_NORMAL];
+ }
+ }
+
+ if (DO_RGBA) {
+ if (VB->ColorPtr[0]) {
+ /* This is incorrect when colormaterial is enabled:
+ */
+ if (VB->ColorPtr[0]->Type != GL_UNSIGNED_BYTE) {
+ if (0) fprintf(stderr, "IMPORTING FLOAT COLORS\n");
+ IMPORT_FLOAT_COLORS( ctx );
+ }
+ col = (GLubyte (*)[4])VB->ColorPtr[0]->Ptr;
+ col_stride = VB->ColorPtr[0]->StrideB;
+ } else {
+ col = &dummy; /* any old memory is fine */
+ col_stride = 0;
+ }
+ }
+
+ if (DO_SPEC) {
+ if (VB->SecondaryColorPtr[0]) {
+ if (VB->SecondaryColorPtr[0]->Type != GL_UNSIGNED_BYTE)
+ IMPORT_FLOAT_SPEC_COLORS( ctx );
+ spec = (GLubyte (*)[4])VB->SecondaryColorPtr[0]->Ptr;
+ spec_stride = VB->SecondaryColorPtr[0]->StrideB;
+ } else {
+ spec = &dummy;
+ spec_stride = 0;
+ }
+ }
+
+ if (DO_FOG) {
+ if (VB->FogCoordPtr) {
+ fog = VB->FogCoordPtr->data;
+ fog_stride = VB->FogCoordPtr->stride;
+ } else {
+ fog = (GLfloat (*)[4])&dummy; fog[0][0] = 0.0F;
+ fog_stride = 0;
+ }
+ }
+
+
+ if (VB->importable_data) {
+ if (start) {
+ coord = (GLuint (*)[4])((GLubyte *)coord + start * coord_stride);
+ if (DO_TEX0)
+ tc0 = (GLuint (*)[4])((GLubyte *)tc0 + start * tc0_stride);
+ if (DO_TEX1)
+ tc1 = (GLuint (*)[4])((GLubyte *)tc1 + start * tc1_stride);
+ if (DO_TEX2)
+ tc2 = (GLuint (*)[4])((GLubyte *)tc2 + start * tc2_stride);
+ if (DO_NORM)
+ norm = (GLuint (*)[4])((GLubyte *)norm + start * norm_stride);
+ if (DO_RGBA)
+ STRIDE_4UB(col, start * col_stride);
+ if (DO_SPEC)
+ STRIDE_4UB(spec, start * spec_stride);
+ if (DO_FOG)
+ fog = (GLfloat (*)[4])((GLubyte *)fog + start * fog_stride);
+ }
+
+ for (i=start; i < end; i++) {
+ v[0].ui = coord[0][0];
+ v[1].ui = coord[0][1];
+ v[2].ui = coord[0][2];
+ if (TCL_DEBUG) fprintf(stderr, "%d: %.2f %.2f %.2f ", i, v[0].f, v[1].f, v[2].f);
+ if (DO_W) {
+ v[3].ui = coord[0][3];
+ if (TCL_DEBUG) fprintf(stderr, "%.2f ", v[3].f);
+ v += 4;
+ }
+ else
+ v += 3;
+ coord = (GLuint (*)[4])((GLubyte *)coord + coord_stride);
+
+ if (DO_NORM) {
+ v[0].ui = norm[0][0];
+ v[1].ui = norm[0][1];
+ v[2].ui = norm[0][2];
+ if (TCL_DEBUG) fprintf(stderr, "norm: %.2f %.2f %.2f ", v[0].f, v[1].f, v[2].f);
+ v += 3;
+ norm = (GLuint (*)[4])((GLubyte *)norm + norm_stride);
+ }
+ if (DO_RGBA) {
+ v[0].ui = LE32_TO_CPU(*(GLuint *)&col[0]);
+ STRIDE_4UB(col, col_stride);
+ if (TCL_DEBUG) fprintf(stderr, "%x ", v[0].ui);
+ v++;
+ }
+ if (DO_SPEC || DO_FOG) {
+ if (DO_SPEC) {
+ v[0].specular.red = spec[0][0];
+ v[0].specular.green = spec[0][1];
+ v[0].specular.blue = spec[0][2];
+ STRIDE_4UB(spec, spec_stride);
+ }
+ if (DO_FOG) {
+ v[0].specular.alpha = fog[0][0] * 255.0;
+ fog = (GLfloat (*)[4])((GLubyte *)fog + fog_stride);
+ }
+ if (TCL_DEBUG) fprintf(stderr, "%x ", v[0].ui);
+ v++;
+ }
+ if (DO_TEX0) {
+ v[0].ui = tc0[0][0];
+ v[1].ui = tc0[0][1];
+ if (TCL_DEBUG) fprintf(stderr, "t0: %.2f %.2f ", v[0].f, v[1].f);
+ if (DO_PTEX) {
+ v[2].ui = tc0[0][3];
+ if (TCL_DEBUG) fprintf(stderr, "%.2f ", v[2].f);
+ v += 3;
+ }
+ else
+ v += 2;
+ tc0 = (GLuint (*)[4])((GLubyte *)tc0 + tc0_stride);
+ }
+ if (DO_TEX1) {
+ v[0].ui = tc1[0][0];
+ v[1].ui = tc1[0][1];
+ if (TCL_DEBUG) fprintf(stderr, "t1: %.2f %.2f ", v[0].f, v[1].f);
+ if (DO_PTEX) {
+ v[2].ui = tc1[0][3];
+ if (TCL_DEBUG) fprintf(stderr, "%.2f ", v[2].f);
+ v += 3;
+ }
+ else
+ v += 2;
+ tc1 = (GLuint (*)[4])((GLubyte *)tc1 + tc1_stride);
+ }
+ if (DO_TEX2) {
+ v[0].ui = tc2[0][0];
+ v[1].ui = tc2[0][1];
+ if (DO_PTEX) {
+ v[2].ui = tc2[0][3];
+ v += 3;
+ }
+ else
+ v += 2;
+ tc2 = (GLuint (*)[4])((GLubyte *)tc2 + tc2_stride);
+ }
+ if (TCL_DEBUG) fprintf(stderr, "\n");
+ }
+ } else {
+ for (i=start; i < end; i++) {
+ v[0].ui = coord[i][0];
+ v[1].ui = coord[i][1];
+ v[2].ui = coord[i][2];
+ if (DO_W) {
+ v[3].ui = coord[i][3];
+ v += 4;
+ }
+ else
+ v += 3;
+
+ if (DO_NORM) {
+ v[0].ui = norm[i][0];
+ v[1].ui = norm[i][1];
+ v[2].ui = norm[i][2];
+ v += 3;
+ }
+ if (DO_RGBA) {
+ v[0].ui = LE32_TO_CPU(*(GLuint *)&col[i]);
+ v++;
+ }
+ if (DO_SPEC || DO_FOG) {
+ if (DO_SPEC) {
+ v[0].specular.red = spec[i][0];
+ v[0].specular.green = spec[i][1];
+ v[0].specular.blue = spec[i][2];
+ }
+ if (DO_FOG) {
+ GLfloat *f = (GLfloat *) ((GLubyte *)fog + fog_stride);
+ v[0].specular.alpha = *f * 255.0;
+ }
+ v++;
+ }
+ if (DO_TEX0) {
+ v[0].ui = tc0[i][0];
+ v[1].ui = tc0[i][1];
+ if (DO_PTEX) {
+ v[2].ui = tc0[i][3];
+ v += 3;
+ }
+ else
+ v += 2;
+ }
+ if (DO_TEX1) {
+ v[0].ui = tc1[i][0];
+ v[1].ui = tc1[i][1];
+ if (DO_PTEX) {
+ v[2].ui = tc1[i][3];
+ v += 3;
+ }
+ else
+ v += 2;
+ }
+ if (DO_TEX2) {
+ v[0].ui = tc2[i][0];
+ v[1].ui = tc2[i][1];
+ if (DO_PTEX) {
+ v[2].ui = tc2[i][3];
+ v += 3;
+ }
+ else
+ v += 2;
+ }
+ }
+ }
+}
+
+
+
+static void TAG(init)( void )
+{
+ int sz = 3;
+ if (DO_W) sz++;
+ if (DO_NORM) sz += 3;
+ if (DO_RGBA) sz++;
+ if (DO_SPEC || DO_FOG) sz++;
+ if (DO_TEX0) sz += 2;
+ if (DO_TEX0 && DO_PTEX) sz++;
+ if (DO_TEX1) sz += 2;
+ if (DO_TEX1 && DO_PTEX) sz++;
+ if (DO_TEX2) sz += 2;
+ if (DO_TEX2 && DO_PTEX) sz++;
+
+ setup_tab[IDX].emit = TAG(emit);
+ setup_tab[IDX].vertex_format = IND;
+ setup_tab[IDX].vertex_size = sz;
+}
+
+
+#undef IND
+#undef TAG
+#undef IDX
diff --git a/src/mesa/drivers/dri/radeon/radeon_maos_verts.c b/src/mesa/drivers/dri/radeon/radeon_maos_verts.c
new file mode 100644
index 0000000000..39b1f57507
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_maos_verts.c
@@ -0,0 +1,335 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Austin, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "array_cache/acache.h"
+#include "tnl/tnl.h"
+#include "tnl/t_pipeline.h"
+#include "tnl/t_imm_debug.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_tex.h"
+#include "radeon_tcl.h"
+#include "radeon_swtcl.h"
+#include "radeon_maos.h"
+
+
+#define RADEON_TCL_MAX_SETUP 13
+
+union emit_union { float f; GLuint ui; radeon_color_t specular; };
+
+static struct {
+ void (*emit)( GLcontext *, GLuint, GLuint, void * );
+ GLuint vertex_size;
+ GLuint vertex_format;
+} setup_tab[RADEON_TCL_MAX_SETUP];
+
+#define DO_W (IND & RADEON_CP_VC_FRMT_W0)
+#define DO_RGBA (IND & RADEON_CP_VC_FRMT_PKCOLOR)
+#define DO_SPEC (IND & RADEON_CP_VC_FRMT_PKSPEC)
+#define DO_FOG (IND & RADEON_CP_VC_FRMT_PKSPEC)
+#define DO_TEX0 (IND & RADEON_CP_VC_FRMT_ST0)
+#define DO_TEX1 (IND & RADEON_CP_VC_FRMT_ST1)
+#define DO_PTEX (IND & RADEON_CP_VC_FRMT_Q0)
+#define DO_NORM (IND & RADEON_CP_VC_FRMT_N0)
+
+#define DO_TEX2 0
+#define DO_TEX3 0
+
+#define GET_TEXSOURCE(n) n
+#define GET_UBYTE_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteColor
+#define GET_UBYTE_SPEC_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteSecondaryColor
+
+#define IMPORT_FLOAT_COLORS radeon_import_float_colors
+#define IMPORT_FLOAT_SPEC_COLORS radeon_import_float_spec_colors
+
+/***********************************************************************
+ * Generate vertex emit functions *
+ ***********************************************************************/
+
+
+/* Defined in order of increasing vertex size:
+ */
+#define IDX 0
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR)
+#define TAG(x) x##_rgba
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 1
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_N0)
+#define TAG(x) x##_n
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 2
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_ST0)
+#define TAG(x) x##_rgba_st
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 3
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_N0)
+#define TAG(x) x##_rgba_n
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 4
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_N0)
+#define TAG(x) x##_st_n
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 5
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_ST1)
+#define TAG(x) x##_rgba_st_st
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 6
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_N0)
+#define TAG(x) x##_rgba_st_n
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 7
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_PKSPEC| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_ST1)
+#define TAG(x) x##_rgba_spec_st_st
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 8
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_ST1| \
+ RADEON_CP_VC_FRMT_N0)
+#define TAG(x) x##_st_st_n
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 9
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_PKSPEC| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_ST1| \
+ RADEON_CP_VC_FRMT_N0)
+#define TAG(x) x##_rgpa_spec_st_st_n
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 10
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_Q0)
+#define TAG(x) x##_rgba_stq
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 11
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_ST1| \
+ RADEON_CP_VC_FRMT_Q1| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_Q0)
+#define TAG(x) x##_rgba_stq_stq
+#include "radeon_maos_vbtmp.h"
+
+#define IDX 12
+#define IND (RADEON_CP_VC_FRMT_XY| \
+ RADEON_CP_VC_FRMT_Z| \
+ RADEON_CP_VC_FRMT_W0| \
+ RADEON_CP_VC_FRMT_PKCOLOR| \
+ RADEON_CP_VC_FRMT_PKSPEC| \
+ RADEON_CP_VC_FRMT_ST0| \
+ RADEON_CP_VC_FRMT_Q0| \
+ RADEON_CP_VC_FRMT_ST1| \
+ RADEON_CP_VC_FRMT_Q1| \
+ RADEON_CP_VC_FRMT_N0)
+#define TAG(x) x##_w_rgpa_spec_stq_stq_n
+#include "radeon_maos_vbtmp.h"
+
+
+
+
+
+/***********************************************************************
+ * Initialization
+ ***********************************************************************/
+
+
+static void init_tcl_verts( void )
+{
+ init_rgba();
+ init_n();
+ init_rgba_n();
+ init_rgba_st();
+ init_st_n();
+ init_rgba_st_st();
+ init_rgba_st_n();
+ init_rgba_spec_st_st();
+ init_st_st_n();
+ init_rgpa_spec_st_st_n();
+ init_rgba_stq();
+ init_rgba_stq_stq();
+ init_w_rgpa_spec_stq_stq_n();
+}
+
+
+void radeonEmitArrays( GLcontext *ctx, GLuint inputs )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLuint req = 0;
+ GLuint vtx = (rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &
+ ~(RADEON_TCL_VTX_Q0|RADEON_TCL_VTX_Q1));
+ int i;
+ static int firsttime = 1;
+
+ if (firsttime) {
+ init_tcl_verts();
+ firsttime = 0;
+ }
+
+ if (1) {
+ req |= RADEON_CP_VC_FRMT_Z;
+ if (VB->ObjPtr->size == 4) {
+ req |= RADEON_CP_VC_FRMT_W0;
+ }
+ }
+
+ if (inputs & VERT_BIT_NORMAL) {
+ req |= RADEON_CP_VC_FRMT_N0;
+ }
+
+ if (inputs & VERT_BIT_COLOR0) {
+ req |= RADEON_CP_VC_FRMT_PKCOLOR;
+ }
+
+ if (inputs & VERT_BIT_COLOR1) {
+ req |= RADEON_CP_VC_FRMT_PKSPEC;
+ }
+
+ if (inputs & VERT_BIT_TEX0) {
+ req |= RADEON_CP_VC_FRMT_ST0;
+
+ if (VB->TexCoordPtr[0]->size == 4) {
+ req |= RADEON_CP_VC_FRMT_Q0;
+ vtx |= RADEON_TCL_VTX_Q0;
+ }
+ }
+
+ if (inputs & VERT_BIT_TEX1) {
+ req |= RADEON_CP_VC_FRMT_ST1;
+
+ if (VB->TexCoordPtr[1]->size == 4) {
+ req |= RADEON_CP_VC_FRMT_Q1;
+ vtx |= RADEON_TCL_VTX_Q1;
+ }
+ }
+
+ if (vtx != rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT]) {
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] = vtx;
+ }
+
+ for (i = 0 ; i < RADEON_TCL_MAX_SETUP ; i++)
+ if ((setup_tab[i].vertex_format & req) == req)
+ break;
+
+ if (rmesa->tcl.vertex_format == setup_tab[i].vertex_format &&
+ rmesa->tcl.indexed_verts.buf)
+ return;
+
+ if (rmesa->tcl.indexed_verts.buf)
+ radeonReleaseArrays( ctx, ~0 );
+
+ radeonAllocDmaRegionVerts( rmesa,
+ &rmesa->tcl.indexed_verts,
+ VB->Count,
+ setup_tab[i].vertex_size * 4,
+ 4);
+
+ setup_tab[i].emit( ctx, 0, VB->Count,
+ rmesa->tcl.indexed_verts.address +
+ rmesa->tcl.indexed_verts.start );
+
+ rmesa->tcl.vertex_format = setup_tab[i].vertex_format;
+ rmesa->tcl.indexed_verts.aos_start = GET_START( &rmesa->tcl.indexed_verts );
+ rmesa->tcl.indexed_verts.aos_size = setup_tab[i].vertex_size;
+ rmesa->tcl.indexed_verts.aos_stride = setup_tab[i].vertex_size;
+
+ rmesa->tcl.aos_components[0] = &rmesa->tcl.indexed_verts;
+ rmesa->tcl.nr_aos_components = 1;
+}
+
+
+
+void radeonReleaseArrays( GLcontext *ctx, GLuint newinputs )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (RADEON_DEBUG & DEBUG_VERTS)
+ _tnl_print_vert_flags( __FUNCTION__, newinputs );
+
+ if (newinputs)
+ radeonReleaseDmaRegion( rmesa, &rmesa->tcl.indexed_verts, __FUNCTION__ );
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_sanity.c b/src/mesa/drivers/dri/radeon/radeon_sanity.c
new file mode 100644
index 0000000000..e3b37bf3de
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_sanity.c
@@ -0,0 +1,1043 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2002 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc, Cedar Park, TX.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+#include <errno.h>
+
+#include "glheader.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_sanity.h"
+
+/* Set this '1' to get more verbiage.
+ */
+#define MORE_VERBOSE 1
+
+#if MORE_VERBOSE
+#define VERBOSE (RADEON_DEBUG & DEBUG_VERBOSE)
+#define NORMAL (1)
+#else
+#define VERBOSE 0
+#define NORMAL (RADEON_DEBUG & DEBUG_VERBOSE)
+#endif
+
+
+/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
+ * 1.3 cmdbuffers allow all previous state to be updated as well as
+ * the tcl scalar and vector areas.
+ */
+static struct {
+ int start;
+ int len;
+ const char *name;
+} packet[RADEON_MAX_STATE_PACKETS] = {
+ { RADEON_PP_MISC,7,"RADEON_PP_MISC" },
+ { RADEON_PP_CNTL,3,"RADEON_PP_CNTL" },
+ { RADEON_RB3D_COLORPITCH,1,"RADEON_RB3D_COLORPITCH" },
+ { RADEON_RE_LINE_PATTERN,2,"RADEON_RE_LINE_PATTERN" },
+ { RADEON_SE_LINE_WIDTH,1,"RADEON_SE_LINE_WIDTH" },
+ { RADEON_PP_LUM_MATRIX,1,"RADEON_PP_LUM_MATRIX" },
+ { RADEON_PP_ROT_MATRIX_0,2,"RADEON_PP_ROT_MATRIX_0" },
+ { RADEON_RB3D_STENCILREFMASK,3,"RADEON_RB3D_STENCILREFMASK" },
+ { RADEON_SE_VPORT_XSCALE,6,"RADEON_SE_VPORT_XSCALE" },
+ { RADEON_SE_CNTL,2,"RADEON_SE_CNTL" },
+ { RADEON_SE_CNTL_STATUS,1,"RADEON_SE_CNTL_STATUS" },
+ { RADEON_RE_MISC,1,"RADEON_RE_MISC" },
+ { RADEON_PP_TXFILTER_0,6,"RADEON_PP_TXFILTER_0" },
+ { RADEON_PP_BORDER_COLOR_0,1,"RADEON_PP_BORDER_COLOR_0" },
+ { RADEON_PP_TXFILTER_1,6,"RADEON_PP_TXFILTER_1" },
+ { RADEON_PP_BORDER_COLOR_1,1,"RADEON_PP_BORDER_COLOR_1" },
+ { RADEON_PP_TXFILTER_2,6,"RADEON_PP_TXFILTER_2" },
+ { RADEON_PP_BORDER_COLOR_2,1,"RADEON_PP_BORDER_COLOR_2" },
+ { RADEON_SE_ZBIAS_FACTOR,2,"RADEON_SE_ZBIAS_FACTOR" },
+ { RADEON_SE_TCL_OUTPUT_VTX_FMT,11,"RADEON_SE_TCL_OUTPUT_VTX_FMT" },
+ { RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED,17,"RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED" },
+ { 0, 4, "R200_PP_TXCBLEND_0" },
+ { 0, 4, "R200_PP_TXCBLEND_1" },
+ { 0, 4, "R200_PP_TXCBLEND_2" },
+ { 0, 4, "R200_PP_TXCBLEND_3" },
+ { 0, 4, "R200_PP_TXCBLEND_4" },
+ { 0, 4, "R200_PP_TXCBLEND_5" },
+ { 0, 4, "R200_PP_TXCBLEND_6" },
+ { 0, 4, "R200_PP_TXCBLEND_7" },
+ { 0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0" },
+ { 0, 6, "R200_PP_TFACTOR_0" },
+ { 0, 4, "R200_SE_VTX_FMT_0" },
+ { 0, 1, "R200_SE_VAP_CNTL" },
+ { 0, 5, "R200_SE_TCL_MATRIX_SEL_0" },
+ { 0, 5, "R200_SE_TCL_TEX_PROC_CTL_2" },
+ { 0, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL" },
+ { 0, 6, "R200_PP_TXFILTER_0" },
+ { 0, 6, "R200_PP_TXFILTER_1" },
+ { 0, 6, "R200_PP_TXFILTER_2" },
+ { 0, 6, "R200_PP_TXFILTER_3" },
+ { 0, 6, "R200_PP_TXFILTER_4" },
+ { 0, 6, "R200_PP_TXFILTER_5" },
+ { 0, 1, "R200_PP_TXOFFSET_0" },
+ { 0, 1, "R200_PP_TXOFFSET_1" },
+ { 0, 1, "R200_PP_TXOFFSET_2" },
+ { 0, 1, "R200_PP_TXOFFSET_3" },
+ { 0, 1, "R200_PP_TXOFFSET_4" },
+ { 0, 1, "R200_PP_TXOFFSET_5" },
+ { 0, 1, "R200_SE_VTE_CNTL" },
+ { 0, 1, "R200_SE_TCL_OUTPUT_VTX_COMP_SEL" },
+ { 0, 1, "R200_PP_TAM_DEBUG3" },
+ { 0, 1, "R200_PP_CNTL_X" },
+ { 0, 1, "R200_RB3D_DEPTHXY_OFFSET" },
+ { 0, 1, "R200_RE_AUX_SCISSOR_CNTL" },
+ { 0, 2, "R200_RE_SCISSOR_TL_0" },
+ { 0, 2, "R200_RE_SCISSOR_TL_1" },
+ { 0, 2, "R200_RE_SCISSOR_TL_2" },
+ { 0, 1, "R200_SE_VAP_CNTL_STATUS" },
+ { 0, 1, "R200_SE_VTX_STATE_CNTL" },
+ { 0, 1, "R200_RE_POINTSIZE" },
+ { 0, 4, "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0" },
+ { 0, 1, "R200_PP_CUBIC_FACES_0" }, /* 61 */
+ { 0, 5, "R200_PP_CUBIC_OFFSET_F1_0" }, /* 62 */
+ { 0, 1, "R200_PP_CUBIC_FACES_1" },
+ { 0, 5, "R200_PP_CUBIC_OFFSET_F1_1" },
+ { 0, 1, "R200_PP_CUBIC_FACES_2" },
+ { 0, 5, "R200_PP_CUBIC_OFFSET_F1_2" },
+ { 0, 1, "R200_PP_CUBIC_FACES_3" },
+ { 0, 5, "R200_PP_CUBIC_OFFSET_F1_3" },
+ { 0, 1, "R200_PP_CUBIC_FACES_4" },
+ { 0, 5, "R200_PP_CUBIC_OFFSET_F1_4" },
+ { 0, 1, "R200_PP_CUBIC_FACES_5" },
+ { 0, 5, "R200_PP_CUBIC_OFFSET_F1_5" },
+ { RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0" },
+ { RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1" },
+ { RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_1" },
+};
+
+struct reg_names {
+ int idx;
+ const char *name;
+};
+
+static struct reg_names reg_names[] = {
+ { RADEON_PP_MISC, "RADEON_PP_MISC" },
+ { RADEON_PP_FOG_COLOR, "RADEON_PP_FOG_COLOR" },
+ { RADEON_RE_SOLID_COLOR, "RADEON_RE_SOLID_COLOR" },
+ { RADEON_RB3D_BLENDCNTL, "RADEON_RB3D_BLENDCNTL" },
+ { RADEON_RB3D_DEPTHOFFSET, "RADEON_RB3D_DEPTHOFFSET" },
+ { RADEON_RB3D_DEPTHPITCH, "RADEON_RB3D_DEPTHPITCH" },
+ { RADEON_RB3D_ZSTENCILCNTL, "RADEON_RB3D_ZSTENCILCNTL" },
+ { RADEON_PP_CNTL, "RADEON_PP_CNTL" },
+ { RADEON_RB3D_CNTL, "RADEON_RB3D_CNTL" },
+ { RADEON_RB3D_COLOROFFSET, "RADEON_RB3D_COLOROFFSET" },
+ { RADEON_RB3D_COLORPITCH, "RADEON_RB3D_COLORPITCH" },
+ { RADEON_SE_CNTL, "RADEON_SE_CNTL" },
+ { RADEON_SE_COORD_FMT, "RADEON_SE_COORDFMT" },
+ { RADEON_SE_CNTL_STATUS, "RADEON_SE_CNTL_STATUS" },
+ { RADEON_RE_LINE_PATTERN, "RADEON_RE_LINE_PATTERN" },
+ { RADEON_RE_LINE_STATE, "RADEON_RE_LINE_STATE" },
+ { RADEON_SE_LINE_WIDTH, "RADEON_SE_LINE_WIDTH" },
+ { RADEON_RB3D_STENCILREFMASK, "RADEON_RB3D_STENCILREFMASK" },
+ { RADEON_RB3D_ROPCNTL, "RADEON_RB3D_ROPCNTL" },
+ { RADEON_RB3D_PLANEMASK, "RADEON_RB3D_PLANEMASK" },
+ { RADEON_SE_VPORT_XSCALE, "RADEON_SE_VPORT_XSCALE" },
+ { RADEON_SE_VPORT_XOFFSET, "RADEON_SE_VPORT_XOFFSET" },
+ { RADEON_SE_VPORT_YSCALE, "RADEON_SE_VPORT_YSCALE" },
+ { RADEON_SE_VPORT_YOFFSET, "RADEON_SE_VPORT_YOFFSET" },
+ { RADEON_SE_VPORT_ZSCALE, "RADEON_SE_VPORT_ZSCALE" },
+ { RADEON_SE_VPORT_ZOFFSET, "RADEON_SE_VPORT_ZOFFSET" },
+ { RADEON_RE_MISC, "RADEON_RE_MISC" },
+ { RADEON_PP_TXFILTER_0, "RADEON_PP_TXFILTER_0" },
+ { RADEON_PP_TXFILTER_1, "RADEON_PP_TXFILTER_1" },
+ { RADEON_PP_TXFILTER_2, "RADEON_PP_TXFILTER_2" },
+ { RADEON_PP_TXFORMAT_0, "RADEON_PP_TXFORMAT_0" },
+ { RADEON_PP_TXFORMAT_1, "RADEON_PP_TXFORMAT_1" },
+ { RADEON_PP_TXFORMAT_2, "RADEON_PP_TXFORMAT_3" },
+ { RADEON_PP_TXOFFSET_0, "RADEON_PP_TXOFFSET_0" },
+ { RADEON_PP_TXOFFSET_1, "RADEON_PP_TXOFFSET_1" },
+ { RADEON_PP_TXOFFSET_2, "RADEON_PP_TXOFFSET_3" },
+ { RADEON_PP_TXCBLEND_0, "RADEON_PP_TXCBLEND_0" },
+ { RADEON_PP_TXCBLEND_1, "RADEON_PP_TXCBLEND_1" },
+ { RADEON_PP_TXCBLEND_2, "RADEON_PP_TXCBLEND_3" },
+ { RADEON_PP_TXABLEND_0, "RADEON_PP_TXABLEND_0" },
+ { RADEON_PP_TXABLEND_1, "RADEON_PP_TXABLEND_1" },
+ { RADEON_PP_TXABLEND_2, "RADEON_PP_TXABLEND_3" },
+ { RADEON_PP_TFACTOR_0, "RADEON_PP_TFACTOR_0" },
+ { RADEON_PP_TFACTOR_1, "RADEON_PP_TFACTOR_1" },
+ { RADEON_PP_TFACTOR_2, "RADEON_PP_TFACTOR_3" },
+ { RADEON_PP_BORDER_COLOR_0, "RADEON_PP_BORDER_COLOR_0" },
+ { RADEON_PP_BORDER_COLOR_1, "RADEON_PP_BORDER_COLOR_1" },
+ { RADEON_PP_BORDER_COLOR_2, "RADEON_PP_BORDER_COLOR_3" },
+ { RADEON_SE_ZBIAS_FACTOR, "RADEON_SE_ZBIAS_FACTOR" },
+ { RADEON_SE_ZBIAS_CONSTANT, "RADEON_SE_ZBIAS_CONSTANT" },
+ { RADEON_SE_TCL_OUTPUT_VTX_FMT, "RADEON_SE_TCL_OUTPUT_VTXFMT" },
+ { RADEON_SE_TCL_OUTPUT_VTX_SEL, "RADEON_SE_TCL_OUTPUT_VTXSEL" },
+ { RADEON_SE_TCL_MATRIX_SELECT_0, "RADEON_SE_TCL_MATRIX_SELECT_0" },
+ { RADEON_SE_TCL_MATRIX_SELECT_1, "RADEON_SE_TCL_MATRIX_SELECT_1" },
+ { RADEON_SE_TCL_UCP_VERT_BLEND_CTL, "RADEON_SE_TCL_UCP_VERT_BLEND_CTL" },
+ { RADEON_SE_TCL_TEXTURE_PROC_CTL, "RADEON_SE_TCL_TEXTURE_PROC_CTL" },
+ { RADEON_SE_TCL_LIGHT_MODEL_CTL, "RADEON_SE_TCL_LIGHT_MODEL_CTL" },
+ { RADEON_SE_TCL_PER_LIGHT_CTL_0, "RADEON_SE_TCL_PER_LIGHT_CTL_0" },
+ { RADEON_SE_TCL_PER_LIGHT_CTL_1, "RADEON_SE_TCL_PER_LIGHT_CTL_1" },
+ { RADEON_SE_TCL_PER_LIGHT_CTL_2, "RADEON_SE_TCL_PER_LIGHT_CTL_2" },
+ { RADEON_SE_TCL_PER_LIGHT_CTL_3, "RADEON_SE_TCL_PER_LIGHT_CTL_3" },
+ { RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, "RADEON_SE_TCL_EMMISSIVE_RED" },
+ { RADEON_SE_TCL_MATERIAL_EMMISSIVE_GREEN, "RADEON_SE_TCL_EMMISSIVE_GREEN" },
+ { RADEON_SE_TCL_MATERIAL_EMMISSIVE_BLUE, "RADEON_SE_TCL_EMMISSIVE_BLUE" },
+ { RADEON_SE_TCL_MATERIAL_EMMISSIVE_ALPHA, "RADEON_SE_TCL_EMMISSIVE_ALPHA" },
+ { RADEON_SE_TCL_MATERIAL_AMBIENT_RED, "RADEON_SE_TCL_AMBIENT_RED" },
+ { RADEON_SE_TCL_MATERIAL_AMBIENT_GREEN, "RADEON_SE_TCL_AMBIENT_GREEN" },
+ { RADEON_SE_TCL_MATERIAL_AMBIENT_BLUE, "RADEON_SE_TCL_AMBIENT_BLUE" },
+ { RADEON_SE_TCL_MATERIAL_AMBIENT_ALPHA, "RADEON_SE_TCL_AMBIENT_ALPHA" },
+ { RADEON_SE_TCL_MATERIAL_DIFFUSE_RED, "RADEON_SE_TCL_DIFFUSE_RED" },
+ { RADEON_SE_TCL_MATERIAL_DIFFUSE_GREEN, "RADEON_SE_TCL_DIFFUSE_GREEN" },
+ { RADEON_SE_TCL_MATERIAL_DIFFUSE_BLUE, "RADEON_SE_TCL_DIFFUSE_BLUE" },
+ { RADEON_SE_TCL_MATERIAL_DIFFUSE_ALPHA, "RADEON_SE_TCL_DIFFUSE_ALPHA" },
+ { RADEON_SE_TCL_MATERIAL_SPECULAR_RED, "RADEON_SE_TCL_SPECULAR_RED" },
+ { RADEON_SE_TCL_MATERIAL_SPECULAR_GREEN, "RADEON_SE_TCL_SPECULAR_GREEN" },
+ { RADEON_SE_TCL_MATERIAL_SPECULAR_BLUE, "RADEON_SE_TCL_SPECULAR_BLUE" },
+ { RADEON_SE_TCL_MATERIAL_SPECULAR_ALPHA, "RADEON_SE_TCL_SPECULAR_ALPHA" },
+ { RADEON_SE_TCL_SHININESS, "RADEON_SE_TCL_SHININESS" },
+ { RADEON_SE_COORD_FMT, "RADEON_SE_COORD_FMT" },
+ { RADEON_PP_TEX_SIZE_0, "RADEON_PP_TEX_SIZE_0" },
+ { RADEON_PP_TEX_SIZE_1, "RADEON_PP_TEX_SIZE_1" },
+ { RADEON_PP_TEX_SIZE_2, "RADEON_PP_TEX_SIZE_2" },
+ { RADEON_PP_TEX_SIZE_0+4, "RADEON_PP_TEX_PITCH_0" },
+ { RADEON_PP_TEX_SIZE_1+4, "RADEON_PP_TEX_PITCH_1" },
+ { RADEON_PP_TEX_SIZE_2+4, "RADEON_PP_TEX_PITCH_2" },
+};
+
+static struct reg_names scalar_names[] = {
+ { RADEON_SS_LIGHT_DCD_ADDR, "LIGHT_DCD" },
+ { RADEON_SS_LIGHT_SPOT_EXPONENT_ADDR, "LIGHT_SPOT_EXPONENT" },
+ { RADEON_SS_LIGHT_SPOT_CUTOFF_ADDR, "LIGHT_SPOT_CUTOFF" },
+ { RADEON_SS_LIGHT_SPECULAR_THRESH_ADDR, "LIGHT_SPECULAR_THRESH" },
+ { RADEON_SS_LIGHT_RANGE_CUTOFF_ADDR, "LIGHT_RANGE_CUTOFF" },
+ { RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR, "VERT_GUARD_CLIP" },
+ { RADEON_SS_VERT_GUARD_DISCARD_ADJ_ADDR, "VERT_GUARD_DISCARD" },
+ { RADEON_SS_HORZ_GUARD_CLIP_ADJ_ADDR, "HORZ_GUARD_CLIP" },
+ { RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR, "HORZ_GUARD_DISCARD" },
+ { RADEON_SS_SHININESS, "SHININESS" },
+ { 1000, "" },
+};
+
+/* Puff these out to make them look like normal (dword) registers.
+ */
+static struct reg_names vector_names[] = {
+ { RADEON_VS_MATRIX_0_ADDR * 4, "MATRIX_0" },
+ { RADEON_VS_MATRIX_1_ADDR * 4, "MATRIX_1" },
+ { RADEON_VS_MATRIX_2_ADDR * 4, "MATRIX_2" },
+ { RADEON_VS_MATRIX_3_ADDR * 4, "MATRIX_3" },
+ { RADEON_VS_MATRIX_4_ADDR * 4, "MATRIX_4" },
+ { RADEON_VS_MATRIX_5_ADDR * 4, "MATRIX_5" },
+ { RADEON_VS_MATRIX_6_ADDR * 4, "MATRIX_6" },
+ { RADEON_VS_MATRIX_7_ADDR * 4, "MATRIX_7" },
+ { RADEON_VS_MATRIX_8_ADDR * 4, "MATRIX_8" },
+ { RADEON_VS_MATRIX_9_ADDR * 4, "MATRIX_9" },
+ { RADEON_VS_MATRIX_10_ADDR * 4, "MATRIX_10" },
+ { RADEON_VS_MATRIX_11_ADDR * 4, "MATRIX_11" },
+ { RADEON_VS_MATRIX_12_ADDR * 4, "MATRIX_12" },
+ { RADEON_VS_MATRIX_13_ADDR * 4, "MATRIX_13" },
+ { RADEON_VS_MATRIX_14_ADDR * 4, "MATRIX_14" },
+ { RADEON_VS_MATRIX_15_ADDR * 4, "MATRIX_15" },
+ { RADEON_VS_LIGHT_AMBIENT_ADDR * 4, "LIGHT_AMBIENT" },
+ { RADEON_VS_LIGHT_DIFFUSE_ADDR * 4, "LIGHT_DIFFUSE" },
+ { RADEON_VS_LIGHT_SPECULAR_ADDR * 4, "LIGHT_SPECULAR" },
+ { RADEON_VS_LIGHT_DIRPOS_ADDR * 4, "LIGHT_DIRPOS" },
+ { RADEON_VS_LIGHT_HWVSPOT_ADDR * 4, "LIGHT_HWVSPOT" },
+ { RADEON_VS_LIGHT_ATTENUATION_ADDR * 4, "LIGHT_ATTENUATION" },
+ { RADEON_VS_MATRIX_EYE2CLIP_ADDR * 4, "MATRIX_EYE2CLIP" },
+ { RADEON_VS_UCP_ADDR * 4, "UCP" },
+ { RADEON_VS_GLOBAL_AMBIENT_ADDR * 4, "GLOBAL_AMBIENT" },
+ { RADEON_VS_FOG_PARAM_ADDR * 4, "FOG_PARAM" },
+ { RADEON_VS_EYE_VECTOR_ADDR * 4, "EYE_VECTOR" },
+ { 1000, "" },
+};
+
+union fi { float f; int i; };
+
+#define ISVEC 1
+#define ISFLOAT 2
+#define TOUCHED 4
+
+struct reg {
+ int idx;
+ struct reg_names *closest;
+ int flags;
+ union fi current;
+ union fi *values;
+ int nvalues;
+ int nalloc;
+ float vmin, vmax;
+};
+
+
+static struct reg regs[Elements(reg_names)+1];
+static struct reg scalars[512+1];
+static struct reg vectors[512*4+1];
+
+static int total, total_changed, bufs;
+
+static void init_regs( void )
+{
+ struct reg_names *tmp;
+ int i;
+
+ for (i = 0 ; i < Elements(regs) ; i++) {
+ regs[i].idx = reg_names[i].idx;
+ regs[i].closest = &reg_names[i];
+ regs[i].flags = 0;
+ }
+
+ for (i = 0, tmp = scalar_names ; i < Elements(scalars) ; i++) {
+ if (tmp[1].idx == i) tmp++;
+ scalars[i].idx = i;
+ scalars[i].closest = tmp;
+ scalars[i].flags = ISFLOAT;
+ }
+
+ for (i = 0, tmp = vector_names ; i < Elements(vectors) ; i++) {
+ if (tmp[1].idx*4 == i) tmp++;
+ vectors[i].idx = i;
+ vectors[i].closest = tmp;
+ vectors[i].flags = ISFLOAT|ISVEC;
+ }
+
+ regs[Elements(regs)-1].idx = -1;
+ scalars[Elements(scalars)-1].idx = -1;
+ vectors[Elements(vectors)-1].idx = -1;
+}
+
+static int find_or_add_value( struct reg *reg, int val )
+{
+ int j;
+
+ for ( j = 0 ; j < reg->nvalues ; j++)
+ if ( val == reg->values[j].i )
+ return 1;
+
+ if (j == reg->nalloc) {
+ reg->nalloc += 5;
+ reg->nalloc *= 2;
+ reg->values = (union fi *) realloc( reg->values,
+ reg->nalloc * sizeof(union fi) );
+ }
+
+ reg->values[reg->nvalues++].i = val;
+ return 0;
+}
+
+static struct reg *lookup_reg( struct reg *tab, int reg )
+{
+ int i;
+
+ for (i = 0 ; tab[i].idx != -1 ; i++) {
+ if (tab[i].idx == reg)
+ return &tab[i];
+ }
+
+ fprintf(stderr, "*** unknown reg 0x%x\n", reg);
+ return 0;
+}
+
+
+static const char *get_reg_name( struct reg *reg )
+{
+ static char tmp[80];
+
+ if (reg->idx == reg->closest->idx)
+ return reg->closest->name;
+
+
+ if (reg->flags & ISVEC) {
+ if (reg->idx/4 != reg->closest->idx)
+ sprintf(tmp, "%s+%d[%d]",
+ reg->closest->name,
+ (reg->idx/4) - reg->closest->idx,
+ reg->idx%4);
+ else
+ sprintf(tmp, "%s[%d]", reg->closest->name, reg->idx%4);
+ }
+ else {
+ if (reg->idx != reg->closest->idx)
+ sprintf(tmp, "%s+%d", reg->closest->name, reg->idx - reg->closest->idx);
+ else
+ sprintf(tmp, "%s", reg->closest->name);
+ }
+
+ return tmp;
+}
+
+static int print_int_reg_assignment( struct reg *reg, int data )
+{
+ int changed = (reg->current.i != data);
+ int ever_seen = find_or_add_value( reg, data );
+
+ if (VERBOSE || (NORMAL && (changed || !ever_seen)))
+ fprintf(stderr, " %s <-- 0x%x", get_reg_name(reg), data);
+
+ if (NORMAL) {
+ if (!ever_seen)
+ fprintf(stderr, " *** BRAND NEW VALUE");
+ else if (changed)
+ fprintf(stderr, " *** CHANGED");
+ }
+
+ reg->current.i = data;
+
+ if (VERBOSE || (NORMAL && (changed || !ever_seen)))
+ fprintf(stderr, "\n");
+
+ return changed;
+}
+
+
+static int print_float_reg_assignment( struct reg *reg, float data )
+{
+ int changed = (reg->current.f != data);
+ int newmin = (data < reg->vmin);
+ int newmax = (data > reg->vmax);
+
+ if (VERBOSE || (NORMAL && (newmin || newmax || changed)))
+ fprintf(stderr, " %s <-- %.3f", get_reg_name(reg), data);
+
+ if (NORMAL) {
+ if (newmin) {
+ fprintf(stderr, " *** NEW MIN (prev %.3f)", reg->vmin);
+ reg->vmin = data;
+ }
+ else if (newmax) {
+ fprintf(stderr, " *** NEW MAX (prev %.3f)", reg->vmax);
+ reg->vmax = data;
+ }
+ else if (changed) {
+ fprintf(stderr, " *** CHANGED");
+ }
+ }
+
+ reg->current.f = data;
+
+ if (VERBOSE || (NORMAL && (newmin || newmax || changed)))
+ fprintf(stderr, "\n");
+
+ return changed;
+}
+
+static int print_reg_assignment( struct reg *reg, int data )
+{
+ reg->flags |= TOUCHED;
+ if (reg->flags & ISFLOAT)
+ return print_float_reg_assignment( reg, *(float *)&data );
+ else
+ return print_int_reg_assignment( reg, data );
+}
+
+static void print_reg( struct reg *reg )
+{
+ if (reg->flags & TOUCHED) {
+ if (reg->flags & ISFLOAT) {
+ fprintf(stderr, " %s == %f\n", get_reg_name(reg), reg->current.f);
+ } else {
+ fprintf(stderr, " %s == 0x%x\n", get_reg_name(reg), reg->current.i);
+ }
+ }
+}
+
+
+static void dump_state( void )
+{
+ int i;
+
+ for (i = 0 ; i < Elements(regs) ; i++)
+ print_reg( &regs[i] );
+
+ for (i = 0 ; i < Elements(scalars) ; i++)
+ print_reg( &scalars[i] );
+
+ for (i = 0 ; i < Elements(vectors) ; i++)
+ print_reg( &vectors[i] );
+}
+
+
+
+static int radeon_emit_packets(
+ drmRadeonCmdHeader header,
+ drmRadeonCmdBuffer *cmdbuf )
+{
+ int id = (int)header.packet.packet_id;
+ int sz = packet[id].len;
+ int *data = (int *)cmdbuf->buf;
+ int i;
+
+ if (sz * sizeof(int) > cmdbuf->bufsz) {
+ fprintf(stderr, "Packet overflows cmdbuf\n");
+ return -EINVAL;
+ }
+
+ if (!packet[id].name) {
+ fprintf(stderr, "*** Unknown packet 0 nr %d\n", id );
+ return -EINVAL;
+ }
+
+
+ if (VERBOSE)
+ fprintf(stderr, "Packet 0 reg %s nr %d\n", packet[id].name, sz );
+
+ for ( i = 0 ; i < sz ; i++) {
+ struct reg *reg = lookup_reg( regs, packet[id].start + i*4 );
+ if (print_reg_assignment( reg, data[i] ))
+ total_changed++;
+ total++;
+ }
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
+
+static int radeon_emit_scalars(
+ drmRadeonCmdHeader header,
+ drmRadeonCmdBuffer *cmdbuf )
+{
+ int sz = header.scalars.count;
+ int *data = (int *)cmdbuf->buf;
+ int start = header.scalars.offset;
+ int stride = header.scalars.stride;
+ int i;
+
+ if (VERBOSE)
+ fprintf(stderr, "emit scalars, start %d stride %d nr %d (end %d)\n",
+ start, stride, sz, start + stride * sz);
+
+
+ for (i = 0 ; i < sz ; i++, start += stride) {
+ struct reg *reg = lookup_reg( scalars, start );
+ if (print_reg_assignment( reg, data[i] ))
+ total_changed++;
+ total++;
+ }
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
+
+static int radeon_emit_scalars2(
+ drmRadeonCmdHeader header,
+ drmRadeonCmdBuffer *cmdbuf )
+{
+ int sz = header.scalars.count;
+ int *data = (int *)cmdbuf->buf;
+ int start = header.scalars.offset + 0x100;
+ int stride = header.scalars.stride;
+ int i;
+
+ if (VERBOSE)
+ fprintf(stderr, "emit scalars2, start %d stride %d nr %d (end %d)\n",
+ start, stride, sz, start + stride * sz);
+
+ if (start + stride * sz > 257) {
+ fprintf(stderr, "emit scalars OVERFLOW %d/%d/%d\n", start, stride, sz);
+ return -1;
+ }
+
+ for (i = 0 ; i < sz ; i++, start += stride) {
+ struct reg *reg = lookup_reg( scalars, start );
+ if (print_reg_assignment( reg, data[i] ))
+ total_changed++;
+ total++;
+ }
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
+/* Check: inf/nan/extreme-size?
+ * Check: table start, end, nr, etc.
+ */
+static int radeon_emit_vectors(
+ drmRadeonCmdHeader header,
+ drmRadeonCmdBuffer *cmdbuf )
+{
+ int sz = header.vectors.count;
+ int *data = (int *)cmdbuf->buf;
+ int start = header.vectors.offset;
+ int stride = header.vectors.stride;
+ int i,j;
+
+ if (VERBOSE)
+ fprintf(stderr, "emit vectors, start %d stride %d nr %d (end %d) (0x%x)\n",
+ start, stride, sz, start + stride * sz, header.i);
+
+/* if (start + stride * (sz/4) > 128) { */
+/* fprintf(stderr, "emit vectors OVERFLOW %d/%d/%d\n", start, stride, sz); */
+/* return -1; */
+/* } */
+
+ for (i = 0 ; i < sz ; start += stride) {
+ int changed = 0;
+ for (j = 0 ; j < 4 ; i++,j++) {
+ struct reg *reg = lookup_reg( vectors, start*4+j );
+ if (print_reg_assignment( reg, data[i] ))
+ changed = 1;
+ }
+ if (changed)
+ total_changed += 4;
+ total += 4;
+ }
+
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
+
+static int print_vertex_format( int vfmt )
+{
+ if (NORMAL) {
+ fprintf(stderr, " %s(%x): %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "vertex format",
+ vfmt,
+ "xy,",
+ (vfmt & RADEON_CP_VC_FRMT_Z) ? "z," : "",
+ (vfmt & RADEON_CP_VC_FRMT_W0) ? "w0," : "",
+ (vfmt & RADEON_CP_VC_FRMT_FPCOLOR) ? "fpcolor," : "",
+ (vfmt & RADEON_CP_VC_FRMT_FPALPHA) ? "fpalpha," : "",
+ (vfmt & RADEON_CP_VC_FRMT_PKCOLOR) ? "pkcolor," : "",
+ (vfmt & RADEON_CP_VC_FRMT_FPSPEC) ? "fpspec," : "",
+ (vfmt & RADEON_CP_VC_FRMT_FPFOG) ? "fpfog," : "",
+ (vfmt & RADEON_CP_VC_FRMT_PKSPEC) ? "pkspec," : "",
+ (vfmt & RADEON_CP_VC_FRMT_ST0) ? "st0," : "",
+ (vfmt & RADEON_CP_VC_FRMT_ST1) ? "st1," : "",
+ (vfmt & RADEON_CP_VC_FRMT_Q1) ? "q1," : "",
+ (vfmt & RADEON_CP_VC_FRMT_ST2) ? "st2," : "",
+ (vfmt & RADEON_CP_VC_FRMT_Q2) ? "q2," : "",
+ (vfmt & RADEON_CP_VC_FRMT_ST3) ? "st3," : "",
+ (vfmt & RADEON_CP_VC_FRMT_Q3) ? "q3," : "",
+ (vfmt & RADEON_CP_VC_FRMT_Q0) ? "q0," : "",
+ (vfmt & RADEON_CP_VC_FRMT_N0) ? "n0," : "",
+ (vfmt & RADEON_CP_VC_FRMT_XY1) ? "xy1," : "",
+ (vfmt & RADEON_CP_VC_FRMT_Z1) ? "z1," : "",
+ (vfmt & RADEON_CP_VC_FRMT_W1) ? "w1," : "",
+ (vfmt & RADEON_CP_VC_FRMT_N1) ? "n1," : "");
+
+
+/* if (!find_or_add_value( &others[V_VTXFMT], vfmt )) */
+/* fprintf(stderr, " *** NEW VALUE"); */
+
+ fprintf(stderr, "\n");
+ }
+
+ return 0;
+}
+
+static char *primname[0xf] = {
+ "NONE",
+ "POINTS",
+ "LINES",
+ "LINE_STRIP",
+ "TRIANGLES",
+ "TRIANGLE_FAN",
+ "TRIANGLE_STRIP",
+ "TRI_TYPE_2",
+ "RECT_LIST",
+ "3VRT_POINTS",
+ "3VRT_LINES",
+};
+
+static int print_prim_and_flags( int prim )
+{
+ int numverts;
+
+ if (NORMAL)
+ fprintf(stderr, " %s(%x): %s%s%s%s%s%s%s\n",
+ "prim flags",
+ prim,
+ ((prim & 0x30) == RADEON_CP_VC_CNTL_PRIM_WALK_IND) ? "IND," : "",
+ ((prim & 0x30) == RADEON_CP_VC_CNTL_PRIM_WALK_LIST) ? "LIST," : "",
+ ((prim & 0x30) == RADEON_CP_VC_CNTL_PRIM_WALK_RING) ? "RING," : "",
+ (prim & RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA) ? "RGBA," : "BGRA, ",
+ (prim & RADEON_CP_VC_CNTL_MAOS_ENABLE) ? "MAOS," : "",
+ (prim & RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE) ? "RADEON," : "",
+ (prim & RADEON_CP_VC_CNTL_TCL_ENABLE) ? "TCL," : "");
+
+ if ((prim & 0xf) > RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST) {
+ fprintf(stderr, " *** Bad primitive: %x\n", prim & 0xf);
+ return -1;
+ }
+
+ numverts = prim>>16;
+
+ if (NORMAL)
+ fprintf(stderr, " prim: %s numverts %d\n", primname[prim&0xf], numverts);
+
+ switch (prim & 0xf) {
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_NONE:
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_POINT:
+ if (numverts < 1) {
+ fprintf(stderr, "Bad nr verts for line %d\n", numverts);
+ return -1;
+ }
+ break;
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_LINE:
+ if ((numverts & 1) || numverts == 0) {
+ fprintf(stderr, "Bad nr verts for line %d\n", numverts);
+ return -1;
+ }
+ break;
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP:
+ if (numverts < 2) {
+ fprintf(stderr, "Bad nr verts for line_strip %d\n", numverts);
+ return -1;
+ }
+ break;
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST:
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_POINT_LIST:
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST:
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST:
+ if (numverts % 3 || numverts == 0) {
+ fprintf(stderr, "Bad nr verts for tri %d\n", numverts);
+ return -1;
+ }
+ break;
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN:
+ case RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP:
+ if (numverts < 3) {
+ fprintf(stderr, "Bad nr verts for strip/fan %d\n", numverts);
+ return -1;
+ }
+ break;
+ default:
+ fprintf(stderr, "Bad primitive\n");
+ return -1;
+ }
+ return 0;
+}
+
+/* build in knowledge about each packet type
+ */
+static int radeon_emit_packet3( drmRadeonCmdBuffer *cmdbuf )
+{
+ int cmdsz;
+ int *cmd = (int *)cmdbuf->buf;
+ int *tmp;
+ int i, stride, size, start;
+
+ cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+
+ if ((cmd[0] & RADEON_CP_PACKET_MASK) != RADEON_CP_PACKET3 ||
+ cmdsz * 4 > cmdbuf->bufsz ||
+ cmdsz > RADEON_CP_PACKET_MAX_DWORDS) {
+ fprintf(stderr, "Bad packet\n");
+ return -EINVAL;
+ }
+
+ switch( cmd[0] & ~RADEON_CP_PACKET_COUNT_MASK ) {
+ case RADEON_CP_PACKET3_NOP:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_NOP, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_NEXT_CHAR:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_NEXT_CHAR, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_PLY_NEXTSCAN:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_PLY_NEXTSCAN, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_SET_SCISSORS:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_SET_SCISSORS, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_3D_RNDR_GEN_INDX_PRIM, %d dwords\n",
+ cmdsz);
+ break;
+ case RADEON_CP_PACKET3_LOAD_MICROCODE:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_LOAD_MICROCODE, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_WAIT_FOR_IDLE:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_WAIT_FOR_IDLE, %d dwords\n", cmdsz);
+ break;
+
+ case RADEON_CP_PACKET3_3D_DRAW_VBUF:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_3D_DRAW_VBUF, %d dwords\n", cmdsz);
+ print_vertex_format(cmd[1]);
+ print_prim_and_flags(cmd[2]);
+ break;
+
+ case RADEON_CP_PACKET3_3D_DRAW_IMMD:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_3D_DRAW_IMMD, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_3D_DRAW_INDX: {
+ int neltdwords;
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_3D_DRAW_INDX, %d dwords\n", cmdsz);
+ print_vertex_format(cmd[1]);
+ print_prim_and_flags(cmd[2]);
+ neltdwords = cmd[2]>>16;
+ neltdwords += neltdwords & 1;
+ neltdwords /= 2;
+ if (neltdwords + 3 != cmdsz)
+ fprintf(stderr, "Mismatch in DRAW_INDX, %d vs cmdsz %d\n",
+ neltdwords, cmdsz);
+ break;
+ }
+ case RADEON_CP_PACKET3_LOAD_PALETTE:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_LOAD_PALETTE, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_3D_LOAD_VBPNTR:
+ if (NORMAL) {
+ fprintf(stderr, "PACKET3_3D_LOAD_VBPNTR, %d dwords\n", cmdsz);
+ fprintf(stderr, " nr arrays: %d\n", cmd[1]);
+ }
+
+ if (cmd[1]/2 + cmd[1]%2 != cmdsz - 3) {
+ fprintf(stderr, " ****** MISMATCH %d/%d *******\n",
+ cmd[1]/2 + cmd[1]%2 + 3, cmdsz);
+ return -EINVAL;
+ }
+
+ if (NORMAL) {
+ tmp = cmd+2;
+ for (i = 0 ; i < cmd[1] ; i++) {
+ if (i & 1) {
+ stride = (tmp[0]>>24) & 0xff;
+ size = (tmp[0]>>16) & 0xff;
+ start = tmp[2];
+ tmp += 3;
+ }
+ else {
+ stride = (tmp[0]>>8) & 0xff;
+ size = (tmp[0]) & 0xff;
+ start = tmp[1];
+ }
+ fprintf(stderr, " array %d: start 0x%x vsize %d vstride %d\n",
+ i, start, size, stride );
+ }
+ }
+ break;
+ case RADEON_CP_PACKET3_CNTL_PAINT:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_PAINT, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_BITBLT:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_BITBLT, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_SMALLTEXT:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_SMALLTEXT, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_HOSTDATA_BLT, %d dwords\n",
+ cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_POLYLINE:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_POLYLINE, %d dwords\n", cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_POLYSCANLINES:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_POLYSCANLINES, %d dwords\n",
+ cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_PAINT_MULTI:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_PAINT_MULTI, %d dwords\n",
+ cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_BITBLT_MULTI:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_BITBLT_MULTI, %d dwords\n",
+ cmdsz);
+ break;
+ case RADEON_CP_PACKET3_CNTL_TRANS_BITBLT:
+ if (NORMAL)
+ fprintf(stderr, "PACKET3_CNTL_TRANS_BITBLT, %d dwords\n",
+ cmdsz);
+ break;
+ default:
+ fprintf(stderr, "UNKNOWN PACKET, %d dwords\n", cmdsz);
+ break;
+ }
+
+ cmdbuf->buf += cmdsz * 4;
+ cmdbuf->bufsz -= cmdsz * 4;
+ return 0;
+}
+
+
+/* Check cliprects for bounds, then pass on to above:
+ */
+static int radeon_emit_packet3_cliprect( drmRadeonCmdBuffer *cmdbuf )
+{
+ XF86DRIClipRectRec *boxes = (XF86DRIClipRectRec *)cmdbuf->boxes;
+ int i = 0;
+
+ if (VERBOSE && total_changed) {
+ dump_state();
+ total_changed = 0;
+ }
+ else fprintf(stderr, "total_changed zero\n");
+
+ if (NORMAL) {
+ do {
+ if ( i < cmdbuf->nbox ) {
+ fprintf(stderr, "Emit box %d/%d %d,%d %d,%d\n",
+ i, cmdbuf->nbox,
+ boxes[i].x1, boxes[i].y1, boxes[i].x2, boxes[i].y2);
+ }
+ } while ( ++i < cmdbuf->nbox );
+ }
+
+ if (cmdbuf->nbox == 1)
+ cmdbuf->nbox = 0;
+
+ return radeon_emit_packet3( cmdbuf );
+}
+
+
+int radeonSanityCmdBuffer( radeonContextPtr rmesa,
+ int nbox,
+ XF86DRIClipRectRec *boxes )
+{
+ int idx;
+ drmRadeonCmdBuffer cmdbuf;
+ drmRadeonCmdHeader header;
+ static int inited = 0;
+
+ if (!inited) {
+ init_regs();
+ inited = 1;
+ }
+
+ cmdbuf.buf = rmesa->store.cmd_buf;
+ cmdbuf.bufsz = rmesa->store.cmd_used;
+ cmdbuf.boxes = (drmClipRect *)boxes;
+ cmdbuf.nbox = nbox;
+
+ while ( cmdbuf.bufsz >= sizeof(header) ) {
+
+ header.i = *(int *)cmdbuf.buf;
+ cmdbuf.buf += sizeof(header);
+ cmdbuf.bufsz -= sizeof(header);
+
+ switch (header.header.cmd_type) {
+ case RADEON_CMD_PACKET:
+ if (radeon_emit_packets( header, &cmdbuf )) {
+ fprintf(stderr,"radeon_emit_packets failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_SCALARS:
+ if (radeon_emit_scalars( header, &cmdbuf )) {
+ fprintf(stderr,"radeon_emit_scalars failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_SCALARS2:
+ if (radeon_emit_scalars2( header, &cmdbuf )) {
+ fprintf(stderr,"radeon_emit_scalars failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_VECTORS:
+ if (radeon_emit_vectors( header, &cmdbuf )) {
+ fprintf(stderr,"radeon_emit_vectors failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_DMA_DISCARD:
+ idx = header.dma.buf_idx;
+ if (NORMAL)
+ fprintf(stderr, "RADEON_CMD_DMA_DISCARD buf %d\n", idx);
+ bufs++;
+ break;
+
+ case RADEON_CMD_PACKET3:
+ if (radeon_emit_packet3( &cmdbuf )) {
+ fprintf(stderr,"radeon_emit_packet3 failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_PACKET3_CLIP:
+ if (radeon_emit_packet3_cliprect( &cmdbuf )) {
+ fprintf(stderr,"radeon_emit_packet3_clip failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_WAIT:
+ break;
+
+ default:
+ fprintf(stderr,"bad cmd_type %d at %p\n",
+ header.header.cmd_type,
+ cmdbuf.buf - sizeof(header));
+ return -EINVAL;
+ }
+ }
+
+ if (0)
+ {
+ static int n = 0;
+ n++;
+ if (n == 10) {
+ fprintf(stderr, "Bufs %d Total emitted %d real changes %d (%.2f%%)\n",
+ bufs,
+ total, total_changed,
+ ((float)total_changed/(float)total*100.0));
+ fprintf(stderr, "Total emitted per buf: %.2f\n",
+ (float)total/(float)bufs);
+ fprintf(stderr, "Real changes per buf: %.2f\n",
+ (float)total_changed/(float)bufs);
+
+ bufs = n = total = total_changed = 0;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_sanity.h b/src/mesa/drivers/dri/radeon/radeon_sanity.h
new file mode 100644
index 0000000000..58e8335dd6
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_sanity.h
@@ -0,0 +1,8 @@
+#ifndef RADEON_SANITY_H
+#define RADEON_SANITY_H
+
+extern int radeonSanityCmdBuffer( radeonContextPtr rmesa,
+ int nbox,
+ XF86DRIClipRectRec *boxes );
+
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_screen.c b/src/mesa/drivers/dri/radeon/radeon_screen.c
new file mode 100644
index 0000000000..ec8ed42d64
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_screen.c
@@ -0,0 +1,421 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c,v 1.6 2002/12/16 16:18:58 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include "glheader.h"
+#include "imports.h"
+
+#include "radeon_context.h"
+#include "radeon_screen.h"
+#include "radeon_macros.h"
+
+#include "utils.h"
+#include "context.h"
+#include "vblank.h"
+
+#ifndef _SOLO
+#include "glxextensions.h"
+#endif
+
+#if 1
+/* Including xf86PciInfo.h introduces a bunch of errors...
+ */
+#define PCI_CHIP_RADEON_QD 0x5144
+#define PCI_CHIP_RADEON_QE 0x5145
+#define PCI_CHIP_RADEON_QF 0x5146
+#define PCI_CHIP_RADEON_QG 0x5147
+
+#define PCI_CHIP_RADEON_QY 0x5159
+#define PCI_CHIP_RADEON_QZ 0x515A
+
+#define PCI_CHIP_RADEON_LW 0x4C57 /* mobility 7 - has tcl */
+
+#define PCI_CHIP_RADEON_LY 0x4C59
+#define PCI_CHIP_RADEON_LZ 0x4C5A
+
+#define PCI_CHIP_RV200_QW 0x5157 /* Radeon 7500 - not an R200 at all */
+#endif
+
+static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
+
+/* Create the device specific screen private data struct.
+ */
+radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv )
+{
+ radeonScreenPtr screen;
+ RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv;
+
+ if ( ! driCheckDriDdxDrmVersions( sPriv, "Radeon", 4, 0, 4, 0, 1, 3 ) )
+ return NULL;
+
+ /* Allocate the private area */
+ screen = (radeonScreenPtr) CALLOC( sizeof(*screen) );
+ if ( !screen ) {
+ __driUtilMessage("%s: Could not allocate memory for screen structure",
+ __FUNCTION__);
+ return NULL;
+ }
+
+ if ( sPriv->drmMinor < 3 ||
+ getenv("RADEON_COMPAT")) {
+ fprintf( stderr, "Radeon DRI driver:\n\t"
+ "Compatibility mode for DRM driver version %d.%d.%d\n\t"
+ "TCL will be disabled, expect reduced performance\n\t"
+ "(prefer DRM radeon.o 1.3.x or newer)\n\t",
+ sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch );
+ }
+
+
+ /* This is first since which regions we map depends on whether or
+ * not we are using a PCI card.
+ */
+ screen->IsPCI = dri_priv->IsPCI;
+
+ if (sPriv->drmMinor >= 3) {
+ int ret;
+ drmRadeonGetParam gp;
+
+ gp.param = RADEON_PARAM_AGP_BUFFER_OFFSET;
+ gp.value = &screen->agp_buffer_offset;
+
+ ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
+ &gp, sizeof(gp));
+ if (ret) {
+ fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_AGP_BUFFER_OFFSET): %d\n", ret);
+ return NULL;
+ }
+
+ if (sPriv->drmMinor >= 6) {
+ gp.param = RADEON_PARAM_IRQ_NR;
+ gp.value = &screen->irq;
+
+ ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM,
+ &gp, sizeof(gp));
+ if (ret) {
+ FREE( screen );
+ fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_IRQ_NR): %d\n", ret);
+ return NULL;
+ }
+ }
+ }
+
+ screen->mmio.handle = dri_priv->registerHandle;
+ screen->mmio.size = dri_priv->registerSize;
+ if ( drmMap( sPriv->fd,
+ screen->mmio.handle,
+ screen->mmio.size,
+ &screen->mmio.map ) ) {
+ FREE( screen );
+ __driUtilMessage("%s: drmMap failed\n", __FUNCTION__ );
+ return NULL;
+ }
+
+ screen->status.handle = dri_priv->statusHandle;
+ screen->status.size = dri_priv->statusSize;
+ if ( drmMap( sPriv->fd,
+ screen->status.handle,
+ screen->status.size,
+ &screen->status.map ) ) {
+ drmUnmap( screen->mmio.map, screen->mmio.size );
+ FREE( screen );
+ __driUtilMessage("%s: drmMap (2) failed\n", __FUNCTION__ );
+ return NULL;
+ }
+ screen->scratch = (__volatile__ CARD32 *)
+ ((GLubyte *)screen->status.map + RADEON_SCRATCH_REG_OFFSET);
+
+ screen->buffers = drmMapBufs( sPriv->fd );
+ if ( !screen->buffers ) {
+ drmUnmap( screen->status.map, screen->status.size );
+ drmUnmap( screen->mmio.map, screen->mmio.size );
+ FREE( screen );
+ __driUtilMessage("%s: drmMapBufs failed\n", __FUNCTION__ );
+ return NULL;
+ }
+
+ if ( !screen->IsPCI ) {
+ screen->agpTextures.handle = dri_priv->agpTexHandle;
+ screen->agpTextures.size = dri_priv->agpTexMapSize;
+ if ( drmMap( sPriv->fd,
+ screen->agpTextures.handle,
+ screen->agpTextures.size,
+ (drmAddressPtr)&screen->agpTextures.map ) ) {
+ drmUnmapBufs( screen->buffers );
+ drmUnmap( screen->status.map, screen->status.size );
+ drmUnmap( screen->mmio.map, screen->mmio.size );
+ FREE( screen );
+ __driUtilMessage("%s: IsPCI failed\n", __FUNCTION__);
+ return NULL;
+ }
+ }
+
+ screen->chipset = 0;
+ switch ( dri_priv->deviceID ) {
+ default:
+ fprintf(stderr, "unknown chip id, assuming full radeon support\n");
+ case PCI_CHIP_RADEON_QD:
+ case PCI_CHIP_RADEON_QE:
+ case PCI_CHIP_RADEON_QF:
+ case PCI_CHIP_RADEON_QG:
+ case PCI_CHIP_RV200_QW:
+ case PCI_CHIP_RADEON_LW:
+ screen->chipset |= RADEON_CHIPSET_TCL;
+ case PCI_CHIP_RADEON_QY:
+ case PCI_CHIP_RADEON_QZ:
+ case PCI_CHIP_RADEON_LY:
+ case PCI_CHIP_RADEON_LZ:
+ break;
+ }
+
+ screen->cpp = dri_priv->bpp / 8;
+ screen->AGPMode = dri_priv->AGPMode;
+
+ screen->frontOffset = dri_priv->frontOffset;
+ screen->frontPitch = dri_priv->frontPitch;
+ screen->backOffset = dri_priv->backOffset;
+ screen->backPitch = dri_priv->backPitch;
+ screen->depthOffset = dri_priv->depthOffset;
+ screen->depthPitch = dri_priv->depthPitch;
+
+ screen->texOffset[RADEON_CARD_HEAP] = dri_priv->textureOffset;
+ screen->texSize[RADEON_CARD_HEAP] = dri_priv->textureSize;
+ screen->logTexGranularity[RADEON_CARD_HEAP] =
+ dri_priv->log2TexGran;
+
+ if ( screen->IsPCI
+ || getenv( "RADEON_AGPTEXTURING_FORCE_DISABLE" ) ) {
+ screen->numTexHeaps = RADEON_NR_TEX_HEAPS - 1;
+ screen->texOffset[RADEON_AGP_HEAP] = 0;
+ screen->texSize[RADEON_AGP_HEAP] = 0;
+ screen->logTexGranularity[RADEON_AGP_HEAP] = 0;
+ } else {
+ screen->numTexHeaps = RADEON_NR_TEX_HEAPS;
+ screen->texOffset[RADEON_AGP_HEAP] =
+ dri_priv->agpTexOffset + RADEON_AGP_TEX_OFFSET;
+ screen->texSize[RADEON_AGP_HEAP] = dri_priv->agpTexMapSize;
+ screen->logTexGranularity[RADEON_AGP_HEAP] =
+ dri_priv->log2AGPTexGran;
+ }
+
+ screen->driScreen = sPriv;
+ screen->sarea_priv_offset = dri_priv->sarea_priv_offset;
+ return screen;
+}
+
+/* Destroy the device specific screen private data struct.
+ */
+void radeonDestroyScreen( __DRIscreenPrivate *sPriv )
+{
+ radeonScreenPtr screen = (radeonScreenPtr)sPriv->private;
+
+ if (!screen)
+ return;
+
+ if ( !screen->IsPCI ) {
+ drmUnmap( screen->agpTextures.map,
+ screen->agpTextures.size );
+ }
+ drmUnmapBufs( screen->buffers );
+ drmUnmap( screen->status.map, screen->status.size );
+ drmUnmap( screen->mmio.map, screen->mmio.size );
+
+ FREE( screen );
+ sPriv->private = NULL;
+}
+
+
+/* Initialize the driver specific screen private data.
+ */
+static GLboolean
+radeonInitDriver( __DRIscreenPrivate *sPriv )
+{
+ sPriv->private = (void *) radeonCreateScreen( sPriv );
+ if ( !sPriv->private ) {
+ radeonDestroyScreen( sPriv );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+
+/* Create and initialize the Mesa and driver specific pixmap buffer
+ * data.
+ */
+static GLboolean
+radeonCreateBuffer( __DRIscreenPrivate *driScrnPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ const __GLcontextModes *mesaVis,
+ GLboolean isPixmap )
+{
+ if (isPixmap) {
+ return GL_FALSE; /* not implemented */
+ }
+ else {
+ const GLboolean swDepth = GL_FALSE;
+ const GLboolean swAlpha = GL_FALSE;
+ const GLboolean swAccum = mesaVis->accumRedBits > 0;
+ const GLboolean swStencil = mesaVis->stencilBits > 0 &&
+ mesaVis->depthBits != 24;
+ driDrawPriv->driverPrivate = (void *)
+ _mesa_create_framebuffer( mesaVis,
+ swDepth,
+ swStencil,
+ swAccum,
+ swAlpha );
+ return (driDrawPriv->driverPrivate != NULL);
+ }
+}
+
+
+static void
+radeonDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
+{
+ _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
+}
+
+
+
+
+/* Fullscreen mode isn't used for much -- could be a way to shrink
+ * front/back buffers & get more texture memory if the client has
+ * changed the video resolution.
+ *
+ * Pageflipping is now done automatically whenever there is a single
+ * 3d client.
+ */
+static GLboolean
+radeonOpenCloseFullScreen( __DRIcontextPrivate *driContextPriv )
+{
+ return GL_TRUE;
+}
+
+static struct __DriverAPIRec radeonAPI = {
+ .InitDriver = radeonInitDriver,
+ .DestroyScreen = radeonDestroyScreen,
+ .CreateContext = radeonCreateContext,
+ .DestroyContext = radeonDestroyContext,
+ .CreateBuffer = radeonCreateBuffer,
+ .DestroyBuffer = radeonDestroyBuffer,
+ .SwapBuffers = radeonSwapBuffers,
+ .MakeCurrent = radeonMakeCurrent,
+ .UnbindContext = radeonUnbindContext,
+ .OpenFullScreen = radeonOpenCloseFullScreen,
+ .CloseFullScreen = radeonOpenCloseFullScreen,
+ .GetSwapInfo = getSwapInfo,
+ .GetMSC = driGetMSC32,
+ .WaitForMSC = driWaitForMSC32,
+ .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.
+ */
+#ifndef _SOLO
+void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
+ int numConfigs, __GLXvisualConfig *config)
+{
+ __DRIscreenPrivate *psp;
+ psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &radeonAPI);
+ return (void *) psp;
+}
+#else
+void *__driCreateScreen(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext)
+{
+ __DRIscreenPrivate *psp;
+ psp = __driUtilCreateScreen(driver, driverContext, &radeonAPI);
+ return (void *) psp;
+}
+#endif
+
+
+#ifndef _SOLO
+/* This function is called by libGL.so as soon as libGL.so is loaded.
+ * This is where we'd register new extension functions with the dispatcher.
+ */
+void
+__driRegisterExtensions( void )
+{
+ PFNGLXENABLEEXTENSIONPROC glx_enable_extension;
+
+
+ if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
+ glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC)
+ glXGetProcAddress( "__glXEnableExtension" );
+
+ if ( glx_enable_extension != NULL ) {
+ glx_enable_extension( "GLX_SGI_swap_control", GL_FALSE );
+ glx_enable_extension( "GLX_SGI_video_sync", GL_FALSE );
+ glx_enable_extension( "GLX_MESA_swap_control", GL_FALSE );
+ glx_enable_extension( "GLX_MESA_swap_frame_usage", GL_FALSE );
+ }
+ }
+}
+#endif
+
+
+/**
+ * Get information about previous buffer swaps.
+ */
+static int
+getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo )
+{
+ radeonContextPtr rmesa;
+
+ if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL)
+ || (dPriv->driContextPriv->driverPrivate == NULL)
+ || (sInfo == NULL) ) {
+ return -1;
+ }
+
+ rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
+ sInfo->swap_count = rmesa->swap_count;
+ sInfo->swap_ust = rmesa->swap_ust;
+ sInfo->swap_missed_count = rmesa->swap_missed_count;
+
+ sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
+ ? driCalculateSwapUsage( dPriv, 0, rmesa->swap_missed_ust )
+ : 0.0;
+
+ return 0;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_screen.h b/src/mesa/drivers/dri/radeon/radeon_screen.h
new file mode 100644
index 0000000000..2c69d8657a
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_screen.h
@@ -0,0 +1,101 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h,v 1.5 2002/12/16 16:18:58 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __RADEON_SCREEN_H__
+#define __RADEON_SCREEN_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+/*
+ * IMPORTS: these headers contain all the DRI, X and kernel-related
+ * definitions that we need.
+ */
+#include "dri_util.h"
+#include "radeon_common.h"
+#include "radeon_dri.h"
+#include "radeon_reg.h"
+#include "radeon_sarea.h"
+
+
+typedef struct {
+ drmHandle handle; /* Handle to the DRM region */
+ drmSize size; /* Size of the DRM region */
+ drmAddress map; /* Mapping of the DRM region */
+} radeonRegionRec, *radeonRegionPtr;
+
+/* chipset features */
+#define RADEON_CHIPSET_TCL (1 << 0)
+
+typedef struct {
+
+ int chipset;
+ int cpp;
+ int IsPCI; /* Current card is a PCI card */
+ int AGPMode;
+ unsigned int irq; /* IRQ number (0 means none) */
+
+ unsigned int frontOffset;
+ unsigned int frontPitch;
+ unsigned int backOffset;
+ unsigned int backPitch;
+
+ unsigned int depthOffset;
+ unsigned int depthPitch;
+
+ /* Shared texture data */
+ int numTexHeaps;
+ int texOffset[RADEON_NR_TEX_HEAPS];
+ int texSize[RADEON_NR_TEX_HEAPS];
+ int logTexGranularity[RADEON_NR_TEX_HEAPS];
+
+ radeonRegionRec mmio;
+ radeonRegionRec status;
+ radeonRegionRec agpTextures;
+
+ drmBufMapPtr buffers;
+
+ __volatile__ CARD32 *scratch;
+
+ __DRIscreenPrivate *driScreen;
+ unsigned int sarea_priv_offset;
+ unsigned int agp_buffer_offset; /* offset in card memory space */
+} radeonScreenRec, *radeonScreenPtr;
+
+extern radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv );
+extern void radeonDestroyScreen( __DRIscreenPrivate *sPriv );
+
+#endif
+#endif /* __RADEON_SCREEN_H__ */
diff --git a/src/mesa/drivers/dri/radeon/radeon_span.c b/src/mesa/drivers/dri/radeon/radeon_span.c
new file mode 100644
index 0000000000..029d7cd8ee
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_span.c
@@ -0,0 +1,415 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.c,v 1.6 2002/10/30 12:51:56 alanh Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#include "glheader.h"
+#include "swrast/swrast.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_span.h"
+#include "radeon_tex.h"
+
+#define DBG 0
+
+#define LOCAL_VARS \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ radeonScreenPtr radeonScreen = rmesa->radeonScreen; \
+ __DRIscreenPrivate *sPriv = rmesa->dri.screen; \
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \
+ GLuint pitch = radeonScreen->frontPitch * radeonScreen->cpp; \
+ GLuint height = dPriv->h; \
+ char *buf = (char *)(sPriv->pFB + \
+ rmesa->state.color.drawOffset + \
+ (dPriv->x * radeonScreen->cpp) + \
+ (dPriv->y * pitch)); \
+ char *read_buf = (char *)(sPriv->pFB + \
+ rmesa->state.pixel.readOffset + \
+ (dPriv->x * radeonScreen->cpp) + \
+ (dPriv->y * pitch)); \
+ GLuint p; \
+ (void) read_buf; (void) buf; (void) p
+
+#define LOCAL_DEPTH_VARS \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ radeonScreenPtr radeonScreen = rmesa->radeonScreen; \
+ __DRIscreenPrivate *sPriv = rmesa->dri.screen; \
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \
+ GLuint height = dPriv->h; \
+ GLuint xo = dPriv->x; \
+ GLuint yo = dPriv->y; \
+ char *buf = (char *)(sPriv->pFB + radeonScreen->depthOffset); \
+ (void) buf
+
+#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS
+
+
+#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_LOCK()
+
+#define HW_CLIPLOOP() \
+ do { \
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \
+ int _nc = dPriv->numClipRects; \
+ \
+ while ( _nc-- ) { \
+ int minx = dPriv->pClipRects[_nc].x1 - dPriv->x; \
+ int miny = dPriv->pClipRects[_nc].y1 - dPriv->y; \
+ int maxx = dPriv->pClipRects[_nc].x2 - dPriv->x; \
+ int maxy = dPriv->pClipRects[_nc].y2 - dPriv->y;
+
+#define HW_ENDCLIPLOOP() \
+ } \
+ } while (0)
+
+#define HW_UNLOCK()
+
+
+
+/* ================================================================
+ * Color buffer
+ */
+
+/* 16 bit, RGB565 color spanline and pixel functions
+ */
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_565( 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 *)(read_buf + _x*2 + _y*pitch); \
+ rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \
+ rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \
+ rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \
+ rgba[3] = 0xff; \
+ } while (0)
+
+#define TAG(x) radeon##x##_RGB565
+#include "spantmp.h"
+
+/* 32 bit, ARGB8888 color spanline and pixel functions
+ */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_8888( color[3], color[0], color[1], color[2] )
+
+#define WRITE_RGBA( _x, _y, r, g, b, a ) \
+do { \
+ *(GLuint *)(buf + _x*4 + _y*pitch) = ((b << 0) | \
+ (g << 8) | \
+ (r << 16) | \
+ (a << 24) ); \
+} while (0)
+
+#define WRITE_PIXEL( _x, _y, p ) \
+do { \
+ *(GLuint *)(buf + _x*4 + _y*pitch) = p; \
+} while (0)
+
+#define READ_RGBA( rgba, _x, _y ) \
+do { \
+ volatile GLuint *ptr = (volatile GLuint *)(read_buf + _x*4 + _y*pitch); \
+ GLuint p = *ptr; \
+ 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) radeon##x##_ARGB8888
+#include "spantmp.h"
+
+
+
+/* ================================================================
+ * Depth buffer
+ */
+
+/* The Radeon family has depth tiling on all the time, so we have to convert
+ * the x,y coordinates into the memory bus address (mba) in the same
+ * manner as the engine. In each case, the linear block address (ba)
+ * is calculated, and then wired with x and y to produce the final
+ * memory address.
+ */
+
+static GLuint radeon_mba_z32( radeonContextPtr rmesa,
+ GLint x, GLint y )
+{
+ GLuint pitch = rmesa->radeonScreen->frontPitch;
+ GLuint ba, address = 0; /* a[0..1] = 0 */
+
+ ba = (y / 16) * (pitch / 16) + (x / 16);
+
+ address |= (x & 0x7) << 2; /* a[2..4] = x[0..2] */
+ address |= (y & 0x3) << 5; /* a[5..6] = y[0..1] */
+ address |=
+ (((x & 0x10) >> 2) ^ (y & 0x4)) << 5; /* a[7] = x[4] ^ y[2] */
+ address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */
+
+ address |= (y & 0x8) << 7; /* a[10] = y[3] */
+ address |=
+ (((x & 0x8) << 1) ^ (y & 0x10)) << 7; /* a[11] = x[3] ^ y[4] */
+ address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */
+
+ return address;
+}
+
+static __inline GLuint radeon_mba_z16( radeonContextPtr rmesa, GLint x, GLint y )
+{
+ GLuint pitch = rmesa->radeonScreen->frontPitch;
+ GLuint ba, address = 0; /* a[0] = 0 */
+
+ ba = (y / 16) * (pitch / 32) + (x / 32);
+
+ address |= (x & 0x7) << 1; /* a[1..3] = x[0..2] */
+ address |= (y & 0x7) << 4; /* a[4..6] = y[0..2] */
+ address |= (x & 0x8) << 4; /* a[7] = x[3] */
+ address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */
+ address |= (y & 0x8) << 7; /* a[10] = y[3] */
+ address |= ((x & 0x10) ^ (y & 0x10)) << 7; /* a[11] = x[4] ^ y[4] */
+ address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */
+
+ return address;
+}
+
+
+/* 16-bit depth buffer functions
+ */
+#define WRITE_DEPTH( _x, _y, d ) \
+ *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo )) = d;
+
+#define READ_DEPTH( d, _x, _y ) \
+ d = *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo ));
+
+#define TAG(x) radeon##x##_16
+#include "depthtmp.h"
+
+/* 24 bit depth, 8 bit stencil depthbuffer functions
+ */
+#define WRITE_DEPTH( _x, _y, d ) \
+do { \
+ GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \
+ GLuint tmp = *(GLuint *)(buf + offset); \
+ tmp &= 0xff000000; \
+ tmp |= ((d) & 0x00ffffff); \
+ *(GLuint *)(buf + offset) = tmp; \
+} while (0)
+
+#define READ_DEPTH( d, _x, _y ) \
+ d = *(GLuint *)(buf + radeon_mba_z32( rmesa, _x + xo, \
+ _y + yo )) & 0x00ffffff;
+
+#define TAG(x) radeon##x##_24_8
+#include "depthtmp.h"
+
+
+/* ================================================================
+ * Stencil buffer
+ */
+
+/* 24 bit depth, 8 bit stencil depthbuffer functions
+ */
+#define WRITE_STENCIL( _x, _y, d ) \
+do { \
+ GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \
+ GLuint tmp = *(GLuint *)(buf + offset); \
+ tmp &= 0x00ffffff; \
+ tmp |= (((d) & 0xff) << 24); \
+ *(GLuint *)(buf + offset) = tmp; \
+} while (0)
+
+#define READ_STENCIL( d, _x, _y ) \
+do { \
+ GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \
+ GLuint tmp = *(GLuint *)(buf + offset); \
+ tmp &= 0xff000000; \
+ d = tmp >> 24; \
+} while (0)
+
+#define TAG(x) radeon##x##_24_8
+#include "stenciltmp.h"
+
+
+/*
+ * This function is called to specify which buffer to read and write
+ * for software rasterization (swrast) fallbacks. This doesn't necessarily
+ * correspond to glDrawBuffer() or glReadBuffer() calls.
+ */
+static void radeonSetBuffer( GLcontext *ctx,
+ GLframebuffer *colorBuffer,
+ GLuint bufferBit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ switch ( bufferBit ) {
+ case FRONT_LEFT_BIT:
+ if ( rmesa->sarea->pfCurrentPage == 1 ) {
+ rmesa->state.pixel.readOffset = rmesa->radeonScreen->backOffset;
+ rmesa->state.pixel.readPitch = rmesa->radeonScreen->backPitch;
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch;
+ } else {
+ rmesa->state.pixel.readOffset = rmesa->radeonScreen->frontOffset;
+ rmesa->state.pixel.readPitch = rmesa->radeonScreen->frontPitch;
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch;
+ }
+ break;
+ case BACK_LEFT_BIT:
+ if ( rmesa->sarea->pfCurrentPage == 1 ) {
+ rmesa->state.pixel.readOffset = rmesa->radeonScreen->frontOffset;
+ rmesa->state.pixel.readPitch = rmesa->radeonScreen->frontPitch;
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch;
+ } else {
+ rmesa->state.pixel.readOffset = rmesa->radeonScreen->backOffset;
+ rmesa->state.pixel.readPitch = rmesa->radeonScreen->backPitch;
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch;
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+/* Move locking out to get reasonable span performance (10x better
+ * than doing this in HW_LOCK above). WaitForIdle() is the main
+ * culprit.
+ */
+
+static void radeonSpanRenderStart( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ RADEON_FIREVERTICES( rmesa );
+ LOCK_HARDWARE( rmesa );
+ radeonWaitForIdleLocked( rmesa );
+}
+
+static void radeonSpanRenderFinish( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ _swrast_flush( ctx );
+ UNLOCK_HARDWARE( rmesa );
+}
+
+void radeonInitSpanFuncs( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx);
+
+ swdd->SetBuffer = radeonSetBuffer;
+
+ switch ( rmesa->radeonScreen->cpp ) {
+ case 2:
+ swdd->WriteRGBASpan = radeonWriteRGBASpan_RGB565;
+ swdd->WriteRGBSpan = radeonWriteRGBSpan_RGB565;
+ swdd->WriteMonoRGBASpan = radeonWriteMonoRGBASpan_RGB565;
+ swdd->WriteRGBAPixels = radeonWriteRGBAPixels_RGB565;
+ swdd->WriteMonoRGBAPixels = radeonWriteMonoRGBAPixels_RGB565;
+ swdd->ReadRGBASpan = radeonReadRGBASpan_RGB565;
+ swdd->ReadRGBAPixels = radeonReadRGBAPixels_RGB565;
+ break;
+
+ case 4:
+ swdd->WriteRGBASpan = radeonWriteRGBASpan_ARGB8888;
+ swdd->WriteRGBSpan = radeonWriteRGBSpan_ARGB8888;
+ swdd->WriteMonoRGBASpan = radeonWriteMonoRGBASpan_ARGB8888;
+ swdd->WriteRGBAPixels = radeonWriteRGBAPixels_ARGB8888;
+ swdd->WriteMonoRGBAPixels = radeonWriteMonoRGBAPixels_ARGB8888;
+ swdd->ReadRGBASpan = radeonReadRGBASpan_ARGB8888;
+ swdd->ReadRGBAPixels = radeonReadRGBAPixels_ARGB8888;
+ break;
+
+ default:
+ break;
+ }
+
+ switch ( rmesa->glCtx->Visual.depthBits ) {
+ case 16:
+ swdd->ReadDepthSpan = radeonReadDepthSpan_16;
+ swdd->WriteDepthSpan = radeonWriteDepthSpan_16;
+ swdd->ReadDepthPixels = radeonReadDepthPixels_16;
+ swdd->WriteDepthPixels = radeonWriteDepthPixels_16;
+ break;
+
+ case 24:
+ swdd->ReadDepthSpan = radeonReadDepthSpan_24_8;
+ swdd->WriteDepthSpan = radeonWriteDepthSpan_24_8;
+ swdd->ReadDepthPixels = radeonReadDepthPixels_24_8;
+ swdd->WriteDepthPixels = radeonWriteDepthPixels_24_8;
+
+ swdd->ReadStencilSpan = radeonReadStencilSpan_24_8;
+ swdd->WriteStencilSpan = radeonWriteStencilSpan_24_8;
+ swdd->ReadStencilPixels = radeonReadStencilPixels_24_8;
+ swdd->WriteStencilPixels = radeonWriteStencilPixels_24_8;
+ break;
+
+ default:
+ break;
+ }
+
+ swdd->SpanRenderStart = radeonSpanRenderStart;
+ swdd->SpanRenderFinish = radeonSpanRenderFinish;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_span.h b/src/mesa/drivers/dri/radeon/radeon_span.h
new file mode 100644
index 0000000000..011e8eff57
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_span.h
@@ -0,0 +1,45 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.h,v 1.2 2002/02/22 21:45:01 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __RADEON_SPAN_H__
+#define __RADEON_SPAN_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void radeonInitSpanFuncs( GLcontext *ctx );
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_state.c b/src/mesa/drivers/dri/radeon/radeon_state.c
new file mode 100644
index 0000000000..7b1bbe75fd
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_state.c
@@ -0,0 +1,2211 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.c,v 1.8 2002/12/16 16:18:58 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "api_arrayelt.h"
+#include "enums.h"
+#include "colormac.h"
+#include "state.h"
+
+#include "swrast/swrast.h"
+#include "array_cache/acache.h"
+#include "tnl/tnl.h"
+#include "tnl/t_pipeline.h"
+#include "main/light.h"
+#include "swrast_setup/swrast_setup.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_tcl.h"
+#include "radeon_tex.h"
+#include "radeon_swtcl.h"
+#include "radeon_vtxfmt.h"
+
+/* =============================================================
+ * Alpha blending
+ */
+
+static void radeonAlphaFunc( GLcontext *ctx, GLenum func, GLfloat ref )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ int pp_misc = rmesa->hw.ctx.cmd[CTX_PP_MISC];
+ GLubyte refByte;
+
+ CLAMPED_FLOAT_TO_UBYTE(refByte, ref);
+
+ RADEON_STATECHANGE( rmesa, ctx );
+
+ pp_misc &= ~(RADEON_ALPHA_TEST_OP_MASK | RADEON_REF_ALPHA_MASK);
+ pp_misc |= (refByte & RADEON_REF_ALPHA_MASK);
+
+ switch ( func ) {
+ case GL_NEVER:
+ pp_misc |= RADEON_ALPHA_TEST_FAIL;
+ break;
+ case GL_LESS:
+ pp_misc |= RADEON_ALPHA_TEST_LESS;
+ break;
+ case GL_EQUAL:
+ pp_misc |= RADEON_ALPHA_TEST_EQUAL;
+ break;
+ case GL_LEQUAL:
+ pp_misc |= RADEON_ALPHA_TEST_LEQUAL;
+ break;
+ case GL_GREATER:
+ pp_misc |= RADEON_ALPHA_TEST_GREATER;
+ break;
+ case GL_NOTEQUAL:
+ pp_misc |= RADEON_ALPHA_TEST_NEQUAL;
+ break;
+ case GL_GEQUAL:
+ pp_misc |= RADEON_ALPHA_TEST_GEQUAL;
+ break;
+ case GL_ALWAYS:
+ pp_misc |= RADEON_ALPHA_TEST_PASS;
+ break;
+ }
+
+ rmesa->hw.ctx.cmd[CTX_PP_MISC] = pp_misc;
+}
+
+static void radeonBlendEquation( GLcontext *ctx, GLenum mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint b = rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] & ~RADEON_COMB_FCN_MASK;
+ GLboolean fallback = GL_FALSE;
+
+ switch ( mode ) {
+ case GL_FUNC_ADD:
+ case GL_LOGIC_OP:
+ b |= RADEON_COMB_FCN_ADD_CLAMP;
+ break;
+
+ case GL_FUNC_SUBTRACT:
+ b |= RADEON_COMB_FCN_SUB_CLAMP;
+ break;
+
+ default:
+ if (ctx->Color.BlendEnabled)
+ fallback = GL_TRUE;
+ else
+ b |= RADEON_COMB_FCN_ADD_CLAMP;
+ break;
+ }
+
+ FALLBACK( rmesa, RADEON_FALLBACK_BLEND_EQ, fallback );
+ if ( !fallback ) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = b;
+ if ( ctx->Color.ColorLogicOpEnabled ) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE;
+ }
+ }
+}
+
+static void radeonBlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint b = rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] &
+ ~(RADEON_SRC_BLEND_MASK | RADEON_DST_BLEND_MASK);
+ GLboolean fallback = GL_FALSE;
+
+ switch ( ctx->Color.BlendSrcRGB ) {
+ case GL_ZERO:
+ b |= RADEON_SRC_BLEND_GL_ZERO;
+ break;
+ case GL_ONE:
+ b |= RADEON_SRC_BLEND_GL_ONE;
+ break;
+ case GL_DST_COLOR:
+ b |= RADEON_SRC_BLEND_GL_DST_COLOR;
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR;
+ break;
+ case GL_SRC_COLOR:
+ b |= RADEON_SRC_BLEND_GL_SRC_COLOR;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ b |= RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case GL_SRC_ALPHA:
+ b |= RADEON_SRC_BLEND_GL_SRC_ALPHA;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ b |= RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case GL_DST_ALPHA:
+ b |= RADEON_SRC_BLEND_GL_DST_ALPHA;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case GL_SRC_ALPHA_SATURATE:
+ b |= RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE;
+ break;
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ if (ctx->Color.BlendEnabled)
+ fallback = GL_TRUE;
+ else
+ b |= RADEON_SRC_BLEND_GL_ONE;
+ break;
+ default:
+ break;
+ }
+
+ switch ( ctx->Color.BlendDstRGB ) {
+ case GL_ZERO:
+ b |= RADEON_DST_BLEND_GL_ZERO;
+ break;
+ case GL_ONE:
+ b |= RADEON_DST_BLEND_GL_ONE;
+ break;
+ case GL_SRC_COLOR:
+ b |= RADEON_DST_BLEND_GL_SRC_COLOR;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case GL_SRC_ALPHA:
+ b |= RADEON_DST_BLEND_GL_SRC_ALPHA;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case GL_DST_COLOR:
+ b |= RADEON_DST_BLEND_GL_DST_COLOR;
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ b |= RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR;
+ break;
+ case GL_DST_ALPHA:
+ b |= RADEON_DST_BLEND_GL_DST_ALPHA;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ b |= RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ if (ctx->Color.BlendEnabled)
+ fallback = GL_TRUE;
+ else
+ b |= RADEON_DST_BLEND_GL_ZERO;
+ break;
+ default:
+ break;
+ }
+
+ FALLBACK( rmesa, RADEON_FALLBACK_BLEND_FUNC, fallback );
+ if ( !fallback ) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = b;
+ }
+}
+
+static void radeonBlendFuncSeparate( GLcontext *ctx,
+ GLenum sfactorRGB, GLenum dfactorRGB,
+ GLenum sfactorA, GLenum dfactorA )
+{
+ radeonBlendFunc( ctx, sfactorRGB, dfactorRGB );
+}
+
+
+/* =============================================================
+ * Depth testing
+ */
+
+static void radeonDepthFunc( GLcontext *ctx, GLenum func )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_Z_TEST_MASK;
+
+ switch ( ctx->Depth.Func ) {
+ case GL_NEVER:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_NEVER;
+ break;
+ case GL_LESS:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_LESS;
+ break;
+ case GL_EQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_EQUAL;
+ break;
+ case GL_LEQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_LEQUAL;
+ break;
+ case GL_GREATER:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_GREATER;
+ break;
+ case GL_NOTEQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_NEQUAL;
+ break;
+ case GL_GEQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_GEQUAL;
+ break;
+ case GL_ALWAYS:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_ALWAYS;
+ break;
+ }
+}
+
+
+static void radeonDepthMask( GLcontext *ctx, GLboolean flag )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ RADEON_STATECHANGE( rmesa, ctx );
+
+ if ( ctx->Depth.Mask ) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_WRITE_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_Z_WRITE_ENABLE;
+ }
+}
+
+static void radeonClearDepth( GLcontext *ctx, GLclampd d )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint format = (rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &
+ RADEON_DEPTH_FORMAT_MASK);
+
+ switch ( format ) {
+ case RADEON_DEPTH_FORMAT_16BIT_INT_Z:
+ rmesa->state.depth.clear = d * 0x0000ffff;
+ break;
+ case RADEON_DEPTH_FORMAT_24BIT_INT_Z:
+ rmesa->state.depth.clear = d * 0x00ffffff;
+ break;
+ }
+}
+
+
+/* =============================================================
+ * Fog
+ */
+
+
+static void radeonFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ union { int i; float f; } c, d;
+ GLchan col[4];
+
+ c.i = rmesa->hw.fog.cmd[FOG_C];
+ d.i = rmesa->hw.fog.cmd[FOG_D];
+
+ switch (pname) {
+ case GL_FOG_MODE:
+ if (!ctx->Fog.Enabled)
+ return;
+ RADEON_STATECHANGE(rmesa, tcl);
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK;
+ switch (ctx->Fog.Mode) {
+ case GL_LINEAR:
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_LINEAR;
+ if (ctx->Fog.Start == ctx->Fog.End) {
+ c.f = 1.0F;
+ d.f = 1.0F;
+ }
+ else {
+ c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start);
+ d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start);
+ }
+ break;
+ case GL_EXP:
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP;
+ c.f = 0.0;
+ d.f = ctx->Fog.Density;
+ break;
+ case GL_EXP2:
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP2;
+ c.f = 0.0;
+ d.f = -(ctx->Fog.Density * ctx->Fog.Density);
+ break;
+ default:
+ return;
+ }
+ break;
+ case GL_FOG_DENSITY:
+ switch (ctx->Fog.Mode) {
+ case GL_EXP:
+ c.f = 0.0;
+ d.f = ctx->Fog.Density;
+ break;
+ case GL_EXP2:
+ c.f = 0.0;
+ d.f = -(ctx->Fog.Density * ctx->Fog.Density);
+ break;
+ default:
+ break;
+ }
+ break;
+ case GL_FOG_START:
+ case GL_FOG_END:
+ if (ctx->Fog.Mode == GL_LINEAR) {
+ if (ctx->Fog.Start == ctx->Fog.End) {
+ c.f = 1.0F;
+ d.f = 1.0F;
+ } else {
+ c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start);
+ d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start);
+ }
+ }
+ break;
+ case GL_FOG_COLOR:
+ RADEON_STATECHANGE( rmesa, ctx );
+ UNCLAMPED_FLOAT_TO_RGB_CHAN( col, ctx->Fog.Color );
+ rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] =
+ radeonPackColor( 4, col[0], col[1], col[2], 0 );
+ break;
+ case GL_FOG_COORDINATE_SOURCE_EXT:
+ /* What to do?
+ */
+ break;
+ default:
+ return;
+ }
+
+ if (c.i != rmesa->hw.fog.cmd[FOG_C] || d.i != rmesa->hw.fog.cmd[FOG_D]) {
+ RADEON_STATECHANGE( rmesa, fog );
+ rmesa->hw.fog.cmd[FOG_C] = c.i;
+ rmesa->hw.fog.cmd[FOG_D] = d.i;
+ }
+}
+
+
+/* =============================================================
+ * Scissoring
+ */
+
+
+static GLboolean intersect_rect( XF86DRIClipRectPtr out,
+ XF86DRIClipRectPtr a,
+ 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 GL_FALSE;
+ if ( out->y1 >= out->y2 ) return GL_FALSE;
+ return GL_TRUE;
+}
+
+
+void radeonRecalcScissorRects( radeonContextPtr rmesa )
+{
+ XF86DRIClipRectPtr out;
+ int i;
+
+ /* Grow cliprect store?
+ */
+ if (rmesa->state.scissor.numAllocedClipRects < rmesa->numClipRects) {
+ while (rmesa->state.scissor.numAllocedClipRects < rmesa->numClipRects) {
+ rmesa->state.scissor.numAllocedClipRects += 1; /* zero case */
+ rmesa->state.scissor.numAllocedClipRects *= 2;
+ }
+
+ if (rmesa->state.scissor.pClipRects)
+ FREE(rmesa->state.scissor.pClipRects);
+
+ rmesa->state.scissor.pClipRects =
+ MALLOC( rmesa->state.scissor.numAllocedClipRects *
+ sizeof(XF86DRIClipRectRec) );
+
+ if ( rmesa->state.scissor.pClipRects == NULL ) {
+ rmesa->state.scissor.numAllocedClipRects = 0;
+ return;
+ }
+ }
+
+ out = rmesa->state.scissor.pClipRects;
+ rmesa->state.scissor.numClipRects = 0;
+
+ for ( i = 0 ; i < rmesa->numClipRects ; i++ ) {
+ if ( intersect_rect( out,
+ &rmesa->pClipRects[i],
+ &rmesa->state.scissor.rect ) ) {
+ rmesa->state.scissor.numClipRects++;
+ out++;
+ }
+ }
+}
+
+
+static void radeonUpdateScissor( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if ( rmesa->dri.drawable ) {
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
+
+ int x = ctx->Scissor.X;
+ int y = dPriv->h - ctx->Scissor.Y - ctx->Scissor.Height;
+ int w = ctx->Scissor.X + ctx->Scissor.Width - 1;
+ int h = dPriv->h - ctx->Scissor.Y - 1;
+
+ rmesa->state.scissor.rect.x1 = x + dPriv->x;
+ rmesa->state.scissor.rect.y1 = y + dPriv->y;
+ rmesa->state.scissor.rect.x2 = w + dPriv->x + 1;
+ rmesa->state.scissor.rect.y2 = h + dPriv->y + 1;
+
+ radeonRecalcScissorRects( rmesa );
+ }
+}
+
+
+static void radeonScissor( GLcontext *ctx,
+ GLint x, GLint y, GLsizei w, GLsizei h )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if ( ctx->Scissor.Enabled ) {
+ RADEON_FIREVERTICES( rmesa ); /* don't pipeline cliprect changes */
+ radeonUpdateScissor( ctx );
+ }
+
+}
+
+
+/* =============================================================
+ * Culling
+ */
+
+static void radeonCullFace( GLcontext *ctx, GLenum unused )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint s = rmesa->hw.set.cmd[SET_SE_CNTL];
+ GLuint t = rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL];
+
+ s |= RADEON_FFACE_SOLID | RADEON_BFACE_SOLID;
+ t &= ~(RADEON_CULL_FRONT | RADEON_CULL_BACK);
+
+ if ( ctx->Polygon.CullFlag ) {
+ switch ( ctx->Polygon.CullFaceMode ) {
+ case GL_FRONT:
+ s &= ~RADEON_FFACE_SOLID;
+ t |= RADEON_CULL_FRONT;
+ break;
+ case GL_BACK:
+ s &= ~RADEON_BFACE_SOLID;
+ t |= RADEON_CULL_BACK;
+ break;
+ case GL_FRONT_AND_BACK:
+ s &= ~(RADEON_FFACE_SOLID | RADEON_BFACE_SOLID);
+ t |= (RADEON_CULL_FRONT | RADEON_CULL_BACK);
+ break;
+ }
+ }
+
+ if ( rmesa->hw.set.cmd[SET_SE_CNTL] != s ) {
+ RADEON_STATECHANGE(rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_CNTL] = s;
+ }
+
+ if ( rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] != t ) {
+ RADEON_STATECHANGE(rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] = t;
+ }
+}
+
+static void radeonFrontFace( GLcontext *ctx, GLenum mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_FFACE_CULL_DIR_MASK;
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_CULL_FRONT_IS_CCW;
+
+ switch ( mode ) {
+ case GL_CW:
+ rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_FFACE_CULL_CW;
+ break;
+ case GL_CCW:
+ rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_FFACE_CULL_CCW;
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_CULL_FRONT_IS_CCW;
+ break;
+ }
+}
+
+
+/* =============================================================
+ * Line state
+ */
+static void radeonLineWidth( GLcontext *ctx, GLfloat widthf )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ RADEON_STATECHANGE( rmesa, lin );
+ RADEON_STATECHANGE( rmesa, set );
+
+ /* Line width is stored in U6.4 format.
+ */
+ rmesa->hw.lin.cmd[LIN_SE_LINE_WIDTH] = (GLuint)(widthf * 16.0);
+ if ( widthf > 1.0 ) {
+ rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_WIDELINE_ENABLE;
+ } else {
+ rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_WIDELINE_ENABLE;
+ }
+}
+
+static void radeonLineStipple( GLcontext *ctx, GLint factor, GLushort pattern )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ RADEON_STATECHANGE( rmesa, lin );
+ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] =
+ ((((GLuint)factor & 0xff) << 16) | ((GLuint)pattern));
+}
+
+
+/* =============================================================
+ * Masks
+ */
+static void radeonColorMask( GLcontext *ctx,
+ GLboolean r, GLboolean g,
+ GLboolean b, GLboolean a )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint mask = radeonPackColor( rmesa->radeonScreen->cpp,
+ ctx->Color.ColorMask[RCOMP],
+ ctx->Color.ColorMask[GCOMP],
+ ctx->Color.ColorMask[BCOMP],
+ ctx->Color.ColorMask[ACOMP] );
+
+ if ( rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] != mask ) {
+ RADEON_STATECHANGE( rmesa, msk );
+ rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] = mask;
+ }
+}
+
+
+/* =============================================================
+ * Polygon state
+ */
+
+static void radeonPolygonOffset( GLcontext *ctx,
+ GLfloat factor, GLfloat units )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat constant = units * rmesa->state.depth.scale;
+
+ RADEON_STATECHANGE( rmesa, zbs );
+ rmesa->hw.zbs.cmd[ZBS_SE_ZBIAS_FACTOR] = *(GLuint *)&factor;
+ rmesa->hw.zbs.cmd[ZBS_SE_ZBIAS_CONSTANT] = *(GLuint *)&constant;
+}
+
+static void radeonPolygonStipple( GLcontext *ctx, const GLubyte *mask )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint i;
+ drmRadeonStipple stipple;
+
+ /* Must flip pattern upside down.
+ */
+ for ( i = 0 ; i < 32 ; i++ ) {
+ rmesa->state.stipple.mask[31 - i] = ((GLuint *) mask)[i];
+ }
+
+ /* TODO: push this into cmd mechanism
+ */
+ RADEON_FIREVERTICES( rmesa );
+ LOCK_HARDWARE( rmesa );
+
+ /* FIXME: Use window x,y offsets into stipple RAM.
+ */
+ stipple.mask = rmesa->state.stipple.mask;
+ drmCommandWrite( rmesa->dri.fd, DRM_RADEON_STIPPLE,
+ &stipple, sizeof(drmRadeonStipple) );
+ UNLOCK_HARDWARE( rmesa );
+}
+
+static void radeonPolygonMode( GLcontext *ctx, GLenum face, GLenum mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLboolean flag = (ctx->_TriangleCaps & DD_TRI_UNFILLED) != 0;
+
+ /* Can't generally do unfilled via tcl, but some good special
+ * cases work.
+ */
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_UNFILLED, flag);
+ if (rmesa->TclFallback) {
+ radeonChooseRenderState( ctx );
+ radeonChooseVertexState( ctx );
+ }
+}
+
+
+/* =============================================================
+ * Rendering attributes
+ *
+ * We really don't want to recalculate all this every time we bind a
+ * texture. These things shouldn't change all that often, so it makes
+ * sense to break them out of the core texture state update routines.
+ */
+
+/* Examine lighting and texture state to determine if separate specular
+ * should be enabled.
+ */
+static void radeonUpdateSpecular( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ CARD32 p = rmesa->hw.ctx.cmd[CTX_PP_CNTL];
+
+ RADEON_STATECHANGE( rmesa, tcl );
+
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE;
+
+ p &= ~RADEON_SPECULAR_ENABLE;
+
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_DIFFUSE_SPECULAR_COMBINE;
+
+
+ if (ctx->Light.Enabled &&
+ ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE;
+ p |= RADEON_SPECULAR_ENABLE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &=
+ ~RADEON_DIFFUSE_SPECULAR_COMBINE;
+ }
+ else if (ctx->Light.Enabled) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE;
+ } else if (ctx->Fog.ColorSumEnabled ) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ p |= RADEON_SPECULAR_ENABLE;
+ } else {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE;
+ }
+
+ if (ctx->Fog.Enabled) {
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC;
+
+ /* Bizzare: have to leave lighting enabled to get fog.
+ */
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE;
+ }
+
+ if ( ctx->_TriangleCaps & DD_SEPARATE_SPECULAR ) {
+ assert( (p & RADEON_SPECULAR_ENABLE) != 0 );
+ } else {
+ assert( (p & RADEON_SPECULAR_ENABLE) == 0 );
+ }
+
+ if ( rmesa->hw.ctx.cmd[CTX_PP_CNTL] != p ) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] = p;
+ }
+
+ /* Update vertex/render formats
+ */
+ if (rmesa->TclFallback) {
+ radeonChooseRenderState( ctx );
+ radeonChooseVertexState( ctx );
+ }
+}
+
+
+/* =============================================================
+ * Materials
+ */
+
+
+/* Update on colormaterial, material emmissive/ambient,
+ * lightmodel.globalambient
+ */
+static void update_global_ambient( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ float *fcmd = (float *)RADEON_DB_STATE( glt );
+
+ /* Need to do more if both emmissive & ambient are PREMULT:
+ */
+ if ((rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &
+ ((3 << RADEON_EMISSIVE_SOURCE_SHIFT) |
+ (3 << RADEON_AMBIENT_SOURCE_SHIFT))) == 0)
+ {
+ COPY_3V( &fcmd[GLT_RED],
+ ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
+ ACC_SCALE_3V( &fcmd[GLT_RED],
+ ctx->Light.Model.Ambient,
+ ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
+ }
+ else
+ {
+ COPY_3V( &fcmd[GLT_RED], ctx->Light.Model.Ambient );
+ }
+
+ RADEON_DB_STATECHANGE(rmesa, &rmesa->hw.glt);
+}
+
+/* Update on change to
+ * - light[p].colors
+ * - light[p].enabled
+ * - material,
+ * - colormaterial enabled
+ * - colormaterial bitmask
+ */
+static void update_light_colors( GLcontext *ctx, GLuint p )
+{
+ struct gl_light *l = &ctx->Light.Light[p];
+
+/* fprintf(stderr, "%s\n", __FUNCTION__); */
+
+ if (l->Enabled) {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ float *fcmd = (float *)RADEON_DB_STATE( lit[p] );
+ GLuint bitmask = ctx->Light.ColorMaterialBitmask;
+ GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
+
+ COPY_4V( &fcmd[LIT_AMBIENT_RED], l->Ambient );
+ COPY_4V( &fcmd[LIT_DIFFUSE_RED], l->Diffuse );
+ COPY_4V( &fcmd[LIT_SPECULAR_RED], l->Specular );
+
+ if (!ctx->Light.ColorMaterialEnabled)
+ bitmask = 0;
+
+ if ((bitmask & MAT_BIT_FRONT_AMBIENT) == 0)
+ SELF_SCALE_3V( &fcmd[LIT_AMBIENT_RED], mat[MAT_ATTRIB_FRONT_AMBIENT] );
+
+ if ((bitmask & MAT_BIT_FRONT_DIFFUSE) == 0)
+ SELF_SCALE_3V( &fcmd[LIT_DIFFUSE_RED], mat[MAT_ATTRIB_FRONT_DIFFUSE] );
+
+ if ((bitmask & MAT_BIT_FRONT_SPECULAR) == 0)
+ SELF_SCALE_3V( &fcmd[LIT_SPECULAR_RED], mat[MAT_ATTRIB_FRONT_SPECULAR] );
+
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] );
+ }
+}
+
+/* Also fallback for asym colormaterial mode in twoside lighting...
+ */
+static void check_twoside_fallback( GLcontext *ctx )
+{
+ GLboolean fallback = GL_FALSE;
+ GLint i;
+
+ if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) {
+ if (ctx->Light.ColorMaterialEnabled &&
+ (ctx->Light.ColorMaterialBitmask & BACK_MATERIAL_BITS) !=
+ ((ctx->Light.ColorMaterialBitmask & FRONT_MATERIAL_BITS)<<1))
+ fallback = GL_TRUE;
+ else {
+ for (i = MAT_ATTRIB_FRONT_AMBIENT; i < MAT_ATTRIB_FRONT_INDEXES; i+=2)
+ if (memcmp( ctx->Light.Material.Attrib[i],
+ ctx->Light.Material.Attrib[i+1],
+ sizeof(GLfloat)*4) != 0) {
+ fallback = GL_TRUE;
+ break;
+ }
+ }
+ }
+
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_LIGHT_TWOSIDE, fallback );
+}
+
+
+static void radeonColorMaterial( GLcontext *ctx, GLenum face, GLenum mode )
+{
+ if (ctx->Light.ColorMaterialEnabled) {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint light_model_ctl1 = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL];
+ GLuint mask = ctx->Light.ColorMaterialBitmask;
+
+ /* Default to PREMULT:
+ */
+ light_model_ctl1 &= ~((0xf << RADEON_EMISSIVE_SOURCE_SHIFT) |
+ (0xf << RADEON_AMBIENT_SOURCE_SHIFT) |
+ (0xf << RADEON_DIFFUSE_SOURCE_SHIFT) |
+ (0xf << RADEON_SPECULAR_SOURCE_SHIFT));
+
+ if (mask & MAT_BIT_FRONT_EMISSION) {
+ light_model_ctl1 |= (3 <<
+ RADEON_EMISSIVE_SOURCE_SHIFT);
+ }
+
+ if (mask & MAT_BIT_FRONT_AMBIENT) {
+ light_model_ctl1 |= (3 <<
+ RADEON_AMBIENT_SOURCE_SHIFT);
+ }
+
+ if (mask & MAT_BIT_FRONT_DIFFUSE) {
+ light_model_ctl1 |= (3 <<
+ RADEON_DIFFUSE_SOURCE_SHIFT);
+ }
+
+ if (mask & MAT_BIT_FRONT_SPECULAR) {
+ light_model_ctl1 |= (3 <<
+ RADEON_SPECULAR_SOURCE_SHIFT);
+ }
+
+ if (light_model_ctl1 != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) {
+ GLuint p;
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = light_model_ctl1;
+
+ for (p = 0 ; p < MAX_LIGHTS; p++)
+ update_light_colors( ctx, p );
+ update_global_ambient( ctx );
+ }
+ }
+
+ check_twoside_fallback( ctx );
+}
+
+void radeonUpdateMaterial( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
+ GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( mtl );
+ GLuint p;
+ GLuint mask = ~0;
+
+ if (ctx->Light.ColorMaterialEnabled)
+ mask &= ~ctx->Light.ColorMaterialBitmask;
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+
+ if (mask & MAT_BIT_FRONT_EMISSION) {
+ fcmd[MTL_EMMISSIVE_RED] = mat[MAT_ATTRIB_FRONT_EMISSION][0];
+ fcmd[MTL_EMMISSIVE_GREEN] = mat[MAT_ATTRIB_FRONT_EMISSION][1];
+ fcmd[MTL_EMMISSIVE_BLUE] = mat[MAT_ATTRIB_FRONT_EMISSION][2];
+ fcmd[MTL_EMMISSIVE_ALPHA] = mat[MAT_ATTRIB_FRONT_EMISSION][3];
+ }
+ if (mask & MAT_BIT_FRONT_AMBIENT) {
+ fcmd[MTL_AMBIENT_RED] = mat[MAT_ATTRIB_FRONT_AMBIENT][0];
+ fcmd[MTL_AMBIENT_GREEN] = mat[MAT_ATTRIB_FRONT_AMBIENT][1];
+ fcmd[MTL_AMBIENT_BLUE] = mat[MAT_ATTRIB_FRONT_AMBIENT][2];
+ fcmd[MTL_AMBIENT_ALPHA] = mat[MAT_ATTRIB_FRONT_AMBIENT][3];
+ }
+ if (mask & MAT_BIT_FRONT_DIFFUSE) {
+ fcmd[MTL_DIFFUSE_RED] = mat[MAT_ATTRIB_FRONT_DIFFUSE][0];
+ fcmd[MTL_DIFFUSE_GREEN] = mat[MAT_ATTRIB_FRONT_DIFFUSE][1];
+ fcmd[MTL_DIFFUSE_BLUE] = mat[MAT_ATTRIB_FRONT_DIFFUSE][2];
+ fcmd[MTL_DIFFUSE_ALPHA] = mat[MAT_ATTRIB_FRONT_DIFFUSE][3];
+ }
+ if (mask & MAT_BIT_FRONT_SPECULAR) {
+ fcmd[MTL_SPECULAR_RED] = mat[MAT_ATTRIB_FRONT_SPECULAR][0];
+ fcmd[MTL_SPECULAR_GREEN] = mat[MAT_ATTRIB_FRONT_SPECULAR][1];
+ fcmd[MTL_SPECULAR_BLUE] = mat[MAT_ATTRIB_FRONT_SPECULAR][2];
+ fcmd[MTL_SPECULAR_ALPHA] = mat[MAT_ATTRIB_FRONT_SPECULAR][3];
+ }
+ if (mask & MAT_BIT_FRONT_SHININESS) {
+ fcmd[MTL_SHININESS] = mat[MAT_ATTRIB_FRONT_SHININESS][0];
+ }
+
+ if (RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mtl )) {
+ for (p = 0 ; p < MAX_LIGHTS; p++)
+ update_light_colors( ctx, p );
+
+ check_twoside_fallback( ctx );
+ update_global_ambient( ctx );
+ }
+ else if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_STATE))
+ fprintf(stderr, "%s: Elided noop material call\n", __FUNCTION__);
+}
+
+/* _NEW_LIGHT
+ * _NEW_MODELVIEW
+ * _MESA_NEW_NEED_EYE_COORDS
+ *
+ * Uses derived state from mesa:
+ * _VP_inf_norm
+ * _h_inf_norm
+ * _Position
+ * _NormDirection
+ * _ModelViewInvScale
+ * _NeedEyeCoords
+ * _EyeZDir
+ *
+ * which are calculated in light.c and are correct for the current
+ * lighting space (model or eye), hence dependencies on _NEW_MODELVIEW
+ * and _MESA_NEW_NEED_EYE_COORDS.
+ */
+static void update_light( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ /* Have to check these, or have an automatic shortcircuit mechanism
+ * to remove noop statechanges. (Or just do a better job on the
+ * front end).
+ */
+ {
+ GLuint tmp = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL];
+
+ if (ctx->_NeedEyeCoords)
+ tmp &= ~RADEON_LIGHT_IN_MODELSPACE;
+ else
+ tmp |= RADEON_LIGHT_IN_MODELSPACE;
+
+
+ /* Leave this test disabled: (unexplained q3 lockup) (even with
+ new packets)
+ */
+ if (tmp != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL])
+ {
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = tmp;
+ }
+ }
+
+ {
+ GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( eye );
+ fcmd[EYE_X] = ctx->_EyeZDir[0];
+ fcmd[EYE_Y] = ctx->_EyeZDir[1];
+ fcmd[EYE_Z] = - ctx->_EyeZDir[2];
+ fcmd[EYE_RESCALE_FACTOR] = ctx->_ModelViewInvScale;
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.eye );
+ }
+
+
+
+ if (ctx->Light.Enabled) {
+ GLint p;
+ for (p = 0 ; p < MAX_LIGHTS; p++) {
+ if (ctx->Light.Light[p].Enabled) {
+ struct gl_light *l = &ctx->Light.Light[p];
+ GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( lit[p] );
+
+ if (l->EyePosition[3] == 0.0) {
+ COPY_3FV( &fcmd[LIT_POSITION_X], l->_VP_inf_norm );
+ COPY_3FV( &fcmd[LIT_DIRECTION_X], l->_h_inf_norm );
+ fcmd[LIT_POSITION_W] = 0;
+ fcmd[LIT_DIRECTION_W] = 0;
+ } else {
+ COPY_4V( &fcmd[LIT_POSITION_X], l->_Position );
+ fcmd[LIT_DIRECTION_X] = -l->_NormDirection[0];
+ fcmd[LIT_DIRECTION_Y] = -l->_NormDirection[1];
+ fcmd[LIT_DIRECTION_Z] = -l->_NormDirection[2];
+ fcmd[LIT_DIRECTION_W] = 0;
+ }
+
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] );
+ }
+ }
+ }
+}
+
+static void radeonLightfv( GLcontext *ctx, GLenum light,
+ GLenum pname, const GLfloat *params )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLint p = light - GL_LIGHT0;
+ struct gl_light *l = &ctx->Light.Light[p];
+ GLfloat *fcmd = (GLfloat *)rmesa->hw.lit[p].cmd;
+
+
+ switch (pname) {
+ case GL_AMBIENT:
+ case GL_DIFFUSE:
+ case GL_SPECULAR:
+ update_light_colors( ctx, p );
+ break;
+
+ case GL_SPOT_DIRECTION:
+ /* picked up in update_light */
+ break;
+
+ case GL_POSITION: {
+ /* positions picked up in update_light, but can do flag here */
+ GLuint flag;
+ GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2;
+
+ /* FIXME: Set RANGE_ATTEN only when needed */
+ if (p&1)
+ flag = RADEON_LIGHT_1_IS_LOCAL;
+ else
+ flag = RADEON_LIGHT_0_IS_LOCAL;
+
+ RADEON_STATECHANGE(rmesa, tcl);
+ if (l->EyePosition[3] != 0.0F)
+ rmesa->hw.tcl.cmd[idx] |= flag;
+ else
+ rmesa->hw.tcl.cmd[idx] &= ~flag;
+ break;
+ }
+
+ case GL_SPOT_EXPONENT:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_SPOT_EXPONENT] = params[0];
+ break;
+
+ case GL_SPOT_CUTOFF: {
+ GLuint flag = (p&1) ? RADEON_LIGHT_1_IS_SPOT : RADEON_LIGHT_0_IS_SPOT;
+ GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2;
+
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_SPOT_CUTOFF] = l->_CosCutoff;
+
+ RADEON_STATECHANGE(rmesa, tcl);
+ if (l->SpotCutoff != 180.0F)
+ rmesa->hw.tcl.cmd[idx] |= flag;
+ else
+ rmesa->hw.tcl.cmd[idx] &= ~flag;
+
+ break;
+ }
+
+ case GL_CONSTANT_ATTENUATION:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_ATTEN_CONST] = params[0];
+ break;
+ case GL_LINEAR_ATTENUATION:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_ATTEN_LINEAR] = params[0];
+ break;
+ case GL_QUADRATIC_ATTENUATION:
+ RADEON_STATECHANGE(rmesa, lit[p]);
+ fcmd[LIT_ATTEN_QUADRATIC] = params[0];
+ break;
+ default:
+ return;
+ }
+
+ /* Set RANGE_ATTEN only when needed */
+ switch (pname) {
+ case GL_POSITION:
+ case GL_LINEAR_ATTENUATION:
+ case GL_QUADRATIC_ATTENUATION:
+ {
+ GLuint flag;
+ GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2;
+
+ if (p&1)
+ flag = RADEON_LIGHT_1_ENABLE_RANGE_ATTEN;
+ else
+ flag = RADEON_LIGHT_0_ENABLE_RANGE_ATTEN;
+
+ RADEON_STATECHANGE(rmesa, tcl);
+ if (l->EyePosition[3] != 0.0F &&
+ (l->LinearAttenuation != 0.0F || l->QuadraticAttenuation != 0.0F))
+ rmesa->hw.tcl.cmd[idx] |= flag;
+ else
+ rmesa->hw.tcl.cmd[idx] &= ~flag;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+
+
+static void radeonLightModelfv( GLcontext *ctx, GLenum pname,
+ const GLfloat *param )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ switch (pname) {
+ case GL_LIGHT_MODEL_AMBIENT:
+ update_global_ambient( ctx );
+ break;
+
+ case GL_LIGHT_MODEL_LOCAL_VIEWER:
+ RADEON_STATECHANGE( rmesa, tcl );
+ if (ctx->Light.Model.LocalViewer)
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LOCAL_VIEWER;
+ else
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LOCAL_VIEWER;
+ break;
+
+ case GL_LIGHT_MODEL_TWO_SIDE:
+ RADEON_STATECHANGE( rmesa, tcl );
+ if (ctx->Light.Model.TwoSide)
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_LIGHT_TWOSIDE;
+ else
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_LIGHT_TWOSIDE;
+
+ check_twoside_fallback( ctx );
+
+ if (rmesa->TclFallback) {
+ radeonChooseRenderState( ctx );
+ radeonChooseVertexState( ctx );
+ }
+ break;
+
+ case GL_LIGHT_MODEL_COLOR_CONTROL:
+ radeonUpdateSpecular(ctx);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void radeonShadeModel( GLcontext *ctx, GLenum mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint s = rmesa->hw.set.cmd[SET_SE_CNTL];
+
+ s &= ~(RADEON_DIFFUSE_SHADE_MASK |
+ RADEON_ALPHA_SHADE_MASK |
+ RADEON_SPECULAR_SHADE_MASK |
+ RADEON_FOG_SHADE_MASK);
+
+ switch ( mode ) {
+ case GL_FLAT:
+ s |= (RADEON_DIFFUSE_SHADE_FLAT |
+ RADEON_ALPHA_SHADE_FLAT |
+ RADEON_SPECULAR_SHADE_FLAT |
+ RADEON_FOG_SHADE_FLAT);
+ break;
+ case GL_SMOOTH:
+ s |= (RADEON_DIFFUSE_SHADE_GOURAUD |
+ RADEON_ALPHA_SHADE_GOURAUD |
+ RADEON_SPECULAR_SHADE_GOURAUD |
+ RADEON_FOG_SHADE_GOURAUD);
+ break;
+ default:
+ return;
+ }
+
+ if ( rmesa->hw.set.cmd[SET_SE_CNTL] != s ) {
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_CNTL] = s;
+ }
+}
+
+
+/* =============================================================
+ * User clip planes
+ */
+
+static void radeonClipPlane( GLcontext *ctx, GLenum plane, const GLfloat *eq )
+{
+ GLint p = (GLint) plane - (GLint) GL_CLIP_PLANE0;
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLint *ip = (GLint *)ctx->Transform._ClipUserPlane[p];
+
+ RADEON_STATECHANGE( rmesa, ucp[p] );
+ rmesa->hw.ucp[p].cmd[UCP_X] = ip[0];
+ rmesa->hw.ucp[p].cmd[UCP_Y] = ip[1];
+ rmesa->hw.ucp[p].cmd[UCP_Z] = ip[2];
+ rmesa->hw.ucp[p].cmd[UCP_W] = ip[3];
+}
+
+static void radeonUpdateClipPlanes( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint p;
+
+ for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
+ if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
+ GLint *ip = (GLint *)ctx->Transform._ClipUserPlane[p];
+
+ RADEON_STATECHANGE( rmesa, ucp[p] );
+ rmesa->hw.ucp[p].cmd[UCP_X] = ip[0];
+ rmesa->hw.ucp[p].cmd[UCP_Y] = ip[1];
+ rmesa->hw.ucp[p].cmd[UCP_Z] = ip[2];
+ rmesa->hw.ucp[p].cmd[UCP_W] = ip[3];
+ }
+ }
+}
+
+
+/* =============================================================
+ * Stencil
+ */
+
+static void radeonStencilFunc( GLcontext *ctx, GLenum func,
+ GLint ref, GLuint mask )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint refmask = ((ctx->Stencil.Ref[0] << RADEON_STENCIL_REF_SHIFT) |
+ (ctx->Stencil.ValueMask[0] << RADEON_STENCIL_MASK_SHIFT));
+
+ RADEON_STATECHANGE( rmesa, ctx );
+ RADEON_STATECHANGE( rmesa, msk );
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_STENCIL_TEST_MASK;
+ rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] &= ~(RADEON_STENCIL_REF_MASK|
+ RADEON_STENCIL_VALUE_MASK);
+
+ switch ( ctx->Stencil.Function[0] ) {
+ case GL_NEVER:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_NEVER;
+ break;
+ case GL_LESS:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_LESS;
+ break;
+ case GL_EQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_EQUAL;
+ break;
+ case GL_LEQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_LEQUAL;
+ break;
+ case GL_GREATER:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_GREATER;
+ break;
+ case GL_NOTEQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_NEQUAL;
+ break;
+ case GL_GEQUAL:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_GEQUAL;
+ break;
+ case GL_ALWAYS:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_ALWAYS;
+ break;
+ }
+
+ rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] |= refmask;
+}
+
+static void radeonStencilMask( GLcontext *ctx, GLuint mask )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ RADEON_STATECHANGE( rmesa, msk );
+ rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] &= ~RADEON_STENCIL_WRITE_MASK;
+ rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] |=
+ (ctx->Stencil.WriteMask[0] << RADEON_STENCIL_WRITEMASK_SHIFT);
+}
+
+static void radeonStencilOp( GLcontext *ctx, GLenum fail,
+ GLenum zfail, GLenum zpass )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~(RADEON_STENCIL_FAIL_MASK |
+ RADEON_STENCIL_ZFAIL_MASK |
+ RADEON_STENCIL_ZPASS_MASK);
+
+ switch ( ctx->Stencil.FailFunc[0] ) {
+ case GL_KEEP:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_KEEP;
+ break;
+ case GL_ZERO:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_ZERO;
+ break;
+ case GL_REPLACE:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_REPLACE;
+ break;
+ case GL_INCR:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_INC;
+ break;
+ case GL_DECR:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_DEC;
+ break;
+ case GL_INVERT:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_INVERT;
+ break;
+ }
+
+ switch ( ctx->Stencil.ZFailFunc[0] ) {
+ case GL_KEEP:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_KEEP;
+ break;
+ case GL_ZERO:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_ZERO;
+ break;
+ case GL_REPLACE:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_REPLACE;
+ break;
+ case GL_INCR:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_INC;
+ break;
+ case GL_DECR:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_DEC;
+ break;
+ case GL_INVERT:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_INVERT;
+ break;
+ }
+
+ switch ( ctx->Stencil.ZPassFunc[0] ) {
+ case GL_KEEP:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_KEEP;
+ break;
+ case GL_ZERO:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_ZERO;
+ break;
+ case GL_REPLACE:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_REPLACE;
+ break;
+ case GL_INCR:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_INC;
+ break;
+ case GL_DECR:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_DEC;
+ break;
+ case GL_INVERT:
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_INVERT;
+ break;
+ }
+}
+
+static void radeonClearStencil( GLcontext *ctx, GLint s )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ rmesa->state.stencil.clear =
+ ((GLuint) ctx->Stencil.Clear |
+ (0xff << RADEON_STENCIL_MASK_SHIFT) |
+ (ctx->Stencil.WriteMask[0] << RADEON_STENCIL_WRITEMASK_SHIFT));
+}
+
+
+/* =============================================================
+ * Window position and viewport transformation
+ */
+
+/*
+ * To correctly position primitives:
+ */
+#define SUBPIXEL_X 0.125
+#define SUBPIXEL_Y 0.125
+
+void radeonUpdateWindow( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
+ GLfloat xoffset = (GLfloat)dPriv->x;
+ GLfloat yoffset = (GLfloat)dPriv->y + dPriv->h;
+ const GLfloat *v = ctx->Viewport._WindowMap.m;
+
+ GLfloat sx = v[MAT_SX];
+ GLfloat tx = v[MAT_TX] + xoffset + SUBPIXEL_X;
+ GLfloat sy = - v[MAT_SY];
+ GLfloat ty = (- v[MAT_TY]) + yoffset + SUBPIXEL_Y;
+ GLfloat sz = v[MAT_SZ] * rmesa->state.depth.scale;
+ GLfloat tz = v[MAT_TZ] * rmesa->state.depth.scale;
+ RADEON_FIREVERTICES( rmesa );
+ RADEON_STATECHANGE( rmesa, vpt );
+
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_XSCALE] = *(GLuint *)&sx;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = *(GLuint *)&tx;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_YSCALE] = *(GLuint *)&sy;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = *(GLuint *)&ty;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZSCALE] = *(GLuint *)&sz;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZOFFSET] = *(GLuint *)&tz;
+}
+
+
+
+static void radeonViewport( GLcontext *ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height )
+{
+ /* Don't pipeline viewport changes, conflict with window offset
+ * setting below. Could apply deltas to rescue pipelined viewport
+ * values, or keep the originals hanging around.
+ */
+ RADEON_FIREVERTICES( RADEON_CONTEXT(ctx) );
+ radeonUpdateWindow( ctx );
+}
+
+static void radeonDepthRange( GLcontext *ctx, GLclampd nearval,
+ GLclampd farval )
+{
+ radeonUpdateWindow( ctx );
+}
+
+void radeonUpdateViewportOffset( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
+ GLfloat xoffset = (GLfloat)dPriv->x;
+ GLfloat yoffset = (GLfloat)dPriv->y + dPriv->h;
+ const GLfloat *v = ctx->Viewport._WindowMap.m;
+
+ GLfloat tx = v[MAT_TX] + xoffset;
+ GLfloat ty = (- v[MAT_TY]) + yoffset;
+
+ if ( rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] != *(GLuint *)&tx ||
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] != *(GLuint *)&ty )
+ {
+ /* Note: this should also modify whatever data the context reset
+ * code uses...
+ */
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = *(GLuint *)&tx;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = *(GLuint *)&ty;
+
+ /* update polygon stipple x/y screen offset */
+ {
+ GLuint stx, sty;
+ GLuint m = rmesa->hw.msc.cmd[MSC_RE_MISC];
+
+ m &= ~(RADEON_STIPPLE_X_OFFSET_MASK |
+ RADEON_STIPPLE_Y_OFFSET_MASK);
+
+ /* add magic offsets, then invert */
+ stx = 31 - ((rmesa->dri.drawable->x - 1) & RADEON_STIPPLE_COORD_MASK);
+ sty = 31 - ((rmesa->dri.drawable->y + rmesa->dri.drawable->h - 1)
+ & RADEON_STIPPLE_COORD_MASK);
+
+ m |= ((stx << RADEON_STIPPLE_X_OFFSET_SHIFT) |
+ (sty << RADEON_STIPPLE_Y_OFFSET_SHIFT));
+
+ if ( rmesa->hw.msc.cmd[MSC_RE_MISC] != m ) {
+ RADEON_STATECHANGE( rmesa, msc );
+ rmesa->hw.msc.cmd[MSC_RE_MISC] = m;
+ }
+ }
+ }
+
+ radeonUpdateScissor( ctx );
+}
+
+
+
+/* =============================================================
+ * Miscellaneous
+ */
+
+static void radeonClearColor( GLcontext *ctx, const GLfloat color[4] )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLubyte c[4];
+ 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]);
+ rmesa->state.color.clear = radeonPackColor( rmesa->radeonScreen->cpp,
+ c[0], c[1], c[2], c[3] );
+}
+
+
+static void radeonRenderMode( GLcontext *ctx, GLenum mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ FALLBACK( rmesa, RADEON_FALLBACK_RENDER_MODE, (mode != GL_RENDER) );
+}
+
+
+static GLuint radeon_rop_tab[] = {
+ RADEON_ROP_CLEAR,
+ RADEON_ROP_AND,
+ RADEON_ROP_AND_REVERSE,
+ RADEON_ROP_COPY,
+ RADEON_ROP_AND_INVERTED,
+ RADEON_ROP_NOOP,
+ RADEON_ROP_XOR,
+ RADEON_ROP_OR,
+ RADEON_ROP_NOR,
+ RADEON_ROP_EQUIV,
+ RADEON_ROP_INVERT,
+ RADEON_ROP_OR_REVERSE,
+ RADEON_ROP_COPY_INVERTED,
+ RADEON_ROP_OR_INVERTED,
+ RADEON_ROP_NAND,
+ RADEON_ROP_SET,
+};
+
+static void radeonLogicOpCode( GLcontext *ctx, GLenum opcode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint rop = (GLuint)opcode - GL_CLEAR;
+
+ ASSERT( rop < 16 );
+
+ RADEON_STATECHANGE( rmesa, msk );
+ rmesa->hw.msk.cmd[MSK_RB3D_ROPCNTL] = radeon_rop_tab[rop];
+}
+
+
+void radeonSetCliprects( radeonContextPtr rmesa, GLenum mode )
+{
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
+
+ switch ( mode ) {
+ case GL_FRONT_LEFT:
+ rmesa->numClipRects = dPriv->numClipRects;
+ rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pClipRects;
+ break;
+ case GL_BACK_LEFT:
+ /* Can't ignore 2d windows if we are page flipping.
+ */
+ if ( dPriv->numBackClipRects == 0 || rmesa->doPageFlip ) {
+ rmesa->numClipRects = dPriv->numClipRects;
+ rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pClipRects;
+ }
+ else {
+ rmesa->numClipRects = dPriv->numBackClipRects;
+ rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pBackClipRects;
+ }
+ break;
+ default:
+ fprintf(stderr, "bad mode in radeonSetCliprects\n");
+ return;
+ }
+
+ if (rmesa->state.scissor.enabled)
+ radeonRecalcScissorRects( rmesa );
+}
+
+
+static void radeonDrawBuffer( GLcontext *ctx, GLenum mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_DRI)
+ fprintf(stderr, "%s %s\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr( mode ));
+
+ RADEON_FIREVERTICES(rmesa); /* don't pipeline cliprect changes */
+
+ /*
+ * _DrawDestMask is easier to cope with than <mode>.
+ */
+ switch ( ctx->Color._DrawDestMask ) {
+ case FRONT_LEFT_BIT:
+ FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE );
+ radeonSetCliprects( rmesa, GL_FRONT_LEFT );
+ break;
+ case BACK_LEFT_BIT:
+ FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE );
+ radeonSetCliprects( rmesa, GL_BACK_LEFT );
+ break;
+ default:
+ /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */
+ FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_TRUE );
+ return;
+ }
+
+ /* We want to update the s/w rast state too so that r200SetBuffer()
+ * gets called.
+ */
+ _swrast_DrawBuffer(ctx, mode);
+
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset &
+ RADEON_COLOROFFSET_MASK);
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch;
+}
+
+static void radeonReadBuffer( GLcontext *ctx, GLenum mode )
+{
+ /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
+}
+
+
+/* =============================================================
+ * State enable/disable
+ */
+
+static void radeonEnable( GLcontext *ctx, GLenum cap, GLboolean state )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint p, flag;
+
+ if ( RADEON_DEBUG & DEBUG_STATE )
+ fprintf( stderr, "%s( %s = %s )\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr( cap ),
+ state ? "GL_TRUE" : "GL_FALSE" );
+
+ switch ( cap ) {
+ /* Fast track this one...
+ */
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_3D:
+ break;
+
+ case GL_ALPHA_TEST:
+ RADEON_STATECHANGE( rmesa, ctx );
+ if (state) {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ALPHA_TEST_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ALPHA_TEST_ENABLE;
+ }
+ break;
+
+ case GL_BLEND:
+ RADEON_STATECHANGE( rmesa, ctx );
+ if (state) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ALPHA_BLEND_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ALPHA_BLEND_ENABLE;
+ }
+ if ( ctx->Color.ColorLogicOpEnabled ) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE;
+ }
+
+ /* Catch a possible fallback:
+ */
+ if (state) {
+ ctx->Driver.BlendEquation( ctx, ctx->Color.BlendEquation );
+ ctx->Driver.BlendFunc( ctx, ctx->Color.BlendSrcRGB,
+ ctx->Color.BlendDstRGB );
+ }
+ else {
+ FALLBACK( rmesa, RADEON_FALLBACK_BLEND_FUNC, GL_FALSE );
+ FALLBACK( rmesa, RADEON_FALLBACK_BLEND_EQ, GL_FALSE );
+ }
+ break;
+
+ case GL_CLIP_PLANE0:
+ case GL_CLIP_PLANE1:
+ case GL_CLIP_PLANE2:
+ case GL_CLIP_PLANE3:
+ case GL_CLIP_PLANE4:
+ case GL_CLIP_PLANE5:
+ p = cap-GL_CLIP_PLANE0;
+ RADEON_STATECHANGE( rmesa, tcl );
+ if (state) {
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= (RADEON_UCP_ENABLE_0<<p);
+ radeonClipPlane( ctx, cap, NULL );
+ }
+ else {
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~(RADEON_UCP_ENABLE_0<<p);
+ }
+ break;
+
+ case GL_COLOR_MATERIAL:
+ radeonColorMaterial( ctx, 0, 0 );
+ if (!state)
+ radeonUpdateMaterial( ctx );
+ break;
+
+ case GL_CULL_FACE:
+ radeonCullFace( ctx, 0 );
+ break;
+
+ case GL_DEPTH_TEST:
+ RADEON_STATECHANGE(rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_Z_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_Z_ENABLE;
+ }
+ break;
+
+ case GL_DITHER:
+ RADEON_STATECHANGE(rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_DITHER_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_DITHER_ENABLE;
+ }
+ break;
+
+ case GL_FOG:
+ RADEON_STATECHANGE(rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_FOG_ENABLE;
+ radeonFogfv( ctx, GL_FOG_MODE, 0 );
+ } else {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_FOG_ENABLE;
+ RADEON_STATECHANGE(rmesa, tcl);
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK;
+ }
+ radeonUpdateSpecular( ctx ); /* for PK_SPEC */
+ if (rmesa->TclFallback)
+ radeonChooseVertexState( ctx );
+ _mesa_allow_light_in_model( ctx, !state );
+ break;
+
+ case GL_LIGHT0:
+ case GL_LIGHT1:
+ case GL_LIGHT2:
+ case GL_LIGHT3:
+ case GL_LIGHT4:
+ case GL_LIGHT5:
+ case GL_LIGHT6:
+ case GL_LIGHT7:
+ RADEON_STATECHANGE(rmesa, tcl);
+ p = cap - GL_LIGHT0;
+ if (p&1)
+ flag = (RADEON_LIGHT_1_ENABLE |
+ RADEON_LIGHT_1_ENABLE_AMBIENT |
+ RADEON_LIGHT_1_ENABLE_SPECULAR);
+ else
+ flag = (RADEON_LIGHT_0_ENABLE |
+ RADEON_LIGHT_0_ENABLE_AMBIENT |
+ RADEON_LIGHT_0_ENABLE_SPECULAR);
+
+ if (state)
+ rmesa->hw.tcl.cmd[p/2 + TCL_PER_LIGHT_CTL_0] |= flag;
+ else
+ rmesa->hw.tcl.cmd[p/2 + TCL_PER_LIGHT_CTL_0] &= ~flag;
+
+ /*
+ */
+ update_light_colors( ctx, p );
+ break;
+
+ case GL_LIGHTING:
+ RADEON_STATECHANGE(rmesa, tcl);
+ radeonUpdateSpecular(ctx);
+ check_twoside_fallback( ctx );
+ break;
+
+ case GL_LINE_SMOOTH:
+ RADEON_STATECHANGE( rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ANTI_ALIAS_LINE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ANTI_ALIAS_LINE;
+ }
+ break;
+
+ case GL_LINE_STIPPLE:
+ RADEON_STATECHANGE( rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_PATTERN_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_PATTERN_ENABLE;
+ }
+ break;
+
+ case GL_COLOR_LOGIC_OP:
+ RADEON_STATECHANGE( rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE;
+ }
+ break;
+
+ case GL_NORMALIZE:
+ RADEON_STATECHANGE( rmesa, tcl );
+ if ( state ) {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_NORMALIZE_NORMALS;
+ } else {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_NORMALIZE_NORMALS;
+ }
+ break;
+
+ case GL_POLYGON_OFFSET_POINT:
+ if (rmesa->dri.drmMinor == 1) {
+ radeonChooseRenderState( ctx );
+ }
+ else {
+ RADEON_STATECHANGE( rmesa, set );
+ if ( state ) {
+ rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_POINT;
+ } else {
+ rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_POINT;
+ }
+ }
+ break;
+
+ case GL_POLYGON_OFFSET_LINE:
+ if (rmesa->dri.drmMinor == 1) {
+ radeonChooseRenderState( ctx );
+ }
+ else {
+ RADEON_STATECHANGE( rmesa, set );
+ if ( state ) {
+ rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_LINE;
+ } else {
+ rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_LINE;
+ }
+ }
+ break;
+
+ case GL_POLYGON_OFFSET_FILL:
+ if (rmesa->dri.drmMinor == 1) {
+ radeonChooseRenderState( ctx );
+ }
+ else {
+ RADEON_STATECHANGE( rmesa, set );
+ if ( state ) {
+ rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_TRI;
+ } else {
+ rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_TRI;
+ }
+ }
+ break;
+
+ case GL_POLYGON_SMOOTH:
+ RADEON_STATECHANGE( rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ANTI_ALIAS_POLY;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ANTI_ALIAS_POLY;
+ }
+ break;
+
+ case GL_POLYGON_STIPPLE:
+ RADEON_STATECHANGE(rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_STIPPLE_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_STIPPLE_ENABLE;
+ }
+ break;
+
+ case GL_RESCALE_NORMAL_EXT: {
+ GLboolean tmp = ctx->_NeedEyeCoords ? state : !state;
+ RADEON_STATECHANGE( rmesa, tcl );
+ if ( tmp ) {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS;
+ } else {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS;
+ }
+ break;
+ }
+
+ case GL_SCISSOR_TEST:
+ RADEON_FIREVERTICES( rmesa );
+ rmesa->state.scissor.enabled = state;
+ radeonUpdateScissor( ctx );
+ break;
+
+ case GL_STENCIL_TEST:
+ if ( rmesa->state.stencil.hwBuffer ) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ if ( state ) {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_STENCIL_ENABLE;
+ } else {
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_STENCIL_ENABLE;
+ }
+ } else {
+ FALLBACK( rmesa, RADEON_FALLBACK_STENCIL, state );
+ }
+ break;
+
+ case GL_TEXTURE_GEN_Q:
+ case GL_TEXTURE_GEN_R:
+ case GL_TEXTURE_GEN_S:
+ case GL_TEXTURE_GEN_T:
+ /* Picked up in radeonUpdateTextureState.
+ */
+ rmesa->recheck_texgen[ctx->Texture.CurrentUnit] = GL_TRUE;
+ break;
+
+ case GL_COLOR_SUM_EXT:
+ radeonUpdateSpecular ( ctx );
+ break;
+
+ default:
+ return;
+ }
+}
+
+
+static void radeonLightingSpaceChange( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLboolean tmp;
+ RADEON_STATECHANGE( rmesa, tcl );
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s %d BEFORE %x\n", __FUNCTION__, ctx->_NeedEyeCoords,
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]);
+
+ if (ctx->_NeedEyeCoords)
+ tmp = ctx->Transform.RescaleNormals;
+ else
+ tmp = !ctx->Transform.RescaleNormals;
+
+ if ( tmp ) {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS;
+ } else {
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS;
+ }
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s %d AFTER %x\n", __FUNCTION__, ctx->_NeedEyeCoords,
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]);
+}
+
+/* =============================================================
+ * Deferred state management - matrices, textures, other?
+ */
+
+
+
+
+static void upload_matrix( radeonContextPtr rmesa, GLfloat *src, int idx )
+{
+ float *dest = ((float *)RADEON_DB_STATE( mat[idx] ))+MAT_ELT_0;
+ int i;
+
+
+ for (i = 0 ; i < 4 ; i++) {
+ *dest++ = src[i];
+ *dest++ = src[i+4];
+ *dest++ = src[i+8];
+ *dest++ = src[i+12];
+ }
+
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mat[idx] );
+}
+
+static void upload_matrix_t( radeonContextPtr rmesa, GLfloat *src, int idx )
+{
+ float *dest = ((float *)RADEON_DB_STATE( mat[idx] ))+MAT_ELT_0;
+ memcpy(dest, src, 16*sizeof(float));
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mat[idx] );
+}
+
+
+static void update_texturematrix( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ GLuint tpc = rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL];
+ GLuint vs = rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL];
+ int unit;
+
+ rmesa->TexMatEnabled = 0;
+
+ for (unit = 0 ; unit < 2; unit++) {
+ if (!ctx->Texture.Unit[unit]._ReallyEnabled) {
+ }
+ else if (ctx->TextureMatrixStack[unit].Top->type != MATRIX_IDENTITY) {
+ GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4;
+
+ rmesa->TexMatEnabled |= (RADEON_TEXGEN_TEXMAT_0_ENABLE|
+ RADEON_TEXMAT_0_ENABLE) << unit;
+
+ if (rmesa->TexGenEnabled & (RADEON_TEXMAT_0_ENABLE << unit)) {
+ /* Need to preconcatenate any active texgen
+ * obj/eyeplane matrices:
+ */
+ _math_matrix_mul_matrix( &rmesa->tmpmat,
+ &rmesa->TexGenMatrix[unit],
+ ctx->TextureMatrixStack[unit].Top );
+ upload_matrix( rmesa, rmesa->tmpmat.m, TEXMAT_0+unit );
+ }
+ else {
+ rmesa->TexMatEnabled |=
+ (RADEON_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift;
+ upload_matrix( rmesa, ctx->TextureMatrixStack[unit].Top->m,
+ TEXMAT_0+unit );
+ }
+ }
+ else if (rmesa->TexGenEnabled & (RADEON_TEXMAT_0_ENABLE << unit)) {
+ upload_matrix( rmesa, rmesa->TexGenMatrix[unit].m,
+ TEXMAT_0+unit );
+ }
+ }
+
+
+ tpc = (rmesa->TexMatEnabled | rmesa->TexGenEnabled);
+
+ vs &= ~((0xf << RADEON_TCL_TEX_0_OUTPUT_SHIFT) |
+ (0xf << RADEON_TCL_TEX_1_OUTPUT_SHIFT));
+
+ if (tpc & RADEON_TEXGEN_TEXMAT_0_ENABLE)
+ vs |= RADEON_TCL_TEX_COMPUTED_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT;
+ else
+ vs |= RADEON_TCL_TEX_INPUT_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT;
+
+ if (tpc & RADEON_TEXGEN_TEXMAT_1_ENABLE)
+ vs |= RADEON_TCL_TEX_COMPUTED_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT;
+ else
+ vs |= RADEON_TCL_TEX_INPUT_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT;
+
+ if (tpc != rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] ||
+ vs != rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL]) {
+
+ RADEON_STATECHANGE(rmesa, tcl);
+ rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] = tpc;
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] = vs;
+ }
+}
+
+
+
+void radeonValidateState( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint new_state = rmesa->NewGLState;
+
+ if (new_state & _NEW_TEXTURE) {
+ radeonUpdateTextureState( ctx );
+ new_state |= rmesa->NewGLState; /* may add TEXTURE_MATRIX */
+ }
+
+ /* Need an event driven matrix update?
+ */
+ if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION))
+ upload_matrix( rmesa, ctx->_ModelProjectMatrix.m, MODEL_PROJ );
+
+ /* Need these for lighting (shouldn't upload otherwise)
+ */
+ if (new_state & (_NEW_MODELVIEW)) {
+ upload_matrix( rmesa, ctx->ModelviewMatrixStack.Top->m, MODEL );
+ upload_matrix_t( rmesa, ctx->ModelviewMatrixStack.Top->inv, MODEL_IT );
+ }
+
+ /* Does this need to be triggered on eg. modelview for
+ * texgen-derived objplane/eyeplane matrices?
+ */
+ if (new_state & _NEW_TEXTURE_MATRIX) {
+ update_texturematrix( ctx );
+ }
+
+ if (new_state & (_NEW_LIGHT|_NEW_MODELVIEW|_MESA_NEW_NEED_EYE_COORDS)) {
+ update_light( ctx );
+ }
+
+ /* emit all active clip planes if projection matrix changes.
+ */
+ if (new_state & (_NEW_PROJECTION)) {
+ if (ctx->Transform.ClipPlanesEnabled)
+ radeonUpdateClipPlanes( ctx );
+ }
+
+
+ rmesa->NewGLState = 0;
+}
+
+
+static void radeonInvalidateState( 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 );
+ _ae_invalidate_state( ctx, new_state );
+ RADEON_CONTEXT(ctx)->NewGLState |= new_state;
+ radeonVtxfmtInvalidate( ctx );
+}
+
+static void radeonWrapRunPipeline( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ if (0)
+ fprintf(stderr, "%s, newstate: %x\n", __FUNCTION__, rmesa->NewGLState);
+
+ /* Validate state:
+ */
+ if (rmesa->NewGLState)
+ radeonValidateState( ctx );
+
+ if (tnl->vb.Material) {
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_MATERIAL, GL_TRUE );
+ }
+
+ /* Run the pipeline.
+ */
+ _tnl_run_pipeline( ctx );
+
+ if (tnl->vb.Material) {
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_MATERIAL, GL_FALSE );
+ radeonUpdateMaterial( ctx ); /* not needed any more? */
+ }
+}
+
+
+/* Initialize the driver's state functions.
+ */
+void radeonInitStateFuncs( GLcontext *ctx )
+{
+ ctx->Driver.UpdateState = radeonInvalidateState;
+ ctx->Driver.LightingSpaceChange = radeonLightingSpaceChange;
+
+ ctx->Driver.DrawBuffer = radeonDrawBuffer;
+ ctx->Driver.ReadBuffer = radeonReadBuffer;
+
+ ctx->Driver.AlphaFunc = radeonAlphaFunc;
+ ctx->Driver.BlendEquation = radeonBlendEquation;
+ ctx->Driver.BlendFunc = radeonBlendFunc;
+ ctx->Driver.BlendFuncSeparate = radeonBlendFuncSeparate;
+ ctx->Driver.ClearColor = radeonClearColor;
+ ctx->Driver.ClearDepth = radeonClearDepth;
+ ctx->Driver.ClearIndex = NULL;
+ ctx->Driver.ClearStencil = radeonClearStencil;
+ ctx->Driver.ClipPlane = radeonClipPlane;
+ ctx->Driver.ColorMask = radeonColorMask;
+ ctx->Driver.CullFace = radeonCullFace;
+ ctx->Driver.DepthFunc = radeonDepthFunc;
+ ctx->Driver.DepthMask = radeonDepthMask;
+ ctx->Driver.DepthRange = radeonDepthRange;
+ ctx->Driver.Enable = radeonEnable;
+ ctx->Driver.Fogfv = radeonFogfv;
+ ctx->Driver.FrontFace = radeonFrontFace;
+ ctx->Driver.Hint = NULL;
+ ctx->Driver.IndexMask = NULL;
+ ctx->Driver.LightModelfv = radeonLightModelfv;
+ ctx->Driver.Lightfv = radeonLightfv;
+ ctx->Driver.LineStipple = radeonLineStipple;
+ ctx->Driver.LineWidth = radeonLineWidth;
+ ctx->Driver.LogicOpcode = radeonLogicOpCode;
+ ctx->Driver.PolygonMode = radeonPolygonMode;
+
+ if (RADEON_CONTEXT(ctx)->dri.drmMinor > 1)
+ ctx->Driver.PolygonOffset = radeonPolygonOffset;
+
+ ctx->Driver.PolygonStipple = radeonPolygonStipple;
+ ctx->Driver.RenderMode = radeonRenderMode;
+ ctx->Driver.Scissor = radeonScissor;
+ ctx->Driver.ShadeModel = radeonShadeModel;
+ ctx->Driver.StencilFunc = radeonStencilFunc;
+ ctx->Driver.StencilMask = radeonStencilMask;
+ ctx->Driver.StencilOp = radeonStencilOp;
+ ctx->Driver.Viewport = radeonViewport;
+
+ /* 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;
+
+ /* 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;
+
+ TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange = radeonUpdateMaterial;
+ TNL_CONTEXT(ctx)->Driver.RunPipeline = radeonWrapRunPipeline;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_state.h b/src/mesa/drivers/dri/radeon/radeon_state.h
new file mode 100644
index 0000000000..a181d427e6
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_state.h
@@ -0,0 +1,77 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.h,v 1.5 2002/11/05 17:46:09 tsi Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __RADEON_STATE_H__
+#define __RADEON_STATE_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "radeon_context.h"
+
+extern void radeonInitState( radeonContextPtr rmesa );
+extern void radeonInitStateFuncs( GLcontext *ctx );
+
+extern void radeonUpdateMaterial( GLcontext *ctx );
+
+extern void radeonSetCliprects( radeonContextPtr rmesa, GLenum mode );
+extern void radeonRecalcScissorRects( radeonContextPtr rmesa );
+extern void radeonUpdateViewportOffset( GLcontext *ctx );
+extern void radeonUpdateWindow( GLcontext *ctx );
+
+extern void radeonValidateState( GLcontext *ctx );
+
+extern void radeonPrintDirty( radeonContextPtr rmesa,
+ const char *msg );
+
+
+extern void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode );
+#define FALLBACK( rmesa, bit, mode ) do { \
+ if ( 0 ) fprintf( stderr, "FALLBACK in %s: #%d=%d\n", \
+ __FUNCTION__, bit, mode ); \
+ radeonFallback( rmesa->glCtx, bit, mode ); \
+} while (0)
+
+
+#define MODEL_PROJ 0
+#define MODEL 1
+#define MODEL_IT 2
+#define TEXMAT_0 3
+#define TEXMAT_1 4
+#define TEXMAT_2 5
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_state_init.c b/src/mesa/drivers/dri/radeon/radeon_state_init.c
new file mode 100644
index 0000000000..971ea699ea
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_state_init.c
@@ -0,0 +1,531 @@
+/* $XFree86$ */
+/*
+ * Copyright 2000, 2001 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "api_arrayelt.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 "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_tcl.h"
+#include "radeon_tex.h"
+#include "radeon_swtcl.h"
+#include "radeon_vtxfmt.h"
+
+/* =============================================================
+ * State initialization
+ */
+
+void radeonPrintDirty( radeonContextPtr rmesa, const char *msg )
+{
+ struct radeon_state_atom *l;
+
+ fprintf(stderr, msg);
+ fprintf(stderr, ": ");
+
+ foreach(l, &(rmesa->hw.dirty)) {
+ fprintf(stderr, "%s, ", l->name);
+ }
+
+ fprintf(stderr, "\n");
+}
+
+static int cmdpkt( int id )
+{
+ drmRadeonCmdHeader h;
+ h.i = 0;
+ h.packet.cmd_type = RADEON_CMD_PACKET;
+ h.packet.packet_id = id;
+ return h.i;
+}
+
+static int cmdvec( int offset, int stride, int count )
+{
+ drmRadeonCmdHeader h;
+ h.i = 0;
+ h.vectors.cmd_type = RADEON_CMD_VECTORS;
+ h.vectors.offset = offset;
+ h.vectors.stride = stride;
+ h.vectors.count = count;
+ return h.i;
+}
+
+static int cmdscl( int offset, int stride, int count )
+{
+ drmRadeonCmdHeader h;
+ h.i = 0;
+ h.scalars.cmd_type = RADEON_CMD_SCALARS;
+ h.scalars.offset = offset;
+ h.scalars.stride = stride;
+ h.scalars.count = count;
+ return h.i;
+}
+
+#define CHECK( NM, FLAG ) \
+static GLboolean check_##NM( GLcontext *ctx ) \
+{ \
+ return FLAG; \
+}
+
+#define TCL_CHECK( NM, FLAG ) \
+static GLboolean check_##NM( GLcontext *ctx ) \
+{ \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ return !rmesa->TclFallback && (FLAG); \
+}
+
+
+CHECK( always, GL_TRUE )
+CHECK( tex0, ctx->Texture.Unit[0]._ReallyEnabled )
+CHECK( tex1, ctx->Texture.Unit[1]._ReallyEnabled )
+CHECK( fog, ctx->Fog.Enabled )
+TCL_CHECK( tcl, GL_TRUE )
+TCL_CHECK( tcl_tex0, ctx->Texture.Unit[0]._ReallyEnabled )
+TCL_CHECK( tcl_tex1, ctx->Texture.Unit[1]._ReallyEnabled )
+TCL_CHECK( tcl_lighting, ctx->Light.Enabled )
+TCL_CHECK( tcl_eyespace_or_lighting, ctx->_NeedEyeCoords || ctx->Light.Enabled )
+TCL_CHECK( tcl_lit0, ctx->Light.Enabled && ctx->Light.Light[0].Enabled )
+TCL_CHECK( tcl_lit1, ctx->Light.Enabled && ctx->Light.Light[1].Enabled )
+TCL_CHECK( tcl_lit2, ctx->Light.Enabled && ctx->Light.Light[2].Enabled )
+TCL_CHECK( tcl_lit3, ctx->Light.Enabled && ctx->Light.Light[3].Enabled )
+TCL_CHECK( tcl_lit4, ctx->Light.Enabled && ctx->Light.Light[4].Enabled )
+TCL_CHECK( tcl_lit5, ctx->Light.Enabled && ctx->Light.Light[5].Enabled )
+TCL_CHECK( tcl_lit6, ctx->Light.Enabled && ctx->Light.Light[6].Enabled )
+TCL_CHECK( tcl_lit7, ctx->Light.Enabled && ctx->Light.Light[7].Enabled )
+TCL_CHECK( tcl_ucp0, (ctx->Transform.ClipPlanesEnabled & 0x1) )
+TCL_CHECK( tcl_ucp1, (ctx->Transform.ClipPlanesEnabled & 0x2) )
+TCL_CHECK( tcl_ucp2, (ctx->Transform.ClipPlanesEnabled & 0x4) )
+TCL_CHECK( tcl_ucp3, (ctx->Transform.ClipPlanesEnabled & 0x8) )
+TCL_CHECK( tcl_ucp4, (ctx->Transform.ClipPlanesEnabled & 0x10) )
+TCL_CHECK( tcl_ucp5, (ctx->Transform.ClipPlanesEnabled & 0x20) )
+TCL_CHECK( tcl_eyespace_or_fog, ctx->_NeedEyeCoords || ctx->Fog.Enabled )
+
+CHECK( txr0, (ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_RECT_BIT))
+CHECK( txr1, (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_RECT_BIT))
+
+
+
+/* Initialize the context's hardware state.
+ */
+void radeonInitState( radeonContextPtr rmesa )
+{
+ GLcontext *ctx = rmesa->glCtx;
+ GLuint color_fmt, depth_fmt, i;
+
+ switch ( rmesa->radeonScreen->cpp ) {
+ case 2:
+ color_fmt = RADEON_COLOR_FORMAT_RGB565;
+ break;
+ case 4:
+ color_fmt = RADEON_COLOR_FORMAT_ARGB8888;
+ break;
+ default:
+ fprintf( stderr, "Error: Unsupported pixel depth... exiting\n" );
+ exit( -1 );
+ }
+
+ rmesa->state.color.clear = 0x00000000;
+
+ switch ( ctx->Visual.depthBits ) {
+ case 16:
+ rmesa->state.depth.clear = 0x0000ffff;
+ rmesa->state.depth.scale = 1.0 / (GLfloat)0xffff;
+ depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z;
+ rmesa->state.stencil.clear = 0x00000000;
+ break;
+ case 24:
+ rmesa->state.depth.clear = 0x00ffffff;
+ rmesa->state.depth.scale = 1.0 / (GLfloat)0xffffff;
+ depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z;
+ rmesa->state.stencil.clear = 0xff000000;
+ break;
+ default:
+ fprintf( stderr, "Error: Unsupported depth %d... exiting\n",
+ ctx->Visual.depthBits );
+ exit( -1 );
+ }
+
+ /* Only have hw stencil when depth buffer is 24 bits deep */
+ rmesa->state.stencil.hwBuffer = ( ctx->Visual.stencilBits > 0 &&
+ ctx->Visual.depthBits == 24 );
+
+ rmesa->Fallback = 0;
+
+ if ( ctx->Visual.doubleBufferMode && rmesa->sarea->pfCurrentPage == 0 ) {
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch;
+ } else {
+ rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset;
+ rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch;
+ }
+ rmesa->state.pixel.readOffset = rmesa->state.color.drawOffset;
+ rmesa->state.pixel.readPitch = rmesa->state.color.drawPitch;
+
+ /* Initialize lists:
+ */
+ make_empty_list(&(rmesa->hw.dirty));
+ make_empty_list(&(rmesa->hw.clean));
+
+
+#define ALLOC_STATE( ATOM, CHK, SZ, NM, FLAG ) \
+ do { \
+ rmesa->hw.ATOM.cmd_size = SZ; \
+ rmesa->hw.ATOM.cmd = (int *)CALLOC(SZ * sizeof(int)); \
+ rmesa->hw.ATOM.lastcmd = (int *)CALLOC(SZ * sizeof(int)); \
+ rmesa->hw.ATOM.name = NM; \
+ rmesa->hw.ATOM.is_tcl = FLAG; \
+ rmesa->hw.ATOM.check = check_##CHK; \
+ insert_at_head(&(rmesa->hw.dirty), &(rmesa->hw.ATOM)); \
+ } while (0)
+
+
+ /* Allocate state buffers:
+ */
+ ALLOC_STATE( ctx, always, CTX_STATE_SIZE, "CTX/context", 0 );
+ ALLOC_STATE( lin, always, LIN_STATE_SIZE, "LIN/line", 0 );
+ ALLOC_STATE( msk, always, MSK_STATE_SIZE, "MSK/mask", 0 );
+ ALLOC_STATE( vpt, always, VPT_STATE_SIZE, "VPT/viewport", 0 );
+ ALLOC_STATE( set, always, SET_STATE_SIZE, "SET/setup", 0 );
+ ALLOC_STATE( msc, always, MSC_STATE_SIZE, "MSC/misc", 0 );
+ ALLOC_STATE( zbs, always, ZBS_STATE_SIZE, "ZBS/zbias", 0 );
+ ALLOC_STATE( tcl, always, TCL_STATE_SIZE, "TCL/tcl", 1 );
+ ALLOC_STATE( mtl, tcl_lighting, MTL_STATE_SIZE, "MTL/material", 1 );
+ ALLOC_STATE( grd, always, GRD_STATE_SIZE, "GRD/guard-band", 1 );
+ ALLOC_STATE( fog, fog, FOG_STATE_SIZE, "FOG/fog", 1 );
+ ALLOC_STATE( glt, tcl_lighting, GLT_STATE_SIZE, "GLT/light-global", 1 );
+ ALLOC_STATE( eye, tcl_lighting, EYE_STATE_SIZE, "EYE/eye-vector", 1 );
+ ALLOC_STATE( tex[0], tex0, TEX_STATE_SIZE, "TEX/tex-0", 0 );
+ ALLOC_STATE( tex[1], tex1, TEX_STATE_SIZE, "TEX/tex-1", 0 );
+ ALLOC_STATE( mat[0], tcl, MAT_STATE_SIZE, "MAT/modelproject", 1 );
+ ALLOC_STATE( mat[1], tcl_eyespace_or_fog, MAT_STATE_SIZE, "MAT/modelview", 1 );
+ ALLOC_STATE( mat[2], tcl_eyespace_or_lighting, MAT_STATE_SIZE, "MAT/it-modelview", 1 );
+ ALLOC_STATE( mat[3], tcl_tex0, MAT_STATE_SIZE, "MAT/texmat0", 1 );
+ ALLOC_STATE( mat[4], tcl_tex1, MAT_STATE_SIZE, "MAT/texmat1", 1 );
+ ALLOC_STATE( ucp[0], tcl_ucp0, UCP_STATE_SIZE, "UCP/userclip-0", 1 );
+ ALLOC_STATE( ucp[1], tcl_ucp1, UCP_STATE_SIZE, "UCP/userclip-1", 1 );
+ ALLOC_STATE( ucp[2], tcl_ucp2, UCP_STATE_SIZE, "UCP/userclip-2", 1 );
+ ALLOC_STATE( ucp[3], tcl_ucp3, UCP_STATE_SIZE, "UCP/userclip-3", 1 );
+ ALLOC_STATE( ucp[4], tcl_ucp4, UCP_STATE_SIZE, "UCP/userclip-4", 1 );
+ ALLOC_STATE( ucp[5], tcl_ucp5, UCP_STATE_SIZE, "UCP/userclip-5", 1 );
+ ALLOC_STATE( lit[0], tcl_lit0, LIT_STATE_SIZE, "LIT/light-0", 1 );
+ ALLOC_STATE( lit[1], tcl_lit1, LIT_STATE_SIZE, "LIT/light-1", 1 );
+ ALLOC_STATE( lit[2], tcl_lit2, LIT_STATE_SIZE, "LIT/light-2", 1 );
+ ALLOC_STATE( lit[3], tcl_lit3, LIT_STATE_SIZE, "LIT/light-3", 1 );
+ ALLOC_STATE( lit[4], tcl_lit4, LIT_STATE_SIZE, "LIT/light-4", 1 );
+ ALLOC_STATE( lit[5], tcl_lit5, LIT_STATE_SIZE, "LIT/light-5", 1 );
+ ALLOC_STATE( lit[6], tcl_lit6, LIT_STATE_SIZE, "LIT/light-6", 1 );
+ ALLOC_STATE( lit[7], tcl_lit7, LIT_STATE_SIZE, "LIT/light-7", 1 );
+ ALLOC_STATE( txr[0], txr0, TXR_STATE_SIZE, "TXR/txr-0", 0 );
+ ALLOC_STATE( txr[1], txr1, TXR_STATE_SIZE, "TXR/txr-1", 0 );
+
+
+ /* Fill in the packet headers:
+ */
+ rmesa->hw.ctx.cmd[CTX_CMD_0] = cmdpkt(RADEON_EMIT_PP_MISC);
+ rmesa->hw.ctx.cmd[CTX_CMD_1] = cmdpkt(RADEON_EMIT_PP_CNTL);
+ rmesa->hw.ctx.cmd[CTX_CMD_2] = cmdpkt(RADEON_EMIT_RB3D_COLORPITCH);
+ rmesa->hw.lin.cmd[LIN_CMD_0] = cmdpkt(RADEON_EMIT_RE_LINE_PATTERN);
+ rmesa->hw.lin.cmd[LIN_CMD_1] = cmdpkt(RADEON_EMIT_SE_LINE_WIDTH);
+ rmesa->hw.msk.cmd[MSK_CMD_0] = cmdpkt(RADEON_EMIT_RB3D_STENCILREFMASK);
+ rmesa->hw.vpt.cmd[VPT_CMD_0] = cmdpkt(RADEON_EMIT_SE_VPORT_XSCALE);
+ rmesa->hw.set.cmd[SET_CMD_0] = cmdpkt(RADEON_EMIT_SE_CNTL);
+ rmesa->hw.set.cmd[SET_CMD_1] = cmdpkt(RADEON_EMIT_SE_CNTL_STATUS);
+ rmesa->hw.msc.cmd[MSC_CMD_0] = cmdpkt(RADEON_EMIT_RE_MISC);
+ rmesa->hw.tex[0].cmd[TEX_CMD_0] = cmdpkt(RADEON_EMIT_PP_TXFILTER_0);
+ rmesa->hw.tex[0].cmd[TEX_CMD_1] = cmdpkt(RADEON_EMIT_PP_BORDER_COLOR_0);
+ rmesa->hw.tex[1].cmd[TEX_CMD_0] = cmdpkt(RADEON_EMIT_PP_TXFILTER_1);
+ rmesa->hw.tex[1].cmd[TEX_CMD_1] = cmdpkt(RADEON_EMIT_PP_BORDER_COLOR_1);
+ rmesa->hw.zbs.cmd[ZBS_CMD_0] = cmdpkt(RADEON_EMIT_SE_ZBIAS_FACTOR);
+ rmesa->hw.tcl.cmd[TCL_CMD_0] = cmdpkt(RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT);
+ rmesa->hw.mtl.cmd[MTL_CMD_0] =
+ cmdpkt(RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED);
+ rmesa->hw.txr[0].cmd[TXR_CMD_0] = cmdpkt(RADEON_EMIT_PP_TEX_SIZE_0);
+ rmesa->hw.txr[1].cmd[TXR_CMD_0] = cmdpkt(RADEON_EMIT_PP_TEX_SIZE_1);
+ rmesa->hw.grd.cmd[GRD_CMD_0] =
+ cmdscl( RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR, 1, 4 );
+ rmesa->hw.fog.cmd[FOG_CMD_0] =
+ cmdvec( RADEON_VS_FOG_PARAM_ADDR, 1, 4 );
+ rmesa->hw.glt.cmd[GLT_CMD_0] =
+ cmdvec( RADEON_VS_GLOBAL_AMBIENT_ADDR, 1, 4 );
+ rmesa->hw.eye.cmd[EYE_CMD_0] =
+ cmdvec( RADEON_VS_EYE_VECTOR_ADDR, 1, 4 );
+
+ for (i = 0 ; i < 5; i++) {
+ rmesa->hw.mat[i].cmd[MAT_CMD_0] =
+ cmdvec( RADEON_VS_MATRIX_0_ADDR + i*4, 1, 16);
+ }
+
+ for (i = 0 ; i < 8; i++) {
+ rmesa->hw.lit[i].cmd[LIT_CMD_0] =
+ cmdvec( RADEON_VS_LIGHT_AMBIENT_ADDR + i, 8, 24 );
+ rmesa->hw.lit[i].cmd[LIT_CMD_1] =
+ cmdscl( RADEON_SS_LIGHT_DCD_ADDR + i, 8, 6 );
+ }
+
+ for (i = 0 ; i < 6; i++) {
+ rmesa->hw.ucp[i].cmd[UCP_CMD_0] =
+ cmdvec( RADEON_VS_UCP_ADDR + i, 1, 4 );
+ }
+
+ rmesa->last_ReallyEnabled = -1;
+
+ /* Initial Harware state:
+ */
+ rmesa->hw.ctx.cmd[CTX_PP_MISC] = (RADEON_ALPHA_TEST_PASS |
+ RADEON_CHROMA_FUNC_FAIL |
+ RADEON_CHROMA_KEY_NEAREST |
+ RADEON_SHADOW_FUNC_EQUAL |
+ RADEON_SHADOW_PASS_1 |
+ RADEON_RIGHT_HAND_CUBE_OGL);
+
+ rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] = (RADEON_FOG_VERTEX |
+ RADEON_FOG_USE_DEPTH);
+
+ rmesa->hw.ctx.cmd[CTX_RE_SOLID_COLOR] = 0x00000000;
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = (RADEON_COMB_FCN_ADD_CLAMP |
+ RADEON_SRC_BLEND_GL_ONE |
+ RADEON_DST_BLEND_GL_ZERO );
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHOFFSET] =
+ rmesa->radeonScreen->depthOffset;
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHPITCH] =
+ ((rmesa->radeonScreen->depthPitch &
+ RADEON_DEPTHPITCH_MASK) |
+ RADEON_DEPTH_ENDIAN_NO_SWAP);
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] = (depth_fmt |
+ RADEON_Z_TEST_LESS |
+ RADEON_STENCIL_TEST_ALWAYS |
+ RADEON_STENCIL_FAIL_KEEP |
+ RADEON_STENCIL_ZPASS_KEEP |
+ RADEON_STENCIL_ZFAIL_KEEP |
+ RADEON_Z_WRITE_ENABLE);
+
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] = (RADEON_SCISSOR_ENABLE |
+ RADEON_ANTI_ALIAS_NONE);
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] = (RADEON_PLANE_MASK_ENABLE |
+ color_fmt |
+ (1<<15));
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_DITHER_ENABLE;
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset &
+ RADEON_COLOROFFSET_MASK);
+
+ rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = ((rmesa->state.color.drawPitch &
+ RADEON_COLORPITCH_MASK) |
+ RADEON_COLOR_ENDIAN_NO_SWAP);
+
+ rmesa->hw.set.cmd[SET_SE_CNTL] = (RADEON_FFACE_CULL_CCW |
+ RADEON_BFACE_SOLID |
+ RADEON_FFACE_SOLID |
+/* RADEON_BADVTX_CULL_DISABLE | */
+ RADEON_FLAT_SHADE_VTX_LAST |
+ RADEON_DIFFUSE_SHADE_GOURAUD |
+ RADEON_ALPHA_SHADE_GOURAUD |
+ RADEON_SPECULAR_SHADE_GOURAUD |
+ RADEON_FOG_SHADE_GOURAUD |
+ RADEON_VPORT_XY_XFORM_ENABLE |
+ RADEON_VPORT_Z_XFORM_ENABLE |
+ RADEON_VTX_PIX_CENTER_OGL |
+ RADEON_ROUND_MODE_TRUNC |
+ RADEON_ROUND_PREC_8TH_PIX);
+
+ rmesa->hw.set.cmd[SET_SE_CNTL_STATUS] =
+#ifdef MESA_BIG_ENDIAN
+ RADEON_VC_32BIT_SWAP;
+#else
+ RADEON_VC_NO_SWAP;
+#endif
+
+ if (!(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) {
+ rmesa->hw.set.cmd[SET_SE_CNTL_STATUS] |= RADEON_TCL_BYPASS;
+ }
+
+ rmesa->hw.set.cmd[SET_SE_COORDFMT] = (
+ RADEON_VTX_W0_IS_NOT_1_OVER_W0 |
+ RADEON_TEX1_W_ROUTING_USE_Q1);
+
+
+ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] = ((1 << 16) | 0xffff);
+
+ rmesa->hw.lin.cmd[LIN_RE_LINE_STATE] =
+ ((0 << RADEON_LINE_CURRENT_PTR_SHIFT) |
+ (1 << RADEON_LINE_CURRENT_COUNT_SHIFT));
+
+ rmesa->hw.lin.cmd[LIN_SE_LINE_WIDTH] = (1 << 4);
+
+ rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] =
+ ((0x00 << RADEON_STENCIL_REF_SHIFT) |
+ (0xff << RADEON_STENCIL_MASK_SHIFT) |
+ (0xff << RADEON_STENCIL_WRITEMASK_SHIFT));
+
+ rmesa->hw.msk.cmd[MSK_RB3D_ROPCNTL] = RADEON_ROP_COPY;
+ rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] = 0xffffffff;
+
+ rmesa->hw.msc.cmd[MSC_RE_MISC] =
+ ((0 << RADEON_STIPPLE_X_OFFSET_SHIFT) |
+ (0 << RADEON_STIPPLE_Y_OFFSET_SHIFT) |
+ RADEON_STIPPLE_BIG_BIT_ORDER);
+
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_XSCALE] = 0x00000000;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = 0x00000000;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_YSCALE] = 0x00000000;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = 0x00000000;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZSCALE] = 0x00000000;
+ rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZOFFSET] = 0x00000000;
+
+ for ( i = 0 ; i < ctx->Const.MaxTextureUnits ; i++ ) {
+ rmesa->hw.tex[i].cmd[TEX_PP_TXFILTER] = RADEON_BORDER_MODE_OGL;
+ rmesa->hw.tex[i].cmd[TEX_PP_TXFORMAT] =
+ (RADEON_TXFORMAT_ENDIAN_NO_SWAP |
+ RADEON_TXFORMAT_PERSPECTIVE_ENABLE |
+ (i << 24) | /* This is one of RADEON_TXFORMAT_ST_ROUTE_STQ[012] */
+ (2 << RADEON_TXFORMAT_WIDTH_SHIFT) |
+ (2 << RADEON_TXFORMAT_HEIGHT_SHIFT));
+
+ /* FIXME: What is this magic value? */
+ rmesa->hw.tex[i].cmd[TEX_PP_TXOFFSET] = 0x2000 << (2 * i);
+
+ rmesa->hw.tex[i].cmd[TEX_PP_BORDER_COLOR] = 0;
+ rmesa->hw.tex[i].cmd[TEX_PP_TXCBLEND] =
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_CURRENT_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX);
+ rmesa->hw.tex[i].cmd[TEX_PP_TXABLEND] =
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX);
+ rmesa->hw.tex[i].cmd[TEX_PP_TFACTOR] = 0;
+ }
+
+ /* Can only add ST1 at the time of doing some multitex but can keep
+ * it after that. Errors if DIFFUSE is missing.
+ */
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] =
+ (RADEON_TCL_VTX_Z0 |
+ RADEON_TCL_VTX_W0 |
+ RADEON_TCL_VTX_PK_DIFFUSE
+ ); /* need to keep this uptodate */
+
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] =
+ ( RADEON_TCL_COMPUTE_XYZW |
+ (RADEON_TCL_TEX_INPUT_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT) |
+ (RADEON_TCL_TEX_INPUT_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT) |
+ (RADEON_TCL_TEX_INPUT_TEX_2 << RADEON_TCL_TEX_2_OUTPUT_SHIFT));
+
+
+ /* XXX */
+ rmesa->hw.tcl.cmd[TCL_MATRIX_SELECT_0] =
+ ((MODEL << RADEON_MODELVIEW_0_SHIFT) |
+ (MODEL_IT << RADEON_IT_MODELVIEW_0_SHIFT));
+
+ rmesa->hw.tcl.cmd[TCL_MATRIX_SELECT_1] =
+ ((MODEL_PROJ << RADEON_MODELPROJECT_0_SHIFT) |
+ (TEXMAT_0 << RADEON_TEXMAT_0_SHIFT) |
+ (TEXMAT_1 << RADEON_TEXMAT_1_SHIFT));
+
+ rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] =
+ (RADEON_UCP_IN_CLIP_SPACE |
+ RADEON_CULL_FRONT_IS_CCW);
+
+ rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] = 0;
+
+ rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] =
+ (RADEON_SPECULAR_LIGHTS |
+ RADEON_DIFFUSE_SPECULAR_COMBINE |
+ RADEON_LOCAL_LIGHT_VEC_GL |
+ (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_EMISSIVE_SOURCE_SHIFT) |
+ (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_AMBIENT_SOURCE_SHIFT) |
+ (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_DIFFUSE_SOURCE_SHIFT) |
+ (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_SPECULAR_SOURCE_SHIFT));
+
+ for (i = 0 ; i < 8; i++) {
+ struct gl_light *l = &ctx->Light.Light[i];
+ GLenum p = GL_LIGHT0 + i;
+ *(float *)&(rmesa->hw.lit[i].cmd[LIT_RANGE_CUTOFF]) = FLT_MAX;
+
+ ctx->Driver.Lightfv( ctx, p, GL_AMBIENT, l->Ambient );
+ ctx->Driver.Lightfv( ctx, p, GL_DIFFUSE, l->Diffuse );
+ ctx->Driver.Lightfv( ctx, p, GL_SPECULAR, l->Specular );
+ ctx->Driver.Lightfv( ctx, p, GL_POSITION, 0 );
+ ctx->Driver.Lightfv( ctx, p, GL_SPOT_DIRECTION, 0 );
+ ctx->Driver.Lightfv( ctx, p, GL_SPOT_EXPONENT, &l->SpotExponent );
+ ctx->Driver.Lightfv( ctx, p, GL_SPOT_CUTOFF, &l->SpotCutoff );
+ ctx->Driver.Lightfv( ctx, p, GL_CONSTANT_ATTENUATION,
+ &l->ConstantAttenuation );
+ ctx->Driver.Lightfv( ctx, p, GL_LINEAR_ATTENUATION,
+ &l->LinearAttenuation );
+ ctx->Driver.Lightfv( ctx, p, GL_QUADRATIC_ATTENUATION,
+ &l->QuadraticAttenuation );
+ }
+
+ ctx->Driver.LightModelfv( ctx, GL_LIGHT_MODEL_AMBIENT,
+ ctx->Light.Model.Ambient );
+
+ TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
+
+ for (i = 0 ; i < 6; i++) {
+ ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, NULL );
+ }
+
+ ctx->Driver.Fogfv( ctx, GL_FOG_MODE, 0 );
+ ctx->Driver.Fogfv( ctx, GL_FOG_DENSITY, &ctx->Fog.Density );
+ ctx->Driver.Fogfv( ctx, GL_FOG_START, &ctx->Fog.Start );
+ ctx->Driver.Fogfv( ctx, GL_FOG_END, &ctx->Fog.End );
+ ctx->Driver.Fogfv( ctx, GL_FOG_COLOR, ctx->Fog.Color );
+ ctx->Driver.Fogfv( ctx, GL_FOG_COORDINATE_SOURCE_EXT, 0 );
+
+ rmesa->hw.grd.cmd[GRD_VERT_GUARD_CLIP_ADJ] = IEEE_ONE;
+ rmesa->hw.grd.cmd[GRD_VERT_GUARD_DISCARD_ADJ] = IEEE_ONE;
+ rmesa->hw.grd.cmd[GRD_HORZ_GUARD_CLIP_ADJ] = IEEE_ONE;
+ rmesa->hw.grd.cmd[GRD_HORZ_GUARD_DISCARD_ADJ] = IEEE_ONE;
+
+ rmesa->hw.eye.cmd[EYE_X] = 0;
+ rmesa->hw.eye.cmd[EYE_Y] = 0;
+ rmesa->hw.eye.cmd[EYE_Z] = IEEE_ONE;
+ rmesa->hw.eye.cmd[EYE_RESCALE_FACTOR] = IEEE_ONE;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_subset.h b/src/mesa/drivers/dri/radeon/radeon_subset.h
new file mode 100644
index 0000000000..1b6e7bd432
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_subset.h
@@ -0,0 +1,75 @@
+/**
+ * \file radeon_subset.h
+ * \brief Radeon subset driver declarations.
+ *
+ * \author Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+/*
+ * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ * Tungsten Grahpics Inc., Austin, Texas.
+ *
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * ATI, TUNGSTEN GRAHPICS AND/OR THEIR SUPPLIERS 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$ */
+
+#ifndef __RADEON_SUBSET_H__
+#define __RADEON_SUBSET_H__
+
+extern void radeonPointsBitmap( GLsizei width, GLsizei height,
+ GLfloat xorig, GLfloat yorig,
+ GLfloat xmove, GLfloat ymove,
+ const GLubyte *bitmap );
+
+extern void radeonReadPixels( GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ GLvoid *pixels );
+
+extern void radeon_select_Install( GLcontext *ctx );
+
+extern void radeonInitSelect( GLcontext *ctx );
+
+extern void radeonVtxfmtDestroy( GLcontext *ctx );
+
+extern void radeonVtxfmtMakeCurrent( GLcontext *ctx );
+
+extern void radeonVtxfmtUnbindContext( GLcontext *ctx );
+
+extern void radeonVtxfmtInit( GLcontext *ctx );
+
+extern void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode );
+
+extern void radeonVtxfmtInvalidate( GLcontext *ctx );
+
+extern void radeonSubsetVtxEnableTCL( radeonContextPtr rmesa, GLboolean flag );
+
+extern void radeonUpdateTextureState( GLcontext *ctx );
+
+extern void radeonInitTextureFuncs( GLcontext *ctx );
+
+extern void radeonAgeTextures( radeonContextPtr rmesa, int heap );
+
+extern void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t );
+
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_bitmap.c b/src/mesa/drivers/dri/radeon/radeon_subset_bitmap.c
new file mode 100644
index 0000000000..cb4a514221
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_subset_bitmap.c
@@ -0,0 +1,197 @@
+/**
+ * \file radeon_subset_bitmap.c
+ * \brief Bitmap drawing.
+ *
+ * \author Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+/*
+ * Copyright 2003 ATI Technologies Inc., Ontario, Canada, and
+ * Tungsten Graphics Inc., Cedar Park, Texas.
+ *
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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$ */
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "colormac.h"
+#include "context.h"
+#include "enums.h"
+#include "imports.h"
+#include "image.h"
+/*#include "mmath.h"*/
+#include "macros.h"
+#include "state.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_subset.h"
+
+/**
+ * \brief Cope with depth operations by drawing individual pixels as points
+ *
+ * \param xorig x coordinate of the bitmap corner.
+ * \param yorig y coordinate of the bitmap corner.
+ * \param xmove increment to the final x coordinate.
+ * \param ymove increment to the final y coordinate.
+ * \param width bitmap width.
+ * \param height bitmap height.
+ * \param bitmap bitmap pointer.
+ *
+ * Clips the bitmap coordinates and adjusts for windows coordinates. Draws the
+ * bitmap with glPoints(), turning off TCL and hardware viewport transformation
+ * to emit raw pixel coordinates. Finally fires any outstanding vertices and
+ * restores TCL, viewport, texture and color states.
+ */
+void
+radeonPointsBitmap( GLsizei width, GLsizei height,
+ GLfloat xorig, GLfloat yorig,
+ GLfloat xmove, GLfloat ymove,
+ const GLubyte *bitmap )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLsizei bmwidth = width, bmheight = height;
+ GLint px, py;
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat saved_color[4], saved_tex0[2];
+ GLint row, col;
+ GLuint orig_se_cntl;
+ GLuint w, h;
+ const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+ if (width < 0 || height < 0) {
+ _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
+ return;
+ }
+
+ if (!ctx->Current.RasterPosValid)
+ return;
+
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
+
+
+ if (ctx->_RotateMode) {
+ width = bmheight; height = bmwidth;
+
+ px = IFLOOR(ctx->Current.RasterPos[0] + yorig);
+ py = IFLOOR(ctx->Current.RasterPos[1] + xorig);
+
+ ctx->Current.RasterPos[0] += ymove;
+ ctx->Current.RasterPos[1] += xmove;
+ }
+ else {
+ px = IFLOOR(ctx->Current.RasterPos[0] - xorig);
+ py = IFLOOR(ctx->Current.RasterPos[1] - yorig);
+
+ ctx->Current.RasterPos[0] += xmove;
+ ctx->Current.RasterPos[1] += ymove;
+ }
+
+
+
+ /* Turn off tcl and the hw viewport transformation so that we can
+ * emit raw pixel coordinates:
+ */
+ radeonSubsetVtxEnableTCL( rmesa, GL_FALSE );
+ RADEON_STATECHANGE( rmesa, set );
+ orig_se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL];
+ rmesa->hw.set.cmd[SET_SE_CNTL] &= ~(RADEON_VPORT_XY_XFORM_ENABLE |
+ RADEON_VPORT_Z_XFORM_ENABLE);
+
+
+ /* Adjust for window coordinates, flip y values:
+ */
+ h = rmesa->dri.drawable->h + rmesa->dri.drawable->y - 1;
+ w = rmesa->dri.drawable->w;
+ px += rmesa->dri.drawable->x;
+
+ /* Save current color, texcoord to restore later:
+ */
+ COPY_4V( saved_color, ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
+ COPY_2V( saved_tex0, ctx->Current.Attrib[VERT_ATTRIB_TEX0] );
+
+ /* Just use the GL entrypoints to talk to radeon_subset_vtx.c:
+ */
+ glBegin( GL_POINTS );
+ glColor4fv( ctx->Current.RasterColor );
+ glTexCoord2fv( ctx->Current.RasterTexCoords[0] );
+
+
+ if (ctx->_RotateMode) {
+ for (col=0; col<width; col++) {
+ const GLubyte *src = (const GLubyte *)
+ _mesa_image_address( unpack, bitmap, height, width,
+ GL_COLOR_INDEX, GL_BITMAP, 0, col, 0 );
+
+ /* Msb first */
+ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
+ for (row=0; row<height; row++) {
+ if (*src & mask) {
+ glVertex2f( px-col, h - (py + row) );
+ }
+ src += mask & 1;
+ mask = ((mask << 7) & 0xff) | (mask >> 1);
+ }
+ /* get ready for next row */
+ if (mask != 128)
+ src++;
+ }
+ }
+ else {
+ for (row=0; row<height; row++) {
+ const GLubyte *src = (const GLubyte *)
+ _mesa_image_address( unpack, bitmap, width, height,
+ GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 );
+
+ /* Msb first */
+ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
+ for (col=0; col<width; col++) {
+ if (*src & mask) {
+ glVertex2f( px+col, h - (py + row) );
+ }
+ src += mask & 1;
+ mask = ((mask << 7) & 0xff) | (mask >> 1);
+ }
+ /* get ready for next row */
+ if (mask != 128)
+ src++;
+ }
+ }
+
+ glEnd();
+ glColor4fv( saved_color );
+ glTexCoord2fv( saved_tex0 );
+
+ /* Fire outstanding vertices, restore state
+ */
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_CNTL] = orig_se_cntl;
+ radeonSubsetVtxEnableTCL( rmesa, GL_TRUE );
+}
+
diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_readpix.c b/src/mesa/drivers/dri/radeon/radeon_subset_readpix.c
new file mode 100644
index 0000000000..f72d3b8472
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_subset_readpix.c
@@ -0,0 +1,246 @@
+/**
+ * \file radeon_subset_readpix.c
+ * \brief Pixel reading.
+ *
+ * \author Keith Whitwell <keith@tungstengraphics.com>
+ * \author Brian Paul <brian@tungstengraphics.com>
+ */
+
+/*
+ * Copyright 2003 ATI Technologies Inc., Ontario, Canada, and
+ * Tungsten Graphics Inc., Cedar Park, Texas.
+ *
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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$ */
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "colormac.h"
+#include "context.h"
+#include "enums.h"
+#include "imports.h"
+/*#include "mmath.h" */
+#include "macros.h"
+#include "state.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_subset.h"
+
+/**
+ * \brief Read pixel in RGBA format on a Radeon 16bpp frame buffer.
+ *
+ * \param rgba destination pointer.
+ * \param ptr pointer to the pixel in the frame buffer.
+ */
+#define READ_RGBA_16( rgba, ptr ) \
+do { \
+ GLushort p = *(GLushort *)ptr; \
+ rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \
+ rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \
+ rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \
+ rgba[3] = 0xff; \
+} while (0)
+
+/**
+ * \brief Read pixel in RGBA format on a Radeon 32bpp frame buffer.
+ *
+ * \param rgba destination pointer.
+ * \param ptr pointer to the pixel in the frame buffer.
+ */
+#define READ_RGBA_32( rgba, ptr ) \
+do { \
+ GLuint p = *(GLuint *)ptr; \
+ rgba[0] = (p >> 16) & 0xff; \
+ rgba[1] = (p >> 8) & 0xff; \
+ rgba[2] = (p >> 0) & 0xff; \
+ rgba[3] = (p >> 24) & 0xff; \
+} while (0)
+
+/**
+ * \brief Read a span in RGBA format.
+ *
+ * \param ctx GL context.
+ * \param n number of pixels in the span.
+ * \param x x position of the span start.
+ * \param y y position of the span.
+ * \param rgba destination buffer.
+ *
+ * Calculates the pointer to the span start in the frame buffer and uses either
+ * #READ_RGBA_16 or #READ_RGBA_32 macros to copy the values.
+ */
+static void ReadRGBASpan( const GLcontext *ctx,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4])
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeonScreenPtr radeonScreen = rmesa->radeonScreen;
+ __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
+ GLuint cpp = radeonScreen->cpp;
+ GLuint pitch = radeonScreen->frontPitch * cpp;
+ GLint i;
+
+ if (ctx->_RotateMode) {
+ char *ptr = (char *)(rmesa->dri.screen->pFB +
+ rmesa->state.pixel.readOffset +
+ ((dPriv->x + (dPriv->w - y - 1)) * cpp) +
+ ((dPriv->y + (dPriv->h - x - 1)) * pitch));
+
+ if (cpp == 4)
+ for (i = 0; i < n; i++, ptr -= pitch)
+ READ_RGBA_32( rgba[i], ptr );
+ else
+ for (i = 0; i < n; i++, ptr -= pitch)
+ READ_RGBA_16( rgba[i], ptr );
+ }
+ else {
+ char *ptr = (char *)(rmesa->dri.screen->pFB +
+ rmesa->state.pixel.readOffset +
+ ((dPriv->x + x) * cpp) +
+ ((dPriv->y + (dPriv->h - y - 1)) * pitch));
+
+ if (cpp == 4)
+ for (i = 0; i < n; i++, ptr += cpp)
+ READ_RGBA_32( rgba[i], ptr );
+ else
+ for (i = 0; i < n; i++, ptr += cpp)
+ READ_RGBA_16( rgba[i], ptr );
+ }
+}
+
+
+/**
+ * \brief Optimized glReadPixels().
+ *
+ * To be used with particular pixel formats GL_UNSIGNED_BYTE and GL_RGBA, when pixel
+ * scaling, biasing and mapping are disabled.
+ *
+ * \param x x start position of the reading rectangle.
+ * \param y y start position of the reading rectangle.
+ * \param width width of the reading rectangle.
+ * \param height height of the reading rectangle.
+ * \param format pixel format. Must be GL_RGBA.
+ * \param type pixel type. Must be GL_UNSIGNED_BYTE.
+ * \param pixels pixel data.
+ *
+ * After asserting the above conditions, compensates for clipping and calls
+ * ReadRGBASpan() to read each row.
+ */
+void radeonReadPixels( GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ GLvoid *pixels )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint srcX = x;
+ GLint srcY = y;
+ GLint readWidth = width; /* actual width read */
+ GLint readHeight = height; /* actual height read */
+ const struct gl_pixelstore_attrib *packing = &ctx->Pack;
+ GLint skipRows = packing->SkipRows;
+ GLint skipPixels = packing->SkipPixels;
+ GLint rowLength;
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+ {
+ GLint tmp, tmps;
+ tmp = x; x = y; y = tmp;
+ tmps = width; width = height; height = tmps;
+ }
+
+ if (width < 0 || height < 0) {
+ _mesa_error( ctx, GL_INVALID_VALUE,
+ "glReadPixels(width=%d height=%d)", width, height );
+ return;
+ }
+
+ if (!pixels) {
+ _mesa_error( ctx, GL_INVALID_VALUE, "glReadPixels(pixels)" );
+ return;
+ }
+
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
+
+
+ /* can't do scale, bias, mapping, etc */
+ assert(!ctx->_ImageTransferState);
+
+ /* can't do fancy pixel packing */
+ assert (packing->Alignment == 1 &&
+ !packing->SwapBytes &&
+ !packing->LsbFirst);
+
+
+ if (packing->RowLength > 0)
+ rowLength = packing->RowLength;
+ else
+ rowLength = width;
+
+ /* horizontal clipping */
+ if (srcX < 0) {
+ skipPixels -= srcX;
+ readWidth += srcX;
+ srcX = 0;
+ }
+ if (srcX + readWidth > (GLint) ctx->ReadBuffer->Width)
+ readWidth -= (srcX + readWidth - (GLint) ctx->ReadBuffer->Width);
+ if (readWidth <= 0)
+ return;
+
+ /* vertical clipping */
+ if (srcY < 0) {
+ skipRows -= srcY;
+ readHeight += srcY;
+ srcY = 0;
+ }
+ if (srcY + readHeight > (GLint) ctx->ReadBuffer->Height)
+ readHeight -= (srcY + readHeight - (GLint) ctx->ReadBuffer->Height);
+ if (readHeight <= 0)
+ return;
+
+ /*
+ * Ready to read!
+ * The window region at (destX, destY) of size (readWidth, readHeight)
+ * will be read back.
+ * We'll write pixel data to buffer pointed to by "pixels" but we'll
+ * skip "skipRows" rows and skip "skipPixels" pixels/row.
+ */
+ if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
+ GLchan *dest = (GLchan *) pixels
+ + (skipRows * rowLength + skipPixels) * 4;
+ GLint row;
+
+ for (row=0; row<readHeight; row++) {
+ ReadRGBASpan(ctx, readWidth, srcX, srcY, (GLchan (*)[4]) dest);
+ dest += rowLength * 4;
+ srcY++;
+ }
+ }
+ else {
+ /* can't do this format/type combination */
+ assert(0);
+ }
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_select.c b/src/mesa/drivers/dri/radeon/radeon_subset_select.c
new file mode 100644
index 0000000000..bd5003ffe5
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_subset_select.c
@@ -0,0 +1,998 @@
+/**
+ * \file radeon_subset_select.c
+ * \brief Selection.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.1
+ *
+ * Copyright (C) 1999-2002 Brian Paul 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 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
+ * BRIAN PAUL 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.
+ */
+
+/* $Id: radeon_subset_select.c,v 1.2 2003/08/22 20:11:45 brianp Exp $ */
+
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+/*#include "mmath.h"*/
+#include "mtypes.h"
+#include "enums.h"
+#include "glapi.h"
+#include "feedback.h"
+
+#include "radeon_context.h"
+#include "radeon_subset.h"
+
+/**
+ * \brief Vertex.
+ */
+typedef struct {
+ struct { GLfloat x, y, z, w; } pos; /**< \brief position */
+ struct { GLfloat x, y, z, w; } eyePos; /**< \brief position, eye coordinates */
+ struct { GLfloat x, y, z, w; } clipPos; /**< \brief clipped coordinates */
+ struct { GLfloat x, y, z, w; } winPos; /**< \brief position, windows coordinates */
+ struct { GLfloat s, t; } texCoord; /**< \brief texture coordinates */
+ struct { GLfloat r, g, b, a; } color; /**< \brief color */
+} vertex;
+
+
+/**
+ * \brief Vertex buffer.
+ */
+static struct select_vb_t {
+ GLuint vCount; /**< \brief vertex count */
+ vertex vBuffer[4]; /**< \brief vertex buffer */
+ GLboolean lineReset;
+ GLboolean partialLineLoop; /**< \brief whether we are in a middle of a line loop */
+} vb;
+
+
+
+
+/**********************************************************************/
+/** \name Vertex Transformation and Clipping */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * \brief Transform a point (column vector) by a matrix: Q = M * P.
+ *
+ * \param Q destination point.
+ * \param P source point.
+ * \param M transformation matrix.
+ */
+#define TRANSFORM_POINT( Q, M, P ) \
+ Q.x = M[0] * P.x + M[4] * P.y + M[8] * P.z + M[12] * P.w; \
+ Q.y = M[1] * P.x + M[5] * P.y + M[9] * P.z + M[13] * P.w; \
+ Q.z = M[2] * P.x + M[6] * P.y + M[10] * P.z + M[14] * P.w; \
+ Q.w = M[3] * P.x + M[7] * P.y + M[11] * P.z + M[15] * P.w;
+
+/**
+ * \brief Clip coord to window coord mapping.
+ *
+ * \param Q destination point.
+ * \param P source point.
+ * \param VP view port.
+ */
+#define MAP_POINT( Q, P, VP ) \
+ Q.x = (GLfloat) (((P.x / P.w) + 1.0) * VP.Width / 2.0 + VP.X); \
+ Q.y = (GLfloat) (((P.y / P.w) + 1.0) * VP.Height / 2.0 + VP.Y); \
+ Q.z = (GLfloat) (((P.z / P.w) + 1.0) * (VP.Far - VP.Near) / 2.0 + VP.Near);\
+ Q.w = (GLfloat) P.w;
+
+
+/**
+ * \brief Linear interpolation: (1 - T) * A + T * B.
+ *
+ * \param T interpolation factor.
+ * \param A first value.
+ * \param B second value.
+ * \result interpolated value.
+ */
+#define INTERPOLATE(T, A, B) ((A) + ((B) - (A)) * (T))
+
+
+
+/**
+ * \brief Interpolate vertex position, color, texcoords, etc.
+ *
+ * \param t interpolation factor.
+ * \param v0 first vertex.
+ * \param v1 second vertex.
+ * \param vOut output vertex.
+ *
+ * Uses the #INTERPOLATE macro for all the interpolation of all elements.
+ */
+static void
+interpolate_vertex(GLfloat t, const vertex *v0, const vertex *v1,
+ vertex *vOut)
+{
+ vOut->eyePos.x = INTERPOLATE(t, v0->eyePos.x, v1->eyePos.x);
+ vOut->eyePos.y = INTERPOLATE(t, v0->eyePos.y, v1->eyePos.y);
+ vOut->eyePos.z = INTERPOLATE(t, v0->eyePos.z, v1->eyePos.z);
+ vOut->eyePos.w = INTERPOLATE(t, v0->eyePos.w, v1->eyePos.w);
+
+ vOut->clipPos.x = INTERPOLATE(t, v0->clipPos.x, v1->clipPos.x);
+ vOut->clipPos.y = INTERPOLATE(t, v0->clipPos.y, v1->clipPos.y);
+ vOut->clipPos.z = INTERPOLATE(t, v0->clipPos.z, v1->clipPos.z);
+ vOut->clipPos.w = INTERPOLATE(t, v0->clipPos.w, v1->clipPos.w);
+
+ vOut->color.r = INTERPOLATE(t, v0->color.r, v1->color.r);
+ vOut->color.g = INTERPOLATE(t, v0->color.g, v1->color.g);
+ vOut->color.b = INTERPOLATE(t, v0->color.b, v1->color.b);
+ vOut->color.a = INTERPOLATE(t, v0->color.a, v1->color.a);
+
+ vOut->texCoord.s = INTERPOLATE(t, v0->texCoord.s, v1->texCoord.s);
+ vOut->texCoord.t = INTERPOLATE(t, v0->texCoord.t, v1->texCoord.t);
+}
+
+
+
+
+/*
+ * Clip bit codes
+ */
+#define CLIP_LEFT 1
+#define CLIP_RIGHT 2
+#define CLIP_BOTTOM 4
+#define CLIP_TOP 8
+#define CLIP_NEAR 16
+#define CLIP_FAR 32
+
+
+/**
+ * \brief Apply view volume clip testing to a point.
+ *
+ * \param v point to test.
+ * \return zero if visible, or the clip code mask, i.e., binary OR of a
+ * combination of the #CLIP_LEFT, #CLIP_RIGHT, #CLIP_BOTTOM, #CLIP_TOP, #CLIP_NEAR,
+ * #CLIP_FAR clip bit codes.
+ */
+static GLuint
+clip_point(const vertex *v)
+{
+ GLuint mask = 0;
+ if (v->clipPos.x > v->clipPos.w) mask |= CLIP_RIGHT;
+ if (v->clipPos.x < -v->clipPos.w) mask |= CLIP_LEFT;
+ if (v->clipPos.y > v->clipPos.w) mask |= CLIP_TOP;
+ if (v->clipPos.y < -v->clipPos.w) mask |= CLIP_BOTTOM;
+ if (v->clipPos.z > v->clipPos.w) mask |= CLIP_FAR;
+ if (v->clipPos.z < -v->clipPos.w) mask |= CLIP_NEAR;
+ return mask;
+}
+
+
+/**
+ * \def GENERAL_CLIP
+ * \brief Clipping utility macro.
+ *
+ * We use 6 instances of this code in each of the clip_line() and
+ * clip_polygon() to clip against the 6 planes. For each plane, we define the
+ * #OUTSIDE and #COMPUTE_INTERSECTION macros appropriately.
+ */
+
+
+/**
+ * \brief Apply clipping to a line segment.
+ *
+ * \param v0in input start vertex
+ * \param v1in input end vertesx
+ * \param v0new output start vertex
+ * \param v1new output end vertex
+ *
+ * \return GL_TRUE if the line segment is visible, or GL_FALSE if it is totally
+ * clipped.
+ *
+ * \sa #GENERAL_CLIP.
+ */
+static GLboolean
+clip_line(const vertex *v0in, const vertex *v1in,
+ vertex *v0new, vertex *v1new)
+{
+ vertex v0, v1, vNew;
+ GLfloat dx, dy, dz, dw, t;
+ GLuint code0, code1;
+
+ code0 = clip_point(v0in);
+ code1 = clip_point(v1in);
+ if (code0 & code1)
+ return GL_FALSE; /* totally clipped */
+
+ *v0new = *v0in;
+ *v1new = *v1in;
+ if (code0 == 0 && code1 == 0)
+ return GL_TRUE; /* no clipping needed */
+
+ v0 = *v0in;
+ v1 = *v1in;
+
+
+#define GENERAL_CLIP \
+ if (OUTSIDE(v0)) { \
+ if (OUTSIDE(v1)) { \
+ /* both verts are outside ==> return 0 */ \
+ return 0; \
+ } \
+ else { \
+ /* v0 is outside, v1 is inside ==> clip */ \
+ COMPUTE_INTERSECTION( v1, v0, vNew ) \
+ interpolate_vertex(t, &v1, &v0, &vNew); \
+ v0 = vNew; \
+ } \
+ } \
+ else { \
+ if (OUTSIDE(v1)) { \
+ /* v0 is inside, v1 is outside ==> clip */ \
+ COMPUTE_INTERSECTION( v0, v1, vNew ) \
+ interpolate_vertex(t, &v0, &v1, &vNew); \
+ v1 = vNew; \
+ } \
+ /* else both verts are inside ==> do nothing */ \
+ }
+
+ /* Clip against +X side */
+#define OUTSIDE(V) (V.clipPos.x > V.clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dx = OUT.clipPos.x - IN.clipPos.x; \
+ dw = OUT.clipPos.w - IN.clipPos.w; \
+ t = (IN.clipPos.x - IN.clipPos.w) / (dw-dx);
+ GENERAL_CLIP
+#undef OUTSIDE
+#undef COMPUTE_INTERSECTION
+
+ /* Clip against -X side */
+#define OUTSIDE(V) (V.clipPos.x < -(V.clipPos.w))
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dx = OUT.clipPos.x - IN.clipPos.x; \
+ dw = OUT.clipPos.w - IN.clipPos.w; \
+ t = -(IN.clipPos.x + IN.clipPos.w) / (dw+dx);
+ GENERAL_CLIP
+#undef OUTSIDE
+#undef COMPUTE_INTERSECTION
+
+ /* Clip against +Y side */
+#define OUTSIDE(V) (V.clipPos.y > V.clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dy = OUT.clipPos.y - IN.clipPos.y; \
+ dw = OUT.clipPos.w - IN.clipPos.w; \
+ t = (IN.clipPos.y - IN.clipPos.w) / (dw-dy);
+ GENERAL_CLIP
+#undef OUTSIDE
+#undef COMPUTE_INTERSECTION
+
+ /* Clip against -Y side */
+#define OUTSIDE(V) (V.clipPos.y < -(V.clipPos.w))
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dy = OUT.clipPos.y - IN.clipPos.y; \
+ dw = OUT.clipPos.w - IN.clipPos.w; \
+ t = -(IN.clipPos.y + IN.clipPos.w) / (dw+dy);
+ GENERAL_CLIP
+#undef OUTSIDE
+#undef COMPUTE_INTERSECTION
+
+ /* Clip against +Z side */
+#define OUTSIDE(V) (V.clipPos.z > V.clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dz = OUT.clipPos.z - IN.clipPos.z; \
+ dw = OUT.clipPos.w - IN.clipPos.w; \
+ t = (IN.clipPos.z - IN.clipPos.w) / (dw-dz);
+ GENERAL_CLIP
+#undef OUTSIDE
+#undef COMPUTE_INTERSECTION
+
+ /* Clip against -Z side */
+#define OUTSIDE(V) (V.clipPos.z < -(V.clipPos.w))
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dz = OUT.clipPos.z - IN.clipPos.z; \
+ dw = OUT.clipPos.w - IN.clipPos.w; \
+ t = -(IN.clipPos.z + IN.clipPos.w) / (dw+dz);
+ GENERAL_CLIP
+#undef OUTSIDE
+#undef COMPUTE_INTERSECTION
+
+#undef GENERAL_CLIP
+
+ *v0new = v0;
+ *v1new = v1;
+ return GL_TRUE;
+}
+
+
+
+/**
+ * \brief Apply clipping to a polygon.
+ *
+ * \param vIn array of input vertices.
+ * \param inCount number of input vertices
+ * \param vOut array of output vertices.
+ *
+ * \return number of vertices in \p vOut.
+ *
+ * \sa #GENERAL_CLIP.
+ */
+static GLuint
+clip_polygon(const vertex *vIn, unsigned int inCount, vertex *vOut)
+{
+ vertex inlist[20], outlist[20];
+ GLfloat dx, dy, dz, dw, t;
+ GLuint incount, outcount, previ, curri, result;
+ const vertex *currVert, *prevVert;
+ vertex *newVert;
+
+
+#define GENERAL_CLIP(INCOUNT, INLIST, OUTCOUNT, OUTLIST) \
+ if (INCOUNT < 3) \
+ return GL_FALSE; \
+ previ = INCOUNT - 1; /* let previous = last vertex */ \
+ prevVert = INLIST + previ; \
+ OUTCOUNT = 0; \
+ for (curri = 0; curri < INCOUNT; curri++) { \
+ currVert = INLIST + curri; \
+ if (INSIDE(currVert)) { \
+ if (INSIDE(prevVert)) { \
+ /* both verts are inside ==> copy current to outlist */ \
+ OUTLIST[OUTCOUNT] = *currVert; \
+ OUTCOUNT++; \
+ } \
+ else { \
+ newVert = OUTLIST + OUTCOUNT; \
+ /* current is inside and previous is outside ==> clip */ \
+ COMPUTE_INTERSECTION( currVert, prevVert, newVert ) \
+ OUTCOUNT++; \
+ /* Output current */ \
+ OUTLIST[OUTCOUNT] = *currVert; \
+ OUTCOUNT++; \
+ } \
+ } \
+ else { \
+ if (INSIDE(prevVert)) { \
+ newVert = OUTLIST + OUTCOUNT; \
+ /* current is outside and previous is inside ==> clip */ \
+ COMPUTE_INTERSECTION( prevVert, currVert, newVert ); \
+ OUTLIST[OUTCOUNT] = *newVert; \
+ OUTCOUNT++; \
+ } \
+ /* else both verts are outside ==> do nothing */ \
+ } \
+ /* let previous = current */ \
+ previ = curri; \
+ prevVert = currVert; \
+ }
+
+/*
+ * Clip against +X
+ */
+#define INSIDE(V) (V->clipPos.x <= V->clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dx = OUT->clipPos.x - IN->clipPos.x; \
+ dw = OUT->clipPos.w - IN->clipPos.w; \
+ t = (IN->clipPos.x - IN->clipPos.w) / (dw - dx); \
+ interpolate_vertex(t, IN, OUT, NEW );
+
+ GENERAL_CLIP(inCount, vIn, outcount, outlist)
+
+#undef INSIDE
+#undef COMPUTE_INTERSECTION
+
+/*
+ * Clip against -X
+ */
+#define INSIDE(V) (V->clipPos.x >= -V->clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dx = OUT->clipPos.x - IN->clipPos.x; \
+ dw = OUT->clipPos.w - IN->clipPos.w; \
+ t = -(IN->clipPos.x + IN->clipPos.w) / (dw + dx); \
+ interpolate_vertex(t, IN, OUT, NEW );
+
+ GENERAL_CLIP(outcount, outlist, incount, inlist)
+
+#undef INSIDE
+#undef COMPUTE_INTERSECTION
+
+/*
+ * Clip against +Y
+ */
+#define INSIDE(V) (V->clipPos.y <= V->clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dy = OUT->clipPos.y - IN->clipPos.y; \
+ dw = OUT->clipPos.w - IN->clipPos.w; \
+ t = (IN->clipPos.y - IN->clipPos.w) / (dw - dy); \
+ interpolate_vertex(t, IN, OUT, NEW );
+
+ GENERAL_CLIP(incount, inlist, outcount, outlist)
+
+#undef INSIDE
+#undef COMPUTE_INTERSECTION
+
+/*
+ * Clip against -Y
+ */
+#define INSIDE(V) (V->clipPos.y >= -V->clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dy = OUT->clipPos.y - IN->clipPos.y; \
+ dw = OUT->clipPos.w - IN->clipPos.w; \
+ t = -(IN->clipPos.y + IN->clipPos.w) / (dw + dy); \
+ interpolate_vertex(t, IN, OUT, NEW );
+
+ GENERAL_CLIP(outcount, outlist, incount, inlist)
+
+#undef INSIDE
+#undef COMPUTE_INTERSECTION
+
+/*
+ * Clip against +Z
+ */
+#define INSIDE(V) (V->clipPos.z <= V->clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dz = OUT->clipPos.z - IN->clipPos.z; \
+ dw = OUT->clipPos.w - IN->clipPos.w; \
+ t = (IN->clipPos.z - IN->clipPos.w) / (dw - dz); \
+ interpolate_vertex(t, IN, OUT, NEW );
+
+ GENERAL_CLIP(incount, inlist, outcount, outlist)
+
+#undef INSIDE
+#undef COMPUTE_INTERSECTION
+
+/*
+ * Clip against -Z
+ */
+#define INSIDE(V) (V->clipPos.z >= -V->clipPos.w)
+#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
+ dz = OUT->clipPos.z - IN->clipPos.z; \
+ dw = OUT->clipPos.w - IN->clipPos.w; \
+ t = -(IN->clipPos.z + IN->clipPos.w) / (dw + dz); \
+ interpolate_vertex(t, IN, OUT, NEW );
+
+ GENERAL_CLIP(outcount, outlist, result, vOut)
+
+#undef INSIDE
+#undef COMPUTE_INTERSECTION
+
+#undef GENERAL_CLIP
+
+ return result;
+}
+
+/*@}*/
+
+
+
+/**********************************************************************/
+/** \name Selection */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * \brief Select point.
+ *
+ * \param v vertex.
+ *
+ * If the clipped point is visible then maps the vertex into window coordinates
+ * and calls _mesa_update_hitflag().
+ */
+static void
+select_point(const vertex *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (clip_point(v) == 0)
+ {
+ vertex c = *v;
+ MAP_POINT(c.winPos, c.clipPos, ctx->Viewport);
+ _mesa_update_hitflag(ctx, c.winPos.z);
+ }
+}
+
+/**
+ * \brief Select line.
+ *
+ * \param v0 first vertex.
+ * \param v1 second vertex.
+ *
+ * If the clipped line is visible then maps the vertices into window coordinates
+ * and calls _mesa_update_hitflag().
+ */
+static void
+select_line(const vertex *v0, const vertex *v1)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ vertex c0, c1;
+ if (clip_line(v0, v1, &c0, &c1))
+ {
+ MAP_POINT(c0.winPos, c0.clipPos, ctx->Viewport);
+ MAP_POINT(c1.winPos, c1.clipPos, ctx->Viewport);
+ _mesa_update_hitflag(ctx, c0.winPos.z);
+ _mesa_update_hitflag(ctx, c1.winPos.z);
+ }
+}
+
+/**
+ * \brief Select line.
+ *
+ * \param v0 first vertex.
+ * \param v1 second vertex.
+ * \param v2 third vertex.
+ *
+ * If the clipped polygon is visible then maps the vertices into window
+ * coordinates and calls _mesa_update_hitflag().
+ */
+static void
+select_triangle(const vertex *v0,
+ const vertex *v1,
+ const vertex *v2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ vertex vlist[3], vclipped[8];
+ GLuint i, n;
+
+ vlist[0] = *v0;
+ vlist[1] = *v1;
+ vlist[2] = *v2;
+ n = clip_polygon(vlist, 3, vclipped);
+ for (i = 0; i < n; i++) {
+ MAP_POINT(vclipped[i].winPos, vclipped[i].clipPos, ctx->Viewport);
+ _mesa_update_hitflag(ctx, vclipped[i].winPos.z);
+ }
+}
+
+/**
+ * \brief Set current vertex coordinates.
+ *
+ * \param x x vertex coordinate.
+ * \param y y vertex coordinate.
+ * \param z z vertex coordinate.
+ * \param w homogeneous coordinate.
+ *
+ * Stores the vertex and current attributes in ::vb, transforms it into eye space and then clip space.
+ *
+ * If a sufficient number of vertices is stored calls one of select_point(),
+ * select_line() or select_triangle(), according to the current primitive.
+ */
+static void
+radeon_select_Vertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_polygon_attrib *p = &(ctx->Polygon);
+ vertex *v = vb.vBuffer + vb.vCount;
+
+ /* store the vertex */
+ v->pos.x = x;
+ v->pos.y = y;
+ v->pos.z = z;
+ v->pos.w = w;
+ v->color.r = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0];
+ v->color.g = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1];
+ v->color.b = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2];
+ v->color.a = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];
+ v->texCoord.s = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0];
+ v->texCoord.t = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1];
+
+ /* transform to eye space, then clip space */
+ TRANSFORM_POINT(v->eyePos, ctx->ModelviewMatrixStack.Top->m, v->pos);
+ TRANSFORM_POINT(v->clipPos, ctx->ProjectionMatrixStack.Top->m, v->eyePos);
+
+ switch (ctx->Driver.CurrentExecPrimitive) {
+ case GL_POINTS:
+ assert(vb.vCount == 0);
+ select_point(v);
+ break;
+ case GL_LINES:
+ if (vb.vCount == 0)
+ {
+ vb.vCount = 1;
+ }
+ else
+ {
+ assert(vb.vCount == 1);
+ select_line(vb.vBuffer + 0, vb.vBuffer + 1);
+ vb.vCount = 0;
+ }
+ break;
+ case GL_LINE_STRIP:
+ if (vb.vCount == 0)
+ {
+ vb.vCount = 1;
+ }
+ else
+ {
+ assert(vb.vCount == 1);
+ select_line(vb.vBuffer + 0, vb.vBuffer + 1);
+ vb.vBuffer[0] = vb.vBuffer[1];
+ /* leave vb.vCount at 1 */
+ }
+ break;
+ case GL_LINE_LOOP:
+ if (vb.vCount == 0)
+ {
+ vb.vCount = 1;
+ vb.partialLineLoop = GL_FALSE;
+ }
+ else if (vb.vCount == 1)
+ {
+ select_line(vb.vBuffer + 0, vb.vBuffer + 1);
+ vb.partialLineLoop = GL_TRUE;
+ vb.vCount = 2;
+ }
+ else
+ {
+ assert(vb.vCount == 2);
+ vb.partialLineLoop = GL_FALSE;
+ select_line(vb.vBuffer + 1, vb.vBuffer + 2);
+ vb.vBuffer[1] = vb.vBuffer[2];
+ /* leave vb.vCount at 2 */
+ }
+ break;
+ case GL_TRIANGLES:
+ if (vb.vCount == 0 || vb.vCount == 1)
+ {
+ vb.vCount++;
+ }
+ else
+ {
+ assert(vb.vCount == 2);
+ select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
+ vb.vCount = 0;
+ }
+ break;
+ case GL_TRIANGLE_STRIP:
+ if (vb.vCount == 0 || vb.vCount == 1)
+ {
+ vb.vCount++;
+ }
+ else if (vb.vCount == 2)
+ {
+ select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
+ vb.vCount = 3;
+ }
+ else
+ {
+ assert(vb.vCount == 3);
+ select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2);
+ vb.vBuffer[0] = vb.vBuffer[2];
+ vb.vBuffer[1] = vb.vBuffer[3];
+ vb.vCount = 2;
+ }
+ break;
+ case GL_TRIANGLE_FAN:
+ if (vb.vCount == 0 || vb.vCount == 1)
+ {
+ vb.vCount++;
+ }
+ else
+ {
+ assert(vb.vCount == 2);
+ select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
+ vb.vBuffer[1] = vb.vBuffer[2];
+ /* leave vb.vCount = 2 */
+ }
+ break;
+ case GL_QUADS:
+ if (vb.vCount < 3)
+ {
+ vb.vCount++;
+ }
+ else
+ {
+ assert(vb.vCount == 3);
+ select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
+ select_triangle(vb.vBuffer + 0, vb.vBuffer + 2, vb.vBuffer + 3);
+ vb.vCount = 0;
+ }
+ break;
+ case GL_QUAD_STRIP:
+ if (vb.vCount < 3)
+ {
+ vb.vCount++;
+ }
+ else
+ {
+ assert(vb.vCount == 3);
+ select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
+ select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2);
+ vb.vBuffer[0] = vb.vBuffer[2];
+ vb.vBuffer[1] = vb.vBuffer[3];
+ vb.vCount = 2;
+ }
+ break;
+ case GL_POLYGON:
+ switch (p->FrontMode) {
+ case GL_POINT:
+ assert(vb.vCount == 0);
+ select_point(v);
+ break;
+ case GL_LINE:
+ if (vb.vCount == 0)
+ {
+ vb.vCount = 1;
+ vb.partialLineLoop = GL_FALSE;
+ }
+ else if (vb.vCount == 1)
+ {
+ select_line(vb.vBuffer + 0, vb.vBuffer + 1);
+ vb.partialLineLoop = GL_TRUE;
+ vb.vCount = 2;
+ }
+ else
+ {
+ assert(vb.vCount == 2);
+ vb.partialLineLoop = GL_FALSE;
+ select_line(vb.vBuffer + 1, vb.vBuffer + 2);
+ vb.vBuffer[1] = vb.vBuffer[2];
+ /* leave vb.vCount at 2 */
+ }
+ break;
+ case GL_FILL:
+ /* draw as a tri-fan */
+ if (vb.vCount == 0 || vb.vCount == 1)
+ {
+ vb.vCount++;
+ }
+ else
+ {
+ assert(vb.vCount == 2);
+ select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
+ vb.vBuffer[1] = vb.vBuffer[2];
+ /* leave vb.vCount = 2 */
+ }
+ break;
+ default:
+ ; /* impossible */
+ }
+ break;
+ default:
+ ; /* outside begin/end -- no action required */
+ }
+}
+
+/**
+ * \brief Calls radeon_select_Vertex4f().
+ */
+static void radeon_select_Vertex2f(GLfloat x, GLfloat y)
+{
+ radeon_select_Vertex4f(x, y, 0.0, 1.0);
+}
+
+/**
+ * \brief Calls radeon_select_Vertex4f().
+ */
+static void radeon_select_Vertex2fv(const GLfloat * v)
+{
+ radeon_select_Vertex4f(v[0], v[1], 0.0, 1.0);
+}
+
+/**
+ * \brief Calls radeon_select_Vertex4f().
+ */
+static void radeon_select_Vertex3f(GLfloat x, GLfloat y, GLfloat z)
+{
+ radeon_select_Vertex4f(x, y, z, 1.0);
+}
+
+/**
+ * \brief Calls radeon_select_Vertex4f().
+ */
+static void radeon_select_Vertex3fv(const GLfloat * v)
+{
+ radeon_select_Vertex4f(v[0], v[1], v[2], 1.0);
+}
+
+
+/**
+ * \brief Set current vertex color.
+ *
+ * \param r red color component.
+ * \param g gree color component.
+ * \param b blue color component.
+ * \param a alpha color component.
+ *
+ * Updates the GL context's current vertex color.
+ */
+static void radeon_select_Color4f( GLfloat r, GLfloat g,
+ GLfloat b, GLfloat a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
+ dest[0] = r;
+ dest[1] = g;
+ dest[2] = b;
+ dest[3] = a;
+}
+
+/**
+ * \brief Calls radeon_select_Color4f().
+ */
+static void radeon_select_Color4fv( const GLfloat *v )
+{
+ radeon_select_Color4f( v[0], v[1], v[2], v[3] );
+}
+
+/**
+ * \brief Calls radeon_select_Color4f().
+ */
+static void radeon_select_Color3f( GLfloat r, GLfloat g, GLfloat b )
+{
+ radeon_select_Color4f( r, g, b, 1.0 );
+}
+
+/**
+ * \brief Calls radeon_select_Color4f().
+ */
+static void radeon_select_Color3fv( const GLfloat *v )
+{
+ radeon_select_Color4f( v[0], v[1], v[2], 1.0 );
+}
+
+/**
+ * \brief Set current vertex texture coordinates.
+ *
+ * \param s texture coordinate.
+ * \param t texture coordinate.
+ *
+ * Updates the GL context's current vertex texture coordinates.
+ */
+static __inline__ void radeon_select_TexCoord2f( GLfloat s, GLfloat t )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
+ dest[0] = s;
+ dest[1] = t;
+}
+
+/**
+ * \brief Calls radeon_select_TexCoord2f().
+ */
+static void radeon_select_TexCoord2fv( const GLfloat *v )
+{
+ radeon_select_TexCoord2f( v[0], v[1] );
+}
+
+
+/**
+ * \brief Process glBegin().
+ *
+ * \param mode primitive.
+ */
+static void radeon_select_Begin(GLenum mode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (mode > GL_POLYGON) {
+ _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
+ return;
+ }
+
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+ return;
+ }
+
+ ctx->Driver.CurrentExecPrimitive = mode;
+
+ vb.vCount = 0;
+ vb.lineReset = GL_TRUE;
+ vb.partialLineLoop = GL_FALSE;
+}
+
+/**
+ * \brief Process glEnd().
+ */
+static void radeon_select_End(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP ||
+ (ctx->Driver.CurrentExecPrimitive == GL_POLYGON &&
+ ctx->Polygon.FrontMode == GL_LINE))
+ && vb.vCount == 2 )
+ {
+ /* draw the last line segment */
+ if (vb.partialLineLoop)
+ select_line(vb.vBuffer + 1, vb.vBuffer + 0);
+ else
+ select_line(vb.vBuffer + 2, vb.vBuffer + 0);
+ }
+
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+}
+
+
+/**
+ * \brief Flush vertices.
+ *
+ * \param ctx GL context.
+ * \param flags not used.
+ *
+ * Nothing much to do here, besides marking the vertices as flushed, as we
+ * don't buffer anything.
+ */
+static void radeonSelectFlushVertices( GLcontext *ctx, GLuint flags )
+{
+ ctx->Driver.NeedFlush = 0;
+}
+
+/**
+ * \brief Install the select callbacks.
+ *
+ * \param ctx GL context.
+ *
+ * Installs the glBegin()/glEnd() associated select callbacks into the glapi
+ * table.
+ */
+void radeon_select_Install( GLcontext *ctx )
+{
+ struct _glapi_table *exec = ctx->Exec;
+
+ exec->Color3f = radeon_select_Color3f;
+ exec->Color3fv = radeon_select_Color3fv;
+ exec->Color4f = radeon_select_Color4f;
+ exec->Color4fv = radeon_select_Color4fv;
+ exec->TexCoord2f = radeon_select_TexCoord2f;
+ exec->TexCoord2fv = radeon_select_TexCoord2fv;
+ exec->Vertex2f = radeon_select_Vertex2f;
+ exec->Vertex2fv = radeon_select_Vertex2fv;
+ exec->Vertex3f = radeon_select_Vertex3f;
+ exec->Vertex3fv = radeon_select_Vertex3fv;
+ exec->Begin = radeon_select_Begin;
+ exec->End = radeon_select_End;
+
+ ctx->Driver.FlushVertices = radeonSelectFlushVertices;
+}
+/*@}*/
+
+
+
+/**
+ * \brief Set rasterization mode.
+ *
+ * \param ctx GL context.
+ * \param mode rasterization mode. Supports GL_RENDER or
+ *
+ * If mode is GL_RENDER, calls either radeonVtxfmtInit() or
+ * radeon_noop_Install depending on whether the application has focus
+ * (i.e., a fullscreen-cliprect) or not. If mode is GL_SELECT, calls
+ * radeon_select_Install().
+ */
+static void radeonRenderMode( GLcontext *ctx, GLenum mode )
+{
+ switch (mode) {
+ case GL_RENDER:
+ radeonVtxfmtInit( ctx );
+ break;
+ case GL_SELECT:
+ radeon_select_Install( ctx );
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Setup the GL context driver callbacks.
+ *
+ * \param ctx GL context.
+ *
+ * \sa Called by radeonCreateContext().
+ */
+void radeonInitSelect( GLcontext *ctx )
+{
+ ctx->Driver.RenderMode = radeonRenderMode;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_tex.c b/src/mesa/drivers/dri/radeon/radeon_subset_tex.c
new file mode 100644
index 0000000000..e401779513
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_subset_tex.c
@@ -0,0 +1,1018 @@
+/**
+ * \file radeon_subset_tex.c
+ * \brief Texturing.
+ *
+ * \author Gareth Hughes <gareth@valinux.com>
+ * \author Brian Paul <brianp@valinux.com>
+ */
+
+/*
+ * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS 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/radeon/radeon_tex.c,v 1.6 2002/09/16 18:05:20 eich Exp $ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "colormac.h"
+#include "context.h"
+#include "enums.h"
+#include "image.h"
+#include "simple_list.h"
+#include "texformat.h"
+#include "texstore.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_subset.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+
+/**
+ * \brief Destroy hardware state associated with a texture.
+ *
+ * \param rmesa Radeon context.
+ * \param t Radeon texture object to be destroyed.
+ *
+ * Frees the memory associated with the texture and if the texture is bound to
+ * a texture unit cleans the associated hardware state.
+ */
+void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
+{
+ if ( t->memBlock ) {
+ mmFreeMem( t->memBlock );
+ t->memBlock = NULL;
+ }
+
+ if ( t->tObj )
+ t->tObj->DriverData = NULL;
+
+ if ( rmesa ) {
+ if ( t == rmesa->state.texture.unit[0].texobj ) {
+ rmesa->state.texture.unit[0].texobj = NULL;
+ remove_from_list( &rmesa->hw.tex[0] );
+ make_empty_list( &rmesa->hw.tex[0] );
+ }
+ }
+
+ remove_from_list( t );
+ FREE( t );
+}
+
+
+/**
+ * \brief Keep track of swapped out texture objects.
+ *
+ * \param rmesa Radeon context.
+ * \param t Radeon texture object.
+ *
+ * Frees the memory associated with the texture, marks all mipmap images in
+ * the texture as dirty and add it to the radeon_texture::swapped list.
+ */
+static void radeonSwapOutTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
+{
+ if ( t->memBlock ) {
+ mmFreeMem( t->memBlock );
+ t->memBlock = NULL;
+ }
+
+ t->dirty_images = ~0;
+ move_to_tail( &rmesa->texture.swapped, t );
+}
+
+
+/**
+ * Texture space has been invalidated.
+ *
+ * \param rmesa Radeon context.
+ * \param heap texture heap number.
+ *
+ * Swaps out every texture in the specified heap.
+ */
+void radeonAgeTextures( radeonContextPtr rmesa, int heap )
+{
+ radeonTexObjPtr t, tmp;
+
+ foreach_s ( t, tmp, &rmesa->texture.objects[heap] )
+ radeonSwapOutTexObj( rmesa, t );
+}
+
+
+/***************************************************************/
+/** \name Texture image conversions
+ */
+/*@{*/
+
+/**
+ * \brief Upload texture image.
+ *
+ * \param rmesa Radeon context.
+ * \param t Radeon texture object.
+ * \param level level of the image to take the sub-image.
+ * \param x sub-image abscissa.
+ * \param y sub-image ordinate.
+ * \param width sub-image width.
+ * \param height sub-image height.
+ *
+ * Fills in a drmRadeonTexture and drmRadeonTexImage structures and uploads the
+ * texture via the DRM_RADEON_TEXTURE ioctl, aborting in case of failure.
+ */
+static void radeonUploadSubImage( radeonContextPtr rmesa,
+ radeonTexObjPtr t, GLint level,
+ GLint x, GLint y, GLint width, GLint height )
+{
+ struct gl_texture_image *texImage;
+ GLint ret;
+ drmRadeonTexture tex;
+ drmRadeonTexImage tmp;
+
+ level += t->firstLevel;
+ texImage = t->tObj->Image[level];
+
+ if ( !texImage || !texImage->Data )
+ return;
+
+ t->image[level].data = texImage->Data;
+
+ tex.offset = t->bufAddr;
+ tex.pitch = (t->image[0].width * texImage->TexFormat->TexelBytes) / 64;
+ tex.format = t->pp_txformat & RADEON_TXFORMAT_FORMAT_MASK;
+ tex.width = texImage->Width;
+ tex.height = texImage->Height;
+ tex.image = &tmp;
+
+ memcpy( &tmp, &t->image[level], sizeof(drmRadeonTexImage) );
+
+ do {
+ ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE,
+ &tex, sizeof(drmRadeonTexture) );
+ } while ( ret && errno == EAGAIN );
+
+ if ( ret ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret );
+ exit( 1 );
+ }
+}
+
+/**
+ * \brief Upload texture images.
+ *
+ * This might require removing our own and/or other client's texture objects to
+ * make room for these images.
+ *
+ * \param rmesa Radeon context.
+ * \param tObj texture object to upload.
+ *
+ * Sets the matching hardware texture format. Calculates which mipmap levels to
+ * send, depending of the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL and the
+ * Radeon offset rules. Kicks out textures until the requested texture fits,
+ * sets the texture hardware state and, while holding the hardware lock,
+ * uploads any images that are new.
+ */
+static void radeonSetTexImages( radeonContextPtr rmesa,
+ struct gl_texture_object *tObj )
+{
+ radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData;
+ const struct gl_texture_image *baseImage = tObj->Image[tObj->BaseLevel];
+ GLint totalSize;
+ GLint texelsPerDword = 0, blitWidth = 0, blitPitch = 0;
+ GLint x, y, width, height;
+ GLint i;
+ GLint firstLevel, lastLevel, numLevels;
+ GLint log2Width, log2Height;
+ GLuint txformat = 0;
+
+ /* This code cannot be reached once we have lost focus
+ */
+ assert(rmesa->radeonScreen->buffers);
+
+ /* Set the hardware texture format
+ */
+ switch (baseImage->TexFormat->MesaFormat) {
+ case MESA_FORMAT_I8:
+ txformat = RADEON_TXFORMAT_I8;
+ texelsPerDword = 4;
+ blitPitch = 64;
+ break;
+ case MESA_FORMAT_RGBA8888:
+ txformat = RADEON_TXFORMAT_RGBA8888 | RADEON_TXFORMAT_ALPHA_IN_MAP;
+ texelsPerDword = 1;
+ blitPitch = 16;
+ break;
+ case MESA_FORMAT_RGB565:
+ txformat = RADEON_TXFORMAT_RGB565;
+ texelsPerDword = 2;
+ blitPitch = 32;
+ break;
+ default:
+ _mesa_problem(NULL, "unexpected texture format in radeonTexImage2D");
+ return;
+ }
+
+ t->pp_txformat &= ~(RADEON_TXFORMAT_FORMAT_MASK |
+ RADEON_TXFORMAT_ALPHA_IN_MAP);
+ t->pp_txformat |= txformat;
+
+
+ /* Select the larger of the two widths for our global texture image
+ * coordinate space. As the Radeon has very strict offset rules, we
+ * can't upload mipmaps directly and have to reference their location
+ * from the aligned start of the whole image.
+ */
+ blitWidth = MAX2( baseImage->Width, blitPitch );
+
+ /* Calculate mipmap offsets and dimensions.
+ */
+ totalSize = 0;
+ x = 0;
+ y = 0;
+
+ /* Compute which mipmap levels we really want to send to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ * Yes, this looks overly complicated, but it's all needed.
+ */
+ firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5);
+ firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ lastLevel = tObj->BaseLevel + (GLint) (tObj->MaxLod + 0.5);
+ lastLevel = MAX2(lastLevel, tObj->BaseLevel);
+ lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = MIN2(lastLevel, tObj->MaxLevel);
+ lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
+
+ /* save these values */
+ t->firstLevel = firstLevel;
+ t->lastLevel = lastLevel;
+
+ numLevels = lastLevel - firstLevel + 1;
+
+ log2Width = tObj->Image[firstLevel]->WidthLog2;
+ log2Height = tObj->Image[firstLevel]->HeightLog2;
+
+ for ( i = 0 ; i < numLevels ; i++ ) {
+ const struct gl_texture_image *texImage = tObj->Image[i + firstLevel];
+ if ( !texImage )
+ break;
+
+ width = texImage->Width;
+ height = texImage->Height;
+
+ /* Texture images have a minimum pitch of 32 bytes (half of the
+ * 64-byte minimum pitch for blits). For images that have a
+ * width smaller than this, we must pad each texture image
+ * scanline out to this amount.
+ */
+ if ( width < blitPitch / 2 ) {
+ width = blitPitch / 2;
+ }
+
+ totalSize += width * height * baseImage->TexFormat->TexelBytes;
+ ASSERT( (totalSize & 31) == 0 );
+
+ while ( width < blitWidth && height > 1 ) {
+ width *= 2;
+ height /= 2;
+ }
+
+ ASSERT(i < RADEON_MAX_TEXTURE_LEVELS);
+ t->image[i].x = x;
+ t->image[i].y = y;
+ t->image[i].width = width;
+ t->image[i].height = height;
+
+ /* While blits must have a pitch of at least 64 bytes, mipmaps
+ * must be aligned on a 32-byte boundary (just like each texture
+ * image scanline).
+ */
+ if ( width >= blitWidth ) {
+ y += height;
+ } else {
+ x += width;
+ if ( x >= blitWidth ) {
+ x = 0;
+ y++;
+ }
+ }
+ }
+
+ /* Align the total size of texture memory block.
+ */
+ t->totalSize = (totalSize + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
+
+ /* Hardware state:
+ */
+ t->pp_txfilter &= ~RADEON_MAX_MIP_LEVEL_MASK;
+ t->pp_txfilter |= (numLevels - 1) << RADEON_MAX_MIP_LEVEL_SHIFT;
+
+ t->pp_txformat &= ~(RADEON_TXFORMAT_WIDTH_MASK |
+ RADEON_TXFORMAT_HEIGHT_MASK);
+ t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_WIDTH_SHIFT) |
+ (log2Height << RADEON_TXFORMAT_HEIGHT_SHIFT));
+ t->dirty_state = TEX_ALL;
+
+ /* Update the local texture LRU.
+ */
+ move_to_head( &rmesa->texture.objects[0], t );
+
+ LOCK_HARDWARE( rmesa );
+
+ /* Kick out textures until the requested texture fits */
+ while ( !t->memBlock ) {
+ t->memBlock = mmAllocMem( rmesa->texture.heap[0], t->totalSize, 12, 0);
+
+ if (!t->memBlock)
+ radeonSwapOutTexObj( rmesa, rmesa->texture.objects[0].prev );
+
+ }
+
+ /* Set the base offset of the texture image */
+ t->bufAddr = rmesa->radeonScreen->texOffset[0] + t->memBlock->ofs;
+ t->pp_txoffset = t->bufAddr;
+
+ /* Upload any images that are new
+ */
+ for ( i = 0 ; i < numLevels ; i++ ) {
+ if ( t->dirty_images & (1 << i) ) {
+ radeonUploadSubImage( rmesa, t, i, 0, 0,
+ t->image[i].width, t->image[i].height );
+ }
+ }
+
+ rmesa->texture.age[0] = ++rmesa->sarea->texAge[0];
+ UNLOCK_HARDWARE( rmesa );
+ t->dirty_images = 0;
+}
+
+/*@}*/
+
+
+/******************************************************************/
+/** \name Texture combine functions
+ */
+/*@{*/
+
+enum {
+ RADEON_DISABLE = 0, /**< \brief disabled */
+ RADEON_REPLACE = 1, /**< \brief replace function */
+ RADEON_MODULATE = 2, /**< \brief modulate function */
+ RADEON_DECAL = 3, /**< \brief decal function */
+ RADEON_BLEND = 4, /**< \brief blend function */
+ RADEON_MAX_COMBFUNC = 5 /**< \brief max number of combine functions */
+} ;
+
+
+/**
+ * \brief Color combine function hardware state table.
+ */
+static GLuint radeon_color_combine[][RADEON_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_CURRENT_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00802800
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T0_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800142
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T0_COLOR |
+ RADEON_COLOR_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x008c2d42
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T0_COLOR |
+ RADEON_COLOR_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x008c2902
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_TFACTOR_COLOR |
+ RADEON_COLOR_ARG_C_T0_COLOR |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ },
+
+};
+
+/**
+ * \brief Alpha combine function hardware state table.
+ */
+static GLuint radeon_alpha_combine[][RADEON_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00800500
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800051
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_T0_ALPHA |
+ RADEON_ALPHA_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x00800100
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x00800051
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_TFACTOR_ALPHA |
+ RADEON_ALPHA_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ },
+
+};
+
+/*@}*/
+
+
+/******************************************************************/
+/** \name Texture unit state management
+ */
+/*@{*/
+
+/**
+ * \brief Update the texture environment.
+ *
+ * \param ctx GL context
+ * \param unit texture unit to update.
+ *
+ * Sets the state of the RADEON_TEX_PP_TXCBLEND and RADEON_TEX_PP_TXABLEND
+ * registers using the ::radeon_color_combine and ::radeon_alpha_combine tables,
+ * and informs of the state change.
+ */
+static void radeonUpdateTextureEnv( GLcontext *ctx, int unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ const GLenum format = tObj->Image[tObj->BaseLevel]->Format;
+ GLuint color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ GLuint alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+
+
+ /* Set the texture environment state. Isn't this nice and clean?
+ * The Radeon will automagically set the texture alpha to 0xff when
+ * the texture format does not include an alpha component. This
+ * reduces the amount of special-casing we have to do, alpha-only
+ * textures being a notable exception.
+ */
+ switch ( texUnit->EnvMode ) {
+ case GL_REPLACE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_REPLACE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE];
+ break;
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_REPLACE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case GL_MODULATE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_MODULATE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_MODULATE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case GL_DECAL:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_DECAL];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case GL_BLEND:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_BLEND];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_BLEND];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_BLEND];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ( rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] != color_combine ||
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] != alpha_combine ) {
+ RADEON_STATECHANGE( rmesa, tex[unit] );
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] = color_combine;
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] = alpha_combine;
+ }
+}
+
+
+#define TEXOBJ_TXFILTER_MASK (RADEON_MAX_MIP_LEVEL_MASK | \
+ RADEON_MIN_FILTER_MASK | \
+ RADEON_MAG_FILTER_MASK | \
+ RADEON_MAX_ANISO_MASK | \
+ RADEON_CLAMP_S_MASK | \
+ RADEON_CLAMP_T_MASK)
+
+#define TEXOBJ_TXFORMAT_MASK (RADEON_TXFORMAT_WIDTH_MASK | \
+ RADEON_TXFORMAT_HEIGHT_MASK | \
+ RADEON_TXFORMAT_FORMAT_MASK | \
+ RADEON_TXFORMAT_ALPHA_IN_MAP)
+
+
+
+void radeonUpdateTextureState( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[0];
+
+ if ( texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT) ) {
+ struct gl_texture_object *tObj = texUnit->_Current;
+ radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData;
+
+ /* Upload teximages (not pipelined)
+ */
+ if ( t->dirty_images ) {
+ RADEON_FIREVERTICES( rmesa );
+ radeonSetTexImages( rmesa, tObj );
+ }
+
+ /* Update state if this is a different texture object to last
+ * time.
+ */
+ if ( rmesa->state.texture.unit[0].texobj != t ) {
+ rmesa->state.texture.unit[0].texobj = t;
+ t->dirty_state |= 1<<0;
+ move_to_head( &rmesa->texture.objects[0], t );
+ }
+
+ if (t->dirty_state) {
+ GLuint *cmd = RADEON_DB_STATE( tex[0] );
+
+ cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK;
+ cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
+ cmd[TEX_PP_TXFILTER] |= t->pp_txfilter & TEXOBJ_TXFILTER_MASK;
+ cmd[TEX_PP_TXFORMAT] |= t->pp_txformat & TEXOBJ_TXFORMAT_MASK;
+ cmd[TEX_PP_TXOFFSET] = t->pp_txoffset;
+ cmd[TEX_PP_BORDER_COLOR] = t->pp_border_color;
+
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[0] );
+ t->dirty_state = 0;
+ }
+
+ /* Newly enabled?
+ */
+ if (!(rmesa->hw.ctx.cmd[CTX_PP_CNTL] & RADEON_TEX_0_ENABLE)) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (RADEON_TEX_0_ENABLE |
+ RADEON_TEX_BLEND_0_ENABLE);
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST0;
+ }
+
+ radeonUpdateTextureEnv( ctx, 0 );
+ }
+ else if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<0)) {
+ /* Texture unit disabled */
+ rmesa->state.texture.unit[0].texobj = 0;
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &=
+ ~((RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << 0);
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST0 |
+ RADEON_TCL_VTX_Q0);
+ }
+}
+
+
+
+/**
+ * \brief Choose texture format.
+ *
+ * \param ctx GL context.
+ * \param internalFormat texture internal format.
+ * \param format pixel format. Not used.
+ * \param type pixel data type. Not used.
+ *
+ * \return pointer to chosen texture format.
+ *
+ * Returns a pointer to one of the Mesa texture formats which is supported by
+ * Radeon and matches the internal format.
+ */
+static const struct gl_texture_format *
+radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+ GLenum format, GLenum type )
+{
+ switch ( internalFormat ) {
+ case GL_RGBA:
+ case GL_RGBA8:
+ return &_mesa_texformat_rgba8888;
+
+ case GL_RGB:
+ case GL_RGB5:
+ return &_mesa_texformat_rgb565;
+
+ case GL_INTENSITY:
+ case GL_INTENSITY8:
+ return &_mesa_texformat_i8;
+
+ default:
+ _mesa_problem(ctx, "unexpected texture format in radeonChoosTexFormat");
+ return NULL;
+ }
+}
+
+/**
+ * \brief Allocate a Radeon texture object.
+ *
+ * \param texObj texture object.
+ *
+ * \return pointer to the device specific texture object on success, or NULL on failure.
+ *
+ * Allocates and initializes a radeon_tex_obj structure to connect it to the
+ * driver private data pointer in \p texObj.
+ */
+static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj )
+{
+ radeonTexObjPtr t;
+
+ t = CALLOC_STRUCT( radeon_tex_obj );
+ if (!t)
+ return NULL;
+
+ t->tObj = texObj;
+ texObj->DriverData = t;
+ make_empty_list( t );
+ t->dirty_images = ~0;
+ return t;
+}
+
+
+/**
+ * \brief Load a texture image.
+ *
+ * \param ctx GL context.
+ * \param texObj texture object
+ * \param target target texture.
+ * \param level level of detail number.
+ * \param internalFormat internal format.
+ * \param width texture image width.
+ * \param height texture image height.
+ * \param border border width.
+ * \param format pixel format.
+ * \param type pixel data type.
+ * \param pixels image data.
+ * \param packing passed to _mesa_store_teximage2d() unchanged.
+ * \param texImage passed to _mesa_store_teximage2d() unchanged.
+ *
+ * If there is a device specific texture object associated with the given
+ * texture object then swaps that texture out. Calls _mesa_store_teximage2d()
+ * with all other parameters unchanged.
+ */
+static void radeonTexImage2D( 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 )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeonTexObjPtr t = (radeonTexObjPtr)texObj->DriverData;
+
+ if ( t )
+ radeonSwapOutTexObj( rmesa, t );
+
+ /* Note, this will call radeonChooseTextureFormat */
+ _mesa_store_teximage2d(ctx, target, level, internalFormat,
+ width, height, border, format, type, pixels,
+ &ctx->Unpack, texObj, texImage);
+}
+
+/**
+ * \brief Set texture environment parameters.
+ *
+ * \param ctx GL context.
+ * \param target texture environment.
+ * \param pname texture parameter. Accepted value is GL_TEXTURE_ENV_COLOR.
+ * \param param parameter value.
+ *
+ * Updates the current unit's RADEON_TEX_PP_TFACTOR register and informs of the
+ * state change.
+ */
+static void radeonTexEnv( GLcontext *ctx, GLenum target,
+ GLenum pname, const GLfloat *param )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint unit = ctx->Texture.CurrentUnit;
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+ switch ( pname ) {
+ case GL_TEXTURE_ENV_COLOR: {
+ GLubyte c[4];
+ GLuint envColor;
+ UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
+ envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
+ if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
+ RADEON_STATECHANGE( rmesa, tex[unit] );
+ rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
+ }
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+
+/**
+ * \brief Set texture parameter.
+ *
+ * \param ctx GL context.
+ * \param target target texture.
+ * \param texObj texture object.
+ * \param pname texture parameter.
+ * \param params parameter value.
+ *
+ * Allocates the device specific texture object data if it doesn't exist
+ * already.
+ *
+ * Updates the texture object radeon_tex_obj::pp_txfilter register and marks
+ * the texture state (radeon_tex_obj::dirty_state) as dirty.
+ */
+static void radeonTexParameter( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *texObj,
+ GLenum pname, const GLfloat *params )
+{
+ radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
+
+ if (!t)
+ t = radeonAllocTexObj( texObj );
+
+ switch ( pname ) {
+ case GL_TEXTURE_MIN_FILTER:
+ t->pp_txfilter &= ~RADEON_MIN_FILTER_MASK;
+ switch ( texObj->MinFilter ) {
+ case GL_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
+ break;
+ }
+ break;
+
+ case GL_TEXTURE_MAG_FILTER:
+ t->pp_txfilter &= ~RADEON_MAG_FILTER_MASK;
+ switch ( texObj->MagFilter ) {
+ case GL_NEAREST:
+ t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
+ break;
+ }
+ break;
+
+ case GL_TEXTURE_WRAP_S:
+ t->pp_txfilter &= ~RADEON_CLAMP_S_MASK;
+ switch ( texObj->WrapS ) {
+ case GL_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
+ break;
+ }
+ break;
+
+ case GL_TEXTURE_WRAP_T:
+ t->pp_txfilter &= ~RADEON_CLAMP_T_MASK;
+ switch ( texObj->WrapT ) {
+ case GL_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
+ break;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ /* Mark this texobj as dirty (one bit per tex unit)
+ */
+ t->dirty_state = TEX_ALL;
+}
+
+/**
+ * \brief Bind texture.
+ *
+ * \param ctx GL context.
+ * \param target not used.
+ * \param texObj texture object.
+ *
+ * Allocates the device specific texture data if it doesn't exist already.
+ */
+static void radeonBindTexture( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *texObj )
+{
+ if ( !texObj->DriverData )
+ radeonAllocTexObj( texObj );
+}
+
+/**
+ * \brief Delete texture.
+ *
+ * \param ctx GL context.
+ * \param texObj texture object.
+ *
+ * Fires any outstanding vertices and destroy the device specific texture
+ * object.
+ */
+static void radeonDeleteTexture( GLcontext *ctx,
+ struct gl_texture_object *texObj )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
+
+ if ( t ) {
+ if ( rmesa )
+ RADEON_FIREVERTICES( rmesa );
+ radeonDestroyTexObj( rmesa, t );
+ }
+}
+
+/**
+ * \brief Initialize context texture object data.
+ *
+ * \param ctx GL context.
+ *
+ * Called by radeonInitTextureFuncs() to setup the context initial texture
+ * objects.
+ */
+static void radeonInitTextureObjects( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_object *texObj;
+ GLuint tmp = ctx->Texture.CurrentUnit;
+
+ ctx->Texture.CurrentUnit = 0;
+
+ texObj = ctx->Texture.Unit[0].Current2D;
+ radeonBindTexture( ctx, GL_TEXTURE_2D, texObj );
+ move_to_tail( &rmesa->texture.swapped,
+ (radeonTexObjPtr)texObj->DriverData );
+
+
+ ctx->Texture.CurrentUnit = tmp;
+}
+
+/**
+ * \brief Setup the GL context driver callbacks.
+ *
+ * \param ctx GL context.
+ *
+ * \sa Called by radeonCreateContext().
+ */
+void radeonInitTextureFuncs( GLcontext *ctx )
+{
+ ctx->Driver.ChooseTextureFormat = radeonChooseTextureFormat;
+ ctx->Driver.TexImage2D = radeonTexImage2D;
+
+ ctx->Driver.BindTexture = radeonBindTexture;
+ ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */
+ ctx->Driver.DeleteTexture = radeonDeleteTexture;
+ ctx->Driver.PrioritizeTexture = NULL;
+ ctx->Driver.ActiveTexture = NULL;
+ ctx->Driver.UpdateTexturePalette = NULL;
+
+ ctx->Driver.TexEnv = radeonTexEnv;
+ ctx->Driver.TexParameter = radeonTexParameter;
+
+ radeonInitTextureObjects( ctx );
+}
+
+/*@}*/
diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_vtx.c b/src/mesa/drivers/dri/radeon/radeon_subset_vtx.c
new file mode 100644
index 0000000000..aa6ec73d5b
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_subset_vtx.c
@@ -0,0 +1,989 @@
+/**
+ * \file radeon_subset_vtx.c
+ * \brief Vertex buffering.
+ *
+ * \author Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+/*
+ * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ * Tungsten Graphics Inc., Cedar Park, Texas.
+ *
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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$ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "api_noop.h"
+#include "context.h"
+/*#include "mmath.h" */
+#include "mtypes.h"
+#include "enums.h"
+#include "glapi.h"
+#include "colormac.h"
+#include "state.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_subset.h"
+
+/**
+ * \brief Union for vertex data.
+ */
+union vertex_dword {
+ float f; /**< \brief floating point value */
+ int i; /**< \brief integer point value */
+};
+
+
+/**
+ * \brief Maximum number of dwords per vertex.
+ *
+ * Defined as 10 to hold: \code xyzw rgba st \endcode
+ */
+#define MAX_VERTEX_DWORDS 10
+
+
+/**
+ * \brief Global vertex buffer data.
+ */
+static struct vb_t {
+ /**
+ * \brief Notification mechanism.
+ *
+ * These are treated as a stack to allow us to do things like build quads in
+ * temporary storage and then emit them as triangles.
+ */
+ struct {
+ GLint vertspace; /**< \brief free vertices count */
+ GLint initial_vertspace; /**< \brief total vertices count */
+ GLint *dmaptr; /**< \brief */
+ void (*notify)( void ); /**< \brief notification callback */
+ } stack[2];
+
+ /**
+ * \brief Storage for current vertex.
+ */
+ union vertex_dword vertex[MAX_VERTEX_DWORDS];
+
+ /**
+ * \brief Temporary storage for quads, etc.
+ */
+ union vertex_dword vertex_store[MAX_VERTEX_DWORDS * 4];
+
+ /**
+ * \name Color/texture
+ *
+ * Pointers to either vertex or ctx->Current.Attrib, depending on whether
+ * color/texture participates in the current vertex.
+ */
+ /*@{*/
+ GLfloat *floatcolorptr; /**< \brief color */
+ GLfloat *texcoordptr; /**< \brief texture */
+ /*@}*/
+
+ /**
+ * \brief Pointer to the GL context.
+ */
+ GLcontext *context;
+
+ /**
+ * \brief Active primitive.
+ *
+ * \note May differ from ctx->Driver.CurrentExecPrimitive.
+ */
+ /*@{*/
+ GLenum prim; /**< \brief primitive */
+ GLuint vertex_format; /**< \brief vertex format */
+ GLint vertex_size; /**< \brief vertex size */
+ GLboolean recheck; /**< \brief set if it's needed to validate this information */
+ /*@}*/
+} vb;
+
+
+static void radeonFlushVertices( GLcontext *, GLuint );
+
+
+/**
+ * \brief Primitive information table.
+ */
+static struct prims_t {
+ int start, /**< \brief vertex count for the starting primitive */
+ incr, /**< \brief vertex increment for a further primitive */
+ hwprim; /**< \brief hardware primitive */
+} prims[10] = {
+ { 1, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_POINT },
+ { 2, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE },
+ { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP },
+ { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP },
+ { 3, 3, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST },
+ { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP },
+ { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN },
+ { 4, 4, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST },
+ { 4, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP },
+ { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN },
+};
+
+
+/**
+ * \brief Finish the primitive in the vertex buffer.
+ *
+ * \param rmesa Radeon context.
+ *
+ * Truncates any redundant vertices off the end of the buffer, emit the
+ * remaining vertices and advances the current DMA region.
+ */
+static void finish_prim( radeonContextPtr rmesa )
+{
+ GLuint prim_end = vb.stack[0].initial_vertspace - vb.stack[0].vertspace;
+
+ /* Too few vertices? (eg: 2 vertices for a triangles prim?)
+ */
+ if (prim_end < prims[vb.prim].start)
+ return;
+
+ /* Drop redundant vertices off end of primitive. (eg: 5 vertices
+ * for triangles prim?)
+ */
+ prim_end -= (prim_end - prims[vb.prim].start) % prims[vb.prim].incr;
+
+ radeonEmitVertexAOS( rmesa, vb.vertex_size, GET_START(&rmesa->dma.current) );
+
+ radeonEmitVbufPrim( rmesa, vb.vertex_format,
+ prims[vb.prim].hwprim | rmesa->tcl.tcl_flag,
+ prim_end );
+
+ rmesa->dma.current.ptr =
+ rmesa->dma.current.start += prim_end * vb.vertex_size * 4;
+}
+
+
+/**
+ * \brief Copy a vertex from the current DMA region
+ *
+ * \param rmesa Radeon context.
+ * \param n vertex index relative to the current DMA region.
+ * \param dst destination pointer.
+ *
+ * Used internally by copy_dma_verts().
+ */
+static void copy_vertex( radeonContextPtr rmesa, GLuint n, GLfloat *dst )
+{
+ GLuint i;
+ GLfloat *src = (GLfloat *)(rmesa->dma.current.address +
+ rmesa->dma.current.ptr +
+ n * vb.vertex_size * 4);
+
+ for (i = 0 ; i < vb.vertex_size; i++)
+ dst[i] = src[i];
+}
+
+
+/**
+ * \brief Copy last vertices from the current DMA buffer to resume in a new buffer.
+ *
+ * \param rmesa Radeon context.
+ * \param tmp destination buffer.
+ *
+ * Takes from the current DMA buffer the last vertices necessary to resume in a
+ * new buffer, according to the current primitive. Uses internally
+ * copy_vertex() for the vertex copying.
+ *
+ */
+static GLuint copy_dma_verts( radeonContextPtr rmesa,
+ GLfloat (*tmp)[MAX_VERTEX_DWORDS] )
+{
+ GLuint ovf, i;
+ GLuint nr = vb.stack[0].initial_vertspace - vb.stack[0].vertspace;
+
+ switch( vb.prim )
+ {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr&1;
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ case GL_LINE_STRIP:
+ if (nr == 0)
+ return 0;
+ copy_vertex( rmesa, nr-1, tmp[0] );
+ return 1;
+ case GL_LINE_LOOP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ if (nr == 0)
+ return 0;
+ else if (nr == 1) {
+ copy_vertex( rmesa, 0, tmp[0] );
+ return 1;
+ } else {
+ copy_vertex( rmesa, 0, tmp[0] );
+ copy_vertex( rmesa, nr-1, tmp[1] );
+ return 2;
+ }
+ case GL_TRIANGLES:
+ ovf = nr % 3;
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ case GL_QUADS:
+ ovf = nr % 4;
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ case GL_TRIANGLE_STRIP:
+ case GL_QUAD_STRIP:
+ ovf = MIN2(nr, 2);
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ default:
+ return 0;
+ }
+}
+
+static void notify_wrap_buffer( void );
+
+/**
+ * \brief Resets the vertex buffer notification mechanism.
+ *
+ * Fills in vb_t::stack with the values from the current DMA region in
+ * radeon_dma::current and sets the notification callback to
+ * notify_wrap_buffer().
+ */
+static void reset_notify( void )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( vb.context );
+
+ vb.stack[0].dmaptr = (int *)(rmesa->dma.current.address +
+ rmesa->dma.current.ptr);
+ vb.stack[0].vertspace = ((rmesa->dma.current.end - rmesa->dma.current.ptr) /
+ (vb.vertex_size * 4));
+ vb.stack[0].vertspace &= ~1; /* even numbers only -- avoid tristrip parity */
+ vb.stack[0].initial_vertspace = vb.stack[0].vertspace;
+ vb.stack[0].notify = notify_wrap_buffer;
+}
+
+/**
+ * \brief Full buffer notification callback.
+ *
+ * Makes a copy of the necessary vertices of the current buffer via
+ * copy_dma_verts(), gets and resets new buffer via radeon and re-emits the
+ * saved vertices.
+ */
+static void notify_wrap_buffer( void )
+{
+ GLcontext *ctx = vb.context;
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat tmp[3][MAX_VERTEX_DWORDS];
+ GLuint i, nrverts = 0;
+
+ /* Copy vertices out of dma:
+ */
+ nrverts = copy_dma_verts( rmesa, tmp );
+ finish_prim( rmesa );
+
+ /* Get new buffer
+ */
+ radeonRefillCurrentDmaRegion( rmesa );
+
+ /* Reset vertspace[0], dmaptr
+ */
+ reset_notify();
+
+ /* Reemit saved vertices
+ */
+ for (i = 0 ; i < nrverts; i++) {
+ memcpy( vb.stack[0].dmaptr, tmp[i], vb.vertex_size * 4 );
+ vb.stack[0].dmaptr += vb.vertex_size;
+ vb.stack[0].vertspace--;
+ }
+}
+
+
+static void notify_noop( void )
+{
+ vb.stack[0].dmaptr = (int *)vb.vertex;
+ vb.stack[0].notify = notify_noop;
+ vb.stack[0].vertspace = 1;
+}
+
+/**
+ * \brief Pop the notification mechanism stack.
+ *
+ * Simply copy the second stack array element into the first.
+ *
+ * \sa vb_t::stack and push_notify().
+ */
+static void pop_notify( void )
+{
+ vb.stack[0] = vb.stack[1];
+}
+
+/**
+ * \brief Push the notification mechanism stack.
+ *
+ * \param notify new notify callback for the stack head.
+ * \param space space available for vertices in \p store.
+ * \param store buffer where to store the vertices.
+ *
+ * Copy the second stack array element into the first and makes the stack head
+ * use the given resources.
+ *
+ * \sa vb_t::stack and pop_notify().
+ */
+static void push_notify( void (*notify)( void ), int space,
+ union vertex_dword *store )
+{
+ vb.stack[1] = vb.stack[0];
+ vb.stack[0].notify = notify;
+ vb.stack[0].initial_vertspace = space;
+ vb.stack[0].vertspace = space;
+ vb.stack[0].dmaptr = (int *)store;
+}
+
+
+/**
+ * \brief Emit a stored vertex (in vb_t::vertex_store) to DMA.
+ *
+ * \param v vertex index.
+ *
+ * Adds the vertex into the current vertex buffer and calls the notification
+ * callback vb_t::notify().
+ */
+static void emit_vertex( int v )
+{
+ int i, *tmp = (int *)vb.vertex_store + v * vb.vertex_size;
+
+ for (i = 0 ; i < vb.vertex_size ; i++)
+ *vb.stack[0].dmaptr++ = *tmp++;
+
+ if (--vb.stack[0].vertspace == 0)
+ vb.stack[0].notify();
+}
+
+
+/**
+ * \brief Emit a quad (in vb_t::vertex_store) to DMA as two triangles.
+ *
+ * \param v0 first vertex index.
+ * \param v1 second vertex index.
+ * \param v2 third vertex index.
+ * \param v3 fourth vertex index.
+ *
+ * Calls emit_vertex() to emit the triangles' vertices.
+ */
+static void emit_quad( int v0, int v1, int v2, int v3 )
+{
+ emit_vertex( v0 ); emit_vertex( v1 ); emit_vertex( v3 );
+ emit_vertex( v1 ); emit_vertex( v2 ); emit_vertex( v3 );
+}
+
+/**
+ * \brief Every fourth vertex in a quad primitive, this is called to emit it.
+ *
+ * Pops the notification stack, calls emit_quad() and pushes the notification
+ * stack again, with itself and the vb_t::vertex_store to process another four
+ * vertices.
+ */
+static void notify_quad( void )
+{
+ pop_notify();
+ emit_quad( 0, 1, 2, 3 );
+ push_notify( notify_quad, 4, vb.vertex_store );
+}
+
+static void notify_qstrip1( void );
+
+/**
+ * \brief After the 4th vertex, emit either a quad or a flipped quad each two
+ * vertices.
+ *
+ * Pops the notification stack, calls emit_quad() with the flipped vertices and
+ * pushes the notification stack again, with notify_qstrip1() and the
+ * vb_t::vertex_store to process another two vertices.
+ *
+ * \sa notify_qstrip1().
+ */
+static void notify_qstrip0( void )
+{
+ pop_notify();
+ emit_quad( 0, 1, 3, 2 );
+ push_notify( notify_qstrip1, 2, vb.vertex_store );
+}
+
+/**
+ * \brief After the 4th vertex, emit either a quad or a flipped quad each two
+ * vertices.
+ *
+ * Pops the notification stack, calls emit_quad() with the straight vertices
+ * and pushes the notification stack again, with notify_qstrip0() and the
+ * vb_t::vertex_store to process another two vertices.
+ *
+ * \sa notify_qstrip0().
+ */
+static void notify_qstrip1( void )
+{
+ pop_notify();
+ emit_quad( 2, 3, 1, 0 );
+ push_notify( notify_qstrip0, 2, vb.vertex_store + 2*vb.vertex_size );
+}
+
+/**
+ * \brief Emit the saved vertex (but hang on to it for later).
+ *
+ * Continue processing this primitive as a linestrip.
+ *
+ * Pops the notification stack and calls emit_quad with the first vertex.
+ */
+static void notify_lineloop0( void )
+{
+ pop_notify();
+ emit_vertex(0);
+}
+
+/**
+ * \brief Invalidate the current vertex format.
+ *
+ * \param ctx GL context.
+ *
+ * Sets the vb_t::recheck flag.
+ */
+void radeonVtxfmtInvalidate( GLcontext *ctx )
+{
+ vb.recheck = GL_TRUE;
+}
+
+
+/**
+ * \brief Validate the vertex format from the context.
+ *
+ * \param ctx GL context.
+ *
+ * Signals a new primitive and determines the appropriate vertex format and
+ * size. Points vb_t::floatcolorptr and vb_t::texcoordptr to the current vertex
+ * and sets them to the current color and texture attributes.
+ *
+ * Clears the vb_t::recheck flag on exit.
+ */
+static void radeonVtxfmtValidate( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ GLuint ind = (RADEON_CP_VC_FRMT_Z |
+ RADEON_CP_VC_FRMT_FPCOLOR |
+ RADEON_CP_VC_FRMT_FPALPHA);
+
+ if (ctx->Driver.NeedFlush)
+ ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush );
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled)
+ ind |= RADEON_CP_VC_FRMT_ST0;
+
+ RADEON_NEWPRIM(rmesa);
+ vb.vertex_format = ind;
+ vb.vertex_size = 3;
+
+ /* Would prefer to use ubyte floats in the vertex:
+ */
+ vb.floatcolorptr = &vb.vertex[vb.vertex_size].f;
+ vb.vertex_size += 4;
+ vb.floatcolorptr[0] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0];
+ vb.floatcolorptr[1] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1];
+ vb.floatcolorptr[2] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2];
+ vb.floatcolorptr[3] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];
+
+ if (ind & RADEON_CP_VC_FRMT_ST0) {
+ vb.texcoordptr = &vb.vertex[vb.vertex_size].f;
+ vb.vertex_size += 2;
+ vb.texcoordptr[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0];
+ vb.texcoordptr[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1];
+ }
+ else
+ vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
+
+ vb.recheck = GL_FALSE;
+ ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT;
+}
+
+
+#define RESET_STIPPLE() do { \
+ RADEON_STATECHANGE( rmesa, lin ); \
+ radeonEmitState( rmesa ); \
+} while (0)
+
+#define AUTO_STIPPLE( mode ) do { \
+ RADEON_STATECHANGE( rmesa, lin ); \
+ if (mode) \
+ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] |= \
+ RADEON_LINE_PATTERN_AUTO_RESET; \
+ else \
+ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] &= \
+ ~RADEON_LINE_PATTERN_AUTO_RESET; \
+ radeonEmitState( rmesa ); \
+} while (0)
+
+
+/**
+ * \brief Process glBegin().
+ *
+ * \param mode primitive.
+ */
+static void radeon_Begin( GLenum mode )
+{
+ GLcontext *ctx = vb.context;
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint se_cntl;
+
+ if (mode > GL_POLYGON) {
+ _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
+ return;
+ }
+
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+ return;
+ }
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (rmesa->NewGLState)
+ radeonValidateState( ctx );
+
+ if (vb.recheck)
+ radeonVtxfmtValidate( ctx );
+
+ /* Do we need to grab a new DMA region for the vertices?
+ */
+ if (rmesa->dma.current.ptr + 12*vb.vertex_size*4 > rmesa->dma.current.end) {
+ RADEON_NEWPRIM( rmesa );
+ radeonRefillCurrentDmaRegion( rmesa );
+ }
+
+ reset_notify();
+ vb.prim = ctx->Driver.CurrentExecPrimitive = mode;
+ se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL] | RADEON_FLAT_SHADE_VTX_LAST;
+
+ if (ctx->Line.StippleFlag &&
+ (mode == GL_LINES ||
+ mode == GL_LINE_LOOP ||
+ mode == GL_LINE_STRIP))
+ RESET_STIPPLE();
+
+ switch( mode ) {
+ case GL_LINES:
+ if (ctx->Line.StippleFlag)
+ AUTO_STIPPLE( GL_TRUE );
+ break;
+ case GL_LINE_LOOP:
+ vb.prim = GL_LINE_STRIP;
+ push_notify( notify_lineloop0, 1, vb.vertex_store );
+ break;
+ case GL_QUADS:
+ vb.prim = GL_TRIANGLES;
+ push_notify( notify_quad, 4, vb.vertex_store );
+ break;
+ case GL_QUAD_STRIP:
+ if (ctx->_TriangleCaps & DD_FLATSHADE) {
+ vb.prim = GL_TRIANGLES;
+ push_notify( notify_qstrip0, 4, vb.vertex_store );
+ }
+ break;
+ case GL_POLYGON:
+ if (ctx->_TriangleCaps & DD_FLATSHADE)
+ se_cntl &= ~RADEON_FLAT_SHADE_VTX_LAST;
+ break;
+ default:
+ break;
+ }
+
+ if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) {
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl;
+ }
+}
+
+
+/**
+ * \brief Process glEnd().
+ *
+ */
+static void radeon_End( void )
+{
+ GLcontext *ctx = vb.context;
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+ return;
+ }
+
+ /* Need to finish a line loop?
+ */
+ if (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP)
+ emit_vertex( 0 );
+
+ /* Need to pop off quads/quadstrip/etc notification?
+ */
+ if (vb.stack[0].notify != notify_wrap_buffer)
+ pop_notify();
+
+ finish_prim( rmesa );
+
+ if (ctx->Driver.CurrentExecPrimitive == GL_LINES && ctx->Line.StippleFlag)
+ AUTO_STIPPLE( GL_FALSE );
+
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+ notify_noop();
+}
+
+
+
+/**
+ * \brief Flush vertices.
+ *
+ * \param ctx GL context.
+ * \param flags flags.
+ *
+ * If FLUSH_UPDATE_CURRENT is et in \p flags then the current vertex attributes
+ * in the GL context is updated from vb_t::floatcolorptr and vb_t::texcoordptr.
+ */
+static void radeonFlushVertices( GLcontext *ctx, GLuint flags )
+{
+ if (flags & FLUSH_UPDATE_CURRENT) {
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = vb.floatcolorptr[0];
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = vb.floatcolorptr[1];
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = vb.floatcolorptr[2];
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = vb.floatcolorptr[3];
+
+ if (vb.vertex_format & RADEON_CP_VC_FRMT_ST0) {
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][0] = vb.texcoordptr[0];
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][1] = vb.texcoordptr[1];
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] = 0.0F;
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] = 1.0F;
+ }
+ }
+
+ ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
+}
+
+
+/**
+ * \brief Set current vertex coordinates.
+ *
+ * \param x x vertex coordinate.
+ * \param y y vertex coordinate.
+ * \param z z vertex coordinate.
+ *
+ * Set the current vertex coordinates. If run out of space in this buffer call
+ * the notification callback.
+ */
+static __inline__ void radeon_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ int i;
+
+ *vb.stack[0].dmaptr++ = *(int *)&x;
+ *vb.stack[0].dmaptr++ = *(int *)&y;
+ *vb.stack[0].dmaptr++ = *(int *)&z;
+
+ for (i = 3; i < vb.vertex_size; i++)
+ *vb.stack[0].dmaptr++ = vb.vertex[i].i;
+
+ if (--vb.stack[0].vertspace == 0)
+ vb.stack[0].notify();
+}
+
+/**
+ * \brief Set current vertex color.
+ *
+ * \param r red color component.
+ * \param g gree color component.
+ * \param b blue color component.
+ * \param a alpha color component.
+ *
+ * Sets the current vertex color via vb_t::floatcolorptr.
+ */
+static __inline__ void radeon_Color4f( GLfloat r, GLfloat g,
+ GLfloat b, GLfloat a )
+{
+ GLfloat *dest = vb.floatcolorptr;
+ dest[0] = r;
+ dest[1] = g;
+ dest[2] = b;
+ dest[3] = a;
+}
+
+/**
+ * \brief Set current vertex texture coordinates.
+ *
+ * \param s texture coordinate.
+ * \param t texture coordinate.
+ *
+ * Sets the current vertex color via vb_t::texcoordptr.
+ */
+static __inline__ void radeon_TexCoord2f( GLfloat s, GLfloat t )
+{
+ GLfloat *dest = vb.texcoordptr;
+ dest[0] = s;
+ dest[1] = t;
+}
+
+/**
+ * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
+ * efficient.
+ */
+static void radeon_Vertex3fv( const GLfloat *v )
+{
+ radeon_Vertex3f( v[0], v[1], v[2] );
+}
+
+/**
+ * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
+ * efficient.
+ */
+static void radeon_Vertex2f( GLfloat x, GLfloat y )
+{
+ radeon_Vertex3f( x, y, 0 );
+}
+
+/**
+ * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
+ * efficient.
+ */
+static void radeon_Vertex2fv( const GLfloat *v )
+{
+ radeon_Vertex3f( v[0], v[1], 0 );
+}
+
+/**
+ * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
+ * efficient.
+ */
+static void radeon_Color4fv( const GLfloat *v )
+{
+ radeon_Color4f( v[0], v[1], v[2], v[3] );
+}
+
+/**
+ * Calls radeon_Color4f(), which is expanded inline by the compiler to be
+ * efficient.
+ */
+static void radeon_Color3f( GLfloat r, GLfloat g, GLfloat b )
+{
+ radeon_Color4f( r, g, b, 1.0 );
+}
+
+/**
+ * Calls radeon_Color4f(), which is expanded inline by the compiler to be
+ * efficient.
+ */
+static void radeon_Color3fv( const GLfloat *v )
+{
+ radeon_Color4f( v[0], v[1], v[2], 1.0 );
+}
+
+/**
+ * Calls radeon_TexCoord2f(), which is expanded inline by the compiler to be
+ * efficient.
+ */
+static void radeon_TexCoord2fv( const GLfloat *v )
+{
+ radeon_TexCoord2f( v[0], v[1] );
+}
+
+
+/**
+ * No-op.
+ */
+void radeonVtxfmtUnbindContext( GLcontext *ctx )
+{
+}
+
+/**
+ * No-op.
+ */
+void radeonVtxfmtMakeCurrent( GLcontext *ctx )
+{
+}
+
+/**
+ * No-op.
+ */
+void radeonVtxfmtDestroy( GLcontext *ctx )
+{
+}
+
+/**
+ * \brief Software rendering fallback.
+ *
+ * \param ctx GL context.
+ * \param bit fallback bitmask.
+ * \param mode enable or disable.
+ *
+ * Does nothing except display a warning message if \p mode is set.
+ */
+void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+ if (mode)
+ fprintf(stderr, "Warning: hit nonexistant fallback path!\n");
+}
+
+/**
+ * \brief Software TCL fallback.
+ *
+ * \param ctx GL context.
+ * \param bit fallback bitmask.
+ * \param mode enable or disable.
+ *
+ * Does nothing except display a warning message if \p mode is set.
+ */
+void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+ if (mode)
+ fprintf(stderr, "Warning: hit nonexistant fallback path!\n");
+}
+
+/**
+ * \brief Called by radeonPointsBitmap() to disable TCL.
+ *
+ * \param rmesa Radeon context.
+ * \param flag whether to enable or disable TCL.
+ *
+ * Updates radeon_tcl_info::tcl_flag.
+ */
+void radeonSubsetVtxEnableTCL( radeonContextPtr rmesa, GLboolean flag )
+{
+ rmesa->tcl.tcl_flag = flag ? RADEON_CP_VC_CNTL_TCL_ENABLE : 0;
+}
+
+
+
+/**********************************************************************/
+/** \name Noop mode for operation without focus */
+/**********************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Process glBegin().
+ *
+ * \param mode primitive.
+ */
+static void radeon_noop_Begin(GLenum mode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (mode > GL_POLYGON) {
+ _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
+ return;
+ }
+
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+ return;
+ }
+
+ ctx->Driver.CurrentExecPrimitive = mode;
+}
+
+/**
+ * \brief Process glEnd().
+ */
+static void radeon_noop_End(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+}
+
+
+/**
+ * \brief Install the noop callbacks.
+ *
+ * \param ctx GL context.
+ *
+ * Installs the noop callbacks into the glapi table. These functions
+ * will not attempt to emit any DMA vertices, but will keep internal
+ * GL state updated. Borrows heavily from the select code.
+ */
+static void radeon_noop_Install( GLcontext *ctx )
+{
+ ctx->Exec->Begin = radeon_noop_Begin;
+ ctx->Exec->End = radeon_noop_End;
+
+ vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
+ vb.floatcolorptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
+
+ notify_noop();
+}
+
+
+/**
+ * \brief Setup the GL context callbacks.
+ *
+ * \param ctx GL context.
+ *
+ * Setups the GL context callbacks and links _glapi_table entries related to
+ * the glBegin()/glEnd() pairs to the functions in this module.
+ *
+ * Called by radeonCreateContext() and radeonRenderMode().
+ */
+void radeonVtxfmtInit( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct _glapi_table *exec = ctx->Exec;
+
+ exec->Color3f = radeon_Color3f;
+ exec->Color3fv = radeon_Color3fv;
+ exec->Color4f = radeon_Color4f;
+ exec->Color4fv = radeon_Color4fv;
+ exec->TexCoord2f = radeon_TexCoord2f;
+ exec->TexCoord2fv = radeon_TexCoord2fv;
+ exec->Vertex2f = radeon_Vertex2f;
+ exec->Vertex2fv = radeon_Vertex2fv;
+ exec->Vertex3f = radeon_Vertex3f;
+ exec->Vertex3fv = radeon_Vertex3fv;
+ exec->Begin = radeon_Begin;
+ exec->End = radeon_End;
+
+ vb.context = ctx;
+
+ ctx->Driver.FlushVertices = radeonFlushVertices;
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+
+ if (rmesa->radeonScreen->buffers) {
+ radeonVtxfmtValidate( ctx );
+ notify_noop();
+ }
+ else
+ radeon_noop_Install( ctx );
+}
+
+
+/*@}*/
+
+
diff --git a/src/mesa/drivers/dri/radeon/radeon_swtcl.c b/src/mesa/drivers/dri/radeon/radeon_swtcl.c
new file mode 100644
index 0000000000..926b1523d6
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_swtcl.c
@@ -0,0 +1,1332 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "colormac.h"
+#include "enums.h"
+#include "imports.h"
+#include "macros.h"
+
+#include "swrast_setup/swrast_setup.h"
+#include "math/m_translate.h"
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_imm_exec.h"
+#include "tnl/t_pipeline.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "radeon_swtcl.h"
+#include "radeon_tcl.h"
+
+/***********************************************************************
+ * Build render functions from dd templates *
+ ***********************************************************************/
+
+
+#define RADEON_XYZW_BIT 0x01
+#define RADEON_RGBA_BIT 0x02
+#define RADEON_SPEC_BIT 0x04
+#define RADEON_TEX0_BIT 0x08
+#define RADEON_TEX1_BIT 0x10
+#define RADEON_PTEX_BIT 0x20
+#define RADEON_MAX_SETUP 0x40
+
+static void flush_last_swtcl_prim( radeonContextPtr rmesa );
+static void flush_last_swtcl_prim_compat( radeonContextPtr rmesa );
+
+static struct {
+ void (*emit)( GLcontext *, GLuint, GLuint, void *, GLuint );
+ 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[RADEON_MAX_SETUP];
+
+
+#define TINY_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \
+ RADEON_CP_VC_FRMT_Z | \
+ RADEON_CP_VC_FRMT_PKCOLOR)
+
+#define NOTEX_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \
+ RADEON_CP_VC_FRMT_Z | \
+ RADEON_CP_VC_FRMT_W0 | \
+ RADEON_CP_VC_FRMT_PKCOLOR | \
+ RADEON_CP_VC_FRMT_PKSPEC)
+
+#define TEX0_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \
+ RADEON_CP_VC_FRMT_Z | \
+ RADEON_CP_VC_FRMT_W0 | \
+ RADEON_CP_VC_FRMT_PKCOLOR | \
+ RADEON_CP_VC_FRMT_PKSPEC | \
+ RADEON_CP_VC_FRMT_ST0)
+
+#define TEX1_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \
+ RADEON_CP_VC_FRMT_Z | \
+ RADEON_CP_VC_FRMT_W0 | \
+ RADEON_CP_VC_FRMT_PKCOLOR | \
+ RADEON_CP_VC_FRMT_PKSPEC | \
+ RADEON_CP_VC_FRMT_ST0 | \
+ RADEON_CP_VC_FRMT_ST1)
+
+#define PROJ_TEX1_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \
+ RADEON_CP_VC_FRMT_Z | \
+ RADEON_CP_VC_FRMT_W0 | \
+ RADEON_CP_VC_FRMT_PKCOLOR | \
+ RADEON_CP_VC_FRMT_PKSPEC | \
+ RADEON_CP_VC_FRMT_ST0 | \
+ RADEON_CP_VC_FRMT_Q0 | \
+ RADEON_CP_VC_FRMT_ST1 | \
+ RADEON_CP_VC_FRMT_Q1)
+
+#define TEX2_VERTEX_FORMAT 0
+#define TEX3_VERTEX_FORMAT 0
+#define PROJ_TEX3_VERTEX_FORMAT 0
+
+#define DO_XYZW (IND & RADEON_XYZW_BIT)
+#define DO_RGBA (IND & RADEON_RGBA_BIT)
+#define DO_SPEC (IND & RADEON_SPEC_BIT)
+#define DO_FOG (IND & RADEON_SPEC_BIT)
+#define DO_TEX0 (IND & RADEON_TEX0_BIT)
+#define DO_TEX1 (IND & RADEON_TEX1_BIT)
+#define DO_TEX2 0
+#define DO_TEX3 0
+#define DO_PTEX (IND & RADEON_PTEX_BIT)
+
+#define VERTEX radeonVertex
+#define VERTEX_COLOR radeon_color_t
+#define GET_VIEWPORT_MAT() 0
+#define GET_TEXSOURCE(n) n
+#define GET_VERTEX_FORMAT() RADEON_CONTEXT(ctx)->swtcl.vertex_format
+#define GET_VERTEX_STORE() RADEON_CONTEXT(ctx)->swtcl.verts
+#define GET_VERTEX_STRIDE_SHIFT() RADEON_CONTEXT(ctx)->swtcl.vertex_stride_shift
+#define GET_UBYTE_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteColor
+#define GET_UBYTE_SPEC_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteSecondaryColor
+
+#define HAVE_HW_VIEWPORT 1
+/* Tiny vertices don't seem to work atm - haven't looked into why.
+ */
+#define HAVE_HW_DIVIDE (IND & ~(RADEON_XYZW_BIT|RADEON_RGBA_BIT))
+#define HAVE_TINY_VERTICES 1
+#define HAVE_RGBA_COLOR 1
+#define HAVE_NOTEX_VERTICES 1
+#define HAVE_TEX0_VERTICES 1
+#define HAVE_TEX1_VERTICES 1
+#define HAVE_TEX2_VERTICES 0
+#define HAVE_TEX3_VERTICES 0
+#define HAVE_PTEX_VERTICES 1
+
+#define CHECK_HW_DIVIDE (!(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE| \
+ DD_TRI_UNFILLED)))
+
+#define IMPORT_QUALIFIER
+#define IMPORT_FLOAT_COLORS radeon_import_float_colors
+#define IMPORT_FLOAT_SPEC_COLORS radeon_import_float_spec_colors
+
+#define INTERP_VERTEX setup_tab[RADEON_CONTEXT(ctx)->swtcl.SetupIndex].interp
+#define COPY_PV_VERTEX setup_tab[RADEON_CONTEXT(ctx)->swtcl.SetupIndex].copy_pv
+
+
+/***********************************************************************
+ * Generate pv-copying and translation functions *
+ ***********************************************************************/
+
+#define TAG(x) radeon_##x
+#define IND ~0
+#include "tnl_dd/t_dd_vb.c"
+#undef IND
+
+
+/***********************************************************************
+ * Generate vertex emit and interp functions *
+ ***********************************************************************/
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT)
+#define TAG(x) x##_wg
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT)
+#define TAG(x) x##_wgt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_PTEX_BIT)
+#define TAG(x) x##_wgpt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT)
+#define TAG(x) x##_wgt0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT|\
+ RADEON_PTEX_BIT)
+#define TAG(x) x##_wgpt0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT)
+#define TAG(x) x##_wgfs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\
+ RADEON_TEX0_BIT)
+#define TAG(x) x##_wgfst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\
+ RADEON_TEX0_BIT|RADEON_PTEX_BIT)
+#define TAG(x) x##_wgfspt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\
+ RADEON_TEX0_BIT|RADEON_TEX1_BIT)
+#define TAG(x) x##_wgfst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\
+ RADEON_TEX0_BIT|RADEON_TEX1_BIT|RADEON_PTEX_BIT)
+#define TAG(x) x##_wgfspt0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+
+/***********************************************************************
+ * Initialization
+ ***********************************************************************/
+
+static void init_setup_tab( void )
+{
+ init_wg();
+ init_wgt0();
+ init_wgpt0();
+ init_wgt0t1();
+ init_wgpt0t1();
+ init_wgfs();
+ init_wgfst0();
+ init_wgfspt0();
+ init_wgfst0t1();
+ init_wgfspt0t1();
+}
+
+
+
+void radeonPrintSetupFlags(char *msg, GLuint flags )
+{
+ fprintf(stderr, "%s(%x): %s%s%s%s%s%s\n",
+ msg,
+ (int)flags,
+ (flags & RADEON_XYZW_BIT) ? " xyzw," : "",
+ (flags & RADEON_RGBA_BIT) ? " rgba," : "",
+ (flags & RADEON_SPEC_BIT) ? " spec/fog," : "",
+ (flags & RADEON_TEX0_BIT) ? " tex-0," : "",
+ (flags & RADEON_TEX1_BIT) ? " tex-1," : "",
+ (flags & RADEON_PTEX_BIT) ? " proj-tex," : "");
+}
+
+
+static void radeonRenderStart( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (!setup_tab[rmesa->swtcl.SetupIndex].check_tex_sizes(ctx)) {
+ GLuint ind = rmesa->swtcl.SetupIndex |= (RADEON_PTEX_BIT|RADEON_RGBA_BIT);
+
+ /* Projective textures are handled nicely; just have to change
+ * up to the new vertex format.
+ */
+ if (setup_tab[ind].vertex_format != rmesa->swtcl.vertex_format) {
+ RADEON_NEWPRIM(rmesa);
+ rmesa->swtcl.vertex_format = setup_tab[ind].vertex_format;
+ rmesa->swtcl.vertex_size = setup_tab[ind].vertex_size;
+ rmesa->swtcl.vertex_stride_shift = setup_tab[ind].vertex_stride_shift;
+ }
+
+ if (!(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+ tnl->Driver.Render.Interp = setup_tab[rmesa->swtcl.SetupIndex].interp;
+ tnl->Driver.Render.CopyPV = setup_tab[rmesa->swtcl.SetupIndex].copy_pv;
+ }
+ }
+
+ if (rmesa->dma.flush != 0 &&
+ rmesa->dma.flush != flush_last_swtcl_prim_compat &&
+ rmesa->dma.flush != flush_last_swtcl_prim)
+ rmesa->dma.flush( rmesa );
+}
+
+
+void radeonBuildVertices( GLcontext *ctx, GLuint start, GLuint count,
+ GLuint newinputs )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ GLubyte *v = ((GLubyte *)rmesa->swtcl.verts +
+ (start << rmesa->swtcl.vertex_stride_shift));
+ GLuint stride = 1 << rmesa->swtcl.vertex_stride_shift;
+
+ newinputs |= rmesa->swtcl.SetupNewInputs;
+ rmesa->swtcl.SetupNewInputs = 0;
+
+ if (!newinputs)
+ return;
+
+ setup_tab[rmesa->swtcl.SetupIndex].emit( ctx, start, count, v, stride );
+}
+
+void radeonChooseVertexState( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint ind = (RADEON_XYZW_BIT | RADEON_RGBA_BIT);
+
+ if (!rmesa->TclFallback || rmesa->Fallback)
+ return;
+
+ if (ctx->Fog.Enabled || (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR))
+ ind |= RADEON_SPEC_BIT;
+
+ if (ctx->Texture._EnabledUnits & 0x2)
+ /* unit 1 enabled */
+ ind |= RADEON_TEX0_BIT|RADEON_TEX1_BIT;
+ else if (ctx->Texture._EnabledUnits & 0x1)
+ /* unit 0 enabled */
+ ind |= RADEON_TEX0_BIT;
+
+ rmesa->swtcl.SetupIndex = ind;
+
+ if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) {
+ tnl->Driver.Render.Interp = radeon_interp_extras;
+ tnl->Driver.Render.CopyPV = radeon_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 != rmesa->swtcl.vertex_format) {
+ RADEON_NEWPRIM(rmesa);
+ rmesa->swtcl.vertex_format = setup_tab[ind].vertex_format;
+ rmesa->swtcl.vertex_size = setup_tab[ind].vertex_size;
+ rmesa->swtcl.vertex_stride_shift = setup_tab[ind].vertex_stride_shift;
+ }
+
+ {
+ GLuint se_coord_fmt, needproj;
+
+ /* HW perspective divide is a win, but tiny vertex formats are a
+ * bigger one.
+ */
+ if (setup_tab[ind].vertex_format == TINY_VERTEX_FORMAT ||
+ (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+ needproj = GL_TRUE;
+ se_coord_fmt = (RADEON_VTX_XY_PRE_MULT_1_OVER_W0 |
+ RADEON_VTX_Z_PRE_MULT_1_OVER_W0 |
+ RADEON_TEX1_W_ROUTING_USE_Q1);
+ }
+ else {
+ needproj = GL_FALSE;
+ se_coord_fmt = (RADEON_VTX_W0_IS_NOT_1_OVER_W0 |
+ RADEON_TEX1_W_ROUTING_USE_Q1);
+ }
+
+ if ( se_coord_fmt != rmesa->hw.set.cmd[SET_SE_COORDFMT] ) {
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_COORDFMT] = se_coord_fmt;
+ }
+ _tnl_need_projected_coords( ctx, needproj );
+ }
+}
+
+
+/* Flush vertices in the current dma region.
+ */
+static void flush_last_swtcl_prim( radeonContextPtr rmesa )
+{
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ rmesa->dma.flush = 0;
+
+ if (rmesa->dma.current.buf) {
+ struct radeon_dma_region *current = &rmesa->dma.current;
+ GLuint current_offset = (rmesa->radeonScreen->agp_buffer_offset +
+ current->buf->buf->idx * RADEON_BUFFER_SIZE +
+ current->start);
+
+ assert (!(rmesa->swtcl.hw_primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND));
+
+ assert (current->start +
+ rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 ==
+ current->ptr);
+
+ if (rmesa->dma.current.start != rmesa->dma.current.ptr) {
+ radeonEmitVertexAOS( rmesa,
+ rmesa->swtcl.vertex_size,
+ current_offset);
+
+ radeonEmitVbufPrim( rmesa,
+ rmesa->swtcl.vertex_format,
+ rmesa->swtcl.hw_primitive,
+ rmesa->swtcl.numverts);
+ }
+
+ rmesa->swtcl.numverts = 0;
+ current->start = current->ptr;
+ }
+}
+
+
+static void flush_last_swtcl_prim_compat( radeonContextPtr rmesa )
+{
+ struct radeon_dma_region *current = &rmesa->dma.current;
+
+ if (RADEON_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s buf %p start %d ptr %d\n",
+ __FUNCTION__,
+ current->buf,
+ current->start,
+ current->ptr);
+
+ assert (!(rmesa->swtcl.hw_primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND));
+ assert (current->start +
+ rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 ==
+ current->ptr);
+ assert (current->start == 0);
+
+ rmesa->dma.flush = 0;
+
+ if (current->ptr && current->buf) {
+ assert (current->buf->refcount == 1);
+
+ radeonCompatEmitPrimitive( rmesa,
+ rmesa->swtcl.vertex_format,
+ rmesa->swtcl.hw_primitive,
+ rmesa->swtcl.numverts);
+
+ /* The buffer has been released:
+ */
+ FREE(current->buf);
+ current->buf = 0;
+ current->start = 0;
+ current->ptr = current->end;
+
+ }
+
+ rmesa->swtcl.numverts = 0;
+}
+
+
+/* Alloc space in the current dma region.
+ */
+static __inline void *radeonAllocDmaLowVerts( radeonContextPtr rmesa,
+ int nverts, int vsize )
+{
+ GLuint bytes = vsize * nverts;
+
+ if ( rmesa->dma.current.ptr + bytes > rmesa->dma.current.end )
+ radeonRefillCurrentDmaRegion( rmesa );
+
+ if (!rmesa->dma.flush) {
+ rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ if (rmesa->dri.drmMinor == 1)
+ rmesa->dma.flush = flush_last_swtcl_prim_compat;
+ else
+ rmesa->dma.flush = flush_last_swtcl_prim;
+ }
+
+ assert( vsize == rmesa->swtcl.vertex_size * 4 );
+ assert( rmesa->dma.flush == flush_last_swtcl_prim ||
+ rmesa->dma.flush == flush_last_swtcl_prim_compat);
+ assert (rmesa->dma.current.start +
+ rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 ==
+ rmesa->dma.current.ptr);
+
+
+ {
+ char *head = rmesa->dma.current.address + rmesa->dma.current.ptr;
+ rmesa->dma.current.ptr += bytes;
+ rmesa->swtcl.numverts += nverts;
+ return head;
+ }
+
+}
+
+
+
+
+void radeon_emit_contiguous_verts( GLcontext *ctx, GLuint start, GLuint count )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint vertex_size = rmesa->swtcl.vertex_size * 4;
+ CARD32 *dest = radeonAllocDmaLowVerts( rmesa, count-start, vertex_size );
+ setup_tab[rmesa->swtcl.SetupIndex].emit( ctx, start, count, dest,
+ vertex_size );
+}
+
+
+
+void radeon_emit_indexed_verts( GLcontext *ctx, GLuint start, GLuint count )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ radeonAllocDmaRegionVerts( rmesa,
+ &rmesa->swtcl.indexed_verts,
+ count - start,
+ rmesa->swtcl.vertex_size * 4,
+ 64);
+
+ setup_tab[rmesa->swtcl.SetupIndex].emit(
+ ctx, start, count,
+ rmesa->swtcl.indexed_verts.address + rmesa->swtcl.indexed_verts.start,
+ rmesa->swtcl.vertex_size * 4 );
+}
+
+
+/*
+ * Render unclipped vertex buffers by emitting vertices directly to
+ * dma buffers. Use strip/fan hardware primitives where possible.
+ * Try to simulate missing primitives with indexed vertices.
+ */
+#define HAVE_POINTS 1
+#define HAVE_LINES 1
+#define HAVE_LINE_STRIPS 1
+#define HAVE_TRIANGLES 1
+#define HAVE_TRI_STRIPS 1
+#define HAVE_TRI_STRIP_1 0
+#define HAVE_TRI_FANS 1
+#define HAVE_QUADS 0
+#define HAVE_QUAD_STRIPS 0
+#define HAVE_POLYGONS 0
+#define HAVE_ELTS 1
+
+static const GLuint hw_prim[GL_POLYGON+1] = {
+ RADEON_CP_VC_CNTL_PRIM_TYPE_POINT,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_LINE,
+ 0,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN,
+ 0,
+ 0,
+ 0
+};
+
+static __inline void radeonDmaPrimitive( radeonContextPtr rmesa, GLenum prim )
+{
+ RADEON_NEWPRIM( rmesa );
+ rmesa->swtcl.hw_primitive = hw_prim[prim];
+ assert(rmesa->dma.current.ptr == rmesa->dma.current.start);
+}
+
+static __inline void radeonEltPrimitive( radeonContextPtr rmesa, GLenum prim )
+{
+ RADEON_NEWPRIM( rmesa );
+ rmesa->swtcl.hw_primitive = hw_prim[prim] | RADEON_CP_VC_CNTL_PRIM_WALK_IND;
+}
+
+
+static void VERT_FALLBACK( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->Driver.Render.PrimitiveNotify( ctx, flags & PRIM_MODE_MASK );
+ tnl->Driver.Render.BuildVertices( ctx, start, count, ~0 );
+ tnl->Driver.Render.PrimTabVerts[flags&PRIM_MODE_MASK]( ctx, start, count, flags );
+ RADEON_CONTEXT(ctx)->swtcl.SetupNewInputs = VERT_BIT_CLIP;
+}
+
+static void ELT_FALLBACK( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->Driver.Render.PrimitiveNotify( ctx, flags & PRIM_MODE_MASK );
+ tnl->Driver.Render.BuildVertices( ctx, start, count, ~0 );
+ tnl->Driver.Render.PrimTabElts[flags&PRIM_MODE_MASK]( ctx, start, count, flags );
+ RADEON_CONTEXT(ctx)->swtcl.SetupNewInputs = VERT_BIT_CLIP;
+}
+
+
+#define LOCAL_VARS radeonContextPtr rmesa = RADEON_CONTEXT(ctx)
+#define ELTS_VARS GLushort *dest
+#define INIT( prim ) radeonDmaPrimitive( rmesa, prim )
+#define ELT_INIT(prim) radeonEltPrimitive( rmesa, prim )
+#define NEW_PRIMITIVE() RADEON_NEWPRIM( rmesa )
+#define NEW_BUFFER() radeonRefillCurrentDmaRegion( rmesa )
+#define GET_CURRENT_VB_MAX_VERTS() \
+ (((int)rmesa->dma.current.end - (int)rmesa->dma.current.ptr) / (rmesa->swtcl.vertex_size*4))
+#define GET_SUBSEQUENT_VB_MAX_VERTS() \
+ ((RADEON_BUFFER_SIZE) / (rmesa->swtcl.vertex_size*4))
+
+#if RADEON_OLD_PACKETS
+# define GET_CURRENT_VB_MAX_ELTS() \
+ ((RADEON_CMD_BUF_SZ - (rmesa->store.cmd_used + 24)) / 2)
+#else
+# define GET_CURRENT_VB_MAX_ELTS() \
+ ((RADEON_CMD_BUF_SZ - (rmesa->store.cmd_used + 16)) / 2)
+#endif
+#define GET_SUBSEQUENT_VB_MAX_ELTS() \
+ ((RADEON_CMD_BUF_SZ - 1024) / 2)
+
+
+
+/* How do you extend an existing primitive?
+ */
+#define ALLOC_ELTS(nr) \
+do { \
+ if (rmesa->dma.flush == radeonFlushElts && \
+ rmesa->store.cmd_used + nr*2 < RADEON_CMD_BUF_SZ) { \
+ \
+ dest = (GLushort *)(rmesa->store.cmd_buf + \
+ rmesa->store.cmd_used); \
+ rmesa->store.cmd_used += nr*2; \
+ } \
+ else { \
+ if (rmesa->dma.flush) { \
+ rmesa->dma.flush( rmesa ); \
+ } \
+ \
+ radeonEmitVertexAOS( rmesa, \
+ rmesa->swtcl.vertex_size, \
+ (rmesa->radeonScreen->agp_buffer_offset + \
+ rmesa->swtcl.indexed_verts.buf->buf->idx * \
+ RADEON_BUFFER_SIZE + \
+ rmesa->swtcl.indexed_verts.start)); \
+ \
+ dest = radeonAllocEltsOpenEnded( rmesa, \
+ rmesa->swtcl.vertex_format, \
+ rmesa->swtcl.hw_primitive, \
+ nr ); \
+ } \
+} while (0)
+
+#define ALLOC_ELTS_NEW_PRIMITIVE(nr) ALLOC_ELTS( nr )
+
+#ifdef MESA_BIG_ENDIAN
+/* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */
+#define EMIT_ELT(offset, x) do { \
+ int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \
+ GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \
+ (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0)
+#else
+#define EMIT_ELT(offset, x) (dest)[offset] = (GLushort) (x)
+#endif
+#define EMIT_TWO_ELTS(offset, x, y) *(GLuint *)(dest+offset) = ((y)<<16)|(x);
+#define INCR_ELTS( nr ) dest += nr
+#define RELEASE_ELT_VERTS() \
+ radeonReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts, __FUNCTION__ )
+#define EMIT_VERTS( ctx, j, nr ) \
+ radeon_emit_contiguous_verts(ctx, j, (j)+(nr))
+#define EMIT_INDEXED_VERTS( ctx, start, count ) \
+ radeon_emit_indexed_verts( ctx, start, count )
+
+
+#define TAG(x) radeon_dma_##x
+#include "tnl_dd/t_dd_dmatmp.h"
+
+
+/**********************************************************************/
+/* Render pipeline stage */
+/**********************************************************************/
+
+
+static GLboolean radeon_run_render( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i, length, flags = 0;
+ render_func *tab = TAG(render_tab_verts);
+
+ if (rmesa->swtcl.indexed_verts.buf && (!VB->Elts || stage->changed_inputs))
+ RELEASE_ELT_VERTS();
+
+ if (VB->ClipOrMask || /* No clipping */
+ rmesa->swtcl.RenderIndex != 0 || /* No per-vertex manipulations */
+ ctx->Line.StippleFlag) /* GH: THIS IS A HACK!!! */
+ return GL_TRUE;
+
+ if (rmesa->dri.drmMinor < 3) {
+ /* drm 1.1 doesn't support vertex primitives starting in the
+ * middle of a buffer. It doesn't support sane indexed vertices
+ * either. drm 1.2 fixes both of these problems, but we don't have a
+ * compatibility layer to that version yet.
+ */
+ return GL_TRUE;
+ }
+
+ tnl->Driver.Render.Start( ctx );
+
+ if (VB->Elts) {
+ tab = TAG(render_tab_elts);
+ if (!rmesa->swtcl.indexed_verts.buf)
+ if (!TAG(emit_elt_verts)(ctx, 0, VB->Count))
+ return GL_TRUE; /* too many vertices */
+ }
+
+ for (i = 0 ; !(flags & PRIM_LAST) ; i += length)
+ {
+ flags = VB->Primitive[i];
+ length = VB->PrimitiveLength[i];
+
+ if (RADEON_DEBUG & DEBUG_PRIMS)
+ fprintf(stderr, "radeon_render.c: prim %s %d..%d\n",
+ _mesa_lookup_enum_by_nr(flags & PRIM_MODE_MASK),
+ i, i+length);
+
+ if (length)
+ tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags );
+ }
+
+ tnl->Driver.Render.Finish( ctx );
+
+ return GL_FALSE; /* finished the pipe */
+}
+
+
+
+static void radeon_check_render( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ GLuint inputs = VERT_BIT_POS | VERT_BIT_CLIP | VERT_BIT_COLOR0;
+
+ if (ctx->RenderMode == GL_RENDER) {
+ if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)
+ inputs |= VERT_BIT_COLOR1;
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled)
+ inputs |= VERT_BIT_TEX0;
+
+ if (ctx->Texture.Unit[1]._ReallyEnabled)
+ inputs |= VERT_BIT_TEX1;
+
+ if (ctx->Fog.Enabled)
+ inputs |= VERT_BIT_FOG;
+ }
+
+ stage->inputs = inputs;
+}
+
+
+static void dtr( struct gl_pipeline_stage *stage )
+{
+ (void)stage;
+}
+
+
+const struct gl_pipeline_stage _radeon_render_stage =
+{
+ "radeon render",
+ (_DD_NEW_SEPARATE_SPECULAR |
+ _NEW_TEXTURE|
+ _NEW_FOG|
+ _NEW_RENDERMODE), /* re-check (new inputs) */
+ 0, /* re-run (always runs) */
+ GL_TRUE, /* active */
+ 0, 0, /* inputs (set in check_render), outputs */
+ 0, 0, /* changed_inputs, private */
+ dtr, /* destructor */
+ radeon_check_render, /* check - initially set to alloc data */
+ radeon_run_render /* run */
+};
+
+
+/**************************************************************************/
+
+/* Radeon texture rectangle expects coords in 0..1 range, not 0..dimension
+ * as in the extension spec. Need to translate here.
+ *
+ * Note that swrast expects 0..dimension, so if a fallback is active,
+ * don't do anything. (Maybe need to configure swrast to match hw)
+ */
+struct texrect_stage_data {
+ GLvector4f texcoord[MAX_TEXTURE_UNITS];
+};
+
+#define TEXRECT_STAGE_DATA(stage) ((struct texrect_stage_data *)stage->privatePtr)
+
+
+static GLboolean run_texrect_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct texrect_stage_data *store = TEXRECT_STAGE_DATA(stage);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i;
+
+ if (rmesa->Fallback)
+ return GL_TRUE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ if (!(ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_RECT_BIT))
+ continue;
+
+ if (stage->changed_inputs & VERT_BIT_TEX(i)) {
+ struct gl_texture_object *texObj = ctx->Texture.Unit[i].CurrentRect;
+ struct gl_texture_image *texImage = texObj->Image[texObj->BaseLevel];
+ const GLfloat iw = 1.0/texImage->Width;
+ const GLfloat ih = 1.0/texImage->Height;
+ GLfloat *in = (GLfloat *)VB->TexCoordPtr[i]->data;
+ GLint instride = VB->TexCoordPtr[i]->stride;
+ GLfloat (*out)[4] = store->texcoord[i].data;
+ GLint j;
+
+ for (j = 0 ; j < VB->Count ; j++) {
+ out[j][0] = in[0] * iw;
+ out[j][1] = in[1] * ih;
+ in = (GLfloat *)((GLubyte *)in + instride);
+ }
+ }
+
+ VB->TexCoordPtr[i] = &store->texcoord[i];
+ }
+
+ return GL_TRUE;
+}
+
+
+/* Called the first time stage->run() is invoked.
+ */
+static GLboolean alloc_texrect_data( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct texrect_stage_data *store;
+ GLuint i;
+
+ stage->privatePtr = CALLOC(sizeof(*store));
+ store = TEXRECT_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 );
+
+ /* Now run the stage.
+ */
+ stage->run = run_texrect_stage;
+ return stage->run( ctx, stage );
+}
+
+
+static void check_texrect( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ GLuint flags = 0;
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_RECT_BIT)
+ flags |= VERT_BIT_TEX0;
+
+ if (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_RECT_BIT)
+ flags |= VERT_BIT_TEX1;
+
+ stage->inputs = flags;
+ stage->outputs = flags;
+ stage->active = (flags != 0);
+}
+
+
+static void free_texrect_data( struct gl_pipeline_stage *stage )
+{
+ struct texrect_stage_data *store = TEXRECT_STAGE_DATA(stage);
+ GLuint i;
+
+ if (store) {
+ for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
+ if (store->texcoord[i].data)
+ _mesa_vector4f_free( &store->texcoord[i] );
+ FREE( store );
+ stage->privatePtr = 0;
+ }
+}
+
+
+const struct gl_pipeline_stage _radeon_texrect_stage =
+{
+ "radeon texrect stage", /* name */
+ _NEW_TEXTURE, /* check_state */
+ _NEW_TEXTURE, /* run_state */
+ GL_TRUE, /* active? */
+ 0, /* inputs */
+ 0, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* private data */
+ free_texrect_data, /* destructor */
+ check_texrect, /* check */
+ alloc_texrect_data, /* run -- initially set to init */
+};
+
+
+/**************************************************************************/
+
+
+static const GLuint reduced_hw_prim[GL_POLYGON+1] = {
+ RADEON_CP_VC_CNTL_PRIM_TYPE_POINT,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_LINE,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_LINE,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_LINE,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST,
+ RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST
+};
+
+static void radeonRasterPrimitive( GLcontext *ctx, GLuint hwprim );
+static void radeonRenderPrimitive( GLcontext *ctx, GLenum prim );
+static void radeonResetLineStipple( GLcontext *ctx );
+
+
+/***********************************************************************
+ * Emit primitives as inline vertices *
+ ***********************************************************************/
+
+#undef LOCAL_VARS
+#define CTX_ARG radeonContextPtr rmesa
+#define CTX_ARG2 rmesa
+#define GET_VERTEX_DWORDS() rmesa->swtcl.vertex_size
+#define ALLOC_VERTS( n, size ) radeonAllocDmaLowVerts( rmesa, n, size * 4 )
+#undef LOCAL_VARS
+#define LOCAL_VARS \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ const GLuint shift = rmesa->swtcl.vertex_stride_shift; \
+ const char *radeonverts = (char *)rmesa->swtcl.verts;
+#define VERT(x) (radeonVertex *)(radeonverts + (x << shift))
+#define VERTEX radeonVertex
+#undef TAG
+#define TAG(x) radeon_##x
+#include "tnl_dd/t_dd_triemit.h"
+
+
+/***********************************************************************
+ * Macros for t_dd_tritmp.h to draw basic primitives *
+ ***********************************************************************/
+
+#define QUAD( a, b, c, d ) radeon_quad( rmesa, a, b, c, d )
+#define TRI( a, b, c ) radeon_triangle( rmesa, a, b, c )
+#define LINE( a, b ) radeon_line( rmesa, a, b )
+#define POINT( a ) radeon_point( rmesa, a )
+
+/***********************************************************************
+ * Build render functions from dd templates *
+ ***********************************************************************/
+
+#define RADEON_TWOSIDE_BIT 0x01
+#define RADEON_UNFILLED_BIT 0x02
+#define RADEON_OFFSET_BIT 0x04 /* drmMinor == 1 */
+#define RADEON_MAX_TRIFUNC 0x08
+
+
+static struct {
+ points_func points;
+ line_func line;
+ triangle_func triangle;
+ quad_func quad;
+} rast_tab[RADEON_MAX_TRIFUNC];
+
+
+#define DO_FALLBACK 0
+#define DO_OFFSET (IND & RADEON_OFFSET_BIT)
+#define DO_UNFILLED (IND & RADEON_UNFILLED_BIT)
+#define DO_TWOSIDE (IND & RADEON_TWOSIDE_BIT)
+#define DO_FLAT 0
+#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 1
+#define HAVE_INDEX 0
+#define HAVE_BACK_COLORS 0
+#define HAVE_HW_FLATSHADE 1
+#define TAB rast_tab
+
+#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) (rmesa->swtcl.verts + (e<<rmesa->swtcl.vertex_stride_shift))
+
+#define VERT_SET_RGBA( v, c ) v->ui[coloroffset] = LE32_TO_CPU(*(GLuint *)c)
+#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset]
+#define VERT_SAVE_RGBA( idx ) color[idx] = CPU_TO_LE32(v[idx]->ui[coloroffset])
+#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = LE32_TO_CPU(color[idx])
+
+#define VERT_SET_SPEC( v0, c ) if (havespec) { \
+ v0->v.specular.red = (c)[0]; \
+ v0->v.specular.green = (c)[1]; \
+ v0->v.specular.blue = (c)[2]; }
+#define VERT_COPY_SPEC( v0, v1 ) if (havespec) { \
+ v0->v.specular.red = v1->v.specular.red; \
+ v0->v.specular.green = v1->v.specular.green; \
+ v0->v.specular.blue = v1->v.specular.blue; }
+#define VERT_SAVE_SPEC( idx ) if (havespec) spec[idx] = CPU_TO_LE32(v[idx]->ui[5])
+#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[5] = LE32_TO_CPU(spec[idx])
+
+#undef LOCAL_VARS
+#undef TAG
+#undef INIT
+
+#define LOCAL_VARS(n) \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ GLuint color[n], spec[n]; \
+ GLuint coloroffset = (rmesa->swtcl.vertex_size == 4 ? 3 : 4); \
+ GLboolean havespec = (rmesa->swtcl.vertex_size > 4); \
+ (void) color; (void) spec; (void) coloroffset; (void) havespec;
+
+/***********************************************************************
+ * Helpers for rendering unfilled primitives *
+ ***********************************************************************/
+
+#define RASTERIZE(x) radeonRasterPrimitive( ctx, reduced_hw_prim[x] )
+#define RENDER_PRIMITIVE rmesa->swtcl.render_primitive
+#undef TAG
+#define TAG(x) x
+#include "tnl_dd/t_dd_unfilled.h"
+#undef IND
+
+
+/***********************************************************************
+ * Generate GL render functions *
+ ***********************************************************************/
+
+
+#define IND (0)
+#define TAG(x) x
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (RADEON_TWOSIDE_BIT)
+#define TAG(x) x##_twoside
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (RADEON_UNFILLED_BIT)
+#define TAG(x) x##_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (RADEON_TWOSIDE_BIT|RADEON_UNFILLED_BIT)
+#define TAG(x) x##_twoside_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (RADEON_OFFSET_BIT)
+#define TAG(x) x##_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (RADEON_TWOSIDE_BIT|RADEON_OFFSET_BIT)
+#define TAG(x) x##_twoside_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (RADEON_UNFILLED_BIT|RADEON_OFFSET_BIT)
+#define TAG(x) x##_unfilled_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (RADEON_TWOSIDE_BIT|RADEON_UNFILLED_BIT|RADEON_OFFSET_BIT)
+#define TAG(x) x##_twoside_unfilled_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+
+static void init_rast_tab( void )
+{
+ init();
+ init_twoside();
+ init_unfilled();
+ init_twoside_unfilled();
+ init_offset();
+ init_twoside_offset();
+ init_unfilled_offset();
+ init_twoside_unfilled_offset();
+}
+
+/**********************************************************************/
+/* Render unclipped begin/end objects */
+/**********************************************************************/
+
+#define VERT(x) (radeonVertex *)(radeonverts + (x << shift))
+#define RENDER_POINTS( start, count ) \
+ for ( ; start < count ; start++) \
+ radeon_point( rmesa, VERT(start) )
+#define RENDER_LINE( v0, v1 ) \
+ radeon_line( rmesa, VERT(v0), VERT(v1) )
+#define RENDER_TRI( v0, v1, v2 ) \
+ radeon_triangle( rmesa, VERT(v0), VERT(v1), VERT(v2) )
+#define RENDER_QUAD( v0, v1, v2, v3 ) \
+ radeon_quad( rmesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) )
+#undef INIT
+#define INIT(x) do { \
+ radeonRenderPrimitive( ctx, x ); \
+} while (0)
+#undef LOCAL_VARS
+#define LOCAL_VARS \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ const GLuint shift = rmesa->swtcl.vertex_stride_shift; \
+ const char *radeonverts = (char *)rmesa->swtcl.verts; \
+ const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \
+ const GLboolean stipple = ctx->Line.StippleFlag; \
+ (void) elt; (void) stipple;
+#define RESET_STIPPLE if ( stipple ) radeonResetLineStipple( ctx );
+#define RESET_OCCLUSION
+#define PRESERVE_VB_DEFS
+#define ELT(x) (x)
+#define TAG(x) radeon_##x##_verts
+#include "tnl/t_vb_rendertmp.h"
+#undef ELT
+#undef TAG
+#define TAG(x) radeon_##x##_elts
+#define ELT(x) elt[x]
+#include "tnl/t_vb_rendertmp.h"
+
+
+
+/**********************************************************************/
+/* Choose render functions */
+/**********************************************************************/
+
+void radeonChooseRenderState( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint index = 0;
+ GLuint flags = ctx->_TriangleCaps;
+
+ if (!rmesa->TclFallback || rmesa->Fallback)
+ return;
+
+ if (flags & DD_TRI_LIGHT_TWOSIDE) index |= RADEON_TWOSIDE_BIT;
+ if (flags & DD_TRI_UNFILLED) index |= RADEON_UNFILLED_BIT;
+ if ((flags & DD_TRI_OFFSET) &&
+ rmesa->dri.drmMinor == 1) index |= RADEON_OFFSET_BIT;
+
+ if (index != rmesa->swtcl.RenderIndex) {
+ tnl->Driver.Render.Points = rast_tab[index].points;
+ tnl->Driver.Render.Line = rast_tab[index].line;
+ tnl->Driver.Render.ClippedLine = 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 = radeon_render_tab_verts;
+ tnl->Driver.Render.PrimTabElts = radeon_render_tab_elts;
+ tnl->Driver.Render.ClippedPolygon = radeon_fast_clipped_poly;
+ } else {
+ tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
+ tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
+ tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon;
+ }
+
+ rmesa->swtcl.RenderIndex = index;
+ }
+}
+
+
+/**********************************************************************/
+/* High level hooks for t_vb_render.c */
+/**********************************************************************/
+
+
+static void radeonRasterPrimitive( GLcontext *ctx, GLuint hwprim )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (rmesa->swtcl.hw_primitive != hwprim) {
+ RADEON_NEWPRIM( rmesa );
+ rmesa->swtcl.hw_primitive = hwprim;
+ }
+}
+
+static void radeonRenderPrimitive( GLcontext *ctx, GLenum prim )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ rmesa->swtcl.render_primitive = prim;
+ if (prim < GL_TRIANGLES || !(ctx->_TriangleCaps & DD_TRI_UNFILLED))
+ radeonRasterPrimitive( ctx, reduced_hw_prim[prim] );
+}
+
+static void radeonRenderFinish( GLcontext *ctx )
+{
+}
+
+static void radeonResetLineStipple( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ RADEON_STATECHANGE( rmesa, lin );
+}
+
+
+/**********************************************************************/
+/* Transition to/from hardware rasterization. */
+/**********************************************************************/
+
+static const char * const fallbackStrings[] = {
+ "Texture mode",
+ "glDrawBuffer(GL_FRONT_AND_BACK)",
+ "glEnable(GL_STENCIL) without hw stencil buffer",
+ "glRenderMode(selection or feedback)",
+ "glBlendEquation",
+ "glBlendFunc",
+ "RADEON_NO_RAST",
+ "Mixing GL_CLAMP_TO_BORDER and GL_CLAMP (or GL_MIRROR_CLAMP_ATI)"
+};
+
+
+static const char *getFallbackString(GLuint bit)
+{
+ int i = 0;
+ while (bit > 1) {
+ i++;
+ bit >>= 1;
+ }
+ return fallbackStrings[i];
+}
+
+
+void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint oldfallback = rmesa->Fallback;
+
+ if (mode) {
+ rmesa->Fallback |= bit;
+ if (oldfallback == 0) {
+ RADEON_FIREVERTICES( rmesa );
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_RASTER, GL_TRUE );
+ _swsetup_Wakeup( ctx );
+ _tnl_need_projected_coords( ctx, GL_TRUE );
+ rmesa->swtcl.RenderIndex = ~0;
+ if (RADEON_DEBUG & DEBUG_FALLBACKS) {
+ fprintf(stderr, "Radeon begin rasterization fallback: 0x%x %s\n",
+ bit, getFallbackString(bit));
+ }
+ }
+ }
+ else {
+ rmesa->Fallback &= ~bit;
+ if (oldfallback == bit) {
+ _swrast_flush( ctx );
+ tnl->Driver.Render.Start = radeonRenderStart;
+ tnl->Driver.Render.PrimitiveNotify = radeonRenderPrimitive;
+ tnl->Driver.Render.Finish = radeonRenderFinish;
+ tnl->Driver.Render.BuildVertices = radeonBuildVertices;
+ tnl->Driver.Render.ResetLineStipple = radeonResetLineStipple;
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_RASTER, GL_FALSE );
+ if (rmesa->TclFallback) {
+ /* These are already done if rmesa->TclFallback goes to
+ * zero above. But not if it doesn't (RADEON_NO_TCL for
+ * example?)
+ */
+ radeonChooseVertexState( ctx );
+ radeonChooseRenderState( ctx );
+ }
+ if (RADEON_DEBUG & DEBUG_FALLBACKS) {
+ fprintf(stderr, "Radeon end rasterization fallback: 0x%x %s\n",
+ bit, getFallbackString(bit));
+ }
+ }
+ }
+}
+
+
+void radeonFlushVertices( GLcontext *ctx, GLuint flags )
+{
+ _tnl_flush_vertices( ctx, flags );
+
+ if (flags & FLUSH_STORED_VERTICES)
+ RADEON_NEWPRIM( RADEON_CONTEXT( ctx ) );
+}
+
+/**********************************************************************/
+/* Initialization. */
+/**********************************************************************/
+
+void radeonInitSwtcl( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint size = TNL_CONTEXT(ctx)->vb.Size;
+ static int firsttime = 1;
+
+ if (firsttime) {
+ init_rast_tab();
+ init_setup_tab();
+ firsttime = 0;
+ }
+
+ tnl->Driver.Render.Start = radeonRenderStart;
+ tnl->Driver.Render.Finish = radeonRenderFinish;
+ tnl->Driver.Render.PrimitiveNotify = radeonRenderPrimitive;
+ tnl->Driver.Render.ResetLineStipple = radeonResetLineStipple;
+ tnl->Driver.Render.BuildVertices = radeonBuildVertices;
+
+ rmesa->swtcl.verts = ALIGN_MALLOC( size * 16 * 4, 32 );
+ rmesa->swtcl.RenderIndex = ~0;
+ rmesa->swtcl.render_primitive = GL_TRIANGLES;
+ rmesa->swtcl.hw_primitive = 0;
+}
+
+
+void radeonDestroySwtcl( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (rmesa->swtcl.indexed_verts.buf)
+ radeonReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts,
+ __FUNCTION__ );
+
+ if (rmesa->swtcl.verts) {
+ ALIGN_FREE(rmesa->swtcl.verts);
+ rmesa->swtcl.verts = 0;
+ }
+
+ if (rmesa->UbyteSecondaryColor.Ptr) {
+ ALIGN_FREE(rmesa->UbyteSecondaryColor.Ptr);
+ rmesa->UbyteSecondaryColor.Ptr = 0;
+ }
+
+ if (rmesa->UbyteColor.Ptr) {
+ ALIGN_FREE(rmesa->UbyteColor.Ptr);
+ rmesa->UbyteColor.Ptr = 0;
+ }
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_swtcl.h b/src/mesa/drivers/dri/radeon/radeon_swtcl.h
new file mode 100644
index 0000000000..c45e711c0b
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_swtcl.h
@@ -0,0 +1,77 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef __RADEON_TRIS_H__
+#define __RADEON_TRIS_H__
+
+#include "mtypes.h"
+#include "swrast/swrast.h"
+#include "radeon_context.h"
+
+extern void radeonInitSwtcl( GLcontext *ctx );
+extern void radeonDestroySwtcl( GLcontext *ctx );
+
+extern void radeonFlushVertices( GLcontext *ctx, GLuint flags );
+extern void radeonChooseRenderState( GLcontext *ctx );
+extern void radeonChooseVertexState( GLcontext *ctx );
+
+extern void radeonCheckTexSizes( GLcontext *ctx );
+
+extern void radeonBuildVertices( GLcontext *ctx, GLuint start, GLuint count,
+ GLuint newinputs );
+
+extern void radeonPrintSetupFlags(char *msg, GLuint flags );
+
+
+extern void radeon_emit_contiguous_verts( GLcontext *ctx,
+ GLuint start,
+ GLuint count );
+
+extern void radeon_emit_indexed_verts( GLcontext *ctx,
+ GLuint start,
+ GLuint count );
+
+extern void radeon_translate_vertex( GLcontext *ctx,
+ const radeonVertex *src,
+ SWvertex *dst );
+
+extern void radeon_print_vertex( GLcontext *ctx, const radeonVertex *v );
+
+extern void radeon_import_float_colors( GLcontext *ctx );
+extern void radeon_import_float_spec_colors( GLcontext *ctx );
+
+
+
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_tcl.c b/src/mesa/drivers/dri/radeon/radeon_tcl.c
new file mode 100644
index 0000000000..651194a804
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_tcl.c
@@ -0,0 +1,527 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Austin, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "light.h"
+#include "mtypes.h"
+#include "enums.h"
+
+#include "array_cache/acache.h"
+#include "tnl/tnl.h"
+#include "tnl/t_pipeline.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_tex.h"
+#include "radeon_tcl.h"
+#include "radeon_swtcl.h"
+#include "radeon_maos.h"
+
+
+
+/*
+ * Render unclipped vertex buffers by emitting vertices directly to
+ * dma buffers. Use strip/fan hardware primitives where possible.
+ * Try to simulate missing primitives with indexed vertices.
+ */
+#define HAVE_POINTS 1
+#define HAVE_LINES 1
+#define HAVE_LINE_LOOP 0
+#define HAVE_LINE_STRIPS 1
+#define HAVE_TRIANGLES 1
+#define HAVE_TRI_STRIPS 1
+#define HAVE_TRI_STRIP_1 0
+#define HAVE_TRI_FANS 1
+#define HAVE_QUADS 0
+#define HAVE_QUAD_STRIPS 0
+#define HAVE_POLYGONS 1
+#define HAVE_ELTS 1
+
+
+#define HW_POINTS RADEON_CP_VC_CNTL_PRIM_TYPE_POINT
+#define HW_LINES RADEON_CP_VC_CNTL_PRIM_TYPE_LINE
+#define HW_LINE_LOOP 0
+#define HW_LINE_STRIP RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP
+#define HW_TRIANGLES RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST
+#define HW_TRIANGLE_STRIP_0 RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP
+#define HW_TRIANGLE_STRIP_1 0
+#define HW_TRIANGLE_FAN RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN
+#define HW_QUADS 0
+#define HW_QUAD_STRIP 0
+#define HW_POLYGON RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN
+
+
+static GLboolean discrete_prim[0x10] = {
+ 0, /* 0 none */
+ 1, /* 1 points */
+ 1, /* 2 lines */
+ 0, /* 3 line_strip */
+ 1, /* 4 tri_list */
+ 0, /* 5 tri_fan */
+ 0, /* 6 tri_type2 */
+ 1, /* 7 rect list (unused) */
+ 1, /* 8 3vert point */
+ 1, /* 9 3vert line */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+
+#define LOCAL_VARS radeonContextPtr rmesa = RADEON_CONTEXT(ctx)
+#define ELT_TYPE GLushort
+
+#define ELT_INIT(prim, hw_prim) \
+ radeonTclPrimitive( ctx, prim, hw_prim | RADEON_CP_VC_CNTL_PRIM_WALK_IND )
+
+#define GET_MESA_ELTS() rmesa->tcl.Elts
+
+
+/* Don't really know how many elts will fit in what's left of cmdbuf,
+ * as there is state to emit, etc:
+ */
+
+/* Testing on isosurf shows a maximum around here. Don't know if it's
+ * the card or driver or kernel module that is causing the behaviour.
+ */
+#define GET_MAX_HW_ELTS() 300
+
+
+#define RESET_STIPPLE() do { \
+ RADEON_STATECHANGE( rmesa, lin ); \
+ radeonEmitState( rmesa ); \
+} while (0)
+
+#define AUTO_STIPPLE( mode ) do { \
+ RADEON_STATECHANGE( rmesa, lin ); \
+ if (mode) \
+ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] |= \
+ RADEON_LINE_PATTERN_AUTO_RESET; \
+ else \
+ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] &= \
+ ~RADEON_LINE_PATTERN_AUTO_RESET; \
+ radeonEmitState( rmesa ); \
+} while (0)
+
+
+
+#define ALLOC_ELTS(nr) radeonAllocElts( rmesa, nr )
+
+static GLushort *radeonAllocElts( radeonContextPtr rmesa, GLuint nr )
+{
+ if (rmesa->dma.flush)
+ rmesa->dma.flush( rmesa );
+
+ radeonEmitAOS( rmesa,
+ rmesa->tcl.aos_components,
+ rmesa->tcl.nr_aos_components, 0 );
+
+ return radeonAllocEltsOpenEnded( rmesa,
+ rmesa->tcl.vertex_format,
+ rmesa->tcl.hw_primitive, nr );
+}
+
+#define CLOSE_ELTS() RADEON_NEWPRIM( rmesa )
+
+
+
+/* TODO: Try to extend existing primitive if both are identical,
+ * discrete and there are no intervening state changes. (Somewhat
+ * duplicates changes to DrawArrays code)
+ */
+static void EMIT_PRIM( GLcontext *ctx,
+ GLenum prim,
+ GLuint hwprim,
+ GLuint start,
+ GLuint count)
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ radeonTclPrimitive( ctx, prim, hwprim );
+
+ radeonEmitAOS( rmesa,
+ rmesa->tcl.aos_components,
+ rmesa->tcl.nr_aos_components,
+ start );
+
+ /* Why couldn't this packet have taken an offset param?
+ */
+ radeonEmitVbufPrim( rmesa,
+ rmesa->tcl.vertex_format,
+ rmesa->tcl.hw_primitive,
+ count - start );
+}
+
+
+
+/* Try & join small primitives
+ */
+#if 0
+#define PREFER_DISCRETE_ELT_PRIM( NR, PRIM ) 0
+#else
+#define PREFER_DISCRETE_ELT_PRIM( NR, PRIM ) \
+ ((NR) < 20 || \
+ ((NR) < 40 && \
+ rmesa->tcl.hw_primitive == (PRIM| \
+ RADEON_CP_VC_CNTL_PRIM_WALK_IND| \
+ RADEON_CP_VC_CNTL_TCL_ENABLE)))
+#endif
+
+#ifdef MESA_BIG_ENDIAN
+/* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */
+#define EMIT_ELT(dest, offset, x) do { \
+ int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \
+ GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \
+ (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0)
+#else
+#define EMIT_ELT(dest, offset, x) (dest)[offset] = (GLushort) (x)
+#endif
+
+#define EMIT_TWO_ELTS(dest, offset, x, y) *(GLuint *)(dest+offset) = ((y)<<16)|(x);
+
+
+
+#define TAG(x) tcl_##x
+#include "tnl_dd/t_dd_dmatmp2.h"
+
+/**********************************************************************/
+/* External entrypoints */
+/**********************************************************************/
+
+void radeonEmitPrimitive( GLcontext *ctx,
+ GLuint first,
+ GLuint last,
+ GLuint flags )
+{
+ tcl_render_tab_verts[flags&PRIM_MODE_MASK]( ctx, first, last, flags );
+}
+
+void radeonEmitEltPrimitive( GLcontext *ctx,
+ GLuint first,
+ GLuint last,
+ GLuint flags )
+{
+ tcl_render_tab_elts[flags&PRIM_MODE_MASK]( ctx, first, last, flags );
+}
+
+void radeonTclPrimitive( GLcontext *ctx,
+ GLenum prim,
+ int hw_prim )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint se_cntl;
+ GLuint newprim = hw_prim | RADEON_CP_VC_CNTL_TCL_ENABLE;
+
+ if (newprim != rmesa->tcl.hw_primitive ||
+ !discrete_prim[hw_prim&0xf]) {
+ RADEON_NEWPRIM( rmesa );
+ rmesa->tcl.hw_primitive = newprim;
+ }
+
+ se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL];
+ se_cntl &= ~RADEON_FLAT_SHADE_VTX_LAST;
+
+ if (prim == GL_POLYGON && (ctx->_TriangleCaps & DD_FLATSHADE))
+ se_cntl |= RADEON_FLAT_SHADE_VTX_0;
+ else
+ se_cntl |= RADEON_FLAT_SHADE_VTX_LAST;
+
+ if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) {
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl;
+ }
+}
+
+
+/**********************************************************************/
+/* Render pipeline stage */
+/**********************************************************************/
+
+
+/* TCL render.
+ */
+static GLboolean radeon_run_tcl_render( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i,flags = 0,length;
+
+ /* TODO: separate this from the swtnl pipeline
+ */
+ if (rmesa->TclFallback)
+ return GL_TRUE; /* fallback to software t&l */
+
+ if (VB->Count == 0)
+ return GL_FALSE;
+
+ radeonReleaseArrays( ctx, stage->changed_inputs );
+ radeonEmitArrays( ctx, stage->inputs );
+
+ rmesa->tcl.Elts = VB->Elts;
+
+ for (i = VB->FirstPrimitive ; !(flags & PRIM_LAST) ; i += length)
+ {
+ flags = VB->Primitive[i];
+ length = VB->PrimitiveLength[i];
+
+ if (RADEON_DEBUG & DEBUG_PRIMS)
+ fprintf(stderr, "%s: prim %s %d..%d\n",
+ __FUNCTION__,
+ _mesa_lookup_enum_by_nr(flags & PRIM_MODE_MASK),
+ i, i+length);
+
+ if (!length)
+ continue;
+
+ if (rmesa->tcl.Elts)
+ radeonEmitEltPrimitive( ctx, i, i+length, flags );
+ else
+ radeonEmitPrimitive( ctx, i, i+length, flags );
+ }
+
+ return GL_FALSE; /* finished the pipe */
+}
+
+
+
+static void radeon_check_tcl_render( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint inputs = VERT_BIT_POS;
+
+ if (ctx->RenderMode == GL_RENDER) {
+ /* Make all this event-driven:
+ */
+ if (ctx->Light.Enabled) {
+ inputs |= VERT_BIT_NORMAL;
+
+ if (1 || ctx->Light.ColorMaterialEnabled) {
+ inputs |= VERT_BIT_COLOR0;
+ }
+ }
+ else {
+ inputs |= VERT_BIT_COLOR0;
+
+ if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
+ inputs |= VERT_BIT_COLOR1;
+ }
+ }
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled) {
+ if (ctx->Texture.Unit[0].TexGenEnabled) {
+ if (rmesa->TexGenNeedNormals[0]) {
+ inputs |= VERT_BIT_NORMAL;
+ }
+ } else {
+ inputs |= VERT_BIT_TEX0;
+ }
+ }
+
+ if (ctx->Texture.Unit[1]._ReallyEnabled) {
+ if (ctx->Texture.Unit[1].TexGenEnabled) {
+ if (rmesa->TexGenNeedNormals[1]) {
+ inputs |= VERT_BIT_NORMAL;
+ }
+ } else {
+ inputs |= VERT_BIT_TEX1;
+ }
+ }
+
+ stage->inputs = inputs;
+ stage->active = 1;
+ }
+ else
+ stage->active = 0;
+}
+
+static void radeon_init_tcl_render( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ stage->check = radeon_check_tcl_render;
+ stage->check( ctx, stage );
+}
+
+static void dtr( struct gl_pipeline_stage *stage )
+{
+ (void)stage;
+}
+
+
+/* Initial state for tcl stage.
+ */
+const struct gl_pipeline_stage _radeon_tcl_stage =
+{
+ "radeon render",
+ (_DD_NEW_SEPARATE_SPECULAR |
+ _NEW_LIGHT|
+ _NEW_TEXTURE|
+ _NEW_FOG|
+ _NEW_RENDERMODE), /* re-check (new inputs) */
+ 0, /* re-run (always runs) */
+ GL_TRUE, /* active */
+ 0, 0, /* inputs (set in check_render), outputs */
+ 0, 0, /* changed_inputs, private */
+ dtr, /* destructor */
+ radeon_init_tcl_render, /* check - initially set to alloc data */
+ radeon_run_tcl_render /* run */
+};
+
+
+
+/**********************************************************************/
+/* Validate state at pipeline start */
+/**********************************************************************/
+
+
+/*-----------------------------------------------------------------------
+ * Manage TCL fallbacks
+ */
+
+
+static void transition_to_swtnl( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint se_cntl;
+
+ RADEON_NEWPRIM( rmesa );
+ rmesa->swtcl.vertex_format = 0;
+
+ radeonChooseVertexState( ctx );
+ radeonChooseRenderState( ctx );
+
+ _mesa_validate_all_lighting_tables( ctx );
+
+ tnl->Driver.NotifyMaterialChange =
+ _mesa_validate_all_lighting_tables;
+
+ radeonReleaseArrays( ctx, ~0 );
+
+ se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL];
+ se_cntl |= RADEON_FLAT_SHADE_VTX_LAST;
+
+ if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) {
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl;
+ }
+}
+
+
+static void transition_to_hwtnl( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint se_coord_fmt = (RADEON_VTX_W0_IS_NOT_1_OVER_W0 |
+ RADEON_TEX1_W_ROUTING_USE_Q1);
+
+ if ( se_coord_fmt != rmesa->hw.set.cmd[SET_SE_COORDFMT] ) {
+ RADEON_STATECHANGE( rmesa, set );
+ rmesa->hw.set.cmd[SET_SE_COORDFMT] = se_coord_fmt;
+ _tnl_need_projected_coords( ctx, GL_FALSE );
+ }
+
+ radeonUpdateMaterial( ctx );
+
+ tnl->Driver.NotifyMaterialChange = radeonUpdateMaterial;
+
+ if ( rmesa->dma.flush )
+ rmesa->dma.flush( rmesa );
+
+ rmesa->dma.flush = 0;
+ rmesa->swtcl.vertex_format = 0;
+
+ if (rmesa->swtcl.indexed_verts.buf)
+ radeonReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts,
+ __FUNCTION__ );
+
+ if (RADEON_DEBUG & DEBUG_FALLBACKS)
+ fprintf(stderr, "Radeon end tcl fallback\n");
+}
+
+static char *fallbackStrings[] = {
+ "Rasterization fallback",
+ "Unfilled triangles",
+ "Twosided lighting, differing materials",
+ "Materials in VB (maybe between begin/end)",
+ "Texgen unit 0",
+ "Texgen unit 1",
+ "Texgen unit 2",
+ "User disable"
+};
+
+
+static char *getFallbackString(GLuint bit)
+{
+ int i = 0;
+ while (bit > 1) {
+ i++;
+ bit >>= 1;
+ }
+ return fallbackStrings[i];
+}
+
+
+
+void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint oldfallback = rmesa->TclFallback;
+
+ if (mode) {
+ rmesa->TclFallback |= bit;
+ if (oldfallback == 0) {
+ if (RADEON_DEBUG & DEBUG_FALLBACKS)
+ fprintf(stderr, "Radeon begin tcl fallback %s\n",
+ getFallbackString( bit ));
+ transition_to_swtnl( ctx );
+ }
+ }
+ else {
+ rmesa->TclFallback &= ~bit;
+ if (oldfallback == bit) {
+ if (RADEON_DEBUG & DEBUG_FALLBACKS)
+ fprintf(stderr, "Radeon end tcl fallback %s\n",
+ getFallbackString( bit ));
+ transition_to_hwtnl( ctx );
+ }
+ }
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_tcl.h b/src/mesa/drivers/dri/radeon/radeon_tcl.h
new file mode 100644
index 0000000000..1e97d32148
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_tcl.h
@@ -0,0 +1,70 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Grahpics Inc., Austin, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef __RADEON_TCL_H__
+#define __RADEON_TCL_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "radeon_context.h"
+
+extern void radeonTclPrimitive( GLcontext *ctx, GLenum prim, int hw_prim );
+extern void radeonEmitEltPrimitive( GLcontext *ctx, GLuint first, GLuint last,
+ GLuint flags );
+extern void radeonEmitPrimitive( GLcontext *ctx, GLuint first, GLuint last,
+ GLuint flags );
+
+extern void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode );
+
+#define RADEON_TCL_FALLBACK_RASTER 0x1 /* rasterization */
+#define RADEON_TCL_FALLBACK_UNFILLED 0x2 /* unfilled tris */
+#define RADEON_TCL_FALLBACK_LIGHT_TWOSIDE 0x4 /* twoside tris */
+#define RADEON_TCL_FALLBACK_MATERIAL 0x8 /* material in vb */
+#define RADEON_TCL_FALLBACK_TEXGEN_0 0x10 /* texgen, unit 0 */
+#define RADEON_TCL_FALLBACK_TEXGEN_1 0x20 /* texgen, unit 1 */
+#define RADEON_TCL_FALLBACK_TEXGEN_2 0x40 /* texgen, unit 2 */
+#define RADEON_TCL_FALLBACK_TCL_DISABLE 0x80 /* user disable */
+#define RADEON_TCL_FALLBACK_TEXRECT_0 0x100 /* texture rectangle */
+#define RADEON_TCL_FALLBACK_TEXRECT_1 0x200 /* texture rectangle */
+#define RADEON_TCL_FALLBACK_TEXRECT_2 0x400 /* texture rectangle */
+
+#define RADEON_MAX_TCL_VERTSIZE (15*4)
+
+#define TCL_FALLBACK( ctx, bit, mode ) radeonTclFallback( ctx, bit, mode )
+
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_tex.c b/src/mesa/drivers/dri/radeon/radeon_tex.c
new file mode 100644
index 0000000000..e068202c5e
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_tex.c
@@ -0,0 +1,733 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c,v 1.6 2002/09/16 18:05:20 eich Exp $ */
+/*
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Brian Paul <brianp@valinux.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "colormac.h"
+#include "context.h"
+#include "enums.h"
+#include "image.h"
+#include "simple_list.h"
+#include "texformat.h"
+#include "texstore.h"
+#include "teximage.h"
+
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_swtcl.h"
+#include "radeon_tex.h"
+
+
+
+/**
+ * Set the texture wrap modes.
+ *
+ * \param t Texture object whose wrap modes are to be set
+ * \param swrap Wrap mode for the \a s texture coordinate
+ * \param twrap Wrap mode for the \a t texture coordinate
+ */
+
+static void radeonSetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap )
+{
+ GLboolean is_clamp = GL_FALSE;
+ GLboolean is_clamp_to_border = GL_FALSE;
+
+ t->pp_txfilter &= ~(RADEON_CLAMP_S_MASK | RADEON_CLAMP_T_MASK | RADEON_BORDER_MODE_D3D);
+
+ switch ( swrap ) {
+ case GL_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
+ break;
+ case GL_CLAMP:
+ t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
+ is_clamp = GL_TRUE;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
+ break;
+ case GL_CLAMP_TO_BORDER:
+ t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
+ is_clamp_to_border = GL_TRUE;
+ break;
+ case GL_MIRRORED_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_S_MIRROR;
+ break;
+ case GL_MIRROR_CLAMP_ATI:
+ t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
+ is_clamp = GL_TRUE;
+ break;
+ case GL_MIRROR_CLAMP_TO_EDGE_ATI:
+ t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_LAST;
+ break;
+ default:
+ _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
+ }
+
+ switch ( twrap ) {
+ case GL_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
+ break;
+ case GL_CLAMP:
+ t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
+ is_clamp = GL_TRUE;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
+ break;
+ case GL_CLAMP_TO_BORDER:
+ t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
+ is_clamp_to_border = GL_TRUE;
+ break;
+ case GL_MIRRORED_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_T_MIRROR;
+ break;
+ case GL_MIRROR_CLAMP_ATI:
+ t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
+ is_clamp = GL_TRUE;
+ break;
+ case GL_MIRROR_CLAMP_TO_EDGE_ATI:
+ t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_LAST;
+ break;
+ default:
+ _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
+ }
+
+ if ( is_clamp_to_border ) {
+ t->pp_txfilter |= RADEON_BORDER_MODE_D3D;
+ }
+
+ t->border_fallback = (is_clamp && is_clamp_to_border);
+}
+
+static void radeonSetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
+{
+ t->pp_txfilter &= ~RADEON_MAX_ANISO_MASK;
+
+ if ( max == 1.0 ) {
+ t->pp_txfilter |= RADEON_MAX_ANISO_1_TO_1;
+ } else if ( max <= 2.0 ) {
+ t->pp_txfilter |= RADEON_MAX_ANISO_2_TO_1;
+ } else if ( max <= 4.0 ) {
+ t->pp_txfilter |= RADEON_MAX_ANISO_4_TO_1;
+ } else if ( max <= 8.0 ) {
+ t->pp_txfilter |= RADEON_MAX_ANISO_8_TO_1;
+ } else {
+ t->pp_txfilter |= RADEON_MAX_ANISO_16_TO_1;
+ }
+}
+
+/**
+ * Set the texture magnification and minification modes.
+ *
+ * \param t Texture whose filter modes are to be set
+ * \param minf Texture minification mode
+ * \param magf Texture magnification mode
+ */
+
+static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
+{
+ GLuint anisotropy = (t->pp_txfilter & RADEON_MAX_ANISO_MASK);
+
+ t->pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK);
+
+ if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) {
+ switch ( minf ) {
+ case GL_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
+ break;
+ }
+ } else {
+ switch ( minf ) {
+ case GL_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_LINEAR;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
+ break;
+ }
+ }
+
+ switch ( magf ) {
+ case GL_NEAREST:
+ t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
+ break;
+ }
+}
+
+static void radeonSetTexBorderColor( radeonTexObjPtr t, GLubyte c[4] )
+{
+ t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
+}
+
+
+/**
+ * Allocate space for and load the mesa images into the texture memory block.
+ * This will happen before drawing with a new texture, or drawing with a
+ * texture after it was swapped out or teximaged again.
+ */
+
+static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj )
+{
+ radeonTexObjPtr t;
+
+ t = CALLOC_STRUCT( radeon_tex_obj );
+ texObj->DriverData = t;
+ if ( t != NULL ) {
+ if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
+ fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, texObj, t );
+ }
+
+ /* Initialize non-image-dependent parts of the state:
+ */
+ t->base.tObj = texObj;
+ t->border_fallback = GL_FALSE;
+
+ t->pp_txfilter = RADEON_BORDER_MODE_OGL;
+ t->pp_txformat = (RADEON_TXFORMAT_ENDIAN_NO_SWAP |
+ RADEON_TXFORMAT_PERSPECTIVE_ENABLE);
+
+ make_empty_list( & t->base );
+
+ radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT );
+ radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
+ radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
+ radeonSetTexBorderColor( t, texObj->_BorderChan );
+ }
+
+ return t;
+}
+
+
+static const struct gl_texture_format *
+radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+ GLenum format, GLenum type )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ const GLboolean do32bpt = ( rmesa->radeonScreen->cpp == 4 );
+
+ switch ( internalFormat ) {
+ case 4:
+ case GL_RGBA:
+ case GL_COMPRESSED_RGBA:
+ if ( format == GL_BGRA ) {
+ if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
+ return &_mesa_texformat_argb8888;
+ }
+ else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
+ return &_mesa_texformat_argb4444;
+ }
+ else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
+ return &_mesa_texformat_argb1555;
+ }
+ }
+ return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_argb4444;
+
+ case 3:
+ case GL_RGB:
+ case GL_COMPRESSED_RGB:
+ if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
+ return &_mesa_texformat_rgb565;
+ }
+ return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_rgb565;
+
+ case GL_RGBA8:
+ case GL_RGB10_A2:
+ case GL_RGBA12:
+ case GL_RGBA16:
+ return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_argb4444;
+
+ case GL_RGBA4:
+ case GL_RGBA2:
+ return &_mesa_texformat_argb4444;
+
+ case GL_RGB5_A1:
+ return &_mesa_texformat_argb1555;
+
+ case GL_RGB8:
+ case GL_RGB10:
+ case GL_RGB12:
+ case GL_RGB16:
+ return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_rgb565;
+
+ case GL_RGB5:
+ case GL_RGB4:
+ case GL_R3_G3_B2:
+ return &_mesa_texformat_rgb565;
+
+ case GL_ALPHA:
+ case GL_ALPHA4:
+ case GL_ALPHA8:
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ case GL_COMPRESSED_ALPHA:
+ return &_mesa_texformat_al88;
+
+ case 1:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE4:
+ case GL_LUMINANCE8:
+ case GL_LUMINANCE12:
+ case GL_LUMINANCE16:
+ case GL_COMPRESSED_LUMINANCE:
+ return &_mesa_texformat_al88;
+
+ 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:
+ case GL_COMPRESSED_LUMINANCE_ALPHA:
+ return &_mesa_texformat_al88;
+
+ case GL_INTENSITY:
+ case GL_INTENSITY4:
+ case GL_INTENSITY8:
+ case GL_INTENSITY12:
+ case GL_INTENSITY16:
+ case GL_COMPRESSED_INTENSITY:
+ return &_mesa_texformat_i8;
+
+ case GL_YCBCR_MESA:
+ if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
+ type == GL_UNSIGNED_BYTE)
+ return &_mesa_texformat_ycbcr;
+ else
+ return &_mesa_texformat_ycbcr_rev;
+
+ default:
+ _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__);
+ return NULL;
+ }
+
+ return NULL; /* never get here */
+}
+
+
+static void radeonTexImage1D( GLcontext *ctx, GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, 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 )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+ if ( t ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) radeonAllocTexObj( texObj );
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
+ return;
+ }
+ }
+
+ /* Note, this will call ChooseTextureFormat */
+ _mesa_store_teximage1d(ctx, target, level, internalFormat,
+ width, border, format, type, pixels,
+ &ctx->Unpack, texObj, texImage);
+
+ t->dirty_images[0] |= (1 << level);
+}
+
+
+static void radeonTexSubImage1D( GLcontext *ctx, GLenum target, GLint level,
+ GLint xoffset,
+ GLsizei width,
+ GLenum format, GLenum type,
+ const GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+ assert( t ); /* this _should_ be true */
+ if ( t ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) radeonAllocTexObj( texObj );
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
+ return;
+ }
+ }
+
+ _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
+ format, type, pixels, packing, texObj,
+ texImage);
+
+ t->dirty_images[0] |= (1 << level);
+}
+
+
+static void radeonTexImage2D( 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 )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+ GLuint face;
+
+ /* which cube face or ordinary 2D image */
+ switch (target) {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ ASSERT(face < 6);
+ break;
+ default:
+ face = 0;
+ }
+
+ if ( t != NULL ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) radeonAllocTexObj( texObj );
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+ return;
+ }
+ }
+
+ /* Note, this will call ChooseTextureFormat */
+ _mesa_store_teximage2d(ctx, target, level, internalFormat,
+ width, height, border, format, type, pixels,
+ &ctx->Unpack, texObj, texImage);
+
+ t->dirty_images[face] |= (1 << level);
+}
+
+
+static void radeonTexSubImage2D( 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 )
+{
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+ GLuint face;
+
+
+ /* which cube face or ordinary 2D image */
+ switch (target) {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ ASSERT(face < 6);
+ break;
+ default:
+ face = 0;
+ }
+
+ assert( t ); /* this _should_ be true */
+ if ( t ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ t = (driTextureObject *) radeonAllocTexObj( texObj );
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
+ return;
+ }
+ }
+
+ _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
+ height, format, type, pixels, packing, texObj,
+ texImage);
+
+ t->dirty_images[face] |= (1 << level);
+}
+
+
+
+#define SCALED_FLOAT_TO_BYTE( x, scale ) \
+ (((GLuint)((255.0F / scale) * (x))) / 2)
+
+static void radeonTexEnv( GLcontext *ctx, GLenum target,
+ GLenum pname, const GLfloat *param )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint unit = ctx->Texture.CurrentUnit;
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+ if ( RADEON_DEBUG & DEBUG_STATE ) {
+ fprintf( stderr, "%s( %s )\n",
+ __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
+ }
+
+ switch ( pname ) {
+ case GL_TEXTURE_ENV_COLOR: {
+ GLubyte c[4];
+ GLuint envColor;
+ UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
+ envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
+ if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
+ RADEON_STATECHANGE( rmesa, tex[unit] );
+ rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
+ }
+ break;
+ }
+
+ case GL_TEXTURE_LOD_BIAS_EXT: {
+ GLfloat bias;
+ GLuint b;
+
+ /* The Radeon's LOD bias is a signed 2's complement value with a
+ * range of -1.0 <= bias < 4.0. We break this into two linear
+ * functions, one mapping [-1.0,0.0] to [-128,0] and one mapping
+ * [0.0,4.0] to [0,127].
+ */
+ bias = CLAMP( *param, -1.0, 4.0 );
+ if ( bias == 0 ) {
+ b = 0;
+ } else if ( bias > 0 ) {
+ b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 4.0 )) << RADEON_LOD_BIAS_SHIFT;
+ } else {
+ b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 1.0 )) << RADEON_LOD_BIAS_SHIFT;
+ }
+ if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] & RADEON_LOD_BIAS_MASK) != b ) {
+ RADEON_STATECHANGE( rmesa, tex[unit] );
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] &= ~RADEON_LOD_BIAS_MASK;
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] |= (b & RADEON_LOD_BIAS_MASK);
+ }
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+
+
+/**
+ * Changes variables and flags for a state update, which will happen at the
+ * next UpdateTextureState
+ */
+
+static void radeonTexParameter( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *texObj,
+ GLenum pname, const GLfloat *params )
+{
+ radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
+
+ if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
+ fprintf( stderr, "%s( %s )\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr( pname ) );
+ }
+
+ if ( ( target != GL_TEXTURE_2D ) &&
+ ( target != GL_TEXTURE_1D ) )
+ return;
+
+ switch ( pname ) {
+ case GL_TEXTURE_MIN_FILTER:
+ case GL_TEXTURE_MAG_FILTER:
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
+ radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
+ break;
+
+ case GL_TEXTURE_WRAP_S:
+ case GL_TEXTURE_WRAP_T:
+ radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT );
+ break;
+
+ case GL_TEXTURE_BORDER_COLOR:
+ radeonSetTexBorderColor( t, texObj->_BorderChan );
+ break;
+
+ case GL_TEXTURE_BASE_LEVEL:
+ case GL_TEXTURE_MAX_LEVEL:
+ case GL_TEXTURE_MIN_LOD:
+ case GL_TEXTURE_MAX_LOD:
+ /* This isn't the most efficient solution but there doesn't appear to
+ * be a nice alternative. Since there's no LOD clamping,
+ * we just have to rely on loading the right subset of mipmap levels
+ * to simulate a clamped LOD.
+ */
+ driSwapOutTextureObject( (driTextureObject *) t );
+ break;
+
+ default:
+ return;
+ }
+
+ /* Mark this texobj as dirty (one bit per tex unit)
+ */
+ t->dirty_state = TEX_ALL;
+}
+
+
+
+static void radeonBindTexture( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *texObj )
+{
+ if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
+ fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, texObj,
+ ctx->Texture.CurrentUnit );
+ }
+
+ if ( target == GL_TEXTURE_2D || target == GL_TEXTURE_1D ) {
+ if ( texObj->DriverData == NULL ) {
+ radeonAllocTexObj( texObj );
+ }
+ }
+}
+
+static void radeonDeleteTexture( GLcontext *ctx,
+ struct gl_texture_object *texObj )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ driTextureObject * t = (driTextureObject *) texObj->DriverData;
+
+ if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
+ fprintf( stderr, "%s( %p (target = %s) )\n", __FUNCTION__, texObj,
+ _mesa_lookup_enum_by_nr( texObj->Target ) );
+ }
+
+ if ( t != NULL ) {
+ if ( rmesa ) {
+ RADEON_FIREVERTICES( rmesa );
+ }
+
+ driDestroyTextureObject( t );
+ }
+}
+
+/* Need:
+ * - Same GEN_MODE for all active bits
+ * - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
+ * - STRQ presumably all supported (matrix means incoming R values
+ * can end up in STQ, this has implications for vertex support,
+ * presumably ok if maos is used, though?)
+ *
+ * Basically impossible to do this on the fly - just collect some
+ * basic info & do the checks from ValidateState().
+ */
+static void radeonTexGen( GLcontext *ctx,
+ GLenum coord,
+ GLenum pname,
+ const GLfloat *params )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint unit = ctx->Texture.CurrentUnit;
+ rmesa->recheck_texgen[unit] = GL_TRUE;
+}
+
+
+void radeonInitTextureFuncs( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+
+ ctx->Driver.ChooseTextureFormat = radeonChooseTextureFormat;
+ ctx->Driver.TexImage1D = radeonTexImage1D;
+ ctx->Driver.TexImage2D = radeonTexImage2D;
+ ctx->Driver.TexImage3D = _mesa_store_teximage3d;
+ ctx->Driver.TexSubImage1D = radeonTexSubImage1D;
+ ctx->Driver.TexSubImage2D = radeonTexSubImage2D;
+ 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.BindTexture = radeonBindTexture;
+ ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */
+ ctx->Driver.DeleteTexture = radeonDeleteTexture;
+ ctx->Driver.IsTextureResident = driIsTextureResident;
+ ctx->Driver.PrioritizeTexture = NULL;
+ ctx->Driver.ActiveTexture = NULL;
+ ctx->Driver.UpdateTexturePalette = NULL;
+
+ ctx->Driver.TexEnv = radeonTexEnv;
+ ctx->Driver.TexParameter = radeonTexParameter;
+ ctx->Driver.TexGen = radeonTexGen;
+
+ driInitTextureObjects( ctx, & rmesa->swapped,
+ DRI_TEXMGR_DO_TEXTURE_1D
+ | DRI_TEXMGR_DO_TEXTURE_2D );
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_tex.h b/src/mesa/drivers/dri/radeon/radeon_tex.h
new file mode 100644
index 0000000000..ce079baec2
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_tex.h
@@ -0,0 +1,53 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.h,v 1.3 2002/02/22 21:45:01 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#ifndef __RADEON_TEX_H__
+#define __RADEON_TEX_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void radeonUpdateTextureState( GLcontext *ctx );
+
+extern int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t,
+ GLuint face );
+
+extern void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t );
+
+extern void radeonInitTextureFuncs( GLcontext *ctx );
+
+#endif
+#endif /* __RADEON_TEX_H__ */
diff --git a/src/mesa/drivers/dri/radeon/radeon_texmem.c b/src/mesa/drivers/dri/radeon/radeon_texmem.c
new file mode 100644
index 0000000000..3adc2a951c
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_texmem.c
@@ -0,0 +1,378 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_texmem.c,v 1.7 2002/12/16 16:18:59 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 on the rights to use, copy, modify, merge, publish,
+distribute, sub license, 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
+NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR THEIR
+SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ */
+#include <errno.h>
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "macros.h"
+#include "simple_list.h"
+
+#include "radeon_context.h"
+#include "radeon_ioctl.h"
+#include "radeon_tex.h"
+
+
+/**
+ * Destroy any device-dependent state associated with the texture. This may
+ * include NULLing out hardware state that points to the texture.
+ */
+void
+radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
+{
+ if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
+ fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, t, t->base.tObj );
+ }
+
+ if ( rmesa != NULL ) {
+ unsigned i;
+
+
+ for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ ) {
+ if ( t == rmesa->state.texture.unit[i].texobj ) {
+ rmesa->state.texture.unit[i].texobj = NULL;
+ remove_from_list( &rmesa->hw.tex[i] );
+ make_empty_list( &rmesa->hw.tex[i] );
+ }
+ }
+ }
+}
+
+
+/* ------------------------------------------------------------
+ * Texture image conversions
+ */
+
+
+static void radeonUploadRectSubImage( radeonContextPtr rmesa,
+ radeonTexObjPtr t,
+ struct gl_texture_image *texImage,
+ GLint x, GLint y,
+ GLint width, GLint height )
+{
+ const struct gl_texture_format *texFormat = texImage->TexFormat;
+ int blit_format, dstPitch, done;
+
+ switch ( texFormat->TexelBytes ) {
+ case 1:
+ blit_format = RADEON_GMC_DST_8BPP_CI;
+ break;
+ case 2:
+ blit_format = RADEON_GMC_DST_16BPP;
+ break;
+ case 4:
+ blit_format = RADEON_GMC_DST_32BPP;
+ break;
+ default:
+ fprintf( stderr, "radeonUploadRectSubImage: unknown blit_format (texelbytes=%d)\n",
+ texFormat->TexelBytes);
+ return;
+ }
+
+ t->image[0][0].data = texImage->Data;
+
+ /* Currently don't need to cope with small pitches.
+ */
+ width = texImage->Width;
+ height = texImage->Height;
+ dstPitch = t->pp_txpitch + 32;
+
+ { /* FIXME: prefer AGP-texturing if possible */
+ /* Data not in agp memory, or bad pitch.
+ */
+ for (done = 0; done < height ; ) {
+ struct radeon_dma_region region;
+ int lines = MIN2( height - done, RADEON_BUFFER_SIZE / dstPitch );
+ int src_pitch;
+ char *tex;
+
+ src_pitch = texImage->RowStride * texFormat->TexelBytes;
+
+ tex = (char *)texImage->Data + done * src_pitch;
+
+ memset(&region, 0, sizeof(region));
+ radeonAllocDmaRegion( rmesa, &region, lines * dstPitch, 1024 );
+
+ /* Copy texdata to dma:
+ */
+ if (0)
+ fprintf(stderr, "%s: src_pitch %d dst_pitch %d\n",
+ __FUNCTION__, src_pitch, dstPitch);
+
+ if (src_pitch == dstPitch) {
+ memcpy( region.address, tex, lines * src_pitch );
+ }
+ else {
+ char *buf = region.address;
+ int i;
+ for (i = 0 ; i < lines ; i++) {
+ memcpy( buf, tex, src_pitch );
+ buf += dstPitch;
+ tex += src_pitch;
+ }
+ }
+
+ radeonEmitWait( rmesa, RADEON_WAIT_3D );
+
+
+
+ /* Blit to framebuffer
+ */
+ radeonEmitBlit( rmesa,
+ blit_format,
+ dstPitch, GET_START( &region ),
+ dstPitch, t->bufAddr,
+ 0, 0,
+ 0, done,
+ width, lines );
+
+ radeonEmitWait( rmesa, RADEON_WAIT_2D );
+
+ radeonReleaseDmaRegion( rmesa, &region, __FUNCTION__ );
+ done += lines;
+ }
+ }
+}
+
+
+/**
+ * Upload the texture image associated with texture \a t at the specified
+ * level at the address relative to \a start.
+ */
+static void uploadSubImage( radeonContextPtr rmesa, radeonTexObjPtr t,
+ GLint hwlevel,
+ GLint x, GLint y, GLint width, GLint height,
+ GLuint face )
+{
+ struct gl_texture_image *texImage = NULL;
+ GLuint offset;
+ GLint imageWidth, imageHeight;
+ GLint ret;
+ drmRadeonTexture tex;
+ drmRadeonTexImage tmp;
+ const int level = hwlevel + t->base.firstLevel;
+
+ if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
+ fprintf( stderr, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n",
+ __FUNCTION__, t, t->base.tObj, level, width, height, face );
+ }
+
+ ASSERT(face < 6);
+
+ /* Ensure we have a valid texture to upload */
+ if ( ( hwlevel < 0 ) || ( hwlevel >= RADEON_MAX_TEXTURE_LEVELS ) ) {
+ _mesa_problem(NULL, "bad texture level in %s", __FUNCTION__);
+ return;
+ }
+
+ switch (face) {
+ case 0:
+ texImage = t->base.tObj->Image[level];
+ break;
+ case 1:
+ texImage = t->base.tObj->NegX[level];
+ break;
+ case 2:
+ texImage = t->base.tObj->PosY[level];
+ break;
+ case 3:
+ texImage = t->base.tObj->NegY[level];
+ break;
+ case 4:
+ texImage = t->base.tObj->PosZ[level];
+ break;
+ case 5:
+ texImage = t->base.tObj->NegZ[level];
+ break;
+ }
+
+ if ( !texImage ) {
+ if ( RADEON_DEBUG & DEBUG_TEXTURE )
+ fprintf( stderr, "%s: texImage %d is NULL!\n", __FUNCTION__, level );
+ return;
+ }
+ if ( !texImage->Data ) {
+ if ( RADEON_DEBUG & DEBUG_TEXTURE )
+ fprintf( stderr, "%s: image data is NULL!\n", __FUNCTION__ );
+ return;
+ }
+
+
+ if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
+ assert(level == 0);
+ assert(hwlevel == 0);
+ if ( RADEON_DEBUG & DEBUG_TEXTURE )
+ fprintf( stderr, "%s: image data is rectangular\n", __FUNCTION__);
+ radeonUploadRectSubImage( rmesa, t, texImage, x, y, width, height );
+ return;
+ }
+
+ imageWidth = texImage->Width;
+ imageHeight = texImage->Height;
+
+ offset = t->bufAddr;
+
+ if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
+ GLint imageX = 0;
+ GLint imageY = 0;
+ GLint blitX = t->image[face][hwlevel].x;
+ GLint blitY = t->image[face][hwlevel].y;
+ GLint blitWidth = t->image[face][hwlevel].width;
+ GLint blitHeight = t->image[face][hwlevel].height;
+ fprintf( stderr, " upload image: %d,%d at %d,%d\n",
+ imageWidth, imageHeight, imageX, imageY );
+ fprintf( stderr, " upload blit: %d,%d at %d,%d\n",
+ blitWidth, blitHeight, blitX, blitY );
+ fprintf( stderr, " blit ofs: 0x%07x level: %d/%d\n",
+ (GLuint)offset, hwlevel, level );
+ }
+
+ t->image[face][hwlevel].data = texImage->Data;
+
+ /* Init the DRM_RADEON_TEXTURE command / drmRadeonTexture struct.
+ * NOTE: we're always use a 1KB-wide blit and I8 texture format.
+ * We used to use 1, 2 and 4-byte texels and used to use the texture
+ * width to dictate the blit width - but that won't work for compressed
+ * textures. (Brian)
+ */
+ tex.offset = offset;
+ tex.pitch = BLIT_WIDTH_BYTES / 64;
+ tex.format = RADEON_TXFORMAT_I8; /* any 1-byte texel format */
+ if (texImage->TexFormat->TexelBytes) {
+ tex.width = imageWidth * texImage->TexFormat->TexelBytes; /* in bytes */
+ tex.height = imageHeight;
+ }
+ else {
+ tex.width = imageWidth; /* compressed */
+ tex.height = imageHeight;
+ if (tex.height < 4)
+ tex.height = 4;
+ }
+ tex.image = &tmp;
+
+ /* copy (x,y,width,height,data) */
+ memcpy( &tmp, &t->image[face][hwlevel], sizeof(drmRadeonTexImage) );
+
+ LOCK_HARDWARE( rmesa );
+ do {
+ ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE,
+ &tex, sizeof(drmRadeonTexture) );
+ } while ( ret && errno == EAGAIN );
+
+ UNLOCK_HARDWARE( rmesa );
+
+ if ( ret ) {
+ fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret );
+ fprintf( stderr, " offset=0x%08x\n",
+ offset );
+ fprintf( stderr, " image width=%d height=%d\n",
+ imageWidth, imageHeight );
+ fprintf( stderr, " blit width=%d height=%d data=%p\n",
+ t->image[face][hwlevel].width, t->image[face][hwlevel].height,
+ t->image[face][hwlevel].data );
+ exit( 1 );
+ }
+}
+
+
+/**
+ * Upload the texture images associated with texture \a t. This might
+ * require the allocation of texture memory.
+ *
+ * \param rmesa Context pointer
+ * \param t Texture to be uploaded
+ * \param face Cube map face to be uploaded. Zero for non-cube maps.
+ */
+
+int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t, GLuint face )
+{
+ const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
+
+ if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
+ fprintf( stderr, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__,
+ rmesa->glCtx, t->base.tObj, t->base.totalSize,
+ t->base.firstLevel, t->base.lastLevel );
+ }
+
+ if ( !t || t->base.totalSize == 0 )
+ return 0;
+
+ LOCK_HARDWARE( rmesa );
+
+ if ( t->base.memBlock == NULL ) {
+ int heap;
+
+ heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps,
+ (driTextureObject *) t );
+ if ( heap == -1 ) {
+ UNLOCK_HARDWARE( rmesa );
+ return -1;
+ }
+
+ /* Set the base offset of the texture image */
+ t->bufAddr = rmesa->radeonScreen->texOffset[heap]
+ + t->base.memBlock->ofs;
+ t->pp_txoffset = t->bufAddr;
+
+
+ /* Mark this texobj as dirty on all units:
+ */
+ t->dirty_state = TEX_ALL;
+ }
+
+
+ /* Let the world know we've used this memory recently.
+ */
+ driUpdateTextureLRU( (driTextureObject *) t );
+ UNLOCK_HARDWARE( rmesa );
+
+
+ /* Upload any images that are new */
+ if (t->base.dirty_images[face]) {
+ int i;
+ for ( i = 0 ; i < numLevels ; i++ ) {
+ if ( (t->base.dirty_images[face] & (1 << (i+t->base.firstLevel))) != 0 ) {
+ uploadSubImage( rmesa, t, i, 0, 0, t->image[face][i].width,
+ t->image[face][i].height, face );
+ }
+ }
+ t->base.dirty_images[face] = 0;
+ }
+
+ return 0;
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_texstate.c b/src/mesa/drivers/dri/radeon/radeon_texstate.c
new file mode 100644
index 0000000000..6dccd31180
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_texstate.c
@@ -0,0 +1,1628 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_texstate.c,v 1.6 2002/12/16 16:18:59 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ 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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "texformat.h"
+#include "enums.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_swtcl.h"
+#include "radeon_tex.h"
+#include "radeon_tcl.h"
+
+
+#define RADEON_TXFORMAT_AL88 RADEON_TXFORMAT_AI88
+#define RADEON_TXFORMAT_YCBCR RADEON_TXFORMAT_YVYU422
+#define RADEON_TXFORMAT_YCBCR_REV RADEON_TXFORMAT_VYUY422
+
+#define _COLOR(f) \
+ [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f, 0 }
+#define _ALPHA(f) \
+ [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f | RADEON_TXFORMAT_ALPHA_IN_MAP, 0 }
+#define _YUV(f) \
+ [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f, RADEON_YUV_TO_RGB }
+#define _INVALID(f) \
+ [ MESA_FORMAT_ ## f ] = { 0xffffffff, 0 }
+#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_YCBCR_REV) \
+ && (tx_table[f].format != 0xffffffff) )
+
+static const struct {
+ GLuint format, filter;
+}
+tx_table[] =
+{
+ _ALPHA(RGBA8888),
+ _ALPHA(ARGB8888),
+ _INVALID(RGB888),
+ _COLOR(RGB565),
+ _ALPHA(ARGB4444),
+ _ALPHA(ARGB1555),
+ _ALPHA(AL88),
+ _INVALID(A8),
+ _INVALID(L8),
+ _COLOR(I8),
+ _INVALID(CI8),
+ _YUV(YCBCR),
+ _YUV(YCBCR_REV),
+};
+
+#undef _COLOR
+#undef _ALPHA
+#undef _INVALID
+
+/**
+ * This function computes the number of bytes of storage needed for
+ * the given texture object (all mipmap levels, all cube faces).
+ * The \c image[face][level].x/y/width/height parameters for upload/blitting
+ * are computed here. \c pp_txfilter, \c pp_txformat, etc. will be set here
+ * too.
+ *
+ * \param rmesa Context pointer
+ * \param tObj GL texture object whose images are to be posted to
+ * hardware state.
+ */
+static void radeonSetTexImages( radeonContextPtr rmesa,
+ struct gl_texture_object *tObj )
+{
+ radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData;
+ const struct gl_texture_image *baseImage = tObj->Image[tObj->BaseLevel];
+ GLint curOffset;
+ GLint i;
+ GLint firstLevel=0, lastLevel=0, numLevels;
+ GLint log2Width, log2Height, log2Depth;
+
+ /* Set the hardware texture format
+ */
+
+ t->pp_txformat &= ~(RADEON_TXFORMAT_FORMAT_MASK |
+ RADEON_TXFORMAT_ALPHA_IN_MAP);
+ t->pp_txfilter &= ~RADEON_YUV_TO_RGB;
+
+ if ( VALID_FORMAT( baseImage->TexFormat->MesaFormat ) ) {
+ t->pp_txformat |= tx_table[ baseImage->TexFormat->MesaFormat ].format;
+ t->pp_txfilter |= tx_table[ baseImage->TexFormat->MesaFormat ].filter;
+ }
+ else {
+ _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__);
+ return;
+ }
+
+
+
+ /* Compute which mipmap levels we really want to send to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ * Yes, this looks overly complicated, but it's all needed.
+ */
+ switch (tObj->Target) {
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5);
+ firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5);
+ lastLevel = MAX2(lastLevel, tObj->BaseLevel);
+ lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = MIN2(lastLevel, tObj->MaxLevel);
+ lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
+ log2Width = tObj->Image[firstLevel]->WidthLog2;
+ log2Height = tObj->Image[firstLevel]->HeightLog2;
+ log2Depth = 0;
+ break;
+ case GL_TEXTURE_RECTANGLE_NV:
+ firstLevel = lastLevel = 0;
+ log2Width = log2Height = 1; /* ? */
+ log2Depth = 0;
+ break;
+ default:
+ return;
+ }
+
+ /* save these values */
+ t->base.firstLevel = firstLevel;
+ t->base.lastLevel = lastLevel;
+
+ numLevels = lastLevel - firstLevel + 1;
+
+ assert(numLevels <= RADEON_MAX_TEXTURE_LEVELS);
+
+ /* Calculate mipmap offsets and dimensions for blitting (uploading)
+ * The idea is that we lay out the mipmap levels within a block of
+ * memory organized as a rectangle of width BLIT_WIDTH_BYTES.
+ */
+ curOffset = 0;
+
+ for (i = 0; i < numLevels; i++) {
+ const struct gl_texture_image *texImage;
+ GLuint size;
+
+ texImage = tObj->Image[i + firstLevel];
+ if ( !texImage )
+ break;
+
+ /* find image size in bytes */
+ if (texImage->IsCompressed) {
+ size = texImage->CompressedSize;
+ }
+ else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
+ size = ((texImage->Width * texImage->TexFormat->TexelBytes + 63)
+ & ~63) * texImage->Height;
+ }
+ else {
+ int w = texImage->Width * texImage->TexFormat->TexelBytes;
+ if (w < 32)
+ w = 32;
+ size = w * texImage->Height * texImage->Depth;
+ }
+ assert(size > 0);
+
+ if (curOffset & 0x1f) {
+ /* align to 32-byte offset */
+ curOffset = (curOffset + 0x1f) & ~0x1f;
+ }
+
+ t->image[0][i].x = curOffset % BLIT_WIDTH_BYTES;
+ t->image[0][i].y = curOffset / BLIT_WIDTH_BYTES;
+ t->image[0][i].width = MIN2(size, BLIT_WIDTH_BYTES);
+ t->image[0][i].height = size / t->image[0][i].width;
+
+#if 0
+ /* for debugging only and only applicable to non-rectangle targets */
+ assert(size % t->image[0][i].width == 0);
+ assert(t->image[0][i].x == 0
+ || (size < BLIT_WIDTH_BYTES && t->image[0][i].height == 1));
+#endif
+
+ if (0)
+ fprintf(stderr,
+ "level %d: %dx%d x=%d y=%d w=%d h=%d size=%d at %d\n",
+ i, texImage->Width, texImage->Height,
+ t->image[0][i].x, t->image[0][i].y,
+ t->image[0][i].width, t->image[0][i].height, size, curOffset);
+
+ curOffset += size;
+
+ }
+
+ /* Align the total size of texture memory block.
+ */
+ t->base.totalSize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
+
+ /* Hardware state:
+ */
+ t->pp_txfilter &= ~RADEON_MAX_MIP_LEVEL_MASK;
+ t->pp_txfilter |= (numLevels - 1) << RADEON_MAX_MIP_LEVEL_SHIFT;
+
+ t->pp_txformat &= ~(RADEON_TXFORMAT_WIDTH_MASK |
+ RADEON_TXFORMAT_HEIGHT_MASK |
+ RADEON_TXFORMAT_CUBIC_MAP_ENABLE);
+ t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_WIDTH_SHIFT) |
+ (log2Height << RADEON_TXFORMAT_HEIGHT_SHIFT));
+
+ t->pp_txsize = (((tObj->Image[firstLevel]->Width - 1) << 0) |
+ ((tObj->Image[firstLevel]->Height - 1) << 16));
+
+ /* Only need to round to nearest 32 for textures, but the blitter
+ * requires 64-byte aligned pitches, and we may/may not need the
+ * blitter. NPOT only!
+ */
+ if (baseImage->IsCompressed)
+ t->pp_txpitch = (tObj->Image[firstLevel]->Width + 63) & ~(63);
+ else
+ t->pp_txpitch = ((tObj->Image[firstLevel]->Width * baseImage->TexFormat->TexelBytes) + 63) & ~(63);
+ t->pp_txpitch -= 32;
+
+ t->dirty_state = TEX_ALL;
+
+ /* FYI: radeonUploadTexImages( rmesa, t ); used to be called here */
+}
+
+
+
+/* ================================================================
+ * Texture combine functions
+ */
+
+#define RADEON_DISABLE 0
+#define RADEON_REPLACE 1
+#define RADEON_MODULATE 2
+#define RADEON_DECAL 3
+#define RADEON_BLEND 4
+#define RADEON_ADD 5
+#define RADEON_MAX_COMBFUNC 6
+
+static GLuint radeon_color_combine[][RADEON_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_CURRENT_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00802800
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T0_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800142
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T0_COLOR |
+ RADEON_COLOR_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x008c2d42
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T0_COLOR |
+ RADEON_COLOR_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x008c2902
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_TFACTOR_COLOR |
+ RADEON_COLOR_ARG_C_T0_COLOR |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_ADD = 0x00812802
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T0_COLOR |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ },
+
+ /* Unit 1:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_CURRENT_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00803000
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T1_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800182
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T1_COLOR |
+ RADEON_COLOR_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x008c3582
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T1_COLOR |
+ RADEON_COLOR_ARG_C_T1_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x008c3102
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_TFACTOR_COLOR |
+ RADEON_COLOR_ARG_C_T1_COLOR |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_ADD = 0x00813002
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T1_COLOR |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ },
+
+ /* Unit 2:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_CURRENT_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00803800
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T2_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x008001c2
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T2_COLOR |
+ RADEON_COLOR_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x008c3dc2
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T2_COLOR |
+ RADEON_COLOR_ARG_C_T2_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x008c3902
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_TFACTOR_COLOR |
+ RADEON_COLOR_ARG_C_T2_COLOR |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_ADD = 0x00813802
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T2_COLOR |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ }
+};
+
+static GLuint radeon_alpha_combine[][RADEON_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00800500
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800051
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_T0_ALPHA |
+ RADEON_ALPHA_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x00800100
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x00800051
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_TFACTOR_ALPHA |
+ RADEON_ALPHA_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_ADD = 0x00800051
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T0_ALPHA |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ },
+
+ /* Unit 1:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00800600
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T1_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800061
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_T1_ALPHA |
+ RADEON_ALPHA_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x00800100
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x00800061
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_TFACTOR_ALPHA |
+ RADEON_ALPHA_ARG_C_T1_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_ADD = 0x00800061
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T1_ALPHA |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ },
+
+ /* Unit 2:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00800700
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T2_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800071
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_T2_ALPHA |
+ RADEON_ALPHA_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x00800100
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x00800071
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_TFACTOR_ALPHA |
+ RADEON_ALPHA_ARG_C_T2_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_ADD = 0x00800021
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T2_ALPHA |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ }
+};
+
+
+/* GL_ARB_texture_env_combine support
+ */
+
+/* The color tables have combine functions for GL_SRC_COLOR,
+ * GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA.
+ */
+static GLuint radeon_texture_color[][RADEON_MAX_TEXTURE_UNITS] =
+{
+ {
+ RADEON_COLOR_ARG_A_T0_COLOR,
+ RADEON_COLOR_ARG_A_T1_COLOR,
+ RADEON_COLOR_ARG_A_T2_COLOR
+ },
+ {
+ RADEON_COLOR_ARG_A_T0_COLOR | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_T1_COLOR | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_T2_COLOR | RADEON_COMP_ARG_A
+ },
+ {
+ RADEON_COLOR_ARG_A_T0_ALPHA,
+ RADEON_COLOR_ARG_A_T1_ALPHA,
+ RADEON_COLOR_ARG_A_T2_ALPHA
+ },
+ {
+ RADEON_COLOR_ARG_A_T0_ALPHA | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_T1_ALPHA | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_T2_ALPHA | RADEON_COMP_ARG_A
+ },
+};
+
+static GLuint radeon_tfactor_color[] =
+{
+ RADEON_COLOR_ARG_A_TFACTOR_COLOR,
+ RADEON_COLOR_ARG_A_TFACTOR_COLOR | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_TFACTOR_ALPHA,
+ RADEON_COLOR_ARG_A_TFACTOR_ALPHA | RADEON_COMP_ARG_A
+};
+
+static GLuint radeon_primary_color[] =
+{
+ RADEON_COLOR_ARG_A_DIFFUSE_COLOR,
+ RADEON_COLOR_ARG_A_DIFFUSE_COLOR | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_DIFFUSE_ALPHA,
+ RADEON_COLOR_ARG_A_DIFFUSE_ALPHA | RADEON_COMP_ARG_A
+};
+
+static GLuint radeon_previous_color[] =
+{
+ RADEON_COLOR_ARG_A_CURRENT_COLOR,
+ RADEON_COLOR_ARG_A_CURRENT_COLOR | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_CURRENT_ALPHA,
+ RADEON_COLOR_ARG_A_CURRENT_ALPHA | RADEON_COMP_ARG_A
+};
+
+/* GL_ZERO table - indices 0-3
+ * GL_ONE table - indices 1-4
+ */
+static GLuint radeon_zero_color[] =
+{
+ RADEON_COLOR_ARG_A_ZERO,
+ RADEON_COLOR_ARG_A_ZERO | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_ZERO,
+ RADEON_COLOR_ARG_A_ZERO | RADEON_COMP_ARG_A,
+ RADEON_COLOR_ARG_A_ZERO
+};
+
+
+/* The alpha tables only have GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA.
+ */
+static GLuint radeon_texture_alpha[][RADEON_MAX_TEXTURE_UNITS] =
+{
+ {
+ RADEON_ALPHA_ARG_A_T0_ALPHA,
+ RADEON_ALPHA_ARG_A_T1_ALPHA,
+ RADEON_ALPHA_ARG_A_T2_ALPHA
+ },
+ {
+ RADEON_ALPHA_ARG_A_T0_ALPHA | RADEON_COMP_ARG_A,
+ RADEON_ALPHA_ARG_A_T1_ALPHA | RADEON_COMP_ARG_A,
+ RADEON_ALPHA_ARG_A_T2_ALPHA | RADEON_COMP_ARG_A
+ },
+};
+
+static GLuint radeon_tfactor_alpha[] =
+{
+ RADEON_ALPHA_ARG_A_TFACTOR_ALPHA,
+ RADEON_ALPHA_ARG_A_TFACTOR_ALPHA | RADEON_COMP_ARG_A
+};
+
+static GLuint radeon_primary_alpha[] =
+{
+ RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA,
+ RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA | RADEON_COMP_ARG_A
+};
+
+static GLuint radeon_previous_alpha[] =
+{
+ RADEON_ALPHA_ARG_A_CURRENT_ALPHA,
+ RADEON_ALPHA_ARG_A_CURRENT_ALPHA | RADEON_COMP_ARG_A
+};
+
+/* GL_ZERO table - indices 0-1
+ * GL_ONE table - indices 1-2
+ */
+static GLuint radeon_zero_alpha[] =
+{
+ RADEON_ALPHA_ARG_A_ZERO,
+ RADEON_ALPHA_ARG_A_ZERO | RADEON_COMP_ARG_A,
+ RADEON_ALPHA_ARG_A_ZERO
+};
+
+
+/* Extract the arg from slot A, shift it into the correct argument slot
+ * and set the corresponding complement bit.
+ */
+#define RADEON_COLOR_ARG( n, arg ) \
+do { \
+ color_combine |= \
+ ((color_arg[n] & RADEON_COLOR_ARG_MASK) \
+ << RADEON_COLOR_ARG_##arg##_SHIFT); \
+ color_combine |= \
+ ((color_arg[n] >> RADEON_COMP_ARG_SHIFT) \
+ << RADEON_COMP_ARG_##arg##_SHIFT); \
+} while (0)
+
+#define RADEON_ALPHA_ARG( n, arg ) \
+do { \
+ alpha_combine |= \
+ ((alpha_arg[n] & RADEON_ALPHA_ARG_MASK) \
+ << RADEON_ALPHA_ARG_##arg##_SHIFT); \
+ alpha_combine |= \
+ ((alpha_arg[n] >> RADEON_COMP_ARG_SHIFT) \
+ << RADEON_COMP_ARG_##arg##_SHIFT); \
+} while (0)
+
+
+/* ================================================================
+ * Texture unit state management
+ */
+
+static GLboolean radeonUpdateTextureEnv( GLcontext *ctx, int unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ GLuint color_combine, alpha_combine;
+
+ /* texUnit->_Current can be NULL if and only if the texture unit is
+ * not actually enabled.
+ */
+ assert( (texUnit->_ReallyEnabled == 0)
+ || (texUnit->_Current != NULL) );
+
+ if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
+ fprintf( stderr, "%s( %p, %d )\n", __FUNCTION__, ctx, unit );
+ }
+
+ /* Set the texture environment state. Isn't this nice and clean?
+ * The chip will automagically set the texture alpha to 0xff when
+ * the texture format does not include an alpha component. This
+ * reduces the amount of special-casing we have to do, alpha-only
+ * textures being a notable exception.
+ */
+ if ( !texUnit->_ReallyEnabled ) {
+ /* Don't cache these results.
+ */
+ rmesa->state.texture.unit[unit].format = 0;
+ rmesa->state.texture.unit[unit].envMode = 0;
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ }
+ else {
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ const GLenum format = tObj->Image[tObj->BaseLevel]->Format;
+ GLuint color_arg[3], alpha_arg[3];
+ GLuint i, numColorArgs = 0, numAlphaArgs = 0;
+ GLuint RGBshift = texUnit->CombineScaleShiftRGB;
+ GLuint Ashift = texUnit->CombineScaleShiftA;
+
+ switch ( texUnit->EnvMode ) {
+ case GL_REPLACE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_REPLACE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE];
+ break;
+ case GL_ALPHA:
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE];
+ break;
+ case GL_LUMINANCE:
+ case GL_RGB:
+ case GL_YCBCR_MESA:
+ color_combine = radeon_color_combine[unit][RADEON_REPLACE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_MODULATE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_MODULATE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_ALPHA:
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_RGB:
+ case GL_LUMINANCE:
+ case GL_YCBCR_MESA:
+ color_combine = radeon_color_combine[unit][RADEON_MODULATE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_DECAL:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_RGB:
+ case GL_YCBCR_MESA:
+ color_combine = radeon_color_combine[unit][RADEON_DECAL];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_BLEND:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_RGB:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_YCBCR_MESA:
+ color_combine = radeon_color_combine[unit][RADEON_BLEND];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_ALPHA:
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_BLEND];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_BLEND];
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_ADD:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_RGB:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_YCBCR_MESA:
+ color_combine = radeon_color_combine[unit][RADEON_ADD];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_ALPHA:
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_ADD];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_ADD];
+ break;
+ case GL_COLOR_INDEX:
+ default:
+ return GL_FALSE;
+ }
+ break;
+
+ case GL_COMBINE:
+ /* Don't cache these results.
+ */
+ rmesa->state.texture.unit[unit].format = 0;
+ rmesa->state.texture.unit[unit].envMode = 0;
+
+ /* Step 0:
+ * Calculate how many arguments we need to process.
+ */
+ switch ( texUnit->CombineModeRGB ) {
+ case GL_REPLACE:
+ numColorArgs = 1;
+ break;
+ case GL_MODULATE:
+ case GL_ADD:
+ case GL_ADD_SIGNED:
+ case GL_SUBTRACT:
+ case GL_DOT3_RGB:
+ case GL_DOT3_RGBA:
+ case GL_DOT3_RGB_EXT:
+ case GL_DOT3_RGBA_EXT:
+ numColorArgs = 2;
+ break;
+ case GL_INTERPOLATE:
+ case GL_MODULATE_ADD_ATI:
+ case GL_MODULATE_SIGNED_ADD_ATI:
+ case GL_MODULATE_SUBTRACT_ATI:
+ numColorArgs = 3;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ switch ( texUnit->CombineModeA ) {
+ case GL_REPLACE:
+ numAlphaArgs = 1;
+ break;
+ case GL_MODULATE:
+ case GL_ADD:
+ case GL_ADD_SIGNED:
+ case GL_SUBTRACT:
+ numAlphaArgs = 2;
+ break;
+ case GL_INTERPOLATE:
+ case GL_MODULATE_ADD_ATI:
+ case GL_MODULATE_SIGNED_ADD_ATI:
+ case GL_MODULATE_SUBTRACT_ATI:
+ numAlphaArgs = 3;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ /* Step 1:
+ * Extract the color and alpha combine function arguments.
+ */
+ for ( i = 0 ; i < numColorArgs ; i++ ) {
+ const GLuint op = texUnit->CombineOperandRGB[i] - GL_SRC_COLOR;
+ assert(op >= 0);
+ assert(op <= 3);
+ switch ( texUnit->CombineSourceRGB[i] ) {
+ case GL_TEXTURE:
+ color_arg[i] = radeon_texture_color[op][unit];
+ break;
+ case GL_CONSTANT:
+ color_arg[i] = radeon_tfactor_color[op];
+ break;
+ case GL_PRIMARY_COLOR:
+ color_arg[i] = radeon_primary_color[op];
+ break;
+ case GL_PREVIOUS:
+ color_arg[i] = radeon_previous_color[op];
+ break;
+ case GL_ZERO:
+ color_arg[i] = radeon_zero_color[op];
+ break;
+ case GL_ONE:
+ color_arg[i] = radeon_zero_color[op+1];
+ break;
+ default:
+ return GL_FALSE;
+ }
+ }
+
+ for ( i = 0 ; i < numAlphaArgs ; i++ ) {
+ const GLuint op = texUnit->CombineOperandA[i] - GL_SRC_ALPHA;
+ assert(op >= 0);
+ assert(op <= 1);
+ switch ( texUnit->CombineSourceA[i] ) {
+ case GL_TEXTURE:
+ alpha_arg[i] = radeon_texture_alpha[op][unit];
+ break;
+ case GL_CONSTANT:
+ alpha_arg[i] = radeon_tfactor_alpha[op];
+ break;
+ case GL_PRIMARY_COLOR:
+ alpha_arg[i] = radeon_primary_alpha[op];
+ break;
+ case GL_PREVIOUS:
+ alpha_arg[i] = radeon_previous_alpha[op];
+ break;
+ case GL_ZERO:
+ alpha_arg[i] = radeon_zero_alpha[op];
+ break;
+ case GL_ONE:
+ alpha_arg[i] = radeon_zero_alpha[op+1];
+ break;
+ default:
+ return GL_FALSE;
+ }
+ }
+
+ /* Step 2:
+ * Build up the color and alpha combine functions.
+ */
+ switch ( texUnit->CombineModeRGB ) {
+ case GL_REPLACE:
+ color_combine = (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, C );
+ break;
+ case GL_MODULATE:
+ color_combine = (RADEON_COLOR_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, B );
+ break;
+ case GL_ADD:
+ color_combine = (RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, C );
+ break;
+ case GL_ADD_SIGNED:
+ color_combine = (RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADDSIGNED |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, C );
+ break;
+ case GL_SUBTRACT:
+ color_combine = (RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_SUBTRACT |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, C );
+ break;
+ case GL_INTERPOLATE:
+ color_combine = (RADEON_BLEND_CTL_BLEND |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, B );
+ RADEON_COLOR_ARG( 1, A );
+ RADEON_COLOR_ARG( 2, C );
+ break;
+
+ case GL_DOT3_RGB_EXT:
+ case GL_DOT3_RGBA_EXT:
+ /* The EXT version of the DOT3 extension does not support the
+ * scale factor, but the ARB version (and the version in OpenGL
+ * 1.3) does.
+ */
+ RGBshift = 0;
+ Ashift = 0;
+ /* FALLTHROUGH */
+
+ case GL_DOT3_RGB:
+ case GL_DOT3_RGBA:
+ /* The R100 / RV200 only support a 1X multiplier in hardware
+ * w/the ARB version.
+ */
+ if ( RGBshift != (RADEON_SCALE_1X >> RADEON_SCALE_SHIFT) ) {
+ return GL_FALSE;
+ }
+
+ RGBshift += 2;
+ Ashift = RGBshift;
+
+ color_combine = (RADEON_COLOR_ARG_C_ZERO |
+ RADEON_BLEND_CTL_DOT3 |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, B );
+ break;
+
+ case GL_MODULATE_ADD_ATI:
+ color_combine = (RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, C );
+ RADEON_COLOR_ARG( 2, B );
+ break;
+ case GL_MODULATE_SIGNED_ADD_ATI:
+ color_combine = (RADEON_BLEND_CTL_ADDSIGNED |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, C );
+ RADEON_COLOR_ARG( 2, B );
+ break;
+ case GL_MODULATE_SUBTRACT_ATI:
+ color_combine = (RADEON_BLEND_CTL_SUBTRACT |
+ RADEON_CLAMP_TX);
+ RADEON_COLOR_ARG( 0, A );
+ RADEON_COLOR_ARG( 1, C );
+ RADEON_COLOR_ARG( 2, B );
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ switch ( texUnit->CombineModeA ) {
+ case GL_REPLACE:
+ alpha_combine = (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, C );
+ break;
+ case GL_MODULATE:
+ alpha_combine = (RADEON_ALPHA_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, A );
+ RADEON_ALPHA_ARG( 1, B );
+ break;
+ case GL_ADD:
+ alpha_combine = (RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, A );
+ RADEON_ALPHA_ARG( 1, C );
+ break;
+ case GL_ADD_SIGNED:
+ alpha_combine = (RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_ADDSIGNED |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, A );
+ RADEON_ALPHA_ARG( 1, C );
+ break;
+ case GL_SUBTRACT:
+ alpha_combine = (RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COMP_ARG_B |
+ RADEON_BLEND_CTL_SUBTRACT |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, A );
+ RADEON_ALPHA_ARG( 1, C );
+ break;
+ case GL_INTERPOLATE:
+ alpha_combine = (RADEON_BLEND_CTL_BLEND |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, B );
+ RADEON_ALPHA_ARG( 1, A );
+ RADEON_ALPHA_ARG( 2, C );
+ break;
+
+ case GL_MODULATE_ADD_ATI:
+ alpha_combine = (RADEON_BLEND_CTL_ADD |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, A );
+ RADEON_ALPHA_ARG( 1, C );
+ RADEON_ALPHA_ARG( 2, B );
+ break;
+ case GL_MODULATE_SIGNED_ADD_ATI:
+ alpha_combine = (RADEON_BLEND_CTL_ADDSIGNED |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, A );
+ RADEON_ALPHA_ARG( 1, C );
+ RADEON_ALPHA_ARG( 2, B );
+ break;
+ case GL_MODULATE_SUBTRACT_ATI:
+ alpha_combine = (RADEON_BLEND_CTL_SUBTRACT |
+ RADEON_CLAMP_TX);
+ RADEON_ALPHA_ARG( 0, A );
+ RADEON_ALPHA_ARG( 1, C );
+ RADEON_ALPHA_ARG( 2, B );
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ if ( (texUnit->CombineModeRGB == GL_DOT3_RGB_EXT)
+ || (texUnit->CombineModeRGB == GL_DOT3_RGB) ) {
+ alpha_combine |= RADEON_DOT_ALPHA_DONT_REPLICATE;
+ }
+
+ /* Step 3:
+ * Apply the scale factor.
+ */
+ color_combine |= (RGBshift << RADEON_SCALE_SHIFT);
+ alpha_combine |= (Ashift << RADEON_SCALE_SHIFT);
+
+ /* All done!
+ */
+ break;
+
+ default:
+ return GL_FALSE;
+ }
+ }
+
+ if ( rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] != color_combine ||
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] != alpha_combine ) {
+ RADEON_STATECHANGE( rmesa, tex[unit] );
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] = color_combine;
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] = alpha_combine;
+ }
+
+ return GL_TRUE;
+}
+
+#define TEXOBJ_TXFILTER_MASK (RADEON_MAX_MIP_LEVEL_MASK | \
+ RADEON_MIN_FILTER_MASK | \
+ RADEON_MAG_FILTER_MASK | \
+ RADEON_MAX_ANISO_MASK | \
+ RADEON_YUV_TO_RGB | \
+ RADEON_YUV_TEMPERATURE_MASK | \
+ RADEON_CLAMP_S_MASK | \
+ RADEON_CLAMP_T_MASK | \
+ RADEON_BORDER_MODE_D3D )
+
+#define TEXOBJ_TXFORMAT_MASK (RADEON_TXFORMAT_WIDTH_MASK | \
+ RADEON_TXFORMAT_HEIGHT_MASK | \
+ RADEON_TXFORMAT_FORMAT_MASK | \
+ RADEON_TXFORMAT_F5_WIDTH_MASK | \
+ RADEON_TXFORMAT_F5_HEIGHT_MASK | \
+ RADEON_TXFORMAT_ALPHA_IN_MAP | \
+ RADEON_TXFORMAT_CUBIC_MAP_ENABLE | \
+ RADEON_TXFORMAT_NON_POWER2)
+
+
+static void import_tex_obj_state( radeonContextPtr rmesa,
+ int unit,
+ radeonTexObjPtr texobj )
+{
+ GLuint *cmd = RADEON_DB_STATE( tex[unit] );
+
+ cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK;
+ cmd[TEX_PP_TXFILTER] |= texobj->pp_txfilter & TEXOBJ_TXFILTER_MASK;
+ cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
+ cmd[TEX_PP_TXFORMAT] |= texobj->pp_txformat & TEXOBJ_TXFORMAT_MASK;
+ cmd[TEX_PP_TXOFFSET] = texobj->pp_txoffset;
+ cmd[TEX_PP_BORDER_COLOR] = texobj->pp_border_color;
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[unit] );
+
+ if (texobj->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
+ GLuint *txr_cmd = RADEON_DB_STATE( txr[unit] );
+ txr_cmd[TXR_PP_TEX_SIZE] = texobj->pp_txsize; /* NPOT only! */
+ txr_cmd[TXR_PP_TEX_PITCH] = texobj->pp_txpitch; /* NPOT only! */
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.txr[unit] );
+ }
+
+ texobj->dirty_state &= ~(1<<unit);
+}
+
+
+
+
+static void set_texgen_matrix( radeonContextPtr rmesa,
+ GLuint unit,
+ const GLfloat *s_plane,
+ const GLfloat *t_plane )
+{
+ static const GLfloat scale_identity[4] = { 1,1,1,1 };
+
+ if (!TEST_EQ_4V( s_plane, scale_identity) ||
+ !TEST_EQ_4V( t_plane, scale_identity)) {
+ rmesa->TexGenEnabled |= RADEON_TEXMAT_0_ENABLE<<unit;
+ rmesa->TexGenMatrix[unit].m[0] = s_plane[0];
+ rmesa->TexGenMatrix[unit].m[4] = s_plane[1];
+ rmesa->TexGenMatrix[unit].m[8] = s_plane[2];
+ rmesa->TexGenMatrix[unit].m[12] = s_plane[3];
+
+ rmesa->TexGenMatrix[unit].m[1] = t_plane[0];
+ rmesa->TexGenMatrix[unit].m[5] = t_plane[1];
+ rmesa->TexGenMatrix[unit].m[9] = t_plane[2];
+ rmesa->TexGenMatrix[unit].m[13] = t_plane[3];
+ rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+ }
+}
+
+/* Ignoring the Q texcoord for now.
+ *
+ * Returns GL_FALSE if fallback required.
+ */
+static GLboolean radeon_validate_texgen( GLcontext *ctx, GLuint unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4;
+ GLuint tmp = rmesa->TexGenEnabled;
+
+ rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_TEXMAT_0_ENABLE<<unit);
+ rmesa->TexGenEnabled &= ~(RADEON_TEXMAT_0_ENABLE<<unit);
+ rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_INPUT_MASK<<inputshift);
+ rmesa->TexGenNeedNormals[unit] = 0;
+
+ if ((texUnit->TexGenEnabled & (S_BIT|T_BIT)) == 0) {
+ /* Disabled, no fallback:
+ */
+ rmesa->TexGenEnabled |=
+ (RADEON_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift;
+ return GL_TRUE;
+ }
+ else if (texUnit->TexGenEnabled & Q_BIT) {
+ /* Very easy to do this, in fact would remove a fallback case
+ * elsewhere, but I haven't done it yet... Fallback:
+ */
+ fprintf(stderr, "fallback Q_BIT\n");
+ return GL_FALSE;
+ }
+ else if ((texUnit->TexGenEnabled & (S_BIT|T_BIT)) != (S_BIT|T_BIT) ||
+ texUnit->GenModeS != texUnit->GenModeT) {
+ /* Mixed modes, fallback:
+ */
+ /* fprintf(stderr, "fallback mixed texgen\n"); */
+ return GL_FALSE;
+ }
+ else
+ rmesa->TexGenEnabled |= RADEON_TEXGEN_TEXMAT_0_ENABLE << unit;
+
+ switch (texUnit->GenModeS) {
+ case GL_OBJECT_LINEAR:
+ rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_OBJ << inputshift;
+ set_texgen_matrix( rmesa, unit,
+ texUnit->ObjectPlaneS,
+ texUnit->ObjectPlaneT);
+ break;
+
+ case GL_EYE_LINEAR:
+ rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_EYE << inputshift;
+ set_texgen_matrix( rmesa, unit,
+ texUnit->EyePlaneS,
+ texUnit->EyePlaneT);
+ break;
+
+ case GL_REFLECTION_MAP_NV:
+ rmesa->TexGenNeedNormals[unit] = GL_TRUE;
+ rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_EYE_REFLECT<<inputshift;
+ break;
+
+ case GL_NORMAL_MAP_NV:
+ rmesa->TexGenNeedNormals[unit] = GL_TRUE;
+ rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_EYE_NORMAL<<inputshift;
+ break;
+
+ case GL_SPHERE_MAP:
+ default:
+ /* Unsupported mode, fallback:
+ */
+ /* fprintf(stderr, "fallback unsupported texgen\n"); */
+ return GL_FALSE;
+ }
+
+ if (tmp != rmesa->TexGenEnabled) {
+ rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+ }
+
+ return GL_TRUE;
+}
+
+
+static void disable_tex( GLcontext *ctx, int unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<unit)) {
+ /* Texture unit disabled */
+ if ( rmesa->state.texture.unit[unit].texobj != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ rmesa->state.texture.unit[unit].texobj->base.bound &= ~(1UL << unit);
+ rmesa->state.texture.unit[unit].texobj = NULL;
+ }
+
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &=
+ ~((RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << unit);
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ switch (unit) {
+ case 0:
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST0 |
+ RADEON_TCL_VTX_Q0);
+ break;
+ case 1:
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST1 |
+ RADEON_TCL_VTX_Q1);
+ break;
+ default:
+ break;
+ }
+
+
+ if (rmesa->TclFallback & (RADEON_TCL_FALLBACK_TEXGEN_0<<unit)) {
+ TCL_FALLBACK( ctx, (RADEON_TCL_FALLBACK_TEXGEN_0<<unit), GL_FALSE);
+ rmesa->recheck_texgen[unit] = GL_TRUE;
+ }
+
+
+
+ {
+ GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4;
+ GLuint tmp = rmesa->TexGenEnabled;
+
+ rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_TEXMAT_0_ENABLE<<unit);
+ rmesa->TexGenEnabled &= ~(RADEON_TEXMAT_0_ENABLE<<unit);
+ rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_INPUT_MASK<<inputshift);
+ rmesa->TexGenNeedNormals[unit] = 0;
+ rmesa->TexGenEnabled |=
+ (RADEON_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift;
+
+ if (tmp != rmesa->TexGenEnabled) {
+ rmesa->recheck_texgen[unit] = GL_TRUE;
+ rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+ }
+ }
+ }
+}
+
+static GLboolean enable_tex_2d( GLcontext *ctx, int unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ struct gl_texture_object *tObj = texUnit->_Current;
+ radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData;
+
+ /* Need to load the 2d images associated with this unit.
+ */
+ if (t->pp_txformat & RADEON_TXFORMAT_NON_POWER2) {
+ t->pp_txformat &= ~RADEON_TXFORMAT_NON_POWER2;
+ t->base.dirty_images[0] = ~0;
+ }
+
+ ASSERT(tObj->Target == GL_TEXTURE_2D || tObj->Target == GL_TEXTURE_1D);
+
+ if ( t->base.dirty_images[0] ) {
+ RADEON_FIREVERTICES( rmesa );
+ radeonSetTexImages( rmesa, tObj );
+ radeonUploadTexImages( rmesa, (radeonTexObjPtr) tObj->DriverData, 0 );
+ if ( !t->base.memBlock )
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean enable_tex_rect( GLcontext *ctx, int unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ struct gl_texture_object *tObj = texUnit->_Current;
+ radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData;
+
+ if (!(t->pp_txformat & RADEON_TXFORMAT_NON_POWER2)) {
+ t->pp_txformat |= RADEON_TXFORMAT_NON_POWER2;
+ t->base.dirty_images[0] = ~0;
+ }
+
+ ASSERT(tObj->Target == GL_TEXTURE_RECTANGLE_NV);
+
+ if ( t->base.dirty_images[0] ) {
+ RADEON_FIREVERTICES( rmesa );
+ radeonSetTexImages( rmesa, tObj );
+ radeonUploadTexImages( rmesa, (radeonTexObjPtr) tObj->DriverData, 0 );
+ if ( !t->base.memBlock /* && !rmesa->prefer_agp_client_texturing FIXME */ ) {
+ fprintf(stderr, "%s: upload failed\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean update_tex_common( GLcontext *ctx, int unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ struct gl_texture_object *tObj = texUnit->_Current;
+ radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData;
+ GLenum format;
+
+ /* Fallback if there's a texture border */
+ if ( tObj->Image[tObj->BaseLevel]->Border > 0 ) {
+ fprintf(stderr, "%s: border\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+
+ /* Update state if this is a different texture object to last
+ * time.
+ */
+ if ( rmesa->state.texture.unit[unit].texobj != t ) {
+ if ( rmesa->state.texture.unit[unit].texobj != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ rmesa->state.texture.unit[unit].texobj->base.bound &=
+ ~(1UL << unit);
+ }
+
+ rmesa->state.texture.unit[unit].texobj = t;
+ t->base.bound |= (1UL << unit);
+ t->dirty_state |= 1<<unit;
+ driUpdateTextureLRU( (driTextureObject *) t ); /* XXX: should be locked! */
+ }
+
+
+ /* Newly enabled?
+ */
+ if ( !(rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<unit))) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |=
+ (RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << unit;
+
+ RADEON_STATECHANGE( rmesa, tcl );
+
+ if (unit == 0)
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST0;
+ else
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST1;
+
+ rmesa->recheck_texgen[unit] = GL_TRUE;
+ }
+
+ if (t->dirty_state & (1<<unit)) {
+ import_tex_obj_state( rmesa, unit, t );
+ }
+
+ if (rmesa->recheck_texgen[unit]) {
+ GLboolean fallback = !radeon_validate_texgen( ctx, unit );
+ TCL_FALLBACK( ctx, (RADEON_TCL_FALLBACK_TEXGEN_0<<unit), fallback);
+ rmesa->recheck_texgen[unit] = 0;
+ rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+ }
+
+ format = tObj->Image[tObj->BaseLevel]->Format;
+ if ( rmesa->state.texture.unit[unit].format != format ||
+ rmesa->state.texture.unit[unit].envMode != texUnit->EnvMode ) {
+ rmesa->state.texture.unit[unit].format = format;
+ rmesa->state.texture.unit[unit].envMode = texUnit->EnvMode;
+ if ( ! radeonUpdateTextureEnv( ctx, unit ) ) {
+ return GL_FALSE;
+ }
+ }
+
+ FALLBACK( rmesa, RADEON_FALLBACK_BORDER_MODE, t->border_fallback );
+ return !t->border_fallback;
+}
+
+
+
+static GLboolean radeonUpdateTextureUnit( GLcontext *ctx, int unit )
+{
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_TEXRECT_0 << unit, 0 );
+
+ if ( texUnit->_ReallyEnabled & (TEXTURE_RECT_BIT) ) {
+ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_TEXRECT_0 << unit, 1 );
+
+ return (enable_tex_rect( ctx, unit ) &&
+ update_tex_common( ctx, unit ));
+ }
+ else if ( texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT) ) {
+ return (enable_tex_2d( ctx, unit ) &&
+ update_tex_common( ctx, unit ));
+ }
+ else if ( texUnit->_ReallyEnabled ) {
+ return GL_FALSE;
+ }
+ else {
+ disable_tex( ctx, unit );
+ return GL_TRUE;
+ }
+}
+
+void radeonUpdateTextureState( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLboolean ok;
+
+ ok = (radeonUpdateTextureUnit( ctx, 0 ) &&
+ radeonUpdateTextureUnit( ctx, 1 ));
+
+ FALLBACK( rmesa, RADEON_FALLBACK_TEXTURE, !ok );
+
+ if (rmesa->TclFallback)
+ radeonChooseVertexState( ctx );
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.c
new file mode 100644
index 0000000000..b613e9eb43
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.c
@@ -0,0 +1,1089 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_vtxfmt.c,v 1.5 2002/12/16 16:18:59 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Cedar Park, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+#include "glheader.h"
+#include "imports.h"
+#include "api_noop.h"
+#include "api_arrayelt.h"
+#include "context.h"
+#include "mtypes.h"
+#include "enums.h"
+#include "glapi.h"
+#include "colormac.h"
+#include "light.h"
+#include "state.h"
+#include "vtxfmt.h"
+
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_array_api.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_tex.h"
+#include "radeon_tcl.h"
+#include "radeon_swtcl.h"
+#include "radeon_vtxfmt.h"
+
+static void radeonVtxfmtFlushVertices( GLcontext *, GLuint );
+
+static void count_func( const char *name, struct dynfn *l )
+{
+ int i = 0;
+ struct dynfn *f;
+ foreach (f, l) i++;
+ if (i) fprintf(stderr, "%s: %d\n", name, i );
+}
+
+static void count_funcs( radeonContextPtr rmesa )
+{
+ count_func( "Vertex2f", &rmesa->vb.dfn_cache.Vertex2f );
+ count_func( "Vertex2fv", &rmesa->vb.dfn_cache.Vertex2fv );
+ count_func( "Vertex3f", &rmesa->vb.dfn_cache.Vertex3f );
+ count_func( "Vertex3fv", &rmesa->vb.dfn_cache.Vertex3fv );
+ count_func( "Color4ub", &rmesa->vb.dfn_cache.Color4ub );
+ count_func( "Color4ubv", &rmesa->vb.dfn_cache.Color4ubv );
+ count_func( "Color3ub", &rmesa->vb.dfn_cache.Color3ub );
+ count_func( "Color3ubv", &rmesa->vb.dfn_cache.Color3ubv );
+ count_func( "Color4f", &rmesa->vb.dfn_cache.Color4f );
+ count_func( "Color4fv", &rmesa->vb.dfn_cache.Color4fv );
+ count_func( "Color3f", &rmesa->vb.dfn_cache.Color3f );
+ count_func( "Color3fv", &rmesa->vb.dfn_cache.Color3fv );
+ count_func( "SecondaryColor3f", &rmesa->vb.dfn_cache.SecondaryColor3fEXT );
+ count_func( "SecondaryColor3fv", &rmesa->vb.dfn_cache.SecondaryColor3fvEXT );
+ count_func( "SecondaryColor3ub", &rmesa->vb.dfn_cache.SecondaryColor3ubEXT );
+ count_func( "SecondaryColor3ubv", &rmesa->vb.dfn_cache.SecondaryColor3ubvEXT );
+ count_func( "Normal3f", &rmesa->vb.dfn_cache.Normal3f );
+ count_func( "Normal3fv", &rmesa->vb.dfn_cache.Normal3fv );
+ count_func( "TexCoord2f", &rmesa->vb.dfn_cache.TexCoord2f );
+ count_func( "TexCoord2fv", &rmesa->vb.dfn_cache.TexCoord2fv );
+ count_func( "TexCoord1f", &rmesa->vb.dfn_cache.TexCoord1f );
+ count_func( "TexCoord1fv", &rmesa->vb.dfn_cache.TexCoord1fv );
+ count_func( "MultiTexCoord2fARB", &rmesa->vb.dfn_cache.MultiTexCoord2fARB );
+ count_func( "MultiTexCoord2fvARB", &rmesa->vb.dfn_cache.MultiTexCoord2fvARB );
+ count_func( "MultiTexCoord1fARB", &rmesa->vb.dfn_cache.MultiTexCoord1fARB );
+ count_func( "MultiTexCoord1fvARB", &rmesa->vb.dfn_cache.MultiTexCoord1fvARB );
+}
+
+
+void radeon_copy_to_current( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ assert(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT);
+
+ if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_N0) {
+ ctx->Current.Attrib[VERT_ATTRIB_NORMAL][0] = rmesa->vb.normalptr[0];
+ ctx->Current.Attrib[VERT_ATTRIB_NORMAL][1] = rmesa->vb.normalptr[1];
+ ctx->Current.Attrib[VERT_ATTRIB_NORMAL][2] = rmesa->vb.normalptr[2];
+ }
+
+ if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_PKCOLOR) {
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->red );
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->green );
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->blue );
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->alpha );
+ }
+
+ if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_FPCOLOR) {
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = rmesa->vb.floatcolorptr[0];
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = rmesa->vb.floatcolorptr[1];
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = rmesa->vb.floatcolorptr[2];
+ }
+
+ if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_FPALPHA)
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = rmesa->vb.floatcolorptr[3];
+
+ if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_PKSPEC) {
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR1][0] = UBYTE_TO_FLOAT( rmesa->vb.specptr->red );
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR1][1] = UBYTE_TO_FLOAT( rmesa->vb.specptr->green );
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR1][2] = UBYTE_TO_FLOAT( rmesa->vb.specptr->blue );
+ }
+
+ if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_ST0) {
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][0] = rmesa->vb.texcoordptr[0][0];
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][1] = rmesa->vb.texcoordptr[0][1];
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] = 0.0F;
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] = 1.0F;
+ }
+
+ if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_ST1) {
+ ctx->Current.Attrib[VERT_ATTRIB_TEX1][0] = rmesa->vb.texcoordptr[1][0];
+ ctx->Current.Attrib[VERT_ATTRIB_TEX1][1] = rmesa->vb.texcoordptr[1][1];
+ ctx->Current.Attrib[VERT_ATTRIB_TEX1][2] = 0.0F;
+ ctx->Current.Attrib[VERT_ATTRIB_TEX1][3] = 1.0F;
+ }
+
+ ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+}
+
+static GLboolean discreet_gl_prim[GL_POLYGON+1] = {
+ 1, /* 0 points */
+ 1, /* 1 lines */
+ 0, /* 2 line_strip */
+ 0, /* 3 line_loop */
+ 1, /* 4 tris */
+ 0, /* 5 tri_fan */
+ 0, /* 6 tri_strip */
+ 1, /* 7 quads */
+ 0, /* 8 quadstrip */
+ 0, /* 9 poly */
+};
+
+static void flush_prims( radeonContextPtr rmesa )
+{
+ int i,j;
+ struct radeon_dma_region tmp = rmesa->dma.current;
+
+ tmp.buf->refcount++;
+ tmp.aos_size = rmesa->vb.vertex_size;
+ tmp.aos_stride = rmesa->vb.vertex_size;
+ tmp.aos_start = GET_START(&tmp);
+
+ rmesa->dma.current.ptr = rmesa->dma.current.start +=
+ (rmesa->vb.initial_counter - rmesa->vb.counter) * rmesa->vb.vertex_size * 4;
+
+ rmesa->tcl.vertex_format = rmesa->vb.vertex_format;
+ rmesa->tcl.aos_components[0] = &tmp;
+ rmesa->tcl.nr_aos_components = 1;
+ rmesa->dma.flush = 0;
+
+ /* Optimize the primitive list:
+ */
+ if (rmesa->vb.nrprims > 1) {
+ for (j = 0, i = 1 ; i < rmesa->vb.nrprims; i++) {
+ int pj = rmesa->vb.primlist[j].prim & 0xf;
+ int pi = rmesa->vb.primlist[i].prim & 0xf;
+
+ if (pj == pi && discreet_gl_prim[pj] &&
+ rmesa->vb.primlist[i].start == rmesa->vb.primlist[j].end) {
+ rmesa->vb.primlist[j].end = rmesa->vb.primlist[i].end;
+ }
+ else {
+ j++;
+ if (j != i) rmesa->vb.primlist[j] = rmesa->vb.primlist[i];
+ }
+ }
+ rmesa->vb.nrprims = j+1;
+ }
+
+ for (i = 0 ; i < rmesa->vb.nrprims; i++) {
+ if (RADEON_DEBUG & DEBUG_PRIMS)
+ fprintf(stderr, "vtxfmt prim %d: %s %d..%d\n", i,
+ _mesa_lookup_enum_by_nr( rmesa->vb.primlist[i].prim &
+ PRIM_MODE_MASK ),
+ rmesa->vb.primlist[i].start,
+ rmesa->vb.primlist[i].end);
+
+ radeonEmitPrimitive( rmesa->glCtx,
+ rmesa->vb.primlist[i].start,
+ rmesa->vb.primlist[i].end,
+ rmesa->vb.primlist[i].prim );
+ }
+
+ rmesa->vb.nrprims = 0;
+ radeonReleaseDmaRegion( rmesa, &tmp, __FUNCTION__ );
+}
+
+
+static void start_prim( radeonContextPtr rmesa, GLuint mode )
+{
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s %d\n", __FUNCTION__, rmesa->vb.initial_counter - rmesa->vb.counter);
+
+ rmesa->vb.primlist[rmesa->vb.nrprims].start = rmesa->vb.initial_counter - rmesa->vb.counter;
+ rmesa->vb.primlist[rmesa->vb.nrprims].prim = mode;
+}
+
+static void note_last_prim( radeonContextPtr rmesa, GLuint flags )
+{
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s %d\n", __FUNCTION__, rmesa->vb.initial_counter - rmesa->vb.counter);
+
+ if (rmesa->vb.prim[0] != GL_POLYGON+1) {
+ rmesa->vb.primlist[rmesa->vb.nrprims].prim |= flags;
+ rmesa->vb.primlist[rmesa->vb.nrprims].end = rmesa->vb.initial_counter - rmesa->vb.counter;
+
+ if (++(rmesa->vb.nrprims) == RADEON_MAX_PRIMS)
+ flush_prims( rmesa );
+ }
+}
+
+
+static void copy_vertex( radeonContextPtr rmesa, GLuint n, GLfloat *dst )
+{
+ GLuint i;
+ GLfloat *src = (GLfloat *)(rmesa->dma.current.address +
+ rmesa->dma.current.ptr +
+ (rmesa->vb.primlist[rmesa->vb.nrprims].start + n) *
+ rmesa->vb.vertex_size * 4);
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "copy_vertex %d\n", rmesa->vb.primlist[rmesa->vb.nrprims].start + n);
+
+ for (i = 0 ; i < rmesa->vb.vertex_size; i++) {
+ dst[i] = src[i];
+ }
+}
+
+/* NOTE: This actually reads the copied vertices back from uncached
+ * memory. Could also use the counter/notify mechanism to populate
+ * tmp on the fly as vertices are generated.
+ */
+static GLuint copy_dma_verts( radeonContextPtr rmesa, GLfloat (*tmp)[15] )
+{
+ GLuint ovf, i;
+ GLuint nr = (rmesa->vb.initial_counter - rmesa->vb.counter) - rmesa->vb.primlist[rmesa->vb.nrprims].start;
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s %d verts\n", __FUNCTION__, nr);
+
+ switch( rmesa->vb.prim[0] )
+ {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr&1;
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ case GL_TRIANGLES:
+ ovf = nr%3;
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ case GL_QUADS:
+ ovf = nr&3;
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ case GL_LINE_STRIP:
+ if (nr == 0)
+ return 0;
+ copy_vertex( rmesa, nr-1, tmp[0] );
+ return 1;
+ case GL_LINE_LOOP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ if (nr == 0)
+ return 0;
+ else if (nr == 1) {
+ copy_vertex( rmesa, 0, tmp[0] );
+ return 1;
+ } else {
+ copy_vertex( rmesa, 0, tmp[0] );
+ copy_vertex( rmesa, nr-1, tmp[1] );
+ return 2;
+ }
+ case GL_TRIANGLE_STRIP:
+ ovf = MIN2(nr, 2);
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ case GL_QUAD_STRIP:
+ switch (nr) {
+ case 0: ovf = 0; break;
+ case 1: ovf = 1; break;
+ default: ovf = 2 + (nr&1); break;
+ }
+ for (i = 0 ; i < ovf ; i++)
+ copy_vertex( rmesa, nr-ovf+i, tmp[i] );
+ return i;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+static void VFMT_FALLBACK_OUTSIDE_BEGIN_END( const char *caller )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_FALLBACKS))
+ fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
+
+ if (ctx->Driver.NeedFlush)
+ radeonVtxfmtFlushVertices( ctx, ctx->Driver.NeedFlush );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx ); /* clear state so fell_back sticks */
+
+ _tnl_wakeup_exec( ctx );
+ ctx->Driver.FlushVertices = radeonFlushVertices;
+
+ assert( rmesa->dma.flush == 0 );
+ rmesa->vb.fell_back = GL_TRUE;
+ rmesa->vb.installed = GL_FALSE;
+}
+
+
+static void VFMT_FALLBACK( const char *caller )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat tmp[3][15];
+ GLuint i, prim;
+ GLuint ind = rmesa->vb.vertex_format;
+ GLuint nrverts;
+ GLfloat alpha = 1.0;
+
+ if (RADEON_DEBUG & (DEBUG_FALLBACKS|DEBUG_VFMT))
+ fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
+
+ if (rmesa->vb.prim[0] == GL_POLYGON+1) {
+ VFMT_FALLBACK_OUTSIDE_BEGIN_END( __FUNCTION__ );
+ return;
+ }
+
+ /* Copy vertices out of dma:
+ */
+ nrverts = copy_dma_verts( rmesa, tmp );
+
+ /* Finish the prim at this point:
+ */
+ note_last_prim( rmesa, 0 );
+ flush_prims( rmesa );
+
+ /* Update ctx->Driver.CurrentExecPrimitive and swap in swtnl.
+ */
+ prim = rmesa->vb.prim[0];
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+ _tnl_wakeup_exec( ctx );
+ ctx->Driver.FlushVertices = radeonFlushVertices;
+
+ assert(rmesa->dma.flush == 0);
+ rmesa->vb.fell_back = GL_TRUE;
+ rmesa->vb.installed = GL_FALSE;
+ glBegin( prim );
+
+ if (rmesa->vb.installed_color_3f_sz == 4)
+ alpha = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];
+
+ /* Replay saved vertices
+ */
+ for (i = 0 ; i < nrverts; i++) {
+ GLuint offset = 3;
+ if (ind & RADEON_CP_VC_FRMT_N0) {
+ glNormal3fv( &tmp[i][offset] );
+ offset += 3;
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_PKCOLOR) {
+ radeon_color_t *col = (radeon_color_t *)&tmp[i][offset];
+ glColor4ub( col->red, col->green, col->blue, col->alpha );
+ offset++;
+ }
+ else if (ind & RADEON_CP_VC_FRMT_FPALPHA) {
+ glColor4fv( &tmp[i][offset] );
+ offset+=4;
+ }
+ else if (ind & RADEON_CP_VC_FRMT_FPCOLOR) {
+ glColor3fv( &tmp[i][offset] );
+ offset+=3;
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_PKSPEC) {
+ radeon_color_t *spec = (radeon_color_t *)&tmp[i][offset];
+ _glapi_Dispatch->SecondaryColor3ubEXT( spec->red, spec->green, spec->blue );
+ offset++;
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_ST0) {
+ glTexCoord2fv( &tmp[i][offset] );
+ offset += 2;
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_ST1) {
+ glMultiTexCoord2fvARB( GL_TEXTURE1_ARB, &tmp[i][offset] );
+ offset += 2;
+ }
+ glVertex3fv( &tmp[i][0] );
+ }
+
+ /* Replay current vertex
+ */
+ if (ind & RADEON_CP_VC_FRMT_N0)
+ glNormal3fv( rmesa->vb.normalptr );
+
+ if (ind & RADEON_CP_VC_FRMT_PKCOLOR)
+ glColor4ub( rmesa->vb.colorptr->red, rmesa->vb.colorptr->green, rmesa->vb.colorptr->blue, rmesa->vb.colorptr->alpha );
+ else if (ind & RADEON_CP_VC_FRMT_FPALPHA)
+ glColor4fv( rmesa->vb.floatcolorptr );
+ else if (ind & RADEON_CP_VC_FRMT_FPCOLOR) {
+ if (rmesa->vb.installed_color_3f_sz == 4 && alpha != 1.0)
+ glColor4f( rmesa->vb.floatcolorptr[0],
+ rmesa->vb.floatcolorptr[1],
+ rmesa->vb.floatcolorptr[2],
+ alpha );
+ else
+ glColor3fv( rmesa->vb.floatcolorptr );
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_PKSPEC)
+ _glapi_Dispatch->SecondaryColor3ubEXT( rmesa->vb.specptr->red, rmesa->vb.specptr->green, rmesa->vb.specptr->blue );
+
+ if (ind & RADEON_CP_VC_FRMT_ST0)
+ glTexCoord2fv( rmesa->vb.texcoordptr[0] );
+
+ if (ind & RADEON_CP_VC_FRMT_ST1)
+ glMultiTexCoord2fvARB( GL_TEXTURE1_ARB, rmesa->vb.texcoordptr[1] );
+}
+
+
+
+static void wrap_buffer( void )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat tmp[3][15];
+ GLuint i, nrverts;
+
+ if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_PRIMS))
+ fprintf(stderr, "%s %d\n", __FUNCTION__, rmesa->vb.initial_counter - rmesa->vb.counter);
+
+ /* Don't deal with parity.
+ */
+ if ((((rmesa->vb.initial_counter - rmesa->vb.counter) -
+ rmesa->vb.primlist[rmesa->vb.nrprims].start) & 1)) {
+ rmesa->vb.counter++;
+ rmesa->vb.initial_counter++;
+ return;
+ }
+
+ /* Copy vertices out of dma:
+ */
+ if (rmesa->vb.prim[0] == GL_POLYGON+1)
+ nrverts = 0;
+ else {
+ nrverts = copy_dma_verts( rmesa, tmp );
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%d vertices to copy\n", nrverts);
+
+ /* Finish the prim at this point:
+ */
+ note_last_prim( rmesa, 0 );
+ }
+
+ /* Fire any buffered primitives
+ */
+ flush_prims( rmesa );
+
+ /* Get new buffer
+ */
+ radeonRefillCurrentDmaRegion( rmesa );
+
+ /* Reset counter, dmaptr
+ */
+ rmesa->vb.dmaptr = (int *)(rmesa->dma.current.ptr + rmesa->dma.current.address);
+ rmesa->vb.counter = (rmesa->dma.current.end - rmesa->dma.current.ptr) /
+ (rmesa->vb.vertex_size * 4);
+ rmesa->vb.counter--;
+ rmesa->vb.initial_counter = rmesa->vb.counter;
+ rmesa->vb.notify = wrap_buffer;
+
+ rmesa->dma.flush = flush_prims;
+
+ /* Restart wrapped primitive:
+ */
+ if (rmesa->vb.prim[0] != GL_POLYGON+1)
+ start_prim( rmesa, rmesa->vb.prim[0] );
+
+ /* Reemit saved vertices
+ */
+ for (i = 0 ; i < nrverts; i++) {
+ if (RADEON_DEBUG & DEBUG_VERTS) {
+ int j;
+ fprintf(stderr, "re-emit vertex %d to %p\n", i, rmesa->vb.dmaptr);
+ if (RADEON_DEBUG & DEBUG_VERBOSE)
+ for (j = 0 ; j < rmesa->vb.vertex_size; j++)
+ fprintf(stderr, "\t%08x/%f\n", *(int*)&tmp[i][j], tmp[i][j]);
+ }
+
+ memcpy( rmesa->vb.dmaptr, tmp[i], rmesa->vb.vertex_size * 4 );
+ rmesa->vb.dmaptr += rmesa->vb.vertex_size;
+ rmesa->vb.counter--;
+ }
+}
+
+
+
+static GLboolean check_vtx_fmt( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint ind = RADEON_CP_VC_FRMT_Z;
+
+ if (rmesa->TclFallback || rmesa->vb.fell_back || ctx->CompileFlag)
+ return GL_FALSE;
+
+ if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)
+ ctx->Driver.FlushVertices( ctx, FLUSH_UPDATE_CURRENT );
+
+ /* Make all this event-driven:
+ */
+ if (ctx->Light.Enabled) {
+ ind |= RADEON_CP_VC_FRMT_N0;
+
+ /* TODO: make this data driven: If we receive only ubytes, send
+ * color as ubytes. Also check if converting (with free
+ * checking for overflow) is cheaper than sending floats
+ * directly.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ ind |= (RADEON_CP_VC_FRMT_FPCOLOR |
+ RADEON_CP_VC_FRMT_FPALPHA);
+ }
+ else
+ ind |= RADEON_CP_VC_FRMT_PKCOLOR; /* for alpha? */
+ }
+ else {
+ /* TODO: make this data driven?
+ */
+ ind |= RADEON_CP_VC_FRMT_PKCOLOR;
+
+ if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
+ ind |= RADEON_CP_VC_FRMT_PKSPEC;
+ }
+ }
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled) {
+ if (ctx->Texture.Unit[0].TexGenEnabled) {
+ if (rmesa->TexGenNeedNormals[0]) {
+ ind |= RADEON_CP_VC_FRMT_N0;
+ }
+ } else {
+ if (ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] != 0.0F ||
+ ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] != 1.0) {
+ if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_FALLBACKS))
+ fprintf(stderr, "%s: rq0\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+ ind |= RADEON_CP_VC_FRMT_ST0;
+ }
+ }
+
+ if (ctx->Texture.Unit[1]._ReallyEnabled) {
+ if (ctx->Texture.Unit[1].TexGenEnabled) {
+ if (rmesa->TexGenNeedNormals[1]) {
+ ind |= RADEON_CP_VC_FRMT_N0;
+ }
+ } else {
+ if (ctx->Current.Attrib[VERT_ATTRIB_TEX1][2] != 0.0F ||
+ ctx->Current.Attrib[VERT_ATTRIB_TEX1][3] != 1.0) {
+ if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_FALLBACKS))
+ fprintf(stderr, "%s: rq1\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+ ind |= RADEON_CP_VC_FRMT_ST1;
+ }
+ }
+
+ if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_STATE))
+ fprintf(stderr, "%s: format: 0x%x\n", __FUNCTION__, ind );
+
+ RADEON_NEWPRIM(rmesa);
+ rmesa->vb.vertex_format = ind;
+ rmesa->vb.vertex_size = 3;
+ rmesa->vb.prim = &ctx->Driver.CurrentExecPrimitive;
+
+ rmesa->vb.normalptr = ctx->Current.Attrib[VERT_ATTRIB_NORMAL];
+ rmesa->vb.colorptr = NULL;
+ rmesa->vb.floatcolorptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
+ rmesa->vb.specptr = NULL;
+ rmesa->vb.floatspecptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR1];
+ rmesa->vb.texcoordptr[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
+ rmesa->vb.texcoordptr[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX1];
+
+ /* Run through and initialize the vertex components in the order
+ * the hardware understands:
+ */
+ if (ind & RADEON_CP_VC_FRMT_N0) {
+ rmesa->vb.normalptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].f;
+ rmesa->vb.vertex_size += 3;
+ rmesa->vb.normalptr[0] = ctx->Current.Attrib[VERT_ATTRIB_NORMAL][0];
+ rmesa->vb.normalptr[1] = ctx->Current.Attrib[VERT_ATTRIB_NORMAL][1];
+ rmesa->vb.normalptr[2] = ctx->Current.Attrib[VERT_ATTRIB_NORMAL][2];
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_PKCOLOR) {
+ rmesa->vb.colorptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].color;
+ rmesa->vb.vertex_size += 1;
+ UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->red, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] );
+ UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->green, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] );
+ UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->blue, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] );
+ UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->alpha, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] );
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_FPCOLOR) {
+ assert(!(ind & RADEON_CP_VC_FRMT_PKCOLOR));
+ rmesa->vb.floatcolorptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].f;
+ rmesa->vb.vertex_size += 3;
+ rmesa->vb.floatcolorptr[0] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0];
+ rmesa->vb.floatcolorptr[1] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1];
+ rmesa->vb.floatcolorptr[2] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2];
+
+ if (ind & RADEON_CP_VC_FRMT_FPALPHA) {
+ rmesa->vb.vertex_size += 1;
+ rmesa->vb.floatcolorptr[3] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];
+ }
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_PKSPEC) {
+ rmesa->vb.specptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].color;
+ rmesa->vb.vertex_size += 1;
+ UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.specptr->red, ctx->Current.Attrib[VERT_ATTRIB_COLOR1][0] );
+ UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.specptr->green, ctx->Current.Attrib[VERT_ATTRIB_COLOR1][1] );
+ UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.specptr->blue, ctx->Current.Attrib[VERT_ATTRIB_COLOR1][2] );
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_ST0) {
+ rmesa->vb.texcoordptr[0] = &rmesa->vb.vertex[rmesa->vb.vertex_size].f;
+ rmesa->vb.vertex_size += 2;
+ rmesa->vb.texcoordptr[0][0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0];
+ rmesa->vb.texcoordptr[0][1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1];
+ }
+
+ if (ind & RADEON_CP_VC_FRMT_ST1) {
+ rmesa->vb.texcoordptr[1] = &rmesa->vb.vertex[rmesa->vb.vertex_size].f;
+ rmesa->vb.vertex_size += 2;
+ rmesa->vb.texcoordptr[1][0] = ctx->Current.Attrib[VERT_ATTRIB_TEX1][0];
+ rmesa->vb.texcoordptr[1][1] = ctx->Current.Attrib[VERT_ATTRIB_TEX1][1];
+ }
+
+ if (rmesa->vb.installed_vertex_format != rmesa->vb.vertex_format) {
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "reinstall on vertex_format change\n");
+ _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt );
+ rmesa->vb.installed_vertex_format = rmesa->vb.vertex_format;
+ }
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s -- success\n", __FUNCTION__);
+
+ return GL_TRUE;
+}
+
+void radeonVtxfmtInvalidate( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ rmesa->vb.recheck = GL_TRUE;
+ rmesa->vb.fell_back = GL_FALSE;
+}
+
+
+static void radeonNewList( GLcontext *ctx, GLuint list, GLenum mode )
+{
+ VFMT_FALLBACK_OUTSIDE_BEGIN_END( __FUNCTION__ );
+}
+
+
+static void radeonVtxfmtValidate( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (ctx->Driver.NeedFlush)
+ ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush );
+
+ rmesa->vb.recheck = GL_FALSE;
+
+ if (check_vtx_fmt( ctx )) {
+ if (!rmesa->vb.installed) {
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "reinstall (new install)\n");
+
+ _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt );
+ ctx->Driver.FlushVertices = radeonVtxfmtFlushVertices;
+ ctx->Driver.NewList = radeonNewList;
+ rmesa->vb.installed = GL_TRUE;
+ }
+ else if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s: already installed", __FUNCTION__);
+ }
+ else {
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s: failed\n", __FUNCTION__);
+
+ if (rmesa->vb.installed) {
+ if (rmesa->dma.flush)
+ rmesa->dma.flush( rmesa );
+ _tnl_wakeup_exec( ctx );
+ ctx->Driver.FlushVertices = radeonFlushVertices;
+ rmesa->vb.installed = GL_FALSE;
+ }
+ }
+}
+
+
+
+/* Materials:
+ */
+static void radeon_Materialfv( GLenum face, GLenum pname,
+ const GLfloat *params )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (rmesa->vb.prim[0] != GL_POLYGON+1) {
+ VFMT_FALLBACK( __FUNCTION__ );
+ glMaterialfv( face, pname, params );
+ return;
+ }
+ _mesa_noop_Materialfv( face, pname, params );
+ radeonUpdateMaterial( ctx );
+}
+
+
+/* Begin/End
+ */
+static void radeon_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s( %s )\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr( mode ));
+
+ if (mode > GL_POLYGON) {
+ _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
+ return;
+ }
+
+ if (rmesa->vb.prim[0] != GL_POLYGON+1) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+ return;
+ }
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (rmesa->NewGLState)
+ radeonValidateState( ctx );
+
+ if (rmesa->vb.recheck)
+ radeonVtxfmtValidate( ctx );
+
+ if (!rmesa->vb.installed) {
+ glBegin( mode );
+ return;
+ }
+
+
+ if (rmesa->dma.flush && rmesa->vb.counter < 12) {
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s: flush almost-empty buffers\n", __FUNCTION__);
+ flush_prims( rmesa );
+ }
+
+ /* Need to arrange to save vertices here? Or always copy from dma (yuk)?
+ */
+ if (!rmesa->dma.flush) {
+ if (rmesa->dma.current.ptr + 12*rmesa->vb.vertex_size*4 >
+ rmesa->dma.current.end) {
+ RADEON_NEWPRIM( rmesa );
+ radeonRefillCurrentDmaRegion( rmesa );
+ }
+
+ rmesa->vb.dmaptr = (int *)(rmesa->dma.current.address + rmesa->dma.current.ptr);
+ rmesa->vb.counter = (rmesa->dma.current.end - rmesa->dma.current.ptr) /
+ (rmesa->vb.vertex_size * 4);
+ rmesa->vb.counter--;
+ rmesa->vb.initial_counter = rmesa->vb.counter;
+ rmesa->vb.notify = wrap_buffer;
+ rmesa->dma.flush = flush_prims;
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ }
+
+
+ rmesa->vb.prim[0] = mode;
+ start_prim( rmesa, mode | PRIM_BEGIN );
+}
+
+
+
+static void radeon_End( void )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (rmesa->vb.prim[0] == GL_POLYGON+1) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+ return;
+ }
+
+ note_last_prim( rmesa, PRIM_END );
+ rmesa->vb.prim[0] = GL_POLYGON+1;
+}
+
+
+/* Fallback on difficult entrypoints:
+ */
+#define PRE_LOOPBACK( FUNC ) \
+do { \
+ if (RADEON_DEBUG & DEBUG_VFMT) \
+ fprintf(stderr, "%s\n", __FUNCTION__); \
+ VFMT_FALLBACK( __FUNCTION__ ); \
+} while (0)
+#define TAG(x) radeon_fallback_##x
+#include "vtxfmt_tmp.h"
+
+
+
+static GLboolean radeonNotifyBegin( GLcontext *ctx, GLenum p )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ assert(!rmesa->vb.installed);
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (rmesa->NewGLState)
+ radeonValidateState( ctx );
+
+ if (ctx->Driver.NeedFlush)
+ ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush );
+
+ if (rmesa->vb.recheck)
+ radeonVtxfmtValidate( ctx );
+
+ if (!rmesa->vb.installed) {
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s -- failed\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+
+ radeon_Begin( p );
+ return GL_TRUE;
+}
+
+static void radeonVtxfmtFlushVertices( GLcontext *ctx, GLuint flags )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ assert(rmesa->vb.installed);
+
+ if (flags & FLUSH_UPDATE_CURRENT) {
+ radeon_copy_to_current( ctx );
+ if (RADEON_DEBUG & DEBUG_VFMT)
+ fprintf(stderr, "reinstall on update_current\n");
+ _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt );
+ ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+ }
+
+ if (flags & FLUSH_STORED_VERTICES) {
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ assert (rmesa->dma.flush == 0 ||
+ rmesa->dma.flush == flush_prims);
+ if (rmesa->dma.flush == flush_prims)
+ flush_prims( RADEON_CONTEXT( ctx ) );
+ ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
+ }
+}
+
+
+
+/* At this point, don't expect very many versions of each function to
+ * be generated, so not concerned about freeing them?
+ */
+
+
+void radeonVtxfmtInit( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+ GLvertexformat *vfmt = &(rmesa->vb.vtxfmt);
+
+ MEMSET( vfmt, 0, sizeof(GLvertexformat) );
+
+ /* Hook in chooser functions for codegen, etc:
+ */
+ radeonVtxfmtInitChoosers( vfmt );
+
+ /* Handled fully in supported states, but no codegen:
+ */
+ vfmt->Materialfv = radeon_Materialfv;
+ vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
+ vfmt->Rectf = _mesa_noop_Rectf; /* generic helper */
+ vfmt->Begin = radeon_Begin;
+ vfmt->End = radeon_End;
+
+ /* Fallback for performance reasons: (Fix with cva/elt path here and
+ * dmatmp2.h style primitive-merging)
+ *
+ * These should call NotifyBegin(), as should _tnl_EvalMesh, to allow
+ * a driver-hook.
+ */
+ vfmt->DrawArrays = radeon_fallback_DrawArrays;
+ vfmt->DrawElements = radeon_fallback_DrawElements;
+ vfmt->DrawRangeElements = radeon_fallback_DrawRangeElements;
+
+
+ /* Not active in supported states; just keep ctx->Current uptodate:
+ */
+ vfmt->FogCoordfvEXT = _mesa_noop_FogCoordfvEXT;
+ vfmt->FogCoordfEXT = _mesa_noop_FogCoordfEXT;
+ vfmt->EdgeFlag = _mesa_noop_EdgeFlag;
+ vfmt->EdgeFlagv = _mesa_noop_EdgeFlagv;
+ vfmt->Indexi = _mesa_noop_Indexi;
+ vfmt->Indexiv = _mesa_noop_Indexiv;
+
+
+ /* Active but unsupported -- fallback if we receive these:
+ */
+ vfmt->CallList = radeon_fallback_CallList;
+ vfmt->EvalCoord1f = radeon_fallback_EvalCoord1f;
+ vfmt->EvalCoord1fv = radeon_fallback_EvalCoord1fv;
+ vfmt->EvalCoord2f = radeon_fallback_EvalCoord2f;
+ vfmt->EvalCoord2fv = radeon_fallback_EvalCoord2fv;
+ vfmt->EvalMesh1 = radeon_fallback_EvalMesh1;
+ vfmt->EvalMesh2 = radeon_fallback_EvalMesh2;
+ vfmt->EvalPoint1 = radeon_fallback_EvalPoint1;
+ vfmt->EvalPoint2 = radeon_fallback_EvalPoint2;
+ vfmt->TexCoord3f = radeon_fallback_TexCoord3f;
+ vfmt->TexCoord3fv = radeon_fallback_TexCoord3fv;
+ vfmt->TexCoord4f = radeon_fallback_TexCoord4f;
+ vfmt->TexCoord4fv = radeon_fallback_TexCoord4fv;
+ vfmt->MultiTexCoord3fARB = radeon_fallback_MultiTexCoord3fARB;
+ vfmt->MultiTexCoord3fvARB = radeon_fallback_MultiTexCoord3fvARB;
+ vfmt->MultiTexCoord4fARB = radeon_fallback_MultiTexCoord4fARB;
+ vfmt->MultiTexCoord4fvARB = radeon_fallback_MultiTexCoord4fvARB;
+ vfmt->Vertex4f = radeon_fallback_Vertex4f;
+ vfmt->Vertex4fv = radeon_fallback_Vertex4fv;
+
+ (void)radeon_fallback_vtxfmt;
+
+ TNL_CONTEXT(ctx)->Driver.NotifyBegin = radeonNotifyBegin;
+
+ rmesa->vb.enabled = 1;
+ rmesa->vb.prim = &ctx->Driver.CurrentExecPrimitive;
+ rmesa->vb.primflags = 0;
+
+ make_empty_list( &rmesa->vb.dfn_cache.Vertex2f );
+ make_empty_list( &rmesa->vb.dfn_cache.Vertex2fv );
+ make_empty_list( &rmesa->vb.dfn_cache.Vertex3f );
+ make_empty_list( &rmesa->vb.dfn_cache.Vertex3fv );
+ make_empty_list( &rmesa->vb.dfn_cache.Color4ub );
+ make_empty_list( &rmesa->vb.dfn_cache.Color4ubv );
+ make_empty_list( &rmesa->vb.dfn_cache.Color3ub );
+ make_empty_list( &rmesa->vb.dfn_cache.Color3ubv );
+ make_empty_list( &rmesa->vb.dfn_cache.Color4f );
+ make_empty_list( &rmesa->vb.dfn_cache.Color4fv );
+ make_empty_list( &rmesa->vb.dfn_cache.Color3f );
+ make_empty_list( &rmesa->vb.dfn_cache.Color3fv );
+ make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3fEXT );
+ make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3fvEXT );
+ make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3ubEXT );
+ make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3ubvEXT );
+ make_empty_list( &rmesa->vb.dfn_cache.Normal3f );
+ make_empty_list( &rmesa->vb.dfn_cache.Normal3fv );
+ make_empty_list( &rmesa->vb.dfn_cache.TexCoord2f );
+ make_empty_list( &rmesa->vb.dfn_cache.TexCoord2fv );
+ make_empty_list( &rmesa->vb.dfn_cache.TexCoord1f );
+ make_empty_list( &rmesa->vb.dfn_cache.TexCoord1fv );
+ make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord2fARB );
+ make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord2fvARB );
+ make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord1fARB );
+ make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord1fvARB );
+
+ radeonInitCodegen( &rmesa->vb.codegen );
+}
+
+static void free_funcs( struct dynfn *l )
+{
+ struct dynfn *f, *tmp;
+ foreach_s (f, tmp, l) {
+ remove_from_list( f );
+ ALIGN_FREE( f->code );
+ FREE( f );
+ }
+}
+
+
+
+void radeonVtxfmtMakeCurrent( GLcontext *ctx )
+{
+}
+
+
+void radeonVtxfmtDestroy( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
+
+ count_funcs( rmesa );
+ free_funcs( &rmesa->vb.dfn_cache.Vertex2f );
+ free_funcs( &rmesa->vb.dfn_cache.Vertex2fv );
+ free_funcs( &rmesa->vb.dfn_cache.Vertex3f );
+ free_funcs( &rmesa->vb.dfn_cache.Vertex3fv );
+ free_funcs( &rmesa->vb.dfn_cache.Color4ub );
+ free_funcs( &rmesa->vb.dfn_cache.Color4ubv );
+ free_funcs( &rmesa->vb.dfn_cache.Color3ub );
+ free_funcs( &rmesa->vb.dfn_cache.Color3ubv );
+ free_funcs( &rmesa->vb.dfn_cache.Color4f );
+ free_funcs( &rmesa->vb.dfn_cache.Color4fv );
+ free_funcs( &rmesa->vb.dfn_cache.Color3f );
+ free_funcs( &rmesa->vb.dfn_cache.Color3fv );
+ free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3ubEXT );
+ free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3ubvEXT );
+ free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3fEXT );
+ free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3fvEXT );
+ free_funcs( &rmesa->vb.dfn_cache.Normal3f );
+ free_funcs( &rmesa->vb.dfn_cache.Normal3fv );
+ free_funcs( &rmesa->vb.dfn_cache.TexCoord2f );
+ free_funcs( &rmesa->vb.dfn_cache.TexCoord2fv );
+ free_funcs( &rmesa->vb.dfn_cache.TexCoord1f );
+ free_funcs( &rmesa->vb.dfn_cache.TexCoord1fv );
+ free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord2fARB );
+ free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord2fvARB );
+ free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord1fARB );
+ free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord1fvARB );
+}
+
diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt.h b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.h
new file mode 100644
index 0000000000..9792fcbb78
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.h
@@ -0,0 +1,124 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_vtxfmt.h,v 1.3 2002/12/21 17:02:16 dawes Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Cedar Park, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#ifndef __RADEON_VTXFMT_H__
+#define __RADEON_VTXFMT_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "radeon_context.h"
+
+
+extern void radeonVtxfmtUpdate( GLcontext *ctx );
+extern void radeonVtxfmtInit( GLcontext *ctx );
+extern void radeonVtxfmtInvalidate( GLcontext *ctx );
+extern void radeonVtxfmtDestroy( GLcontext *ctx );
+extern void radeonVtxfmtInitChoosers( GLvertexformat *vfmt );
+
+extern void radeonVtxfmtMakeCurrent( GLcontext *ctx );
+extern void radeonVtxfmtUnbindContext( GLcontext *ctx );
+
+extern void radeon_copy_to_current( GLcontext *ctx );
+
+#define DFN( FUNC, CACHE) \
+do { \
+ char *start = (char *)&FUNC; \
+ char *end = (char *)&FUNC##_end; \
+ insert_at_head( &CACHE, dfn ); \
+ dfn->key = key; \
+ dfn->code = ALIGN_MALLOC( end - start, 16 ); \
+ memcpy (dfn->code, start, end - start); \
+} \
+while ( 0 )
+
+#define FIXUP( CODE, OFFSET, CHECKVAL, NEWVAL ) \
+do { \
+ int *icode = (int *)(CODE+OFFSET); \
+ assert (*icode == CHECKVAL); \
+ *icode = (int)NEWVAL; \
+} while (0)
+
+
+/* Useful for figuring out the offsets:
+ */
+#define FIXUP2( CODE, OFFSET, CHECKVAL, NEWVAL ) \
+do { \
+ while (*(int *)(CODE+OFFSET) != CHECKVAL) OFFSET++; \
+ fprintf(stderr, "%s/%d CVAL %x OFFSET %d VAL %x\n", __FUNCTION__, \
+ __LINE__, CHECKVAL, OFFSET, (int)(NEWVAL)); \
+ *(int *)(CODE+OFFSET) = (int)(NEWVAL); \
+ OFFSET += 4; \
+} while (0)
+
+/*
+ */
+void radeonInitCodegen( struct dfn_generators *gen );
+void radeonInitX86Codegen( struct dfn_generators *gen );
+void radeonInitSSECodegen( struct dfn_generators *gen );
+
+
+
+/* Defined in radeon_vtxfmt_x86.c
+ */
+struct dynfn *radeon_makeX86Vertex2f( GLcontext *, int );
+struct dynfn *radeon_makeX86Vertex2fv( GLcontext *, int );
+struct dynfn *radeon_makeX86Vertex3f( GLcontext *, int );
+struct dynfn *radeon_makeX86Vertex3fv( GLcontext *, int );
+struct dynfn *radeon_makeX86Color4ub( GLcontext *, int );
+struct dynfn *radeon_makeX86Color4ubv( GLcontext *, int );
+struct dynfn *radeon_makeX86Color3ub( GLcontext *, int );
+struct dynfn *radeon_makeX86Color3ubv( GLcontext *, int );
+struct dynfn *radeon_makeX86Color4f( GLcontext *, int );
+struct dynfn *radeon_makeX86Color4fv( GLcontext *, int );
+struct dynfn *radeon_makeX86Color3f( GLcontext *, int );
+struct dynfn *radeon_makeX86Color3fv( GLcontext *, int );
+struct dynfn *radeon_makeX86SecondaryColor3ubEXT( GLcontext *, int );
+struct dynfn *radeon_makeX86SecondaryColor3ubvEXT( GLcontext *, int );
+struct dynfn *radeon_makeX86SecondaryColor3fEXT( GLcontext *, int );
+struct dynfn *radeon_makeX86SecondaryColor3fvEXT( GLcontext *, int );
+struct dynfn *radeon_makeX86Normal3f( GLcontext *, int );
+struct dynfn *radeon_makeX86Normal3fv( GLcontext *, int );
+struct dynfn *radeon_makeX86TexCoord2f( GLcontext *, int );
+struct dynfn *radeon_makeX86TexCoord2fv( GLcontext *, int );
+struct dynfn *radeon_makeX86TexCoord1f( GLcontext *, int );
+struct dynfn *radeon_makeX86TexCoord1fv( GLcontext *, int );
+struct dynfn *radeon_makeX86MultiTexCoord2fARB( GLcontext *, int );
+struct dynfn *radeon_makeX86MultiTexCoord2fvARB( GLcontext *, int );
+struct dynfn *radeon_makeX86MultiTexCoord1fARB( GLcontext *, int );
+struct dynfn *radeon_makeX86MultiTexCoord1fvARB( GLcontext *, int );
+
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt_c.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_c.c
new file mode 100644
index 0000000000..188e34a420
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_c.c
@@ -0,0 +1,905 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2002 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Cedar Park, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+#include "glheader.h"
+#include "mtypes.h"
+#include "colormac.h"
+#include "simple_list.h"
+#include "api_noop.h"
+#include "vtxfmt.h"
+
+#include "radeon_vtxfmt.h"
+
+/* Fallback versions of all the entrypoints for situations where
+ * codegen isn't available. This is still a lot faster than the
+ * vb/pipeline implementation in Mesa.
+ */
+static void radeon_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ int i;
+
+ *rmesa->vb.dmaptr++ = *(int *)&x;
+ *rmesa->vb.dmaptr++ = *(int *)&y;
+ *rmesa->vb.dmaptr++ = *(int *)&z;
+
+ for (i = 3; i < rmesa->vb.vertex_size; i++)
+ *rmesa->vb.dmaptr++ = rmesa->vb.vertex[i].i;
+
+ if (--rmesa->vb.counter == 0)
+ rmesa->vb.notify();
+}
+
+
+static void radeon_Vertex3fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ int i;
+
+ *rmesa->vb.dmaptr++ = *(int *)&v[0];
+ *rmesa->vb.dmaptr++ = *(int *)&v[1];
+ *rmesa->vb.dmaptr++ = *(int *)&v[2];
+
+ for (i = 3; i < rmesa->vb.vertex_size; i++)
+ *rmesa->vb.dmaptr++ = rmesa->vb.vertex[i].i;
+
+ if (--rmesa->vb.counter == 0)
+ rmesa->vb.notify();
+}
+
+
+static void radeon_Vertex2f( GLfloat x, GLfloat y )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ int i;
+
+ *rmesa->vb.dmaptr++ = *(int *)&x;
+ *rmesa->vb.dmaptr++ = *(int *)&y;
+ *rmesa->vb.dmaptr++ = 0;
+
+ for (i = 3; i < rmesa->vb.vertex_size; i++)
+ *rmesa->vb.dmaptr++ = *(int *)&rmesa->vb.vertex[i];
+
+ if (--rmesa->vb.counter == 0)
+ rmesa->vb.notify();
+}
+
+
+static void radeon_Vertex2fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ int i;
+
+ *rmesa->vb.dmaptr++ = *(int *)&v[0];
+ *rmesa->vb.dmaptr++ = *(int *)&v[1];
+ *rmesa->vb.dmaptr++ = 0;
+
+ for (i = 3; i < rmesa->vb.vertex_size; i++)
+ *rmesa->vb.dmaptr++ = rmesa->vb.vertex[i].i;
+
+ if (--rmesa->vb.counter == 0)
+ rmesa->vb.notify();
+}
+
+
+
+/* Color for ubyte (packed) color formats:
+ */
+static void radeon_Color3ub_ub( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.colorptr;
+ dest->red = r;
+ dest->green = g;
+ dest->blue = b;
+ dest->alpha = 0xff;
+}
+
+static void radeon_Color3ubv_ub( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.colorptr;
+ dest->red = v[0];
+ dest->green = v[1];
+ dest->blue = v[2];
+ dest->alpha = 0xff;
+}
+
+static void radeon_Color4ub_ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.colorptr;
+ dest->red = r;
+ dest->green = g;
+ dest->blue = b;
+ dest->alpha = a;
+}
+
+static void radeon_Color4ubv_ub( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ *(GLuint *)rmesa->vb.colorptr = LE32_TO_CPU(*(GLuint *)v);
+}
+
+
+static void radeon_Color3f_ub( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.colorptr;
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->red, r );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->green, g );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, b );
+ dest->alpha = 255;
+}
+
+static void radeon_Color3fv_ub( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.colorptr;
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->red, v[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->green, v[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, v[2] );
+ dest->alpha = 255;
+}
+
+static void radeon_Color4f_ub( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.colorptr;
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->red, r );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->green, g );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, b );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->alpha, a );
+}
+
+static void radeon_Color4fv_ub( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.colorptr;
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->red, v[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->green, v[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, v[2] );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->alpha, v[3] );
+}
+
+
+/* Color for float color+alpha formats:
+ */
+static void radeon_Color3ub_4f( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(r);
+ dest[1] = UBYTE_TO_FLOAT(g);
+ dest[2] = UBYTE_TO_FLOAT(b);
+ dest[3] = 1.0;
+}
+
+static void radeon_Color3ubv_4f( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(v[0]);
+ dest[1] = UBYTE_TO_FLOAT(v[1]);
+ dest[2] = UBYTE_TO_FLOAT(v[2]);
+ dest[3] = 1.0;
+}
+
+static void radeon_Color4ub_4f( GLubyte r, GLubyte g, GLubyte b, GLubyte a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(r);
+ dest[1] = UBYTE_TO_FLOAT(g);
+ dest[2] = UBYTE_TO_FLOAT(b);
+ dest[3] = UBYTE_TO_FLOAT(a);
+}
+
+static void radeon_Color4ubv_4f( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(v[0]);
+ dest[1] = UBYTE_TO_FLOAT(v[1]);
+ dest[2] = UBYTE_TO_FLOAT(v[2]);
+ dest[3] = UBYTE_TO_FLOAT(v[3]);
+}
+
+
+static void radeon_Color3f_4f( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = r;
+ dest[1] = g;
+ dest[2] = b;
+ dest[3] = 1.0;
+}
+
+static void radeon_Color3fv_4f( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+ dest[3] = 1.0;
+}
+
+static void radeon_Color4f_4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = r;
+ dest[1] = g;
+ dest[2] = b;
+ dest[3] = a;
+}
+
+static void radeon_Color4fv_4f( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+ dest[3] = v[3];
+}
+
+
+/* Color for float color formats:
+ */
+static void radeon_Color3ub_3f( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(r);
+ dest[1] = UBYTE_TO_FLOAT(g);
+ dest[2] = UBYTE_TO_FLOAT(b);
+}
+
+static void radeon_Color3ubv_3f( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(v[0]);
+ dest[1] = UBYTE_TO_FLOAT(v[1]);
+ dest[2] = UBYTE_TO_FLOAT(v[2]);
+}
+
+static void radeon_Color4ub_3f( GLubyte r, GLubyte g, GLubyte b, GLubyte a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(r);
+ dest[1] = UBYTE_TO_FLOAT(g);
+ dest[2] = UBYTE_TO_FLOAT(b);
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = UBYTE_TO_FLOAT(a);
+}
+
+static void radeon_Color4ubv_3f( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = UBYTE_TO_FLOAT(v[0]);
+ dest[1] = UBYTE_TO_FLOAT(v[1]);
+ dest[2] = UBYTE_TO_FLOAT(v[2]);
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = UBYTE_TO_FLOAT(v[3]);
+}
+
+
+static void radeon_Color3f_3f( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = r;
+ dest[1] = g;
+ dest[2] = b;
+}
+
+static void radeon_Color3fv_3f( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+}
+
+static void radeon_Color4f_3f( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = r;
+ dest[1] = g;
+ dest[2] = b;
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = a;
+}
+
+static void radeon_Color4fv_3f( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatcolorptr;
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = v[3];
+}
+
+
+/* Secondary Color:
+ */
+static void radeon_SecondaryColor3ubEXT_ub( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.specptr;
+ dest->red = r;
+ dest->green = g;
+ dest->blue = b;
+ dest->alpha = 0xff;
+}
+
+static void radeon_SecondaryColor3ubvEXT_ub( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.specptr;
+ dest->red = v[0];
+ dest->green = v[1];
+ dest->blue = v[2];
+ dest->alpha = 0xff;
+}
+
+static void radeon_SecondaryColor3fEXT_ub( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.specptr;
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->red, r );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->green, g );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, b );
+ dest->alpha = 255;
+}
+
+static void radeon_SecondaryColor3fvEXT_ub( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeon_color_t *dest = rmesa->vb.specptr;
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->red, v[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->green, v[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, v[2] );
+ dest->alpha = 255;
+}
+
+static void radeon_SecondaryColor3ubEXT_3f( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatspecptr;
+ dest[0] = UBYTE_TO_FLOAT(r);
+ dest[1] = UBYTE_TO_FLOAT(g);
+ dest[2] = UBYTE_TO_FLOAT(b);
+ dest[3] = 1.0;
+}
+
+static void radeon_SecondaryColor3ubvEXT_3f( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatspecptr;
+ dest[0] = UBYTE_TO_FLOAT(v[0]);
+ dest[1] = UBYTE_TO_FLOAT(v[1]);
+ dest[2] = UBYTE_TO_FLOAT(v[2]);
+ dest[3] = 1.0;
+}
+
+static void radeon_SecondaryColor3fEXT_3f( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatspecptr;
+ dest[0] = r;
+ dest[1] = g;
+ dest[2] = b;
+ dest[3] = 1.0;
+}
+
+static void radeon_SecondaryColor3fvEXT_3f( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.floatspecptr;
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+ dest[3] = 1.0;
+}
+
+
+/* Normal
+ */
+static void radeon_Normal3f( GLfloat n0, GLfloat n1, GLfloat n2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.normalptr;
+ dest[0] = n0;
+ dest[1] = n1;
+ dest[2] = n2;
+}
+
+static void radeon_Normal3fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.normalptr;
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+}
+
+
+/* TexCoord
+ */
+static void radeon_TexCoord1f( GLfloat s )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[0];
+ dest[0] = s;
+ dest[1] = 0;
+}
+
+static void radeon_TexCoord1fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[0];
+ dest[0] = v[0];
+ dest[1] = 0;
+}
+
+static void radeon_TexCoord2f( GLfloat s, GLfloat t )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[0];
+ dest[0] = s;
+ dest[1] = t;
+}
+
+static void radeon_TexCoord2fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[0];
+ dest[0] = v[0];
+ dest[1] = v[1];
+}
+
+
+/* MultiTexcoord
+ *
+ * Technically speaking, these functions should subtract GL_TEXTURE0 from
+ * \c target before masking and using it. The value of GL_TEXTURE0 is 0x84C0,
+ * which has the low-order 5 bits 0. For all possible valid values of
+ * \c target. Subtracting GL_TEXTURE0 has the net effect of masking \c target
+ * with 0x1F. Masking with 0x1F and then masking with 0x01 is redundant, so
+ * the subtraction has been omitted.
+ */
+
+static void radeon_MultiTexCoord1fARB( GLenum target, GLfloat s )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[target & 1];
+ dest[0] = s;
+ dest[1] = 0;
+}
+
+static void radeon_MultiTexCoord1fvARB( GLenum target, const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[target & 1];
+ dest[0] = v[0];
+ dest[1] = 0;
+}
+
+static void radeon_MultiTexCoord2fARB( GLenum target, GLfloat s, GLfloat t )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[target & 1];
+ dest[0] = s;
+ dest[1] = t;
+}
+
+static void radeon_MultiTexCoord2fvARB( GLenum target, const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLfloat *dest = rmesa->vb.texcoordptr[target & 1];
+ dest[0] = v[0];
+ dest[1] = v[1];
+}
+
+static struct dynfn *lookup( struct dynfn *l, int key )
+{
+ struct dynfn *f;
+
+ foreach( f, l ) {
+ if (f->key == key)
+ return f;
+ }
+
+ return 0;
+}
+
+/* Can't use the loopback template for this:
+ */
+
+#define CHOOSE(FN, FNTYPE, MASK, ACTIVE, ARGS1, ARGS2 ) \
+static void choose_##FN ARGS1 \
+{ \
+ GET_CURRENT_CONTEXT(ctx); \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ int key = rmesa->vb.vertex_format & (MASK|ACTIVE); \
+ struct dynfn *dfn; \
+ \
+ dfn = lookup( &rmesa->vb.dfn_cache.FN, key ); \
+ if (dfn == 0) \
+ dfn = rmesa->vb.codegen.FN( ctx, key ); \
+ else if (RADEON_DEBUG & DEBUG_CODEGEN) \
+ fprintf(stderr, "%s -- cached codegen\n", __FUNCTION__ ); \
+ \
+ if (dfn) \
+ ctx->Exec->FN = (FNTYPE)(dfn->code); \
+ else { \
+ if (RADEON_DEBUG & DEBUG_CODEGEN) \
+ fprintf(stderr, "%s -- generic version\n", __FUNCTION__ ); \
+ ctx->Exec->FN = radeon_##FN; \
+ } \
+ \
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
+ ctx->Exec->FN ARGS2; \
+}
+
+
+
+/* For the _3f case, only allow one color function to be hooked in at
+ * a time. Eventually, use a similar mechanism to allow selecting the
+ * color component of the vertex format based on client behaviour.
+ *
+ * Note: Perform these actions even if there is a codegen or cached
+ * codegen version of the chosen function.
+ */
+#define CHOOSE_COLOR(FN, FNTYPE, NR, MASK, ACTIVE, ARGS1, ARGS2 ) \
+static void choose_##FN ARGS1 \
+{ \
+ GET_CURRENT_CONTEXT(ctx); \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ int key = rmesa->vb.vertex_format & (MASK|ACTIVE); \
+ struct dynfn *dfn; \
+ \
+ if (rmesa->vb.vertex_format & ACTIVE_PKCOLOR) { \
+ ctx->Exec->FN = radeon_##FN##_ub; \
+ } \
+ else if ((rmesa->vb.vertex_format & \
+ (ACTIVE_FPCOLOR|ACTIVE_FPALPHA)) == ACTIVE_FPCOLOR) { \
+ \
+ if (rmesa->vb.installed_color_3f_sz != NR) { \
+ rmesa->vb.installed_color_3f_sz = NR; \
+ if (NR == 3) ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = 1.0; \
+ if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) { \
+ radeon_copy_to_current( ctx ); \
+ _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt ); \
+ ctx->Exec->FN ARGS2; \
+ return; \
+ } \
+ } \
+ \
+ ctx->Exec->FN = radeon_##FN##_3f; \
+ } \
+ else { \
+ ctx->Exec->FN = radeon_##FN##_4f; \
+ } \
+ \
+ \
+ dfn = lookup( &rmesa->vb.dfn_cache.FN, key ); \
+ if (!dfn) dfn = rmesa->vb.codegen.FN( ctx, key ); \
+ \
+ if (dfn) { \
+ if (RADEON_DEBUG & DEBUG_CODEGEN) \
+ fprintf(stderr, "%s -- codegen version\n", __FUNCTION__ ); \
+ ctx->Exec->FN = (FNTYPE)dfn->code; \
+ } \
+ else if (RADEON_DEBUG & DEBUG_CODEGEN) \
+ fprintf(stderr, "%s -- 'c' version\n", __FUNCTION__ ); \
+ \
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
+ ctx->Exec->FN ARGS2; \
+}
+
+
+
+/* Right now there are both _ub and _3f versions of the secondary color
+ * functions. Currently, we only set-up the hardware to use the _ub versions.
+ * The _3f versions are needed for the cases where secondary color isn't used
+ * in the vertex format, but it still needs to be stored in the context
+ * state vector.
+ */
+#define CHOOSE_SECONDARY_COLOR(FN, FNTYPE, MASK, ACTIVE, ARGS1, ARGS2 ) \
+static void choose_##FN ARGS1 \
+{ \
+ GET_CURRENT_CONTEXT(ctx); \
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \
+ int key = rmesa->vb.vertex_format & (MASK|ACTIVE); \
+ struct dynfn *dfn = lookup( &rmesa->vb.dfn_cache.FN, key ); \
+ \
+ if (dfn == 0) \
+ dfn = rmesa->vb.codegen.FN( ctx, key ); \
+ else if (RADEON_DEBUG & DEBUG_CODEGEN) \
+ fprintf(stderr, "%s -- cached version\n", __FUNCTION__ ); \
+ \
+ if (dfn) \
+ ctx->Exec->FN = (FNTYPE)(dfn->code); \
+ else { \
+ if (RADEON_DEBUG & DEBUG_CODEGEN) \
+ fprintf(stderr, "%s -- generic version\n", __FUNCTION__ ); \
+ ctx->Exec->FN = ((rmesa->vb.vertex_format & ACTIVE_PKSPEC) != 0) \
+ ? radeon_##FN##_ub : radeon_##FN##_3f; \
+ } \
+ \
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
+ ctx->Exec->FN ARGS2; \
+}
+
+
+
+
+
+/* Shorthands
+ */
+#define ACTIVE_XYZW (RADEON_CP_VC_FRMT_W0|RADEON_CP_VC_FRMT_Z)
+#define ACTIVE_NORM RADEON_CP_VC_FRMT_N0
+
+#define ACTIVE_PKCOLOR RADEON_CP_VC_FRMT_PKCOLOR
+#define ACTIVE_FPCOLOR RADEON_CP_VC_FRMT_FPCOLOR
+#define ACTIVE_FPALPHA RADEON_CP_VC_FRMT_FPALPHA
+#define ACTIVE_COLOR (ACTIVE_FPCOLOR|ACTIVE_PKCOLOR)
+
+#define ACTIVE_PKSPEC RADEON_CP_VC_FRMT_PKSPEC
+#define ACTIVE_FPSPEC RADEON_CP_VC_FRMT_FPSPEC
+#define ACTIVE_SPEC (ACTIVE_FPSPEC|ACTIVE_PKSPEC)
+
+#define ACTIVE_ST0 RADEON_CP_VC_FRMT_ST0
+#define ACTIVE_ST1 RADEON_CP_VC_FRMT_ST1
+#define ACTIVE_ST_ALL (RADEON_CP_VC_FRMT_ST1|RADEON_CP_VC_FRMT_ST0)
+
+/* Each codegen function should be able to be fully specified by a
+ * subsetted version of rmesa->vb.vertex_format.
+ */
+#define MASK_NORM (ACTIVE_XYZW)
+#define MASK_COLOR (MASK_NORM|ACTIVE_NORM)
+#define MASK_SPEC (MASK_COLOR|ACTIVE_COLOR)
+#define MASK_ST0 (MASK_SPEC|ACTIVE_SPEC)
+#define MASK_ST1 (MASK_ST0|ACTIVE_ST0)
+#define MASK_ST_ALL (MASK_ST1|ACTIVE_ST1)
+#define MASK_VERTEX (MASK_ST_ALL|ACTIVE_FPALPHA)
+
+
+typedef void (*p4f)( GLfloat, GLfloat, GLfloat, GLfloat );
+typedef void (*p3f)( GLfloat, GLfloat, GLfloat );
+typedef void (*p2f)( GLfloat, GLfloat );
+typedef void (*p1f)( GLfloat );
+typedef void (*pe2f)( GLenum, GLfloat, GLfloat );
+typedef void (*pe1f)( GLenum, GLfloat );
+typedef void (*p4ub)( GLubyte, GLubyte, GLubyte, GLubyte );
+typedef void (*p3ub)( GLubyte, GLubyte, GLubyte );
+typedef void (*pfv)( const GLfloat * );
+typedef void (*pefv)( GLenum, const GLfloat * );
+typedef void (*pubv)( const GLubyte * );
+
+
+CHOOSE(Normal3f, p3f, MASK_NORM, ACTIVE_NORM,
+ (GLfloat a,GLfloat b,GLfloat c), (a,b,c))
+CHOOSE(Normal3fv, pfv, MASK_NORM, ACTIVE_NORM,
+ (const GLfloat *v), (v))
+
+CHOOSE_COLOR(Color4ub, p4ub, 4, MASK_COLOR, ACTIVE_COLOR,
+ (GLubyte a,GLubyte b, GLubyte c, GLubyte d), (a,b,c,d))
+CHOOSE_COLOR(Color4ubv, pubv, 4, MASK_COLOR, ACTIVE_COLOR,
+ (const GLubyte *v), (v))
+CHOOSE_COLOR(Color3ub, p3ub, 3, MASK_COLOR, ACTIVE_COLOR,
+ (GLubyte a,GLubyte b, GLubyte c), (a,b,c))
+CHOOSE_COLOR(Color3ubv, pubv, 3, MASK_COLOR, ACTIVE_COLOR,
+ (const GLubyte *v), (v))
+
+CHOOSE_COLOR(Color4f, p4f, 4, MASK_COLOR, ACTIVE_COLOR,
+ (GLfloat a,GLfloat b, GLfloat c, GLfloat d), (a,b,c,d))
+CHOOSE_COLOR(Color4fv, pfv, 4, MASK_COLOR, ACTIVE_COLOR,
+ (const GLfloat *v), (v))
+CHOOSE_COLOR(Color3f, p3f, 3, MASK_COLOR, ACTIVE_COLOR,
+ (GLfloat a,GLfloat b, GLfloat c), (a,b,c))
+CHOOSE_COLOR(Color3fv, pfv, 3, MASK_COLOR, ACTIVE_COLOR,
+ (const GLfloat *v), (v))
+
+
+CHOOSE_SECONDARY_COLOR(SecondaryColor3ubEXT, p3ub, MASK_SPEC, ACTIVE_SPEC,
+ (GLubyte a,GLubyte b, GLubyte c), (a,b,c))
+CHOOSE_SECONDARY_COLOR(SecondaryColor3ubvEXT, pubv, MASK_SPEC, ACTIVE_SPEC,
+ (const GLubyte *v), (v))
+CHOOSE_SECONDARY_COLOR(SecondaryColor3fEXT, p3f, MASK_SPEC, ACTIVE_SPEC,
+ (GLfloat a,GLfloat b, GLfloat c), (a,b,c))
+CHOOSE_SECONDARY_COLOR(SecondaryColor3fvEXT, pfv, MASK_SPEC, ACTIVE_SPEC,
+ (const GLfloat *v), (v))
+
+CHOOSE(TexCoord2f, p2f, MASK_ST0, ACTIVE_ST0,
+ (GLfloat a,GLfloat b), (a,b))
+CHOOSE(TexCoord2fv, pfv, MASK_ST0, ACTIVE_ST0,
+ (const GLfloat *v), (v))
+CHOOSE(TexCoord1f, p1f, MASK_ST0, ACTIVE_ST0,
+ (GLfloat a), (a))
+CHOOSE(TexCoord1fv, pfv, MASK_ST0, ACTIVE_ST0,
+ (const GLfloat *v), (v))
+
+CHOOSE(MultiTexCoord2fARB, pe2f, MASK_ST_ALL, ACTIVE_ST_ALL,
+ (GLenum u,GLfloat a,GLfloat b), (u,a,b))
+CHOOSE(MultiTexCoord2fvARB, pefv, MASK_ST_ALL, ACTIVE_ST_ALL,
+ (GLenum u,const GLfloat *v), (u,v))
+CHOOSE(MultiTexCoord1fARB, pe1f, MASK_ST_ALL, ACTIVE_ST_ALL,
+ (GLenum u,GLfloat a), (u,a))
+CHOOSE(MultiTexCoord1fvARB, pefv, MASK_ST_ALL, ACTIVE_ST_ALL,
+ (GLenum u,const GLfloat *v), (u,v))
+
+CHOOSE(Vertex3f, p3f, MASK_VERTEX, MASK_VERTEX,
+ (GLfloat a,GLfloat b,GLfloat c), (a,b,c))
+CHOOSE(Vertex3fv, pfv, MASK_VERTEX, MASK_VERTEX,
+ (const GLfloat *v), (v))
+CHOOSE(Vertex2f, p2f, MASK_VERTEX, MASK_VERTEX,
+ (GLfloat a,GLfloat b), (a,b))
+CHOOSE(Vertex2fv, pfv, MASK_VERTEX, MASK_VERTEX,
+ (const GLfloat *v), (v))
+
+
+
+
+
+void radeonVtxfmtInitChoosers( GLvertexformat *vfmt )
+{
+ vfmt->Color3f = choose_Color3f;
+ vfmt->Color3fv = choose_Color3fv;
+ vfmt->Color3ub = choose_Color3ub;
+ vfmt->Color3ubv = choose_Color3ubv;
+ vfmt->Color4f = choose_Color4f;
+ vfmt->Color4fv = choose_Color4fv;
+ vfmt->Color4ub = choose_Color4ub;
+ vfmt->Color4ubv = choose_Color4ubv;
+ vfmt->SecondaryColor3fEXT = choose_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = choose_SecondaryColor3fvEXT;
+ vfmt->SecondaryColor3ubEXT = choose_SecondaryColor3ubEXT;
+ vfmt->SecondaryColor3ubvEXT = choose_SecondaryColor3ubvEXT;
+ vfmt->MultiTexCoord1fARB = choose_MultiTexCoord1fARB;
+ vfmt->MultiTexCoord1fvARB = choose_MultiTexCoord1fvARB;
+ vfmt->MultiTexCoord2fARB = choose_MultiTexCoord2fARB;
+ vfmt->MultiTexCoord2fvARB = choose_MultiTexCoord2fvARB;
+ vfmt->Normal3f = choose_Normal3f;
+ vfmt->Normal3fv = choose_Normal3fv;
+ vfmt->TexCoord1f = choose_TexCoord1f;
+ vfmt->TexCoord1fv = choose_TexCoord1fv;
+ vfmt->TexCoord2f = choose_TexCoord2f;
+ vfmt->TexCoord2fv = choose_TexCoord2fv;
+ vfmt->Vertex2f = choose_Vertex2f;
+ vfmt->Vertex2fv = choose_Vertex2fv;
+ vfmt->Vertex3f = choose_Vertex3f;
+ vfmt->Vertex3fv = choose_Vertex3fv;
+}
+
+
+static struct dynfn *codegen_noop( GLcontext *ctx, int key )
+{
+ (void) ctx; (void) key;
+ return 0;
+}
+
+void radeonInitCodegen( struct dfn_generators *gen )
+{
+ gen->Vertex3f = codegen_noop;
+ gen->Vertex3fv = codegen_noop;
+ gen->Color4ub = codegen_noop;
+ gen->Color4ubv = codegen_noop;
+ gen->Normal3f = codegen_noop;
+ gen->Normal3fv = codegen_noop;
+ gen->TexCoord2f = codegen_noop;
+ gen->TexCoord2fv = codegen_noop;
+ gen->MultiTexCoord2fARB = codegen_noop;
+ gen->MultiTexCoord2fvARB = codegen_noop;
+ gen->Vertex2f = codegen_noop;
+ gen->Vertex2fv = codegen_noop;
+ gen->Color3ub = codegen_noop;
+ gen->Color3ubv = codegen_noop;
+ gen->Color4f = codegen_noop;
+ gen->Color4fv = codegen_noop;
+ gen->Color3f = codegen_noop;
+ gen->Color3fv = codegen_noop;
+ gen->SecondaryColor3fEXT = codegen_noop;
+ gen->SecondaryColor3fvEXT = codegen_noop;
+ gen->SecondaryColor3ubEXT = codegen_noop;
+ gen->SecondaryColor3ubvEXT = codegen_noop;
+ gen->TexCoord1f = codegen_noop;
+ gen->TexCoord1fv = codegen_noop;
+ gen->MultiTexCoord1fARB = codegen_noop;
+ gen->MultiTexCoord1fvARB = codegen_noop;
+
+ if (!getenv("RADEON_NO_CODEGEN")) {
+#if defined(USE_X86_ASM)
+ radeonInitX86Codegen( gen );
+#endif
+
+#if defined(USE_SSE_ASM)
+ radeonInitSSECodegen( gen );
+#endif
+ }
+}
diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt_sse.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_sse.c
new file mode 100644
index 0000000000..0f2c82bd87
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_sse.c
@@ -0,0 +1,232 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Cedar Park, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "simple_list.h"
+#include "radeon_vtxfmt.h"
+
+#if defined(USE_SSE_ASM)
+#include "X86/common_x86_asm.h"
+
+#define EXTERN( FUNC ) \
+extern const char *FUNC; \
+extern const char *FUNC##_end
+
+EXTERN( _sse_Attribute2fv );
+EXTERN( _sse_Attribute2f );
+EXTERN( _sse_Attribute3fv );
+EXTERN( _sse_Attribute3f );
+EXTERN( _sse_MultiTexCoord2fv );
+EXTERN( _sse_MultiTexCoord2f );
+EXTERN( _sse_MultiTexCoord2fv_2 );
+EXTERN( _sse_MultiTexCoord2f_2 );
+
+/* Build specialized versions of the immediate calls on the fly for
+ * the current state.
+ */
+
+static struct dynfn *radeon_makeSSEAttribute2fv( struct dynfn * cache, int key,
+ const char * name, void * dest)
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _sse_Attribute2fv, (*cache) );
+ FIXUP(dfn->code, 10, 0x0, (int)dest);
+ return dfn;
+}
+
+static struct dynfn *radeon_makeSSEAttribute2f( struct dynfn * cache, int key,
+ const char * name, void * dest )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _sse_Attribute2f, (*cache) );
+ FIXUP(dfn->code, 8, 0x0, (int)dest);
+ return dfn;
+}
+
+static struct dynfn *radeon_makeSSEAttribute3fv( struct dynfn * cache, int key,
+ const char * name, void * dest)
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _sse_Attribute3fv, (*cache) );
+ FIXUP(dfn->code, 13, 0x0, (int)dest);
+ FIXUP(dfn->code, 18, 0x8, 8+(int)dest);
+ return dfn;
+}
+
+static struct dynfn *radeon_makeSSEAttribute3f( struct dynfn * cache, int key,
+ const char * name, void * dest )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _sse_Attribute3f, (*cache) );
+ FIXUP(dfn->code, 12, 0x0, (int)dest);
+ FIXUP(dfn->code, 17, 0x8, 8+(int)dest);
+ return dfn;
+}
+
+static struct dynfn * radeon_makeSSENormal3fv( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeSSEAttribute3fv( & rmesa->vb.dfn_cache.Normal3fv, key,
+ __FUNCTION__, rmesa->vb.normalptr );
+}
+
+static struct dynfn *radeon_makeSSENormal3f( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeSSEAttribute3f( & rmesa->vb.dfn_cache.Normal3f, key,
+ __FUNCTION__, rmesa->vb.normalptr );
+}
+
+static struct dynfn *radeon_makeSSEColor3fv( GLcontext *ctx, int key )
+{
+ if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA))
+ return 0;
+ else
+ {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeSSEAttribute3fv( & rmesa->vb.dfn_cache.Color3fv, key,
+ __FUNCTION__, rmesa->vb.floatcolorptr );
+ }
+}
+
+static struct dynfn *radeon_makeSSEColor3f( GLcontext *ctx, int key )
+{
+ if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA))
+ return 0;
+ else
+ {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeSSEAttribute3f( & rmesa->vb.dfn_cache.Color3f, key,
+ __FUNCTION__, rmesa->vb.floatcolorptr );
+ }
+}
+
+static struct dynfn *radeon_makeSSETexCoord2fv( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeSSEAttribute2fv( & rmesa->vb.dfn_cache.TexCoord2fv, key,
+ __FUNCTION__, rmesa->vb.texcoordptr[0] );
+}
+
+static struct dynfn *radeon_makeSSETexCoord2f( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeSSEAttribute2f( & rmesa->vb.dfn_cache.TexCoord2f, key,
+ __FUNCTION__, rmesa->vb.texcoordptr[0] );
+}
+
+static struct dynfn *radeon_makeSSEMultiTexCoord2fv( GLcontext *ctx, int key )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+ if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) ==
+ (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) {
+ DFN ( _sse_MultiTexCoord2fv, rmesa->vb.dfn_cache.MultiTexCoord2fvARB );
+ FIXUP(dfn->code, 18, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]);
+ } else {
+ DFN ( _sse_MultiTexCoord2fv_2, rmesa->vb.dfn_cache.MultiTexCoord2fvARB );
+ FIXUP(dfn->code, 14, 0x0, (int)rmesa->vb.texcoordptr);
+ }
+ return dfn;
+}
+
+static struct dynfn *radeon_makeSSEMultiTexCoord2f( GLcontext *ctx, int key )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+ if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) ==
+ (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) {
+ DFN ( _sse_MultiTexCoord2f, rmesa->vb.dfn_cache.MultiTexCoord2fARB );
+ FIXUP(dfn->code, 16, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]);
+ } else {
+ DFN ( _sse_MultiTexCoord2f_2, rmesa->vb.dfn_cache.MultiTexCoord2fARB );
+ FIXUP(dfn->code, 15, 0x0, (int)rmesa->vb.texcoordptr);
+ }
+ return dfn;
+}
+
+void radeonInitSSECodegen( struct dfn_generators *gen )
+{
+ if ( cpu_has_xmm ) {
+ gen->Normal3fv = (void *) radeon_makeSSENormal3fv;
+ gen->Normal3f = (void *) radeon_makeSSENormal3f;
+ gen->Color3fv = (void *) radeon_makeSSEColor3fv;
+ gen->Color3f = (void *) radeon_makeSSEColor3f;
+ gen->TexCoord2fv = (void *) radeon_makeSSETexCoord2fv;
+ gen->TexCoord2f = (void *) radeon_makeSSETexCoord2f;
+ gen->MultiTexCoord2fvARB = (void *) radeon_makeSSEMultiTexCoord2fv;
+ gen->MultiTexCoord2fARB = (void *) radeon_makeSSEMultiTexCoord2f;
+ }
+}
+
+#else
+
+void radeonInitSSECodegen( struct dfn_generators *gen )
+{
+ (void) gen;
+}
+
+#endif
diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt_x86.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_x86.c
new file mode 100644
index 0000000000..92941ca5f8
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_x86.c
@@ -0,0 +1,437 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ Tungsten Graphics Inc., Cedar Park, Texas.
+
+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 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "simple_list.h"
+#include "radeon_vtxfmt.h"
+
+#if defined(USE_X86_ASM)
+
+#define EXTERN( FUNC ) \
+extern const char *FUNC; \
+extern const char *FUNC##_end
+
+EXTERN ( _x86_Attribute2fv );
+EXTERN ( _x86_Attribute2f );
+EXTERN ( _x86_Attribute3fv );
+EXTERN ( _x86_Attribute3f );
+EXTERN ( _x86_Vertex3fv_6 );
+EXTERN ( _x86_Vertex3fv_8 );
+EXTERN ( _x86_Vertex3fv );
+EXTERN ( _x86_Vertex3f_4 );
+EXTERN ( _x86_Vertex3f_6 );
+EXTERN ( _x86_Vertex3f );
+EXTERN ( _x86_Color4ubv_ub );
+EXTERN ( _x86_Color4ubv_4f );
+EXTERN ( _x86_Color4ub_ub );
+EXTERN ( _x86_MultiTexCoord2fv );
+EXTERN ( _x86_MultiTexCoord2fv_2 );
+EXTERN ( _x86_MultiTexCoord2f );
+EXTERN ( _x86_MultiTexCoord2f_2 );
+
+
+/* Build specialized versions of the immediate calls on the fly for
+ * the current state. Generic x86 versions.
+ */
+
+struct dynfn *radeon_makeX86Vertex3f( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x %d\n", __FUNCTION__, key, rmesa->vb.vertex_size );
+
+ switch (rmesa->vb.vertex_size) {
+ case 4: {
+
+ DFN ( _x86_Vertex3f_4, rmesa->vb.dfn_cache.Vertex3f );
+ FIXUP(dfn->code, 2, 0x0, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 25, 0x0, (int)&rmesa->vb.vertex[3]);
+ FIXUP(dfn->code, 36, 0x0, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 46, 0x0, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 51, 0x0, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 60, 0x0, (int)&rmesa->vb.notify);
+ break;
+ }
+ case 6: {
+
+ DFN ( _x86_Vertex3f_6, rmesa->vb.dfn_cache.Vertex3f );
+ FIXUP(dfn->code, 3, 0x0, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 28, 0x0, (int)&rmesa->vb.vertex[3]);
+ FIXUP(dfn->code, 34, 0x0, (int)&rmesa->vb.vertex[4]);
+ FIXUP(dfn->code, 40, 0x0, (int)&rmesa->vb.vertex[5]);
+ FIXUP(dfn->code, 57, 0x0, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 63, 0x0, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 70, 0x0, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 79, 0x0, (int)&rmesa->vb.notify);
+ break;
+ }
+ default: {
+
+ DFN ( _x86_Vertex3f, rmesa->vb.dfn_cache.Vertex3f );
+ FIXUP(dfn->code, 3, 0x0, (int)&rmesa->vb.vertex[3]);
+ FIXUP(dfn->code, 9, 0x0, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 37, 0x0, rmesa->vb.vertex_size-3);
+ FIXUP(dfn->code, 44, 0x0, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 50, 0x0, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 56, 0x0, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 67, 0x0, (int)&rmesa->vb.notify);
+ break;
+ }
+ }
+
+ return dfn;
+}
+
+
+
+struct dynfn *radeon_makeX86Vertex3fv( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x %d\n", __FUNCTION__, key, rmesa->vb.vertex_size );
+
+ switch (rmesa->vb.vertex_size) {
+ case 6: {
+
+ DFN ( _x86_Vertex3fv_6, rmesa->vb.dfn_cache.Vertex3fv );
+ FIXUP(dfn->code, 1, 0x00000000, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 27, 0x0000001c, (int)&rmesa->vb.vertex[3]);
+ FIXUP(dfn->code, 33, 0x00000020, (int)&rmesa->vb.vertex[4]);
+ FIXUP(dfn->code, 45, 0x00000024, (int)&rmesa->vb.vertex[5]);
+ FIXUP(dfn->code, 56, 0x00000000, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 61, 0x00000004, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 67, 0x00000004, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 76, 0x00000008, (int)&rmesa->vb.notify);
+ break;
+ }
+
+
+ case 8: {
+
+ DFN ( _x86_Vertex3fv_8, rmesa->vb.dfn_cache.Vertex3fv );
+ FIXUP(dfn->code, 1, 0x00000000, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 27, 0x0000001c, (int)&rmesa->vb.vertex[3]);
+ FIXUP(dfn->code, 33, 0x00000020, (int)&rmesa->vb.vertex[4]);
+ FIXUP(dfn->code, 45, 0x0000001c, (int)&rmesa->vb.vertex[5]);
+ FIXUP(dfn->code, 51, 0x00000020, (int)&rmesa->vb.vertex[6]);
+ FIXUP(dfn->code, 63, 0x00000024, (int)&rmesa->vb.vertex[7]);
+ FIXUP(dfn->code, 74, 0x00000000, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 79, 0x00000004, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 85, 0x00000004, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 94, 0x00000008, (int)&rmesa->vb.notify);
+ break;
+ }
+
+
+
+ default: {
+
+ DFN ( _x86_Vertex3fv, rmesa->vb.dfn_cache.Vertex3fv );
+ FIXUP(dfn->code, 8, 0x01010101, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 32, 0x00000006, rmesa->vb.vertex_size-3);
+ FIXUP(dfn->code, 37, 0x00000058, (int)&rmesa->vb.vertex[3]);
+ FIXUP(dfn->code, 45, 0x01010101, (int)&rmesa->vb.dmaptr);
+ FIXUP(dfn->code, 50, 0x02020202, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 58, 0x02020202, (int)&rmesa->vb.counter);
+ FIXUP(dfn->code, 67, 0x0, (int)&rmesa->vb.notify);
+ break;
+ }
+ }
+
+ return dfn;
+}
+
+static struct dynfn *
+radeon_makeX86Attribute2fv( struct dynfn * cache, int key,
+ const char * name, void * dest )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _x86_Attribute2fv, (*cache) );
+ FIXUP(dfn->code, 11, 0x0, (int)dest);
+ FIXUP(dfn->code, 16, 0x4, 4+(int)dest);
+
+ return dfn;
+}
+
+static struct dynfn *
+radeon_makeX86Attribute2f( struct dynfn * cache, int key,
+ const char * name, void * dest )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _x86_Attribute2f, (*cache) );
+ FIXUP(dfn->code, 1, 0x0, (int)dest);
+
+ return dfn;
+}
+
+
+static struct dynfn *
+radeon_makeX86Attribute3fv( struct dynfn * cache, int key,
+ const char * name, void * dest )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _x86_Attribute3fv, (*cache) );
+ FIXUP(dfn->code, 14, 0x0, (int)dest);
+ FIXUP(dfn->code, 20, 0x4, 4+(int)dest);
+ FIXUP(dfn->code, 25, 0x8, 8+(int)dest);
+
+ return dfn;
+}
+
+static struct dynfn *
+radeon_makeX86Attribute3f( struct dynfn * cache, int key,
+ const char * name, void * dest )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", name, key );
+
+ DFN ( _x86_Attribute3f, (*cache) );
+ FIXUP(dfn->code, 14, 0x0, (int)dest);
+ FIXUP(dfn->code, 20, 0x4, 4+(int)dest);
+ FIXUP(dfn->code, 25, 0x8, 8+(int)dest);
+
+ return dfn;
+}
+
+struct dynfn *radeon_makeX86Normal3fv( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeX86Attribute3fv( & rmesa->vb.dfn_cache.Normal3fv, key,
+ __FUNCTION__, rmesa->vb.normalptr );
+}
+
+struct dynfn *radeon_makeX86Normal3f( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeX86Attribute3f( & rmesa->vb.dfn_cache.Normal3f, key,
+ __FUNCTION__, rmesa->vb.normalptr );
+}
+
+struct dynfn *radeon_makeX86Color4ubv( GLcontext *ctx, int key )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+ if (key & RADEON_CP_VC_FRMT_PKCOLOR) {
+ DFN ( _x86_Color4ubv_ub, rmesa->vb.dfn_cache.Color4ubv);
+ FIXUP(dfn->code, 5, 0x12345678, (int)rmesa->vb.colorptr);
+ return dfn;
+ }
+ else {
+
+ DFN ( _x86_Color4ubv_4f, rmesa->vb.dfn_cache.Color4ubv);
+ FIXUP(dfn->code, 2, 0x00000000, (int)_mesa_ubyte_to_float_color_tab);
+ FIXUP(dfn->code, 27, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr);
+ FIXUP(dfn->code, 33, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr+4);
+ FIXUP(dfn->code, 55, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr+8);
+ FIXUP(dfn->code, 61, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr+12);
+ return dfn;
+ }
+}
+
+struct dynfn *radeon_makeX86Color4ub( GLcontext *ctx, int key )
+{
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+ if (key & RADEON_CP_VC_FRMT_PKCOLOR) {
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ DFN ( _x86_Color4ub_ub, rmesa->vb.dfn_cache.Color4ub );
+ FIXUP(dfn->code, 18, 0x0, (int)rmesa->vb.colorptr);
+ FIXUP(dfn->code, 24, 0x0, (int)rmesa->vb.colorptr+1);
+ FIXUP(dfn->code, 30, 0x0, (int)rmesa->vb.colorptr+2);
+ FIXUP(dfn->code, 36, 0x0, (int)rmesa->vb.colorptr+3);
+ return dfn;
+ }
+ else
+ return 0;
+}
+
+
+struct dynfn *radeon_makeX86Color3fv( GLcontext *ctx, int key )
+{
+ if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA))
+ return 0;
+ else
+ {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeX86Attribute3fv( & rmesa->vb.dfn_cache.Color3fv, key,
+ __FUNCTION__, rmesa->vb.floatcolorptr );
+ }
+}
+
+struct dynfn *radeon_makeX86Color3f( GLcontext *ctx, int key )
+{
+ if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA))
+ return 0;
+ else
+ {
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeX86Attribute3f( & rmesa->vb.dfn_cache.Color3f, key,
+ __FUNCTION__, rmesa->vb.floatcolorptr );
+ }
+}
+
+
+
+struct dynfn *radeon_makeX86TexCoord2fv( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeX86Attribute2fv( & rmesa->vb.dfn_cache.TexCoord2fv, key,
+ __FUNCTION__, rmesa->vb.texcoordptr[0] );
+}
+
+struct dynfn *radeon_makeX86TexCoord2f( GLcontext *ctx, int key )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ return radeon_makeX86Attribute2f( & rmesa->vb.dfn_cache.TexCoord2f, key,
+ __FUNCTION__, rmesa->vb.texcoordptr[0] );
+}
+
+struct dynfn *radeon_makeX86MultiTexCoord2fvARB( GLcontext *ctx, int key )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+ if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) ==
+ (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) {
+ DFN ( _x86_MultiTexCoord2fv, rmesa->vb.dfn_cache.MultiTexCoord2fvARB );
+ FIXUP(dfn->code, 21, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]);
+ FIXUP(dfn->code, 27, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]+4);
+ } else {
+ DFN ( _x86_MultiTexCoord2fv_2, rmesa->vb.dfn_cache.MultiTexCoord2fvARB );
+ FIXUP(dfn->code, 14, 0x0, (int)rmesa->vb.texcoordptr);
+ }
+ return dfn;
+}
+
+struct dynfn *radeon_makeX86MultiTexCoord2fARB( GLcontext *ctx,
+ int key )
+{
+ struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+
+ if (RADEON_DEBUG & DEBUG_CODEGEN)
+ fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+ if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) ==
+ (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) {
+ DFN ( _x86_MultiTexCoord2f, rmesa->vb.dfn_cache.MultiTexCoord2fARB );
+ FIXUP(dfn->code, 20, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]);
+ FIXUP(dfn->code, 26, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]+4);
+ }
+ else {
+ /* Note: this might get generated multiple times, even though the
+ * actual emitted code is the same.
+ */
+ DFN ( _x86_MultiTexCoord2f_2, rmesa->vb.dfn_cache.MultiTexCoord2fARB );
+ FIXUP(dfn->code, 18, 0x0, (int)rmesa->vb.texcoordptr);
+ }
+ return dfn;
+}
+
+
+void radeonInitX86Codegen( struct dfn_generators *gen )
+{
+ gen->Vertex3f = radeon_makeX86Vertex3f;
+ gen->Vertex3fv = radeon_makeX86Vertex3fv;
+ gen->Color4ub = radeon_makeX86Color4ub; /* PKCOLOR only */
+ gen->Color4ubv = radeon_makeX86Color4ubv; /* PKCOLOR only */
+ gen->Normal3f = radeon_makeX86Normal3f;
+ gen->Normal3fv = radeon_makeX86Normal3fv;
+ gen->TexCoord2f = radeon_makeX86TexCoord2f;
+ gen->TexCoord2fv = radeon_makeX86TexCoord2fv;
+ gen->MultiTexCoord2fARB = radeon_makeX86MultiTexCoord2fARB;
+ gen->MultiTexCoord2fvARB = radeon_makeX86MultiTexCoord2fvARB;
+ gen->Color3f = radeon_makeX86Color3f;
+ gen->Color3fv = radeon_makeX86Color3fv;
+
+ /* Not done:
+ */
+/* gen->Vertex2f = radeon_makeX86Vertex2f; */
+/* gen->Vertex2fv = radeon_makeX86Vertex2fv; */
+/* gen->Color3ub = radeon_makeX86Color3ub; */
+/* gen->Color3ubv = radeon_makeX86Color3ubv; */
+/* gen->Color4f = radeon_makeX86Color4f; */
+/* gen->Color4fv = radeon_makeX86Color4fv; */
+/* gen->TexCoord1f = radeon_makeX86TexCoord1f; */
+/* gen->TexCoord1fv = radeon_makeX86TexCoord1fv; */
+/* gen->MultiTexCoord1fARB = radeon_makeX86MultiTexCoord1fARB; */
+/* gen->MultiTexCoord1fvARB = radeon_makeX86MultiTexCoord1fvARB; */
+}
+
+
+#else
+
+void radeonInitX86Codegen( struct dfn_generators *gen )
+{
+ (void) gen;
+}
+
+#endif
diff --git a/src/mesa/drivers/dri/radeon/server/radeon_common.h b/src/mesa/drivers/dri/radeon/server/radeon_common.h
index c26ccd3cc2..0792b5c2e0 100644
--- a/src/mesa/drivers/dri/radeon/server/radeon_common.h
+++ b/src/mesa/drivers/dri/radeon/server/radeon_common.h
@@ -1,19 +1,5 @@
-/**
- * \file server/radeon_common.h
- * \brief Common header definitions for Radeon 2D/3D/DRM driver suite.
+/* radeon_common.h -- common header definitions for Radeon 2D/3D/DRM suite
*
- * \note Some of these structures are meant for backward compatibility and
- * aren't used by the subset driver.
- *
- * \author Gareth Hughes <gareth@valinux.com>
- * \author Kevin E. Martin <martin@valinux.com>
- * \author Keith Whitwell <keith@tungstengraphics.com>
- *
- * \author Converted to common header format by
- * Jens Owen <jens@tungstengraphics.com>
- */
-
-/*
* Copyright 2000 VA Linux Systems, Inc., Fremont, California.
* Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
@@ -36,10 +22,19 @@
* 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.
+ *
+ * Author:
+ * Gareth Hughes <gareth@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ *
+ * Converted to common header format:
+ * Jens Owen <jens@tungstengraphics.com>
+ *
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drmRadeon.h,v 1.6 2001/04/16 15:02:13 tsi Exp $
+ *
*/
-/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drmRadeon.h,v 1.6 2001/04/16 15:02:13 tsi Exp $ */
-
#ifndef _RADEON_COMMON_H_
#define _RADEON_COMMON_H_
@@ -90,42 +85,33 @@
#define RADEON_CLEAR_DEPTH 4
-/**
- * \brief DRM_RADEON_CP_INIT ioctl argument type.
- */
typedef struct {
enum {
- DRM_RADEON_INIT_CP = 0x01, /**< \brief initialize CP */
- DRM_RADEON_CLEANUP_CP = 0x02, /**< \brief clean up CP */
- DRM_RADEON_INIT_R200_CP = 0x03 /**< \brief initialize R200 CP */
- } func; /**< \brief request */
- unsigned long sarea_priv_offset; /**< \brief SAREA private offset */
- int is_pci; /**< \brief is current card a PCI card? */
- int cp_mode; /**< \brief CP mode */
- int agp_size; /**< \brief AGP space size */
- int ring_size; /**< \brief CP ring buffer size */
- int usec_timeout; /**< \brief timeout for DRM operations in usecs */
-
- unsigned int fb_bpp;
- unsigned int front_offset; /**< \brief front color buffer offset */
- unsigned int front_pitch; /**< \brief front color buffer pitch */
- unsigned int back_offset; /**< \brief back color buffer offset */
- unsigned int back_pitch; /**< \brief back color buffer pitch*/
- unsigned int depth_bpp; /**< \brief depth buffer bits-per-pixel */
- unsigned int depth_offset; /**< \brief depth buffer offset */
- unsigned int depth_pitch; /**< \brief depth buffer pitch */
-
- unsigned long fb_offset; /**< \brief framebuffer offset */
- unsigned long mmio_offset; /**< \brief MMIO register offset */
- unsigned long ring_offset; /**< \brief CP ring buffer offset */
- unsigned long ring_rptr_offset; /**< \brief CP ring buffer read pointer offset */
- unsigned long buffers_offset; /**< \brief vertex buffers offset */
- unsigned long agp_textures_offset; /**< \brief AGP textures offset */
+ DRM_RADEON_INIT_CP = 0x01,
+ DRM_RADEON_CLEANUP_CP = 0x02,
+ DRM_RADEON_INIT_R200_CP = 0x03
+ } func;
+ unsigned long sarea_priv_offset;
+ int is_pci;
+ int cp_mode;
+ int agp_size;
+ int ring_size;
+ int usec_timeout;
+
+ unsigned int fb_bpp;
+ unsigned int front_offset, front_pitch;
+ unsigned int back_offset, back_pitch;
+ unsigned int depth_bpp;
+ unsigned int depth_offset, depth_pitch;
+
+ unsigned long fb_offset;
+ unsigned long mmio_offset;
+ unsigned long ring_offset;
+ unsigned long ring_rptr_offset;
+ unsigned long buffers_offset;
+ unsigned long agp_textures_offset;
} drmRadeonInit;
-/**
- * \brief DRM_RADEON_CP_STOP ioctl argument type.
- */
typedef struct {
int flush;
int idle;
@@ -143,17 +129,13 @@ typedef union drmRadeonClearR {
unsigned int ui[5];
} drmRadeonClearRect;
-/**
- * \brief DRM_RADEON_CLEAR ioctl argument type.
- */
typedef struct drmRadeonClearT {
- unsigned int flags; /**< \brief bitmask of the planes to clear */
- unsigned int clear_color; /**< \brief color buffer clear value */
- unsigned int clear_depth; /**< \brief depth buffer clear value */
- unsigned int color_mask; /**< \brief color buffer clear mask */
- unsigned int depth_mask; /**< \brief stencil buffer clear value
- * \todo Misnamed field. */
- drmRadeonClearRect *depth_boxes; /**< \brief depth buffer cliprects */
+ unsigned int flags;
+ unsigned int clear_color;
+ unsigned int clear_depth;
+ unsigned int color_mask;
+ unsigned int depth_mask; /* misnamed field: should be stencil */
+ drmRadeonClearRect *depth_boxes;
} drmRadeonClearType;
typedef struct drmRadeonFullscreenT {
@@ -163,16 +145,10 @@ typedef struct drmRadeonFullscreenT {
} func;
} drmRadeonFullscreenType;
-/**
- * \brief DRM_RADEON_STIPPLE ioctl argument type.
- */
typedef struct {
unsigned int *mask;
} drmRadeonStipple;
-/**
- * \brief Texture image for drmRadeonTexture.
- */
typedef struct {
unsigned int x;
unsigned int y;
@@ -181,22 +157,18 @@ typedef struct {
const void *data;
} drmRadeonTexImage;
-/**
- * \brief DRM_RADEON_TEXTURE ioctl argument type.
- */
typedef struct {
- int offset; /**< \brief texture offset */
- int pitch; /**< \brief texture pitch */
- int format; /**< \brief pixel format */
- int width; /**< \brief texture width */
- int height; /**< \brief texture height */
- drmRadeonTexImage *image; /**< \brief image */
+ int offset;
+ int pitch;
+ int format;
+ int width; /* Texture image coordinates */
+ int height;
+ drmRadeonTexImage *image;
} drmRadeonTexture;
#define RADEON_MAX_TEXTURE_UNITS 3
-
/* Layout matches drm_radeon_state_t in linux drm_radeon.h.
*/
typedef struct {
@@ -266,16 +238,13 @@ typedef struct {
unsigned int dirty;
} drmRadeonState;
-/**
- * \brief DRM 1.1 vertex ioctl.
- *
- * Used in compatibility modes.
+/* 1.1 vertex ioctl. Used in compatibility modes.
*/
typedef struct {
- int prim; /**< \brief Primitive number */
- int idx; /**< \brief Index of vertex buffer */
- int count; /**< \brief Number of vertices in buffer */
- int discard; /**< \brief Client finished with buffer? */
+ int prim;
+ int idx; /* Index of vertex buffer */
+ int count; /* Number of vertices in buffer */
+ int discard; /* Client finished with buffer? */
} drmRadeonVertex;
typedef struct {
@@ -283,13 +252,13 @@ typedef struct {
unsigned int finish;
unsigned int prim:8;
unsigned int stateidx:8;
- unsigned int numverts:16; /**< overloaded as offset/64 for elt prims */
+ unsigned int numverts:16; /* overloaded as offset/64 for elt prims */
unsigned int vc_format;
} drmRadeonPrim;
typedef struct {
- int idx; /**< \brief Index of vertex buffer */
- int discard; /**< \brief Client finished with buffer? */
+ int idx; /* Index of vertex buffer */
+ int discard; /* Client finished with buffer? */
int nr_states;
drmRadeonState *state;
int nr_prims;
@@ -299,156 +268,127 @@ typedef struct {
#define RADEON_MAX_STATES 16
#define RADEON_MAX_PRIMS 64
-
-/**
- * \brief Command buffer.
- *
- * \todo Replace with true DMA stream?
+/* Command buffer. Replace with true dma stream?
*/
typedef struct {
- int bufsz; /**< \brief buffer size */
- char *buf; /**< \brief buffer */
- int nbox; /**< \brief number of cliprects */
- drmClipRect *boxes; /**< \brief cliprects */
+ int bufsz;
+ char *buf;
+ int nbox;
+ drmClipRect *boxes;
} drmRadeonCmdBuffer;
-
-/**
- * \brief Per-packet identifiers for use with the ::RADEON_CMD_PACKET command
- * in the DRM_RADEON_CMDBUF ioctl.
- *
- * \note Comments relate new packets to old state bits and the packet size.
+/* New style per-packet identifiers for use in cmd_buffer ioctl with
+ * the RADEON_EMIT_PACKET command. Comments relate new packets to old
+ * state bits and the packet size:
*/
-enum drmRadeonCmdPkt {
- RADEON_EMIT_PP_MISC = 0, /* context/7 */
- RADEON_EMIT_PP_CNTL = 1, /* context/3 */
- RADEON_EMIT_RB3D_COLORPITCH = 2, /* context/1 */
- RADEON_EMIT_RE_LINE_PATTERN = 3, /* line/2 */
- RADEON_EMIT_SE_LINE_WIDTH = 4, /* line/1 */
- RADEON_EMIT_PP_LUM_MATRIX = 5, /* bumpmap/1 */
- RADEON_EMIT_PP_ROT_MATRIX_0 = 6, /* bumpmap/2 */
- RADEON_EMIT_RB3D_STENCILREFMASK = 7, /* masks/3 */
- RADEON_EMIT_SE_VPORT_XSCALE = 8, /* viewport/6 */
- RADEON_EMIT_SE_CNTL = 9, /* setup/2 */
- RADEON_EMIT_SE_CNTL_STATUS = 10, /* setup/1 */
- RADEON_EMIT_RE_MISC = 11, /* misc/1 */
- RADEON_EMIT_PP_TXFILTER_0 = 12, /* tex0/6 */
- RADEON_EMIT_PP_BORDER_COLOR_0 = 13, /* tex0/1 */
- RADEON_EMIT_PP_TXFILTER_1 = 14, /* tex1/6 */
- RADEON_EMIT_PP_BORDER_COLOR_1 = 15, /* tex1/1 */
- RADEON_EMIT_PP_TXFILTER_2 = 16, /* tex2/6 */
- RADEON_EMIT_PP_BORDER_COLOR_2 = 17, /* tex2/1 */
- RADEON_EMIT_SE_ZBIAS_FACTOR = 18, /* zbias/2 */
- RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT = 19, /* tcl/11 */
- RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED = 20, /* material/17 */
- R200_EMIT_PP_TXCBLEND_0 = 21, /* tex0/4 */
- R200_EMIT_PP_TXCBLEND_1 = 22, /* tex1/4 */
- R200_EMIT_PP_TXCBLEND_2 = 23, /* tex2/4 */
- R200_EMIT_PP_TXCBLEND_3 = 24, /* tex3/4 */
- R200_EMIT_PP_TXCBLEND_4 = 25, /* tex4/4 */
- R200_EMIT_PP_TXCBLEND_5 = 26, /* tex5/4 */
- R200_EMIT_PP_TXCBLEND_6 = 27, /* /4 */
- R200_EMIT_PP_TXCBLEND_7 = 28, /* /4 */
- R200_EMIT_TCL_LIGHT_MODEL_CTL_0 = 29, /* tcl/6 */
- R200_EMIT_TFACTOR_0 = 30, /* tf/6 */
- R200_EMIT_VTX_FMT_0 = 31, /* vtx/4 */
- R200_EMIT_VAP_CTL = 32, /* vap/1 */
- R200_EMIT_MATRIX_SELECT_0 = 33, /* msl/5 */
- R200_EMIT_TEX_PROC_CTL_2 = 34, /* tcg/5 */
- R200_EMIT_TCL_UCP_VERT_BLEND_CTL = 35, /* tcl/1 */
- R200_EMIT_PP_TXFILTER_0 = 36, /* tex0/6 */
- R200_EMIT_PP_TXFILTER_1 = 37, /* tex1/6 */
- R200_EMIT_PP_TXFILTER_2 = 38, /* tex2/6 */
- R200_EMIT_PP_TXFILTER_3 = 39, /* tex3/6 */
- R200_EMIT_PP_TXFILTER_4 = 40, /* tex4/6 */
- R200_EMIT_PP_TXFILTER_5 = 41, /* tex5/6 */
- R200_EMIT_PP_TXOFFSET_0 = 42, /* tex0/1 */
- R200_EMIT_PP_TXOFFSET_1 = 43, /* tex1/1 */
- R200_EMIT_PP_TXOFFSET_2 = 44, /* tex2/1 */
- R200_EMIT_PP_TXOFFSET_3 = 45, /* tex3/1 */
- R200_EMIT_PP_TXOFFSET_4 = 46, /* tex4/1 */
- R200_EMIT_PP_TXOFFSET_5 = 47, /* tex5/1 */
- R200_EMIT_VTE_CNTL = 48, /* vte/1 */
- R200_EMIT_OUTPUT_VTX_COMP_SEL = 49, /* vtx/1 */
- R200_EMIT_PP_TAM_DEBUG3 = 50, /* tam/1 */
- R200_EMIT_PP_CNTL_X = 51, /* cst/1 */
- R200_EMIT_RB3D_DEPTHXY_OFFSET = 52, /* cst/1 */
- R200_EMIT_RE_AUX_SCISSOR_CNTL = 53, /* cst/1 */
- R200_EMIT_RE_SCISSOR_TL_0 = 54, /* cst/2 */
- R200_EMIT_RE_SCISSOR_TL_1 = 55, /* cst/2 */
- R200_EMIT_RE_SCISSOR_TL_2 = 56, /* cst/2 */
- R200_EMIT_SE_VAP_CNTL_STATUS = 57, /* cst/1 */
- R200_EMIT_SE_VTX_STATE_CNTL = 58, /* cst/1 */
- R200_EMIT_RE_POINTSIZE = 59, /* cst/1 */
- R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 = 60, /* cst/4 */
- R200_EMIT_PP_CUBIC_FACES_0 = 61,
- R200_EMIT_PP_CUBIC_OFFSETS_0 = 62,
- R200_EMIT_PP_CUBIC_FACES_1 = 63,
- R200_EMIT_PP_CUBIC_OFFSETS_1 = 64,
- R200_EMIT_PP_CUBIC_FACES_2 = 65,
- R200_EMIT_PP_CUBIC_OFFSETS_2 = 66,
- R200_EMIT_PP_CUBIC_FACES_3 = 67,
- R200_EMIT_PP_CUBIC_OFFSETS_3 = 68,
- R200_EMIT_PP_CUBIC_FACES_4 = 69,
- R200_EMIT_PP_CUBIC_OFFSETS_4 = 70,
- R200_EMIT_PP_CUBIC_FACES_5 = 71,
- R200_EMIT_PP_CUBIC_OFFSETS_5 = 72,
- RADEON_MAX_STATE_PACKETS = 73
-} ;
-
-
-/**
- * \brief Command types understood by the DRM_RADEON_CMDBUF ioctl.
- *
- * More can be added but obviously these can't be removed or changed.
- *
- * \sa drmRadeonCmdHeader.
- */
-enum drmRadeonCmdType {
- RADEON_CMD_PACKET = 1, /**< \brief emit one of the ::drmRadeonCmdPkt register packets */
- RADEON_CMD_SCALARS = 2, /**< \brief emit scalar data */
- RADEON_CMD_VECTORS = 3, /**< \brief emit vector data */
- RADEON_CMD_DMA_DISCARD = 4, /**< \brief discard current DMA buffer */
- RADEON_CMD_PACKET3 = 5, /**< \brief emit hardware packet */
- RADEON_CMD_PACKET3_CLIP = 6, /**< \brief emit hardware packet wrapped in cliprects */
- RADEON_CMD_SCALARS2 = 7, /**< \brief R200 stopgap */
- RADEON_CMD_WAIT = 8 /**< \brief synchronization */
-} ;
-
-/**
- * \brief Command packet headers understood by the DRM_RADEON_CMDBUF ioctl.
- *
- * \sa drmRadeonCmdType.
+#define RADEON_EMIT_PP_MISC 0 /* context/7 */
+#define RADEON_EMIT_PP_CNTL 1 /* context/3 */
+#define RADEON_EMIT_RB3D_COLORPITCH 2 /* context/1 */
+#define RADEON_EMIT_RE_LINE_PATTERN 3 /* line/2 */
+#define RADEON_EMIT_SE_LINE_WIDTH 4 /* line/1 */
+#define RADEON_EMIT_PP_LUM_MATRIX 5 /* bumpmap/1 */
+#define RADEON_EMIT_PP_ROT_MATRIX_0 6 /* bumpmap/2 */
+#define RADEON_EMIT_RB3D_STENCILREFMASK 7 /* masks/3 */
+#define RADEON_EMIT_SE_VPORT_XSCALE 8 /* viewport/6 */
+#define RADEON_EMIT_SE_CNTL 9 /* setup/2 */
+#define RADEON_EMIT_SE_CNTL_STATUS 10 /* setup/1 */
+#define RADEON_EMIT_RE_MISC 11 /* misc/1 */
+#define RADEON_EMIT_PP_TXFILTER_0 12 /* tex0/6 */
+#define RADEON_EMIT_PP_BORDER_COLOR_0 13 /* tex0/1 */
+#define RADEON_EMIT_PP_TXFILTER_1 14 /* tex1/6 */
+#define RADEON_EMIT_PP_BORDER_COLOR_1 15 /* tex1/1 */
+#define RADEON_EMIT_PP_TXFILTER_2 16 /* tex2/6 */
+#define RADEON_EMIT_PP_BORDER_COLOR_2 17 /* tex2/1 */
+#define RADEON_EMIT_SE_ZBIAS_FACTOR 18 /* zbias/2 */
+#define RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT 19 /* tcl/11 */
+#define RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED 20 /* material/17 */
+#define R200_EMIT_PP_TXCBLEND_0 21 /* tex0/4 */
+#define R200_EMIT_PP_TXCBLEND_1 22 /* tex1/4 */
+#define R200_EMIT_PP_TXCBLEND_2 23 /* tex2/4 */
+#define R200_EMIT_PP_TXCBLEND_3 24 /* tex3/4 */
+#define R200_EMIT_PP_TXCBLEND_4 25 /* tex4/4 */
+#define R200_EMIT_PP_TXCBLEND_5 26 /* tex5/4 */
+#define R200_EMIT_PP_TXCBLEND_6 27 /* /4 */
+#define R200_EMIT_PP_TXCBLEND_7 28 /* /4 */
+#define R200_EMIT_TCL_LIGHT_MODEL_CTL_0 29 /* tcl/6 */
+#define R200_EMIT_TFACTOR_0 30 /* tf/6 */
+#define R200_EMIT_VTX_FMT_0 31 /* vtx/4 */
+#define R200_EMIT_VAP_CTL 32 /* vap/1 */
+#define R200_EMIT_MATRIX_SELECT_0 33 /* msl/5 */
+#define R200_EMIT_TEX_PROC_CTL_2 34 /* tcg/5 */
+#define R200_EMIT_TCL_UCP_VERT_BLEND_CTL 35 /* tcl/1 */
+#define R200_EMIT_PP_TXFILTER_0 36 /* tex0/6 */
+#define R200_EMIT_PP_TXFILTER_1 37 /* tex1/6 */
+#define R200_EMIT_PP_TXFILTER_2 38 /* tex2/6 */
+#define R200_EMIT_PP_TXFILTER_3 39 /* tex3/6 */
+#define R200_EMIT_PP_TXFILTER_4 40 /* tex4/6 */
+#define R200_EMIT_PP_TXFILTER_5 41 /* tex5/6 */
+#define R200_EMIT_PP_TXOFFSET_0 42 /* tex0/1 */
+#define R200_EMIT_PP_TXOFFSET_1 43 /* tex1/1 */
+#define R200_EMIT_PP_TXOFFSET_2 44 /* tex2/1 */
+#define R200_EMIT_PP_TXOFFSET_3 45 /* tex3/1 */
+#define R200_EMIT_PP_TXOFFSET_4 46 /* tex4/1 */
+#define R200_EMIT_PP_TXOFFSET_5 47 /* tex5/1 */
+#define R200_EMIT_VTE_CNTL 48 /* vte/1 */
+#define R200_EMIT_OUTPUT_VTX_COMP_SEL 49 /* vtx/1 */
+#define R200_EMIT_PP_TAM_DEBUG3 50 /* tam/1 */
+#define R200_EMIT_PP_CNTL_X 51 /* cst/1 */
+#define R200_EMIT_RB3D_DEPTHXY_OFFSET 52 /* cst/1 */
+#define R200_EMIT_RE_AUX_SCISSOR_CNTL 53 /* cst/1 */
+#define R200_EMIT_RE_SCISSOR_TL_0 54 /* cst/2 */
+#define R200_EMIT_RE_SCISSOR_TL_1 55 /* cst/2 */
+#define R200_EMIT_RE_SCISSOR_TL_2 56 /* cst/2 */
+#define R200_EMIT_SE_VAP_CNTL_STATUS 57 /* cst/1 */
+#define R200_EMIT_SE_VTX_STATE_CNTL 58 /* cst/1 */
+#define R200_EMIT_RE_POINTSIZE 59 /* cst/1 */
+#define R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 60 /* cst/4 */
+#define R200_EMIT_PP_CUBIC_FACES_0 61
+#define R200_EMIT_PP_CUBIC_OFFSETS_0 62
+#define R200_EMIT_PP_CUBIC_FACES_1 63
+#define R200_EMIT_PP_CUBIC_OFFSETS_1 64
+#define R200_EMIT_PP_CUBIC_FACES_2 65
+#define R200_EMIT_PP_CUBIC_OFFSETS_2 66
+#define R200_EMIT_PP_CUBIC_FACES_3 67
+#define R200_EMIT_PP_CUBIC_OFFSETS_3 68
+#define R200_EMIT_PP_CUBIC_FACES_4 69
+#define R200_EMIT_PP_CUBIC_OFFSETS_4 70
+#define R200_EMIT_PP_CUBIC_FACES_5 71
+#define R200_EMIT_PP_CUBIC_OFFSETS_5 72
+#define RADEON_EMIT_PP_TEX_SIZE_0 73
+#define RADEON_EMIT_PP_TEX_SIZE_1 74
+#define RADEON_EMIT_PP_TEX_SIZE_2 75
+#define RADEON_MAX_STATE_PACKETS 76
+
+
+/* Commands understood by cmd_buffer ioctl. More can be added but
+ * obviously these can't be removed or changed:
*/
+#define RADEON_CMD_PACKET 1 /* emit one of the register packets above */
+#define RADEON_CMD_SCALARS 2 /* emit scalar data */
+#define RADEON_CMD_VECTORS 3 /* emit vector data */
+#define RADEON_CMD_DMA_DISCARD 4 /* discard current dma buf */
+#define RADEON_CMD_PACKET3 5 /* emit hw packet */
+#define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */
+#define RADEON_CMD_SCALARS2 7 /* R200 stopgap */
+#define RADEON_CMD_WAIT 8 /* synchronization */
+
typedef union {
- /** \brief integer equivalent */
int i;
-
struct {
unsigned char cmd_type, pad0, pad1, pad2;
} header;
-
- /** \brief emit a register packet */
struct {
unsigned char cmd_type, packet_id, pad0, pad1;
} packet;
-
- /** \brief scalar data */
struct {
unsigned char cmd_type, offset, stride, count;
} scalars;
-
- /** \brief vector data */
struct {
unsigned char cmd_type, offset, stride, count;
} vectors;
-
- /** \brief discard current DMA buffer */
struct {
unsigned char cmd_type, buf_idx, pad0, pad1;
} dma;
-
- /** \brief synchronization */
struct {
unsigned char cmd_type, flags, pad0, pad1;
} wait;
@@ -458,12 +398,10 @@ typedef union {
#define RADEON_WAIT_2D 0x1
#define RADEON_WAIT_3D 0x2
-/**
- * \brief DRM_RADEON_GETPARAM ioctl argument type.
- */
+
typedef struct drm_radeon_getparam {
- int param; /**< \brief parameter number */
- int *value; /**< \brief parameter value */
+ int param;
+ void *value;
} drmRadeonGetParam;
#define RADEON_PARAM_AGP_BUFFER_OFFSET 1
@@ -472,10 +410,6 @@ typedef struct drm_radeon_getparam {
#define RADEON_PARAM_LAST_CLEAR 4
#define RADEON_PARAM_IRQ_NR 5
#define RADEON_PARAM_AGP_BASE 6
-#define RADEON_PARAM_REGISTER_HANDLE 7
-#define RADEON_PARAM_STATUS_HANDLE 8
-#define RADEON_PARAM_SAREA_HANDLE 9
-#define RADEON_PARAM_AGP_TEX_HANDLE 10
#define RADEON_MEM_REGION_AGP 1
@@ -493,29 +427,18 @@ typedef struct drm_radeon_mem_free {
int region_offset;
} drmRadeonMemFree;
-/**
- * \brief DRM_RADEON_INIT_HEAP argument type.
- */
typedef struct drm_radeon_mem_init_heap {
- int region; /**< \brief region type */
- int size; /**< \brief region size */
- int start; /**< \brief region start offset */
+ int region;
+ int size;
+ int start;
} drmRadeonMemInitHeap;
-/**
- * \brief DRM_RADEON_IRQ_EMIT ioctl argument type.
- *
- * New in DRM 1.6: userspace can request and wait on IRQ's.
+/* 1.6: Userspace can request & wait on irq's:
*/
typedef struct drm_radeon_irq_emit {
int *irq_seq;
} drmRadeonIrqEmit;
-/**
- * \brief DRM_RADEON_IRQ_WAIT ioctl argument type.
- *
- * New in DRM 1.6: userspace can request and wait on IRQ's.
- */
typedef struct drm_radeon_irq_wait {
int irq_seq;
} drmRadeonIrqWait;
diff --git a/src/mesa/drivers/dri/radeon/server/radeon_dri.c b/src/mesa/drivers/dri/radeon/server/radeon_dri.c
index f14bd13a95..4271aa7da2 100644
--- a/src/mesa/drivers/dri/radeon/server/radeon_dri.c
+++ b/src/mesa/drivers/dri/radeon/server/radeon_dri.c
@@ -12,6 +12,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <unistd.h>
#include "driver.h"
#include "drm.h"
@@ -23,9 +24,6 @@
#include "radeon_sarea.h"
#include "sarea.h"
-#include <unistd.h>
-
-
/* HACK - for now, put this here... */
/* Alpha - this may need to be a variable to handle UP1x00 vs TITAN */
@@ -735,7 +733,7 @@ static int RADEONMemoryInit( const DRIDriverContext *ctx, RADEONInfoPtr info )
* Setups a RADEONDRIRec structure to be passed to radeon_dri.so for its
* initialization.
*/
-static int RADEONScreenInit( DRIDriverContext *ctx, RADEONInfoPtr info )
+static int RADEONScreenInit( const DRIDriverContext *ctx, RADEONInfoPtr info )
{
RADEONDRIPtr pRADEONDRI;
int err;
diff --git a/src/mesa/drivers/dri/radeon/server/radeon_reg.h b/src/mesa/drivers/dri/radeon/server/radeon_reg.h
index 2cd9dbe094..5570a43945 100644
--- a/src/mesa/drivers/dri/radeon/server/radeon_reg.h
+++ b/src/mesa/drivers/dri/radeon/server/radeon_reg.h
@@ -1,24 +1,4 @@
-/**
- * \file server/radeon_reg.h
- * \brief Registers and register definitions for the Radeon.
- *
- * \authors Kevin E. Martin <martin@xfree86.org>
- * \authors Rickard E. Faith <faith@valinux.com>
- * \authors Alan Hourihane <alanh@fairlite.demon.co.uk>
- *
- * \par References
- *
- * - RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
- * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
- * 1999.
- * - RAGE 128 Software Development Manual (Technical Reference Manual P/N
- * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
- *
- * \note !!!! FIXME !!!! THIS FILE HAS BEEN CONVERTED FROM r128_reg.h
- * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT
- * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED!
- */
-
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h,v 1.25 2003/02/07 18:08:59 martin Exp $ */
/*
* Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
* VA Linux Systems Inc., Fremont, California.
@@ -47,7 +27,28 @@
* DEALINGS IN THE SOFTWARE.
*/
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h,v 1.20 2002/10/12 01:38:07 martin Exp $ */
+/*
+ * Authors:
+ * Kevin E. Martin <martin@xfree86.org>
+ * Rickard E. Faith <faith@valinux.com>
+ * Alan Hourihane <alanh@fairlite.demon.co.uk>
+ *
+ * References:
+ *
+ * !!!! FIXME !!!!
+ * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
+ * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
+ * 1999.
+ *
+ * !!!! FIXME !!!!
+ * RAGE 128 Software Development Manual (Technical Reference Manual P/N
+ * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
+ *
+ */
+
+/* !!!! FIXME !!!! NOTE: THIS FILE HAS BEEN CONVERTED FROM r128_reg.h
+ * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT
+ * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED! */
#ifndef _RADEON_REG_H_
#define _RADEON_REG_H_
@@ -216,6 +217,10 @@
#define RADEON_CONFIG_APER_SIZE 0x0108
#define RADEON_CONFIG_BONDS 0x00e8
#define RADEON_CONFIG_CNTL 0x00e0
+# define RADEON_CFG_ATI_REV_A11 (0 << 16)
+# define RADEON_CFG_ATI_REV_A12 (1 << 16)
+# define RADEON_CFG_ATI_REV_A13 (2 << 16)
+# define RADEON_CFG_ATI_REV_ID_MASK (0xf << 16)
#define RADEON_CONFIG_MEMSIZE 0x00f8
#define RADEON_CONFIG_MEMSIZE_EMBEDDED 0x0114
#define RADEON_CONFIG_REG_1_BASE 0x010c
@@ -302,6 +307,10 @@
#define RADEON_CRTC2_PITCH 0x032c
#define RADEON_CRTC_STATUS 0x005c
# define RADEON_CRTC_VBLANK_SAVE (1 << 1)
+# define RADEON_CRTC_VBLANK_SAVE_CLEAR (1 << 1)
+#define RADEON_CRTC2_STATUS 0x03fc
+# define RADEON_CRTC2_VBLANK_SAVE (1 << 1)
+# define RADEON_CRTC2_VBLANK_SAVE_CLEAR (1 << 1)
#define RADEON_CRTC_V_SYNC_STRT_WID 0x020c
# define RADEON_CRTC_V_SYNC_STRT (0x7ff << 0)
# define RADEON_CRTC_V_SYNC_STRT_SHIFT 0
@@ -492,6 +501,7 @@
#define RADEON_DST_LINE_START 0x1600
#define RADEON_DST_LINE_END 0x1604
#define RADEON_DST_LINE_PATCOUNT 0x1608
+# define RADEON_BRES_CNTL_SHIFT 8
#define RADEON_DST_OFFSET 0x1404
#define RADEON_DST_PITCH 0x1408
#define RADEON_DST_PITCH_OFFSET 0x142c
@@ -554,6 +564,7 @@
#define RADEON_FP_GEN_CNTL 0x0284
# define RADEON_FP_FPON (1 << 0)
# define RADEON_FP_TMDS_EN (1 << 2)
+# define RADEON_FP_PANEL_FORMAT (1 << 3)
# define RADEON_FP_EN_TMDS (1 << 7)
# define RADEON_FP_DETECT_SENSE (1 << 8)
# define RADEON_FP_SEL_CRTC2 (1 << 13)
@@ -612,6 +623,8 @@
#define RADEON_GEN_INT_STATUS 0x0044
# define RADEON_VSYNC_INT_AK (1 << 2)
# define RADEON_VSYNC_INT (1 << 2)
+# define RADEON_VSYNC2_INT_AK (1 << 6)
+# define RADEON_VSYNC2_INT (1 << 6)
#define RADEON_GENENB 0x03c3 /* VGA */
#define RADEON_GENFC_RD 0x03ca /* VGA */
#define RADEON_GENFC_WT 0x03da /* VGA, 0x03ba */
@@ -708,6 +721,9 @@
#define RADEON_MM_DATA 0x0004
#define RADEON_MM_INDEX 0x0000
#define RADEON_MPLL_CNTL 0x000e /* PLL */
+#define RADEON_MPP_TB_CONFIG 0x01c0 /* ? */
+#define RADEON_MPP_GP_CONFIG 0x01c8 /* ? */
+
#define RADEON_N_VIF_COUNT 0x0248
@@ -863,6 +879,8 @@
# define RADEON_P2PLL_REF_DIV_MASK 0x03ff
# define RADEON_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */
# define RADEON_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */
+# define R300_PPLL_REF_DIV_ACC_MASK (0x3ff < 18)
+# define R300_PPLL_REF_DIV_ACC_SHIFT 18
#define RADEON_PALETTE_DATA 0x00b4
#define RADEON_PALETTE_30_DATA 0x00b8
#define RADEON_PALETTE_INDEX 0x00b0
@@ -1122,6 +1140,10 @@
# define RADEON_LOD_BIAS_SHIFT 8
# define RADEON_MAX_MIP_LEVEL_MASK (0x0f << 16)
# define RADEON_MAX_MIP_LEVEL_SHIFT 16
+# define RADEON_YUV_TO_RGB (1 << 20)
+# define RADEON_YUV_TEMPERATURE_COOL (0 << 21)
+# define RADEON_YUV_TEMPERATURE_HOT (1 << 21)
+# define RADEON_YUV_TEMPERATURE_MASK (1 << 21)
# define RADEON_WRAPEN_S (1 << 22)
# define RADEON_CLAMP_S_WRAP (0 << 23)
# define RADEON_CLAMP_S_MIRROR (1 << 23)
@@ -1129,6 +1151,8 @@
# define RADEON_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23)
# define RADEON_CLAMP_S_CLAMP_BORDER (4 << 23)
# define RADEON_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23)
+# define RADEON_CLAMP_S_CLAMP_GL (6 << 23)
+# define RADEON_CLAMP_S_MIRROR_CLAMP_GL (7 << 23)
# define RADEON_CLAMP_S_MASK (7 << 23)
# define RADEON_WRAPEN_T (1 << 26)
# define RADEON_CLAMP_T_WRAP (0 << 27)
@@ -1137,6 +1161,8 @@
# define RADEON_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27)
# define RADEON_CLAMP_T_CLAMP_BORDER (4 << 27)
# define RADEON_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27)
+# define RADEON_CLAMP_T_CLAMP_GL (6 << 27)
+# define RADEON_CLAMP_T_MIRROR_CLAMP_GL (7 << 27)
# define RADEON_CLAMP_T_MASK (7 << 27)
# define RADEON_BORDER_MODE_OGL (0 << 31)
# define RADEON_BORDER_MODE_D3D (1 << 31)
@@ -1152,6 +1178,11 @@
# define RADEON_TXFORMAT_ARGB8888 (6 << 0)
# define RADEON_TXFORMAT_RGBA8888 (7 << 0)
# define RADEON_TXFORMAT_Y8 (8 << 0)
+# define RADEON_TXFORMAT_VYUY422 (10 << 0)
+# define RADEON_TXFORMAT_YVYU422 (11 << 0)
+# define RADEON_TXFORMAT_DXT1 (12 << 0)
+# define RADEON_TXFORMAT_DXT23 (14 << 0)
+# define RADEON_TXFORMAT_DXT45 (15 << 0)
# define RADEON_TXFORMAT_FORMAT_MASK (31 << 0)
# define RADEON_TXFORMAT_FORMAT_SHIFT 0
# define RADEON_TXFORMAT_APPLE_YUV_MODE (1 << 5)
@@ -1161,6 +1192,10 @@
# define RADEON_TXFORMAT_WIDTH_SHIFT 8
# define RADEON_TXFORMAT_HEIGHT_MASK (15 << 12)
# define RADEON_TXFORMAT_HEIGHT_SHIFT 12
+# define RADEON_TXFORMAT_F5_WIDTH_MASK (15 << 16)
+# define RADEON_TXFORMAT_F5_WIDTH_SHIFT 16
+# define RADEON_TXFORMAT_F5_HEIGHT_MASK (15 << 20)
+# define RADEON_TXFORMAT_F5_HEIGHT_SHIFT 20
# define RADEON_TXFORMAT_ST_ROUTE_STQ0 (0 << 24)
# define RADEON_TXFORMAT_ST_ROUTE_MASK (3 << 24)
# define RADEON_TXFORMAT_ST_ROUTE_STQ1 (1 << 24)
@@ -1173,6 +1208,26 @@
# define RADEON_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29)
# define RADEON_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30)
# define RADEON_TXFORMAT_PERSPECTIVE_ENABLE (1 << 31)
+#define RADEON_PP_CUBIC_FACES_0 0x1d24
+#define RADEON_PP_CUBIC_FACES_1 0x1d28
+#define RADEON_PP_CUBIC_FACES_2 0x1d2c
+# define RADEON_FACE_WIDTH_1_SHIFT 0
+# define RADEON_FACE_HEIGHT_1_SHIFT 4
+# define RADEON_FACE_WIDTH_1_MASK (0xf << 0)
+# define RADEON_FACE_HEIGHT_1_MASK (0xf << 4)
+# define RADEON_FACE_WIDTH_2_SHIFT 8
+# define RADEON_FACE_HEIGHT_2_SHIFT 12
+# define RADEON_FACE_WIDTH_2_MASK (0xf << 8)
+# define RADEON_FACE_HEIGHT_2_MASK (0xf << 12)
+# define RADEON_FACE_WIDTH_3_SHIFT 16
+# define RADEON_FACE_HEIGHT_3_SHIFT 20
+# define RADEON_FACE_WIDTH_3_MASK (0xf << 16)
+# define RADEON_FACE_HEIGHT_3_MASK (0xf << 20)
+# define RADEON_FACE_WIDTH_4_SHIFT 24
+# define RADEON_FACE_HEIGHT_4_SHIFT 28
+# define RADEON_FACE_WIDTH_4_MASK (0xf << 24)
+# define RADEON_FACE_HEIGHT_4_MASK (0xf << 28)
+
#define RADEON_PP_TXOFFSET_0 0x1c5c
#define RADEON_PP_TXOFFSET_1 0x1c74
#define RADEON_PP_TXOFFSET_2 0x1c8c
@@ -1187,6 +1242,39 @@
# define RADEON_TXO_MICRO_TILE_OPT (2 << 3)
# define RADEON_TXO_OFFSET_MASK 0xffffffe0
# define RADEON_TXO_OFFSET_SHIFT 5
+
+#define RADEON_PP_CUBIC_OFFSET_T0_0 0x1dd0 /* bits [31:5] */
+#define RADEON_PP_CUBIC_OFFSET_T0_1 0x1dd4
+#define RADEON_PP_CUBIC_OFFSET_T0_2 0x1dd8
+#define RADEON_PP_CUBIC_OFFSET_T0_3 0x1ddc
+#define RADEON_PP_CUBIC_OFFSET_T0_4 0x1de0
+#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00
+#define RADEON_PP_CUBIC_OFFSET_T1_1 0x1e04
+#define RADEON_PP_CUBIC_OFFSET_T1_2 0x1e08
+#define RADEON_PP_CUBIC_OFFSET_T1_3 0x1e0c
+#define RADEON_PP_CUBIC_OFFSET_T1_4 0x1e10
+#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14
+#define RADEON_PP_CUBIC_OFFSET_T2_1 0x1e18
+#define RADEON_PP_CUBIC_OFFSET_T2_2 0x1e1c
+#define RADEON_PP_CUBIC_OFFSET_T2_3 0x1e20
+#define RADEON_PP_CUBIC_OFFSET_T2_4 0x1e24
+
+#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */
+#define RADEON_PP_TEX_SIZE_1 0x1d0c
+#define RADEON_PP_TEX_SIZE_2 0x1d14
+# define RADEON_TEX_USIZE_MASK (0x7ff << 0)
+# define RADEON_TEX_USIZE_SHIFT 0
+# define RADEON_TEX_VSIZE_MASK (0x7ff << 16)
+# define RADEON_TEX_VSIZE_SHIFT 16
+# define RADEON_SIGNED_RGB_MASK (1 << 30)
+# define RADEON_SIGNED_RGB_SHIFT 30
+# define RADEON_SIGNED_ALPHA_MASK (1 << 31)
+# define RADEON_SIGNED_ALPHA_SHIFT 31
+#define RADEON_PP_TEX_PITCH_0 0x1d08 /* NPOT */
+#define RADEON_PP_TEX_PITCH_1 0x1d10 /* NPOT */
+#define RADEON_PP_TEX_PITCH_2 0x1d18 /* NPOT */
+/* note: bits 13-5: 32 byte aligned stride of texture map */
+
#define RADEON_PP_TXCBLEND_0 0x1c60
#define RADEON_PP_TXCBLEND_1 0x1c78
#define RADEON_PP_TXCBLEND_2 0x1c90
diff --git a/src/mesa/drivers/dri/radeon/server/radeon_sarea.h b/src/mesa/drivers/dri/radeon/server/radeon_sarea.h
index f682bb6b6a..81e4325d7a 100644
--- a/src/mesa/drivers/dri/radeon/server/radeon_sarea.h
+++ b/src/mesa/drivers/dri/radeon/server/radeon_sarea.h
@@ -296,9 +296,9 @@ typedef struct {
/** \brief Texture regions.
* Last element is sentinal
*/
- radeon_tex_region_t texList[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1];
+ drmTextureRegion texList[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1];
/** \brief last time texture was uploaded */
- int texAge[RADEON_NR_TEX_HEAPS];
+ unsigned int texAge[RADEON_NR_TEX_HEAPS];
/*@}*/
int ctxOwner; /**< \brief last context to upload state */
diff --git a/src/mesa/tnl_dd/imm/NOTES.imm b/src/mesa/tnl_dd/imm/NOTES.imm
new file mode 100644
index 0000000000..9b2bd65e4b
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/NOTES.imm
@@ -0,0 +1,112 @@
+
+NOTE:
+
+These files are incomplete. They do not yet form a working
+implementation of hte concepts discused below.
+
+
+OVERVIEW
+
+The t_dd_imm_* files form a set of templates to produce driver -
+specific software tnl modules for a small subset of transformation and
+lighting states.
+
+The approach is quite different to the large vertex buffers of the
+src/tnl module, and is based around a cache of four recent vertices
+and a 'current' vertex which is updated directly from the Color,
+Normal, Texcoord, SecondaryColor and Fog entrypoints.
+
+The current vertex is actually a composite of the ctx->Current values
+and a partial hardware vertex maintained where the hardware values
+differ from those in ctx->Current. For example, clamped color values
+are kept in the hardware vertex, while texcoords remain in
+ctx->Current.
+
+A crude diagram:
+
+ +--------------+ +-------------------+
+ | ctx->Current | | Current-HW-vertex |
+ +--------------+ +-------------------+
+ \ /
+ \ /
+ \ /
+ \ /
+ --------- --------
+ | |
+ v v
+ +--------+ +--------+ +--------+ +--------+
+ | vert-0 | | vert-1 | | vert-2 | | vert-3 |
+ +--------+ +--------+ +--------+ +--------+
+ |
+ |
+ v
+
+ DMA
+
+
+Here values from ctx->Current and current-HW-vertex are merged to
+build vert-2, which is then dumped to hardware (DMA). A state machine
+determines which vertex is built in turn, and how the vertices are
+used to present primitives to hardware. These actions all occur
+during a call to Vertex{234}f{v}.
+
+Each vert-n includes clip coordinates and a clipmask in addition to
+the hardware (window) coordinates. This information allows clipping
+to take place directly on these vertices, if need be.
+
+t_dd_imm_capi.h
+
+ Color{34}{fub}{v}() implementations. These update both
+ ctx->Current (unclamped float colors) and current-HW-vertex
+ with hardware-specific color values (typically unsigned
+ bytes).
+
+ When lighting is enabled, the functions from src/api_noop.c
+ should be used, which just update ctx->Current. (The
+ current-hw-vertex colors are produced from lighting, which is
+ keyed to Normal3f).
+
+t_dd_imm_vb.c
+
+ Support functions for clipping and fallback. See
+ t_dd_imm_primtmp.h.
+
+t_dd_imm_napi.c
+t_dd_imm_napi.h
+
+ Versions of Normal3f{v} to perform lighting with one or more
+ infinite lights. Updates ctx->Current.Normal and the current
+ HW colors.
+
+ When lighting is disabled, use the functions from api_noop.c
+ instead.
+
+
+t_dd_imm_primtmp.h
+
+ State machine to control emission of vertices and primitives
+ to hardware. Called indirectly from Vertex{234}f{v}. Capable
+ of supporting hardware strip and fan primitives, and of
+ decomposing to discreet primitives for clipping or fallback,
+ or where the native primitive is unavailable.
+
+t_dd_imm_tapi.h
+
+ Implementations of TexCoord{v} and MultiTexCoord4f{v}ARB to
+ fire a callback when transitioning to projective texture.
+ Most drivers will need to change vertex format at this point,
+ some may need to enable a software rasterization fallback.
+
+t_dd_imm_vapi.h
+
+ Implementations of Vertex{234}f{v}. These perform
+ transformation and cliptesting on their arguments, then jump
+ into the state machine implemented in primtmp.h.
+
+t_dd_imm_vertex.h
+
+ Support functions for building and clip-interpolating hardware
+ vertices. Called from primtmp.h.
+
+
+Keith Whitwell, June 2001. \ No newline at end of file
diff --git a/src/mesa/tnl_dd/imm/t_dd_imm_capi.h b/src/mesa/tnl_dd/imm/t_dd_imm_capi.h
new file mode 100644
index 0000000000..77f3a4ab49
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/t_dd_imm_capi.h
@@ -0,0 +1,419 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL 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:
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+/* Template for immediate mode color functions.
+ *
+ * FIXME: Floating-point color versions of these...
+ */
+
+
+static void TAG(Color3f)( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = CLAMP(r, 0.0f, 1.0f);
+ CURRENT_COLOR( GCOMP ) = CLAMP(g, 0.0f, 1.0f);
+ CURRENT_COLOR( BCOMP ) = CLAMP(b, 0.0f, 1.0f);
+ CURRENT_COLOR( ACOMP ) = 1.0f;
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( RCOMP ), r );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( GCOMP ), g );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( BCOMP ), b );
+ CURRENT_COLOR( ACOMP ) = 255;
+#endif
+}
+
+static void TAG(Color3fv)( const GLfloat *v )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = CLAMP(v[0], 0.0f, 1.0f);
+ CURRENT_COLOR( GCOMP ) = CLAMP(v[1], 0.0f, 1.0f);
+ CURRENT_COLOR( BCOMP ) = CLAMP(v[2], 0.0f, 1.0f);
+ CURRENT_COLOR( ACOMP ) = 1.0f;
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( RCOMP ), v[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( GCOMP ), v[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( BCOMP ), v[2] );
+ CURRENT_COLOR( ACOMP ) = 255;
+#endif
+}
+
+static void TAG(Color3ub)( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = UBYTE_TO_FLOAT( r );
+ CURRENT_COLOR( GCOMP ) = UBYTE_TO_FLOAT( g );
+ CURRENT_COLOR( BCOMP ) = UBYTE_TO_FLOAT( b );
+ CURRENT_COLOR( ACOMP ) = 1.0f;
+#else
+ CURRENT_COLOR( RCOMP ) = r;
+ CURRENT_COLOR( GCOMP ) = g;
+ CURRENT_COLOR( BCOMP ) = b;
+ CURRENT_COLOR( ACOMP ) = 255;
+#endif
+}
+
+static void TAG(Color3ubv)( const GLubyte *v )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = UBYTE_TO_FLOAT( v[0] );
+ CURRENT_COLOR( GCOMP ) = UBYTE_TO_FLOAT( v[1] );
+ CURRENT_COLOR( BCOMP ) = UBYTE_TO_FLOAT( v[2] );
+ CURRENT_COLOR( ACOMP ) = 1.0f;
+#else
+ CURRENT_COLOR( RCOMP ) = v[0];
+ CURRENT_COLOR( GCOMP ) = v[1];
+ CURRENT_COLOR( BCOMP ) = v[2];
+ CURRENT_COLOR( ACOMP ) = 255;
+#endif
+}
+
+static void TAG(Color4f)( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = CLAMP(r, 0.0f, 1.0f);
+ CURRENT_COLOR( GCOMP ) = CLAMP(g, 0.0f, 1.0f);
+ CURRENT_COLOR( BCOMP ) = CLAMP(b, 0.0f, 1.0f);
+ CURRENT_COLOR( ACOMP ) = CLAMP(a, 0.0f, 1.0f);
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( RCOMP ), r );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( GCOMP ), g );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( BCOMP ), b );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( ACOMP ), a );
+#endif
+}
+
+static void TAG(Color4fv)( const GLfloat *v )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = CLAMP(v[0], 0.0f, 1.0f);
+ CURRENT_COLOR( GCOMP ) = CLAMP(v[1], 0.0f, 1.0f);
+ CURRENT_COLOR( BCOMP ) = CLAMP(v[2], 0.0f, 1.0f);
+ CURRENT_COLOR( ACOMP ) = CLAMP(v[3], 0.0f, 1.0f);
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( RCOMP ), v[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( GCOMP ), v[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( BCOMP ), v[2] );
+ UNCLAMPED_FLOAT_TO_UBYTE( CURRENT_COLOR( ACOMP ), v[3] );
+#endif
+}
+
+static void TAG(Color4ub)( GLubyte r, GLubyte g, GLubyte b, GLubyte a )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = UBYTE_TO_FLOAT( r );
+ CURRENT_COLOR( GCOMP ) = UBYTE_TO_FLOAT( g );
+ CURRENT_COLOR( BCOMP ) = UBYTE_TO_FLOAT( b );
+ CURRENT_COLOR( ACOMP ) = UBYTE_TO_FLOAT( a );
+#else
+ CURRENT_COLOR( RCOMP ) = r;
+ CURRENT_COLOR( GCOMP ) = g;
+ CURRENT_COLOR( BCOMP ) = b;
+ CURRENT_COLOR( ACOMP ) = a;
+#endif
+}
+
+static void TAG(Color4ubv)( const GLubyte *v )
+{
+ GET_CURRENT;
+#ifdef COLOR_IS_FLOAT
+ CURRENT_COLOR( RCOMP ) = UBYTE_TO_FLOAT( v[0] );
+ CURRENT_COLOR( GCOMP ) = UBYTE_TO_FLOAT( v[1] );
+ CURRENT_COLOR( BCOMP ) = UBYTE_TO_FLOAT( v[2] );
+ CURRENT_COLOR( ACOMP ) = UBYTE_TO_FLOAT( v[3] );
+#else
+ CURRENT_COLOR( RCOMP ) = v[0];
+ CURRENT_COLOR( GCOMP ) = v[1];
+ CURRENT_COLOR( BCOMP ) = v[2];
+ CURRENT_COLOR( ACOMP ) = v[3];
+#endif
+}
+
+
+static void TAG(ColorMaterial3f)( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = r;
+ color[1] = g;
+ color[2] = b;
+ color[3] = 1.0;
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+static void TAG(ColorMaterial3fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = v[0];
+ color[1] = v[1];
+ color[2] = v[2];
+ color[3] = 1.0;
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+static void TAG(ColorMaterial3ub)( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = UBYTE_TO_FLOAT( r );
+ color[1] = UBYTE_TO_FLOAT( g );
+ color[2] = UBYTE_TO_FLOAT( b );
+ color[3] = 1.0;
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+static void TAG(ColorMaterial3ubv)( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = UBYTE_TO_FLOAT( v[0] );
+ color[1] = UBYTE_TO_FLOAT( v[1] );
+ color[2] = UBYTE_TO_FLOAT( v[2] );
+ color[3] = 1.0;
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+static void TAG(ColorMaterial4f)( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = r;
+ color[1] = g;
+ color[2] = b;
+ color[3] = a;
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+static void TAG(ColorMaterial4fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = v[0];
+ color[1] = v[1];
+ color[2] = v[2];
+ color[3] = v[3];
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+static void TAG(ColorMaterial4ub)( GLubyte r, GLubyte g, GLubyte b, GLubyte a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = UBYTE_TO_FLOAT( r );
+ color[1] = UBYTE_TO_FLOAT( g );
+ color[2] = UBYTE_TO_FLOAT( b );
+ color[3] = UBYTE_TO_FLOAT( a );
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+static void TAG(ColorMaterial4ubv)( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *color = ctx->Current.Color;
+
+ color[0] = UBYTE_TO_FLOAT( v[0] );
+ color[1] = UBYTE_TO_FLOAT( v[1] );
+ color[2] = UBYTE_TO_FLOAT( v[2] );
+ color[3] = UBYTE_TO_FLOAT( v[3] );
+
+ _mesa_update_color_material( ctx, color );
+ RECALC_BASE_COLOR( ctx );
+}
+
+
+
+
+
+/* =============================================================
+ * Color chooser functions:
+ */
+
+static void TAG(choose_Color3f)( GLfloat r, GLfloat g, GLfloat b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color3f = TAG(ColorMaterial3f);
+ } else {
+ ctx->Exec->Color3f = _mesa_noop_Color3f;
+ }
+ } else {
+ ctx->Exec->Color3f = TAG(Color3f);
+ }
+ glColor3f( r, g, b );
+}
+
+static void TAG(choose_Color3fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color3fv = TAG(ColorMaterial3fv);
+ } else {
+ ctx->Exec->Color3fv = _mesa_noop_Color3fv;
+ }
+ } else {
+ ctx->Exec->Color3fv = TAG(Color3fv);
+ }
+ glColor3fv( v );
+}
+
+static void TAG(choose_Color3ub)( GLubyte r, GLubyte g, GLubyte b )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color3ub = TAG(ColorMaterial3ub);
+ } else {
+ ctx->Exec->Color3ub = _mesa_noop_Color3ub;
+ }
+ } else {
+ ctx->Exec->Color3ub = TAG(Color3ub);
+ }
+ glColor3ub( r, g, b );
+}
+
+static void TAG(choose_Color3ubv)( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color3ubv = TAG(ColorMaterial3ubv);
+ } else {
+ ctx->Exec->Color3ubv = _mesa_noop_Color3ubv;
+ }
+ } else {
+ ctx->Exec->Color3ubv = TAG(Color3ubv);
+ }
+ glColor3ubv( v );
+}
+
+static void TAG(choose_Color4f)( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color4f = TAG(ColorMaterial4f);
+ } else {
+ ctx->Exec->Color4f = _mesa_noop_Color4f;
+ }
+ } else {
+ ctx->Exec->Color4f = TAG(Color4f);
+ }
+ glColor4f( r, g, b, a );
+}
+
+static void TAG(choose_Color4fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color4fv = TAG(ColorMaterial4fv);
+ } else {
+ ctx->Exec->Color4fv = _mesa_noop_Color4fv;
+ }
+ } else {
+ ctx->Exec->Color4fv = TAG(Color4fv);
+ }
+ glColor4fv( v );
+}
+
+static void TAG(choose_Color4ub)( GLubyte r, GLubyte g, GLubyte b, GLubyte a )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color4ub = TAG(ColorMaterial4ub);
+ } else {
+ ctx->Exec->Color4ub = _mesa_noop_Color4ub;
+ }
+ } else {
+ ctx->Exec->Color4ub = TAG(Color4ub);
+ }
+ glColor4ub( r, g, b, a );
+}
+
+static void TAG(choose_Color4ubv)( const GLubyte *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ( ctx->Light.Enabled ) {
+ if ( ctx->Light.ColorMaterialEnabled ) {
+ ctx->Exec->Color4ubv = TAG(ColorMaterial4ubv);
+ } else {
+ ctx->Exec->Color4ubv = _mesa_noop_Color4ubv;
+ }
+ } else {
+ ctx->Exec->Color4ubv = TAG(Color4ubv);
+ }
+ glColor4ubv( v );
+}
+
+
+
+#undef GET_CURRENT
+#undef CURRENT_COLOR
+#undef CURRENT_SPECULAR
+#undef COLOR_IS_FLOAT
+#undef RECALC_BASE_COLOR
+#undef TAG
diff --git a/src/mesa/tnl_dd/imm/t_dd_imm_napi.h b/src/mesa/tnl_dd/imm/t_dd_imm_napi.h
new file mode 100644
index 0000000000..9844f615ff
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/t_dd_imm_napi.h
@@ -0,0 +1,226 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith_whitwell@yahoo.com>
+ */
+
+/* Template for immediate mode normal functions. Optimize for infinite
+ * lights when doing software lighting.
+ */
+
+static void TAG(Normal3f_single)( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_VERTEX;
+ const struct gl_light *light = ctx->Light.EnabledList.prev;
+ GLfloat n_dot_h, n_dot_VP, spec, sum[3];
+ GLfloat *normal = ctx->Current.Normal;
+ GLfloat scale = 1.0;
+
+ ASSIGN_3V( normal, x, y, z );
+ COPY_3V( sum, BASE_COLOR );
+
+ if ( IND & NORM_RESCALE ) {
+ scale = ctx->_ModelViewInvScale;
+ } else if ( IND & NORM_NORMALIZE ) {
+ scale = LEN_3FV( normal );
+ if ( scale != 0.0 ) scale = 1.0 / scale;
+ }
+
+ n_dot_VP = DOT3( normal, light->_VP_inf_norm ) * scale;
+ if ( n_dot_VP > 0.0F ) {
+ ACC_SCALE_SCALAR_3V( sum, n_dot_VP, light->_MatDiffuse[0] );
+ n_dot_h = DOT3( normal, light->_h_inf_norm ) * scale;
+ if ( n_dot_h > 0.0F ) {
+ GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V( sum, spec, light->_MatSpecular[0] );
+ }
+ }
+
+#ifdef LIT_COLOR_IS_FLOAT
+ LIT_COLOR ( RCOMP ) = CLAMP(sum[0], 0.0f, 0.1f);
+ LIT_COLOR ( GCOMP ) = CLAMP(sum[1], 0.0f, 0.1f);
+ LIT_COLOR ( BCOMP ) = CLAMP(sum[2], 0.0f, 0.1f);
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( RCOMP ), sum[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( GCOMP ), sum[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( BCOMP ), sum[2] );
+#endif
+ LIT_COLOR( ACOMP ) = LIT_ALPHA;
+}
+
+static void TAG(Normal3fv_single)( const GLfloat *normal )
+{
+ GET_CURRENT_VERTEX;
+ const struct gl_light *light = ctx->Light.EnabledList.prev;
+ GLfloat n_dot_h, n_dot_VP, spec, sum[3];
+ GLfloat scale = 1.0;
+
+ COPY_3V( ctx->Current.Normal, normal );
+ COPY_3V( sum, BASE_COLOR );
+
+ if ( IND & NORM_RESCALE ) {
+ scale = ctx->_ModelViewInvScale;
+ } else if ( IND & NORM_NORMALIZE ) {
+ scale = LEN_3FV( normal );
+ if ( scale != 0.0 ) scale = 1.0 / scale;
+ }
+
+ n_dot_VP = DOT3( normal, light->_VP_inf_norm ) * scale;
+ if ( n_dot_VP > 0.0F ) {
+ ACC_SCALE_SCALAR_3V( sum, n_dot_VP, light->_MatDiffuse[0] );
+ n_dot_h = DOT3( normal, light->_h_inf_norm ) * scale;
+ if ( n_dot_h > 0.0F ) {
+ GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V( sum, spec, light->_MatSpecular[0] );
+ }
+ }
+
+#ifdef LIT_COLOR_IS_FLOAT
+ LIT_COLOR ( RCOMP ) = CLAMP(sum[0], 0.0f, 0.1f);
+ LIT_COLOR ( GCOMP ) = CLAMP(sum[1], 0.0f, 0.1f);
+ LIT_COLOR ( BCOMP ) = CLAMP(sum[2], 0.0f, 0.1f);
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( RCOMP ), sum[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( GCOMP ), sum[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( BCOMP ), sum[2] );
+#endif
+ LIT_COLOR( ACOMP ) = LIT_ALPHA;
+}
+
+
+static void TAG(Normal3f_multi)( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_VERTEX;
+ struct gl_light *light;
+ GLfloat n_dot_h, n_dot_VP, spec, sum[3], tmp[3];
+ GLfloat *normal;
+
+ ASSIGN_3V( ctx->Current.Normal, x, y, z );
+ COPY_3V( sum, BASE_COLOR );
+
+ if ( IND & NORM_RESCALE ) {
+ normal = tmp;
+ ASSIGN_3V( normal, x, y, z );
+ SELF_SCALE_SCALAR_3V( normal, ctx->_ModelViewInvScale );
+ } else if ( IND & NORM_NORMALIZE ) {
+ normal = tmp;
+ ASSIGN_3V( normal, x, y, z );
+ NORMALIZE_3FV( normal );
+ } else {
+ normal = ctx->Current.Normal;
+ }
+
+ foreach ( light, &ctx->Light.EnabledList ) {
+ n_dot_VP = DOT3( normal, light->_VP_inf_norm );
+ if ( n_dot_VP > 0.0F ) {
+ ACC_SCALE_SCALAR_3V( sum, n_dot_VP, light->_MatDiffuse[0] );
+ n_dot_h = DOT3( normal, light->_h_inf_norm );
+ if ( n_dot_h > 0.0F ) {
+ GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V( sum, spec, light->_MatSpecular[0] );
+ }
+ }
+ }
+
+#ifdef LIT_COLOR_IS_FLOAT
+ LIT_COLOR ( RCOMP ) = CLAMP(sum[0], 0.0f, 0.1f);
+ LIT_COLOR ( GCOMP ) = CLAMP(sum[1], 0.0f, 0.1f);
+ LIT_COLOR ( BCOMP ) = CLAMP(sum[2], 0.0f, 0.1f);
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( RCOMP ), sum[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( GCOMP ), sum[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( BCOMP ), sum[2] );
+#endif
+ LIT_COLOR( ACOMP ) = LIT_ALPHA;
+}
+
+static void TAG(Normal3fv_multi)( const GLfloat *n )
+{
+ GET_CURRENT_VERTEX;
+ struct gl_light *light;
+ GLfloat n_dot_h, n_dot_VP, spec, sum[3], tmp[3];
+ GLfloat *normal;
+
+ COPY_3V( ctx->Current.Normal, n );
+ COPY_3V( sum, BASE_COLOR );
+
+ if ( IND & NORM_RESCALE ) {
+ normal = tmp;
+ COPY_3V( normal, n );
+ SELF_SCALE_SCALAR_3V( normal, ctx->_ModelViewInvScale );
+ } else if ( IND & NORM_NORMALIZE ) {
+ normal = tmp;
+ COPY_3V( normal, n );
+ NORMALIZE_3FV( normal );
+ } else {
+ normal = ctx->Current.Normal;
+ }
+
+ foreach ( light, &ctx->Light.EnabledList ) {
+ n_dot_VP = DOT3( normal, light->_VP_inf_norm );
+ if ( n_dot_VP > 0.0F ) {
+ ACC_SCALE_SCALAR_3V( sum, n_dot_VP, light->_MatDiffuse[0] );
+ n_dot_h = DOT3( normal, light->_h_inf_norm );
+ if ( n_dot_h > 0.0F ) {
+ GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V( sum, spec, light->_MatSpecular[0] );
+ }
+ }
+ }
+
+#ifdef LIT_COLOR_IS_FLOAT
+ LIT_COLOR ( RCOMP ) = CLAMP(sum[0], 0.0f, 0.1f);
+ LIT_COLOR ( GCOMP ) = CLAMP(sum[1], 0.0f, 0.1f);
+ LIT_COLOR ( BCOMP ) = CLAMP(sum[2], 0.0f, 0.1f);
+#else
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( RCOMP ), sum[0] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( GCOMP ), sum[1] );
+ UNCLAMPED_FLOAT_TO_UBYTE( LIT_COLOR( BCOMP ), sum[2] );
+#endif
+ LIT_COLOR( ACOMP ) = LIT_ALPHA;
+}
+
+
+
+static void TAG(init_norm)( void )
+{
+ norm_tab[IND].normal3f_single = TAG(Normal3f_single);
+ norm_tab[IND].normal3fv_single = TAG(Normal3fv_single);
+ norm_tab[IND].normal3f_multi = TAG(Normal3f_multi);
+ norm_tab[IND].normal3fv_multi = TAG(Normal3fv_multi);
+}
+
+
+
+#ifndef PRESERVE_NORMAL_DEFS
+#undef GET_CURRENT
+#undef GET_CURRENT_VERTEX
+#undef LIT_COLOR
+#undef LIT_COLOR_IS_FLOAT
+#endif
+#undef PRESERVE_NORMAL_DEFS
+#undef IND
+#undef TAG
diff --git a/src/mesa/tnl_dd/imm/t_dd_imm_primtmp.h b/src/mesa/tnl_dd/imm/t_dd_imm_primtmp.h
new file mode 100644
index 0000000000..97dca3fd42
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/t_dd_imm_primtmp.h
@@ -0,0 +1,570 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL 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 <keithw@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+/* Template for immediate mode vertices.
+ *
+ * Probably instantiate once for each vertex format used:
+ * - TINY_VERTICES
+ * - TEX0_VERTICES
+ * - TEX1_VERTICES
+ * - PTEX_VERTICES
+ *
+ * Have to handle TEX->PTEX transition somehow.
+ */
+
+#define DBG 0
+
+
+
+/* =============================================================
+ * GL_POINTS
+ */
+
+static void TAG(flush_point_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ if ( !v0->mask ) {
+ LOCAL_VARS;
+ DRAW_POINT( v0 );
+ }
+}
+
+
+/* =============================================================
+ * GL_LINES
+ */
+
+static void TAG(flush_line_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_line_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ FLUSH_VERTEX = TAG(flush_line_1);
+ ACTIVE_VERTEX = IMM_VERTICES( 1 );
+}
+
+static void TAG(flush_line_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v1 = v0 - 1;
+ ACTIVE_VERTEX = IMM_VERTICES( 0 );
+ FLUSH_VERTEX = TAG(flush_line_0);
+ if (FALLBACK_OR_CLIPPING)
+ CLIP_OR_DRAW_LINE( ctx, v1, v0 );
+ else
+ DRAW_LINE( ctx, v1, v0 );
+}
+
+
+/* =============================================================
+ * GL_LINE_LOOP
+ */
+
+static void TAG(flush_line_loop_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_line_loop_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_line_loop_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ ACTIVE_VERTEX = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_line_loop_1);
+}
+
+#define DRAW_LINELOOP_LINE( a, b ) \
+ if (!HAVE_LINE_STRIP || FALLBACK_OR_CLIPPING) { \
+ CLIP_OR_DRAW_LINE( ctx, a, b ); \
+ } else if (EXTEND_PRIM( 1 )) { \
+ EMIT_VERTEX( b ); \
+ } else { \
+ BEGIN_PRIM( GL_LINE_STRIP, 2 ); \
+ EMIT_VERTEX( a ); \
+ EMIT_VERTEX( b ); \
+ }
+
+static void TAG(flush_line_loop_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v1 = v0 - 1;
+ ACTIVE_VERTEX = v1;
+ FLUSH_VERTEX = TAG(flush_line_loop_2);
+ DRAW_LINELOOP_LINE( v1, v0 );
+}
+
+static void TAG(flush_line_loop_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v1 = v0 + 1;
+ ACTIVE_VERTEX = v1;
+ FLUSH_VERTEX = TAG(flush_line_loop_1);
+ DRAW_LINELOOP_LINE( v1, v0 );
+}
+
+static void TAG(end_line_loop)( GLcontext *ctx )
+{
+ LOCAL_VARS;
+
+ if ( FLUSH_VERTEX != TAG(flush_line_loop_0) ) {
+ TNL_VERTEX *v1 = ACTIVE_VERTEX;
+ TNL_VERTEX *v0 = IMM_VERTICES( 0 );
+ DRAW_LINELOOP_LINE( v1, v0 );
+ }
+}
+
+
+
+/* =============================================================
+ * GL_LINE_STRIP
+ */
+
+static void TAG(flush_line_strip_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_line_strip_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_line_strip_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ ACTIVE_VERTEX = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_line_strip_0b);
+}
+
+
+static void TAG(flush_line_strip_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v1 = v0 - 1;
+
+ ACTIVE_VERTEX = v1;
+ FLUSH_VERTEX = TAG(flush_line_strip_2);
+
+ if (!HAVE_LINE_STRIP || FALLBACK_OR_CLIPPING)
+ CLIP_OR_DRAW_LINE( ctx, v1, v0 );
+ else if (EXTEND_PRIM( 1 )) {
+ EMIT_VERTEX( v0 );
+ } else {
+ BEGIN_PRIM( GL_LINE_STRIP, 2 );
+ EMIT_VERTEX( v1 );
+ EMIT_VERTEX( v0 );
+ }
+}
+
+static void TAG(flush_line_strip_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v1 = v0 + 1;
+
+ ACTIVE_VERTEX = v1;
+ FLUSH_VERTEX = TAG(flush_line_strip_1);
+
+ if (!HAVE_LINE_STRIP || FALLBACK_OR_CLIPPING)
+ CLIP_OR_DRAW_LINE( ctx, v1, v0 );
+ else if (EXTEND_PRIM( 1 )) {
+ EMIT_VERTEX( v0 );
+ } else {
+ BEGIN_PRIM( GL_LINE_STRIP, 2 );
+ EMIT_VERTEX( v1 );
+ EMIT_VERTEX( v0 );
+ }
+}
+
+
+
+/* =============================================================
+ * GL_TRIANGLES
+ */
+
+static void TAG(flush_triangle_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_triangle_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_triangle_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ if ( DBG ) fprintf( stderr, __FUNCTION__ "\n" );
+
+ ACTIVE_VERTEX = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_triangle_1);
+ BEGIN_PRIM( GL_TRIANGLES, 0 );
+}
+
+static void TAG(flush_triangle_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ if ( DBG ) fprintf( stderr, __FUNCTION__ "\n" );
+
+ ACTIVE_VERTEX = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_triangle_2);
+}
+
+static void TAG(flush_triangle_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v2 = v0 - 2;
+ TNL_VERTEX *v1 = v0 - 1;
+
+ if ( DBG ) fprintf( stderr, __FUNCTION__ "\n" );
+
+ ACTIVE_VERTEX = v2;
+ FLUSH_VERTEX = TAG(flush_triangle_0);
+
+ /* nothing gained by trying to emit as hw primitives -- that
+ * happens normally in this case.
+ */
+ if (FALLBACK_OR_CLIPPING)
+ CLIP_OR_DRAW_TRI( ctx, v2, v1, v0 );
+ else
+ DRAW_TRI( ctx, v2, v1, v0 );
+}
+
+
+
+
+/* =============================================================
+ * GL_TRIANGLE_STRIP
+ */
+
+static void TAG(flush_tri_strip_3)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_tri_strip_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_tri_strip_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_tri_strip_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 1 );
+ FLUSH_VERTEX = TAG(flush_tri_strip_1);
+}
+
+static void TAG(flush_tri_strip_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 2 );
+ FLUSH_VERTEX = TAG(flush_tri_strip_2);
+}
+
+#define DO_TRISTRIP_TRI( vert0, vert1 ) \
+ if (!HAVE_TRI_STRIP || FALLBACK_OR_CLIPPING) { \
+ TNL_VERTEX *v2 = IMM_VERTICES( vert0 ); \
+ TNL_VERTEX *v1 = IMM_VERTICES( vert1 ); \
+ TAG(draw_tri)( ctx, v2, v1, v0 ); \
+ } else if (EXTEND_PRIM( 1 )) { \
+ EMIT_VERTEX( v0 ); \
+ } else { \
+ TNL_VERTEX *v2 = IMM_VERTICES( vert0 ); \
+ TNL_VERTEX *v1 = IMM_VERTICES( vert1 ); \
+ BEGIN_PRIM( GL_TRIANGLE_STRIP, 3 ); \
+ EMIT_VERTEX( v2 ); \
+ EMIT_VERTEX( v1 ); \
+ EMIT_VERTEX( v0 ); \
+ }
+
+static void TAG(flush_tri_strip_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ FLUSH_VERTEX = TAG(flush_tri_strip_3);
+ ACTIVE_VERTEX = IMM_VERTICES( 3 );
+ DO_TRISTRIP_TRI( 0, 1 );
+}
+
+static void TAG(flush_tri_strip_3)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ FLUSH_VERTEX = TAG(flush_tri_strip_4);
+ ACTIVE_VERTEX = IMM_VERTICES( 0 );
+ DO_TRISTRIP_TRI( 1, 2 );
+}
+
+static void TAG(flush_tri_strip_4)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ FLUSH_VERTEX = TAG(flush_tri_strip_5);
+ ACTIVE_VERTEX = IMM_VERTICES( 1 );
+ DO_TRISTRIP_TRI( 2, 3 );
+}
+
+static void TAG(flush_tri_strip_5)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ FLUSH_VERTEX = TAG(flush_tri_strip_2);
+ ACTIVE_VERTEX = IMM_VERTICES( 2 );
+ DO_TRISTRIP_TRI( 0, 3 );
+}
+
+
+
+/* =============================================================
+ * GL_TRIANGLE_FAN
+ */
+
+static void TAG(flush_tri_fan_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_tri_fan_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_tri_fan_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ ACTIVE_VERTEX = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_tri_fan_1);
+}
+
+static void TAG(flush_tri_fan_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ ACTIVE_VERTEX = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_tri_fan_2);
+}
+
+#define DO_TRIFAN_TRI( vert0, vert1 ) \
+ if (!HAVE_TRI_FAN || FALLBACK_OR_CLIPPING) { \
+ TNL_VERTEX *v2 = IMM_VERTICES( vert0 ); \
+ TNL_VERTEX *v1 = IMM_VERTICES( vert1 ); \
+ TAG(draw_tri)( ctx, v2, v1, v0 ); \
+ } else if (EXTEND_PRIM( 1 )) { \
+ EMIT_VERTEX( v0 ); \
+ } else { \
+ TNL_VERTEX *v2 = IMM_VERTICES( vert0 ); \
+ TNL_VERTEX *v1 = IMM_VERTICES( vert1 ); \
+ BEGIN_PRIM( GL_TRIANGLE_FAN, 3 ); \
+ EMIT_VERTEX( v2 ); \
+ EMIT_VERTEX( v1 ); \
+ EMIT_VERTEX( v0 ); \
+ }
+
+static void TAG(flush_tri_fan_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 1 );
+ FLUSH_VERTEX = TAG(flush_tri_fan_3 );
+ DO_TRIFAN_TRI( 0, 1 );
+}
+
+static void TAG(flush_tri_fan_3)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 2 );
+ FLUSH_VERTEX = TAG(flush_tri_fan_2 );
+ DO_TRIFAN_TRI( 0, 2 );
+}
+
+
+
+/* =============================================================
+ * GL_QUADS
+ */
+
+static void TAG(flush_quad_3)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_quad_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_quad_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_quad_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ IMM_VERTEX( v0 ) = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_quad_1);
+}
+
+static void TAG(flush_quad_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ IMM_VERTEX( v0 ) = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_quad_2);
+}
+
+static void TAG(flush_quad_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ IMM_VERTEX( v0 ) = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_quad_3);
+}
+
+static void TAG(flush_quad_3)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v3 = v0 - 3;
+ TNL_VERTEX *v2 = v0 - 2;
+ TNL_VERTEX *v1 = v0 - 1;
+
+ IMM_VERTEX( v0 ) = v3;
+ FLUSH_VERTEX = TAG(flush_quad_0);
+
+ if (!HAVE_HW_QUADS || FALLBACK_OR_CLIPPING) {
+ CLIP_OR_DRAW_TRI( ctx, v3, v2, v0 );
+ CLIP_OR_DRAW_TRI( ctx, v2, v1, v0 );
+ } else {
+ EXTEND_PRIM_NF( GL_QUADS, 4 );
+ EMIT_VERTEX( v3 );
+ EMIT_VERTEX( v2 );
+ EMIT_VERTEX( v1 );
+ EMIT_VERTEX( v0 );
+ }
+}
+
+
+
+/* =============================================================
+ * GL_QUAD_STRIP
+ */
+
+static void TAG(flush_quad_strip_3)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_quad_strip_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_quad_strip_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_quad_strip_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ IMM_VERTEX( v3 ) = v0;
+ IMM_VERTEX( v0 ) = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_quad_strip_1);
+}
+
+static void TAG(flush_quad_strip_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ IMM_VERTEX( v2 ) = v0;
+ IMM_VERTEX( v0 ) = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_quad_strip_2);
+}
+
+static void TAG(flush_quad_strip_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+
+ IMM_VERTEX( v1 ) = v0;
+ IMM_VERTEX( v0 ) = v0 + 1;
+ FLUSH_VERTEX = TAG(flush_quad_strip_3);
+}
+
+static void TAG(flush_quad_strip_3)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ TNL_VERTEX *v3 = IMM_VERTEX( v3 );
+ TNL_VERTEX *v2 = IMM_VERTEX( v2 );
+ TNL_VERTEX *v1 = IMM_VERTEX( v1 );
+
+ IMM_VERTEX( v0 ) = v3;
+ IMM_VERTEX( v2 ) = v0;
+ IMM_VERTEX( v3 ) = v1;
+ FLUSH_VERTEX = TAG(flush_quad_strip_2);
+
+ if (FALLBACK_OR_CLIPPING) {
+ CLIP_OR_DRAW_TRI( ctx, v3, v2, v0 );
+ CLIP_OR_DRAW_TRI( ctx, v2, v1, v0 );
+ } else {
+ DRAW_TRI( ctx, v3, v2, v0 );
+ DRAW_TRI( ctx, v2, v1, v0 );
+ }
+}
+
+
+
+/* =============================================================
+ * GL_POLYGON
+ */
+
+static void TAG(flush_poly_2)( GLcontext *ctx, TNL_VERTEX *v0 );
+static void TAG(flush_poly_1)( GLcontext *ctx, TNL_VERTEX *v0 );
+
+static void TAG(flush_poly_0)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 1 );
+ FLUSH_VERTEX = TAG(flush_poly_1);
+}
+
+static void TAG(flush_poly_1)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 2 );
+ FLUSH_VERTEX = TAG(flush_poly_2);
+}
+
+#define DO_POLY_TRI( vert0, vert1 ) \
+ if (!HAVE_POLYGONS || FALLBACK_OR_CLIPPING) { \
+ TNL_VERTEX *v2 = IMM_VERTICES( vert0 ); \
+ TNL_VERTEX *v1 = IMM_VERTICES( vert1 ); \
+ TAG(draw_tri)( ctx, v1, v0, v2 ); \
+ } else if (EXTEND_PRIM( 1 )) { \
+ EMIT_VERTEX( v0 ); \
+ } else { \
+ TNL_VERTEX *v2 = IMM_VERTICES( vert0 ); \
+ TNL_VERTEX *v1 = IMM_VERTICES( vert1 ); \
+ BEGIN_PRIM( GL_POLYGON, 3 ); \
+ EMIT_VERTEX( v2 ); \
+ EMIT_VERTEX( v1 ); \
+ EMIT_VERTEX( v0 ); \
+ }
+
+static void TAG(flush_poly_2)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 1 );
+ FLUSH_VERTEX = TAG(flush_poly_3);
+ DO_POLY_TRI( 0, 1 );
+}
+
+static void TAG(flush_poly_3)( GLcontext *ctx, TNL_VERTEX *v0 )
+{
+ LOCAL_VARS;
+ ACTIVE_VERTEX = IMM_VERTICES( 2 );
+ FLUSH_VERTEX = TAG(flush_poly_2);
+ DO_POLY_TRI( 0, 2 );
+}
+
+
+void (*TAG(flush_tab)[GL_POLYGON+1])( GLcontext *, TNL_VERTEX * ) =
+{
+ TAG(flush_point),
+ TAG(flush_line_0),
+ TAG(flush_line_loop_0),
+ TAG(flush_line_strip_0),
+ TAG(flush_triangle_0),
+ TAG(flush_tri_strip_0),
+ TAG(flush_tri_fan_0),
+ TAG(flush_quad_0),
+ TAG(flush_quad_strip_0),
+ TAG(flush_poly_0),
+};
+
+
+#ifndef PRESERVE_PRIM_DEFS
+#undef LOCAL_VARS
+#undef GET_INTERP_FUNC
+#undef IMM_VERTEX
+#undef IMM_VERTICES
+#undef FLUSH_VERTEX
+#endif
+#undef PRESERVE_PRIM_DEFS
+#undef EXTEND_PRIM
+#undef EMIT_VERTEX
+#undef EMIT_VERTEX_TRI
+#undef EMIT_VERTEX_LINE
+#undef EMIT_VERTEX_POINT
+#undef TAG
diff --git a/src/mesa/tnl_dd/imm/t_dd_imm_tapi.h b/src/mesa/tnl_dd/imm/t_dd_imm_tapi.h
new file mode 100644
index 0000000000..b82a9abebf
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/t_dd_imm_tapi.h
@@ -0,0 +1,75 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith_whitwell@yahoo.com>
+ */
+
+/* Template for immediate mode texture coordinate functions.
+ */
+
+#ifndef DO_PROJ_TEX
+#error "Need to define DO_PROJ_TEX"
+#endif
+
+
+/* =============================================================
+ * Notify on calls to texture4f, to allow switch to projected texture
+ * vertex format:
+ */
+
+static void TAG(TexCoord4f)( GLfloat s, GLfloat t, GLfloat r, GLfloat q )
+{
+ GET_CURRENT;
+ DO_PROJ_TEX;
+ TEXCOORD4( s, t, r, q );
+}
+
+static void TAG(TexCoord4fv)( const GLfloat *v )
+{
+ GET_CURRENT;
+ DO_PROJ_TEX;
+ TEXCOORD4( v[0], v[1], v[2], v[3] );
+}
+
+static void TAG(MultiTexCoord4fARB)( GLenum target, GLfloat s,
+ GLfloat t, GLfloat r, GLfloat q )
+{
+ GET_CURRENT;
+ DO_PROJ_TEX;
+ MULTI_TEXCOORD4( unit, s, t, r, q );
+}
+
+static void TAG(MultiTexCoord4fvARB)( GLenum target, const GLfloat *v )
+{
+ GET_CURRENT;
+ DO_PROJ_TEX;
+ MULTI_TEXCOORD4( unit, v[0], v[1], v[2], v[3] );
+}
+
+
+
+#undef DO_PROJ_TEX
+#undef TAG
diff --git a/src/mesa/tnl_dd/imm/t_dd_imm_vapi.h b/src/mesa/tnl_dd/imm/t_dd_imm_vapi.h
new file mode 100644
index 0000000000..95e93b1c83
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/t_dd_imm_vapi.h
@@ -0,0 +1,159 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL 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:
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+/* Template for immediate mode vertex functions.
+ */
+
+#define DBG 0
+
+#define VERTEX( ox, oy, oz, ow )
+do {
+ GET_CURRENT_VERTEX;
+ GLfloat w;
+ GLuint mask;
+ const GLfloat * const m = ctx->_ModelProjectMatrix.m;
+
+ if (DO_FULL_MATRIX) {
+ VERTEX_CLIP(0) = m[0] * ox + m[4] * oy + m[8] * oz + m[12] * ow;
+ VERTEX_CLIP(1) = m[1] * ox + m[5] * oy + m[9] * oz + m[13] * ow;
+ VERTEX_CLIP(2) = m[2] * ox + m[6] * oy + m[10] * oz + m[14] * ow;
+ VERTEX_CLIP(3) = m[3] * ox + m[7] * oy + m[11] * oz + m[15] * ow;
+ w = VERTEX_CLIP(3);
+ }
+ else if (DO_NOROT_MATRIX) {
+ VERTEX_CLIP(0) = m[0] * ox + m[12] * ow;
+ VERTEX_CLIP(1) = m[5] * oy + m[13] * ow;
+ VERTEX_CLIP(2) = m[10] * oz + m[14] * ow;
+ VERTEX_CLIP(3) = ow;
+ w = ow;
+ }
+ else {
+ ASSERT (DO_IDENTITY_MATRIX);
+ VERTEX_CLIP(0) = ox;
+ VERTEX_CLIP(1) = oy;
+ VERTEX_CLIP(2) = oz;
+ VERTEX_CLIP(3) = ow;
+ w = ow;
+ }
+
+ mask = 0;
+ if (DO_CLIP_TEST) {
+ if ( VERTEX_CLIP(0) > w ) mask |= CLIP_RIGHT_BIT;
+ if ( VERTEX_CLIP(0) < -w ) mask |= CLIP_LEFT_BIT;
+ if ( VERTEX_CLIP(1) > w ) mask |= CLIP_TOP_BIT;
+ if ( VERTEX_CLIP(1) < -w ) mask |= CLIP_BOTTOM_BIT;
+ if ( VERTEX_CLIP(2) > w ) mask |= CLIP_FAR_BIT;
+ if ( VERTEX_CLIP(2) < -w ) mask |= CLIP_NEAR_BIT;
+ VERTEX_MASK(v) = mask;
+ }
+
+ if (!mask) {
+ if (HAVE_VERTEX_WIN) {
+ if (!HAVE_HW_VIEWPORT) {
+ const GLfloat *s = GET_VIEWPORT_MATRIX();
+ if (HAVE_W && HAVE_HW_DIVIDE) {
+ VERTEX_WIN( 0 ) = s[0] * VERTEX_CLIP( 0 ) + s[12];
+ VERTEX_WIN( 1 ) = s[5] * VERTEX_CLIP( 1 ) + s[13];
+ VERTEX_WIN( 2 ) = s[10] * VERTEX_CLIP( 2 ) + s[14];
+ VERTEX_WIN( 3 ) = w;
+ }
+ else {
+ const GLfloat oow = 1.0/w; /* possibly opt away */
+ VERTEX_WIN( 0 ) = s[0] * VERTEX_CLIP( 0 ) * oow + s[12];
+ VERTEX_WIN( 1 ) = s[5] * VERTEX_CLIP( 1 ) * oow + s[13];
+ VERTEX_WIN( 2 ) = s[10] * VERTEX_CLIP( 2 ) * oow + s[14];
+ if (HAVE_W)
+ VERTEX_WIN( 3 ) = oow;
+ }
+ }
+ else if (HAVE_W && HAVE_HW_DIVIDE) {
+ if (!VERTEX_WIN_IS_VERTEX_CLIP) {
+ VERTEX_WIN( 0 ) = VERTEX_CLIP( 0 );
+ VERTEX_WIN( 1 ) = VERTEX_CLIP( 1 );
+ VERTEX_WIN( 2 ) = VERTEX_CLIP( 2 );
+ VERTEX_WIN( 3 ) = w;
+ }
+ }
+ else {
+ const GLfloat oow = 1.0/w; /* possibly opt away */
+ VERTEX_WIN( 0 ) = VERTEX_CLIP( 0 ) * oow;
+ VERTEX_WIN( 1 ) = VERTEX_CLIP( 1 ) * oow;
+ VERTEX_WIN( 2 ) = VERTEX_CLIP( 2 ) * oow;
+ if (HAVE_W)
+ VERTEX_WIN( 3 ) = oow;
+ }
+ }
+ } else if (!FALLBACK_OR_CLIPPING) {
+ SET_CLIPPING(); /* transition to clipping */
+ }
+
+ COPY_VERTEX_FROM_CURRENT;
+ BUILD_PRIM_FROM_VERTEX;
+}
+
+/* Let the compiler optimize away the constant operations:
+ */
+static void VTAG(Vertex2f)( GLfloat ox, GLfloat oy )
+{
+ /* Cliptest on clip[2] could also be eliminated...
+ */
+ VERTEX( ox, oy, 0, 1 );
+}
+
+static void VTAG(Vertex2fv)( const GLfloat *obj )
+{
+ /* Cliptest on clip[2] could also be eliminated...
+ */
+ VERTEX( obj[0], obj[1], 0, 1 );
+}
+
+static void VTAG(Vertex3f)( GLfloat ox, GLfloat oy, GLfloat oz )
+{
+ VERTEX( ox, oy, oz, 1 );
+}
+
+static void VTAG(Vertex3fv)( const GLfloat *obj )
+{
+ VERTEX( obj[0], obj[1], obj[2], 1 );
+}
+
+static void VTAG(Vertex4f)( GLfloat ox, GLfloat oy, GLfloat oz, GLfloat ow )
+{
+ VERTEX( ox, oy, oz, ow );
+}
+
+static void VTAG(Vertex4fv)( const GLfloat *obj )
+{
+ VERTEX( obj[0], obj[1], obj[2], obj[3] );
+}
+
+
+#undef DO_FULL_MATRIX
+#undef VTAG
+#undef VERTEX
diff --git a/src/mesa/tnl_dd/imm/t_dd_imm_vb.c b/src/mesa/tnl_dd/imm/t_dd_imm_vb.c
new file mode 100644
index 0000000000..0c4462f556
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/t_dd_imm_vb.c
@@ -0,0 +1,204 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith_whitwell@yahoo.com>
+ */
+
+/* Template to build clipping routines to support t_dd_imm_primtmp.h.
+ *
+ * The TAG(draw_line) and TAG(draw_triangle) routines are called in
+ * clipping and fallback scenarios, and when the native hardware
+ * primitive (eg polygons) is unavailable.
+ */
+
+
+#define CLIP_DOTPROD(K, A, B, C, D) \
+ (CLIP_X(K)*A + CLIP_Y(K)*B + \
+ CLIP_Z(K)*C + CLIP_W(K)*D)
+
+#define POLY_CLIP( PLANE, A, B, C, D ) \
+do { \
+ if (mask & PLANE) { \
+ TNL_VERTEX **indata = inlist[in]; \
+ TNL_VERTEX **outdata = inlist[in ^= 1]; \
+ TNL_VERTEX *J = indata[0]; \
+ GLfloat dpJ = CLIP_DOTPROD(J, A, B, C, D ); \
+ GLuint outcount = 0; \
+ GLuint i; \
+ \
+ indata[n] = indata[0]; /* prevent rotation of vertices */ \
+ for (i = 1; i <= n; i++) { \
+ TNL_VERTEX *I = indata[i]; \
+ GLfloat dpI = CLIP_DOTPROD(idx, A, B, C, D ); \
+ \
+ if (!NEGATIVE(dpPrev)) { \
+ outdata[outcount++] = J; \
+ } \
+ \
+ if (DIFFERENT_SIGNS(dpI, dpJ)) { \
+ TNL_VERTEX *O = verts++; \
+ outdata[outcount++] = O; \
+ if (NEGATIVE(dpI)) { \
+ /* Going out of bounds. Avoid division by zero as we \
+ * know dp != dpPrev from DIFFERENT_SIGNS, above. \
+ */ \
+ GLfloat t = dpI / (dpI - dpJ); \
+ INTERP( ctx, t, O, I, J ); \
+ } else { \
+ /* Coming back in. \
+ */ \
+ GLfloat t = dpJ / (dpJ - dpI); \
+ INTERP( ctx, t, O, J, I ); \
+ } \
+ } \
+ \
+ J = I; \
+ dpJ = dpI; \
+ } \
+ \
+ if (outcount < 3) \
+ return; \
+ \
+ nr = outcount; \
+ } \
+} while (0)
+
+
+#define LINE_CLIP(PLANE, A, B, C, D ) \
+do { \
+ if (mask & PLANE) { \
+ GLfloat dpI = CLIP_DOTPROD( I, A, B, C, D ); \
+ GLfloat dpJ = CLIP_DOTPROD( J, A, B, C, D ); \
+ \
+ if (DIFFERENT_SIGNS(dpI, dpJ)) { \
+ TNL_VERTEX *O = verts++; \
+ if (NEGATIVE(dpJ)) { \
+ GLfloat t = dpI / (dpI - dpJ); \
+ INTERP( ctx, t, O, I, J ); \
+ J = O; \
+ } else { \
+ GLfloat t = dpJ / (dpJ - dpI); \
+ INTERP( ctx, t, O, J, I ); \
+ I = O; \
+ } \
+ } \
+ else if (NEGATIVE(dpI)) \
+ return; \
+ } \
+} while (0)
+
+
+
+/* Clip a line against the viewport and user clip planes.
+ */
+static void TAG(clip_draw_line)( GLcontext *ctx,
+ TNL_VERTEX *I,
+ TNL_VERTEX *J,
+ GLuint mask )
+{
+ LOCAL_VARS;
+ GET_INTERP_FUNC;
+ TNL_VERTEX tmp[MAX_CLIPPED_VERTICES];
+ TNL_VERTEX *verts = tmp;
+ TNL_VERTEX *pv = J;
+
+ LINE_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
+ LINE_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
+ LINE_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
+ LINE_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
+ LINE_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
+ LINE_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
+
+ if ((ctx->_TriangleCaps & DD_FLATSHADE) && J != pv)
+ COPY_PV( ctx, J, pv );
+
+ DRAW_LINE( I, J );
+}
+
+
+/* Clip a triangle against the viewport and user clip planes.
+ */
+static void TAG(clip_draw_triangle)( GLcontext *ctx,
+ TNL_VERTEX *v0,
+ TNL_VERTEX *v1,
+ TNL_VERTEX *v2,
+ GLuint mask )
+{
+ LOCAL_VARS;
+ GET_INTERP_FUNC;
+ TNL_VERTEX tmp[MAX_CLIPPED_VERTICES];
+ TNL_VERTEX *verts = tmp;
+ TNL_VERTEX *(inlist[2][MAX_CLIPPED_VERTICES]);
+ TNL_VERTEX **out;
+ GLuint in = 0;
+ GLuint n = 3;
+ GLuint i;
+
+ ASSIGN_3V(inlist, v2, v0, v1 ); /* pv rotated to slot zero */
+
+ POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
+ POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
+ POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
+ POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
+ POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
+ POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
+
+ if ((ctx->_TriangleCaps & DD_FLATSHADE) && v2 != inlist[0])
+ COPY_PV( ctx, inlist[0], v2 );
+
+ out = inlist[in];
+ DRAW_POLYGON( out, n );
+}
+
+
+static __inline void TAG(draw_triangle)( GLcontext *ctx,
+ TNL_VERTEX *v0,
+ TNL_VERTEX *v1,
+ TNL_VERTEX *v2 )
+{
+ LOCAL_VARS;
+ GLubyte ormask = (v0->mask | v1->mask | v2->mask);
+
+ if ( !ormask ) {
+ DRAW_TRI( v0, v1, v2 );
+ } else if ( !(v0->mask & v1->mask & v2->mask) ) {
+ TAG(clip_draw_triangle)( ctx, v0, v1, v2, ormask );
+ }
+}
+
+static __inline void TAG(draw_line)( GLcontext *ctx,
+ TNL_VERTEX *v0,
+ TNL_VERTEX *v1 )
+{
+ LOCAL_VARS;
+ GLubyte ormask = (v0->mask | v1->mask);
+
+ if ( !ormask ) {
+ DRAW_LINE( v0, v1 );
+ } else if ( !(v0->mask & v1->mask) ) {
+ TAG(clip_draw_line)( ctx, v0, v1, ormask );
+ }
+}
+
diff --git a/src/mesa/tnl_dd/imm/t_dd_imm_vbtmp.h b/src/mesa/tnl_dd/imm/t_dd_imm_vbtmp.h
new file mode 100644
index 0000000000..2f76553cff
--- /dev/null
+++ b/src/mesa/tnl_dd/imm/t_dd_imm_vbtmp.h
@@ -0,0 +1,268 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith_whitwell@yahoo.com>
+ */
+
+/* Template to build support for t_dd_imm_* tnl module using vertices
+ * as defined in t_dd_vertex.h.
+ *
+ * See t_dd_vbtmp.h for definitions of arguments to this file.
+ * Unfortunately it seems necessary to duplicate a lot of that code.
+ */
+
+#ifndef LOCALVARS
+#define LOCALVARS
+#endif
+
+
+
+/* COPY_VERTEX_FROM_CURRENT in t_dd_imm_vapi.c
+ */
+static void TAG(emit_vfmt)( GLcontext *ctx, VERTEX *v )
+{
+ LOCALVARS
+ ;
+
+ /* This template assumes (like t_dd_vbtmp.h) that color is ubyte.
+ */
+ if (DO_TEX0 || DO_TEX1 || !HAVE_TINY_VERTICES)
+ {
+ const GLubyte *col = GET_HARDWARE_COLOR();
+ if (HAVE_RGBA_COLOR) {
+ v->v.ui[4] = *(GLuint *)&col;
+ } else {
+ v->v.color.blue = col[2];
+ v->v.color.green = col[1];
+ v->v.color.red = col[0];
+ v->v.color.alpha = col[3];
+ }
+ }
+ else {
+ if (HAVE_RGBA_COLOR) {
+ v->v.ui[3] = *(GLuint *)col;
+ }
+ else {
+ v->tv.color.blue = col[2];
+ v->tv.color.green = col[1];
+ v->tv.color.red = col[0];
+ v->tv.color.alpha = col[3];
+ }
+ }
+
+ if (DO_TEX0) {
+ GLfloat *tc = ctx->Current.Texture[0];
+ v->v.u0 = tc[0];
+ v->v.v0 = tc[1];
+ if (DO_PTEX) {
+ if (HAVE_PTEX_VERTICES) {
+ v->pv.q0 = tc[3];
+ }
+ else {
+ float rhw = 1.0 / tc[3];
+ v->v.w *= tc[3];
+ v->v.u0 *= rhw;
+ v->v.v0 *= rhw;
+ }
+ }
+ }
+ if (DO_TEX1) {
+ GLfloat *tc = ctx->Current.Texture[1];
+ if (DO_PTEX) {
+ v->pv.u1 = tc[0];
+ v->pv.v1 = tc[1];
+ v->pv.q1 = tc[3];
+ }
+ else {
+ v->v.u1 = tc[0];
+ v->v.v1 = tc[1];
+ }
+ }
+ else if (DO_PTEX) {
+ *(GLuint *)&v->pv.q1 = 0; /* avoid culling on radeon */
+ }
+ if (DO_TEX2) {
+ GLfloat *tc = ctx->Current.Texture[2];
+ if (DO_PTEX) {
+ v->pv.u2 = tc[0];
+ v->pv.v2 = tc[1];
+ v->pv.q2 = tc[3];
+ }
+ else {
+ v->v.u2 = tc[0];
+ v->v.v2 = tc[1];
+ }
+ }
+ if (DO_TEX3) {
+ GLfloat *tc = ctx->Current.Texture[3];
+ if (DO_PTEX) {
+ v->pv.u3 = tc[0];
+ v->pv.v3 = tc[1];
+ v->pv.q3 = tc[3];
+ }
+ else {
+ v->v.u3 = tc[0];
+ v->v.v3 = tc[1];
+ }
+ }
+}
+
+
+
+
+static void TAG(interp)( GLcontext *ctx,
+ GLfloat t,
+ TNL_VERTEX *dst,
+ TNL_VERTEX *in,
+ TNL_VERTEX *out )
+{
+ LOCALVARS
+ const GLfloat *s = GET_VIEWPORT_MAT();
+ GLfloat w;
+
+ (void)s;
+
+ if (HAVE_HW_DIVIDE) {
+ VIEWPORT_X( dst->v.v.x, dst->clip[0] );
+ VIEWPORT_Y( dst->v.v.y, dst->clip[1] );
+ VIEWPORT_Z( dst->v.v.z, dst->clip[2] );
+ w = dstclip[3];
+ }
+ else {
+ w = 1.0 / dst->clip[3];
+ VIEWPORT_X( dst->v.v.x, dst->clip[0] * w );
+ VIEWPORT_Y( dst->v.v.y, dst->clip[1] * w );
+ VIEWPORT_Z( dst->v.v.z, dst->clip[2] * w );
+ }
+
+ if (HAVE_HW_DIVIDE || DO_TEX0) {
+
+ dst->v.v.w = w;
+
+ INTERP_UB( t, dst->v.ub4[4][0], out->v.ub4[4][0], in->v.ub4[4][0] );
+ INTERP_UB( t, dst->v.ub4[4][1], out->v.ub4[4][1], in->v.ub4[4][1] );
+ INTERP_UB( t, dst->v.ub4[4][2], out->v.ub4[4][2], in->v.ub4[4][2] );
+ INTERP_UB( t, dst->v.ub4[4][3], out->v.ub4[4][3], in->v.ub4[4][3] );
+
+ if (DO_TEX0) {
+ if (DO_PTEX) {
+ if (HAVE_PTEX_VERTICES) {
+ INTERP_F( t, dst->v.pv.u0, out->v.pv.u0, in->v.pv.u0 );
+ INTERP_F( t, dst->v.pv.v0, out->v.pv.v0, in->v.pv.v0 );
+ INTERP_F( t, dst->v.pv.q0, out->v.pv.q0, in->v.pv.q0 );
+ } else {
+ GLfloat wout = out->clip[3]; /* projected clip */
+ GLfloat win = in->clip[3]; /* projected clip */
+ GLfloat qout = out->v.pv.w / wout;
+ GLfloat qin = in->v.pv.w / win;
+ GLfloat qdst, rqdst;
+
+ ASSERT( !HAVE_HW_DIVIDE ); /* assert win, wout projected clip */
+
+ INTERP_F( t, dst->v.v.u0, out->v.v.u0 * qout, in->v.v.u0 * qin );
+ INTERP_F( t, dst->v.v.v0, out->v.v.v0 * qout, in->v.v.v0 * qin );
+ INTERP_F( t, qdst, qout, qin );
+
+ rqdst = 1.0 / qdst;
+ dst->v.v.u0 *= rqdst;
+ dst->v.v.v0 *= rqdst;
+ dst->v.v.w *= rqdst;
+ }
+ }
+ else {
+ INTERP_F( t, dst->v.v.u0, out->v.v.u0, in->v.v.u0 );
+ INTERP_F( t, dst->v.v.v0, out->v.v.v0, in->v.v.v0 );
+ }
+ }
+ if (DO_TEX1) {
+ if (DO_PTEX) {
+ INTERP_F( t, dst->v.pv.u1, out->v.pv.u1, in->v.pv.u1 );
+ INTERP_F( t, dst->v.pv.v1, out->v.pv.v1, in->v.pv.v1 );
+ INTERP_F( t, dst->v.pv.q1, out->v.pv.q1, in->v.pv.q1 );
+ } else {
+ INTERP_F( t, dst->v.v.u1, out->v.v.u1, in->v.v.u1 );
+ INTERP_F( t, dst->v.v.v1, out->v.v.v1, in->v.v.v1 );
+ }
+ }
+ else if (DO_PTEX) {
+ dst->v.pv.q0 = 0.0; /* must be a valid float on radeon */
+ }
+ if (DO_TEX2) {
+ if (DO_PTEX) {
+ INTERP_F( t, dst->v.pv.u2, out->v.pv.u2, in->v.pv.u2 );
+ INTERP_F( t, dst->v.pv.v2, out->v.pv.v2, in->v.pv.v2 );
+ INTERP_F( t, dst->v.pv.q2, out->v.pv.q2, in->v.pv.q2 );
+ } else {
+ INTERP_F( t, dst->v.v.u2, out->v.v.u2, in->v.v.u2 );
+ INTERP_F( t, dst->v.v.v2, out->v.v.v2, in->v.v.v2 );
+ }
+ }
+ if (DO_TEX3) {
+ if (DO_PTEX) {
+ INTERP_F( t, dst->v.pv.u3, out->v.pv.u3, in->v.pv.u3 );
+ INTERP_F( t, dst->v.pv.v3, out->v.pv.v3, in->v.pv.v3 );
+ INTERP_F( t, dst->v.pv.q3, out->v.pv.q3, in->v.pv.q3 );
+ } else {
+ INTERP_F( t, dst->v.v.u3, out->v.v.u3, in->v.v.u3 );
+ INTERP_F( t, dst->v.v.v3, out->v.v.v3, in->v.v.v3 );
+ }
+ }
+ } else {
+ /* 4-dword vertex. Color is in v[3] and there is no oow coordinate.
+ */
+ INTERP_UB( t, dst->v.ub4[3][0], out->v.ub4[3][0], in->v.ub4[3][0] );
+ INTERP_UB( t, dst->v.ub4[3][1], out->v.ub4[3][1], in->v.ub4[3][1] );
+ INTERP_UB( t, dst->v.ub4[3][2], out->v.ub4[3][2], in->v.ub4[3][2] );
+ INTERP_UB( t, dst->v.ub4[3][3], out->v.ub4[3][3], in->v.ub4[3][3] );
+ }
+}
+
+
+static __inline void TAG(copy_pv)( GLcontext *ctx,
+ TNL_VERTEX *dst,
+ TNL_VERTEX *src )
+{
+ if (DO_TEX0 || DO_TEX1 || !HAVE_TINY_VERTICES) {
+ dst->v.v.ui[4] = src->v.v.ui[4];
+ }
+ else {
+ dst->v.v.ui[3] = src->v.v.ui[3];
+ }
+}
+
+
+
+static void TAG(init)( void )
+{
+ setup_tab[IND].emit = TAG(emit_vfmt);
+ setup_tab[IND].interp = TAG(interp_vfmt);
+}
+
+
+#undef IND
+#undef TAG
+
+
+
diff --git a/src/mesa/tnl_dd/t_dd.c b/src/mesa/tnl_dd/t_dd.c
new file mode 100644
index 0000000000..731da5c320
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd.c
@@ -0,0 +1,58 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+static void copy_pv_rgba4_spec5( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ i810ContextPtr imesa = I810_CONTEXT( ctx );
+ GLubyte *i810verts = (GLubyte *)imesa->verts;
+ GLuint shift = imesa->vertex_stride_shift;
+ i810Vertex *dst = (i810Vertex *)(i810verts + (edst << shift));
+ i810Vertex *src = (i810Vertex *)(i810verts + (esrc << shift));
+ dst->ui[4] = src->ui[4];
+ dst->ui[5] = src->ui[5];
+}
+
+static void copy_pv_rgba4( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ i810ContextPtr imesa = I810_CONTEXT( ctx );
+ GLubyte *i810verts = (GLubyte *)imesa->verts;
+ GLuint shift = imesa->vertex_stride_shift;
+ i810Vertex *dst = (i810Vertex *)(i810verts + (edst << shift));
+ i810Vertex *src = (i810Vertex *)(i810verts + (esrc << shift));
+ dst->ui[4] = src->ui[4];
+}
+
+static void copy_pv_rgba3( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ i810ContextPtr imesa = I810_CONTEXT( ctx );
+ GLubyte *i810verts = (GLubyte *)imesa->verts;
+ GLuint shift = imesa->vertex_stride_shift;
+ i810Vertex *dst = (i810Vertex *)(i810verts + (edst << shift));
+ i810Vertex *src = (i810Vertex *)(i810verts + (esrc << shift));
+ dst->ui[3] = src->ui[3];
+}
diff --git a/src/mesa/tnl_dd/t_dd_dmatmp.h b/src/mesa/tnl_dd/t_dd_dmatmp.h
new file mode 100644
index 0000000000..d9f709389d
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_dmatmp.h
@@ -0,0 +1,1105 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+/* Template for render stages which build and emit vertices directly
+ * to fixed-size dma buffers. Useful for rendering strips and other
+ * native primitives where clipping and per-vertex tweaks such as
+ * those in t_dd_tritmp.h are not required.
+ *
+ * Produces code for both inline triangles and indexed triangles.
+ * Where various primitive types are unaccelerated by hardware, the
+ * code attempts to fallback to other primitive types (quadstrips to
+ * tristrips, lineloops to linestrips), or to indexed vertices.
+ * Ultimately, a FALLBACK() macro is invoked if there is no way to
+ * render the primitive natively.
+ */
+
+#if !defined(HAVE_TRIANGLES)
+#error "must have at least triangles to use render template"
+#endif
+
+#if !HAVE_ELTS
+#define ELTS_VARS
+#define ALLOC_ELTS( nr )
+#define EMIT_ELT( offset, elt )
+#define EMIT_TWO_ELTS( offset, elt0, elt1 )
+#define INCR_ELTS( nr )
+#define ELT_INIT(prim)
+#define GET_CURRENT_VB_MAX_ELTS() 0
+#define GET_SUBSEQUENT_VB_MAX_ELTS() 0
+#define ALLOC_ELTS_NEW_PRIMITIVE(nr)
+#define RELEASE_ELT_VERTS()
+#define EMIT_INDEXED_VERTS( ctx, start, count )
+#endif
+
+#ifndef EMIT_TWO_ELTS
+#define EMIT_TWO_ELTS( offset, elt0, elt1 ) \
+do { \
+ EMIT_ELT( offset, elt0 ); \
+ EMIT_ELT( offset+1, elt1 ); \
+} while (0)
+#endif
+
+#ifndef FINISH
+#define FINISH
+#endif
+
+/**********************************************************************/
+/* Render whole begin/end objects */
+/**********************************************************************/
+
+
+
+static GLboolean TAG(emit_elt_verts)( GLcontext *ctx,
+ GLuint start, GLuint count )
+{
+ if (HAVE_ELTS) {
+ LOCAL_VARS;
+ GLuint nr = count - start;
+
+ if ( nr >= GET_SUBSEQUENT_VB_MAX_VERTS() ) /* assumes same packing for
+ * indexed and regualar verts
+ */
+ return GL_FALSE;
+
+ NEW_PRIMITIVE(); /* finish last prim */
+ EMIT_INDEXED_VERTS( ctx, start, count );
+ return GL_TRUE;
+ } else {
+ return GL_FALSE;
+ }
+}
+
+#if (HAVE_ELTS)
+static void TAG(emit_elts)( GLcontext *ctx, GLuint *elts, GLuint nr )
+{
+ GLint i;
+ LOCAL_VARS;
+ ELTS_VARS;
+
+ ALLOC_ELTS( nr );
+
+ for ( i = 0 ; i < nr ; i+=2, elts += 2 ) {
+ EMIT_TWO_ELTS( 0, elts[0], elts[1] );
+ INCR_ELTS( 2 );
+ }
+}
+#endif
+
+
+/***********************************************************************
+ * Render non-indexed primitives.
+ ***********************************************************************/
+
+
+
+static void TAG(render_points_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_POINTS) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz = GET_CURRENT_VB_MAX_VERTS();
+ GLuint j, nr;
+
+ INIT( GL_POINTS );
+
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr ) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ } else {
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+static void TAG(render_lines_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_LINES) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz = GET_CURRENT_VB_MAX_VERTS();
+ GLuint j, nr;
+
+ INIT( GL_LINES );
+
+ /* Emit whole number of lines in total and in each buffer:
+ */
+ count -= (count-start) & 1;
+ currentsz -= currentsz & 1;
+ dmasz -= dmasz & 1;
+
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr ) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ } else {
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_line_strip_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_LINE_STRIPS) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz = GET_CURRENT_VB_MAX_VERTS();
+ GLuint j, nr;
+
+ NEW_PRIMITIVE(); /* always a new primitive */
+ INIT( GL_LINE_STRIP );
+
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ } else {
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_line_loop_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_LINE_STRIPS) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz = GET_CURRENT_VB_MAX_VERTS();
+ GLuint j, nr;
+
+ NEW_PRIMITIVE();
+ INIT( GL_LINE_STRIP );
+
+ if (flags & PRIM_BEGIN)
+ j = start;
+ else
+ j = start + 1;
+
+ /* Ensure last vertex won't wrap buffers:
+ */
+ currentsz--;
+ dmasz--;
+
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ if (j + 1 < count) {
+ for ( ; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+
+ if (start < count - 1 && (flags & PRIM_END))
+ EMIT_VERTS( ctx, start, 1 );
+ }
+ else if (start + 1 < count && (flags & PRIM_END)) {
+ EMIT_VERTS( ctx, start+1, 1 );
+ EMIT_VERTS( ctx, start, 1 );
+ }
+
+ FINISH;
+
+ } else {
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_triangles_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3;
+ int currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
+ GLuint j, nr;
+
+ INIT(GL_TRIANGLES);
+
+ /* Emit whole number of tris in total. dmasz is already a multiple
+ * of 3.
+ */
+ count -= (count-start)%3;
+
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+ FINISH;
+}
+
+
+
+static void TAG(render_tri_strip_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_TRI_STRIPS) {
+ LOCAL_VARS;
+ GLuint j, nr;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz;
+
+ INIT(GL_TRIANGLE_STRIP);
+ NEW_PRIMITIVE();
+
+ currentsz = GET_CURRENT_VB_MAX_VERTS();
+
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ if ((flags & PRIM_PARITY) && count - start > 2) {
+ if (HAVE_TRI_STRIP_1 && 0) {
+ } else {
+ EMIT_VERTS( ctx, start, 1 );
+ currentsz--;
+ }
+ }
+
+ /* From here on emit even numbers of tris when wrapping over buffers:
+ */
+ dmasz -= (dmasz & 1);
+ currentsz -= (currentsz & 1);
+
+ for (j = start ; j + 2 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ } else {
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+static void TAG(render_tri_fan_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_TRI_FANS) {
+ LOCAL_VARS;
+ GLuint j, nr;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz = GET_CURRENT_VB_MAX_VERTS();
+
+ NEW_PRIMITIVE();
+ INIT(GL_TRIANGLE_FAN);
+
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ for (j = start + 1 ; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j + 1 );
+ EMIT_VERTS( ctx, start, 1 );
+ EMIT_VERTS( ctx, j, nr - 1 );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ }
+ else {
+ /* Could write code to emit these as indexed vertices (for the
+ * g400, for instance).
+ */
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_poly_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_POLYGONS) {
+ LOCAL_VARS;
+ GLuint j, nr;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz = GET_CURRENT_VB_MAX_VERTS();
+
+ NEW_PRIMITIVE();
+ INIT(GL_POLYGON);
+
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ for (j = start + 1 ; j + 1 < count ; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j + 1 );
+ EMIT_VERTS( ctx, start, 1 );
+ EMIT_VERTS( ctx, j, nr - 1 );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ }
+ else if (HAVE_TRI_FANS && !(ctx->_TriangleCaps & DD_FLATSHADE)) {
+ TAG(render_tri_fan_verts)( ctx, start, count, flags );
+ } else {
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+static void TAG(render_quad_strip_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j, nr;
+
+ if (HAVE_QUAD_STRIPS) {
+ LOCAL_VARS;
+ GLuint j, nr;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz;
+
+ INIT(GL_QUAD_STRIP);
+ NEW_PRIMITIVE();
+
+ currentsz = GET_CURRENT_VB_MAX_VERTS();
+
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ dmasz -= (dmasz & 2);
+ currentsz -= (currentsz & 2);
+
+ for (j = start ; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ } else if (HAVE_TRI_STRIPS && (ctx->_TriangleCaps & DD_FLATSHADE)) {
+ if (TAG(emit_elt_verts)( ctx, start, count )) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint j, nr;
+
+ /* Simulate flat-shaded quadstrips using indexed vertices:
+ */
+ NEW_PRIMITIVE();
+ ELT_INIT( GL_TRIANGLES );
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz -= dmasz & 1;
+ count -= (count-start) & 1;
+ currentsz -= currentsz & 1;
+
+ if (currentsz < 12)
+ currentsz = dmasz;
+
+ currentsz = currentsz/6*2;
+ dmasz = dmasz/6*2;
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+ if (nr >= 4) {
+ GLint quads = (nr/2)-1;
+ GLint i;
+ ELTS_VARS;
+
+ NEW_PRIMITIVE();
+ ALLOC_ELTS_NEW_PRIMITIVE( quads*6 );
+
+ for ( i = j-start ; i < j-start+quads*2 ; i+=2 ) {
+ EMIT_TWO_ELTS( 0, (i+0), (i+1) );
+ EMIT_TWO_ELTS( 2, (i+2), (i+1) );
+ EMIT_TWO_ELTS( 4, (i+3), (i+2) );
+ INCR_ELTS( 6 );
+ }
+
+ NEW_PRIMITIVE();
+ }
+ currentsz = dmasz;
+ }
+
+ RELEASE_ELT_VERTS();
+ }
+ else {
+ /* Vertices won't fit in a single buffer or elts not available,
+ * VERT_FALLBACK.
+ */
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+ }
+ else if (HAVE_TRI_STRIPS) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
+ int currentsz = GET_CURRENT_VB_MAX_VERTS();
+
+ /* Emit smooth-shaded quadstrips as tristrips:
+ */
+ NEW_PRIMITIVE();
+ INIT( GL_TRIANGLE_STRIP );
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz -= dmasz & 1;
+ currentsz -= currentsz & 1;
+ count -= (count-start) & 1;
+
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+
+ FINISH;
+
+ } else {
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_quads_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_QUADS) {
+ LOCAL_VARS;
+ int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/4) * 4;
+ int currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
+ GLuint j, nr;
+
+ INIT(GL_QUADS);
+
+ /* Emit whole number of quads in total. dmasz is already a multiple
+ * of 4.
+ */
+ count -= (count-start)%4;
+
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr) {
+ nr = MIN2( currentsz, count - j );
+ EMIT_VERTS( ctx, j, nr );
+ currentsz = dmasz;
+ }
+ FINISH;
+ } else if (TAG(emit_elt_verts)( ctx, start, count )) {
+ /* Hardware doesn't have a quad primitive type -- try to
+ * simulate it using indexed vertices and the triangle
+ * primitive:
+ */
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint j, nr;
+
+ NEW_PRIMITIVE();
+ ELT_INIT( GL_TRIANGLES );
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz -= dmasz & 3;
+ count -= (count-start) & 3;
+ currentsz -= currentsz & 3;
+
+ /* Adjust for rendering as triangles:
+ */
+ currentsz = currentsz/6*4;
+ dmasz = dmasz/6*4;
+
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr ) {
+ nr = MIN2( currentsz, count - j );
+ if (nr >= 4) {
+ GLint quads = nr/4;
+ GLint i;
+ ELTS_VARS;
+
+ NEW_PRIMITIVE();
+ ALLOC_ELTS_NEW_PRIMITIVE( quads*6 );
+
+ for ( i = j-start ; i < j-start+quads*4 ; i+=4 ) {
+ EMIT_TWO_ELTS( 0, (i+0), (i+1) );
+ EMIT_TWO_ELTS( 2, (i+3), (i+1) );
+ EMIT_TWO_ELTS( 4, (i+2), (i+3) );
+ INCR_ELTS( 6 );
+ }
+
+ NEW_PRIMITIVE();
+ }
+ currentsz = dmasz;
+ }
+
+ RELEASE_ELT_VERTS();
+ }
+ else {
+ /* Vertices won't fit in a single buffer, fallback.
+ */
+ VERT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+static void TAG(render_noop)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+}
+
+
+
+
+static render_func TAG(render_tab_verts)[GL_POLYGON+2] =
+{
+ TAG(render_points_verts),
+ TAG(render_lines_verts),
+ TAG(render_line_loop_verts),
+ TAG(render_line_strip_verts),
+ TAG(render_triangles_verts),
+ TAG(render_tri_strip_verts),
+ TAG(render_tri_fan_verts),
+ TAG(render_quads_verts),
+ TAG(render_quad_strip_verts),
+ TAG(render_poly_verts),
+ TAG(render_noop),
+};
+
+
+/****************************************************************************
+ * Render elts using hardware indexed verts *
+ ****************************************************************************/
+
+#if (HAVE_ELTS)
+static void TAG(render_points_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_POINTS) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ GLuint j, nr;
+
+ ELT_INIT( GL_POINTS );
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr ) {
+ nr = MIN2( currentsz, count - j );
+ TAG(emit_elts)( ctx, elts+j, nr );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ } else {
+ ELT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+
+static void TAG(render_lines_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_LINES) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ GLuint j, nr;
+
+ ELT_INIT( GL_LINES );
+
+ /* Emit whole number of lines in total and in each buffer:
+ */
+ count -= (count-start) & 1;
+ currentsz -= currentsz & 1;
+ dmasz -= dmasz & 1;
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr ) {
+ nr = MIN2( currentsz, count - j );
+ TAG(emit_elts)( ctx, elts+j, nr );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ } else {
+ ELT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_line_strip_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_LINE_STRIPS) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ GLuint j, nr;
+
+ NEW_PRIMITIVE(); /* always a new primitive */
+ ELT_INIT( GL_LINE_STRIP );
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j );
+ TAG(emit_elts)( ctx, elts+j, nr );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ } else {
+ /* TODO: Try to emit as indexed lines.
+ */
+ ELT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_line_loop_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_LINE_STRIPS) {
+ LOCAL_VARS;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ GLuint j, nr;
+
+ NEW_PRIMITIVE();
+ ELT_INIT( GL_LINE_STRIP );
+
+ if (flags & PRIM_BEGIN)
+ j = start;
+ else
+ j = start + 1;
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ /* Ensure last vertex doesn't wrap:
+ */
+ currentsz--;
+ dmasz--;
+
+ for ( ; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j );
+/* NEW_PRIMITIVE(); */
+ TAG(emit_elts)( ctx, elts+j, nr );
+ currentsz = dmasz;
+ }
+
+ if (flags & PRIM_END)
+ TAG(emit_elts)( ctx, elts+start, 1 );
+
+ NEW_PRIMITIVE();
+ } else {
+ /* TODO: Try to emit as indexed lines */
+ ELT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+/* For verts, we still eliminate the copy from main memory to dma
+ * buffers. For elts, this is probably no better (worse?) than the
+ * standard path.
+ */
+static void TAG(render_triangles_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3;
+ int currentsz;
+ GLuint j, nr;
+
+ NEW_PRIMITIVE();
+ ELT_INIT( GL_TRIANGLES );
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+
+ /* Emit whole number of tris in total. dmasz is already a multiple
+ * of 3.
+ */
+ count -= (count-start)%3;
+ currentsz -= currentsz%3;
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j < count; j += nr) {
+ nr = MIN2( currentsz, count - j );
+ TAG(emit_elts)( ctx, elts+j, nr );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+}
+
+
+
+static void TAG(render_tri_strip_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_TRI_STRIPS) {
+ LOCAL_VARS;
+ GLuint j, nr;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+
+ NEW_PRIMITIVE();
+ ELT_INIT( GL_TRIANGLE_STRIP );
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ if ((flags & PRIM_PARITY) && count - start > 2) {
+ TAG(emit_elts)( ctx, elts+start, 1 );
+ }
+
+ /* Keep the same winding over multiple buffers:
+ */
+ dmasz -= (dmasz & 1);
+ currentsz -= (currentsz & 1);
+
+ for (j = start ; j + 2 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+ TAG(emit_elts)( ctx, elts+j, nr );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ } else {
+ /* TODO: try to emit as indexed triangles */
+ ELT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+static void TAG(render_tri_fan_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_TRI_FANS) {
+ LOCAL_VARS;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ GLuint j, nr;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+
+ NEW_PRIMITIVE();
+ ELT_INIT( GL_TRIANGLE_FAN );
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ for (j = start + 1 ; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j + 1 );
+ TAG(emit_elts)( ctx, elts+start, 1 );
+ TAG(emit_elts)( ctx, elts+j, nr - 1 );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ } else {
+ /* TODO: try to emit as indexed triangles */
+ ELT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+
+static void TAG(render_poly_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_POLYGONS && 0) {
+ } else if (HAVE_TRI_FANS && !(ctx->_TriangleCaps & DD_FLATSHADE)) {
+ LOCAL_VARS;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ GLuint j, nr;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+
+ NEW_PRIMITIVE();
+ ELT_INIT( GL_TRIANGLE_FAN );
+
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+ if (currentsz < 8) {
+ NEW_BUFFER();
+ currentsz = dmasz;
+ }
+
+ for (j = start + 1 ; j + 1 < count ; j += nr - 1 ) {
+ nr = MIN2( currentsz, count - j + 1 );
+ TAG(emit_elts)( ctx, elts+start, 1 );
+ TAG(emit_elts)( ctx, elts+j, nr - 1 );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ } else {
+ ELT_FALLBACK( ctx, start, count, flags );
+ }
+}
+
+static void TAG(render_quad_strip_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_QUAD_STRIPS && 0) {
+ }
+ else if (HAVE_TRI_STRIPS) {
+ LOCAL_VARS;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint j, nr;
+
+ NEW_PRIMITIVE();
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz -= dmasz & 1;
+ count -= (count-start) & 1;
+ currentsz -= currentsz & 1;
+
+ if (currentsz < 12)
+ currentsz = dmasz;
+
+ if (ctx->_TriangleCaps & DD_FLATSHADE) {
+ ELT_INIT( GL_TRIANGLES );
+
+ currentsz = currentsz/6*2;
+ dmasz = dmasz/6*2;
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+
+ if (nr >= 4)
+ {
+ GLint i;
+ GLint quads = (nr/2)-1;
+ ELTS_VARS;
+
+
+ NEW_PRIMITIVE();
+ ALLOC_ELTS_NEW_PRIMITIVE( quads*6 );
+
+ for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
+ EMIT_TWO_ELTS( 0, elts[0], elts[1] );
+ EMIT_TWO_ELTS( 2, elts[2], elts[1] );
+ EMIT_TWO_ELTS( 4, elts[3], elts[2] );
+ INCR_ELTS( 6 );
+ }
+
+ NEW_PRIMITIVE();
+ }
+
+ currentsz = dmasz;
+ }
+ }
+ else {
+ ELT_INIT( GL_TRIANGLE_STRIP );
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+ TAG(emit_elts)( ctx, elts+j, nr );
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ }
+ }
+}
+
+
+static void TAG(render_quads_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (HAVE_QUADS && 0) {
+ } else {
+ LOCAL_VARS;
+ GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+ int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
+ int currentsz;
+ GLuint j, nr;
+
+ ELT_INIT( GL_TRIANGLES );
+ currentsz = GET_CURRENT_VB_MAX_ELTS();
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz -= dmasz & 3;
+ count -= (count-start) & 3;
+ currentsz -= currentsz & 3;
+
+ /* Adjust for rendering as triangles:
+ */
+ currentsz = currentsz/6*4;
+ dmasz = dmasz/6*4;
+
+ if (currentsz < 8)
+ currentsz = dmasz;
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( currentsz, count - j );
+
+ if (nr >= 4)
+ {
+ GLint quads = nr/4;
+ GLint i;
+ ELTS_VARS;
+ NEW_PRIMITIVE();
+ ALLOC_ELTS_NEW_PRIMITIVE( quads * 6 );
+
+ for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
+ EMIT_TWO_ELTS( 0, elts[0], elts[1] );
+ EMIT_TWO_ELTS( 2, elts[3], elts[1] );
+ EMIT_TWO_ELTS( 4, elts[2], elts[3] );
+ INCR_ELTS( 6 );
+ }
+ }
+
+ NEW_PRIMITIVE();
+ currentsz = dmasz;
+ }
+ }
+}
+
+
+
+static render_func TAG(render_tab_elts)[GL_POLYGON+2] =
+{
+ TAG(render_points_elts),
+ TAG(render_lines_elts),
+ TAG(render_line_loop_elts),
+ TAG(render_line_strip_elts),
+ TAG(render_triangles_elts),
+ TAG(render_tri_strip_elts),
+ TAG(render_tri_fan_elts),
+ TAG(render_quads_elts),
+ TAG(render_quad_strip_elts),
+ TAG(render_poly_elts),
+ TAG(render_noop),
+};
+#endif
diff --git a/src/mesa/tnl_dd/t_dd_dmatmp2.h b/src/mesa/tnl_dd/t_dd_dmatmp2.h
new file mode 100644
index 0000000000..3f58d24c95
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_dmatmp2.h
@@ -0,0 +1,949 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.0.3
+ *
+ * Copyright (C) 1999-2002 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+/* Template for render stages which build and emit vertices directly
+ * to fixed-size dma buffers. Useful for rendering strips and other
+ * native primitives where clipping and per-vertex tweaks such as
+ * those in t_dd_tritmp.h are not required.
+ *
+ */
+
+#if !HAVE_TRIANGLES || !HAVE_POINTS || !HAVE_LINES
+#error "must have points, lines & triangles to use render template"
+#endif
+
+#if !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
+#error "must have tri strip and fans to use render template"
+#endif
+
+#if !HAVE_LINE_STRIPS
+#error "must have line strips to use render template"
+#endif
+
+#if !HAVE_POLYGONS
+#error "must have polygons to use render template"
+#endif
+
+#if !HAVE_ELTS
+#error "must have elts to use render template"
+#endif
+
+
+#ifndef EMIT_TWO_ELTS
+#define EMIT_TWO_ELTS( dest, offset, elt0, elt1 ) \
+do { \
+ (dest)[offset] = (elt0); \
+ (dest)[offset+1] = (elt1); \
+} while (0)
+#endif
+
+
+/**********************************************************************/
+/* Render whole begin/end objects */
+/**********************************************************************/
+
+
+static ELT_TYPE *TAG(emit_elts)( GLcontext *ctx,
+ ELT_TYPE *dest,
+ GLuint *elts, GLuint nr )
+{
+ GLint i;
+ LOCAL_VARS;
+
+ for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) {
+ EMIT_TWO_ELTS( dest, 0, elts[0], elts[1] );
+ dest += 2;
+ }
+ if (i < nr) {
+ EMIT_ELT( dest, 0, elts[0] );
+ dest += 1;
+ }
+
+ return dest;
+}
+
+static ELT_TYPE *TAG(emit_consecutive_elts)( GLcontext *ctx,
+ ELT_TYPE *dest,
+ GLuint start, GLuint nr )
+{
+ GLint i;
+ LOCAL_VARS;
+
+ for ( i = 0 ; i+1 < nr ; i+=2, start += 2 ) {
+ EMIT_TWO_ELTS( dest, 0, start, start+1 );
+ dest += 2;
+ }
+ if (i < nr) {
+ EMIT_ELT( dest, 0, start );
+ dest += 1;
+ }
+
+ return dest;
+}
+
+/***********************************************************************
+ * Render non-indexed primitives.
+ ***********************************************************************/
+
+
+
+static void TAG(render_points_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (start < count) {
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+ EMIT_PRIM( ctx, GL_POINTS, HW_POINTS, start, count );
+ }
+}
+
+static void TAG(render_lines_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+ count -= (count-start) & 1;
+
+ if (start+1 >= count)
+ return;
+
+ if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag) {
+ RESET_STIPPLE();
+ AUTO_STIPPLE( GL_TRUE );
+ }
+
+ EMIT_PRIM( ctx, GL_LINES, HW_LINES, start, count );
+
+ if ((flags & PRIM_END) && ctx->Line.StippleFlag)
+ AUTO_STIPPLE( GL_FALSE );
+}
+
+
+static void TAG(render_line_strip_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (start+1 >= count)
+ return;
+
+ if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag)
+ RESET_STIPPLE();
+
+
+ if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_LINES ))
+ {
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint j, nr;
+
+ ELT_INIT( GL_LINES, HW_LINES );
+
+ /* Emit whole number of lines in each full buffer.
+ */
+ dmasz = dmasz/2;
+
+
+ for (j = start; j + 1 < count; j += nr - 1 ) {
+ ELT_TYPE *dest;
+ GLint i;
+
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( (nr-1)*2 );
+
+ for ( i = j ; i+1 < j+nr ; i+=1 ) {
+ EMIT_TWO_ELTS( dest, 0, (i+0), (i+1) );
+ dest += 2;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+ else
+ EMIT_PRIM( ctx, GL_LINE_STRIP, HW_LINE_STRIP, start, count );
+}
+
+
+static void TAG(render_line_loop_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ GLuint j, nr;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (flags & PRIM_BEGIN) {
+ j = start;
+ if (ctx->Line.StippleFlag)
+ RESET_STIPPLE( );
+ }
+ else
+ j = start + 1;
+
+ if (flags & PRIM_END) {
+
+ if (start+1 >= count)
+ return;
+
+ if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_LINES )) {
+ int dmasz = GET_MAX_HW_ELTS();
+
+ ELT_INIT( GL_LINES, HW_LINES );
+
+ /* Emit whole number of lines in each full buffer.
+ */
+ dmasz = dmasz/2;
+
+ /* Ensure last vertex doesn't wrap:
+ */
+ dmasz--;
+
+ for (; j + 1 < count; ) {
+ GLint i;
+ ELT_TYPE *dest;
+
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( nr*2 ); /* allocs room for 1 more line */
+
+ for ( i = 0 ; i < nr - 1 ; i+=1 ) {
+ EMIT_TWO_ELTS( dest, 0, (j+i), (j+i+1) );
+ dest += 2;
+ }
+
+ j += nr - 1;
+
+ /* Emit 1 more line into space alloced above */
+ if (j + 1 >= count) {
+ EMIT_TWO_ELTS( dest, 0, (j), (start) );
+ dest += 2;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+ else
+ {
+ int dmasz = GET_MAX_HW_ELTS() - 1;
+
+ ELT_INIT( GL_LINE_STRIP, HW_LINE_STRIP );
+
+ for ( ; j + 1 < count; ) {
+ nr = MIN2( dmasz, count - j );
+ if (j + nr < count) {
+ ELT_TYPE *dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_consecutive_elts)( ctx, dest, j, nr );
+ j += nr - 1;
+ CLOSE_ELTS();
+ }
+ else if (nr) {
+ ELT_TYPE *dest = ALLOC_ELTS( nr + 1 );
+ dest = TAG(emit_consecutive_elts)( ctx, dest, j, nr );
+ dest = TAG(emit_consecutive_elts)( ctx, dest, start, 1 );
+ j += nr;
+ CLOSE_ELTS();
+ }
+ }
+ }
+ } else {
+ TAG(render_line_strip_verts)( ctx, j, count, flags );
+ }
+}
+
+
+static void TAG(render_triangles_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ count -= (count-start)%3;
+
+ if (start+2 >= count) {
+ return;
+ }
+
+ /* need a PREFER_DISCRETE_ELT_PRIM here too..
+ */
+ EMIT_PRIM( ctx, GL_TRIANGLES, HW_TRIANGLES, start, count );
+}
+
+
+
+static void TAG(render_tri_strip_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (start + 2 >= count)
+ return;
+
+ if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_TRIANGLES ))
+ {
+ int dmasz = GET_MAX_HW_ELTS();
+ int parity = 0;
+ GLuint j, nr;
+
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+
+ if (flags & PRIM_PARITY)
+ parity = 1;
+
+ /* Emit even number of tris in each full buffer.
+ */
+ dmasz = dmasz/3;
+ dmasz -= dmasz & 1;
+
+ for (j = start; j + 2 < count; j += nr - 2 ) {
+ ELT_TYPE *dest;
+ GLint i;
+
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( (nr-2)*3 );
+
+ for ( i = j ; i+2 < j+nr ; i++, parity^=1 ) {
+ EMIT_ELT( dest, 0, (i+0+parity) );
+ EMIT_ELT( dest, 1, (i+1-parity) );
+ EMIT_ELT( dest, 2, (i+2) );
+ dest += 3;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+ else if ((flags & PRIM_PARITY) == 0)
+ EMIT_PRIM( ctx, GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0, start, count );
+ else if (HAVE_TRI_STRIP_1)
+ EMIT_PRIM( ctx, GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_1, start, count );
+ else {
+ /* Emit the first triangle with elts, then the rest as a regular strip.
+ * TODO: Make this unlikely in t_imm_api.c
+ */
+ ELT_TYPE *dest;
+
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+ dest = ALLOC_ELTS( 3 );
+ EMIT_ELT( dest, 0, (start+1) );
+ EMIT_ELT( dest, 1, (start+0) );
+ EMIT_ELT( dest, 2, (start+2) );
+ dest += 3;
+ CLOSE_ELTS();
+
+ start++;
+ if (start + 2 >= count)
+ return;
+
+ EMIT_PRIM( ctx, GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0, start,
+ count );
+ }
+}
+
+static void TAG(render_tri_fan_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (start+2 >= count)
+ return;
+
+ if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_TRIANGLES ))
+ {
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint j, nr;
+
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+
+ dmasz = dmasz/3;
+
+ for (j = start + 1; j + 1 < count; j += nr - 1 ) {
+ ELT_TYPE *dest;
+ GLint i;
+
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( (nr-1)*3 );
+
+ for ( i = j ; i+1 < j+nr ; i++ ) {
+ EMIT_ELT( dest, 0, (start) );
+ EMIT_ELT( dest, 1, (i) );
+ EMIT_ELT( dest, 2, (i+1) );
+ dest += 3;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+ else {
+ EMIT_PRIM( ctx, GL_TRIANGLE_FAN, HW_TRIANGLE_FAN, start, count );
+ }
+}
+
+
+static void TAG(render_poly_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (start+2 >= count)
+ return;
+
+ EMIT_PRIM( ctx, GL_POLYGON, HW_POLYGON, start, count );
+}
+
+static void TAG(render_quad_strip_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ count -= (count-start) & 1;
+
+ if (start+3 >= count)
+ return;
+
+ if (HAVE_QUAD_STRIPS) {
+ EMIT_PRIM( ctx, GL_QUAD_STRIP, HW_QUAD_STRIP, start, count );
+ }
+ else if (ctx->_TriangleCaps & DD_FLATSHADE) {
+ LOCAL_VARS;
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint j, nr;
+
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz = (dmasz/6)*2;
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ ELT_TYPE *dest;
+ GLint quads, i;
+
+ nr = MIN2( dmasz, count - j );
+ quads = (nr/2)-1;
+ dest = ALLOC_ELTS( quads*6 );
+
+ for ( i = j ; i < j+quads*2 ; i+=2 ) {
+ EMIT_TWO_ELTS( dest, 0, (i+0), (i+1) );
+ EMIT_TWO_ELTS( dest, 2, (i+2), (i+1) );
+ EMIT_TWO_ELTS( dest, 4, (i+3), (i+2) );
+ dest += 6;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+ else {
+ EMIT_PRIM( ctx, GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0, start, count );
+ }
+}
+
+
+static void TAG(render_quads_verts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+ count -= (count-start)%4;
+
+ if (start+3 >= count)
+ return;
+
+ if (HAVE_QUADS) {
+ EMIT_PRIM( ctx, HW_QUADS, GL_QUADS, start, count );
+ }
+ else {
+ /* Hardware doesn't have a quad primitive type -- simulate it
+ * using indexed vertices and the triangle primitive:
+ */
+ LOCAL_VARS;
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint j, nr;
+
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+
+ /* Adjust for rendering as triangles:
+ */
+ dmasz = (dmasz/6)*4;
+
+ for (j = start; j < count; j += nr ) {
+ ELT_TYPE *dest;
+ GLint quads, i;
+
+ nr = MIN2( dmasz, count - j );
+ quads = nr/4;
+ dest = ALLOC_ELTS( quads*6 );
+
+ for ( i = j ; i < j+quads*4 ; i+=4 ) {
+ EMIT_TWO_ELTS( dest, 0, (i+0), (i+1) );
+ EMIT_TWO_ELTS( dest, 2, (i+3), (i+1) );
+ EMIT_TWO_ELTS( dest, 4, (i+2), (i+3) );
+ dest += 6;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+}
+
+static void TAG(render_noop)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+}
+
+
+
+
+static render_func TAG(render_tab_verts)[GL_POLYGON+2] =
+{
+ TAG(render_points_verts),
+ TAG(render_lines_verts),
+ TAG(render_line_loop_verts),
+ TAG(render_line_strip_verts),
+ TAG(render_triangles_verts),
+ TAG(render_tri_strip_verts),
+ TAG(render_tri_fan_verts),
+ TAG(render_quads_verts),
+ TAG(render_quad_strip_verts),
+ TAG(render_poly_verts),
+ TAG(render_noop),
+};
+
+
+/****************************************************************************
+ * Render elts using hardware indexed verts *
+ ****************************************************************************/
+
+static void TAG(render_points_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint *elts = GET_MESA_ELTS();
+ GLuint j, nr;
+ ELT_TYPE *dest;
+
+ ELT_INIT( GL_POINTS, HW_POINTS );
+
+ for (j = start; j < count; j += nr ) {
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
+ CLOSE_ELTS();
+ }
+}
+
+
+
+static void TAG(render_lines_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint *elts = GET_MESA_ELTS();
+ GLuint j, nr;
+ ELT_TYPE *dest;
+
+ if (start+1 >= count)
+ return;
+
+ if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag) {
+ RESET_STIPPLE();
+ AUTO_STIPPLE( GL_TRUE );
+ }
+
+ ELT_INIT( GL_LINES, HW_LINES );
+
+ /* Emit whole number of lines in total and in each buffer:
+ */
+ count -= (count-start) & 1;
+ dmasz -= dmasz & 1;
+
+ for (j = start; j < count; j += nr ) {
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
+ CLOSE_ELTS();
+ }
+
+ if ((flags & PRIM_END) && ctx->Line.StippleFlag)
+ AUTO_STIPPLE( GL_FALSE );
+}
+
+
+static void TAG(render_line_strip_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint *elts = GET_MESA_ELTS();
+ GLuint j, nr;
+ ELT_TYPE *dest;
+
+ if (start+1 >= count)
+ return;
+
+ ELT_INIT( GL_LINE_STRIP, HW_LINE_STRIP );
+
+ if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag)
+ RESET_STIPPLE();
+
+ for (j = start; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
+ CLOSE_ELTS();
+ }
+}
+
+
+static void TAG(render_line_loop_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint *elts = GET_MESA_ELTS();
+ GLuint j, nr;
+ ELT_TYPE *dest;
+
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ if (flags & PRIM_BEGIN)
+ j = start;
+ else
+ j = start + 1;
+
+
+ if (flags & PRIM_END) {
+ if (start+1 >= count)
+ return;
+ }
+ else {
+ if (j+1 >= count)
+ return;
+ }
+
+ ELT_INIT( GL_LINE_STRIP, HW_LINE_STRIP );
+
+ if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag)
+ RESET_STIPPLE();
+
+
+ /* Ensure last vertex doesn't wrap:
+ */
+ dmasz--;
+
+ for ( ; j + 1 < count; ) {
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( nr+1 ); /* Reserve possible space for last elt */
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
+ j += nr - 1;
+ if (j + 1 >= count && (flags & PRIM_END)) {
+ dest = TAG(emit_elts)( ctx, dest, elts+start, 1 );
+ }
+ CLOSE_ELTS();
+ }
+}
+
+
+static void TAG(render_triangles_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ GLuint *elts = GET_MESA_ELTS();
+ int dmasz = GET_MAX_HW_ELTS()/3*3;
+ GLuint j, nr;
+ ELT_TYPE *dest;
+
+ if (start+2 >= count)
+ return;
+
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+
+
+ /* Emit whole number of tris in total. dmasz is already a multiple
+ * of 3.
+ */
+ count -= (count-start)%3;
+
+ for (j = start; j < count; j += nr) {
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
+ CLOSE_ELTS();
+ }
+}
+
+
+
+static void TAG(render_tri_strip_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ GLuint j, nr;
+ GLuint *elts = GET_MESA_ELTS();
+ int dmasz = GET_MAX_HW_ELTS();
+ ELT_TYPE *dest;
+
+ if (start+2 >= count)
+ return;
+
+ ELT_INIT( GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0 );
+
+ /* Keep the same winding over multiple buffers:
+ */
+ dmasz -= (dmasz & 1);
+
+ for (j = start ; j + 2 < count; j += nr - 2 ) {
+ nr = MIN2( dmasz, count - j );
+
+ if (flags & PRIM_PARITY) {
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, 1 );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr-1 );
+ nr--; flags &= ~PRIM_PARITY;
+ CLOSE_ELTS();
+ }
+ else {
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
+ CLOSE_ELTS();
+ }
+ }
+}
+
+static void TAG(render_tri_fan_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ GLuint *elts = GET_MESA_ELTS();
+ GLuint j, nr;
+ int dmasz = GET_MAX_HW_ELTS();
+ ELT_TYPE *dest;
+
+ if (start+2 >= count)
+ return;
+
+ ELT_INIT( GL_TRIANGLE_FAN, HW_TRIANGLE_FAN );
+
+ for (j = start + 1 ; j + 1 < count; j += nr - 1 ) {
+ nr = MIN2( dmasz, count - j + 1 );
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+start, 1 );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr - 1 );
+ CLOSE_ELTS();
+ }
+}
+
+
+static void TAG(render_poly_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ GLuint *elts = GET_MESA_ELTS();
+ GLuint j, nr;
+ int dmasz = GET_MAX_HW_ELTS();
+ ELT_TYPE *dest;
+
+ if (start+2 >= count)
+ return;
+
+ ELT_INIT( GL_POLYGON, HW_POLYGON );
+
+ for (j = start + 1 ; j + 1 < count ; j += nr - 1 ) {
+ nr = MIN2( dmasz, count - j + 1 );
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+start, 1 );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr - 1 );
+ CLOSE_ELTS();
+ }
+}
+
+static void TAG(render_quad_strip_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (start+3 >= count)
+ return;
+
+ if (HAVE_QUAD_STRIPS && 0) {
+ }
+ else {
+ LOCAL_VARS;
+ GLuint *elts = GET_MESA_ELTS();
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint j, nr;
+ ELT_TYPE *dest;
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz -= dmasz & 1;
+ count -= (count-start) & 1;
+
+ if (ctx->_TriangleCaps & DD_FLATSHADE) {
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+
+ dmasz = dmasz/6*2;
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( dmasz, count - j );
+
+ if (nr >= 4)
+ {
+ GLint quads = (nr/2)-1;
+ ELT_TYPE *dest = ALLOC_ELTS( quads*6 );
+ GLint i;
+
+ for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
+ EMIT_TWO_ELTS( dest, 0, elts[0], elts[1] );
+ EMIT_TWO_ELTS( dest, 2, elts[2], elts[1] );
+ EMIT_TWO_ELTS( dest, 4, elts[3], elts[2] );
+ dest += 6;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+ }
+ else {
+ ELT_INIT( GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0 );
+
+ for (j = start; j + 3 < count; j += nr - 2 ) {
+ nr = MIN2( dmasz, count - j );
+ dest = ALLOC_ELTS( nr );
+ dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
+ CLOSE_ELTS();
+ }
+ }
+ }
+}
+
+
+static void TAG(render_quads_elts)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ if (start+3 >= count)
+ return;
+
+ if (HAVE_QUADS && 0) {
+ } else {
+ LOCAL_VARS;
+ GLuint *elts = GET_MESA_ELTS();
+ int dmasz = GET_MAX_HW_ELTS();
+ GLuint j, nr;
+
+ ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
+
+ /* Emit whole number of quads in total, and in each buffer.
+ */
+ dmasz -= dmasz & 3;
+ count -= (count-start) & 3;
+
+ /* Adjust for rendering as triangles:
+ */
+ dmasz = dmasz/6*4;
+
+ for (j = start; j + 3 < count; j += nr ) {
+ nr = MIN2( dmasz, count - j );
+
+ {
+ GLint quads = nr/4;
+ ELT_TYPE *dest = ALLOC_ELTS( quads * 6 );
+ GLint i;
+
+ for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
+ EMIT_TWO_ELTS( dest, 0, elts[0], elts[1] );
+ EMIT_TWO_ELTS( dest, 2, elts[3], elts[1] );
+ EMIT_TWO_ELTS( dest, 4, elts[2], elts[3] );
+ dest += 6;
+ }
+
+ CLOSE_ELTS();
+ }
+ }
+ }
+}
+
+
+
+static render_func TAG(render_tab_elts)[GL_POLYGON+2] =
+{
+ TAG(render_points_elts),
+ TAG(render_lines_elts),
+ TAG(render_line_loop_elts),
+ TAG(render_line_strip_elts),
+ TAG(render_triangles_elts),
+ TAG(render_tri_strip_elts),
+ TAG(render_tri_fan_elts),
+ TAG(render_quads_elts),
+ TAG(render_quad_strip_elts),
+ TAG(render_poly_elts),
+ TAG(render_noop),
+};
diff --git a/src/mesa/tnl_dd/t_dd_rendertmp.h b/src/mesa/tnl_dd/t_dd_rendertmp.h
new file mode 100644
index 0000000000..fc00e76934
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_rendertmp.h
@@ -0,0 +1,437 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+#ifndef POSTFIX
+#define POSTFIX
+#endif
+
+#ifndef INIT
+#define INIT(x)
+#endif
+
+#ifndef NEED_EDGEFLAG_SETUP
+#define NEED_EDGEFLAG_SETUP 0
+#define EDGEFLAG_GET(a) 0
+#define EDGEFLAG_SET(a,b) (void)b
+#endif
+
+#ifndef RESET_STIPPLE
+#define RESET_STIPPLE
+#endif
+
+#ifndef RESET_OCCLUSION
+#define RESET_OCCLUSION
+#endif
+
+#ifndef TEST_PRIM_END
+#define TEST_PRIM_END(flags) (flags & PRIM_END)
+#define TEST_PRIM_BEGIN(flags) (flags & PRIM_BEGIN)
+#define TEST_PRIM_PARITY(flags) (flags & PRIM_PARITY)
+#endif
+
+#ifndef ELT
+#define ELT(x) x
+#endif
+
+#ifndef RENDER_TAB_QUALIFIER
+#define RENDER_TAB_QUALIFIER static
+#endif
+
+static void TAG(render_points)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_POINTS);
+ RENDER_POINTS( start, count );
+ POSTFIX;
+}
+
+static void TAG(render_lines)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_LINES);
+ for (j=start+1; j<count; j+=2 ) {
+ RENDER_LINE( ELT(j-1), ELT(j) );
+ RESET_STIPPLE;
+ }
+ POSTFIX;
+}
+
+
+static void TAG(render_line_strip)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_LINE_STRIP);
+
+ for (j=start+1; j<count; j++ )
+ RENDER_LINE( ELT(j-1), ELT(j) );
+
+ if (TEST_PRIM_END(flags))
+ RESET_STIPPLE;
+
+ POSTFIX;
+}
+
+
+static void TAG(render_line_loop)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint i;
+ LOCAL_VARS;
+
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_LINE_LOOP);
+
+ if (start+1 < count) {
+ if (TEST_PRIM_BEGIN(flags)) {
+ RENDER_LINE( ELT(start), ELT(start+1) );
+ }
+
+ for ( i = start+2 ; i < count ; i++) {
+ RENDER_LINE( ELT(i-1), ELT(i) );
+ }
+
+ if ( TEST_PRIM_END(flags)) {
+ RENDER_LINE( ELT(count-1), ELT(start) );
+ RESET_STIPPLE;
+ }
+ }
+
+ POSTFIX;
+}
+
+
+static void TAG(render_triangles)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_TRIANGLES);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2; j<count; j+=3) {
+ /* Leave the edgeflags as supplied by the user.
+ */
+ RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+2; j<count; j+=3) {
+ RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+
+
+static void TAG(render_tri_strip)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ GLuint parity = 0;
+ LOCAL_VARS;
+
+ if (TEST_PRIM_PARITY(flags))
+ parity = 1;
+
+ INIT(GL_TRIANGLE_STRIP);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2;j<count;j++,parity^=1) {
+ GLuint ej2 = ELT(j-2+parity);
+ GLuint ej1 = ELT(j-1-parity);
+ GLuint ej = ELT(j);
+ GLboolean ef2 = EDGEFLAG_GET( ej2 );
+ GLboolean ef1 = EDGEFLAG_GET( ej1 );
+ GLboolean ef = EDGEFLAG_GET( ej );
+ EDGEFLAG_SET( ej2, GL_TRUE );
+ EDGEFLAG_SET( ej1, GL_TRUE );
+ EDGEFLAG_SET( ej, GL_TRUE );
+ RENDER_TRI( ej2, ej1, ej );
+ EDGEFLAG_SET( ej2, ef2 );
+ EDGEFLAG_SET( ej1, ef1 );
+ EDGEFLAG_SET( ej, ef );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+2; j<count ; j++, parity^=1) {
+ RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+
+static void TAG(render_tri_fan)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_TRIANGLE_FAN);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2;j<count;j++) {
+ /* For trifans, all edges are boundary.
+ */
+ GLuint ejs = ELT(start);
+ GLuint ej1 = ELT(j-1);
+ GLuint ej = ELT(j);
+ GLboolean efs = EDGEFLAG_GET( ejs );
+ GLboolean ef1 = EDGEFLAG_GET( ej1 );
+ GLboolean ef = EDGEFLAG_GET( ej );
+ EDGEFLAG_SET( ejs, GL_TRUE );
+ EDGEFLAG_SET( ej1, GL_TRUE );
+ EDGEFLAG_SET( ej, GL_TRUE );
+ RENDER_TRI( ejs, ej1, ej);
+ EDGEFLAG_SET( ejs, efs );
+ EDGEFLAG_SET( ej1, ef1 );
+ EDGEFLAG_SET( ej, ef );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+2;j<count;j++) {
+ RENDER_TRI( ELT(start), ELT(j-1), ELT(j) );
+ }
+ }
+
+ POSTFIX;
+}
+
+
+static void TAG(render_poly)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j = start+2;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ GLboolean efstart = EDGEFLAG_GET( ELT(start) );
+ GLboolean efcount = EDGEFLAG_GET( ELT(count-1) );
+
+ /* If the primitive does not begin here, the first edge
+ * is non-boundary.
+ */
+ if (!TEST_PRIM_BEGIN(flags))
+ EDGEFLAG_SET( ELT(start), GL_FALSE );
+
+ /* If the primitive does not end here, the final edge is
+ * non-boundary.
+ */
+ if (!TEST_PRIM_END(flags))
+ EDGEFLAG_SET( ELT(count-1), GL_FALSE );
+
+ /* Draw the first triangles (possibly zero)
+ */
+ if (j<count-1) {
+ GLboolean ef = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j), GL_FALSE );
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+ EDGEFLAG_SET( ELT(j), ef );
+ j++;
+
+ /* Don't render the first edge again:
+ */
+ EDGEFLAG_SET( ELT(start), GL_FALSE );
+
+ for (;j<count-1;j++) {
+ GLboolean efj = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j), GL_FALSE );
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+ EDGEFLAG_SET( ELT(j), efj );
+ }
+ }
+
+ /* Draw the last or only triangle
+ */
+ if (j < count)
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+
+ /* Restore the first and last edgeflags:
+ */
+ EDGEFLAG_SET( ELT(count-1), efcount );
+ EDGEFLAG_SET( ELT(start), efstart );
+
+ if (TEST_PRIM_END(flags)) {
+ RESET_STIPPLE;
+ }
+ }
+ else {
+ for (j=start+2;j<count;j++) {
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_quads)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_QUADS);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+3; j<count; j+=4) {
+ /* Use user-specified edgeflags for quads.
+ */
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+3; j<count; j+=4) {
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_quad_strip)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_QUAD_STRIP);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+3;j<count;j+=2) {
+ /* All edges are boundary. Set edgeflags to 1, draw the
+ * quad, and restore them to the original values.
+ */
+ GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) );
+ GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) );
+ GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) );
+ GLboolean ef = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j-3), GL_TRUE );
+ EDGEFLAG_SET( ELT(j-2), GL_TRUE );
+ EDGEFLAG_SET( ELT(j-1), GL_TRUE );
+ EDGEFLAG_SET( ELT(j), GL_TRUE );
+ RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
+ EDGEFLAG_SET( ELT(j-3), ef3 );
+ EDGEFLAG_SET( ELT(j-2), ef2 );
+ EDGEFLAG_SET( ELT(j-1), ef1 );
+ EDGEFLAG_SET( ELT(j), ef );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+3;j<count;j+=2) {
+ RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_noop)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ (void)(ctx && start && count && flags);
+}
+
+RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(GLcontext *,
+ GLuint,
+ GLuint,
+ GLuint) =
+{
+ TAG(render_points),
+ TAG(render_lines),
+ TAG(render_line_loop),
+ TAG(render_line_strip),
+ TAG(render_triangles),
+ TAG(render_tri_strip),
+ TAG(render_tri_fan),
+ TAG(render_quads),
+ TAG(render_quad_strip),
+ TAG(render_poly),
+ TAG(render_noop),
+};
+
+
+
+#ifndef PRESERVE_VB_DEFS
+#undef RENDER_TRI
+#undef RENDER_QUAD
+#undef RENDER_LINE
+#undef RENDER_POINTS
+#undef LOCAL_VARS
+#undef INIT
+#undef POSTFIX
+#undef RESET_STIPPLE
+#undef DBG
+#undef ELT
+#undef RENDER_TAB_QUALIFIER
+#endif
+
+#ifndef PRESERVE_TAG
+#undef TAG
+#endif
+
+#undef PRESERVE_VB_DEFS
+#undef PRESERVE_TAG
diff --git a/src/mesa/tnl_dd/t_dd_triemit.h b/src/mesa/tnl_dd/t_dd_triemit.h
new file mode 100644
index 0000000000..2f5bcee7ec
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_triemit.h
@@ -0,0 +1,157 @@
+#ifndef DO_DEBUG_VERTS
+#define DO_DEBUG_VERTS 0
+#endif
+
+#ifndef PRINT_VERTEX
+#define PRINT_VERTEX(x)
+#endif
+
+#if defined(USE_X86_ASM)
+#define COPY_DWORDS( j, vb, vertsize, v ) \
+do { \
+ int __tmp; \
+ __asm__ __volatile__( "rep ; movsl" \
+ : "=%c" (j), "=D" (vb), "=S" (__tmp) \
+ : "0" (vertsize), \
+ "D" ((long)vb), \
+ "S" ((long)v) ); \
+} while (0)
+#else
+#define COPY_DWORDS( j, vb, vertsize, v ) \
+do { \
+ for ( j = 0 ; j < vertsize ; j++ ) \
+ vb[j] = ((GLuint *)v)[j]; \
+ vb += vertsize; \
+} while (0)
+#endif
+
+
+
+#if HAVE_QUADS
+static __inline void TAG(quad)( CTX_ARG,
+ VERTEX *v0,
+ VERTEX *v1,
+ VERTEX *v2,
+ VERTEX *v3 )
+{
+ GLuint vertsize = GET_VERTEX_DWORDS();
+ GLuint *vb = (GLuint *)ALLOC_VERTS( 4, vertsize);
+ GLuint j;
+
+ if (DO_DEBUG_VERTS) {
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ PRINT_VERTEX(v0);
+ PRINT_VERTEX(v1);
+ PRINT_VERTEX(v2);
+ PRINT_VERTEX(v3);
+ }
+
+ COPY_DWORDS( j, vb, vertsize, v0 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+ COPY_DWORDS( j, vb, vertsize, v2 );
+ COPY_DWORDS( j, vb, vertsize, v3 );
+}
+#else
+static __inline void TAG(quad)( CTX_ARG,
+ VERTEX *v0,
+ VERTEX *v1,
+ VERTEX *v2,
+ VERTEX *v3 )
+{
+ GLuint vertsize = GET_VERTEX_DWORDS();
+ GLuint *vb = (GLuint *)ALLOC_VERTS( 6, vertsize);
+ GLuint j;
+
+ if (DO_DEBUG_VERTS) {
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ PRINT_VERTEX(v0);
+ PRINT_VERTEX(v1);
+ PRINT_VERTEX(v2);
+ PRINT_VERTEX(v3);
+ }
+
+ COPY_DWORDS( j, vb, vertsize, v0 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+ COPY_DWORDS( j, vb, vertsize, v3 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+ COPY_DWORDS( j, vb, vertsize, v2 );
+ COPY_DWORDS( j, vb, vertsize, v3 );
+}
+#endif
+
+
+static __inline void TAG(triangle)( CTX_ARG,
+ VERTEX *v0,
+ VERTEX *v1,
+ VERTEX *v2 )
+{
+ GLuint vertsize = GET_VERTEX_DWORDS();
+ GLuint *vb = (GLuint *)ALLOC_VERTS( 3, vertsize);
+ GLuint j;
+
+ if (DO_DEBUG_VERTS) {
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ PRINT_VERTEX(v0);
+ PRINT_VERTEX(v1);
+ PRINT_VERTEX(v2);
+ }
+
+ COPY_DWORDS( j, vb, vertsize, v0 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+ COPY_DWORDS( j, vb, vertsize, v2 );
+}
+
+
+#if HAVE_LINES
+static __inline void TAG(line)( CTX_ARG,
+ VERTEX *v0,
+ VERTEX *v1 )
+{
+ GLuint vertsize = GET_VERTEX_DWORDS();
+ GLuint *vb = (GLuint *)ALLOC_VERTS( 2, vertsize);
+ GLuint j;
+
+ COPY_DWORDS( j, vb, vertsize, v0 );
+ COPY_DWORDS( j, vb, vertsize, v1 );
+}
+#endif
+
+#if HAVE_POINTS
+static __inline void TAG(point)( CTX_ARG,
+ VERTEX *v0 )
+{
+ GLuint vertsize = GET_VERTEX_DWORDS();
+ GLuint *vb = (GLuint *)ALLOC_VERTS( 1, vertsize);
+ int j;
+
+ COPY_DWORDS( j, vb, vertsize, v0 );
+}
+#endif
+
+
+static void TAG(fast_clipped_poly)( GLcontext *ctx, const GLuint *elts,
+ GLuint n )
+{
+ LOCAL_VARS
+ GLuint vertsize = GET_VERTEX_DWORDS();
+ GLuint *vb = (GLuint *)ALLOC_VERTS( (n-2) * 3, vertsize );
+ const GLuint *start = (const GLuint *)VERT(elts[0]);
+ int i,j;
+
+ if (DO_DEBUG_VERTS) {
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ PRINT_VERTEX(VERT(elts[0]));
+ PRINT_VERTEX(VERT(elts[1]));
+ }
+
+ for (i = 2 ; i < n ; i++) {
+ if (DO_DEBUG_VERTS) {
+ PRINT_VERTEX(VERT(elts[i]));
+ }
+
+ COPY_DWORDS( j, vb, vertsize, VERT(elts[i-1]) );
+ COPY_DWORDS( j, vb, vertsize, VERT(elts[i]) );
+ COPY_DWORDS( j, vb, vertsize, start );
+ }
+}
+
diff --git a/src/mesa/tnl_dd/t_dd_tritmp.h b/src/mesa/tnl_dd/t_dd_tritmp.h
new file mode 100644
index 0000000000..cc47798d5e
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_tritmp.h
@@ -0,0 +1,739 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+/* Template for building functions to plug into the driver interface
+ * of t_vb_render.c:
+ * ctx->Driver.QuadFunc
+ * ctx->Driver.TriangleFunc
+ * ctx->Driver.LineFunc
+ * ctx->Driver.PointsFunc
+ *
+ * DO_TWOSIDE: Plug back-color values from the VB into backfacing triangles,
+ * and restore vertices afterwards.
+ * DO_OFFSET: Calculate offset for triangles and adjust vertices. Restore
+ * vertices after rendering.
+ * DO_FLAT: For hardware without native flatshading, copy provoking colors
+ * into the other vertices. Restore after rendering.
+ * DO_UNFILLED: Decompose triangles to lines and points where appropriate.
+ *
+ * HAVE_RGBA: Vertices have rgba values (otherwise index values).
+ * HAVE_SPEC: Vertices have secondary rgba values.
+ *
+ * VERT_X(v): Alias for vertex x value.
+ * VERT_Y(v): Alias for vertex y value.
+ * VERT_Z(v): Alias for vertex z value.
+ * DEPTH_SCALE: Scale for offset.
+ *
+ * VERTEX: Hardware vertex type.
+ * GET_VERTEX(n): Retreive vertex with index n.
+ * AREA_IS_CCW(a): Return true if triangle with signed area a is ccw.
+ *
+ * VERT_SET_RGBA: Assign vertex rgba from VB color.
+ * VERT_COPY_RGBA: Copy vertex rgba another vertex.
+ * VERT_SAVE_RGBA: Save vertex rgba to a local variable.
+ * VERT_RESTORE_RGBA: Restore vertex rgba from a local variable.
+ * --> Similar for IND and SPEC.
+ *
+ * LOCAL_VARS(n): (At least) define local vars for save/restore rgba.
+ *
+ */
+
+#if HAVE_RGBA
+#define VERT_SET_IND( v, c ) (void) c
+#define VERT_COPY_IND( v0, v1 )
+#define VERT_SAVE_IND( idx )
+#define VERT_RESTORE_IND( idx )
+#if HAVE_BACK_COLORS
+#define VERT_SET_RGBA( v, c )
+#endif
+#else
+#define VERT_SET_RGBA( v, c ) (void) c
+#define VERT_COPY_RGBA( v0, v1 )
+#define VERT_SAVE_RGBA( idx )
+#define VERT_RESTORE_RGBA( idx )
+#if HAVE_BACK_COLORS
+#define VERT_SET_IND( v, c )
+#endif
+#endif
+
+#if !HAVE_SPEC
+#define VERT_SET_SPEC( v, c ) (void) c
+#define VERT_COPY_SPEC( v0, v1 )
+#define VERT_SAVE_SPEC( idx )
+#define VERT_RESTORE_SPEC( idx )
+#if HAVE_BACK_COLORS
+#define VERT_COPY_SPEC1( v )
+#endif
+#else
+#if HAVE_BACK_COLORS
+#define VERT_SET_SPEC( v, c )
+#endif
+#endif
+
+#if !HAVE_BACK_COLORS
+#define VERT_COPY_SPEC1( v )
+#define VERT_COPY_IND1( v )
+#define VERT_COPY_RGBA1( v )
+#endif
+
+#ifndef INSANE_VERTICES
+#define VERT_SET_Z(v,val) VERT_Z(v) = val
+#define VERT_Z_ADD(v,val) VERT_Z(v) += val
+#endif
+
+#if DO_TRI
+static void TAG(triangle)( GLcontext *ctx, GLuint e0, GLuint e1, GLuint e2 )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb;
+ VERTEX *v[3];
+ GLfloat offset;
+ GLfloat z[3];
+ GLenum mode = GL_FILL;
+ GLuint facing;
+ LOCAL_VARS(3);
+
+/* fprintf(stderr, "%s\n", __FUNCTION__); */
+
+ v[0] = (VERTEX *)GET_VERTEX(e0);
+ v[1] = (VERTEX *)GET_VERTEX(e1);
+ v[2] = (VERTEX *)GET_VERTEX(e2);
+
+ if (DO_TWOSIDE || DO_OFFSET || DO_UNFILLED)
+ {
+ GLfloat ex = VERT_X(v[0]) - VERT_X(v[2]);
+ GLfloat ey = VERT_Y(v[0]) - VERT_Y(v[2]);
+ GLfloat fx = VERT_X(v[1]) - VERT_X(v[2]);
+ GLfloat fy = VERT_Y(v[1]) - VERT_Y(v[2]);
+ GLfloat cc = ex*fy - ey*fx;
+
+ if (DO_TWOSIDE || DO_UNFILLED)
+ {
+ facing = AREA_IS_CCW( cc ) ^ ctx->Polygon._FrontBit;
+
+ if (DO_UNFILLED) {
+ if (facing) {
+ mode = ctx->Polygon.BackMode;
+ if (ctx->Polygon.CullFlag &&
+ ctx->Polygon.CullFaceMode != GL_FRONT) {
+ return;
+ }
+ } else {
+ mode = ctx->Polygon.FrontMode;
+ if (ctx->Polygon.CullFlag &&
+ ctx->Polygon.CullFaceMode != GL_BACK) {
+ return;
+ }
+ }
+ }
+
+ if (DO_TWOSIDE && facing == 1)
+ {
+ if (HAVE_RGBA) {
+ if (HAVE_BACK_COLORS) {
+ if (!DO_FLAT) {
+ VERT_SAVE_RGBA( 0 );
+ VERT_SAVE_RGBA( 1 );
+ VERT_COPY_RGBA1( v[0] );
+ VERT_COPY_RGBA1( v[1] );
+ }
+ VERT_SAVE_RGBA( 2 );
+ VERT_COPY_RGBA1( v[2] );
+ if (HAVE_SPEC) {
+ if (!DO_FLAT) {
+ VERT_SAVE_SPEC( 0 );
+ VERT_SAVE_SPEC( 1 );
+ VERT_COPY_SPEC1( v[0] );
+ VERT_COPY_SPEC1( v[1] );
+ }
+ VERT_SAVE_SPEC( 2 );
+ VERT_COPY_SPEC1( v[2] );
+ }
+ }
+ else {
+ GLchan (*vbcolor)[4] = VB->ColorPtr[1]->Ptr;
+ ASSERT(VB->ColorPtr[1]->Type == CHAN_TYPE);
+ ASSERT(VB->ColorPtr[1]->StrideB == 4*sizeof(GLchan));
+ (void) vbcolor;
+
+ if (!DO_FLAT) {
+ VERT_SAVE_RGBA( 0 );
+ VERT_SAVE_RGBA( 1 );
+ VERT_SET_RGBA( v[0], vbcolor[e0] );
+ VERT_SET_RGBA( v[1], vbcolor[e1] );
+ }
+ VERT_SAVE_RGBA( 2 );
+ VERT_SET_RGBA( v[2], vbcolor[e2] );
+
+ if (HAVE_SPEC && VB->SecondaryColorPtr[1]) {
+ GLchan (*vbspec)[4] = VB->SecondaryColorPtr[1]->Ptr;
+
+ if (!DO_FLAT) {
+ VERT_SAVE_SPEC( 0 );
+ VERT_SAVE_SPEC( 1 );
+ VERT_SET_SPEC( v[0], vbspec[e0] );
+ VERT_SET_SPEC( v[1], vbspec[e1] );
+ }
+ VERT_SAVE_SPEC( 2 );
+ VERT_SET_SPEC( v[2], vbspec[e2] );
+ }
+ }
+ }
+ else {
+ GLuint *vbindex = VB->IndexPtr[1]->data;
+ if (!DO_FLAT) {
+ VERT_SET_IND( v[0], vbindex[e0] );
+ VERT_SET_IND( v[1], vbindex[e1] );
+ }
+ VERT_SET_IND( v[2], vbindex[e2] );
+ }
+ }
+ }
+
+
+ if (DO_OFFSET)
+ {
+ offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
+ z[0] = VERT_Z(v[0]);
+ z[1] = VERT_Z(v[1]);
+ z[2] = VERT_Z(v[2]);
+ if (cc * cc > 1e-16) {
+ GLfloat ic = 1.0 / cc;
+ GLfloat ez = z[0] - z[2];
+ GLfloat fz = z[1] - z[2];
+ GLfloat a = ey*fz - ez*fy;
+ GLfloat b = ez*fx - ex*fz;
+ GLfloat ac = a * ic;
+ GLfloat bc = b * ic;
+ if ( ac < 0.0f ) ac = -ac;
+ if ( bc < 0.0f ) bc = -bc;
+ offset += MAX2( ac, bc ) * ctx->Polygon.OffsetFactor;
+ }
+ offset *= ctx->MRD;
+ }
+ }
+
+ if (DO_FLAT) {
+ if (HAVE_RGBA) {
+ VERT_SAVE_RGBA( 0 );
+ VERT_SAVE_RGBA( 1 );
+ VERT_COPY_RGBA( v[0], v[2] );
+ VERT_COPY_RGBA( v[1], v[2] );
+ if (HAVE_SPEC && VB->SecondaryColorPtr[0]) {
+ VERT_SAVE_SPEC( 0 );
+ VERT_SAVE_SPEC( 1 );
+ VERT_COPY_SPEC( v[0], v[2] );
+ VERT_COPY_SPEC( v[1], v[2] );
+ }
+ }
+ else {
+ VERT_SAVE_IND( 0 );
+ VERT_SAVE_IND( 1 );
+ VERT_COPY_IND( v[0], v[2] );
+ VERT_COPY_IND( v[1], v[2] );
+ }
+ }
+
+ if (mode == GL_POINT) {
+ if (DO_OFFSET && ctx->Polygon.OffsetPoint) {
+ VERT_Z_ADD(v[0], offset);
+ VERT_Z_ADD(v[1], offset);
+ VERT_Z_ADD(v[2], offset);
+ }
+ UNFILLED_TRI( ctx, GL_POINT, e0, e1, e2 );
+ } else if (mode == GL_LINE) {
+ if (DO_OFFSET && ctx->Polygon.OffsetLine) {
+ VERT_Z_ADD(v[0], offset);
+ VERT_Z_ADD(v[1], offset);
+ VERT_Z_ADD(v[2], offset);
+ }
+ UNFILLED_TRI( ctx, GL_LINE, e0, e1, e2 );
+ } else {
+ if (DO_OFFSET && ctx->Polygon.OffsetFill) {
+ VERT_Z_ADD(v[0], offset);
+ VERT_Z_ADD(v[1], offset);
+ VERT_Z_ADD(v[2], offset);
+ }
+ if (DO_UNFILLED)
+ RASTERIZE( GL_TRIANGLES );
+ TRI( v[0], v[1], v[2] );
+ }
+
+ if (DO_OFFSET)
+ {
+ VERT_SET_Z(v[0], z[0]);
+ VERT_SET_Z(v[1], z[1]);
+ VERT_SET_Z(v[2], z[2]);
+ }
+
+ if (DO_TWOSIDE && facing == 1)
+ {
+ if (HAVE_RGBA) {
+ if (!DO_FLAT) {
+ VERT_RESTORE_RGBA( 0 );
+ VERT_RESTORE_RGBA( 1 );
+ }
+ VERT_RESTORE_RGBA( 2 );
+ if (HAVE_SPEC) {
+ if (!DO_FLAT) {
+ VERT_RESTORE_SPEC( 0 );
+ VERT_RESTORE_SPEC( 1 );
+ }
+ VERT_RESTORE_SPEC( 2 );
+ }
+ }
+ else {
+ GLuint *vbindex = VB->IndexPtr[0]->data;
+ if (!DO_FLAT) {
+ VERT_SET_IND( v[0], vbindex[e0] );
+ VERT_SET_IND( v[1], vbindex[e1] );
+ }
+ VERT_SET_IND( v[2], vbindex[e2] );
+ }
+ }
+
+
+ if (DO_FLAT) {
+ if (HAVE_RGBA) {
+ VERT_RESTORE_RGBA( 0 );
+ VERT_RESTORE_RGBA( 1 );
+ if (HAVE_SPEC && VB->SecondaryColorPtr[0]) {
+ VERT_RESTORE_SPEC( 0 );
+ VERT_RESTORE_SPEC( 1 );
+ }
+ }
+ else {
+ VERT_RESTORE_IND( 0 );
+ VERT_RESTORE_IND( 1 );
+ }
+ }
+}
+#endif
+
+#if DO_QUAD
+#if DO_FULL_QUAD
+static void TAG(quad)( GLcontext *ctx,
+ GLuint e0, GLuint e1, GLuint e2, GLuint e3 )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb;
+ VERTEX *v[4];
+ GLfloat offset;
+ GLfloat z[4];
+ GLenum mode = GL_FILL;
+ GLuint facing;
+ LOCAL_VARS(4);
+
+ v[0] = (VERTEX *)GET_VERTEX(e0);
+ v[1] = (VERTEX *)GET_VERTEX(e1);
+ v[2] = (VERTEX *)GET_VERTEX(e2);
+ v[3] = (VERTEX *)GET_VERTEX(e3);
+
+ if (DO_TWOSIDE || DO_OFFSET || DO_UNFILLED)
+ {
+ GLfloat ex = VERT_X(v[2]) - VERT_X(v[0]);
+ GLfloat ey = VERT_Y(v[2]) - VERT_Y(v[0]);
+ GLfloat fx = VERT_X(v[3]) - VERT_X(v[1]);
+ GLfloat fy = VERT_Y(v[3]) - VERT_Y(v[1]);
+ GLfloat cc = ex*fy - ey*fx;
+
+ if (DO_TWOSIDE || DO_UNFILLED)
+ {
+ facing = AREA_IS_CCW( cc ) ^ ctx->Polygon._FrontBit;
+
+ if (DO_UNFILLED) {
+ if (facing) {
+ mode = ctx->Polygon.BackMode;
+ if (ctx->Polygon.CullFlag &&
+ ctx->Polygon.CullFaceMode != GL_FRONT) {
+ return;
+ }
+ } else {
+ mode = ctx->Polygon.FrontMode;
+ if (ctx->Polygon.CullFlag &&
+ ctx->Polygon.CullFaceMode != GL_BACK) {
+ return;
+ }
+ }
+ }
+
+ if (DO_TWOSIDE && facing == 1)
+ {
+ if (HAVE_RGBA) {
+ GLchan (*vbcolor)[4] = VB->ColorPtr[1]->Ptr;
+ (void)vbcolor;
+
+ if (HAVE_BACK_COLORS) {
+ if (!DO_FLAT) {
+ VERT_SAVE_RGBA( 0 );
+ VERT_SAVE_RGBA( 1 );
+ VERT_SAVE_RGBA( 2 );
+ VERT_COPY_RGBA1( v[0] );
+ VERT_COPY_RGBA1( v[1] );
+ VERT_COPY_RGBA1( v[2] );
+ }
+ VERT_SAVE_RGBA( 3 );
+ VERT_COPY_RGBA1( v[3] );
+ if (HAVE_SPEC) {
+ if (!DO_FLAT) {
+ VERT_SAVE_SPEC( 0 );
+ VERT_SAVE_SPEC( 1 );
+ VERT_SAVE_SPEC( 2 );
+ VERT_COPY_SPEC1( v[0] );
+ VERT_COPY_SPEC1( v[1] );
+ VERT_COPY_SPEC1( v[2] );
+ }
+ VERT_SAVE_SPEC( 3 );
+ VERT_COPY_SPEC1( v[3] );
+ }
+ }
+ else {
+ if (!DO_FLAT) {
+ VERT_SAVE_RGBA( 0 );
+ VERT_SAVE_RGBA( 1 );
+ VERT_SAVE_RGBA( 2 );
+ VERT_SET_RGBA( v[0], vbcolor[e0] );
+ VERT_SET_RGBA( v[1], vbcolor[e1] );
+ VERT_SET_RGBA( v[2], vbcolor[e2] );
+ }
+ VERT_SAVE_RGBA( 3 );
+ VERT_SET_RGBA( v[3], vbcolor[e3] );
+
+ if (HAVE_SPEC && VB->SecondaryColorPtr[1]) {
+ GLchan (*vbspec)[4] = VB->SecondaryColorPtr[1]->Ptr;
+ ASSERT(VB->SecondaryColorPtr[1]->StrideB==4*sizeof(GLchan));
+
+ if (!DO_FLAT) {
+ VERT_SAVE_SPEC( 0 );
+ VERT_SAVE_SPEC( 1 );
+ VERT_SAVE_SPEC( 2 );
+ VERT_SET_SPEC( v[0], vbspec[e0] );
+ VERT_SET_SPEC( v[1], vbspec[e1] );
+ VERT_SET_SPEC( v[2], vbspec[e2] );
+ }
+ VERT_SAVE_SPEC( 3 );
+ VERT_SET_SPEC( v[3], vbspec[e3] );
+ }
+ }
+ }
+ else {
+ GLuint *vbindex = VB->IndexPtr[1]->data;
+ if (!DO_FLAT) {
+ VERT_SET_IND( v[0], vbindex[e0] );
+ VERT_SET_IND( v[1], vbindex[e1] );
+ VERT_SET_IND( v[2], vbindex[e2] );
+ }
+ VERT_SET_IND( v[3], vbindex[e3] );
+ }
+ }
+ }
+
+
+ if (DO_OFFSET)
+ {
+ offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
+ z[0] = VERT_Z(v[0]);
+ z[1] = VERT_Z(v[1]);
+ z[2] = VERT_Z(v[2]);
+ z[3] = VERT_Z(v[3]);
+ if (cc * cc > 1e-16) {
+ GLfloat ez = z[2] - z[0];
+ GLfloat fz = z[3] - z[1];
+ GLfloat a = ey*fz - ez*fy;
+ GLfloat b = ez*fx - ex*fz;
+ GLfloat ic = 1.0 / cc;
+ GLfloat ac = a * ic;
+ GLfloat bc = b * ic;
+ if ( ac < 0.0f ) ac = -ac;
+ if ( bc < 0.0f ) bc = -bc;
+ offset += MAX2( ac, bc ) * ctx->Polygon.OffsetFactor;
+ }
+ offset *= ctx->MRD;
+ }
+ }
+
+ if (DO_FLAT) {
+ if (HAVE_RGBA) {
+ VERT_SAVE_RGBA( 0 );
+ VERT_SAVE_RGBA( 1 );
+ VERT_SAVE_RGBA( 2 );
+ VERT_COPY_RGBA( v[0], v[3] );
+ VERT_COPY_RGBA( v[1], v[3] );
+ VERT_COPY_RGBA( v[2], v[3] );
+ if (HAVE_SPEC && VB->SecondaryColorPtr[0]) {
+ VERT_SAVE_SPEC( 0 );
+ VERT_SAVE_SPEC( 1 );
+ VERT_SAVE_SPEC( 2 );
+ VERT_COPY_SPEC( v[0], v[3] );
+ VERT_COPY_SPEC( v[1], v[3] );
+ VERT_COPY_SPEC( v[2], v[3] );
+ }
+ }
+ else {
+ VERT_SAVE_IND( 0 );
+ VERT_SAVE_IND( 1 );
+ VERT_SAVE_IND( 2 );
+ VERT_COPY_IND( v[0], v[3] );
+ VERT_COPY_IND( v[1], v[3] );
+ VERT_COPY_IND( v[2], v[3] );
+ }
+ }
+
+ if (mode == GL_POINT) {
+ if (( DO_OFFSET) && ctx->Polygon.OffsetPoint) {
+ VERT_Z_ADD(v[0], offset);
+ VERT_Z_ADD(v[1], offset);
+ VERT_Z_ADD(v[2], offset);
+ VERT_Z_ADD(v[3], offset);
+ }
+ UNFILLED_QUAD( ctx, GL_POINT, e0, e1, e2, e3 );
+ } else if (mode == GL_LINE) {
+ if (DO_OFFSET && ctx->Polygon.OffsetLine) {
+ VERT_Z_ADD(v[0], offset);
+ VERT_Z_ADD(v[1], offset);
+ VERT_Z_ADD(v[2], offset);
+ VERT_Z_ADD(v[3], offset);
+ }
+ UNFILLED_QUAD( ctx, GL_LINE, e0, e1, e2, e3 );
+ } else {
+ if (DO_OFFSET && ctx->Polygon.OffsetFill) {
+ VERT_Z_ADD(v[0], offset);
+ VERT_Z_ADD(v[1], offset);
+ VERT_Z_ADD(v[2], offset);
+ VERT_Z_ADD(v[3], offset);
+ }
+ RASTERIZE( GL_TRIANGLES );
+ QUAD( (v[0]), (v[1]), (v[2]), (v[3]) );
+ }
+
+ if (DO_OFFSET)
+ {
+ VERT_SET_Z(v[0], z[0]);
+ VERT_SET_Z(v[1], z[1]);
+ VERT_SET_Z(v[2], z[2]);
+ VERT_SET_Z(v[3], z[3]);
+ }
+
+ if (DO_TWOSIDE && facing == 1)
+ {
+ if (HAVE_RGBA) {
+ if (!DO_FLAT) {
+ VERT_RESTORE_RGBA( 0 );
+ VERT_RESTORE_RGBA( 1 );
+ VERT_RESTORE_RGBA( 2 );
+ }
+ VERT_RESTORE_RGBA( 3 );
+ if (HAVE_SPEC) {
+ if (!DO_FLAT) {
+ VERT_RESTORE_SPEC( 0 );
+ VERT_RESTORE_SPEC( 1 );
+ VERT_RESTORE_SPEC( 2 );
+ }
+ VERT_RESTORE_SPEC( 3 );
+ }
+ }
+ else {
+ GLuint *vbindex = VB->IndexPtr[0]->data;
+ if (!DO_FLAT) {
+ VERT_SET_IND( v[0], vbindex[e0] );
+ VERT_SET_IND( v[1], vbindex[e1] );
+ VERT_SET_IND( v[2], vbindex[e2] );
+ }
+ VERT_SET_IND( v[3], vbindex[e3] );
+ }
+ }
+
+
+ if (DO_FLAT) {
+ if (HAVE_RGBA) {
+ VERT_RESTORE_RGBA( 0 );
+ VERT_RESTORE_RGBA( 1 );
+ VERT_RESTORE_RGBA( 2 );
+ if (HAVE_SPEC && VB->SecondaryColorPtr[0]) {
+ VERT_RESTORE_SPEC( 0 );
+ VERT_RESTORE_SPEC( 1 );
+ VERT_RESTORE_SPEC( 2 );
+ }
+ }
+ else {
+ VERT_RESTORE_IND( 0 );
+ VERT_RESTORE_IND( 1 );
+ VERT_RESTORE_IND( 2 );
+ }
+ }
+}
+#else
+static void TAG(quad)( GLcontext *ctx, GLuint e0,
+ GLuint e1, GLuint e2, GLuint e3 )
+{
+ if (DO_UNFILLED) {
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte ef1 = VB->EdgeFlag[e1];
+ GLubyte ef3 = VB->EdgeFlag[e3];
+ VB->EdgeFlag[e1] = 0;
+ TAG(triangle)( ctx, e0, e1, e3 );
+ VB->EdgeFlag[e1] = ef1;
+ VB->EdgeFlag[e3] = 0;
+ TAG(triangle)( ctx, e1, e2, e3 );
+ VB->EdgeFlag[e3] = ef3;
+ } else {
+ TAG(triangle)( ctx, e0, e1, e3 );
+ TAG(triangle)( ctx, e1, e2, e3 );
+ }
+}
+#endif
+#endif
+
+#if DO_LINE
+static void TAG(line)( GLcontext *ctx, GLuint e0, GLuint e1 )
+{
+ TNLvertexbuffer *VB = &TNL_CONTEXT(ctx)->vb;
+ VERTEX *v[2];
+ LOCAL_VARS(2);
+
+ v[0] = (VERTEX *)GET_VERTEX(e0);
+ v[1] = (VERTEX *)GET_VERTEX(e1);
+
+ if (DO_FLAT) {
+ if (HAVE_RGBA) {
+ VERT_SAVE_RGBA( 0 );
+ VERT_COPY_RGBA( v[0], v[1] );
+ if (HAVE_SPEC && VB->SecondaryColorPtr[0]) {
+ VERT_SAVE_SPEC( 0 );
+ VERT_COPY_SPEC( v[0], v[1] );
+ }
+ }
+ else {
+ VERT_SAVE_IND( 0 );
+ VERT_COPY_IND( v[0], v[1] );
+ }
+ }
+
+ LINE( v[0], v[1] );
+
+ if (DO_FLAT) {
+ if (HAVE_RGBA) {
+ VERT_RESTORE_RGBA( 0 );
+
+ if (HAVE_SPEC && VB->SecondaryColorPtr[0]) {
+ VERT_RESTORE_SPEC( 0 );
+ }
+ }
+ else {
+ VERT_RESTORE_IND( 0 );
+ }
+ }
+}
+#endif
+
+#if DO_POINTS
+static void TAG(points)( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb;
+ int i;
+ LOCAL_VARS(1);
+
+ if (VB->Elts == 0) {
+ for ( i = first ; i < last ; i++ ) {
+ if ( VB->ClipMask[i] == 0 ) {
+ VERTEX *v = (VERTEX *)GET_VERTEX(i);
+ POINT( v );
+ }
+ }
+ } else {
+ for ( i = first ; i < last ; i++ ) {
+ GLuint e = VB->Elts[i];
+ if ( VB->ClipMask[e] == 0 ) {
+ VERTEX *v = (VERTEX *)GET_VERTEX(e);
+ POINT( v );
+ }
+ }
+ }
+}
+#endif
+
+static void TAG(init)( void )
+{
+#if DO_QUAD
+ TAB[IND].quad = TAG(quad);
+#endif
+#if DO_TRI
+ TAB[IND].triangle = TAG(triangle);
+#endif
+#if DO_LINE
+ TAB[IND].line = TAG(line);
+#endif
+#if DO_POINTS
+ TAB[IND].points = TAG(points);
+#endif
+}
+
+#undef IND
+#undef TAG
+
+#if HAVE_RGBA
+#undef VERT_SET_IND
+#undef VERT_COPY_IND
+#undef VERT_SAVE_IND
+#undef VERT_RESTORE_IND
+#if HAVE_BACK_COLORS
+#undef VERT_SET_RGBA
+#endif
+#else
+#undef VERT_SET_RGBA
+#undef VERT_COPY_RGBA
+#undef VERT_SAVE_RGBA
+#undef VERT_RESTORE_RGBA
+#if HAVE_BACK_COLORS
+#undef VERT_SET_IND
+#endif
+#endif
+
+#if !HAVE_SPEC
+#undef VERT_SET_SPEC
+#undef VERT_COPY_SPEC
+#undef VERT_SAVE_SPEC
+#undef VERT_RESTORE_SPEC
+#if HAVE_BACK_COLORS
+#undef VERT_COPY_SPEC1
+#endif
+#else
+#if HAVE_BACK_COLORS
+#undef VERT_SET_SPEC
+#endif
+#endif
+
+#if !HAVE_BACK_COLORS
+#undef VERT_COPY_SPEC1
+#undef VERT_COPY_IND1
+#undef VERT_COPY_RGBA1
+#endif
+
+#ifndef INSANE_VERTICES
+#undef VERT_SET_Z
+#undef VERT_Z_ADD
+#endif
diff --git a/src/mesa/tnl_dd/t_dd_unfilled.h b/src/mesa/tnl_dd/t_dd_unfilled.h
new file mode 100644
index 0000000000..46415ea5f6
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_unfilled.h
@@ -0,0 +1,212 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#if HAVE_RGBA
+#define VERT_SET_IND( v, c )
+#define VERT_COPY_IND( v0, v1 )
+#define VERT_SAVE_IND( idx )
+#define VERT_RESTORE_IND( idx )
+#endif
+
+#if !HAVE_SPEC
+#define VERT_SET_SPEC( v, c )
+#define VERT_COPY_SPEC( v0, v1 )
+#define VERT_SAVE_SPEC( idx )
+#define VERT_RESTORE_SPEC( idx )
+#endif
+
+static void TAG(unfilled_tri)( GLcontext *ctx,
+ GLenum mode,
+ GLuint e0, GLuint e1, GLuint e2 )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte *ef = VB->EdgeFlag;
+ VERTEX *v[3];
+ LOCAL_VARS(3);
+
+ v[0] = (VERTEX *)GET_VERTEX(e0);
+ v[1] = (VERTEX *)GET_VERTEX(e1);
+ v[2] = (VERTEX *)GET_VERTEX(e2);
+
+ if ((ctx->_TriangleCaps & DD_FLATSHADE) && HAVE_HW_FLATSHADE) {
+ if (HAVE_RGBA) {
+ VERT_SAVE_RGBA(0);
+ VERT_SAVE_RGBA(1);
+ VERT_COPY_RGBA(v[0], v[2]);
+ VERT_COPY_RGBA(v[1], v[2]);
+
+ if (HAVE_SPEC) {
+ VERT_SAVE_SPEC(0);
+ VERT_SAVE_SPEC(1);
+ VERT_COPY_SPEC(v[0], v[2]);
+ VERT_COPY_SPEC(v[1], v[2]);
+ }
+ } else {
+ VERT_SAVE_IND(0);
+ VERT_SAVE_IND(1);
+ VERT_COPY_IND(v[0], v[2]);
+ VERT_COPY_IND(v[1], v[2]);
+ }
+ }
+
+/* fprintf(stderr, "%s %s %d %d %d\n", __FUNCTION__, */
+/* _mesa_lookup_enum_by_nr( mode ), */
+/* ef[e0], ef[e1], ef[e2]); */
+
+ if (mode == GL_POINT) {
+ RASTERIZE(GL_POINTS);
+ if (ef[e0]) POINT( v[0] );
+ if (ef[e1]) POINT( v[1] );
+ if (ef[e2]) POINT( v[2] );
+ }
+ else {
+ RASTERIZE(GL_LINES);
+ if (RENDER_PRIMITIVE == GL_POLYGON) {
+ if (ef[e2]) LINE( v[2], v[0] );
+ if (ef[e0]) LINE( v[0], v[1] );
+ if (ef[e1]) LINE( v[1], v[2] );
+ }
+ else {
+ if (ef[e0]) LINE( v[0], v[1] );
+ if (ef[e1]) LINE( v[1], v[2] );
+ if (ef[e2]) LINE( v[2], v[0] );
+ }
+ }
+
+ if ((ctx->_TriangleCaps & DD_FLATSHADE) && HAVE_HW_FLATSHADE) {
+ if (HAVE_RGBA) {
+ VERT_RESTORE_RGBA(0);
+ VERT_RESTORE_RGBA(1);
+
+ if (HAVE_SPEC) {
+ VERT_RESTORE_SPEC(0);
+ VERT_RESTORE_SPEC(1);
+ }
+ } else {
+ VERT_RESTORE_IND(0);
+ VERT_RESTORE_IND(1);
+ }
+ }
+}
+
+
+static void TAG(unfilled_quad)( GLcontext *ctx,
+ GLenum mode,
+ GLuint e0, GLuint e1,
+ GLuint e2, GLuint e3 )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte *ef = VB->EdgeFlag;
+ VERTEX *v[4];
+ LOCAL_VARS(4);
+
+ v[0] = (VERTEX *)GET_VERTEX(e0);
+ v[1] = (VERTEX *)GET_VERTEX(e1);
+ v[2] = (VERTEX *)GET_VERTEX(e2);
+ v[3] = (VERTEX *)GET_VERTEX(e3);
+
+ /* Hardware flatshading breaks down here. If the hardware doesn't
+ * support flatshading, this will already have been done:
+ */
+ if ((ctx->_TriangleCaps & DD_FLATSHADE) && HAVE_HW_FLATSHADE) {
+ if (HAVE_RGBA) {
+ VERT_SAVE_RGBA(0);
+ VERT_SAVE_RGBA(1);
+ VERT_SAVE_RGBA(2);
+ VERT_COPY_RGBA(v[0], v[3]);
+ VERT_COPY_RGBA(v[1], v[3]);
+ VERT_COPY_RGBA(v[2], v[3]);
+
+ if (HAVE_SPEC) {
+ VERT_SAVE_SPEC(0);
+ VERT_SAVE_SPEC(1);
+ VERT_SAVE_SPEC(2);
+ VERT_COPY_SPEC(v[0], v[3]);
+ VERT_COPY_SPEC(v[1], v[3]);
+ VERT_COPY_SPEC(v[2], v[3]);
+ }
+ } else {
+ VERT_SAVE_IND(0);
+ VERT_SAVE_IND(1);
+ VERT_SAVE_IND(2);
+ VERT_COPY_IND(v[0], v[3]);
+ VERT_COPY_IND(v[1], v[3]);
+ VERT_COPY_IND(v[2], v[3]);
+ }
+ }
+
+ if (mode == GL_POINT) {
+ RASTERIZE(GL_POINTS);
+ if (ef[e0]) POINT( v[0] );
+ if (ef[e1]) POINT( v[1] );
+ if (ef[e2]) POINT( v[2] );
+ if (ef[e3]) POINT( v[3] );
+ }
+ else {
+ RASTERIZE(GL_LINES);
+ if (ef[e0]) LINE( v[0], v[1] );
+ if (ef[e1]) LINE( v[1], v[2] );
+ if (ef[e2]) LINE( v[2], v[3] );
+ if (ef[e3]) LINE( v[3], v[0] );
+ }
+
+ if ((ctx->_TriangleCaps & DD_FLATSHADE) && HAVE_HW_FLATSHADE) {
+ if (HAVE_RGBA) {
+ VERT_RESTORE_RGBA(0);
+ VERT_RESTORE_RGBA(1);
+ VERT_RESTORE_RGBA(2);
+
+ if (HAVE_SPEC) {
+ VERT_RESTORE_SPEC(0);
+ VERT_RESTORE_SPEC(1);
+ VERT_RESTORE_SPEC(2);
+ }
+ } else {
+ VERT_RESTORE_IND(0);
+ VERT_RESTORE_IND(1);
+ VERT_RESTORE_IND(2);
+ }
+ }
+}
+
+
+#if HAVE_RGBA
+#undef VERT_SET_IND
+#undef VERT_COPY_IND
+#undef VERT_SAVE_IND
+#undef VERT_RESTORE_IND
+#endif
+
+#if !HAVE_SPEC
+#undef VERT_SET_SPEC
+#undef VERT_COPY_SPEC
+#undef VERT_SAVE_SPEC
+#undef VERT_RESTORE_SPEC
+#endif
+
+#undef TAG
diff --git a/src/mesa/tnl_dd/t_dd_vb.c b/src/mesa/tnl_dd/t_dd_vb.c
new file mode 100644
index 0000000000..4a742bcbbe
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_vb.c
@@ -0,0 +1,392 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+#include "math/m_translate.h"
+
+#if (HAVE_HW_VIEWPORT)
+#define UNVIEWPORT_VARS
+#define UNVIEWPORT_X(x) x
+#define UNVIEWPORT_Y(x) x
+#define UNVIEWPORT_Z(x) x
+#endif
+
+#ifndef LOCALVARS
+#define LOCALVARS
+#endif
+
+#ifndef CHECK_HW_DIVIDE
+#define CHECK_HW_DIVIDE 1
+#endif
+
+/* These don't need to be duplicated, but there's currently nowhere
+ * really convenient to put them. Need to build some actual .o files in
+ * this directory?
+ */
+static void copy_pv_rgba4_spec5( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ LOCALVARS
+ GLubyte *verts = GET_VERTEX_STORE();
+ GLuint shift = GET_VERTEX_STRIDE_SHIFT();
+ GLuint *dst = (GLuint *)(verts + (edst << shift));
+ GLuint *src = (GLuint *)(verts + (esrc << shift));
+ dst[4] = src[4];
+ dst[5] = src[5];
+}
+
+static void copy_pv_rgba4( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ LOCALVARS
+ GLubyte *verts = GET_VERTEX_STORE();
+ GLuint shift = GET_VERTEX_STRIDE_SHIFT();
+ GLuint *dst = (GLuint *)(verts + (edst << shift));
+ GLuint *src = (GLuint *)(verts + (esrc << shift));
+ dst[4] = src[4];
+}
+
+static void copy_pv_rgba3( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ LOCALVARS
+ GLubyte *verts = GET_VERTEX_STORE();
+ GLuint shift = GET_VERTEX_STRIDE_SHIFT();
+ GLuint *dst = (GLuint *)(verts + (edst << shift));
+ GLuint *src = (GLuint *)(verts + (esrc << shift));
+ dst[3] = src[3];
+}
+
+
+void TAG(translate_vertex)(GLcontext *ctx,
+ const VERTEX *src,
+ SWvertex *dst)
+{
+ LOCALVARS
+ GLuint format = GET_VERTEX_FORMAT();
+ GLfloat *s = ctx->Viewport._WindowMap.m;
+ UNVIEWPORT_VARS;
+
+ if (format == TINY_VERTEX_FORMAT) {
+ if (HAVE_HW_VIEWPORT) {
+ dst->win[0] = s[0] * src->v.x + s[12];
+ dst->win[1] = s[5] * src->v.y + s[13];
+ dst->win[2] = s[10] * src->v.z + s[14];
+ dst->win[3] = 1.0;
+ } else {
+ dst->win[0] = UNVIEWPORT_X( src->v.x );
+ dst->win[1] = UNVIEWPORT_Y( src->v.y );
+ dst->win[2] = UNVIEWPORT_Z( src->v.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 {
+ if (HAVE_HW_VIEWPORT) {
+ if (HAVE_HW_DIVIDE && CHECK_HW_DIVIDE) {
+ GLfloat oow = 1.0 / src->v.w;
+ dst->win[0] = s[0] * src->v.x * oow + s[12];
+ dst->win[1] = s[5] * src->v.y * oow + s[13];
+ dst->win[2] = s[10] * src->v.z * oow + s[14];
+ dst->win[3] = oow;
+ } else {
+ dst->win[0] = s[0] * src->v.x + s[12];
+ dst->win[1] = s[5] * src->v.y + s[13];
+ dst->win[2] = s[10] * src->v.z + s[14];
+ dst->win[3] = src->v.w;
+ }
+ } else {
+ dst->win[0] = UNVIEWPORT_X( src->v.x );
+ dst->win[1] = UNVIEWPORT_Y( src->v.y );
+ dst->win[2] = UNVIEWPORT_Z( src->v.z );
+ dst->win[3] = src->v.w;
+ }
+
+ 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;
+
+ dst->specular[0] = src->v.specular.red;
+ dst->specular[1] = src->v.specular.green;
+ dst->specular[2] = src->v.specular.blue;
+
+ dst->fog = src->v.specular.alpha/255.0;
+
+ if (HAVE_PTEX_VERTICES &&
+ ((HAVE_TEX2_VERTICES && format == PROJ_TEX3_VERTEX_FORMAT) ||
+ (format == PROJ_TEX1_VERTEX_FORMAT))) {
+
+ dst->texcoord[0][0] = src->pv.u0;
+ dst->texcoord[0][1] = src->pv.v0;
+ dst->texcoord[0][3] = src->pv.q0;
+
+ dst->texcoord[1][0] = src->pv.u1;
+ dst->texcoord[1][1] = src->pv.v1;
+ dst->texcoord[1][3] = src->pv.q1;
+
+ if (HAVE_TEX2_VERTICES) {
+ dst->texcoord[2][0] = src->pv.u2;
+ dst->texcoord[2][1] = src->pv.v2;
+ dst->texcoord[2][3] = src->pv.q2;
+ }
+
+ if (HAVE_TEX3_VERTICES) {
+ dst->texcoord[3][0] = src->pv.u3;
+ dst->texcoord[3][1] = src->pv.v3;
+ dst->texcoord[3][3] = src->pv.q3;
+ }
+ }
+ else {
+ dst->texcoord[0][0] = src->v.u0;
+ dst->texcoord[0][1] = src->v.v0;
+ dst->texcoord[0][3] = 1.0;
+
+ dst->texcoord[1][0] = src->v.u1;
+ dst->texcoord[1][1] = src->v.v1;
+ dst->texcoord[1][3] = 1.0;
+
+ if (HAVE_TEX2_VERTICES) {
+ dst->texcoord[2][0] = src->v.u2;
+ dst->texcoord[2][1] = src->v.v2;
+ dst->texcoord[2][3] = 1.0;
+ }
+
+ if (HAVE_TEX3_VERTICES) {
+ dst->texcoord[3][0] = src->v.u3;
+ dst->texcoord[3][1] = src->v.v3;
+ dst->texcoord[3][3] = 1.0;
+ }
+ }
+ }
+
+ dst->pointSize = ctx->Point._Size;
+}
+
+
+
+void TAG(print_vertex)( GLcontext *ctx, const VERTEX *v )
+{
+ LOCALVARS
+ GLuint format = GET_VERTEX_FORMAT();
+
+ fprintf(stderr, "(%x) ", format);
+
+ switch (format) {
+#if HAVE_TINY_VERTICES
+ case TINY_VERTEX_FORMAT:
+ fprintf(stderr, "xyz %.4f,%.4f,%.4f rgba %x:%x:%x:%x\n",
+ v->v.x, v->v.y, v->v.z,
+ v->tv.color.red,
+ v->tv.color.green,
+ v->tv.color.blue,
+ v->tv.color.alpha);
+ break;
+#endif
+#if HAVE_NOTEX_VERTICES
+ case NOTEX_VERTEX_FORMAT:
+ fprintf(stderr, "xyzw %.4f,%.4f,%.4f,%.4f rgba %x:%x:%x:%x spec %x:%x:%x:%x\n",
+ v->v.x, v->v.y, v->v.z, v->v.w,
+ v->v.color.red,
+ v->v.color.green,
+ v->v.color.blue,
+ v->v.color.alpha,
+ v->v.specular.red,
+ v->v.specular.green,
+ v->v.specular.blue,
+ v->v.specular.alpha);
+ break;
+#endif
+#if HAVE_TEX0_VERTICES
+ case TEX0_VERTEX_FORMAT:
+ fprintf(stderr, "xyzw %.4f,%.4f,%.4f,%.4f rgba %x:%x:%x:%x st %.4f,%.4f\n",
+ v->v.x, v->v.y, v->v.z, v->v.w,
+ v->v.color.red,
+ v->v.color.green,
+ v->v.color.blue,
+ v->v.color.alpha,
+ v->v.u0,
+ v->v.v0);
+ break;
+#endif
+#if HAVE_TEX1_VERTICES
+ case TEX1_VERTEX_FORMAT:
+ fprintf(stderr, "xyzw %.4f,%.4f,%.4f,%.4f rgba %x:%x:%x:%x st %.4f,%.4f st %.4f,%.4f\n",
+ v->v.x, v->v.y, v->v.z, v->v.w,
+ v->v.color.red,
+ v->v.color.green,
+ v->v.color.blue,
+ v->v.color.alpha,
+ v->v.u0,
+ v->v.v0,
+ v->v.u1,
+ v->v.u2);
+ break;
+#endif
+#if HAVE_PTEX_VERTICES
+ case PROJ_TEX1_VERTEX_FORMAT:
+ fprintf(stderr, "xyzw %.4f,%.4f,%.4f,%.4f rgba %x:%x:%x:%x stq %.4f,%.4f,%.4f stq %.4f,%.4f,%.4f\n",
+ v->v.x, v->v.y, v->v.z, v->v.w,
+ v->v.color.red,
+ v->v.color.green,
+ v->v.color.blue,
+ v->v.color.alpha,
+ v->pv.u0,
+ v->pv.v0,
+ v->pv.q0,
+ v->pv.u1,
+ v->pv.v1,
+ v->pv.q1);
+ break;
+#endif
+ default:
+ fprintf(stderr, "???\n");
+ break;
+ }
+
+ fprintf(stderr, "\n");
+}
+
+static void do_import( struct vertex_buffer *VB,
+ struct gl_client_array *to,
+ struct gl_client_array *from )
+{
+ 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);
+}
+
+#ifndef IMPORT_QUALIFIER
+#define IMPORT_QUALIFIER static
+#endif
+
+IMPORT_QUALIFIER void TAG(import_float_colors)( GLcontext *ctx )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct gl_client_array *to = GET_UBYTE_COLOR_STORE();
+ do_import( VB, to, VB->ColorPtr[0] );
+ VB->ColorPtr[0] = to;
+}
+
+IMPORT_QUALIFIER void TAG(import_float_spec_colors)( GLcontext *ctx )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct gl_client_array *to = GET_UBYTE_SPEC_COLOR_STORE();
+ do_import( VB, to, VB->SecondaryColorPtr[0] );
+ VB->SecondaryColorPtr[0] = to;
+}
+
+/* Interpolate the elements of the VB not included in typical hardware
+ * vertices.
+ *
+ * NOTE: All these arrays are guarenteed by tnl to be writeable and
+ * have good stride.
+ */
+#ifndef INTERP_QUALIFIER
+#define INTERP_QUALIFIER static
+#endif
+
+#define GET_COLOR(ptr, idx) (((GLchan (*)[4])((ptr)->Ptr))[idx])
+
+
+INTERP_QUALIFIER void TAG(interp_extras)( GLcontext *ctx,
+ GLfloat t,
+ GLuint dst, GLuint out, GLuint in,
+ GLboolean force_boundary )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ 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->SecondaryColorPtr[1]) {
+ INTERP_3CHAN( t,
+ GET_COLOR(VB->SecondaryColorPtr[1], dst),
+ GET_COLOR(VB->SecondaryColorPtr[1], out),
+ GET_COLOR(VB->SecondaryColorPtr[1], in) );
+ }
+ }
+
+ if (VB->EdgeFlag) {
+ VB->EdgeFlag[dst] = VB->EdgeFlag[out] || force_boundary;
+ }
+
+ INTERP_VERTEX(ctx, t, dst, out, in, force_boundary);
+}
+
+INTERP_QUALIFIER void TAG(copy_pv_extras)( GLcontext *ctx,
+ GLuint dst, GLuint src )
+{
+ LOCALVARS
+ 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) );
+
+ if (VB->SecondaryColorPtr[1]) {
+ COPY_CHAN4( GET_COLOR(VB->SecondaryColorPtr[1], dst),
+ GET_COLOR(VB->SecondaryColorPtr[1], src) );
+ }
+ }
+
+ COPY_PV_VERTEX(ctx, dst, src);
+}
+
+
+#undef INTERP_QUALIFIER
+#undef IMPORT_QUALIFIER
+#undef GET_COLOR
+
+#undef IND
+#undef TAG
diff --git a/src/mesa/tnl_dd/t_dd_vbtmp.h b/src/mesa/tnl_dd/t_dd_vbtmp.h
new file mode 100644
index 0000000000..5aad0b5622
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_vbtmp.h
@@ -0,0 +1,834 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.0.1
+ *
+ * Copyright (C) 1999-2003 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+/* Unlike the other templates here, this assumes quite a bit about the
+ * underlying hardware. Specifically it assumes a d3d-like vertex
+ * format, with a layout more or less constrained to look like the
+ * following:
+ *
+ * union {
+ * struct {
+ * float x, y, z, w;
+ * struct { char r, g, b, a; } color;
+ * struct { char r, g, b, fog; } spec;
+ * float u0, v0;
+ * float u1, v1;
+ * float u2, v2;
+ * float u3, v3;
+ * } v;
+ * struct {
+ * float x, y, z, w;
+ * struct { char r, g, b, a; } color;
+ * struct { char r, g, b, fog; } spec;
+ * float u0, v0, q0;
+ * float u1, v1, q1;
+ * float u2, v2, q2;
+ * float u3, v3, q3;
+ * } pv;
+ * struct {
+ * float x, y, z;
+ * struct { char r, g, b, a; } color;
+ * } tv;
+ * float f[16];
+ * unsigned int ui[16];
+ * unsigned char ub4[4][16];
+ * }
+ *
+
+ * VERTEX: hw vertex type as above
+ * VERTEX_COLOR: hw color struct type in VERTEX
+ *
+ * DO_XYZW: Emit xyz and maybe w coordinates.
+ * DO_RGBA: Emit color.
+ * DO_SPEC: Emit specular color.
+ * DO_FOG: Emit fog coordinate in specular alpha.
+ * DO_TEX0: Emit tex0 u,v coordinates.
+ * DO_TEX1: Emit tex1 u,v coordinates.
+ * DO_TEX2: Emit tex2 u,v coordinates.
+ * DO_TEX3: Emit tex3 u,v coordinates.
+ * DO_PTEX: Emit tex0,1,2,3 q coordinates where possible.
+ *
+ * HAVE_RGBA_COLOR: Hardware takes color in rgba order (else bgra).
+ *
+ * HAVE_HW_VIEWPORT: Hardware performs viewport transform.
+ * HAVE_HW_DIVIDE: Hardware performs perspective divide.
+ *
+ * HAVE_TINY_VERTICES: Hardware understands v.tv format.
+ * HAVE_PTEX_VERTICES: Hardware understands v.pv format.
+ * HAVE_NOTEX_VERTICES: Hardware understands v.v format with texcount 0.
+ *
+ * Additionally, this template assumes it is emitting *transformed*
+ * vertices; the modifications to emit untransformed vertices (ie. to
+ * t&l hardware) are probably too great to cooexist with the code
+ * already in this file.
+ *
+ * NOTE: The PTEX vertex format always includes TEX0 and TEX1, even if
+ * only TEX0 is enabled, in order to maintain a vertex size which is
+ * an exact number of quadwords.
+ */
+
+#if (HAVE_HW_VIEWPORT)
+#define VIEWPORT_X(dst,x) dst = x
+#define VIEWPORT_Y(dst,y) dst = y
+#define VIEWPORT_Z(dst,z) dst = z
+#else
+#define VIEWPORT_X(dst,x) dst = s[0] * x + s[12]
+#define VIEWPORT_Y(dst,y) dst = s[5] * y + s[13]
+#define VIEWPORT_Z(dst,z) dst = s[10] * z + s[14]
+#endif
+
+#if (HAVE_HW_DIVIDE && !HAVE_PTEX_VERTICES)
+#error "can't cope with this combination"
+#endif
+
+#ifndef LOCALVARS
+#define LOCALVARS
+#endif
+
+#ifndef CHECK_HW_DIVIDE
+#define CHECK_HW_DIVIDE 1
+#endif
+
+#if (HAVE_HW_DIVIDE || DO_SPEC || DO_TEX0 || DO_FOG || !HAVE_TINY_VERTICES)
+
+static void TAG(emit)( GLcontext *ctx,
+ GLuint start, GLuint end,
+ void *dest,
+ GLuint stride )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLfloat (*tc0)[4], (*tc1)[4], (*fog)[4];
+ GLfloat (*tc2)[4], (*tc3)[4];
+ GLubyte (*col)[4], (*spec)[4];
+ GLuint tc0_stride, tc1_stride, col_stride, spec_stride, fog_stride;
+ GLuint tc2_stride, tc3_stride;
+ GLuint tc0_size, tc1_size;
+ GLuint tc2_size, tc3_size;
+ GLfloat (*coord)[4];
+ GLuint coord_stride;
+ VERTEX *v = (VERTEX *)dest;
+ const GLfloat *s = GET_VIEWPORT_MAT();
+ const GLubyte *mask = VB->ClipMask;
+ int i;
+
+/* fprintf(stderr, "%s(big) importable %d %d..%d\n", */
+/* __FUNCTION__, VB->importable_data, start, end); */
+
+ if (HAVE_HW_VIEWPORT && HAVE_HW_DIVIDE && CHECK_HW_DIVIDE) {
+ (void) s;
+ coord = VB->ClipPtr->data;
+ coord_stride = VB->ClipPtr->stride;
+ }
+ else {
+ coord = VB->NdcPtr->data;
+ coord_stride = VB->NdcPtr->stride;
+ }
+
+ if (DO_TEX3) {
+ const GLuint t3 = GET_TEXSOURCE(3);
+ tc3 = VB->TexCoordPtr[t3]->data;
+ tc3_stride = VB->TexCoordPtr[t3]->stride;
+ if (DO_PTEX)
+ tc3_size = VB->TexCoordPtr[t3]->size;
+ }
+
+ if (DO_TEX2) {
+ const GLuint t2 = GET_TEXSOURCE(2);
+ tc2 = VB->TexCoordPtr[t2]->data;
+ tc2_stride = VB->TexCoordPtr[t2]->stride;
+ if (DO_PTEX)
+ tc2_size = VB->TexCoordPtr[t2]->size;
+ }
+
+ if (DO_TEX1) {
+ const GLuint t1 = GET_TEXSOURCE(1);
+ tc1 = VB->TexCoordPtr[t1]->data;
+ tc1_stride = VB->TexCoordPtr[t1]->stride;
+ if (DO_PTEX)
+ tc1_size = VB->TexCoordPtr[t1]->size;
+ }
+
+ if (DO_TEX0) {
+ const GLuint t0 = GET_TEXSOURCE(0);
+ tc0_stride = VB->TexCoordPtr[t0]->stride;
+ tc0 = VB->TexCoordPtr[t0]->data;
+ if (DO_PTEX)
+ tc0_size = VB->TexCoordPtr[t0]->size;
+ }
+
+ if (DO_RGBA) {
+ 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;
+ }
+
+ if (DO_SPEC) {
+ if (VB->SecondaryColorPtr[0]) {
+ if (VB->SecondaryColorPtr[0]->Type != GL_UNSIGNED_BYTE)
+ IMPORT_FLOAT_SPEC_COLORS( ctx );
+ spec = (GLubyte (*)[4])VB->SecondaryColorPtr[0]->Ptr;
+ spec_stride = VB->SecondaryColorPtr[0]->StrideB;
+ } else {
+ GLubyte tmp[4];
+ spec = &tmp;
+ spec_stride = 0;
+ }
+ }
+
+ if (DO_FOG) {
+ if (VB->FogCoordPtr) {
+ fog = VB->FogCoordPtr->data;
+ fog_stride = VB->FogCoordPtr->stride;
+ }
+ else {
+ static GLfloat tmp[4] = {0, 0, 0, 0};
+ fog = &tmp;
+ fog_stride = 0;
+ }
+ }
+
+ if (VB->importable_data || (DO_SPEC && !spec_stride) || (DO_FOG && !fog_stride)) {
+ /* May have nonstandard strides:
+ */
+ if (start) {
+ coord = (GLfloat (*)[4])((GLubyte *)coord + start * coord_stride);
+ if (DO_TEX0)
+ tc0 = (GLfloat (*)[4])((GLubyte *)tc0 + start * tc0_stride);
+ if (DO_TEX1)
+ tc1 = (GLfloat (*)[4])((GLubyte *)tc1 + start * tc1_stride);
+ if (DO_TEX2)
+ tc2 = (GLfloat (*)[4])((GLubyte *)tc2 + start * tc2_stride);
+ if (DO_TEX3)
+ tc3 = (GLfloat (*)[4])((GLubyte *)tc3 + start * tc3_stride);
+ if (DO_RGBA)
+ STRIDE_4UB(col, start * col_stride);
+ if (DO_SPEC)
+ STRIDE_4UB(spec, start * spec_stride);
+ if (DO_FOG)
+ /*STRIDE_F(fog, start * fog_stride);*/
+ fog = (GLfloat (*)[4])((GLubyte *)fog + start * fog_stride);
+ }
+
+ for (i=start; i < end; i++, v = (VERTEX *)((GLubyte *)v + stride)) {
+ if (DO_XYZW) {
+ if (HAVE_HW_VIEWPORT || mask[i] == 0) {
+ VIEWPORT_X(v->v.x, coord[0][0]);
+ VIEWPORT_Y(v->v.y, coord[0][1]);
+ VIEWPORT_Z(v->v.z, coord[0][2]);
+ v->v.w = coord[0][3];
+ }
+/* fprintf(stderr, "vert %d: %.2f %.2f %.2f %.2f\n", */
+/* i, v->v.x, v->v.y, v->v.z, v->v.w); */
+ coord = (GLfloat (*)[4])((GLubyte *)coord + coord_stride);
+ }
+ if (DO_RGBA) {
+ if (HAVE_RGBA_COLOR) {
+ *(GLuint *)&v->v.color = LE32_TO_CPU(*(GLuint *)&col[0]);
+ STRIDE_4UB(col, col_stride);
+ } else {
+ v->v.color.blue = col[0][2];
+ v->v.color.green = col[0][1];
+ v->v.color.red = col[0][0];
+ v->v.color.alpha = col[0][3];
+ STRIDE_4UB(col, col_stride);
+ }
+ }
+ if (DO_SPEC) {
+ v->v.specular.red = spec[0][0];
+ v->v.specular.green = spec[0][1];
+ v->v.specular.blue = spec[0][2];
+ STRIDE_4UB(spec, spec_stride);
+ }
+ if (DO_FOG) {
+ v->v.specular.alpha = fog[0][0] * 255.0;
+ /*STRIDE_F(fog, fog_stride);*/
+ fog = (GLfloat (*)[4])((GLubyte *)fog + fog_stride);
+ }
+ if (DO_TEX0) {
+ v->v.u0 = tc0[0][0];
+ v->v.v0 = tc0[0][1];
+ if (DO_PTEX) {
+ if (HAVE_PTEX_VERTICES) {
+ if (tc0_size == 4)
+ v->pv.q0 = tc0[0][3];
+ else
+ v->pv.q0 = 1.0;
+ }
+ else if (tc0_size == 4) {
+ float rhw = 1.0 / tc0[0][3];
+ v->v.w *= tc0[0][3];
+ v->v.u0 *= rhw;
+ v->v.v0 *= rhw;
+ }
+ }
+ tc0 = (GLfloat (*)[4])((GLubyte *)tc0 + tc0_stride);
+ }
+ if (DO_TEX1) {
+ if (DO_PTEX) {
+ v->pv.u1 = tc1[0][0];
+ v->pv.v1 = tc1[0][1];
+ if (tc1_size == 4)
+ v->pv.q1 = tc1[0][3];
+ else
+ v->pv.q1 = 1.0;
+ }
+ else {
+ v->v.u1 = tc1[0][0];
+ v->v.v1 = tc1[0][1];
+ }
+ tc1 = (GLfloat (*)[4])((GLubyte *)tc1 + tc1_stride);
+ }
+ else if (DO_PTEX) {
+ *(GLuint *)&v->pv.q1 = 0; /* avoid culling on radeon */
+ }
+ if (DO_TEX2) {
+ if (DO_PTEX) {
+ v->pv.u2 = tc2[0][0];
+ v->pv.v2 = tc2[0][1];
+ if (tc2_size == 4)
+ v->pv.q2 = tc2[0][3];
+ else
+ v->pv.q2 = 1.0;
+ }
+ else {
+ v->v.u2 = tc2[0][0];
+ v->v.v2 = tc2[0][1];
+ }
+ tc2 = (GLfloat (*)[4])((GLubyte *)tc2 + tc2_stride);
+ }
+ if (DO_TEX3) {
+ if (DO_PTEX) {
+ v->pv.u3 = tc3[0][0];
+ v->pv.v3 = tc3[0][1];
+ if (tc3_size == 4)
+ v->pv.q3 = tc3[0][3];
+ else
+ v->pv.q3 = 1.0;
+ }
+ else {
+ v->v.u3 = tc3[0][0];
+ v->v.v3 = tc3[0][1];
+ }
+ tc3 = (GLfloat (*)[4])((GLubyte *)tc3 + tc3_stride);
+ }
+ }
+ }
+ else {
+ for (i=start; i < end; i++, v = (VERTEX *)((GLubyte *)v + stride)) {
+ if (DO_XYZW) {
+ if (HAVE_HW_VIEWPORT || mask[i] == 0) {
+ VIEWPORT_X(v->v.x, coord[i][0]);
+ VIEWPORT_Y(v->v.y, coord[i][1]);
+ VIEWPORT_Z(v->v.z, coord[i][2]);
+ v->v.w = coord[i][3];
+ }
+ }
+ if (DO_RGBA) {
+ if (HAVE_RGBA_COLOR) {
+ *(GLuint *)&v->v.color = LE32_TO_CPU(*(GLuint *)&col[i]);
+ }
+ else {
+ v->v.color.blue = col[i][2];
+ v->v.color.green = col[i][1];
+ v->v.color.red = col[i][0];
+ v->v.color.alpha = col[i][3];
+ }
+ }
+ if (DO_SPEC) {
+ v->v.specular.red = spec[i][0];
+ v->v.specular.green = spec[i][1];
+ v->v.specular.blue = spec[i][2];
+ }
+ if (DO_FOG) {
+ v->v.specular.alpha = fog[i][0] * 255.0;
+ }
+ if (DO_TEX0) {
+ v->v.u0 = tc0[i][0];
+ v->v.v0 = tc0[i][1];
+ if (DO_PTEX) {
+ if (HAVE_PTEX_VERTICES) {
+ if (tc0_size == 4)
+ v->pv.q0 = tc0[i][3];
+ else
+ v->pv.q0 = 1.0;
+
+ v->pv.q1 = 0; /* radeon */
+ }
+ else if (tc0_size == 4) {
+ float rhw = 1.0 / tc0[i][3];
+ v->v.w *= tc0[i][3];
+ v->v.u0 *= rhw;
+ v->v.v0 *= rhw;
+ }
+ }
+ }
+ if (DO_TEX1) {
+ if (DO_PTEX) {
+ v->pv.u1 = tc1[i][0];
+ v->pv.v1 = tc1[i][1];
+ if (tc1_size == 4)
+ v->pv.q1 = tc1[i][3];
+ else
+ v->pv.q1 = 1.0;
+ }
+ else {
+ v->v.u1 = tc1[i][0];
+ v->v.v1 = tc1[i][1];
+ }
+ }
+ }
+ }
+}
+#else
+#if DO_XYZW
+
+#if HAVE_HW_DIVIDE
+#error "cannot use tiny vertices with hw perspective divide"
+#endif
+
+static void TAG(emit)( GLcontext *ctx, GLuint start, GLuint end,
+ void *dest, GLuint stride )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte (*col)[4];
+ GLuint col_stride;
+ GLfloat (*coord)[4] = VB->NdcPtr->data;
+ GLuint coord_stride = VB->NdcPtr->stride;
+ GLfloat *v = (GLfloat *)dest;
+ const GLubyte *mask = VB->ClipMask;
+ const GLfloat *s = GET_VIEWPORT_MAT();
+ int i;
+
+ (void) s;
+
+ ASSERT(stride == 4);
+
+ 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);
+
+/* fprintf(stderr, "%s(small) importable %x\n", */
+/* __FUNCTION__, VB->importable_data); */
+
+ /* 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) {
+ coord = (GLfloat (*)[4])((GLubyte *)coord + start * coord_stride);
+ STRIDE_4UB(col, start * col_stride);
+ }
+
+ for (i=start; i < end; i++, v+=4) {
+ if (HAVE_HW_VIEWPORT || mask[i] == 0) {
+ VIEWPORT_X(v[0], coord[0][0]);
+ VIEWPORT_Y(v[1], coord[0][1]);
+ VIEWPORT_Z(v[2], coord[0][2]);
+ }
+ coord = (GLfloat (*)[4])((GLubyte *)coord + coord_stride);
+ if (DO_RGBA) {
+ if (HAVE_RGBA_COLOR) {
+ *(GLuint *)&v[3] = LE32_TO_CPU(*(GLuint *)col);
+ }
+ else {
+ VERTEX_COLOR *c = (VERTEX_COLOR *)&v[3];
+ c->blue = col[0][2];
+ c->green = col[0][1];
+ c->red = col[0][0];
+ c->alpha = col[0][3];
+ }
+ STRIDE_4UB( col, col_stride );
+ }
+/* fprintf(stderr, "vert %d: %.2f %.2f %.2f %x\n", */
+/* i, v[0], v[1], v[2], *(int *)&v[3]); */
+ }
+ }
+ else {
+ for (i=start; i < end; i++, v+=4) {
+ if (HAVE_HW_VIEWPORT || mask[i] == 0) {
+ VIEWPORT_X(v[0], coord[i][0]);
+ VIEWPORT_Y(v[1], coord[i][1]);
+ VIEWPORT_Z(v[2], coord[i][2]);
+ }
+ if (DO_RGBA) {
+ if (HAVE_RGBA_COLOR) {
+ *(GLuint *)&v[3] = LE32_TO_CPU(*(GLuint *)&col[i]);
+ }
+ else {
+ VERTEX_COLOR *c = (VERTEX_COLOR *)&v[3];
+ c->blue = col[i][2];
+ c->green = col[i][1];
+ c->red = col[i][0];
+ c->alpha = col[i][3];
+ }
+ }
+/* fprintf(stderr, "vert %d: %.2f %.2f %.2f %x\n", */
+/* i, v[0], v[1], v[2], *(int *)&v[3]); */
+
+ }
+ }
+}
+#else
+static void TAG(emit)( GLcontext *ctx, GLuint start, GLuint end,
+ void *dest, GLuint stride )
+{
+ LOCALVARS
+ 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 (GET_VERTEX_FORMAT() == TINY_VERTEX_FORMAT)
+ v += 3;
+ else
+ v += 4;
+
+ for (i=start; i < end; i++, STRIDE_F(v, stride)) {
+ if (HAVE_RGBA_COLOR) {
+ *(GLuint *)v = LE32_TO_CPU(*(GLuint *)col[0]);
+ }
+ else {
+ VERTEX_COLOR *c = (VERTEX_COLOR *)v;
+ c->blue = col[0][2];
+ c->green = col[0][1];
+ c->red = col[0][0];
+ c->alpha = col[0][3];
+ }
+ STRIDE_4UB( col, col_stride );
+ }
+}
+#endif /* emit */
+#endif /* emit */
+
+#if (DO_XYZW) && (DO_RGBA)
+
+
+#if (HAVE_PTEX_VERTICES)
+static GLboolean TAG(check_tex_sizes)( GLcontext *ctx )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ /* Force 'missing' texcoords to something valid.
+ */
+ if (DO_TEX3 && VB->TexCoordPtr[2] == 0)
+ VB->TexCoordPtr[2] = VB->TexCoordPtr[3];
+
+ if (DO_TEX2 && VB->TexCoordPtr[1] == 0)
+ VB->TexCoordPtr[1] = VB->TexCoordPtr[2];
+
+ if (DO_TEX1 && VB->TexCoordPtr[0] == 0)
+ VB->TexCoordPtr[0] = VB->TexCoordPtr[1];
+
+ if (DO_PTEX)
+ return GL_TRUE;
+
+ if ((DO_TEX3 && VB->TexCoordPtr[GET_TEXSOURCE(3)]->size == 4) ||
+ (DO_TEX2 && VB->TexCoordPtr[GET_TEXSOURCE(2)]->size == 4) ||
+ (DO_TEX1 && VB->TexCoordPtr[GET_TEXSOURCE(1)]->size == 4) ||
+ (DO_TEX0 && VB->TexCoordPtr[GET_TEXSOURCE(0)]->size == 4))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+#else
+static GLboolean TAG(check_tex_sizes)( GLcontext *ctx )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ /* Force 'missing' texcoords to something valid.
+ */
+ if (DO_TEX3 && VB->TexCoordPtr[2] == 0)
+ VB->TexCoordPtr[2] = VB->TexCoordPtr[3];
+
+ if (DO_TEX2 && VB->TexCoordPtr[1] == 0)
+ VB->TexCoordPtr[1] = VB->TexCoordPtr[2];
+
+ if (DO_TEX1 && VB->TexCoordPtr[0] == 0)
+ VB->TexCoordPtr[0] = VB->TexCoordPtr[1];
+
+ if (DO_PTEX)
+ return GL_TRUE;
+
+ /* No hardware support for projective texture. Can fake it for
+ * TEX0 only.
+ */
+ if ((DO_TEX3 && VB->TexCoordPtr[GET_TEXSOURCE(3)]->size == 4) ||
+ (DO_TEX2 && VB->TexCoordPtr[GET_TEXSOURCE(2)]->size == 4) ||
+ (DO_TEX1 && VB->TexCoordPtr[GET_TEXSOURCE(1)]->size == 4)) {
+ PTEX_FALLBACK();
+ return GL_FALSE;
+ }
+
+ if (DO_TEX0 && VB->TexCoordPtr[GET_TEXSOURCE(0)]->size == 4) {
+ if (DO_TEX1 || DO_TEX2 || DO_TEX3) {
+ PTEX_FALLBACK();
+ }
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+#endif /* ptex */
+
+
+static void TAG(interp)( GLcontext *ctx,
+ GLfloat t,
+ GLuint edst, GLuint eout, GLuint ein,
+ GLboolean force_boundary )
+{
+ LOCALVARS
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte *ddverts = GET_VERTEX_STORE();
+ GLuint shift = GET_VERTEX_STRIDE_SHIFT();
+ const GLfloat *dstclip = VB->ClipPtr->data[edst];
+ GLfloat w;
+ const GLfloat *s = GET_VIEWPORT_MAT();
+
+ VERTEX *dst = (VERTEX *)(ddverts + (edst << shift));
+ VERTEX *in = (VERTEX *)(ddverts + (ein << shift));
+ VERTEX *out = (VERTEX *)(ddverts + (eout << shift));
+
+ (void)s;
+
+ if (HAVE_HW_DIVIDE && CHECK_HW_DIVIDE) {
+ VIEWPORT_X( dst->v.x, dstclip[0] );
+ VIEWPORT_Y( dst->v.y, dstclip[1] );
+ VIEWPORT_Z( dst->v.z, dstclip[2] );
+ w = dstclip[3];
+ }
+ else {
+ w = 1.0 / dstclip[3];
+ VIEWPORT_X( dst->v.x, dstclip[0] * w );
+ VIEWPORT_Y( dst->v.y, dstclip[1] * w );
+ VIEWPORT_Z( dst->v.z, dstclip[2] * w );
+ }
+
+ if ((HAVE_HW_DIVIDE && CHECK_HW_DIVIDE) ||
+ DO_FOG || DO_SPEC || DO_TEX0 || DO_TEX1 ||
+ DO_TEX2 || DO_TEX3 || !HAVE_TINY_VERTICES) {
+
+ dst->v.w = w;
+
+ 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 (DO_SPEC) {
+ INTERP_UB( t, dst->v.specular.red, out->v.specular.red, in->v.specular.red );
+ INTERP_UB( t, dst->v.specular.green, out->v.specular.green, in->v.specular.green );
+ INTERP_UB( t, dst->v.specular.blue, out->v.specular.blue, in->v.specular.blue );
+ }
+ if (DO_FOG) {
+ INTERP_UB( t, dst->v.specular.alpha, out->v.specular.alpha, in->v.specular.alpha );
+ }
+ if (DO_TEX0) {
+ if (DO_PTEX) {
+ if (HAVE_PTEX_VERTICES) {
+ INTERP_F( t, dst->pv.u0, out->pv.u0, in->pv.u0 );
+ INTERP_F( t, dst->pv.v0, out->pv.v0, in->pv.v0 );
+ INTERP_F( t, dst->pv.q0, out->pv.q0, in->pv.q0 );
+ } else {
+ GLfloat wout = VB->NdcPtr->data[eout][3];
+ GLfloat win = VB->NdcPtr->data[ein][3];
+ GLfloat qout = out->pv.w / wout;
+ GLfloat qin = in->pv.w / win;
+ GLfloat qdst, rqdst;
+
+ ASSERT( !HAVE_HW_DIVIDE );
+
+ INTERP_F( t, dst->v.u0, out->v.u0 * qout, in->v.u0 * qin );
+ INTERP_F( t, dst->v.v0, out->v.v0 * qout, in->v.v0 * qin );
+ INTERP_F( t, qdst, qout, qin );
+
+ rqdst = 1.0 / qdst;
+ dst->v.u0 *= rqdst;
+ dst->v.v0 *= rqdst;
+ dst->v.w *= rqdst;
+ }
+ }
+ else {
+ INTERP_F( t, dst->v.u0, out->v.u0, in->v.u0 );
+ INTERP_F( t, dst->v.v0, out->v.v0, in->v.v0 );
+ }
+ }
+ if (DO_TEX1) {
+ if (DO_PTEX) {
+ INTERP_F( t, dst->pv.u1, out->pv.u1, in->pv.u1 );
+ INTERP_F( t, dst->pv.v1, out->pv.v1, in->pv.v1 );
+ INTERP_F( t, dst->pv.q1, out->pv.q1, in->pv.q1 );
+ } else {
+ INTERP_F( t, dst->v.u1, out->v.u1, in->v.u1 );
+ INTERP_F( t, dst->v.v1, out->v.v1, in->v.v1 );
+ }
+ }
+ else if (DO_PTEX) {
+ dst->pv.q1 = 0.0; /* must be a valid float on radeon */
+ }
+ if (DO_TEX2) {
+ if (DO_PTEX) {
+ INTERP_F( t, dst->pv.u2, out->pv.u2, in->pv.u2 );
+ INTERP_F( t, dst->pv.v2, out->pv.v2, in->pv.v2 );
+ INTERP_F( t, dst->pv.q2, out->pv.q2, in->pv.q2 );
+ } else {
+ INTERP_F( t, dst->v.u2, out->v.u2, in->v.u2 );
+ INTERP_F( t, dst->v.v2, out->v.v2, in->v.v2 );
+ }
+ }
+ if (DO_TEX3) {
+ if (DO_PTEX) {
+ INTERP_F( t, dst->pv.u3, out->pv.u3, in->pv.u3 );
+ INTERP_F( t, dst->pv.v3, out->pv.v3, in->pv.v3 );
+ INTERP_F( t, dst->pv.q3, out->pv.q3, in->pv.q3 );
+ } else {
+ INTERP_F( t, dst->v.u3, out->v.u3, in->v.u3 );
+ INTERP_F( t, dst->v.v3, out->v.v3, in->v.v3 );
+ }
+ }
+ } 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 /* rgba && xyzw */
+
+
+static void TAG(init)( void )
+{
+ setup_tab[IND].emit = TAG(emit);
+
+#if (DO_XYZW && DO_RGBA)
+ setup_tab[IND].check_tex_sizes = TAG(check_tex_sizes);
+ setup_tab[IND].interp = TAG(interp);
+#endif
+
+ if (DO_SPEC)
+ setup_tab[IND].copy_pv = copy_pv_rgba4_spec5;
+ else if (HAVE_HW_DIVIDE || DO_SPEC || DO_FOG || DO_TEX0 || DO_TEX1 ||
+ DO_TEX2 || DO_TEX3 || !HAVE_TINY_VERTICES)
+ setup_tab[IND].copy_pv = copy_pv_rgba4;
+ else
+ setup_tab[IND].copy_pv = copy_pv_rgba3;
+
+ if (DO_TEX3) {
+ if (DO_PTEX) {
+ ASSERT(HAVE_PTEX_VERTICES);
+ setup_tab[IND].vertex_format = PROJ_TEX3_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 18;
+ setup_tab[IND].vertex_stride_shift = 7;
+ }
+ else {
+ setup_tab[IND].vertex_format = TEX3_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 14;
+ setup_tab[IND].vertex_stride_shift = 6;
+ }
+ }
+ else if (DO_TEX2) {
+ if (DO_PTEX) {
+ ASSERT(HAVE_PTEX_VERTICES);
+ setup_tab[IND].vertex_format = PROJ_TEX3_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 18;
+ setup_tab[IND].vertex_stride_shift = 7;
+ }
+ else {
+ setup_tab[IND].vertex_format = TEX2_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 12;
+ setup_tab[IND].vertex_stride_shift = 6;
+ }
+ }
+ else if (DO_TEX1) {
+ if (DO_PTEX) {
+ ASSERT(HAVE_PTEX_VERTICES);
+ setup_tab[IND].vertex_format = PROJ_TEX1_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 12;
+ setup_tab[IND].vertex_stride_shift = 6;
+ }
+ else {
+ setup_tab[IND].vertex_format = TEX1_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 10;
+ setup_tab[IND].vertex_stride_shift = 6;
+ }
+ }
+ else if (DO_TEX0) {
+ if (DO_PTEX && HAVE_PTEX_VERTICES) {
+ setup_tab[IND].vertex_format = PROJ_TEX1_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 12;
+ setup_tab[IND].vertex_stride_shift = 6;
+ } else {
+ setup_tab[IND].vertex_format = TEX0_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 8;
+ setup_tab[IND].vertex_stride_shift = 5;
+ }
+ }
+ else if (!HAVE_HW_DIVIDE && !DO_SPEC && !DO_FOG && HAVE_TINY_VERTICES) {
+ setup_tab[IND].vertex_format = TINY_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 4;
+ setup_tab[IND].vertex_stride_shift = 4;
+ } else if (HAVE_NOTEX_VERTICES) {
+ setup_tab[IND].vertex_format = NOTEX_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 6;
+ setup_tab[IND].vertex_stride_shift = 5;
+ } else {
+ setup_tab[IND].vertex_format = TEX0_VERTEX_FORMAT;
+ setup_tab[IND].vertex_size = 8;
+ setup_tab[IND].vertex_stride_shift = 5;
+ }
+
+ assert(setup_tab[IND].vertex_size * 4 <=
+ 1 << setup_tab[IND].vertex_stride_shift);
+}
+
+
+#undef IND
+#undef TAG
diff --git a/src/mesa/tnl_dd/t_dd_vertex.h b/src/mesa/tnl_dd/t_dd_vertex.h
new file mode 100644
index 0000000000..d45dd09fbd
--- /dev/null
+++ b/src/mesa/tnl_dd/t_dd_vertex.h
@@ -0,0 +1,78 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.0.3
+ *
+ * Copyright (C) 1999-2002 Brian Paul 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 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
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+typedef struct {
+ GLfloat x, y, z, w;
+} TAG(_coord_t);
+
+#ifdef COLOR_IS_RGBA
+typedef struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+ GLubyte alpha, blue, green, red;
+#else
+ GLubyte red, green, blue, alpha;
+#endif
+} TAG(_color_t);
+#else
+typedef struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+ GLubyte alpha, red, green, blue;
+#else
+ GLubyte blue, green, red, alpha;
+#endif
+} TAG(_color_t);
+#endif
+
+typedef union {
+ struct {
+ GLfloat x, y, z, w;
+ TAG(_color_t) color;
+ TAG(_color_t) specular;
+ GLfloat u0, v0;
+ GLfloat u1, v1;
+ GLfloat u2, v2;
+ GLfloat u3, v3;
+ } v;
+ struct {
+ GLfloat x, y, z, w;
+ TAG(_color_t) color;
+ TAG(_color_t) specular;
+ GLfloat u0, v0, q0;
+ GLfloat u1, v1, q1;
+ GLfloat u2, v2, q2;
+ GLfloat u3, v3, q3;
+ } pv;
+ struct {
+ GLfloat x, y, z;
+ TAG(_color_t) color;
+ } tv;
+ GLfloat f[24];
+ GLuint ui[24];
+ GLubyte ub4[24][4];
+} TAG(Vertex), *TAG(VertexPtr);
+