OSDN Git Service

First batch of code for GL_NV_fragment_program.
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 14 Jan 2003 04:55:45 +0000 (04:55 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 14 Jan 2003 04:55:45 +0000 (04:55 +0000)
Re-org of some GL_NV_vertex_program code.
Replace MAX_TEXTURE_UNITS with MAX_TEXTURE_COORD_UNITS and MAX_TEXTURE_IMAGE_UNITS.

46 files changed:
src/mesa/Makefile.X11
src/mesa/array_cache/ac_context.c
src/mesa/array_cache/ac_context.h
src/mesa/array_cache/ac_import.c
src/mesa/main/Makefile.DJ
src/mesa/main/Makefile.OSMesa16
src/mesa/main/Makefile.X11
src/mesa/main/Makefile.win
src/mesa/main/api_arrayelt.c
src/mesa/main/api_noop.c
src/mesa/main/config.h
src/mesa/main/context.c
src/mesa/main/descrip.mms
src/mesa/main/dlist.c
src/mesa/main/enable.c
src/mesa/main/extensions.c
src/mesa/main/get.c
src/mesa/main/mtypes.h
src/mesa/main/nvfragparse.c [new file with mode: 0644]
src/mesa/main/nvfragparse.h [new file with mode: 0644]
src/mesa/main/nvfragprog.h [new file with mode: 0644]
src/mesa/main/nvprogram.c [new file with mode: 0644]
src/mesa/main/nvprogram.h [new file with mode: 0644]
src/mesa/main/nvvertexec.c [new file with mode: 0644]
src/mesa/main/nvvertexec.h [new file with mode: 0644]
src/mesa/main/nvvertparse.c [new file with mode: 0644]
src/mesa/main/nvvertparse.h [new file with mode: 0644]
src/mesa/main/nvvertprog.h [new file with mode: 0644]
src/mesa/main/state.c
src/mesa/main/texobj.c
src/mesa/swrast/s_aaline.c
src/mesa/swrast/s_aatritemp.h
src/mesa/swrast/s_context.c
src/mesa/swrast/s_context.h
src/mesa/swrast/s_pointtemp.h
src/mesa/swrast/s_span.c
src/mesa/swrast/s_tritemp.h
src/mesa/swrast/swrast.h
src/mesa/swrast_setup/ss_vbtmp.h
src/mesa/tnl/t_context.h
src/mesa/tnl/t_imm_api.c
src/mesa/tnl/t_imm_debug.c
src/mesa/tnl/t_imm_dlist.c
src/mesa/tnl/t_vb_program.c
src/mesa/tnl/t_vb_texgen.c
src/mesa/tnl/t_vb_texmat.c

index 940135f..9ccaafc 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.X11,v 1.72 2002/10/29 23:09:40 brianp Exp $
+# $Id: Makefile.X11,v 1.73 2003/01/14 04:55:45 brianp Exp $
 
 # Mesa 3-D graphics library
 # Version:  5.0
@@ -56,6 +56,10 @@ CORE_SOURCES = \
        lines.c \
        matrix.c \
        mmath.c \
+       nvprogram.c \
+       nvfragparse.c \
+       nvvertexec.c \
+       nvvertparse.c \
        pixel.c \
        points.c \
        polygon.c \
@@ -70,9 +74,6 @@ CORE_SOURCES = \
        texstore.c \
        texutil.c \
        varray.c \
-       vpexec.c \
-       vpparse.c \
-       vpstate.c \
        vtxfmt.c \
        X86/x86.c \
        X86/common_x86.c \
@@ -107,6 +108,7 @@ CORE_SOURCES = \
        swrast/s_lines.c \
        swrast/s_logic.c \
        swrast/s_masking.c \
+       swrast/s_nvfragprog.c \
        swrast/s_pixeltex.c \
        swrast/s_points.c \
        swrast/s_readpix.c \
index 03532e6..a09a55c 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: ac_context.c,v 1.9 2002/10/29 20:28:58 brianp Exp $ */
+/* $Id: ac_context.c,v 1.10 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -91,7 +91,7 @@ static void _ac_fallbacks_init( GLcontext *ctx )
    cl->Enabled = 1;
    cl->Flags = CA_CLIENT_DATA; /* hack */
 
-   for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++) {
+   for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++) {
       cl = &ac->Fallback.TexCoord[i];
       cl->Size = 4;
       cl->Type = GL_FLOAT;
@@ -188,7 +188,7 @@ static void _ac_cache_init( GLcontext *ctx )
    cl->Enabled = 1;
    cl->Flags = 0;
 
-   for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
       cl = &ac->Cache.TexCoord[i];
       cl->Size = 4;
       cl->Type = GL_FLOAT;
@@ -254,7 +254,7 @@ static void _ac_raw_init( GLcontext *ctx )
    ac->IsCached.SecondaryColor = GL_FALSE;
    ac->IsCached.Vertex = GL_FALSE;
 
-   for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++) {
+   for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++) {
       ac->Raw.TexCoord[i] = ac->Fallback.TexCoord[i];
       ac->IsCached.TexCoord[i] = GL_FALSE;
    }
@@ -291,7 +291,7 @@ void _ac_DestroyContext( GLcontext *ctx )
    if (ac->Cache.Index.Ptr) FREE( ac->Cache.Index.Ptr );
    if (ac->Cache.FogCoord.Ptr) FREE( ac->Cache.FogCoord.Ptr );
 
-   for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
       if (ac->Cache.TexCoord[i].Ptr)
         FREE( ac->Cache.TexCoord[i].Ptr );
    }
index 6b3e1a4..fbc9074 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: ac_context.h,v 1.5 2002/10/29 20:28:58 brianp Exp $ */
+/* $Id: ac_context.h,v 1.6 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -45,7 +45,7 @@ struct ac_arrays {
    struct gl_client_array SecondaryColor;
    struct gl_client_array FogCoord;
    struct gl_client_array Index;
-   struct gl_client_array TexCoord[MAX_TEXTURE_UNITS];
+   struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS];
    struct gl_client_array EdgeFlag;
    struct gl_client_array Attrib[VERT_ATTRIB_MAX];  /* GL_NV_vertex_program */
 };
@@ -57,7 +57,7 @@ struct ac_array_pointers {
    struct gl_client_array *SecondaryColor;
    struct gl_client_array *FogCoord;
    struct gl_client_array *Index;
-   struct gl_client_array *TexCoord[MAX_TEXTURE_UNITS];
+   struct gl_client_array *TexCoord[MAX_TEXTURE_COORD_UNITS];
    struct gl_client_array *EdgeFlag;
    struct gl_client_array *Attrib[VERT_ATTRIB_MAX];  /* GL_NV_vertex_program */
 };
@@ -69,7 +69,7 @@ struct ac_array_flags {
    GLboolean SecondaryColor;
    GLboolean FogCoord;
    GLboolean Index;
-   GLboolean TexCoord[MAX_TEXTURE_UNITS];
+   GLboolean TexCoord[MAX_TEXTURE_COORD_UNITS];
    GLboolean EdgeFlag;
    GLboolean Attrib[VERT_ATTRIB_MAX];  /* GL_NV_vertex_program */
 };
index 1715e43..f8b92a4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ac_import.c,v 1.21 2002/10/29 20:28:58 brianp Exp $ */
+/* $Id: ac_import.c,v 1.22 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -214,7 +214,7 @@ static void reset_attrib( GLcontext *ctx, GLuint index )
       }
       else if (index >= VERT_ATTRIB_TEX0 && index <= VERT_ATTRIB_TEX7) {
          GLuint unit = index - VERT_ATTRIB_TEX0;
-         ASSERT(unit < MAX_TEXTURE_UNITS);
+         ASSERT(unit < MAX_TEXTURE_COORD_UNITS);
          ac->Raw.Attrib[index] = ctx->Array.TexCoord[unit];
       }
       else {
index 5301eea..9bbbec6 100644 (file)
@@ -1,7 +1,7 @@
 # Mesa 3-D graphics library\r
-# Version:  4.1\r
+# Version:  5.1\r
 # \r
-# Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.\r
+# Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.\r
 # \r
 # Permission is hereby granted, free of charge, to any person obtaining a\r
 # copy of this software and associated documentation files (the "Software"),\r
@@ -20,7 +20,7 @@
 # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
 \r
-# DOS/DJGPP core makefile v1.3 for Mesa 5.0\r
+# DOS/DJGPP core makefile v1.3 for Mesa 5.1\r
 #\r
 #  Copyright (C) 2002 - Borca Daniel\r
 #  Email : dborca@yahoo.com\r
@@ -119,6 +119,10 @@ CORE_SOURCES = \
        lines.c \\r
        matrix.c \\r
        mmath.c \\r
+       nvprogram.c \\r
+       nvfragparse.c \\r
+       nvvertexec.c \\r
+       nvvertparse.c \\r
        pixel.c \\r
        points.c \\r
        polygon.c \\r
@@ -132,10 +136,6 @@ CORE_SOURCES = \
        texstate.c \\r
        texstore.c \\r
        texutil.c \\r
-       varray.c \\r
-       vpexec.c \\r
-       vpparse.c \\r
-       vpstate.c \\r
        vtxfmt.c \\r
        math/m_debug_clip.c \\r
        math/m_debug_norm.c \\r
@@ -166,6 +166,7 @@ CORE_SOURCES = \
        swrast/s_lines.c \\r
        swrast/s_logic.c \\r
        swrast/s_masking.c \\r
+       swrast/s_nvfragprog.c \\r
        swrast/s_pixeltex.c \\r
        swrast/s_points.c \\r
        swrast/s_readpix.c \\r
index ce374d4..c1899e7 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.OSMesa16,v 1.10 2003/01/14 03:00:55 brianp Exp $
+# $Id: Makefile.OSMesa16,v 1.11 2003/01/14 04:55:45 brianp Exp $
 
 # Mesa 3-D graphics library
 # Version:  5.0
@@ -57,6 +57,10 @@ CORE_SOURCES = \
        lines.c \
        matrix.c \
        mmath.c \
+       nvprogram.c \
+       nvfragparse.c \
+       nvvertexec.c \
+       nvvertparse.c \
        pixel.c \
        points.c \
        polygon.c \
@@ -71,9 +75,6 @@ CORE_SOURCES = \
        texstore.c \
        texutil.c \
        varray.c \
-       vpexec.c \
-       vpparse.c \
-       vpstate.c \
        vtxfmt.c \
        X86/x86.c \
        X86/common_x86.c \
@@ -108,6 +109,7 @@ CORE_SOURCES = \
        swrast/s_lines.c \
        swrast/s_logic.c \
        swrast/s_masking.c \
+       swrast/s_nvfragprog.c \
        swrast/s_pixeltex.c \
        swrast/s_points.c \
        swrast/s_readpix.c \
index 940135f..9ccaafc 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.X11,v 1.72 2002/10/29 23:09:40 brianp Exp $
+# $Id: Makefile.X11,v 1.73 2003/01/14 04:55:45 brianp Exp $
 
 # Mesa 3-D graphics library
 # Version:  5.0
@@ -56,6 +56,10 @@ CORE_SOURCES = \
        lines.c \
        matrix.c \
        mmath.c \
+       nvprogram.c \
+       nvfragparse.c \
+       nvvertexec.c \
+       nvvertparse.c \
        pixel.c \
        points.c \
        polygon.c \
@@ -70,9 +74,6 @@ CORE_SOURCES = \
        texstore.c \
        texutil.c \
        varray.c \
-       vpexec.c \
-       vpparse.c \
-       vpstate.c \
        vtxfmt.c \
        X86/x86.c \
        X86/common_x86.c \
@@ -107,6 +108,7 @@ CORE_SOURCES = \
        swrast/s_lines.c \
        swrast/s_logic.c \
        swrast/s_masking.c \
+       swrast/s_nvfragprog.c \
        swrast/s_pixeltex.c \
        swrast/s_points.c \
        swrast/s_readpix.c \
index 24c41d2..ebb59e7 100644 (file)
@@ -12,31 +12,6 @@ TOP = ..
 SUBDIRS = osmesa.dir
 
 CORE_SRCS = \
-       tnl\t_array_api.c \
-       tnl\t_array_import.c \
-       tnl\t_context.c \
-       tnl\t_eval_api.c \
-       tnl\t_imm_alloc.c \
-       tnl\t_imm_api.c \
-       tnl\t_imm_debug.c \
-       tnl\t_imm_dlist.c \
-       tnl\t_imm_elt.c \
-       tnl\t_imm_eval.c \
-       tnl\t_imm_exec.c \
-       tnl\t_imm_fixup.c \
-       tnl\t_pipeline.c \
-       tnl\t_vb_fog.c \
-       tnl\t_vb_light.c \
-       tnl\t_vb_normals.c \
-       tnl\t_vb_points.c \
-       tnl\t_vb_program.c \
-       tnl\t_vb_render.c \
-       tnl\t_vb_texgen.c \
-       tnl\t_vb_texmat.c \
-       tnl\t_vb_vertex.c \
-       swrast_setup\ss_context.c \
-       swrast_setup\ss_triangle.c \
-       swrast_setup\ss_vb.c \
        api_loopback.c \
        api_noop.c \
        api_validate.c \
@@ -71,6 +46,10 @@ CORE_SRCS = \
        lines.c \
        matrix.c \
        mmath.c \
+       nvprogram.c \
+       nvfragparse.c \
+       nvvertexec.c \
+       nvvertparse.c \
        pixel.c \
        points.c \
        polygon.c \
@@ -85,9 +64,6 @@ CORE_SRCS = \
        texstore.c \
        texutil.c \
        varray.c \
-       vpexec.c \
-       vpparse.c \
-       vpstate.c \
        vtxfmt.c \
 #      X86\x86.c \
 #      X86\common_x86.c \
@@ -121,6 +97,7 @@ CORE_SRCS = \
        swrast\s_lines.c \
        swrast\s_logic.c \
        swrast\s_masking.c \
+       swrast\s_nvfragprog.c \
        swrast\s_pixeltex.c \
        swrast\s_points.c \
        swrast\s_readpix.c \
@@ -129,7 +106,32 @@ CORE_SRCS = \
        swrast\s_texstore.c \
        swrast\s_texture.c \
        swrast\s_triangle.c \
-       swrast\s_zoom.c
+       swrast\s_zoom.c \
+       swrast_setup\ss_context.c \
+       swrast_setup\ss_triangle.c \
+       swrast_setup\ss_vb.c \
+       tnl\t_array_api.c \
+       tnl\t_array_import.c \
+       tnl\t_context.c \
+       tnl\t_eval_api.c \
+       tnl\t_imm_alloc.c \
+       tnl\t_imm_api.c \
+       tnl\t_imm_debug.c \
+       tnl\t_imm_dlist.c \
+       tnl\t_imm_elt.c \
+       tnl\t_imm_eval.c \
+       tnl\t_imm_exec.c \
+       tnl\t_imm_fixup.c \
+       tnl\t_pipeline.c \
+       tnl\t_vb_fog.c \
+       tnl\t_vb_light.c \
+       tnl\t_vb_normals.c \
+       tnl\t_vb_points.c \
+       tnl\t_vb_program.c \
+       tnl\t_vb_render.c \
+       tnl\t_vb_texgen.c \
+       tnl\t_vb_texmat.c \
+       tnl\t_vb_vertex.c
 
 DRIVER_SRCS = \
        Trace\tr_context.c \
index 154f6e5..8d64b1e 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: api_arrayelt.c,v 1.11 2002/10/29 20:28:36 brianp Exp $ */
+/* $Id: api_arrayelt.c,v 1.12 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -53,7 +53,7 @@ typedef struct {
 } AEarray;
 
 typedef struct {
-   AEtexarray texarrays[MAX_TEXTURE_UNITS+1];
+   AEtexarray texarrays[MAX_TEXTURE_COORD_UNITS + 1];
    AEarray arrays[32];
    GLuint NewState;
 } AEcontext;
index a443227..6a42262 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: api_noop.c,v 1.10 2002/04/09 16:56:50 keithw Exp $ */
+/* $Id: api_noop.c,v 1.11 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -239,7 +239,7 @@ void _mesa_noop_MultiTexCoord1fARB( GLenum target, GLfloat a )
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], a);
@@ -256,7 +256,7 @@ void _mesa_noop_MultiTexCoord1fvARB( GLenum target, const GLfloat *v )
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], v[0]);
@@ -273,7 +273,7 @@ void _mesa_noop_MultiTexCoord2fARB( GLenum target, GLfloat a, GLfloat b )
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], a);
@@ -290,7 +290,7 @@ void _mesa_noop_MultiTexCoord2fvARB( GLenum target, const GLfloat *v )
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], v[0]);
@@ -307,7 +307,7 @@ void _mesa_noop_MultiTexCoord3fARB( GLenum target, GLfloat a, GLfloat b, GLfloat
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], a);
@@ -324,7 +324,7 @@ void _mesa_noop_MultiTexCoord3fvARB( GLenum target, const GLfloat *v )
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], v[0]);
@@ -342,7 +342,7 @@ void _mesa_noop_MultiTexCoord4fARB( GLenum target, GLfloat a, GLfloat b,
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], a);
@@ -359,7 +359,7 @@ void _mesa_noop_MultiTexCoord4fvARB( GLenum target, const GLfloat *v )
 
    /* unit is unsigned -- cannot be less than zero.
     */
-   if (unit < MAX_TEXTURE_UNITS)
+   if (unit < MAX_TEXTURE_COORD_UNITS)
    {
       GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit];
       COPY_FLOAT(dest[0], v[0]);
index 985176f..b9e58cd 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: config.h,v 1.42 2002/10/16 17:57:51 brianp Exp $ */
+/* $Id: config.h,v 1.43 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
- * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
+ * 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"),
 /* Number of texture units - GL_ARB_multitexture */
 #define MAX_TEXTURE_UNITS 8
 
+/* New: separate numbers of texture coordinates and texture image units.
+ * These values will eventually replace most instances of MAX_TEXTURE_UNITS.
+ * We should always have MAX_TEXTURE_COORD_UNITS <= MAX_TEXTURE_IMAGE_UNITS.
+ * And, GL_MAX_TEXTURE_UNITS <= MAX_TEXTURE_COORD_UNITS.
+ */
+#define MAX_TEXTURE_COORD_UNITS 8
+#define MAX_TEXTURE_IMAGE_UNITS 8
+
 /* Maximum viewport/image size: */
 #define MAX_WIDTH 2048
 #define MAX_HEIGHT 2048
 /* GL_EXT_texture_lod_bias */
 #define MAX_TEXTURE_LOD_BIAS 4.0
 
+/* GL_NV_vertex_program */
+#define MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS 128
+#define MAX_NV_VERTEX_PROGRAM_TEMPS         12
+#define MAX_NV_VERTEX_PROGRAM_PARAMS        96
+#define MAX_NV_VERTEX_PROGRAM_INPUTS        16
+#define MAX_NV_VERTEX_PROGRAM_OUTPUTS       15
+
+/* GL_NV_fragment_program */
+#define MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS 128
+#define MAX_NV_FRAGMENT_PROGRAM_TEMPS         96
+#define MAX_NV_FRAGMENT_PROGRAM_PARAMS        64
+#define MAX_NV_FRAGMENT_PROGRAM_INPUTS        12
+#define MAX_NV_FRAGMENT_PROGRAM_OUTPUTS        7
+#define MAX_NV_FRAGMENT_PROGRAM_WRITE_ONLYS    2
+
 
 
 /*
  */
 #define FEATURE_NV_vertex_program 1
 
+#define FEATURE_NV_fragment_program 1
+
 
 #endif /* CONFIG_H */
index 2784fa8..2d43652 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: context.c,v 1.190 2002/12/12 13:03:15 keithw Exp $ */
+/* $Id: context.c,v 1.191 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
 #include "mtypes.h"
 #include "varray.h"
 #if FEATURE_NV_vertex_program
-#include "vpstate.h"
+#include "nvprogram.h"
+#include "nvvertprog.h"
+#endif
+#if FEATURE_NV_fragment_program
+#include "nvfragprog.h"
 #endif
 #include "vtxfmt.h"
 #include "math/m_translate.h"
@@ -641,7 +645,7 @@ alloc_shared_state( void )
    ss->DisplayList = _mesa_NewHashTable();
    ss->TexObjects = _mesa_NewHashTable();
 #if FEATURE_NV_vertex_program
-   ss->VertexPrograms = _mesa_NewHashTable();
+   ss->Programs = _mesa_NewHashTable();
 #endif
 
    /* Default Texture objects */
@@ -676,7 +680,7 @@ alloc_shared_state( void )
 
    if (!ss->DisplayList || !ss->TexObjects
 #if FEATURE_NV_vertex_program
-       || !ss->VertexPrograms
+       || !ss->Programs
 #endif
        || outOfMemory) {
       /* Ran out of memory at some point.  Free everything and return NULL */
@@ -684,8 +688,8 @@ alloc_shared_state( void )
          _mesa_DeleteHashTable(ss->DisplayList);
       if (ss->TexObjects)
          _mesa_DeleteHashTable(ss->TexObjects);
-      if (ss->VertexPrograms)
-         _mesa_DeleteHashTable(ss->VertexPrograms);
+      if (ss->Programs)
+         _mesa_DeleteHashTable(ss->Programs);
       if (ss->Default1D)
          _mesa_free_texture_object(ss, ss->Default1D);
       if (ss->Default2D)
@@ -735,7 +739,7 @@ free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
 #if FEATURE_NV_vertex_program
    /* Free vertex programs */
    while (1) {
-      GLuint prog = _mesa_HashFirstEntry(ss->VertexPrograms);
+      GLuint prog = _mesa_HashFirstEntry(ss->Programs);
       if (prog) {
          _mesa_delete_program(ctx, prog);
       }
@@ -743,7 +747,7 @@ free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
          break;
       }
    }
-   _mesa_DeleteHashTable(ss->VertexPrograms);
+   _mesa_DeleteHashTable(ss->Programs);
 #endif
 
    _glthread_DESTROY_MUTEX(ss->Mutex);
@@ -918,6 +922,8 @@ init_attrib_groups( GLcontext *ctx )
    ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
    ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
    ctx->Const.MaxTextureUnits = MAX_TEXTURE_UNITS;
+   ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
+   ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
    ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
    ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
    ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
@@ -946,7 +952,7 @@ init_attrib_groups( GLcontext *ctx )
                      _NEW_PROJECTION);
    init_matrix_stack(&ctx->ColorMatrixStack, MAX_COLOR_STACK_DEPTH,
                      _NEW_COLOR_MATRIX);
-   for (i = 0; i < MAX_TEXTURE_UNITS; i++)
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
       init_matrix_stack(&ctx->TextureMatrixStack[i], MAX_TEXTURE_STACK_DEPTH,
                         _NEW_TEXTURE_MATRIX);
    for (i = 0; i < MAX_PROGRAM_MATRICES; i++)
@@ -990,7 +996,7 @@ init_attrib_groups( GLcontext *ctx )
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 0.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_FOG], 0.0, 0.0, 0.0, 0.0 );
-   for (i = 0; i < MAX_TEXTURE_UNITS; i++)
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
       ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_TEX0 + i], 0.0, 0.0, 0.0, 1.0 );
    ctx->Current.Index = 1;
    ctx->Current.EdgeFlag = GL_TRUE;
@@ -999,7 +1005,7 @@ init_attrib_groups( GLcontext *ctx )
    ctx->Current.RasterDistance = 0.0;
    ASSIGN_4V( ctx->Current.RasterColor, 1.0, 1.0, 1.0, 1.0 );
    ctx->Current.RasterIndex = 1;
-   for (i=0; i<MAX_TEXTURE_UNITS; i++)
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
       ASSIGN_4V( ctx->Current.RasterTexCoords[i], 0.0, 0.0, 0.0, 1.0 );
    ctx->Current.RasterPosValid = GL_TRUE;
 
@@ -1261,7 +1267,7 @@ init_attrib_groups( GLcontext *ctx )
    ctx->Point.Threshold = 1.0;
    ctx->Point.PointSprite = GL_FALSE; /* GL_NV_point_sprite */
    ctx->Point.SpriteRMode = GL_ZERO; /* GL_NV_point_sprite */
-   for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
       ctx->Point.CoordReplace[i] = GL_FALSE; /* GL_NV_point_sprite */
    }
 
@@ -1388,7 +1394,7 @@ init_attrib_groups( GLcontext *ctx )
    ctx->Array.Index.Ptr = NULL;
    ctx->Array.Index.Enabled = GL_FALSE;
    ctx->Array.Index.Flags = CA_CLIENT_DATA;
-   for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
       ctx->Array.TexCoord[i].Size = 4;
       ctx->Array.TexCoord[i].Type = GL_FLOAT;
       ctx->Array.TexCoord[i].Stride = 0;
@@ -1457,17 +1463,23 @@ init_attrib_groups( GLcontext *ctx )
    _mesa_init_colortable(&ctx->PostColorMatrixColorTable);
    _mesa_init_colortable(&ctx->ProxyPostColorMatrixColorTable);
 
-   /* GL_NV_vertex_program */
+   /* Vertex/fragment programs */
+   ctx->Program.ErrorPos = -1;
+   ctx->Program.ErrorString = _mesa_strdup("");
+#if FEATURE_NV_vertex_program
    ctx->VertexProgram.Enabled = GL_FALSE;
    ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
    ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
-   ctx->VertexProgram.CurrentID = 0;
-   ctx->VertexProgram.ErrorPos = -1;
    ctx->VertexProgram.Current = NULL;
    for (i = 0; i < VP_NUM_PROG_REGS / 4; i++) {
       ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
       ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
    }
+#endif
+#if FEATURE_NV_fragment_program
+   ctx->FragmentProgram.Enabled = GL_FALSE;
+   ctx->FragmentProgram.Current = NULL;
+#endif
 
    /* Miscellaneous */
    ctx->NewState = _NEW_ALL;
@@ -1684,11 +1696,11 @@ _mesa_initialize_context( GLcontext *ctx,
    _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
 
    /* Effectively bind the default textures to all texture units */
-   ctx->Shared->Default1D->RefCount += MAX_TEXTURE_UNITS;
-   ctx->Shared->Default2D->RefCount += MAX_TEXTURE_UNITS;
-   ctx->Shared->Default3D->RefCount += MAX_TEXTURE_UNITS;
-   ctx->Shared->DefaultCubeMap->RefCount += MAX_TEXTURE_UNITS;
-   ctx->Shared->DefaultRect->RefCount += MAX_TEXTURE_UNITS;
+   ctx->Shared->Default1D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
+   ctx->Shared->Default2D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
+   ctx->Shared->Default3D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
+   ctx->Shared->DefaultCubeMap->RefCount += MAX_TEXTURE_IMAGE_UNITS;
+   ctx->Shared->DefaultRect->RefCount += MAX_TEXTURE_IMAGE_UNITS;
 
    init_attrib_groups( ctx );
 
@@ -1930,7 +1942,7 @@ _mesa_free_context_data( GLcontext *ctx )
    free_matrix_stack(&ctx->ModelviewMatrixStack);
    free_matrix_stack(&ctx->ProjectionMatrixStack);
    free_matrix_stack(&ctx->ColorMatrixStack);
-   for (i = 0; i < MAX_TEXTURE_UNITS; i++)
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
       free_matrix_stack(&ctx->TextureMatrixStack[i]);
    for (i = 0; i < MAX_PROGRAM_MATRICES; i++)
       free_matrix_stack(&ctx->ProgramMatrixStack[i]);
@@ -1940,9 +1952,16 @@ _mesa_free_context_data( GLcontext *ctx )
 
 #if FEATURE_NV_vertex_program
    if (ctx->VertexProgram.Current) {
-      ctx->VertexProgram.Current->RefCount--;
-      if (ctx->VertexProgram.Current->RefCount <= 0)
-         _mesa_delete_program(ctx, ctx->VertexProgram.CurrentID);
+      ctx->VertexProgram.Current->Base.RefCount--;
+      if (ctx->VertexProgram.Current->Base.RefCount <= 0)
+         _mesa_delete_program(ctx, ctx->VertexProgram.Current->Base.Id);
+   }
+#endif
+#if FEATURE_NV_fragment_program
+   if (ctx->FragmentProgram.Current) {
+      ctx->FragmentProgram.Current->Base.RefCount--;
+      if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
+         _mesa_delete_program(ctx, ctx->FragmentProgram.Current->Base.Id);
    }
 #endif
 
index 215ace4..27f31ca 100644 (file)
@@ -49,6 +49,10 @@ CORE_SOURCES =accum.c \
        lines.c \
        matrix.c \
        mmath.c \
+       nvprogram.c \
+       nvfragparse.c \
+       nvvertexec.c \
+       nvvertparse.c \
        pixel.c \
        points.c \
        polygon.c \
@@ -64,8 +68,6 @@ CORE_SOURCES =accum.c \
        texutil.c \
        varray.c \
        vtxfmt.c \
-       vpstate.c \
-       vpexec.c \
        vsnprintf.c \
        vtparse.c \
        [.x86]x86.c
@@ -101,6 +103,7 @@ RASTER_SOURCES = [.swrast]s_aatriangle.c \
 [.swrast]s_lines.c \
 [.swrast]s_logic.c \
 [.swrast]s_masking.c \
+[.swrast]s_nvfragprog.c \
 [.swrast]s_pixeltex.c \
 [.swrast]s_points.c \
 [.swrast]s_readpix.c \
@@ -189,6 +192,10 @@ lines.obj,\
 matrix.obj
 
 OBJECTS3=mmath.obj,\
+nvprogram.obj \
+nvfragparse.obj \
+nvvertexec.obj \
+nvvertparse.obj \
 pixel.obj,\
 points.obj,\
 polygon.obj,\
@@ -204,9 +211,6 @@ texstore.obj,\
 texutil.obj,\
 varray.obj,\
 vtxfmt.obj,\
-vpstate.obj,\
-vpexec.obj,\
-vpparse.obj,\
 vsnprintf.obj
 
 OBJECTS4=[.x]glxapi.obj,[.x]fakeglx.obj,[.x]xfonts.obj,\
@@ -241,6 +245,7 @@ OBJECTS8=[.swrast]s_drawpix.obj,\
 [.swrast]s_lines.obj,\
 [.swrast]s_logic.obj,\
 [.swrast]s_masking.obj,\
+[.swrast]s_nvfragprog.obj,\
 [.swrast]s_pixeltex.obj,\
 [.swrast]s_points.obj
 
@@ -438,6 +443,8 @@ imports.obj : imports.c
        $(CC) $(CFLAGS) /obj=[.swrast]s_logic.obj [.swrast]s_logic.c
 [.swrast]s_masking.obj : [.swrast]s_masking.c
        $(CC) $(CFLAGS) /obj=[.swrast]s_masking.obj [.swrast]s_masking.c
+[.swrast]s_nvfragprog.obj : [.swrast]s_nvfragprog.c
+       $(CC) $(CFLAGS) /obj=[.swrast]s_nvfragprog.obj [.swrast]s_nvfragprog.c
 [.swrast]s_pixeltex.obj : [.swrast]s_pixeltex.c
        $(CC) $(CFLAGS) /obj=[.swrast]s_pixeltex.obj [.swrast]s_pixeltex.c
 [.swrast]s_points.obj : [.swrast]s_points.c
index 2391d8d..2fcfb4a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dlist.c,v 1.100 2002/11/06 15:16:23 brianp Exp $ */
+/* $Id: dlist.c,v 1.101 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -62,7 +62,7 @@
 #include "mtypes.h"
 #include "varray.h"
 #if FEATURE_NV_vertex_program
-#include "vpstate.h"
+#include "nvprogram.h"
 #endif
 
 #include "math/m_matrix.h"
index 744668f..84d0311 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: enable.c,v 1.71 2002/10/24 23:57:20 brianp Exp $ */
+/* $Id: enable.c,v 1.72 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -873,6 +873,16 @@ void _mesa_set_enable( GLcontext *ctx, GLenum cap, GLboolean state )
          break;
 #endif /* FEATURE_NV_vertex_program */
 
+#if FEATURE_NV_fragment_program
+      case GL_FRAGMENT_PROGRAM_NV:
+         CHECK_EXTENSION(NV_fragment_program, cap);
+         if (ctx->FragmentProgram.Enabled == state)
+            return;
+         FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+         ctx->FragmentProgram.Enabled = state;
+         break;
+#endif /* FEATURE_NV_fragment_program */
+
       /* GL_NV_texture_rectangle */
       case GL_TEXTURE_RECTANGLE_NV:
          CHECK_EXTENSION(NV_texture_rectangle, cap);
@@ -1265,6 +1275,12 @@ _mesa_IsEnabled( GLenum cap )
          }
 #endif /* FEATURE_NV_vertex_program */
 
+#if FEATURE_NV_fragment_program
+      case GL_FRAGMENT_PROGRAM_NV:
+         CHECK_EXTENSION(NV_fragment_program);
+         return ctx->FragmentProgram.Enabled;
+#endif /* FEATURE_NV_fragment_program */
+
       /* GL_NV_texture_rectangle */
       case GL_TEXTURE_RECTANGLE_NV:
          CHECK_EXTENSION(NV_texture_rectangle);
index f387fb2..8362164 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: extensions.c,v 1.85 2002/10/25 21:06:27 brianp Exp $ */
+/* $Id: extensions.c,v 1.86 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -116,6 +116,7 @@ static struct {
    { OFF, "GL_NV_point_sprite",                F(NV_point_sprite) },
    { OFF, "GL_NV_texture_rectangle",           F(NV_texture_rectangle) },
    { ON,  "GL_NV_texgen_reflection",           F(NV_texgen_reflection) },
+   { OFF, "GL_NV_fragment_program",            F(NV_fragment_program) },
    { OFF, "GL_NV_vertex_program",              F(NV_vertex_program) },
    { OFF, "GL_NV_vertex_program1_1",           F(NV_vertex_program1_1) },
    { OFF, "GL_SGI_color_matrix",               F(SGI_color_matrix) },
@@ -191,6 +192,9 @@ _mesa_enable_sw_extensions(GLcontext *ctx)
       "GL_NV_vertex_program",
       "GL_NV_vertex_program1_1",
 #endif
+#if FEATURE_NV_fragment_program
+      "GL_NV_fragment_program",
+#endif
       "GL_SGI_color_matrix",
       "GL_SGI_color_table",
       "GL_SGIS_generate_mipmap",
index 074972d..851f54f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: get.c,v 1.100 2002/11/14 16:14:55 brianp Exp $ */
+/* $Id: get.c,v 1.101 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -1375,11 +1375,15 @@ _mesa_GetBooleanv( GLenum pname, GLboolean *params )
          break;
       case GL_VERTEX_PROGRAM_BINDING_NV:
          CHECK_EXTENSION_B(NV_vertex_program, pname);
-         *params = (ctx->VertexProgram.CurrentID != 0) ? GL_TRUE : GL_FALSE;
+         if (ctx->VertexProgram.Current &&
+             ctx->VertexProgram.Current->Base.Id != 0)
+            *params = GL_TRUE;
+         else
+            *params = GL_FALSE;
          break;
       case GL_PROGRAM_ERROR_POSITION_NV:
          CHECK_EXTENSION_B(NV_vertex_program, pname);
-         *params = (ctx->VertexProgram.ErrorPos != 0) ? GL_TRUE : GL_FALSE;
+         *params = (ctx->Program.ErrorPos != 0) ? GL_TRUE : GL_FALSE;
          break;
       case GL_VERTEX_ATTRIB_ARRAY0_NV:
       case GL_VERTEX_ATTRIB_ARRAY1_NV:
@@ -1449,6 +1453,29 @@ _mesa_GetBooleanv( GLenum pname, GLboolean *params )
          break;
 #endif /* FEATURE_NV_vertex_program */
 
+#if FEATURE_NV_fragment_program
+      case GL_MAX_TEXTURE_COORDS_NV:
+         CHECK_EXTENSION_B(NV_fragment_program, pname);
+         *params = INT_TO_BOOL(ctx->Const.MaxTextureCoordUnits);
+         break;
+      case GL_MAX_TEXTURE_IMAGE_UNITS_NV:
+         CHECK_EXTENSION_B(NV_fragment_program, pname);
+         *params = INT_TO_BOOL(ctx->Const.MaxTextureImageUnits);
+         break;
+      case GL_FRAGMENT_PROGRAM_BINDING_NV:
+         CHECK_EXTENSION_B(NV_fragment_program, pname);
+         if (ctx->VertexProgram.Current &&
+             ctx->VertexProgram.Current->Base.Id != 0)
+            *params = GL_TRUE;
+         else
+            *params = GL_FALSE;
+         break;
+      case GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV:
+         CHECK_EXTENSION_B(NV_fragment_program, pname);
+         *params = MAX_NV_FRAGMENT_PROGRAM_PARAMS ? GL_TRUE : GL_FALSE;
+         break;
+#endif /* FEATURE_NV_fragment_program */
+
       /* GL_NV_texture_rectangle */
       case GL_TEXTURE_RECTANGLE_NV:
          CHECK_EXTENSION_B(NV_texture_rectangle, pname);
@@ -2740,11 +2767,14 @@ _mesa_GetDoublev( GLenum pname, GLdouble *params )
          break;
       case GL_VERTEX_PROGRAM_BINDING_NV:
          CHECK_EXTENSION_D(NV_vertex_program, pname);
-         *params = (GLdouble) ctx->VertexProgram.CurrentID;
+         if (ctx->VertexProgram.Current)
+            *params = (GLdouble) ctx->VertexProgram.Current->Base.Id;
+         else
+            *params = 0.0;
          break;
       case GL_PROGRAM_ERROR_POSITION_NV:
          CHECK_EXTENSION_D(NV_vertex_program, pname);
-         *params = (GLdouble) ctx->VertexProgram.ErrorPos;
+         *params = (GLdouble) ctx->Program.ErrorPos;
          break;
       case GL_VERTEX_ATTRIB_ARRAY0_NV:
       case GL_VERTEX_ATTRIB_ARRAY1_NV:
@@ -2814,6 +2844,28 @@ _mesa_GetDoublev( GLenum pname, GLdouble *params )
          break;
 #endif /* FEATURE_NV_vertex_program */
 
+#if FEATURE_NV_fragment_program
+      case GL_MAX_TEXTURE_COORDS_NV:
+         CHECK_EXTENSION_B(NV_fragment_program, pname);
+         *params = (GLdouble) ctx->Const.MaxTextureCoordUnits;
+         break;
+      case GL_MAX_TEXTURE_IMAGE_UNITS_NV:
+         CHECK_EXTENSION_B(NV_fragment_program, pname);
+         *params = (GLdouble) ctx->Const.MaxTextureImageUnits;
+         break;
+      case GL_FRAGMENT_PROGRAM_BINDING_NV:
+         CHECK_EXTENSION_D(NV_fragment_program, pname);
+         if (ctx->FragmentProgram.Current)
+            *params = (GLdouble) ctx->FragmentProgram.Current->Base.Id;
+         else
+            *params = 0.0;
+         break;
+      case GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV:
+         CHECK_EXTENSION_D(NV_fragment_program, pname);
+         *params = (GLdouble) MAX_NV_FRAGMENT_PROGRAM_PARAMS;
+         break;
+#endif /* FEATURE_NV_fragment_program */
+
       /* GL_NV_texture_rectangle */
       case GL_TEXTURE_RECTANGLE_NV:
          CHECK_EXTENSION_D(NV_texture_rectangle, pname);
@@ -4036,11 +4088,11 @@ _mesa_GetFloatv( GLenum pname, GLfloat *params )
 
       /* GL_NV_point_sprite */
       case GL_POINT_SPRITE_NV:
-         CHECK_EXTENSION_B(NV_point_sprite, pname);
+         CHECK_EXTENSION_F(NV_point_sprite, pname);
          *params = (GLfloat) ctx->Point.PointSprite;
          break;
       case GL_POINT_SPRITE_R_MODE_NV:
-         CHECK_EXTENSION_B(NV_point_sprite, pname);
+         CHECK_EXTENSION_F(NV_point_sprite, pname);
          *params = (GLfloat) ctx->Point.SpriteRMode;
          break;
 
@@ -4081,11 +4133,14 @@ _mesa_GetFloatv( GLenum pname, GLfloat *params )
          break;
       case GL_VERTEX_PROGRAM_BINDING_NV:
          CHECK_EXTENSION_F(NV_vertex_program, pname);
-         *params = (GLfloat) ctx->VertexProgram.CurrentID;
+         if (ctx->VertexProgram.Current)
+            *params = (GLfloat) ctx->VertexProgram.Current->Base.Id;
+         else
+            *params = 0.0;
          break;
       case GL_PROGRAM_ERROR_POSITION_NV:
          CHECK_EXTENSION_F(NV_vertex_program, pname);
-         *params = (GLfloat) ctx->VertexProgram.ErrorPos;
+         *params = (GLfloat) ctx->Program.ErrorPos;
          break;
       case GL_VERTEX_ATTRIB_ARRAY0_NV:
       case GL_VERTEX_ATTRIB_ARRAY1_NV:
@@ -4125,7 +4180,7 @@ _mesa_GetFloatv( GLenum pname, GLfloat *params )
       case GL_MAP1_VERTEX_ATTRIB13_4_NV:
       case GL_MAP1_VERTEX_ATTRIB14_4_NV:
       case GL_MAP1_VERTEX_ATTRIB15_4_NV:
-         CHECK_EXTENSION_B(NV_vertex_program, pname);
+         CHECK_EXTENSION_F(NV_vertex_program, pname);
          {
             GLuint n = (GLuint) pname - GL_MAP1_VERTEX_ATTRIB0_4_NV;
             *params = (GLfloat) ctx->Eval.Map1Attrib[n];
@@ -4147,12 +4202,35 @@ _mesa_GetFloatv( GLenum pname, GLfloat *params )
       case GL_MAP2_VERTEX_ATTRIB13_4_NV:
       case GL_MAP2_VERTEX_ATTRIB14_4_NV:
       case GL_MAP2_VERTEX_ATTRIB15_4_NV:
-         CHECK_EXTENSION_B(NV_vertex_program, pname);
+         CHECK_EXTENSION_F(NV_vertex_program, pname);
          {
             GLuint n = (GLuint) pname - GL_MAP2_VERTEX_ATTRIB0_4_NV;
             *params = (GLfloat) ctx->Eval.Map2Attrib[n];
          }
          break;
+#endif /* FEATURE_NV_vertex_program */
+
+#if FEATURE_NV_fragment_program
+      case GL_MAX_TEXTURE_COORDS_NV:
+         CHECK_EXTENSION_F(NV_fragment_program, pname);
+         *params = (GLfloat) ctx->Const.MaxTextureCoordUnits;
+         break;
+      case GL_MAX_TEXTURE_IMAGE_UNITS_NV:
+         CHECK_EXTENSION_F(NV_fragment_program, pname);
+         *params = (GLfloat) ctx->Const.MaxTextureImageUnits;
+         break;
+      case GL_FRAGMENT_PROGRAM_BINDING_NV:
+         CHECK_EXTENSION_F(NV_fragment_program, pname);
+         if (ctx->FragmentProgram.Current)
+            *params = (GLfloat) ctx->FragmentProgram.Current->Base.Id;
+         else
+            *params = 0.0;
+         break;
+      case GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV:
+         CHECK_EXTENSION_F(NV_fragment_program, pname);
+         *params = (GLfloat) MAX_NV_FRAGMENT_PROGRAM_PARAMS;
+         break;
+#endif /* FEATURE_NV_fragment_program */
 
       /* GL_NV_texture_rectangle */
       case GL_TEXTURE_RECTANGLE_NV:
@@ -4167,7 +4245,6 @@ _mesa_GetFloatv( GLenum pname, GLfloat *params )
          CHECK_EXTENSION_F(NV_texture_rectangle, pname);
          *params = (GLfloat) ctx->Const.MaxTextureRectSize;
          break;
-#endif /* FEATURE_NV_vertex_program */
 
       /* GL_EXT_stencil_two_side */
       case GL_STENCIL_TEST_TWO_SIDE_EXT:
@@ -5416,11 +5493,11 @@ _mesa_GetIntegerv( GLenum pname, GLint *params )
 
       /* GL_NV_point_sprite */
       case GL_POINT_SPRITE_NV:
-         CHECK_EXTENSION_B(NV_point_sprite, pname);
+         CHECK_EXTENSION_I(NV_point_sprite, pname);
          *params = (GLint) ctx->Point.PointSprite;
          break;
       case GL_POINT_SPRITE_R_MODE_NV:
-         CHECK_EXTENSION_B(NV_point_sprite, pname);
+         CHECK_EXTENSION_I(NV_point_sprite, pname);
          *params = (GLint) ctx->Point.SpriteRMode;
          break;
 
@@ -5461,11 +5538,14 @@ _mesa_GetIntegerv( GLenum pname, GLint *params )
          break;
       case GL_VERTEX_PROGRAM_BINDING_NV:
          CHECK_EXTENSION_I(NV_vertex_program, pname);
-         *params = (GLint) ctx->VertexProgram.CurrentID;
+         if (ctx->VertexProgram.Current)
+            *params = (GLint) ctx->VertexProgram.Current->Base.Id;
+         else
+            *params = 0;
          break;
       case GL_PROGRAM_ERROR_POSITION_NV:
          CHECK_EXTENSION_I(NV_vertex_program, pname);
-         *params = (GLint) ctx->VertexProgram.ErrorPos;
+         *params = (GLint) ctx->Program.ErrorPos;
          break;
       case GL_VERTEX_ATTRIB_ARRAY0_NV:
       case GL_VERTEX_ATTRIB_ARRAY1_NV:
@@ -5505,7 +5585,7 @@ _mesa_GetIntegerv( GLenum pname, GLint *params )
       case GL_MAP1_VERTEX_ATTRIB13_4_NV:
       case GL_MAP1_VERTEX_ATTRIB14_4_NV:
       case GL_MAP1_VERTEX_ATTRIB15_4_NV:
-         CHECK_EXTENSION_B(NV_vertex_program, pname);
+         CHECK_EXTENSION_I(NV_vertex_program, pname);
          {
             GLuint n = (GLuint) pname - GL_MAP1_VERTEX_ATTRIB0_4_NV;
             *params = (GLint) ctx->Eval.Map1Attrib[n];
@@ -5527,12 +5607,35 @@ _mesa_GetIntegerv( GLenum pname, GLint *params )
       case GL_MAP2_VERTEX_ATTRIB13_4_NV:
       case GL_MAP2_VERTEX_ATTRIB14_4_NV:
       case GL_MAP2_VERTEX_ATTRIB15_4_NV:
-         CHECK_EXTENSION_B(NV_vertex_program, pname);
+         CHECK_EXTENSION_I(NV_vertex_program, pname);
          {
             GLuint n = (GLuint) pname - GL_MAP2_VERTEX_ATTRIB0_4_NV;
             *params = (GLint) ctx->Eval.Map2Attrib[n];
          }
          break;
+#endif /* FEATURE_NV_vertex_program */
+
+#if FEATURE_NV_fragment_program
+      case GL_MAX_TEXTURE_COORDS_NV:
+         CHECK_EXTENSION_I(NV_fragment_program, pname);
+         *params = (GLint) ctx->Const.MaxTextureCoordUnits;
+         break;
+      case GL_MAX_TEXTURE_IMAGE_UNITS_NV:
+         CHECK_EXTENSION_I(NV_fragment_program, pname);
+         *params = (GLint) ctx->Const.MaxTextureImageUnits;
+         break;
+      case GL_FRAGMENT_PROGRAM_BINDING_NV:
+         CHECK_EXTENSION_I(NV_fragment_program, pname);
+         if (ctx->FragmentProgram.Current)
+            *params = (GLint) ctx->FragmentProgram.Current->Base.Id;
+         else
+            *params = 0;
+         break;
+      case GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV:
+         CHECK_EXTENSION_I(NV_fragment_program, pname);
+         *params = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
+         break;
+#endif /* FEATURE_NV_fragment_program */
 
       /* GL_NV_texture_rectangle */
       case GL_TEXTURE_RECTANGLE_NV:
@@ -5547,7 +5650,6 @@ _mesa_GetIntegerv( GLenum pname, GLint *params )
          CHECK_EXTENSION_I(NV_texture_rectangle, pname);
          *params = (GLint) ctx->Const.MaxTextureRectSize;
          break;
-#endif /* FEATURE_NV_vertex_program */
 
       /* GL_EXT_stencil_two_side */
       case GL_STENCIL_TEST_TWO_SIDE_EXT:
@@ -5682,6 +5784,10 @@ _mesa_GetString( GLenum name )
             }
          case GL_EXTENSIONS:
             return (const GLubyte *) _mesa_extensions_get_string(ctx);
+#if FEATURE_NV_fragment_program
+         case GL_PROGRAM_ERROR_STRING_NV:
+            return (const GLubyte *) ctx->Program.ErrorString;
+#endif
          default:
             _mesa_error( ctx, GL_INVALID_ENUM, "glGetString" );
             return (const GLubyte *) 0;
index fde7e3f..dfb3f12 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mtypes.h,v 1.97 2002/10/21 15:52:34 brianp Exp $ */
+/* $Id: mtypes.h,v 1.98 2003/01/14 04:55:45 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -361,7 +361,7 @@ struct gl_current_attrib {
    GLfloat RasterColor[4];                     /* Current raster color */
    GLfloat RasterSecondaryColor[4];             /* Current rast 2ndary color */
    GLuint RasterIndex;                         /* Current raster index */
-   GLfloat RasterTexCoords[MAX_TEXTURE_UNITS][4];/* Current raster texcoords */
+   GLfloat RasterTexCoords[MAX_TEXTURE_COORD_UNITS][4];
    GLboolean RasterPosValid;                   /* Raster pos valid flag */
 };
 
@@ -433,8 +433,8 @@ struct gl_enable_attrib {
    GLboolean SampleCoverage;          /* GL_ARB_multisample */
    GLboolean SampleCoverageInvert;    /* GL_ARB_multisample */
    GLboolean RasterPositionUnclipped; /* GL_IBM_rasterpos_clip */
-   GLuint Texture[MAX_TEXTURE_UNITS];
-   GLuint TexGen[MAX_TEXTURE_UNITS];
+   GLuint Texture[MAX_TEXTURE_IMAGE_UNITS];
+   GLuint TexGen[MAX_TEXTURE_COORD_UNITS];
    GLboolean VertexProgram;           /* GL_NV_vertex_program */
    GLboolean VertexProgramPointSize;  /* GL_NV_vertex_program */
    GLboolean VertexProgramTwoSide;    /* GL_NV_vertex_program */
@@ -679,7 +679,7 @@ struct gl_point_attrib {
    GLfloat Threshold;          /* GL_EXT_point_parameters */
    GLboolean _Attenuated;      /* True if Params != [1, 0, 0] */
    GLboolean PointSprite;      /* GL_NV_point_sprite */
-   GLboolean CoordReplace[MAX_TEXTURE_UNITS]; /* GL_NV_point_sprite */
+   GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /* GL_NV_point_sprite */
    GLenum SpriteRMode;         /* GL_NV_point_sprite */
 };
 
@@ -1046,7 +1046,7 @@ struct gl_array_attrib {
    struct gl_client_array SecondaryColor;
    struct gl_client_array FogCoord;
    struct gl_client_array Index;
-   struct gl_client_array TexCoord[MAX_TEXTURE_UNITS];
+   struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS];
    struct gl_client_array EdgeFlag;
 
    struct gl_client_array VertexAttrib[16];  /* GL_NV_vertex_program */
@@ -1134,125 +1134,103 @@ struct gl_evaluators {
 };
 
 
-/*
- * Vertex program tokens and datatypes
- */
-
-#define VP_MAX_INSTRUCTIONS 128
-
-#define VP_NUM_INPUT_REGS VERT_ATTRIB_MAX
-#define VP_NUM_OUTPUT_REGS 15
-#define VP_NUM_TEMP_REGS 12
-#define VP_NUM_PROG_REGS 96
 
-#define VP_NUM_TOTAL_REGISTERS (VP_NUM_INPUT_REGS + VP_NUM_OUTPUT_REGS + VP_NUM_TEMP_REGS + VP_NUM_PROG_REGS)
-
-/* Location of register sets within the whole register file */
-#define VP_INPUT_REG_START  0
-#define VP_INPUT_REG_END    (VP_INPUT_REG_START + VP_NUM_INPUT_REGS - 1)
-#define VP_OUTPUT_REG_START (VP_INPUT_REG_END + 1)
-#define VP_OUTPUT_REG_END   (VP_OUTPUT_REG_START + VP_NUM_OUTPUT_REGS - 1)
-#define VP_TEMP_REG_START   (VP_OUTPUT_REG_END + 1)
-#define VP_TEMP_REG_END     (VP_TEMP_REG_START + VP_NUM_TEMP_REGS - 1)
-#define VP_PROG_REG_START   (VP_TEMP_REG_END + 1)
-#define VP_PROG_REG_END     (VP_PROG_REG_START + VP_NUM_PROG_REGS - 1)
-
-
-/* Machine state (i.e. the register file) */
+/* NV_vertex_program runtime state */
 struct vp_machine
 {
-   GLfloat Registers[VP_NUM_TOTAL_REGISTERS][4];
+   GLfloat Registers[MAX_NV_VERTEX_PROGRAM_TEMPS
+                    + MAX_NV_VERTEX_PROGRAM_PARAMS
+                    + MAX_NV_VERTEX_PROGRAM_INPUTS
+                    + MAX_NV_VERTEX_PROGRAM_OUTPUTS][4];
    GLint AddressReg;  /* might someday be a 4-vector */
 };
 
 
-/* Vertex program opcodes */
-enum vp_opcode
+/* NV_fragment_program runtime state */
+struct fp_machine
 {
-   MOV,
-   LIT,
-   RCP,
-   RSQ,
-   EXP,
-   LOG,
-   MUL,
-   ADD,
-   DP3,
-   DP4,
-   DST,
-   MIN,
-   MAX,
-   SLT,
-   SGE,
-   MAD,
-   ARL,
-   DPH,
-   RCC,
-   SUB,
-   ABS,
-   END
+   GLfloat Registers[MAX_NV_FRAGMENT_PROGRAM_TEMPS
+                    + MAX_NV_FRAGMENT_PROGRAM_PARAMS
+                    + MAX_NV_FRAGMENT_PROGRAM_INPUTS
+                    + MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
+                    + MAX_NV_FRAGMENT_PROGRAM_WRITE_ONLYS][4];
+   GLuint CondCodes[4];
 };
 
 
-/* Instruction source register */
-struct vp_src_register
-{
-   GLint Register;    /* or the offset from the address register */
-   GLuint Swizzle[4];
-   GLboolean Negate;
-   GLboolean RelAddr;
-};
+/* Vertex and fragment instructions */
+struct vp_instruction;
+struct fp_instruction;
 
 
-/* Instruction destination register */
-struct vp_dst_register
+/* Base class for any kind of program object */
+struct program
 {
-   GLint Register;
-   GLboolean WriteMask[4];
+   GLuint Id;
+   GLubyte *String;    /* Null-terminated program text */
+   GLenum Target;
+   GLint RefCount;
+   GLboolean Resident;
 };
 
 
-/* Vertex program instruction */
-struct vp_instruction
+/* Vertex program object */
+struct vertex_program
 {
-   enum vp_opcode Opcode;
-   struct vp_src_register SrcReg[3];
-   struct vp_dst_register DstReg;
+   struct program Base;   /* base class */
+   struct vp_instruction *Instructions;  /* Compiled instructions */
+   GLboolean IsPositionInvariant;  /* GL_NV_vertex_program1_1 */
+   GLuint InputsRead;     /* Bitmask of which input regs are read */
+   GLuint OutputsWritten; /* Bitmask of which output regs are written to */
 };
 
 
-/* The actual vertex program, stored in the hash table */
-struct vp_program
+/* Fragment program object */
+struct fragment_program
 {
-   GLubyte *String;                      /* Original user code */
-   struct vp_instruction *Instructions;  /* Compiled instructions */
-   GLenum Target;      /* GL_VERTEX_PROGRAM_NV or GL_VERTEX_STATE_PROGRAM_NV */
-   GLint RefCount;            /* Since programs can be shared among contexts */
-   GLboolean IsPositionInvariant;  /* GL_NV_vertex_program1_1 */
-   GLboolean Resident;
+   struct program Base;   /* base class */
+   struct fp_instruction *Instructions;  /* Compiled instructions */
    GLuint InputsRead;     /* Bitmask of which input regs are read */
    GLuint OutputsWritten; /* Bitmask of which output regs are written to */
+   GLfloat LocalParams[MAX_NV_FRAGMENT_PROGRAM_PARAMS][4];
+};
+
+
+/*
+ * State common to vertex and fragment programs.
+ */
+struct program_state {
+   GLint ErrorPos;                       /* GL_PROGRAM_ERROR_POSITION_NV */
+   const char *ErrorString;              /* GL_PROGRAM_ERROR_STRING_NV */
 };
 
 
 /*
- * State vars for GL_NV_vertex_program
+ * State for GL_NV_vertex_program
  */
 struct vertex_program_state
 {
    GLboolean Enabled;                    /* GL_VERTEX_PROGRAM_NV */
    GLboolean PointSizeEnabled;           /* GL_VERTEX_PROGRAM_POINT_SIZE_NV */
    GLboolean TwoSideEnabled;             /* GL_VERTEX_PROGRAM_TWO_SIDE_NV */
-   GLuint CurrentID;                     /* currently bound program's ID */
-   GLint ErrorPos;                       /* GL_PROGRAM_ERROR_POSITION_NV */
-   struct vp_program *Current;           /* ptr to currently bound program */
+   struct vertex_program *Current;       /* ptr to currently bound program */
    struct vp_machine Machine;            /* machine state */
 
-   GLenum TrackMatrix[VP_NUM_PROG_REGS / 4];
-   GLenum TrackMatrixTransform[VP_NUM_PROG_REGS / 4];
+   GLenum TrackMatrix[MAX_NV_VERTEX_PROGRAM_PARAMS / 4];
+   GLenum TrackMatrixTransform[MAX_NV_VERTEX_PROGRAM_PARAMS / 4];
 };
 
 
+/*
+ * State for GL_NV_fragment_program
+ */
+struct fragment_program_state
+{
+   GLboolean Enabled;                    /* GL_VERTEX_PROGRAM_NV */
+   struct fragment_program *Current;     /* ptr to currently bound program */
+   struct fp_machine Machine;            /* machine state */
+};
+
 
 /*
  * State which can be shared by multiple contexts:
@@ -1271,8 +1249,8 @@ struct gl_shared_state {
    struct gl_texture_object *DefaultCubeMap;
    struct gl_texture_object *DefaultRect;
 
-   /* GL_NV_vertex_program */
-   struct _mesa_HashTable *VertexPrograms;
+   /* GL_NV_vertex/_program */
+   struct _mesa_HashTable *Programs;
 
    void *DriverData;  /* Device driver shared state */
 };
@@ -1325,6 +1303,8 @@ struct gl_constants {
    GLint MaxCubeTextureLevels;          /* GL_ARB_texture_cube_map */
    GLint MaxTextureRectSize;            /* GL_NV_texture_rectangle */
    GLuint MaxTextureUnits;
+   GLuint MaxTextureCoordUnits;
+   GLuint MaxTextureImageUnits;
    GLfloat MaxTextureMaxAnisotropy;    /* GL_EXT_texture_filter_anisotropic */
    GLfloat MaxTextureLodBias;           /* GL_EXT_texture_lod_bias */
    GLuint MaxArrayLockSize;
@@ -1406,6 +1386,7 @@ struct gl_extensions {
    GLboolean MESA_resize_buffers;
    GLboolean MESA_ycbcr_texture;
    GLboolean NV_blend_square;
+   GLboolean NV_fragment_program;
    GLboolean NV_point_sprite;
    GLboolean NV_texture_rectangle;
    GLboolean NV_texgen_reflection;
@@ -1662,7 +1643,7 @@ struct __GLcontextRec {
    struct matrix_stack ModelviewMatrixStack;
    struct matrix_stack ProjectionMatrixStack;
    struct matrix_stack ColorMatrixStack;
-   struct matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS];
+   struct matrix_stack TextureMatrixStack[MAX_TEXTURE_COORD_UNITS];
    struct matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES];
    struct matrix_stack *CurrentStack; /* Points to one of the above stacks */
 
@@ -1734,7 +1715,9 @@ struct __GLcontextRec {
    struct gl_color_table PostColorMatrixColorTable;
    struct gl_color_table ProxyPostColorMatrixColorTable;
 
-   struct vertex_program_state VertexProgram;  /* GL_NV_vertex_program */
+   struct program_state Program;             /* for vertex or fragment progs */
+   struct vertex_program_state VertexProgram;      /* GL_NV_vertex_program */
+   struct fragment_program_state FragmentProgram;  /* GL_NV_fragment_program */
 
    GLenum ErrorValue;        /* Last error code */
    GLenum RenderMode;        /* either GL_RENDER, GL_SELECT, GL_FEEDBACK */
diff --git a/src/mesa/main/nvfragparse.c b/src/mesa/main/nvfragparse.c
new file mode 100644 (file)
index 0000000..c4035f0
--- /dev/null
@@ -0,0 +1,1619 @@
+/* $Id: nvfragparse.c,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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.
+ */
+
+
+/**
+ * \file nvfragparse.c
+ * \brief NVIDIA fragment program parser.
+ * \author Brian Paul
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "mmath.h"
+#include "mtypes.h"
+#include "nvfragprog.h"
+#include "nvfragparse.h"
+#include "nvprogram.h"
+
+
+#define FRAG_ATTRIB_WPOS  0
+#define FRAG_ATTRIB_COL0  1
+#define FRAG_ATTRIB_COL1  2
+#define FRAG_ATTRIB_FOGC  3
+#define FRAG_ATTRIB_TEX0  4
+#define FRAG_ATTRIB_TEX1  5
+#define FRAG_ATTRIB_TEX2  6
+#define FRAG_ATTRIB_TEX3  7
+#define FRAG_ATTRIB_TEX4  8
+#define FRAG_ATTRIB_TEX5  9
+#define FRAG_ATTRIB_TEX6  10
+#define FRAG_ATTRIB_TEX7  11
+
+
+#define INPUT_1V     1
+#define INPUT_2V     2
+#define INPUT_3V     3
+#define INPUT_1S     4
+#define INPUT_2S     5
+#define INPUT_CC     6
+#define INPUT_1V_T   7  /* one source vector, plus textureId */
+#define INPUT_3V_T   8  /* one source vector, plus textureId */
+#define INPUT_NONE   9
+#define OUTPUT_V    20
+#define OUTPUT_S    21
+#define OUTPUT_NONE 22
+
+/* Optional suffixes */
+#define _R  0x01  /* real */
+#define _H  0x02  /* half */
+#define _X  0x04  /* fixed */
+#define _C  0x08  /* set cond codes */
+#define _S  0x10  /* saturate */
+
+#define SINGLE  _R
+#define HALF    _H
+#define FIXED   _X
+
+struct instruction_pattern {
+   const char *name;
+   enum fp_opcode opcode;
+   GLuint inputs;
+   GLuint outputs;
+   GLuint suffixes;
+};
+
+static const struct instruction_pattern Instructions[] = {
+   { "ADD", FP_OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "COS", FP_OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
+   { "DDX", FP_OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
+   { "DDY", FP_OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
+   { "DP3", FP_OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
+   { "DP4", FP_OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
+   { "DST", FP_OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
+   { "EX2", FP_OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
+   { "FLR", FP_OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "FRC", FP_OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "KIL", FP_OPCODE_KIL, INPUT_CC, OUTPUT_NONE, 0                   },
+   { "LG2", FP_OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
+   { "LIT", FP_OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
+   { "LRP", FP_OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "MAD", FP_OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "MAX", FP_OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "MIN", FP_OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "MOV", FP_OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "MUL", FP_OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "PK2H",  FP_OPCODE_PK2H,  INPUT_1V, OUTPUT_S, 0                  },
+   { "PK2US", FP_OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0                  },
+   { "PK4B",  FP_OPCODE_PK4B,  INPUT_1V, OUTPUT_S, 0                  },
+   { "PK2UB", FP_OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0                  },
+   { "POW", FP_OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H |      _C | _S },
+   { "RCP", FP_OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
+   { "RFL", FP_OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
+   { "RSQ", FP_OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
+   { "SEQ", FP_OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "SFL", FP_OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "SGE", FP_OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "SGT", FP_OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "SIN", FP_OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
+   { "SLE", FP_OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "SLT", FP_OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "SNE", FP_OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "STR", FP_OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "SUB", FP_OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+   { "TEX", FP_OPCODE_SUB, INPUT_1V_T, OUTPUT_V,              _C | _S },
+   { "TXD", FP_OPCODE_SUB, INPUT_3V_T, OUTPUT_V,              _C | _S },
+   { "TXP", FP_OPCODE_SUB, INPUT_1V_T, OUTPUT_V,              _C | _S },
+   { "UP2H",  FP_OPCODE_UP2H,  INPUT_1S, OUTPUT_V,            _C | _S },
+   { "UP2US", FP_OPCODE_UP2US, INPUT_1S, OUTPUT_V,            _C | _S },
+   { "UP4B",  FP_OPCODE_UP4B,  INPUT_1S, OUTPUT_V,            _C | _S },
+   { "UP4UB", FP_OPCODE_UP4UB, INPUT_1S, OUTPUT_V,            _C | _S },
+   { "X2D", FP_OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H |      _C | _S },
+   { NULL, -1, 0, 0, 0 }
+};
+
+
+/**********************************************************************/
+
+
+struct parse_state {
+   const GLubyte *start;    /* start of program */
+   const GLubyte *end;      /* one char past end of the program */
+   const GLubyte *s;        /* current position */
+   GLboolean IsStateProgram;
+   GLboolean IsVersion1_1;
+};
+
+
+
+/*
+ * Search a list of instruction structures for a match.
+ */
+static struct instruction_pattern
+MatchInstruction(const char *token)
+{
+   const struct instruction_pattern *inst;
+   struct instruction_pattern result;
+
+   for (inst = Instructions; inst->name; inst++) {
+      if (_mesa_strncmp(token, inst->name, 3) == 0) {
+         /* matched! */
+         int i = 3;
+         result = *inst;
+         result.suffixes = 0;
+         /* look at suffix */
+         if (token[i] == 'R') {
+            result.suffixes |= _R;
+            i++;
+         }
+         else if (token[i] == 'H') {
+            result.suffixes |= _H;
+            i++;
+         }
+         else if (token[i] == 'X') {
+            result.suffixes |= _X;
+            i++;
+         }
+         if (token[i] == 'C') {
+            result.suffixes |= _C;
+            i++;
+         }
+         if (token[i] == '_' && token[i+1] == 'S' &&
+             token[i+2] == 'A' && token[i+3] == 'T') {
+            result.suffixes |= _S;
+         }
+         return result;
+      }
+   }
+   result.opcode = -1;
+   return result;
+}
+
+
+
+
+/**********************************************************************/
+
+
+static GLboolean IsLetter(char b)
+{
+   return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b == '_');
+}
+
+
+static GLboolean IsDigit(char b)
+{
+   return b >= '0' && b <= '9';
+}
+
+
+static GLboolean IsWhitespace(char b)
+{
+   return b == ' ' || b == '\t' || b == '\n' || b == '\r';
+}
+
+
+/**
+ * Starting at 'str' find the next token.  A token can be an integer,
+ * an identifier or punctuation symbol.
+ * \return <= 0 we found an error, else, return number of characters parsed.
+ */
+static GLint
+GetToken(const char *str, char *token)
+{
+   GLint i = 0, j = 0;
+
+   token[0] = 0;
+
+   /* skip whitespace and comments */
+   while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
+      if (str[i] == '#') {
+         /* skip comment */
+         while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
+            i++;
+         }
+      }
+      else {
+         /* skip whitespace */
+         i++;
+      }
+   }
+
+   if (str[i] == 0)
+      return -i;
+
+   /* try matching an integer */
+   while (str[i] && IsDigit(str[i])) {
+      token[j++] = str[i++];
+   }
+   if (j > 0 || !str[i]) {
+      token[j] = 0;
+      return i;
+   }
+
+   /* try matching an identifier */
+   if (IsLetter(str[i])) {
+      while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
+         token[j++] = str[i++];
+      }
+      token[j] = 0;
+      return i;
+   }
+
+   /* punctuation */
+   if (str[i]) {
+      token[0] = str[i++];
+      token[1] = 0;
+      return i;
+   }
+
+   /* end of input */
+   token[0] = 0;
+   return i;
+}
+
+
+/**
+ * Get next token from input stream and increment stream pointer past token.
+ */
+static GLboolean
+Parse_Token(const char **s, char *token)
+{
+   GLint i;
+   i = GetToken(*s, token);
+   if (i <= 0) {
+      *s += (-i);
+      return GL_FALSE;
+   }
+   *s += i;
+   return GL_TRUE;
+}
+
+
+/**
+ * Get next token from input stream but don't increment stream pointer.
+ */
+static GLboolean
+Peek_Token(const char **s, char *token)
+{
+   GLint i, len;
+   i = GetToken(*s, token);
+   if (i <= 0) {
+      *s += (-i);
+      return GL_FALSE;
+   }
+   len = _mesa_strlen(token);
+   *s += (i - len);
+   return GL_TRUE;
+}
+
+
+/**
+ * String equality test
+ */
+static GLboolean
+StrEq(const char *a, const char *b)
+{
+   GLint i;
+   for (i = 0; a[i] && b[i] && a[i] == (char) b[i]; i++)
+      ;
+   if (a[i] == 0 && b[i] == 0)
+      return GL_TRUE;
+   else
+      return GL_FALSE;
+}
+
+
+
+/**********************************************************************/
+
+static const char *InputRegisters[] = {
+   "WPOS", "COL0", "COL1", "FOGC",
+   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
+};
+
+static const char *OutputRegisters[] = {
+   "COLR", "COLH", "TEX0", "TEX1", "TEX2", "TEX3", "DEPR", NULL
+};
+
+
+#ifdef DEBUG
+
+#define PARSE_ERROR                                            \
+do {                                                           \
+   _mesa_printf("fpparse.c error at %d: parse error\n", __LINE__);     \
+   return GL_FALSE;                                            \
+} while(0)
+
+#define PARSE_ERROR1(msg)                                      \
+do {                                                           \
+   _mesa_printf("fpparse.c error at %d: %s\n", __LINE__, msg); \
+   return GL_FALSE;                                            \
+} while(0)
+
+#define PARSE_ERROR2(msg1, msg2)                                       \
+do {                                                                   \
+   _mesa_printf("fpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2);\
+   return GL_FALSE;                                                    \
+} while(0)
+
+#else
+
+#define PARSE_ERROR                return GL_FALSE
+#define PARSE_ERROR1(msg1)         return GL_FALSE
+#define PARSE_ERROR2(msg1, msg2)   return GL_FALSE
+
+#endif
+
+
+static GLint
+TempRegisterNumber(GLuint r)
+{
+   if (r >= FP_TEMP_REG_START && r <= FP_TEMP_REG_END)
+      return r - FP_TEMP_REG_START;
+   else
+      return -1;
+}
+
+static GLint
+HalfTempRegisterNumber(GLuint r)
+{
+   if (r >= FP_TEMP_REG_START + 32 && r <= FP_TEMP_REG_END)
+      return r - FP_TEMP_REG_START - 32;
+   else
+      return -1;
+}
+
+static GLint
+InputRegisterNumber(GLuint r)
+{
+   if (r >= FP_INPUT_REG_START && r <= FP_INPUT_REG_END)
+      return r - FP_INPUT_REG_START;
+   else
+      return -1;
+}
+
+static GLint
+OutputRegisterNumber(GLuint r)
+{
+   if (r >= FP_OUTPUT_REG_START && r <= FP_OUTPUT_REG_END)
+      return r - FP_OUTPUT_REG_START;
+   else
+      return -1;
+}
+
+static GLint
+ProgramRegisterNumber(GLuint r)
+{
+   if (r >= FP_PROG_REG_START && r <= FP_PROG_REG_END)
+      return r - FP_PROG_REG_START;
+   else
+      return -1;
+}
+
+static GLint
+DummyRegisterNumber(GLuint r)
+{
+   if (r >= FP_DUMMY_REG_START && r <= FP_DUMMY_REG_END)
+      return r - FP_DUMMY_REG_START;
+   else
+      return -1;
+}
+
+
+
+/**********************************************************************/
+
+
+/**
+ * Try to match 'pattern' as the next token after any whitespace/comments.
+ */
+static GLboolean
+Parse_String(const char **s, const char *pattern)
+{
+   GLint i;
+
+   /* skip whitespace and comments */
+   while (IsWhitespace(**s) || **s == '#') {
+      if (**s == '#') {
+         while (**s && (**s != '\n' && **s != '\r')) {
+            *s += 1;
+         }
+      }
+      else {
+         /* skip whitespace */
+         *s += 1;
+      }
+   }
+
+   /* Try to match the pattern */
+   for (i = 0; pattern[i]; i++) {
+      if (**s != pattern[i])
+         PARSE_ERROR2("failed to match", pattern); /* failure */
+      *s += 1;
+   }
+
+   return GL_TRUE; /* success */
+}
+
+
+static GLboolean
+Parse_Identifier(const char **s, char *ident)
+{
+   if (!Parse_Token(s, ident))
+      PARSE_ERROR;
+   if (IsLetter(ident[0]))
+      return GL_TRUE;
+   else
+      PARSE_ERROR1("Expected an identfier");
+}
+
+
+/**
+ * Parse a floating point constant.
+ * [+/-]N[.N[eN]]
+ */
+static GLboolean
+Parse_ScalarConstant(const char **s, GLfloat *number)
+{
+   char *end;
+
+   *number = _mesa_strtof(*s, &end);
+
+   if (end && end > *s) {
+      /* got a number */
+      *s = end;
+      return GL_TRUE;
+   }
+   else {
+      /* should be an identifier */
+      char ident[100];
+      if (!Parse_Identifier(s, ident))
+         PARSE_ERROR1("Expected an identifier");
+      /* XXX Look up the value in the symbol table */
+      *number = -999;
+      return GL_TRUE;
+   }
+}
+
+
+
+/**
+ * Parse a vector constant, one of:
+ *   { float }
+ *   { float, float }
+ *   { float, float, float }
+ *   { float, float, float, float }
+ */
+static GLboolean
+Parse_VectorConstant(const char **s, GLfloat *vec)
+{
+   char token[100];
+
+   if (!Parse_String(s, "{"))
+      return GL_FALSE;
+
+   if (!Parse_ScalarConstant(s, vec+0))  /* X */
+      return GL_FALSE;
+
+   if (!Parse_Token(s, token))  /* , or } */
+      return GL_FALSE;
+
+   if (token[0] == '}') {
+      vec[1] = vec[2] = vec[3] = vec[0];
+      return GL_TRUE;
+   }
+
+   if (token[0] != ',')
+      PARSE_ERROR1("Expected comma in vector constant");
+
+   if (!Parse_ScalarConstant(s, vec+1))  /* Y */
+      return GL_FALSE;
+
+   if (!Parse_Token(s, token))  /* , or } */
+      return GL_FALSE;
+
+   if (token[0] == '}') {
+      vec[2] = vec[3] = vec[1];
+      return GL_TRUE;
+   }
+
+   if (token[0] != ',')
+      PARSE_ERROR1("Expected comma in vector constant");
+
+   if (!Parse_ScalarConstant(s, vec+2))  /* Z */
+      return GL_FALSE;
+
+   if (!Parse_Token(s, token))  /* , or } */
+      return GL_FALSE;
+
+   if (token[0] == '}') {
+      vec[3] = vec[2];
+      return GL_TRUE;
+   }
+
+   if (token[0] != ',')
+      PARSE_ERROR1("Expected comma in vector constant");
+
+   if (!Parse_ScalarConstant(s, vec+3))  /* W */
+      return GL_FALSE;
+
+   if (!Parse_String(s, "}"))
+      PARSE_ERROR1("Expected closing brace in vector constant");
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_VectorOrScalarConstant(const char **s, GLfloat *vec)
+{
+   char token[100];
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] == '{') {
+      return Parse_VectorConstant(s, vec);
+   }
+   else {
+      GLboolean b = Parse_ScalarConstant(s, vec);
+      if (b) {
+         vec[1] = vec[2] = vec[3] = vec[0];
+      }
+      return b;
+   }
+}
+
+
+/**
+ * Parse a texture image source:
+ *    [TEX0 | TEX1 | .. | TEX15]
+ *    [TEX0 | TEX1 | .. | TEX15] . [1D | 2D | 3D | CUBE | RECT]
+ */
+static GLboolean
+Parse_TextureImageId(const char **s, GLuint *unit, GLenum *target)
+{
+   return GL_TRUE;
+}
+
+
+/**
+ * Parse a swizzle suffix like .x or .z or .wxyz or .xxyy etc and return
+ * the swizzle indexes.
+ */
+static GLboolean
+Parse_SwizzleSuffix(const char *token, GLuint swizzle[4])
+{
+   if (token[1] == 0) {
+      /* single letter swizzle (scalar) */
+      if (token[0] == 'x')
+         ASSIGN_4V(swizzle, 0, 0, 0, 0);
+      else if (token[0] == 'y')
+         ASSIGN_4V(swizzle, 1, 1, 1, 1);
+      else if (token[0] == 'z')
+         ASSIGN_4V(swizzle, 2, 2, 2, 2);
+      else if (token[0] == 'w')
+         ASSIGN_4V(swizzle, 3, 3, 3, 3);
+      else
+         return GL_FALSE;
+   }
+   else {
+      /* 4-component swizzle (vector) */
+      GLint k;
+      for (k = 0; token[k] && k < 4; k++) {
+         if (token[k] == 'x')
+            swizzle[k] = 0;
+         else if (token[k] == 'y')
+            swizzle[k] = 1;
+         else if (token[k] == 'z')
+            swizzle[k] = 2;
+         else if (token[k] == 'w')
+            swizzle[k] = 3;
+         else
+            return GL_FALSE;
+      }
+      if (k != 4)
+         return GL_FALSE;
+   }
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_CondCodeMask(const char **s, struct fp_dst_register *dstReg)
+{
+   char token[100];
+
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (StrEq(token, "EQ"))
+      dstReg->CondMask = COND_EQ;
+   else if (StrEq(token, "GE"))
+      dstReg->CondMask = COND_GE;
+   else if (StrEq(token, "GT"))
+      dstReg->CondMask = COND_GT;
+   else if (StrEq(token, "LE"))
+      dstReg->CondMask = COND_LE;
+   else if (StrEq(token, "LT"))
+      dstReg->CondMask = COND_LT;
+   else if (StrEq(token, "NE"))
+      dstReg->CondMask = COND_NE;
+   else if (StrEq(token, "TR"))
+      dstReg->CondMask = COND_TR;
+   else if (StrEq(token, "FL"))
+      dstReg->CondMask = COND_FL;
+   else
+      PARSE_ERROR1("Invalid condition code mask");
+
+   /* look for optional .xyzw swizzle */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+
+   if (token[0] == '.') {
+      Parse_String(s, "."); /* consume '.' */
+      if (!Parse_Token(s, token))  /* get xyzw suffix */
+         PARSE_ERROR;
+
+      if (!Parse_SwizzleSuffix(token, dstReg->CondSwizzle))
+         PARSE_ERROR1("Bad swizzle suffix");
+   }
+
+   return GL_TRUE;
+}
+
+
+/**
+ * Parse a temporary register: Rnn or Hnn
+ */
+static GLboolean
+Parse_TempReg(const char **s, GLint *tempRegNum)
+{
+   char token[100];
+
+   /* Should be 'R##' or 'H##' */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] != 'R' && token[0] != 'H')
+      PARSE_ERROR1("Expected R## or H##");
+
+   if (IsDigit(token[1])) {
+      GLint reg = _mesa_atoi((token + 1));
+      if (token[0] == 'H')
+         reg += 32;
+      if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
+         PARSE_ERROR1("Bad temporary register name");
+      *tempRegNum = FP_TEMP_REG_START + reg;
+   }
+   else {
+      PARSE_ERROR1("Bad temporary register name");
+   }
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_DummyReg(const char **s, GLint *regNum)
+{
+   char token[100];
+
+   /* Should be 'RC' or 'HC' */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (_mesa_strcmp(token, "RC")) {
+       *regNum = FP_DUMMY_REG_START;
+   }
+   else if (_mesa_strcmp(token, "HC")) {
+       *regNum = FP_DUMMY_REG_START + 1;
+   }
+   else {
+      PARSE_ERROR1("Bad write-only register name");
+   }
+
+   return GL_TRUE;
+}
+
+
+/**
+ * Parse a program local parameter register "p[##]"
+ */
+static GLboolean
+Parse_ProgramParamReg(const char **s, GLint *regNum)
+{
+   char token[100];
+
+   if (!Parse_String(s, "p"))
+      PARSE_ERROR;
+
+   if (!Parse_String(s, "["))
+      PARSE_ERROR;
+
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (IsDigit(token[0])) {
+      /* a numbered program parameter register */
+      GLint reg = _mesa_atoi(token);
+      if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
+         PARSE_ERROR1("Bad constant program number");
+      *regNum = FP_PROG_REG_START + reg;
+   }
+   else {
+      PARSE_ERROR;
+   }
+
+   if (!Parse_String(s, "]"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+/**
+ * Parse f[name]  - fragment input register
+ */
+static GLboolean
+Parse_AttribReg(const char **s, GLint *tempRegNum)
+{
+   char token[100];
+   GLint j;
+
+   /* Match 'f' */
+   if (!Parse_String(s, "f"))
+      PARSE_ERROR;
+
+   /* Match '[' */
+   if (!Parse_String(s, "["))
+      PARSE_ERROR;
+
+   /* get <name> and look for match */
+   if (!Parse_Token(s, token)) {
+      PARSE_ERROR;
+   }
+   for (j = 0; InputRegisters[j]; j++) {
+      if (StrEq(token, InputRegisters[j])) {
+         *tempRegNum = FP_INPUT_REG_START + j;
+         break;
+      }
+   }
+   if (!InputRegisters[j]) {
+      /* unknown input register label */
+      PARSE_ERROR2("Bad register name", token);
+   }
+
+   /* Match '[' */
+   if (!Parse_String(s, "]"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_OutputReg(const char **s, GLint *outputRegNum)
+{
+   char token[100];
+   GLint j;
+
+   /* Match 'o' */
+   if (!Parse_String(s, "o"))
+      PARSE_ERROR;
+
+   /* Match '[' */
+   if (!Parse_String(s, "["))
+      PARSE_ERROR;
+
+   /* Get output reg name */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   /* try to match an output register name */
+   for (j = 0; OutputRegisters[j]; j++) {
+      if (StrEq(token, OutputRegisters[j])) {
+         *outputRegNum = FP_OUTPUT_REG_START + j;
+         break;
+      }
+   }
+   if (!OutputRegisters[j])
+      PARSE_ERROR1("Unrecognized output register name");
+
+   /* Match ']' */
+   if (!Parse_String(s, "]"))
+      PARSE_ERROR1("Expected ]");
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_MaskedDstReg(const char **s, struct fp_dst_register *dstReg)
+{
+   char token[100];
+
+   /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+
+   if (_mesa_strcmp(token, "RC") == 0 ||
+       _mesa_strcmp(token, "HC") == 0) {
+      /* a write-only register */
+      if (!Parse_DummyReg(s, &dstReg->Register))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'R' || token[0] == 'H') {
+      /* a temporary register */
+      if (!Parse_TempReg(s, &dstReg->Register))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'o') {
+      /* an output register */
+      if (!Parse_OutputReg(s, &dstReg->Register))
+         PARSE_ERROR;
+   }
+   else {
+      PARSE_ERROR1("Bad destination register name");
+   }
+
+   /* Parse optional write mask */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+
+   if (token[0] == '.') {
+      /* got a mask */
+      GLint k = 0;
+
+      if (!Parse_String(s, "."))
+         PARSE_ERROR;
+
+      if (!Parse_Token(s, token))  /* get xyzw writemask */
+         PARSE_ERROR;
+
+      dstReg->WriteMask[0] = GL_FALSE;
+      dstReg->WriteMask[1] = GL_FALSE;
+      dstReg->WriteMask[2] = GL_FALSE;
+      dstReg->WriteMask[3] = GL_FALSE;
+
+      if (token[k] == 'x') {
+         dstReg->WriteMask[0] = GL_TRUE;
+         k++;
+      }
+      if (token[k] == 'y') {
+         dstReg->WriteMask[1] = GL_TRUE;
+         k++;
+      }
+      if (token[k] == 'z') {
+         dstReg->WriteMask[2] = GL_TRUE;
+         k++;
+      }
+      if (token[k] == 'w') {
+         dstReg->WriteMask[3] = GL_TRUE;
+         k++;
+      }
+      if (k == 0) {
+         PARSE_ERROR1("Bad writemask character");
+      }
+
+      /* peek optional cc mask */
+      if (!Peek_Token(s, token))
+         PARSE_ERROR;
+   }
+   else {
+      dstReg->WriteMask[0] = GL_TRUE;
+      dstReg->WriteMask[1] = GL_TRUE;
+      dstReg->WriteMask[2] = GL_TRUE;
+      dstReg->WriteMask[3] = GL_TRUE;
+   }
+
+   /* optional condition code mask */
+   if (token[0] == '(') {
+      /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
+      /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
+      Parse_String(s, "(");
+
+      if (!Parse_CondCodeMask(s, dstReg))
+         PARSE_ERROR;
+
+      if (!Parse_String(s, ")"))  /* consume ")" */
+         PARSE_ERROR;
+
+      return GL_TRUE;
+   }
+   else {
+      /* no cond code mask */
+      dstReg->CondMask = COND_TR;
+      dstReg->CondSwizzle[0] = 0;
+      dstReg->CondSwizzle[1] = 1;
+      dstReg->CondSwizzle[2] = 2;
+      dstReg->CondSwizzle[3] = 3;
+      return GL_TRUE;
+   }
+}
+
+
+static GLboolean
+Parse_SwizzleSrcReg(const char **s, struct fp_src_register *srcReg)
+{
+   char token[100];
+
+   /* XXX need to parse absolute value and another negation ***/
+   srcReg->NegateBase = GL_FALSE;
+   srcReg->Abs = GL_FALSE;
+   srcReg->NegateAbs = GL_FALSE;
+
+   /* check for '-' */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] == '-') {
+      (void) Parse_String(s, "-");
+      srcReg->NegateBase = GL_TRUE;
+      if (!Peek_Token(s, token))
+         PARSE_ERROR;
+   }
+   else {
+      srcReg->NegateBase = GL_FALSE;
+   }
+
+   /* Src reg can be R<n>, H<n> or a named fragment attrib */
+   if (token[0] == 'R' || token[0] == 'H') {
+      if (!Parse_TempReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'f') {
+      if (!Parse_AttribReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'p') {
+      if (!Parse_ProgramParamReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else {
+      /* Also parse defined/declared constant or vector literal */
+      PARSE_ERROR2("Bad source register name", token);
+   }
+
+   /* init swizzle fields */
+   srcReg->Swizzle[0] = 0;
+   srcReg->Swizzle[1] = 1;
+   srcReg->Swizzle[2] = 2;
+   srcReg->Swizzle[3] = 3;
+
+   /* Look for optional swizzle suffix */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] == '.') {
+      (void) Parse_String(s, ".");  /* consume . */
+
+      if (!Parse_Token(s, token))
+         PARSE_ERROR;
+
+      if (!Parse_SwizzleSuffix(token, srcReg->Swizzle))
+         PARSE_ERROR1("Bad swizzle suffix");
+   }
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ScalarSrcReg(const char **s, struct fp_src_register *srcReg)
+{
+   char token[100];
+
+   /* check for '-' */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] == '-') {
+      srcReg->NegateBase = GL_TRUE;
+      (void) Parse_String(s, "-"); /* consume '-' */
+      if (!Peek_Token(s, token))
+         PARSE_ERROR;
+   }
+   else {
+      srcReg->NegateBase = GL_FALSE;
+   }
+
+   /* Src reg can be R<n>, H<n> or a named fragment attrib */
+   if (token[0] == 'R' || token[0] == 'H') {
+      if (!Parse_TempReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'f') {
+      if (!Parse_AttribReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else {
+      PARSE_ERROR2("Bad source register name", token);
+   }
+
+   /* Look for .[xyzw] suffix */
+   if (!Parse_String(s, "."))
+      PARSE_ERROR;
+
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (token[0] == 'x' && token[1] == 0) {
+      srcReg->Swizzle[0] = 0;
+   }
+   else if (token[0] == 'y' && token[1] == 0) {
+      srcReg->Swizzle[0] = 1;
+   }
+   else if (token[0] == 'z' && token[1] == 0) {
+      srcReg->Swizzle[0] = 2;
+   }
+   else if (token[0] == 'w' && token[1] == 0) {
+      srcReg->Swizzle[0] = 3;
+   }
+   else {
+      PARSE_ERROR1("Bad scalar source suffix");
+   }
+   srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
+
+   return GL_TRUE;
+}
+
+
+
+static GLboolean
+Parse_InstructionSequence(const char **s, struct fp_instruction program[])
+{
+   char token[100];
+   GLint count = 0;
+
+   while (1) {
+      struct fp_instruction *inst = program + count;
+      struct instruction_pattern instMatch;
+
+      /* Initialize the instruction */
+      inst->SrcReg[0].Register = -1;
+      inst->SrcReg[1].Register = -1;
+      inst->SrcReg[2].Register = -1;
+      inst->DstReg.Register = -1;
+
+      /* get token */
+      if (!Parse_Token(s, token)) {
+         inst->Opcode = FP_OPCODE_END;
+         printf("END OF PROGRAM %d\n", count);
+         break;
+      }
+
+      /* special instructions */
+      if (StrEq(token, "DEFINE")) {
+         char id[100];
+         GLfloat value[4];
+         if (!Parse_Identifier(s, id))
+            PARSE_ERROR;
+         if (!Parse_String(s, "="))
+            PARSE_ERROR1("Expected = symbol");
+         if (!Parse_VectorOrScalarConstant(s, value))
+            PARSE_ERROR;
+         printf("Parsed DEFINE %s = %f %f %f %f\n", id, value[0], value[1],
+                value[2], value[3]);
+      }
+      else if (StrEq(token, "DECLARE")) {
+         char id[100];
+         GLfloat value[4];
+         if (!Parse_Identifier(s, id))
+            PARSE_ERROR;
+         if (!Peek_Token(s, token))
+            PARSE_ERROR;
+         if (token[0] == '=') {
+            Parse_String(s, "=");
+            if (!Parse_VectorOrScalarConstant(s, value))
+               PARSE_ERROR;
+            printf("Parsed DECLARE %s = %f %f %f %f\n", id, value[0], value[1],
+                   value[2], value[3]);
+         }
+         else {
+            printf("Parsed DECLARE %s\n", id);
+         }
+      }
+
+      /* try to find matching instuction */
+      instMatch = MatchInstruction(token);
+      if (instMatch.opcode < 0) {
+         /* bad instruction name */
+         PARSE_ERROR2("Unexpected token: ", token);
+      }
+
+      inst->Opcode = instMatch.opcode;
+      inst->Precision = instMatch.suffixes & (_R | _H | _X);
+      inst->Saturate = (instMatch.suffixes & (_S)) ? GL_TRUE : GL_FALSE;
+      inst->UpdateCondRegister = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
+
+      /*
+       * parse the input and output operands
+       */
+      if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
+         if (!Parse_MaskedDstReg(s, &inst->DstReg))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+      }
+      else if (instMatch.outputs == OUTPUT_NONE) {
+         ASSERT(instMatch.opcode == FP_OPCODE_KIL);
+         /* This is a little weird, the cond code info is in the dest register */
+         if (!Parse_CondCodeMask(s, &inst->DstReg))
+            PARSE_ERROR;
+      }
+
+      if (instMatch.inputs == INPUT_1V) {
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
+            PARSE_ERROR;
+      }
+      else if (instMatch.inputs == INPUT_2V) {
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
+            PARSE_ERROR;
+      }
+      else if (instMatch.inputs == INPUT_3V) {
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
+            PARSE_ERROR;
+      }
+      else if (instMatch.inputs == INPUT_1S) {
+         if (!Parse_ScalarSrcReg(s, &inst->SrcReg[1]))
+            PARSE_ERROR;
+      }
+      else if (instMatch.inputs == INPUT_2S) {
+         if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_ScalarSrcReg(s, &inst->SrcReg[1]))
+            PARSE_ERROR;
+      }
+      else if (instMatch.inputs == INPUT_CC) {
+#if 00
+         if (!ParseCondCodeSrc(s, &inst->srcReg[0]))
+            PARSE_ERROR;
+#endif
+      }
+      else if (instMatch.inputs == INPUT_1V_T) {
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_TextureImageId(s, &inst->TexSrcUnit, &inst->TexSrcTarget))
+            PARSE_ERROR;
+      }
+      else if (instMatch.inputs == INPUT_1V_T) {
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[2]))
+            PARSE_ERROR;
+         if (!Parse_String(s, ","))
+            PARSE_ERROR;
+         if (!Parse_TextureImageId(s, &inst->TexSrcUnit, &inst->TexSrcTarget))
+            PARSE_ERROR;
+      }
+
+      /* end of statement semicolon */
+      if (!Parse_String(s, ";"))
+         PARSE_ERROR;
+
+      count++;
+      if (count >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
+         PARSE_ERROR1("Program too long");
+   }
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_Program(const char **s, struct fp_instruction instBuffer[])
+{
+   return Parse_InstructionSequence(s, instBuffer);
+}
+
+
+/**
+ * Parse/compile the 'str' returning the compiled 'program'.
+ * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
+ * indicates the position of the error in 'str'.
+ */
+void
+_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
+                                const GLubyte *str, GLsizei len,
+                                struct fragment_program *program)
+{
+   const char *s;
+   struct fp_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
+   GLubyte *newString;
+   struct fp_instruction *newInst;
+   GLenum target;
+   GLubyte *programString;
+
+   /* Make a null-terminated copy of the program string */
+   programString = (GLubyte *) MALLOC(len + 1);
+   if (!programString) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+      return;
+   }
+   MEMCPY(programString, str, len);
+   programString[len] = 0;
+
+
+   /* check the program header */
+   if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
+      target = GL_FRAGMENT_PROGRAM_NV;
+      s = (const char *) programString + 7;
+   }
+   else {
+      /* invalid header */
+      _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
+      return;
+   }
+
+   /* make sure target and header match */
+   if (target != dstTarget) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
+                  target, dstTarget);
+      return;
+   }
+
+   if (Parse_Program(&s, instBuffer)) {
+      GLuint numInst;
+      GLuint strLen;
+      GLuint inputsRead = 0;
+      GLuint outputsWritten = 0;
+      /**GLuint progRegsWritten = 0;**/
+
+      /* Find length of the program and compute bitmasks to indicate which
+       * vertex input registers are read, which vertex result registers are
+       * written to, and which program registers are written to.
+       * We could actually do this while we parse the program.
+       */
+      for (numInst = 0; instBuffer[numInst].Opcode != FP_OPCODE_END; numInst++) {
+#if 0
+         const GLint srcReg0 = instBuffer[numInst].SrcReg[0].Register;
+         const GLint srcReg1 = instBuffer[numInst].SrcReg[1].Register;
+         const GLint srcReg2 = instBuffer[numInst].SrcReg[2].Register;
+         const GLint dstReg = instBuffer[numInst].DstReg.Register;
+
+         if ((r = OutputRegisterNumber(dstReg)) >= 0)
+            outputsWritten |= (1 << r);
+         else if (IsProgRegister(dstReg))
+            progRegsWritten |= (1 << (dstReg - FP_PROG_REG_START));
+         if ((r = InputRegisterNumber(srcReg0)) >= 0
+             && !instBuffer[numInst].SrcReg[0].RelAddr)
+            inputsRead |= (1 << r);
+         if ((r = InputRegisterNumber(srcReg1) >= 0
+             && !instBuffer[numInst].SrcReg[1].RelAddr)
+            inputsRead |= (1 << r);
+         if ((r = InputRegisterNumber(srcReg2) >= 0
+             && !instBuffer[numInst].SrcReg[2].RelAddr)
+            inputsRead |= (1 << r);
+#endif
+      }
+      numInst++;
+      printf("numInst %d\n", numInst);
+
+      program->InputsRead = inputsRead;
+      program->OutputsWritten = outputsWritten;
+
+      /* make copy of the input program string */
+      strLen = _mesa_strlen((const char *) str);
+      newString = (GLubyte *) MALLOC(strLen + 1);
+      if (!newString) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+         return;
+      }
+      MEMCPY(newString, str, strLen);
+      newString[strLen] = 0; /* terminate */
+
+      /* copy the compiled instructions */
+      assert(numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
+      newInst = (struct fp_instruction *) MALLOC(numInst * sizeof(struct fp_instruction));
+      if (!newInst) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+         return;  /* out of memory */
+      }
+      MEMCPY(newInst, instBuffer, numInst * sizeof(struct fp_instruction));
+
+      /* install the program */
+      program->Base.Target = target;
+      if (program->Base.String) {
+         FREE(program->Base.String);
+      }
+      program->Base.String = newString;
+      if (program->Instructions) {
+         FREE(program->Instructions);
+      }
+      program->Instructions = newInst;
+
+#ifdef DEBUG
+      _mesa_printf("--- glLoadProgramNV result ---\n");
+      _mesa_print_nv_fragment_program(program);
+      _mesa_printf("------------------------------\n");
+#endif
+   }
+   else {
+      /* Error! */
+#ifdef DEBUG
+      /* print a message showing the program line containing the error */
+      ctx->Program.ErrorPos = (GLubyte *) s - str;
+      {
+         const GLubyte *p = str, *line = str;
+         int lineNum = 1, statementNum = 1, column = 0;
+         char errorLine[1000];
+         int i;
+         while (*p && p < (const GLubyte *) s) {  /* s is the error position */
+            if (*p == '\n') {
+               line = p + 1;
+               lineNum++;
+               column = 0;
+            }
+            else if (*p == ';') {
+               statementNum++;
+            }
+            else
+               column++;
+            p++;
+         }
+         if (p) {
+            /* Copy the line with the error into errorLine so we can null-
+             * terminate it.
+             */
+            for (i = 0; line[i] != '\n' && line[i]; i++)
+               errorLine[i] = (char) line[i];
+            errorLine[i] = 0;
+         }
+         /*
+         _mesa_debug("Error pos = %d  (%c) col %d\n",
+                 ctx->Program.ErrorPos, *s, column);
+         */
+         _mesa_debug(ctx, "Fragment program error on line %2d: %s\n", lineNum, errorLine);
+         _mesa_debug(ctx, "  (statement %2d) near column %2d: ", statementNum, column+1);
+         for (i = 0; i < column; i++)
+            _mesa_debug(ctx, " ");
+         _mesa_debug(ctx, "^\n");
+      }
+#endif
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
+   }
+}
+
+
+static void
+PrintSrcReg(const struct fp_src_register *src)
+{
+   static const char comps[5] = "xyzw";
+   GLint r;
+
+   if (src->NegateAbs) {
+      _mesa_printf("-");
+   }
+   if (src->Abs) {
+      _mesa_printf("|");
+   }
+   if (src->NegateBase) {
+      _mesa_printf("-");
+   }
+   if ((r = OutputRegisterNumber(src->Register)) >= 0) {
+      _mesa_printf("o[%s]", OutputRegisters[r]);
+   }
+   else if ((r = InputRegisterNumber(src->Register)) >= 0) {
+      _mesa_printf("f[%s]", InputRegisters[r]);
+   }
+   else if ((r = ProgramRegisterNumber(src->Register)) >= 0) {
+      _mesa_printf("p[%d]", r);
+   }
+   else if ((r = HalfTempRegisterNumber(src->Register)) >= 0) {
+      _mesa_printf("H%d", r);
+   }
+   else if ((r = TempRegisterNumber(src->Register)) >= 0) {
+      _mesa_printf("R%d", r);
+   }
+   else if ((r = DummyRegisterNumber(src->Register)) >= 0) {
+      _mesa_printf("%cC", "HR"[r]);
+   }
+   else {
+      _mesa_problem(NULL, "Bad fragment register");
+      return;
+   }
+   if (src->Swizzle[0] == src->Swizzle[1] &&
+       src->Swizzle[0] == src->Swizzle[2] &&
+       src->Swizzle[0] == src->Swizzle[3]) {
+      _mesa_printf(".%c", comps[src->Swizzle[0]]);
+   }
+   else if (src->Swizzle[0] != 0 ||
+            src->Swizzle[1] != 1 ||
+            src->Swizzle[2] != 2 ||
+            src->Swizzle[3] != 3) {
+      _mesa_printf(".%c%c%c%c",
+                   comps[src->Swizzle[0]],
+                   comps[src->Swizzle[1]],
+                   comps[src->Swizzle[2]],
+                   comps[src->Swizzle[3]]);
+   }
+   if (src->Abs) {
+      _mesa_printf("|");
+   }
+}
+
+static void
+PrintCondCode(const struct fp_dst_register *dst)
+{
+   static const char *comps = "xyzw";
+   static const char *ccString[] = {
+      "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
+   };
+
+   _mesa_printf("%s", ccString[dst->CondMask]);
+   if (dst->CondSwizzle[0] == dst->CondSwizzle[1] &&
+       dst->CondSwizzle[0] == dst->CondSwizzle[2] &&
+       dst->CondSwizzle[0] == dst->CondSwizzle[3]) {
+      _mesa_printf(".%c", comps[dst->CondSwizzle[0]]);
+   }
+   else if (dst->CondSwizzle[0] != 0 ||
+            dst->CondSwizzle[1] != 1 ||
+            dst->CondSwizzle[2] != 2 ||
+            dst->CondSwizzle[3] != 3) {
+      _mesa_printf(".%c%c%c%c",
+                   comps[dst->CondSwizzle[0]],
+                   comps[dst->CondSwizzle[1]],
+                   comps[dst->CondSwizzle[2]],
+                   comps[dst->CondSwizzle[3]]);
+   }
+}
+
+
+static void
+PrintDstReg(const struct fp_dst_register *dst)
+{
+   GLint w = dst->WriteMask[0] + dst->WriteMask[1]
+           + dst->WriteMask[2] + dst->WriteMask[3];
+   GLint r;
+
+   if ((r = OutputRegisterNumber(dst->Register)) >= 0) {
+      _mesa_printf("o[%s]", OutputRegisters[r]);
+   }
+   else if ((r = HalfTempRegisterNumber(dst->Register)) >= 0) {
+      _mesa_printf("H[%s]", InputRegisters[r]);
+   }
+   else if ((r = TempRegisterNumber(dst->Register)) >= 0) {
+      _mesa_printf("R[%s]", InputRegisters[r]);
+   }
+   else if ((r = ProgramRegisterNumber(dst->Register)) >= 0) {
+      _mesa_printf("p[%d]", r);
+   }
+   else if ((r = DummyRegisterNumber(dst->Register)) >= 0) {
+      _mesa_printf("%cC", "HR"[r]);
+   }
+   else {
+      _mesa_printf("???");
+   }
+
+   if (w != 0 && w != 4) {
+      _mesa_printf(".");
+      if (dst->WriteMask[0])
+         _mesa_printf("x");
+      if (dst->WriteMask[1])
+         _mesa_printf("y");
+      if (dst->WriteMask[2])
+         _mesa_printf("z");
+      if (dst->WriteMask[3])
+         _mesa_printf("w");
+   }
+
+   if (dst->CondMask != COND_TR ||
+       dst->CondSwizzle[0] != 0 ||
+       dst->CondSwizzle[1] != 1 ||
+       dst->CondSwizzle[2] != 2 ||
+       dst->CondSwizzle[3] != 3) {
+      _mesa_printf(" (");
+      PrintCondCode(dst);
+      _mesa_printf(")");
+   }
+}
+
+
+/**
+ * Print (unparse) the given vertex program.  Just for debugging.
+ */
+void
+_mesa_print_nv_fragment_program(const struct fragment_program *program)
+{
+   const struct fp_instruction *inst;
+
+   for (inst = program->Instructions; inst->Opcode != FP_OPCODE_END; inst++) {
+      int i;
+      for (i = 0; Instructions[i].name; i++) {
+         if (inst->Opcode == Instructions[i].opcode) {
+            /* print instruction name */
+            _mesa_printf("%s", Instructions[i].name);
+            if (inst->Precision == HALF)
+               _mesa_printf("H");
+            else if (inst->Precision == FIXED)
+               _mesa_printf("X");
+            if (inst->UpdateCondRegister)
+               _mesa_printf("C");
+            if (inst->Saturate)
+               _mesa_printf("_SAT");
+            _mesa_printf(" ");
+
+            if (Instructions[i].inputs == INPUT_CC) {
+               PrintCondCode(&inst->DstReg);
+            }
+            else if (Instructions[i].outputs == OUTPUT_V ||
+                     Instructions[i].outputs == OUTPUT_S) {
+               /* print dest register */
+               PrintDstReg(&inst->DstReg);
+               _mesa_printf(", ");
+            }
+
+            /* print source register(s) */
+            if (Instructions[i].inputs == INPUT_1V ||
+                Instructions[i].inputs == INPUT_1S) {
+               PrintSrcReg(&inst->SrcReg[0]);
+            }
+            else if (Instructions[i].inputs == INPUT_2V ||
+                     Instructions[i].inputs == INPUT_2S) {
+               PrintSrcReg(&inst->SrcReg[0]);
+               _mesa_printf(", ");
+               PrintSrcReg(&inst->SrcReg[1]);
+            }
+            else if (Instructions[i].inputs == INPUT_3V) {
+               PrintSrcReg(&inst->SrcReg[0]);
+               _mesa_printf(", ");
+               PrintSrcReg(&inst->SrcReg[1]);
+               _mesa_printf(", ");
+               PrintSrcReg(&inst->SrcReg[2]);
+            }
+
+            _mesa_printf(";\n");
+            break;
+         }
+      }
+      if (!Instructions[i].name) {
+         _mesa_printf("Bad opcode %d\n", inst->Opcode);
+      }
+   }
+}
+
diff --git a/src/mesa/main/nvfragparse.h b/src/mesa/main/nvfragparse.h
new file mode 100644 (file)
index 0000000..dd07be1
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id: nvfragparse.h,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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:
+ *    Brian Paul
+ */
+
+
+#ifndef NVFRAGPARSE_H
+#define NVFRAGPARSE_H
+
+
+extern void
+_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum target,
+                                const GLubyte *str, GLsizei len,
+                                struct fragment_program *program);
+
+
+extern void
+_mesa_print_nv_fragment_program(const struct fragment_program *program);
+
+
+#endif
diff --git a/src/mesa/main/nvfragprog.h b/src/mesa/main/nvfragprog.h
new file mode 100644 (file)
index 0000000..687ebb2
--- /dev/null
@@ -0,0 +1,149 @@
+/* $Id: nvfragprog.h,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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.
+ */
+
+
+/* Private vertex program types and constants only used by files
+ * related to vertex programs.
+ */
+
+
+#ifndef NVFRAGPROG_H
+#define NVFRAGPROG_H
+
+#include "config.h"
+
+
+/* Location of register sets within the whole register file */
+#define FP_INPUT_REG_START  0
+#define FP_INPUT_REG_END    (FP_INPUT_REG_START + MAX_NV_FRAGMENT_PROGRAM_INPUTS - 1)
+#define FP_OUTPUT_REG_START (FP_INPUT_REG_END + 1)
+#define FP_OUTPUT_REG_END   (FP_OUTPUT_REG_START + MAX_NV_FRAGMENT_PROGRAM_OUTPUTS - 1)
+#define FP_TEMP_REG_START   (FP_OUTPUT_REG_END + 1)
+#define FP_TEMP_REG_END     (FP_TEMP_REG_START + MAX_NV_FRAGMENT_PROGRAM_TEMPS - 1)
+#define FP_PROG_REG_START   (FP_TEMP_REG_END + 1)
+#define FP_PROG_REG_END     (FP_PROG_REG_START + MAX_NV_FRAGMENT_PROGRAM_PARAMS - 1)
+#define FP_DUMMY_REG_START  (FP_PROG_REG_END + 1)
+#define FP_DUMMY_REG_END    (FP_DUMMY_REG_START + MAX_NV_FRAGMENT_PROGRAM_WRITE_ONLYS - 1)
+
+
+
+#define COND_GT  1  /* greater than zero */
+#define COND_EQ  2  /* equal to zero */
+#define COND_LT  3  /* less than zero */
+#define COND_UN  4  /* unordered (NaN) */
+#define COND_GE  5  /* greater then or equal to zero */
+#define COND_LE  6  /* less then or equal to zero */
+#define COND_NE  7  /* not equal to zero */
+#define COND_TR  8  /* always true */
+#define COND_FL  9  /* always false */
+
+
+enum fp_opcode {
+   FP_OPCODE_ADD = 1000,
+   FP_OPCODE_COS,
+   FP_OPCODE_DDX,
+   FP_OPCODE_DDY,
+   FP_OPCODE_DP3,
+   FP_OPCODE_DP4,
+   FP_OPCODE_DST,
+   FP_OPCODE_EX2,
+   FP_OPCODE_FLR,
+   FP_OPCODE_FRC,
+   FP_OPCODE_KIL,
+   FP_OPCODE_LG2,
+   FP_OPCODE_LIT,
+   FP_OPCODE_LRP,
+   FP_OPCODE_MAD,
+   FP_OPCODE_MAX,
+   FP_OPCODE_MIN,
+   FP_OPCODE_MOV,
+   FP_OPCODE_MUL,
+   FP_OPCODE_PK2H,
+   FP_OPCODE_PK2US,
+   FP_OPCODE_PK4B,
+   FP_OPCODE_PK4UB,
+   FP_OPCODE_POW,
+   FP_OPCODE_RCP,
+   FP_OPCODE_RFL,
+   FP_OPCODE_RSQ,
+   FP_OPCODE_SEQ,
+   FP_OPCODE_SFL,
+   FP_OPCODE_SGE,
+   FP_OPCODE_SGT,
+   FP_OPCODE_SIN,
+   FP_OPCODE_SLE,
+   FP_OPCODE_SLT,
+   FP_OPCODE_SNE,
+   FP_OPCODE_STR,
+   FP_OPCODE_SUB,
+   FP_OPCODE_TEX,
+   FP_OPCODE_TXC,
+   FP_OPCODE_TXP,
+   FP_OPCODE_UP2H,
+   FP_OPCODE_UP2US,
+   FP_OPCODE_UP4B,
+   FP_OPCODE_UP4UB,
+   FP_OPCODE_X2D,
+   FP_OPCODE_END /* private opcode */
+};
+
+
+struct fp_src_register
+{
+   GLint RegType;  /* constant, param, temp or attribute register */
+   GLint Register;    /* or the offset from the address register */
+   GLuint Swizzle[4];
+   GLboolean NegateBase; /* negate before absolute value? */
+   GLboolean Abs;        /* take absolute value? */
+   GLboolean NegateAbs;  /* negate after absolute value? */
+};
+
+
+/* Instruction destination register */
+struct fp_dst_register
+{
+   GLint Register;
+   GLboolean WriteMask[4];
+   GLuint CondMask;
+   GLuint CondSwizzle[4];
+};
+
+
+struct fp_instruction
+{
+   enum fp_opcode Opcode;
+   struct fp_src_register SrcReg[3];
+   struct fp_dst_register DstReg;
+   GLboolean Saturate;
+   GLboolean UpdateCondRegister;
+   GLuint Precision;    /* SINGLE, HALF or FIXED */
+   GLuint TexSrcUnit;   /* texture unit for TEX, TXD, TXP instructions */
+   GLenum TexSrcTarget; /* texture target for TEX, TXD, TXP instructions */
+};
+
+
+
+#endif
diff --git a/src/mesa/main/nvprogram.c b/src/mesa/main/nvprogram.c
new file mode 100644 (file)
index 0000000..87a1a17
--- /dev/null
@@ -0,0 +1,1182 @@
+/* $Id: nvprogram.c,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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.
+ */
+
+/**
+ * \file nvprogram.c
+ * \brief NVIDIA vertex/fragment program state management functions.
+ * \author Brian Paul
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "nvfragparse.h"
+#include "nvfragprog.h"
+#include "nvvertexec.h"
+#include "nvvertparse.h"
+#include "nvvertprog.h"
+#include "nvprogram.h"
+
+
+
+/**
+ * Set the vertex/fragment program error state (position and error string).
+ * This is generally called from within the parsers.
+ */
+void
+_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
+{
+   ctx->Program.ErrorPos = pos;
+   _mesa_free((void *) ctx->Program.ErrorString);
+   if (!string)
+      string = "";
+   ctx->Program.ErrorString = _mesa_strdup(string);
+}
+
+
+/**
+ * Delete a program and remove it from the hash table, ignoring the
+ * reference count.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_delete_program(GLcontext *ctx, GLuint id)
+{
+   struct program *prog = (struct program *)
+      _mesa_HashLookup(ctx->Shared->Programs, id);
+
+   if (prog) {
+      if (prog->String)
+         FREE(prog->String);
+      if (prog->Target == GL_VERTEX_PROGRAM_NV ||
+          prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
+         struct vertex_program *vprog = (struct vertex_program *) prog;
+         if (vprog->Instructions)
+            FREE(vprog->Instructions);
+      }
+      else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) {
+         struct fragment_program *fprog = (struct fragment_program *) prog;
+         if (fprog->Instructions)
+            FREE(fprog->Instructions);
+      }
+      _mesa_HashRemove(ctx->Shared->Programs, id);
+      FREE(prog);
+   }
+}
+
+
+/**
+ * Bind a program (make it current)
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_BindProgramNV(GLenum target, GLuint id)
+{
+   struct program *prog;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      if (ctx->VertexProgram.Current &&
+          ctx->VertexProgram.Current->Base.Id == id)
+         return;
+      /* decrement refcount on previously bound vertex program */
+      if (ctx->VertexProgram.Current) {
+         ctx->VertexProgram.Current->Base.RefCount--;
+         /* and delete if refcount goes below one */
+         if (ctx->VertexProgram.Current->Base.RefCount <= 0)
+            _mesa_delete_program(ctx, ctx->VertexProgram.Current->Base.Id);
+      }
+   }
+   else if (target == GL_FRAGMENT_PROGRAM_NV) {
+      if (ctx->FragmentProgram.Current &&
+          ctx->FragmentProgram.Current->Base.Id == id)
+         return;
+      /* decrement refcount on previously bound fragment program */
+      if (ctx->FragmentProgram.Current) {
+         ctx->FragmentProgram.Current->Base.RefCount--;
+         /* and delete if refcount goes below one */
+         if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
+            _mesa_delete_program(ctx, ctx->FragmentProgram.Current->Base.Id);
+      }
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV");
+      return;
+   }
+
+   /* NOTE: binding to a non-existant program is not an error.
+    * That's supposed to be caught in glBegin.
+    */
+   prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+
+   if (!prog && id > 0){
+      /* allocate new program */
+      if (target == GL_VERTEX_PROGRAM_NV) {
+         struct vertex_program *vprog = CALLOC_STRUCT(vertex_program);
+         if (!vprog) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV");
+            return;
+         }
+         prog = &(vprog->Base);
+      }
+      else if (target == GL_FRAGMENT_PROGRAM_NV) {
+         struct fragment_program *fprog = CALLOC_STRUCT(fragment_program);
+         if (!fprog) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV");
+            return;
+         }
+         prog = &(fprog->Base);
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV(target)");
+         return;
+      }
+      prog->Id = id;
+      prog->Target = target;
+      prog->Resident = GL_TRUE;
+      prog->RefCount = 1;
+      _mesa_HashInsert(ctx->Shared->Programs, id, prog);
+   }
+
+   /* bind now */
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      ctx->VertexProgram.Current = (struct vertex_program *) prog;
+   }
+   else if (target == GL_FRAGMENT_PROGRAM_NV) {
+      ctx->FragmentProgram.Current = (struct fragment_program *) prog;
+   }
+
+   if (prog)
+      prog->RefCount++;
+}
+
+
+/**
+ * Delete a list of programs.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_DeleteProgramsNV(GLsizei n, const GLuint *ids)
+{
+   GLint i;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (n < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
+      return;
+   }
+
+   for (i = 0; i < n; i++) {
+      if (ids[i] != 0) {
+         struct program *prog = (struct program *)
+            _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
+         if (prog) {
+            if (prog->Target == GL_VERTEX_PROGRAM_NV ||
+                prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
+               if (ctx->VertexProgram.Current &&
+                   ctx->VertexProgram.Current->Base.Id == ids[i]) {
+                  /* unbind this currently bound program */
+                  _mesa_BindProgramNV(prog->Target, 0);
+               }
+            }
+            else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) {
+               if (ctx->FragmentProgram.Current &&
+                   ctx->FragmentProgram.Current->Base.Id == ids[i]) {
+                  /* unbind this currently bound program */
+                  _mesa_BindProgramNV(prog->Target, 0);
+               }
+            }
+            else {
+               _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
+               return;
+            }
+            prog->RefCount--;
+            if (prog->RefCount <= 0) {
+               _mesa_delete_program(ctx, ids[i]);
+            }
+         }
+      }
+   }
+}
+
+
+/**
+ * Execute a vertex state program.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params)
+{
+   struct vertex_program *vprog;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target != GL_VERTEX_STATE_PROGRAM_NV) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV");
+      return;
+   }
+
+   vprog = (struct vertex_program *)
+      _mesa_HashLookup(ctx->Shared->Programs, id);
+
+   if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV");
+      return;
+   }
+   
+   _mesa_init_vp_registers(ctx);
+   _mesa_init_tracked_matrices(ctx);
+   COPY_4V(ctx->VertexProgram.Machine.Registers[VP_INPUT_REG_START], params);
+   _mesa_exec_vertex_program(ctx, vprog);
+}
+
+
+/**
+ * Generate a list of new program identifiers.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GenProgramsNV(GLsizei n, GLuint *ids)
+{
+   GLuint first;
+   GLuint i;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (n < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGenProgramsNV");
+      return;
+   }
+
+   if (!ids)
+      return;
+
+   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
+
+   for (i = 0; i < (GLuint) n; i++) {
+      const int bytes = MAX2(sizeof(struct vertex_program),
+                             sizeof(struct fragment_program));
+      struct program *prog = (struct program *) CALLOC(bytes);
+      if (!prog) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenProgramsNV");
+         return;
+      }
+      prog->RefCount = 1;
+      prog->Id = first + i;
+      _mesa_HashInsert(ctx->Shared->Programs, first + i, prog);
+   }
+
+   /* Return the program names */
+   for (i = 0; i < (GLuint) n; i++) {
+      ids[i] = first + i;
+   }
+}
+
+
+/**
+ * Determine if a set of programs is resident in hardware.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+GLboolean _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids,
+                                      GLboolean *residences)
+{
+   GLint i;
+   GLboolean retVal = GL_TRUE;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+   if (n < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)");
+      return GL_FALSE;
+   }
+
+   for (i = 0; i < n; i++) {
+      struct program *prog;
+
+      if (ids[i] == 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(id=0)");
+         return GL_FALSE;
+      }
+
+      prog = (struct program *)
+                   _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
+      if (!prog) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(id)");
+         return GL_FALSE;
+      }
+
+      if (!prog->Resident) {
+         retVal = GL_FALSE;
+         break;
+      }
+   }
+
+   /* only write to residences if returning false! */
+   if (retVal == GL_FALSE) {
+      for (i = 0; i < n; i++) {
+         const struct program *prog = (const struct program *)
+            _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
+         residences[i] = prog->Resident;
+      }
+   }
+
+   return retVal;
+}
+
+
+/**
+ * Request that a set of programs be resident in hardware.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids)
+{
+   GLint i;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (n < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)");
+      return;
+   }
+
+   /* just error checking for now */
+   for (i = 0; i < n; i++) {
+      struct program *prog;
+
+      if (ids[i] == 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
+         return;
+      }
+
+      prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
+
+      if (!prog) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
+         return;
+      }
+
+      prog->Resident = GL_TRUE;
+   }
+}
+
+
+/**
+ * Get a program parameter register.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetProgramParameterfvNV(GLenum target, GLuint index,
+                              GLenum pname, GLfloat *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      if (pname == GL_PROGRAM_PARAMETER_NV) {
+         if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
+            index += VP_PROG_REG_START;
+            COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
+         }
+         else {
+            _mesa_error(ctx, GL_INVALID_VALUE,
+                        "glGetProgramParameterfvNV(index)");
+            return;
+         }
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)");
+         return;
+      }
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)");
+      return;
+   }
+}
+
+
+/**
+ * Get a program parameter register.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetProgramParameterdvNV(GLenum target, GLuint index,
+                              GLenum pname, GLdouble *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      if (pname == GL_PROGRAM_PARAMETER_NV) {
+         if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
+            index += VP_PROG_REG_START;
+            COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
+         }
+         else {
+            _mesa_error(ctx, GL_INVALID_VALUE,
+                        "glGetProgramParameterdvNV(index)");
+            return;
+         }
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)");
+         return;
+      }
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)");
+      return;
+   }
+}
+
+
+/**
+ * Get a program attribute.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
+{
+   struct program *prog;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+   if (!prog) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
+      return;
+   }
+
+   switch (pname) {
+      case GL_PROGRAM_TARGET_NV:
+         *params = prog->Target;
+         return;
+      case GL_PROGRAM_LENGTH_NV:
+         *params = prog->String ? _mesa_strlen((char *) prog->String) : 0;
+         return;
+      case GL_PROGRAM_RESIDENT_NV:
+         *params = prog->Resident;
+         return;
+      default:
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
+         return;
+   }
+}
+
+
+/**
+ * Get the program source code.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
+{
+   struct program *prog;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (pname != GL_PROGRAM_STRING_NV) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
+      return;
+   }
+
+   prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+   if (!prog) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
+      return;
+   }
+
+   if (prog->String) {
+      MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String));
+   }
+   else {
+      program[0] = 0;
+   }
+}
+
+
+/**
+ * Get matrix tracking information.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
+                         GLenum pname, GLint *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      GLuint i;
+
+      if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
+         return;
+      }
+
+      i = address / 4;
+
+      switch (pname) {
+         case GL_TRACK_MATRIX_NV:
+            params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
+            return;
+         case GL_TRACK_MATRIX_TRANSFORM_NV:
+            params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
+            return;
+         default:
+            _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
+            return;
+      }
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
+      return;
+   }
+}
+
+
+/**
+ * Get a vertex (or vertex array) attribute.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (index == 0 || index >= VP_NUM_INPUT_REGS) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
+      return;
+   }
+
+   switch (pname) {
+      case GL_ATTRIB_ARRAY_SIZE_NV:
+         params[0] = ctx->Array.VertexAttrib[index].Size;
+         break;
+      case GL_ATTRIB_ARRAY_STRIDE_NV:
+         params[0] = ctx->Array.VertexAttrib[index].Stride;
+         break;
+      case GL_ATTRIB_ARRAY_TYPE_NV:
+         params[0] = ctx->Array.VertexAttrib[index].Type;
+         break;
+      case GL_CURRENT_ATTRIB_NV:
+         COPY_4V(params, ctx->Current.Attrib[index]);
+         break;
+      default:
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
+         return;
+   }
+}
+
+/**
+ * Get a vertex (or vertex array) attribute.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (index == 0 || index >= VP_NUM_INPUT_REGS) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
+      return;
+   }
+
+   switch (pname) {
+      case GL_ATTRIB_ARRAY_SIZE_NV:
+         params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Size;
+         break;
+      case GL_ATTRIB_ARRAY_STRIDE_NV:
+         params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Stride;
+         break;
+      case GL_ATTRIB_ARRAY_TYPE_NV:
+         params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Type;
+         break;
+      case GL_CURRENT_ATTRIB_NV:
+         COPY_4V(params, ctx->Current.Attrib[index]);
+         break;
+      default:
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
+         return;
+   }
+}
+
+/**
+ * Get a vertex (or vertex array) attribute.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (index == 0 || index >= VP_NUM_INPUT_REGS) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
+      return;
+   }
+
+   switch (pname) {
+      case GL_ATTRIB_ARRAY_SIZE_NV:
+         params[0] = ctx->Array.VertexAttrib[index].Size;
+         break;
+      case GL_ATTRIB_ARRAY_STRIDE_NV:
+         params[0] = ctx->Array.VertexAttrib[index].Stride;
+         break;
+      case GL_ATTRIB_ARRAY_TYPE_NV:
+         params[0] = ctx->Array.VertexAttrib[index].Type;
+         break;
+      case GL_CURRENT_ATTRIB_NV:
+         COPY_4V_CAST(params, ctx->Current.Attrib[index], GLint);
+         break;
+      default:
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
+         return;
+   }
+}
+
+
+/**
+ * Get a vertex array attribute pointer.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
+      return;
+   }
+
+   if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
+      return;
+   }
+
+   *pointer = ctx->Array.VertexAttrib[index].Ptr;;
+}
+
+
+/**
+ * Determine if id names a program.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ * \param id is the program identifier
+ * \return GL_TRUE if id is a program, else GL_FALSE.
+ */
+GLboolean _mesa_IsProgramNV(GLuint id)
+{
+   struct program *prog;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+   if (id == 0)
+      return GL_FALSE;
+
+   prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+   if (prog && prog->Target)
+      return GL_TRUE;
+   else
+      return GL_FALSE;
+}
+
+
+/**
+ * Load a program.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
+                    const GLubyte *program)
+{
+   struct program *prog;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (id == 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
+      return;
+   }
+
+   prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+
+   if (prog && prog->Target != 0 && prog->Target != target) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
+      return;
+   }
+
+   /* Reset error pos and string */
+   _mesa_set_program_error(ctx, -1, NULL);
+
+   if (target == GL_VERTEX_PROGRAM_NV ||
+       target == GL_VERTEX_STATE_PROGRAM_NV) {
+      struct vertex_program *vprog = (struct vertex_program *) prog;
+      if (!vprog) {
+         vprog = CALLOC_STRUCT(vertex_program);
+         if (!vprog) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+            return;
+         }
+         vprog->Base.RefCount = 1;
+         vprog->Base.Resident = GL_TRUE;
+         _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
+      }
+      _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
+   }
+   else if (target == GL_FRAGMENT_PROGRAM_NV) {
+      struct fragment_program *fprog = (struct fragment_program *) prog;
+      if (!fprog) {
+         fprog = CALLOC_STRUCT(fragment_program);
+         if (!fprog) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+            return;
+         }
+         fprog->Base.RefCount = 1;
+         fprog->Base.Resident = GL_TRUE;
+         _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
+      }
+      _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "LoadProgramNV(target)");
+   }
+}
+
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_ProgramParameter4dNV(GLenum target, GLuint index,
+                           GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+   _mesa_ProgramParameter4fNV(target, index, x, y, z, w);
+}
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_ProgramParameter4dvNV(GLenum target, GLuint index,
+                            const GLdouble *params)
+{
+   _mesa_ProgramParameter4fNV(target, index,
+                              params[0], params[1], params[2], params[3]);
+}
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_ProgramParameter4fNV(GLenum target, GLuint index,
+                           GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
+         index += VP_PROG_REG_START;
+         ASSIGN_4V(ctx->VertexProgram.Machine.Registers[index], x, y, z, w);
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameterrNV(index)");
+         return;
+      }
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameterrNV");
+      return;
+   }
+}
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_ProgramParameter4fvNV(GLenum target, GLuint index,
+                            const GLfloat *params)
+{
+   _mesa_ProgramParameter4fNV(target, index,
+                              params[0], params[1], params[2], params[3]);
+}
+
+
+
+/**
+ * Set a sequence of program parameter registers.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_ProgramParameters4dvNV(GLenum target, GLuint index,
+                             GLuint num, const GLdouble *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      GLuint i;
+      if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV");
+         return;
+      }
+      index += VP_PROG_REG_START;
+      for (i = 0; i < num; i++) {
+         COPY_4V_CAST(ctx->VertexProgram.Machine.Registers[index + i], 
+                      params, GLfloat);
+         params += 4;
+      };
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV");
+      return;
+   }
+}
+
+
+/**
+ * Set a sequence of program parameter registers.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_ProgramParameters4fvNV(GLenum target, GLuint index,
+                             GLuint num, const GLfloat *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      GLuint i;
+      if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
+         return;
+      }
+      index += VP_PROG_REG_START;
+      for (i = 0; i < num; i++) {
+         COPY_4V(ctx->VertexProgram.Machine.Registers[index + i], params);
+         params += 4;
+      };
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV");
+      return;
+   }
+}
+
+
+
+/**
+ * Setup tracking of matrices into program parameter registers.
+ * \note Called from the GL API dispatcher.
+ */
+void
+_mesa_TrackMatrixNV(GLenum target, GLuint address,
+                    GLenum matrix, GLenum transform)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_VERTEX_PROGRAM_NV) {
+      if (address & 0x3) {
+         /* addr must be multiple of four */
+         _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)");
+         return;
+      }
+
+      switch (matrix) {
+         case GL_NONE:
+         case GL_MODELVIEW:
+         case GL_PROJECTION:
+         case GL_TEXTURE:
+         case GL_COLOR:
+         case GL_MODELVIEW_PROJECTION_NV:
+         case GL_MATRIX0_NV:
+         case GL_MATRIX1_NV:
+         case GL_MATRIX2_NV:
+         case GL_MATRIX3_NV:
+         case GL_MATRIX4_NV:
+         case GL_MATRIX5_NV:
+         case GL_MATRIX6_NV:
+         case GL_MATRIX7_NV:
+            /* OK, fallthrough */
+            break;
+         default:
+            _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)");
+            return;
+      }
+
+      switch (transform) {
+         case GL_IDENTITY_NV:
+         case GL_INVERSE_NV:
+         case GL_TRANSPOSE_NV:
+         case GL_INVERSE_TRANSPOSE_NV:
+            /* OK, fallthrough */
+            break;
+         default:
+            _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)");
+            return;
+      }
+
+      ctx->VertexProgram.TrackMatrix[address / 4] = matrix;
+      ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform;
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)");
+      return;
+   }
+}
+
+
+static GLfloat *
+lookup_program_parameter(struct fragment_program *fprog,
+                         GLsizei len, const GLubyte *name)
+{
+   return NULL;
+}
+
+
+void
+glProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
+                            GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   struct program *prog;
+   GLfloat *p;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+   if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV");
+      return;
+   }
+
+   if (len <= 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
+      return;
+   }
+
+   p = lookup_program_parameter((struct fragment_program *) prog, len, name);
+   if (!p) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
+      return;
+   }
+
+   p[0] = x;
+   p[1] = y;
+   p[2] = z;
+   p[3] = w;
+}
+
+
+void
+glProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
+                             const float v[])
+{
+   glProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
+}
+
+
+void
+glProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
+                            GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+   glProgramNamedParameter4fNV(id, len, name, x, y, z, w);
+}
+
+
+void
+glProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
+                             const double v[])
+{
+   glProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
+}
+
+
+void
+glGetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
+                               GLfloat *params)
+{
+   struct program *prog;
+   const GLfloat *p;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+   if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV");
+      return;
+   }
+
+   if (len <= 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
+      return;
+   }
+
+   p = lookup_program_parameter((struct fragment_program *) prog, len, name);
+   if (!p) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
+      return;
+   }
+
+   params[0] = p[0];
+   params[1] = p[1];
+   params[2] = p[2];
+   params[3] = p[3];
+}
+
+
+void
+glGetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
+                               GLdouble *params)
+{
+   GLfloat floatParams[4];
+   glGetProgramNamedParameterfvNV(id, len, name, floatParams);
+   COPY_4V(params, floatParams);
+}
+
+
+void
+glProgramLocalParameter4fARB(GLenum target, GLuint index,
+                             GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_FRAGMENT_PROGRAM_NV) {
+      struct fragment_program *fprog = ctx->FragmentProgram.Current;
+      if (!fprog) {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
+         return;
+      }
+      if (index >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
+         return;
+      }
+      fprog->LocalParams[index][0] = x;
+      fprog->LocalParams[index][1] = y;
+      fprog->LocalParams[index][2] = z;
+      fprog->LocalParams[index][3] = w;
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
+      return;
+   }
+}
+
+
+void
+glProgramLocalParameter4fvARB(GLenum target, GLuint index,
+                              const GLfloat *params)
+{
+   glProgramLocalParameter4fARB(target, index, params[0], params[1],
+                                params[2], params[3]);
+}
+
+
+void
+glProgramLocalParameter4dARB(GLenum target, GLuint index,
+                             GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+   glProgramLocalParameter4fARB(target, index, x, y, z, w);
+}
+
+
+void
+glProgramLocalParameter4dvARB(GLenum target, GLuint index,
+                              const GLdouble *params)
+{
+   glProgramLocalParameter4fARB(target, index, params[0], params[1],
+                                params[2], params[3]);
+}
+
+
+void
+glGetProgramLocalParameterfvARB(GLenum target, GLuint index, GLfloat *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (target == GL_FRAGMENT_PROGRAM_NV) {
+      struct fragment_program *fprog = ctx->FragmentProgram.Current;
+      if (!fprog) {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramLocalParameterARB");
+         return;
+      }
+      if (index >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramLocalParameterARB");
+         return;
+      }
+      params[0] = fprog->LocalParams[index][0];
+      params[1] = fprog->LocalParams[index][1];
+      params[2] = fprog->LocalParams[index][2];
+      params[3] = fprog->LocalParams[index][3];
+   }
+   else {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramLocalParameterARB");
+      return;
+   }
+}
+
+
+void
+glGetProgramLocalParameterdvARB(GLenum target, GLuint index, GLdouble *params)
+{
+   GLfloat floatParams[4];
+   glGetProgramLocalParameterfvARB(target, index, floatParams);
+   COPY_4V(params, floatParams);
+}
diff --git a/src/mesa/main/nvprogram.h b/src/mesa/main/nvprogram.h
new file mode 100644 (file)
index 0000000..3ede705
--- /dev/null
@@ -0,0 +1,156 @@
+/* $Id: nvprogram.h,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.1
+ *
+ * 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:
+ *    Brian Paul
+ */
+
+
+#ifndef NVPROGRAM_H
+#define NVPROGRAM_H
+
+
+extern void
+_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string);
+
+extern void
+_mesa_delete_program(GLcontext *ctx, GLuint id);
+
+
+extern void
+_mesa_BindProgramNV(GLenum target, GLuint id);
+
+extern void
+_mesa_DeleteProgramsNV(GLsizei n, const GLuint *ids);
+
+extern void
+_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params);
+
+extern void
+_mesa_GenProgramsNV(GLsizei n, GLuint *ids);
+
+extern GLboolean
+_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, GLboolean *residences);
+
+extern void
+_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids);
+
+
+extern void
+_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, GLenum pname, GLfloat *params);
+
+extern void
+_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, GLenum pname, GLdouble *params);
+
+extern void
+_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params);
+
+extern void
+_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program);
+
+extern void
+_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, GLenum pname, GLint *params);
+
+extern void
+_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params);
+
+extern void
+_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params);
+
+extern void
+_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params);
+
+extern void
+_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer);
+
+extern GLboolean
+_mesa_IsProgramNV(GLuint id);
+
+extern void
+_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+
+extern void
+_mesa_ProgramParameter4dNV(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+
+extern void
+_mesa_ProgramParameter4dvNV(GLenum target, GLuint index, const GLdouble *params);
+
+extern void
+_mesa_ProgramParameter4fNV(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+extern void
+_mesa_ProgramParameter4fvNV(GLenum target, GLuint index, const GLfloat *params);
+
+extern void
+_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, GLuint num, const GLdouble *params);
+
+extern void
+_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, GLuint num, const GLfloat *params);
+
+extern void
+_mesa_TrackMatrixNV(GLenum target, GLuint address, GLenum matrix, GLenum transform);
+
+
+extern void
+_mesa_VertexAttribs1svNV(GLuint index, GLsizei n, const GLshort *v);
+
+extern void
+_mesa_VertexAttribs1fvNV(GLuint index, GLsizei n, const GLfloat *v);
+
+extern void
+_mesa_VertexAttribs1dvNV(GLuint index, GLsizei n, const GLdouble *v);
+
+extern void
+_mesa_VertexAttribs2svNV(GLuint index, GLsizei n, const GLshort *v);
+
+extern void
+_mesa_VertexAttribs2fvNV(GLuint index, GLsizei n, const GLfloat *v);
+
+extern void
+_mesa_VertexAttribs2dvNV(GLuint index, GLsizei n, const GLdouble *v);
+
+extern void
+_mesa_VertexAttribs3svNV(GLuint index, GLsizei n, const GLshort *v);
+
+extern void
+_mesa_VertexAttribs3fvNV(GLuint index, GLsizei n, const GLfloat *v);
+
+extern void
+_mesa_VertexAttribs3dvNV(GLuint index, GLsizei n, const GLdouble *v);
+
+extern void
+_mesa_VertexAttribs4svNV(GLuint index, GLsizei n, const GLshort *v);
+
+extern void
+_mesa_VertexAttribs4fvNV(GLuint index, GLsizei n, const GLfloat *v);
+
+extern void
+_mesa_VertexAttribs4dvNV(GLuint index, GLsizei n, const GLdouble *v);
+
+extern void
+_mesa_VertexAttribs4ubvNV(GLuint index, GLsizei n, const GLubyte *v);
+
+
+#endif
diff --git a/src/mesa/main/nvvertexec.c b/src/mesa/main/nvvertexec.c
new file mode 100644 (file)
index 0000000..59fc969
--- /dev/null
@@ -0,0 +1,699 @@
+/* $Id: nvvertexec.c,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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.
+ */
+
+/**
+ * \file nvvertexec.c
+ * \brief Code to execute vertex programs.
+ * \author Brian Paul
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "nvvertexec.h"
+#include "nvvertprog.h"
+#include "mmath.h"
+#include "math/m_matrix.h"
+
+
+/**
+ * Load/initialize the vertex program registers.
+ * This needs to be done per vertex.
+ */
+void
+_mesa_init_vp_registers(GLcontext *ctx)
+{
+   struct vp_machine *machine = &(ctx->VertexProgram.Machine);
+   GLuint i;
+
+   /* Input registers get initialized from the current vertex attribs */
+   MEMCPY(machine->Registers[VP_INPUT_REG_START],
+          ctx->Current.Attrib,
+          16 * 4 * sizeof(GLfloat));
+
+   /* Output and temp regs are initialized to [0,0,0,1] */
+   for (i = VP_OUTPUT_REG_START; i <= VP_OUTPUT_REG_END; i++) {
+      machine->Registers[i][0] = 0.0F;
+      machine->Registers[i][1] = 0.0F;
+      machine->Registers[i][2] = 0.0F;
+      machine->Registers[i][3] = 1.0F;
+   }
+   for (i = VP_TEMP_REG_START; i <= VP_TEMP_REG_END; i++) {
+      machine->Registers[i][0] = 0.0F;
+      machine->Registers[i][1] = 0.0F;
+      machine->Registers[i][2] = 0.0F;
+      machine->Registers[i][3] = 1.0F;
+   }
+
+   /* The program regs aren't touched */
+}
+
+
+
+/**
+ * Copy the 16 elements of a matrix into four consecutive program
+ * registers starting at 'pos'.
+ */
+static void
+load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16])
+{
+   GLuint i;
+   pos += VP_PROG_REG_START;
+   for (i = 0; i < 4; i++) {
+      registers[pos + i][0] = mat[0 + i];
+      registers[pos + i][1] = mat[4 + i];
+      registers[pos + i][2] = mat[8 + i];
+      registers[pos + i][3] = mat[12 + i];
+   }
+}
+
+
+/**
+ * As above, but transpose the matrix.
+ */
+static void
+load_transpose_matrix(GLfloat registers[][4], GLuint pos,
+                      const GLfloat mat[16])
+{
+   pos += VP_PROG_REG_START;
+   MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat));
+}
+
+
+/**
+ * Load all currently tracked matrices into the program registers.
+ * This needs to be done per glBegin/glEnd.
+ */
+void
+_mesa_init_tracked_matrices(GLcontext *ctx)
+{
+   GLuint i;
+
+   for (i = 0; i < VP_NUM_PROG_REGS / 4; i++) {
+      /* point 'mat' at source matrix */
+      GLmatrix *mat;
+      if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) {
+         mat = ctx->ModelviewMatrixStack.Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) {
+         mat = ctx->ProjectionMatrixStack.Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) {
+         mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) {
+         mat = ctx->ColorMatrixStack.Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) {
+         /* XXX verify the combined matrix is up to date */
+         mat = &ctx->_ModelProjectMatrix;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV &&
+               ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) {
+         GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV;
+         ASSERT(n < MAX_PROGRAM_MATRICES);
+         mat = ctx->ProgramMatrixStack[n].Top;
+      }
+      else {
+         /* no matrix is tracked, but we leave the register values as-is */
+         assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE);
+         continue;
+      }
+
+      /* load the matrix */
+      if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) {
+         load_matrix(ctx->VertexProgram.Machine.Registers, i*4, mat->m);
+      }
+      else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) {
+         _math_matrix_analyse(mat); /* update the inverse */
+         assert((mat->flags & MAT_DIRTY_INVERSE) == 0);
+         load_matrix(ctx->VertexProgram.Machine.Registers, i*4, mat->inv);
+      }
+      else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) {
+         load_transpose_matrix(ctx->VertexProgram.Machine.Registers, i*4, mat->m);
+      }
+      else {
+         assert(ctx->VertexProgram.TrackMatrixTransform[i]
+                == GL_INVERSE_TRANSPOSE_NV);
+         _math_matrix_analyse(mat); /* update the inverse */
+         assert((mat->flags & MAT_DIRTY_INVERSE) == 0);
+         load_transpose_matrix(ctx->VertexProgram.Machine.Registers,
+                               i*4, mat->inv);
+      }
+   }
+}
+
+
+
+/**
+ * For debugging.  Dump the current vertex program machine registers.
+ */
+void
+_mesa_dump_vp_machine( const struct vp_machine *machine )
+{
+   int i;
+   _mesa_printf("VertexIn:\n");
+   for (i = 0; i < VP_NUM_INPUT_REGS; i++) {
+      _mesa_printf("%d: %f %f %f %f   ", i,
+             machine->Registers[i + VP_INPUT_REG_START][0],
+             machine->Registers[i + VP_INPUT_REG_START][1],
+             machine->Registers[i + VP_INPUT_REG_START][2],
+             machine->Registers[i + VP_INPUT_REG_START][3]);
+   }
+   _mesa_printf("\n");
+
+   _mesa_printf("VertexOut:\n");
+   for (i = 0; i < VP_NUM_OUTPUT_REGS; i++) {
+      _mesa_printf("%d: %f %f %f %f   ", i,
+             machine->Registers[i + VP_OUTPUT_REG_START][0],
+             machine->Registers[i + VP_OUTPUT_REG_START][1],
+             machine->Registers[i + VP_OUTPUT_REG_START][2],
+             machine->Registers[i + VP_OUTPUT_REG_START][3]);
+   }
+   _mesa_printf("\n");
+
+   _mesa_printf("Registers:\n");
+   for (i = 0; i < VP_NUM_TEMP_REGS; i++) {
+      _mesa_printf("%d: %f %f %f %f   ", i,
+             machine->Registers[i + VP_TEMP_REG_START][0],
+             machine->Registers[i + VP_TEMP_REG_START][1],
+             machine->Registers[i + VP_TEMP_REG_START][2],
+             machine->Registers[i + VP_TEMP_REG_START][3]);
+   }
+   _mesa_printf("\n");
+
+   _mesa_printf("Parameters:\n");
+   for (i = 0; i < VP_NUM_PROG_REGS; i++) {
+      _mesa_printf("%d: %f %f %f %f   ", i,
+             machine->Registers[i + VP_PROG_REG_START][0],
+             machine->Registers[i + VP_PROG_REG_START][1],
+             machine->Registers[i + VP_PROG_REG_START][2],
+             machine->Registers[i + VP_PROG_REG_START][3]);
+   }
+   _mesa_printf("\n");
+}
+
+
+/**
+ * Fetch a 4-element float vector from the given source register.
+ * Apply swizzling and negating as needed.
+ */
+static void
+fetch_vector4( const struct vp_src_register *source,
+               const struct vp_machine *machine,
+               GLfloat result[4] )
+{
+   static const GLfloat zero[4] = { 0, 0, 0, 0 };
+   const GLfloat *src;
+
+   if (source->RelAddr) {
+      GLint reg = source->Register + machine->AddressReg;
+      if (reg < VP_PROG_REG_START || reg > VP_PROG_REG_END)
+         src = zero;
+      else
+         src = machine->Registers[reg];
+   }
+   else {
+      src = machine->Registers[source->Register];
+   }
+
+   if (source->Negate) {
+      result[0] = -src[source->Swizzle[0]];
+      result[1] = -src[source->Swizzle[1]];
+      result[2] = -src[source->Swizzle[2]];
+      result[3] = -src[source->Swizzle[3]];
+   }
+   else {
+      result[0] = src[source->Swizzle[0]];
+      result[1] = src[source->Swizzle[1]];
+      result[2] = src[source->Swizzle[2]];
+      result[3] = src[source->Swizzle[3]];
+   }
+}
+
+
+/**
+ * As above, but only return result[0] element.
+ */
+static void
+fetch_vector1( const struct vp_src_register *source,
+               const struct vp_machine *machine,
+               GLfloat result[4] )
+{
+   static const GLfloat zero[4] = { 0, 0, 0, 0 };
+   const GLfloat *src;
+
+   if (source->RelAddr) {
+      GLint reg = source->Register + machine->AddressReg;
+      if (reg < VP_PROG_REG_START || reg > VP_PROG_REG_END)
+         src = zero;
+      else
+         src = machine->Registers[reg];
+   }
+   else {
+      src = machine->Registers[source->Register];
+   }
+
+   if (source->Negate) {
+      result[0] = -src[source->Swizzle[0]];
+   }
+   else {
+      result[0] = src[source->Swizzle[0]];
+   }
+}
+
+
+/**
+ * Store 4 floats into a register.
+ */
+static void
+store_vector4( const struct vp_dst_register *dest, struct vp_machine *machine,
+               const GLfloat value[4] )
+{
+   GLfloat *dst = machine->Registers[dest->Register];
+
+   if (dest->WriteMask[0])
+      dst[0] = value[0];
+   if (dest->WriteMask[1])
+      dst[1] = value[1];
+   if (dest->WriteMask[2])
+      dst[2] = value[2];
+   if (dest->WriteMask[3])
+      dst[3] = value[3];
+}
+
+
+/**
+ * Set x to positive or negative infinity.
+ */
+#ifdef USE_IEEE
+#define SET_POS_INFINITY(x)  ( *((GLuint *) &x) = 0x7F800000 )
+#define SET_NEG_INFINITY(x)  ( *((GLuint *) &x) = 0xFF800000 )
+#elif defined(VMS)
+#define SET_POS_INFINITY(x)  x = __MAXFLOAT
+#define SET_NEG_INFINITY(x)  x = -__MAXFLOAT
+#else
+#define SET_POS_INFINITY(x)  x = (GLfloat) HUGE_VAL
+#define SET_NEG_INFINITY(x)  x = (GLfloat) -HUGE_VAL
+#endif
+
+#define SET_FLOAT_BITS(x, bits) ((fi_type *) &(x))->i = bits
+
+
+/**
+ * Execute the given vertex program
+ */
+void
+_mesa_exec_vertex_program(GLcontext *ctx, const struct vertex_program *program)
+{
+   struct vp_machine *machine = &ctx->VertexProgram.Machine;
+   const struct vp_instruction *inst;
+
+   /* XXX load vertex fields into input registers */
+   /* and do other initialization */
+
+
+   for (inst = program->Instructions; inst->Opcode != VP_OPCODE_END; inst++) {
+      switch (inst->Opcode) {
+         case VP_OPCODE_MOV:
+            {
+               GLfloat t[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               store_vector4( &inst->DstReg, machine, t );
+            }
+            break;
+         case VP_OPCODE_LIT:
+            {
+               const GLfloat epsilon = 1.0e-5F; /* XXX fix? */
+               GLfloat t[4], lit[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               if (t[3] < -(128.0F - epsilon))
+                   t[3] = - (128.0F - epsilon);
+               else if (t[3] > 128.0F - epsilon)
+                  t[3] = 128.0F - epsilon;
+               if (t[0] < 0.0)
+                  t[0] = 0.0;
+               if (t[1] < 0.0)
+                  t[1] = 0.0;
+               lit[0] = 1.0;
+               lit[1] = t[0];
+               lit[2] = (t[0] > 0.0) ? (GLfloat) exp(t[3] * log(t[1])) : 0.0F;
+               lit[3] = 1.0;
+               store_vector4( &inst->DstReg, machine, lit );
+            }
+            break;
+         case VP_OPCODE_RCP:
+            {
+               GLfloat t[4];
+               fetch_vector1( &inst->SrcReg[0], machine, t );
+               if (t[0] != 1.0F)
+                  t[0] = 1.0F / t[0];  /* div by zero is infinity! */
+               t[1] = t[2] = t[3] = t[0];
+               store_vector4( &inst->DstReg, machine, t );
+            }
+            break;
+         case VP_OPCODE_RSQ:
+            {
+               GLfloat t[4];
+               fetch_vector1( &inst->SrcReg[0], machine, t );
+               t[0] = (float) (1.0 / sqrt(fabs(t[0])));
+               t[1] = t[2] = t[3] = t[0];
+               store_vector4( &inst->DstReg, machine, t );
+            }
+            break;
+         case VP_OPCODE_EXP:
+            {
+               GLfloat t[4], q[4], floor_t0;
+               fetch_vector1( &inst->SrcReg[0], machine, t );
+               floor_t0 = (float) floor(t[0]);
+               if (floor_t0 > FLT_MAX_EXP) {
+                  SET_POS_INFINITY(q[0]);
+                  q[1] = 0.0F;
+                  SET_POS_INFINITY(q[2]);
+                  q[3] = 1.0F;
+               }
+               else if (floor_t0 < FLT_MIN_EXP) {
+                  q[0] = 0.0F;
+                  q[1] = 0.0F;
+                  q[2] = 0.0F;
+                  q[3] = 0.0F;
+               }
+               else {
+#ifdef USE_IEEE
+                  GLint ii = (GLint) floor_t0;
+                  ii = (ii < 23) + 0x3f800000;
+                  SET_FLOAT_BITS(q[0], ii);
+                  q[0] = *((GLfloat *) &ii);
+#else
+                  q[0] = (GLfloat) pow(2.0, floor_t0);
+#endif
+                  q[1] = t[0] - floor_t0;
+                  q[2] = (GLfloat) (q[0] * LOG2(q[1]));
+                  q[3] = 1.0F;
+               }
+               store_vector4( &inst->DstReg, machine, t );
+            }
+            break;
+         case VP_OPCODE_LOG:
+            {
+               GLfloat t[4], q[4], abs_t0;
+               fetch_vector1( &inst->SrcReg[0], machine, t );
+               abs_t0 = (GLfloat) fabs(t[0]);
+               if (abs_t0 != 0.0F) {
+                  /* Since we really can't handle infinite values on VMS
+                   * like other OSes we'll use __MAXFLOAT to represent
+                   * infinity.  This may need some tweaking.
+                   */
+#ifdef VMS
+                  if (abs_t0 == __MAXFLOAT) {
+#else
+                  if (IS_INF_OR_NAN(abs_t0)) {
+#endif
+                     SET_POS_INFINITY(q[0]);
+                     q[1] = 1.0F;
+                     SET_POS_INFINITY(q[2]);
+                  }
+                  else {
+                     int exponent;
+                     double mantissa = frexp(t[0], &exponent);
+                     q[0] = (GLfloat) (exponent - 1);
+                     q[1] = (GLfloat) (2.0 * mantissa); /* map [.5, 1) -> [1, 2) */
+                     q[2] = (GLfloat) (q[0] + LOG2(q[1]));
+                  }
+               }
+               else {
+                  SET_NEG_INFINITY(q[0]);
+                  q[1] = 1.0F;
+                  SET_NEG_INFINITY(q[2]);
+               }
+               q[3] = 1.0;
+               store_vector4( &inst->DstReg, machine, q );
+            }
+            break;
+         case VP_OPCODE_MUL:
+            {
+               GLfloat t[4], u[4], prod[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               prod[0] = t[0] * u[0];
+               prod[1] = t[1] * u[1];
+               prod[2] = t[2] * u[2];
+               prod[3] = t[3] * u[3];
+               store_vector4( &inst->DstReg, machine, prod );
+            }
+            break;
+         case VP_OPCODE_ADD:
+            {
+               GLfloat t[4], u[4], sum[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               sum[0] = t[0] + u[0];
+               sum[1] = t[1] + u[1];
+               sum[2] = t[2] + u[2];
+               sum[3] = t[3] + u[3];
+               store_vector4( &inst->DstReg, machine, sum );
+            }
+            break;
+         case VP_OPCODE_DP3:
+            {
+               GLfloat t[4], u[4], dot[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               dot[0] = t[0] * u[0] + t[1] * u[1] + t[2] * u[2];
+               dot[1] = dot[2] = dot[3] = dot[0];
+               store_vector4( &inst->DstReg, machine, dot );
+            }
+            break;
+         case VP_OPCODE_DP4:
+            {
+               GLfloat t[4], u[4], dot[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               dot[0] = t[0] * u[0] + t[1] * u[1] + t[2] * u[2] + t[3] * u[3];
+               dot[1] = dot[2] = dot[3] = dot[0];
+               store_vector4( &inst->DstReg, machine, dot );
+            }
+            break;
+         case VP_OPCODE_DST:
+            {
+               GLfloat t[4], u[4], dst[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               dst[0] = 1.0F;
+               dst[1] = t[1] * u[1];
+               dst[2] = t[2];
+               dst[3] = u[3];
+               store_vector4( &inst->DstReg, machine, dst );
+            }
+            break;
+         case VP_OPCODE_MIN:
+            {
+               GLfloat t[4], u[4], min[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               min[0] = (t[0] < u[0]) ? t[0] : u[0];
+               min[1] = (t[1] < u[1]) ? t[1] : u[1];
+               min[2] = (t[2] < u[2]) ? t[2] : u[2];
+               min[3] = (t[3] < u[3]) ? t[3] : u[3];
+               store_vector4( &inst->DstReg, machine, min );
+            }
+            break;
+         case VP_OPCODE_MAX:
+            {
+               GLfloat t[4], u[4], max[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               max[0] = (t[0] > u[0]) ? t[0] : u[0];
+               max[1] = (t[1] > u[1]) ? t[1] : u[1];
+               max[2] = (t[2] > u[2]) ? t[2] : u[2];
+               max[3] = (t[3] > u[3]) ? t[3] : u[3];
+               store_vector4( &inst->DstReg, machine, max );
+            }
+            break;
+         case VP_OPCODE_SLT:
+            {
+               GLfloat t[4], u[4], slt[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               slt[0] = (t[0] < u[0]) ? 1.0F : 0.0F;
+               slt[1] = (t[1] < u[1]) ? 1.0F : 0.0F;
+               slt[2] = (t[2] < u[2]) ? 1.0F : 0.0F;
+               slt[3] = (t[3] < u[3]) ? 1.0F : 0.0F;
+               store_vector4( &inst->DstReg, machine, slt );
+            }
+            break;
+         case VP_OPCODE_SGE:
+            {
+               GLfloat t[4], u[4], sge[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               sge[0] = (t[0] >= u[0]) ? 1.0F : 0.0F;
+               sge[1] = (t[1] >= u[1]) ? 1.0F : 0.0F;
+               sge[2] = (t[2] >= u[2]) ? 1.0F : 0.0F;
+               sge[3] = (t[3] >= u[3]) ? 1.0F : 0.0F;
+               store_vector4( &inst->DstReg, machine, sge );
+            }
+            break;
+         case VP_OPCODE_MAD:
+            {
+               GLfloat t[4], u[4], v[4], sum[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               fetch_vector4( &inst->SrcReg[2], machine, v );
+               sum[0] = t[0] * u[0] + v[0];
+               sum[1] = t[1] * u[1] + v[1];
+               sum[2] = t[2] * u[2] + v[2];
+               sum[3] = t[3] * u[3] + v[3];
+               store_vector4( &inst->DstReg, machine, sum );
+            }
+            break;
+         case VP_OPCODE_ARL:
+            {
+               GLfloat t[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               machine->AddressReg = (GLint) floor(t[0]);
+            }
+            break;
+         case VP_OPCODE_DPH:
+            {
+               GLfloat t[4], u[4], dot[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               dot[0] = t[0] * u[0] + t[1] * u[1] + t[2] * u[2] + u[3];
+               dot[1] = dot[2] = dot[3] = dot[0];
+               store_vector4( &inst->DstReg, machine, dot );
+            }
+            break;
+         case VP_OPCODE_RCC:
+            {
+               GLfloat t[4], u;
+               fetch_vector1( &inst->SrcReg[0], machine, t );
+               if (t[0] == 1.0F)
+                  u = 1.0F;
+               else
+                  u = 1.0F / t[0];
+               if (u > 0.0F) {
+                  if (u > 1.884467e+019F) {
+                     u = 1.884467e+019F;  /* IEEE 32-bit binary value 0x5F800000 */
+                  }
+                  else if (u < 5.42101e-020F) {
+                     u = 5.42101e-020F;   /* IEEE 32-bit binary value 0x1F800000 */
+                  }
+               }
+               else {
+                  if (u < -1.884467e+019F) {
+                     u = -1.884467e+019F; /* IEEE 32-bit binary value 0xDF800000 */
+                  }
+                  else if (u > -5.42101e-020F) {
+                     u = -5.42101e-020F;  /* IEEE 32-bit binary value 0x9F800000 */
+                  }
+               }
+               t[0] = t[1] = t[2] = t[3] = u;
+               store_vector4( &inst->DstReg, machine, t );
+            }
+            break;
+         case VP_OPCODE_SUB:
+            {
+               GLfloat t[4], u[4], sum[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               fetch_vector4( &inst->SrcReg[1], machine, u );
+               sum[0] = t[0] - u[0];
+               sum[1] = t[1] - u[1];
+               sum[2] = t[2] - u[2];
+               sum[3] = t[3] - u[3];
+               store_vector4( &inst->DstReg, machine, sum );
+            }
+            break;
+         case VP_OPCODE_ABS:
+            {
+               GLfloat t[4];
+               fetch_vector4( &inst->SrcReg[0], machine, t );
+               if (t[0] < 0.0)  t[0] = -t[0];
+               if (t[1] < 0.0)  t[1] = -t[1];
+               if (t[2] < 0.0)  t[2] = -t[2];
+               if (t[3] < 0.0)  t[3] = -t[3];
+               store_vector4( &inst->DstReg, machine, t );
+            }
+            break;
+
+         case VP_OPCODE_END:
+            return;
+         default:
+            /* bad instruction opcode */
+            _mesa_problem(ctx, "Bad VP Opcode in _mesa_exec_vertex_program");
+            return;
+      }
+   }
+}
+
+
+
+/**
+Thoughts on vertex program optimization:
+
+The obvious thing to do is to compile the vertex program into X86/SSE/3DNow!
+assembly code.  That will probably be a lot of work.
+
+Another approach might be to replace the vp_instruction->Opcode field with
+a pointer to a specialized C function which executes the instruction.
+In particular we can write functions which skip swizzling, negating,
+masking, relative addressing, etc. when they're not needed.
+
+For example:
+
+void simple_add( struct vp_instruction *inst )
+{
+   GLfloat *sum = machine->Registers[inst->DstReg.Register];
+   GLfloat *a = machine->Registers[inst->SrcReg[0].Register];
+   GLfloat *b = machine->Registers[inst->SrcReg[1].Register];
+   sum[0] = a[0] + b[0];
+   sum[1] = a[1] + b[1];
+   sum[2] = a[2] + b[2];
+   sum[3] = a[3] + b[3];
+}
+
+*/
+
+/*
+
+KW:
+
+A first step would be to 'vectorize' the programs in the same way as
+the normal transformation code in the tnl module.  Thus each opcode
+takes zero or more input vectors (registers) and produces one or more
+output vectors.
+
+These operations would intially be coded in C, with machine-specific
+assembly following, as is currently the case for matrix
+transformations in the math/ directory.  The preprocessing scheme for
+selecting simpler operations Brian describes above would also work
+here.
+
+This should give reasonable performance without excessive effort.
+
+*/
diff --git a/src/mesa/main/nvvertexec.h b/src/mesa/main/nvvertexec.h
new file mode 100644 (file)
index 0000000..76b2b66
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id: nvvertexec.h,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.1
+ *
+ * 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:
+ *    Brian Paul
+ */
+
+#ifndef NVVERTEXEC_H
+#define NVVERTEXEC_H
+
+extern void
+_mesa_init_vp_registers(GLcontext *ctx);
+
+extern void
+_mesa_init_tracked_matrices(GLcontext *ctx);
+
+extern void
+_mesa_exec_vertex_program(GLcontext *ctx, const struct vertex_program *program);
+
+extern void
+_mesa_dump_vp_machine( const struct vp_machine *machine );
+
+#endif
diff --git a/src/mesa/main/nvvertparse.c b/src/mesa/main/nvvertparse.c
new file mode 100644 (file)
index 0000000..f0c51e2
--- /dev/null
@@ -0,0 +1,1584 @@
+/* $Id: nvvertparse.c,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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.
+ */
+
+/**
+ * \file nvvertparse.c
+ * \brief NVIDIA vertex program parser.
+ * \author Brian Paul
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "nvprogram.h"
+#include "nvvertparse.h"
+#include "nvvertprog.h"
+
+
+/************************ Symbol Table ******************************/
+
+/* A simple symbol table implementation for ARB_vertex_program
+ * (not used yet)
+ */
+
+#if 000
+struct symbol
+{
+   GLubyte *name;
+   GLint value;
+   struct symbol *next;
+};
+
+static struct symbol *SymbolTable = NULL;
+
+static GLboolean
+IsSymbol(const GLubyte *symbol)
+{
+   struct symbol *s;
+   for (s = SymbolTable; s; s = s->next) {
+      if (strcmp((char *) symbol, (char *)s->name) == 0)
+         return GL_TRUE;
+   }
+   return GL_FALSE;
+}
+
+static GLint
+GetSymbolValue(const GLubyte *symbol)
+{
+   struct symbol *s;
+   for (s = SymbolTable; s; s = s->next) {
+      if (strcmp((char *) symbol, (char *)s->name) == 0)
+         return s->value;
+   }
+   return 0;
+}
+
+static void
+AddSymbol(const GLubyte *symbol, GLint value)
+{
+   struct symbol *s = MALLOC_STRUCT(symbol);
+   if (s) {
+      s->name = (GLubyte *) strdup((char *) symbol);
+      s->value = value;
+      s->next = SymbolTable;
+      SymbolTable = s;
+   }
+}
+
+static void
+ResetSymbolTable(void)
+{
+   struct symbol *s, *next;
+   for (s = SymbolTable; s; s = next) {
+      next = s->next;
+      FREE(s->name);
+      FREE(s);
+      s = next;
+   }   
+   SymbolTable = NULL;
+}
+#endif
+
+/***************************** Parsing ******************************/
+
+
+static GLboolean IsLetter(GLubyte b)
+{
+   return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
+}
+
+
+static GLboolean IsDigit(GLubyte b)
+{
+   return b >= '0' && b <= '9';
+}
+
+
+static GLboolean IsWhitespace(GLubyte b)
+{
+   return b == ' ' || b == '\t' || b == '\n' || b == '\r';
+}
+
+
+/**
+ * Starting at 'str' find the next token.  A token can be an integer,
+ * an identifier or punctuation symbol.
+ * \return <= 0 we found an error, else, return number of characters parsed.
+ */
+static GLint
+GetToken(const GLubyte *str, GLubyte *token)
+{
+   GLint i = 0, j = 0;
+
+   token[0] = 0;
+
+   /* skip whitespace and comments */
+   while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
+      if (str[i] == '#') {
+         /* skip comment */
+         while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
+            i++;
+         }
+      }
+      else {
+         /* skip whitespace */
+         i++;
+      }
+   }
+
+   if (str[i] == 0)
+      return -i;
+
+   /* try matching an integer */
+   while (str[i] && IsDigit(str[i])) {
+      token[j++] = str[i++];
+   }
+   if (j > 0 || !str[i]) {
+      token[j] = 0;
+      return i;
+   }
+
+   /* try matching an identifier */
+   if (IsLetter(str[i])) {
+      while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
+         token[j++] = str[i++];
+      }
+      token[j] = 0;
+      return i;
+   }
+
+   /* punctuation */
+   if (str[i]) {
+      token[0] = str[i++];
+      token[1] = 0;
+      return i;
+   }
+
+   /* end of input */
+   token[0] = 0;
+   return i;
+}
+
+
+/**
+ * Get next token from input stream and increment stream pointer past token.
+ */
+static GLboolean
+Parse_Token(const GLubyte **s, GLubyte *token)
+{
+   GLint i;
+   i = GetToken(*s, token);
+   if (i <= 0) {
+      *s += (-i);
+      return GL_FALSE;
+   }
+   *s += i;
+   return GL_TRUE;
+}
+
+
+/**
+ * Get next token from input stream but don't increment stream pointer.
+ */
+static GLboolean
+Peek_Token(const GLubyte **s, GLubyte *token)
+{
+   GLint i, len;
+   i = GetToken(*s, token);
+   if (i <= 0) {
+      *s += (-i);
+      return GL_FALSE;
+   }
+   len = _mesa_strlen((char *) token);
+   *s += (i - len);
+   return GL_TRUE;
+}
+
+
+/**
+ * String equality test
+ */
+static GLboolean
+StrEq(const GLubyte *a, const GLubyte *b)
+{
+   GLint i;
+   for (i = 0; a[i] && b[i] && a[i] == b[i]; i++)
+      ;
+   if (a[i] == 0 && b[i] == 0)
+      return GL_TRUE;
+   else
+      return GL_FALSE;
+}
+
+
+/**********************************************************************/
+
+static const char *InputRegisters[] = {
+   "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
+   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
+};
+
+static const char *OutputRegisters[] = {
+   "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
+   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
+};
+
+static const char *Opcodes[] = {
+   "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
+   "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
+   "ABS", "END", NULL
+};
+
+
+#ifdef DEBUG
+
+#define PARSE_ERROR                                            \
+do {                                                           \
+   _mesa_printf("vpparse.c error at %d: parse error\n", __LINE__);     \
+   return GL_FALSE;                                            \
+} while(0)
+
+#define PARSE_ERROR1(msg)                                      \
+do {                                                           \
+   _mesa_printf("vpparse.c error at %d: %s\n", __LINE__, msg); \
+   return GL_FALSE;                                            \
+} while(0)
+
+#define PARSE_ERROR2(msg1, msg2)                                       \
+do {                                                                   \
+   _mesa_printf("vpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2);       \
+   return GL_FALSE;                                                    \
+} while(0)
+
+#else
+
+#define PARSE_ERROR                return GL_FALSE
+#define PARSE_ERROR1(msg1)         return GL_FALSE
+#define PARSE_ERROR2(msg1, msg2)   return GL_FALSE
+
+#endif
+
+
+static GLuint
+IsProgRegister(GLuint r)
+{
+   return (GLuint) (r >= VP_PROG_REG_START && r <= VP_PROG_REG_END);
+}
+
+static GLuint
+IsInputRegister(GLuint r)
+{
+   return (GLuint) (r >= VP_INPUT_REG_START && r <= VP_INPUT_REG_END);
+}
+
+static GLuint
+IsOutputRegister(GLuint r)
+{
+   return (GLuint) (r >= VP_OUTPUT_REG_START && r <= VP_OUTPUT_REG_END);
+}
+
+
+
+/**********************************************************************/
+
+/* XXX
+ * These shouldn't be globals as that makes the parser non-reentrant.
+ * We should really define a "ParserContext" class which contains these
+ * and the <s> pointer into the program text.
+ */
+static GLboolean IsStateProgram = GL_FALSE;
+static GLboolean IsPositionInvariant = GL_FALSE;
+static GLboolean IsVersion1_1 = GL_FALSE;
+
+/**
+ * Try to match 'pattern' as the next token after any whitespace/comments.
+ */
+static GLboolean
+Parse_String(const GLubyte **s, const char *pattern)
+{
+   GLint i;
+
+   /* skip whitespace and comments */
+   while (IsWhitespace(**s) || **s == '#') {
+      if (**s == '#') {
+         while (**s && (**s != '\n' && **s != '\r')) {
+            *s += 1;
+         }
+      }
+      else {
+         /* skip whitespace */
+         *s += 1;
+      }
+   }
+
+   /* Try to match the pattern */
+   for (i = 0; pattern[i]; i++) {
+      if (**s != pattern[i])
+         PARSE_ERROR2("failed to match", pattern); /* failure */
+      *s += 1;
+   }
+
+   return GL_TRUE; /* success */
+}
+
+
+/**
+ * Parse a temporary register: Rnn
+ */
+static GLboolean
+Parse_TempReg(const GLubyte **s, GLint *tempRegNum)
+{
+   GLubyte token[100];
+
+   /* Should be 'R##' */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] != 'R')
+      PARSE_ERROR1("Expected R##");
+
+   if (IsDigit(token[1])) {
+      GLint reg = _mesa_atoi((char *) (token + 1));
+      if (reg >= VP_NUM_TEMP_REGS)
+         PARSE_ERROR1("Bad temporary register name");
+      *tempRegNum = VP_TEMP_REG_START + reg;
+   }
+   else {
+      PARSE_ERROR1("Bad temporary register name");
+   }
+
+   return GL_TRUE;
+}
+
+
+/**
+ * Parse address register "A0.x"
+ */
+static GLboolean
+Parse_AddrReg(const GLubyte **s)
+{
+   /* match 'A0' */
+   if (!Parse_String(s, "A0"))
+      PARSE_ERROR;
+
+   /* match '.' */
+   if (!Parse_String(s, "."))
+      PARSE_ERROR;
+
+   /* match 'x' */
+   if (!Parse_String(s, "x"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+/**
+ * Parse absolute program parameter register "c[##]"
+ */
+static GLboolean
+Parse_AbsParamReg(const GLubyte **s, GLint *regNum)
+{
+   GLubyte token[100];
+
+   if (!Parse_String(s, "c"))
+      PARSE_ERROR;
+
+   if (!Parse_String(s, "["))
+      PARSE_ERROR;
+
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (IsDigit(token[0])) {
+      /* a numbered program parameter register */
+      GLint reg = _mesa_atoi((char *) token);
+      if (reg >= VP_NUM_PROG_REGS)
+         PARSE_ERROR1("Bad constant program number");
+      *regNum = VP_PROG_REG_START + reg;
+   }
+   else {
+      PARSE_ERROR;
+   }
+
+   if (!Parse_String(s, "]"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ParamReg(const GLubyte **s, struct vp_src_register *srcReg)
+{
+   GLubyte token[100];
+
+   if (!Parse_String(s, "c"))
+      PARSE_ERROR;
+
+   if (!Parse_String(s, "["))
+      PARSE_ERROR;
+
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+
+   if (IsDigit(token[0])) {
+      /* a numbered program parameter register */
+      GLint reg;
+      (void) Parse_Token(s, token);
+      reg = _mesa_atoi((char *) token);
+      if (reg >= VP_NUM_PROG_REGS)
+         PARSE_ERROR1("Bad constant program number");
+      srcReg->Register = VP_PROG_REG_START + reg;
+   }
+   else if (StrEq(token, (GLubyte *) "A0")) {
+      /* address register "A0.x" */
+      if (!Parse_AddrReg(s))
+         PARSE_ERROR;
+
+      srcReg->RelAddr = GL_TRUE;
+      srcReg->Register = 0;
+
+      /* Look for +/-N offset */
+      if (!Peek_Token(s, token))
+         PARSE_ERROR;
+
+      if (token[0] == '-' || token[0] == '+') {
+         const GLubyte sign = token[0];
+         (void) Parse_Token(s, token); /* consume +/- */
+
+         /* an integer should be next */
+         if (!Parse_Token(s, token))
+            PARSE_ERROR;
+
+         if (IsDigit(token[0])) {
+            const GLint k = _mesa_atoi((char *) token);
+            if (sign == '-') {
+               if (k > 64)
+                  PARSE_ERROR1("Bad address offset");
+               srcReg->Register = -k;
+            }
+            else {
+               if (k > 63)
+                  PARSE_ERROR1("Bad address offset");
+               srcReg->Register = k;
+            }
+         }
+         else {
+            PARSE_ERROR;
+         }
+      }
+      else {
+         /* probably got a ']', catch it below */
+      }
+   }
+   else {
+      PARSE_ERROR;
+   }
+
+   /* Match closing ']' */
+   if (!Parse_String(s, "]"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+/**
+ * Parse v[#] or v[<name>]
+ */
+static GLboolean
+Parse_AttribReg(const GLubyte **s, GLint *tempRegNum)
+{
+   GLubyte token[100];
+   GLint j;
+
+   /* Match 'v' */
+   if (!Parse_String(s, "v"))
+      PARSE_ERROR;
+
+   /* Match '[' */
+   if (!Parse_String(s, "["))
+      PARSE_ERROR;
+
+   /* match number or named register */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (IsStateProgram && token[0] != '0')
+      PARSE_ERROR1("Only v[0] accessible in vertex state programs");
+
+   if (IsDigit(token[0])) {
+      GLint reg = _mesa_atoi((char *) token);
+      if (reg >= VP_NUM_INPUT_REGS)
+         PARSE_ERROR1("Bad vertex attribute register name");
+      *tempRegNum = VP_INPUT_REG_START + reg;
+   }
+   else {
+      for (j = 0; InputRegisters[j]; j++) {
+         if (StrEq(token, (const GLubyte *) InputRegisters[j])) {
+            *tempRegNum = VP_INPUT_REG_START + j;
+            break;
+         }
+      }
+      if (!InputRegisters[j]) {
+         /* unknown input register label */
+         PARSE_ERROR2("Bad register name", token);
+      }
+   }
+
+   /* Match '[' */
+   if (!Parse_String(s, "]"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_OutputReg(const GLubyte **s, GLint *outputRegNum)
+{
+   GLubyte token[100];
+   GLint start, j;
+
+   /* Match 'o' */
+   if (!Parse_String(s, "o"))
+      PARSE_ERROR;
+
+   /* Match '[' */
+   if (!Parse_String(s, "["))
+      PARSE_ERROR;
+
+   /* Get output reg name */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (IsPositionInvariant)
+      start = 1; /* skip HPOS register name */
+   else
+      start = 0;
+
+   /* try to match an output register name */
+   for (j = start; OutputRegisters[j]; j++) {
+      if (StrEq(token, (const GLubyte *) OutputRegisters[j])) {
+         *outputRegNum = VP_OUTPUT_REG_START + j;
+         break;
+      }
+   }
+   if (!OutputRegisters[j])
+      PARSE_ERROR1("Unrecognized output register name");
+
+   /* Match ']' */
+   if (!Parse_String(s, "]"))
+      PARSE_ERROR1("Expected ]");
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_MaskedDstReg(const GLubyte **s, struct vp_dst_register *dstReg)
+{
+   GLubyte token[100];
+
+   /* Dst reg can be R<n> or o[n] */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+
+   if (token[0] == 'R') {
+      /* a temporary register */
+      if (!Parse_TempReg(s, &dstReg->Register))
+         PARSE_ERROR;
+   }
+   else if (!IsStateProgram && token[0] == 'o') {
+      /* an output register */
+      if (!Parse_OutputReg(s, &dstReg->Register))
+         PARSE_ERROR;
+   }
+   else if (IsStateProgram && token[0] == 'c') {
+      /* absolute program parameter register */
+      if (!Parse_AbsParamReg(s, &dstReg->Register))
+         PARSE_ERROR;
+   }
+   else {
+      PARSE_ERROR1("Bad destination register name");
+   }
+
+   /* Parse optional write mask */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+
+   if (token[0] == '.') {
+      /* got a mask */
+      GLint k = 0;
+
+      if (!Parse_String(s, "."))
+         PARSE_ERROR;
+
+      if (!Parse_Token(s, token))
+         PARSE_ERROR;
+
+      dstReg->WriteMask[0] = GL_FALSE;
+      dstReg->WriteMask[1] = GL_FALSE;
+      dstReg->WriteMask[2] = GL_FALSE;
+      dstReg->WriteMask[3] = GL_FALSE;
+
+      if (token[k] == 'x') {
+         dstReg->WriteMask[0] = GL_TRUE;
+         k++;
+      }
+      if (token[k] == 'y') {
+         dstReg->WriteMask[1] = GL_TRUE;
+         k++;
+      }
+      if (token[k] == 'z') {
+         dstReg->WriteMask[2] = GL_TRUE;
+         k++;
+      }
+      if (token[k] == 'w') {
+         dstReg->WriteMask[3] = GL_TRUE;
+         k++;
+      }
+      if (k == 0) {
+         PARSE_ERROR1("Bad writemask character");
+      }
+      return GL_TRUE;
+   }
+   else {
+      dstReg->WriteMask[0] = GL_TRUE;
+      dstReg->WriteMask[1] = GL_TRUE;
+      dstReg->WriteMask[2] = GL_TRUE;
+      dstReg->WriteMask[3] = GL_TRUE;
+      return GL_TRUE;
+   }
+}
+
+
+static GLboolean
+Parse_SwizzleSrcReg(const GLubyte **s, struct vp_src_register *srcReg)
+{
+   GLubyte token[100];
+
+   srcReg->RelAddr = GL_FALSE;
+
+   /* check for '-' */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] == '-') {
+      (void) Parse_String(s, "-");
+      srcReg->Negate = GL_TRUE;
+      if (!Peek_Token(s, token))
+         PARSE_ERROR;
+   }
+   else {
+      srcReg->Negate = GL_FALSE;
+   }
+
+   /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
+   if (token[0] == 'R') {
+      if (!Parse_TempReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'c') {
+      if (!Parse_ParamReg(s, srcReg))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'v') {
+      if (!Parse_AttribReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else {
+      PARSE_ERROR2("Bad source register name", token);
+   }
+
+   /* init swizzle fields */
+   srcReg->Swizzle[0] = 0;
+   srcReg->Swizzle[1] = 1;
+   srcReg->Swizzle[2] = 2;
+   srcReg->Swizzle[3] = 3;
+
+   /* Look for optional swizzle suffix */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] == '.') {
+      (void) Parse_String(s, ".");  /* consume . */
+
+      if (!Parse_Token(s, token))
+         PARSE_ERROR;
+
+      if (token[1] == 0) {
+         /* single letter swizzle */
+         if (token[0] == 'x')
+            ASSIGN_4V(srcReg->Swizzle, 0, 0, 0, 0);
+         else if (token[0] == 'y')
+            ASSIGN_4V(srcReg->Swizzle, 1, 1, 1, 1);
+         else if (token[0] == 'z')
+            ASSIGN_4V(srcReg->Swizzle, 2, 2, 2, 2);
+         else if (token[0] == 'w')
+            ASSIGN_4V(srcReg->Swizzle, 3, 3, 3, 3);
+         else
+            PARSE_ERROR1("Expected x, y, z, or w");
+      }
+      else {
+         /* 2, 3 or 4-component swizzle */
+         GLint k;
+         for (k = 0; token[k] && k < 5; k++) {
+            if (token[k] == 'x')
+               srcReg->Swizzle[k] = 0;
+            else if (token[k] == 'y')
+               srcReg->Swizzle[k] = 1;
+            else if (token[k] == 'z')
+               srcReg->Swizzle[k] = 2;
+            else if (token[k] == 'w')
+               srcReg->Swizzle[k] = 3;
+            else
+               PARSE_ERROR;
+         }
+         if (k >= 5)
+            PARSE_ERROR;
+      }
+   }
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ScalarSrcReg(const GLubyte **s, struct vp_src_register *srcReg)
+{
+   GLubyte token[100];
+
+   srcReg->RelAddr = GL_FALSE;
+
+   /* check for '-' */
+   if (!Peek_Token(s, token))
+      PARSE_ERROR;
+   if (token[0] == '-') {
+      srcReg->Negate = GL_TRUE;
+      (void) Parse_String(s, "-"); /* consume '-' */
+      if (!Peek_Token(s, token))
+         PARSE_ERROR;
+   }
+   else {
+      srcReg->Negate = GL_FALSE;
+   }
+
+   /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
+   if (token[0] == 'R') {
+      if (!Parse_TempReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'c') {
+      if (!Parse_ParamReg(s, srcReg))
+         PARSE_ERROR;
+   }
+   else if (token[0] == 'v') {
+      if (!Parse_AttribReg(s, &srcReg->Register))
+         PARSE_ERROR;
+   }
+   else {
+      PARSE_ERROR2("Bad source register name", token);
+   }
+
+   /* Look for .[xyzw] suffix */
+   if (!Parse_String(s, "."))
+      PARSE_ERROR;
+
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (token[0] == 'x' && token[1] == 0) {
+      srcReg->Swizzle[0] = 0;
+   }
+   else if (token[0] == 'y' && token[1] == 0) {
+      srcReg->Swizzle[0] = 1;
+   }
+   else if (token[0] == 'z' && token[1] == 0) {
+      srcReg->Swizzle[0] = 2;
+   }
+   else if (token[0] == 'w' && token[1] == 0) {
+      srcReg->Swizzle[0] = 3;
+   }
+   else {
+      PARSE_ERROR1("Bad scalar source suffix");
+   }
+   srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
+
+   return GL_TRUE;
+}
+
+
+static GLint
+Parse_UnaryOpInstruction(const GLubyte **s, struct vp_instruction *inst)
+{
+   GLubyte token[100];
+
+   /* opcode */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (StrEq(token, (GLubyte *) "MOV")) {
+      inst->Opcode = VP_OPCODE_MOV;
+   }
+   else if (StrEq(token, (GLubyte *) "LIT")) {
+      inst->Opcode = VP_OPCODE_LIT;
+   }
+   else if (StrEq(token, (GLubyte *) "ABS") && IsVersion1_1) {
+      inst->Opcode = VP_OPCODE_ABS;
+   }
+   else {
+      PARSE_ERROR;
+   }
+
+   /* dest reg */
+   if (!Parse_MaskedDstReg(s, &inst->DstReg))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* src arg */
+   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
+      PARSE_ERROR;
+
+   /* semicolon */
+   if (!Parse_String(s, ";"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_BiOpInstruction(const GLubyte **s, struct vp_instruction *inst)
+{
+   GLubyte token[100];
+
+   /* opcode */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (StrEq(token, (GLubyte *) "MUL")) {
+      inst->Opcode = VP_OPCODE_MUL;
+   }
+   else if (StrEq(token, (GLubyte *) "ADD")) {
+      inst->Opcode = VP_OPCODE_ADD;
+   }
+   else if (StrEq(token, (GLubyte *) "DP3")) {
+      inst->Opcode = VP_OPCODE_DP3;
+   }
+   else if (StrEq(token, (GLubyte *) "DP4")) {
+      inst->Opcode = VP_OPCODE_DP4;
+   }
+   else if (StrEq(token, (GLubyte *) "DST")) {
+      inst->Opcode = VP_OPCODE_DST;
+   }
+   else if (StrEq(token, (GLubyte *) "MIN")) {
+      inst->Opcode = VP_OPCODE_ADD;
+   }
+   else if (StrEq(token, (GLubyte *) "MAX")) {
+      inst->Opcode = VP_OPCODE_ADD;
+   }
+   else if (StrEq(token, (GLubyte *) "SLT")) {
+      inst->Opcode = VP_OPCODE_SLT;
+   }
+   else if (StrEq(token, (GLubyte *) "SGE")) {
+      inst->Opcode = VP_OPCODE_SGE;
+   }
+   else if (StrEq(token, (GLubyte *) "DPH") && IsVersion1_1) {
+      inst->Opcode = VP_OPCODE_DPH;
+   }
+   else if (StrEq(token, (GLubyte *) "SUB") && IsVersion1_1) {
+      inst->Opcode = VP_OPCODE_SUB;
+   }
+   else {
+      PARSE_ERROR;
+   }
+
+   /* dest reg */
+   if (!Parse_MaskedDstReg(s, &inst->DstReg))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* first src arg */
+   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* second src arg */
+   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
+      PARSE_ERROR;
+
+   /* semicolon */
+   if (!Parse_String(s, ";"))
+      PARSE_ERROR;
+
+   /* make sure we don't reference more than one program parameter register */
+   if (IsProgRegister(inst->SrcReg[0].Register) &&
+       IsProgRegister(inst->SrcReg[1].Register) &&
+       inst->SrcReg[0].Register != inst->SrcReg[1].Register)
+      PARSE_ERROR1("Can't reference two program parameter registers");
+
+   /* make sure we don't reference more than one vertex attribute register */
+   if (IsInputRegister(inst->SrcReg[0].Register) &&
+       IsInputRegister(inst->SrcReg[1].Register) &&
+       inst->SrcReg[0].Register != inst->SrcReg[1].Register)
+      PARSE_ERROR1("Can't reference two vertex attribute registers");
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_TriOpInstruction(const GLubyte **s, struct vp_instruction *inst)
+{
+   GLubyte token[100];
+
+   /* opcode */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (StrEq(token, (GLubyte *) "MAD")) {
+      inst->Opcode = VP_OPCODE_MAD;
+   }
+   else {
+      PARSE_ERROR;
+   }
+
+   /* dest reg */
+   if (!Parse_MaskedDstReg(s, &inst->DstReg))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* first src arg */
+   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* second src arg */
+   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* third src arg */
+   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[2]))
+      PARSE_ERROR;
+
+   /* semicolon */
+   if (!Parse_String(s, ";"))
+      PARSE_ERROR;
+
+   /* make sure we don't reference more than one program parameter register */
+   if ((IsProgRegister(inst->SrcReg[0].Register) &&
+        IsProgRegister(inst->SrcReg[1].Register) &&
+        inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
+       (IsProgRegister(inst->SrcReg[0].Register) &&
+        IsProgRegister(inst->SrcReg[2].Register) &&
+        inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
+       (IsProgRegister(inst->SrcReg[1].Register) &&
+        IsProgRegister(inst->SrcReg[2].Register) &&
+        inst->SrcReg[1].Register != inst->SrcReg[2].Register))
+      PARSE_ERROR1("Can only reference one program register");
+
+   /* make sure we don't reference more than one vertex attribute register */
+   if ((IsInputRegister(inst->SrcReg[0].Register) &&
+        IsInputRegister(inst->SrcReg[1].Register) &&
+        inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
+       (IsInputRegister(inst->SrcReg[0].Register) &&
+        IsInputRegister(inst->SrcReg[2].Register) &&
+        inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
+       (IsInputRegister(inst->SrcReg[1].Register) &&
+        IsInputRegister(inst->SrcReg[2].Register) &&
+        inst->SrcReg[1].Register != inst->SrcReg[2].Register))
+      PARSE_ERROR1("Can only reference one input register");
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ScalarInstruction(const GLubyte **s, struct vp_instruction *inst)
+{
+   GLubyte token[100];
+
+   /* opcode */
+   if (!Parse_Token(s, token))
+      PARSE_ERROR;
+
+   if (StrEq(token, (GLubyte *) "RCP")) {
+      inst->Opcode = VP_OPCODE_RCP;
+   }
+   else if (StrEq(token, (GLubyte *) "RSQ")) {
+      inst->Opcode = VP_OPCODE_RSQ;
+   }
+   else if (StrEq(token, (GLubyte *) "EXP")) {
+      inst->Opcode = VP_OPCODE_EXP;
+   }
+   else if (StrEq(token, (GLubyte *) "LOG")) {
+      inst->Opcode = VP_OPCODE_LOG;
+   }
+   else if (StrEq(token, (GLubyte *) "RCC") && IsVersion1_1) {
+      inst->Opcode = VP_OPCODE_RCC;
+   }
+   else {
+      PARSE_ERROR;
+   }
+
+   /* dest reg */
+   if (!Parse_MaskedDstReg(s, &inst->DstReg))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* first src arg */
+   if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
+      PARSE_ERROR;
+
+   /* semicolon */
+   if (!Parse_String(s, ";"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_AddressInstruction(const GLubyte **s, struct vp_instruction *inst)
+{
+   inst->Opcode = VP_OPCODE_ARL;
+
+   /* opcode */
+   if (!Parse_String(s, "ARL"))
+      PARSE_ERROR;
+
+   /* dest A0 reg */
+   if (!Parse_AddrReg(s))
+      PARSE_ERROR;
+
+   /* comma */
+   if (!Parse_String(s, ","))
+      PARSE_ERROR;
+
+   /* parse src reg */
+   if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
+      PARSE_ERROR;
+
+   /* semicolon */
+   if (!Parse_String(s, ";"))
+      PARSE_ERROR;
+
+   return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_EndInstruction(const GLubyte **s, struct vp_instruction *inst)
+{
+   GLubyte token[100];
+
+   /* opcode */
+   if (!Parse_String(s, "END"))
+      PARSE_ERROR;
+
+   inst->Opcode = VP_OPCODE_END;
+
+   /* this should fail! */
+   if (Parse_Token(s, token))
+      PARSE_ERROR2("Unexpected token after END:", token);
+   else
+      return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_OptionSequence(const GLubyte **s, struct vp_instruction program[])
+{
+   while (1) {
+      GLubyte token[100];
+      if (!Peek_Token(s, token)) {
+         PARSE_ERROR1("Unexpected end of input");
+         return GL_FALSE; /* end of input */
+      }
+
+      if (!StrEq(token, (GLubyte *) "OPTION"))
+         return GL_TRUE;  /* probably an instruction */
+
+      Parse_Token(s, token);
+
+      if (!Parse_String(s, "NV_position_invariant"))
+         return GL_FALSE;
+      if (!Parse_String(s, ";"))
+         return GL_FALSE;
+      IsPositionInvariant = GL_TRUE;
+   }
+}
+
+
+static GLboolean
+Parse_InstructionSequence(const GLubyte **s, struct vp_instruction program[])
+{
+   GLubyte token[100];
+   GLint count = 0;
+
+   while (1) {
+      struct vp_instruction *inst = program + count;
+
+      /* Initialize the instruction */
+      inst->SrcReg[0].Register = -1;
+      inst->SrcReg[1].Register = -1;
+      inst->SrcReg[2].Register = -1;
+      inst->DstReg.Register = -1;
+
+      if (!Peek_Token(s, token))
+         PARSE_ERROR;
+
+      if (StrEq(token, (GLubyte *) "MOV") ||
+          StrEq(token, (GLubyte *) "LIT") ||
+          StrEq(token, (GLubyte *) "ABS")) {
+         if (!Parse_UnaryOpInstruction(s, inst))
+            PARSE_ERROR;
+      }
+      else if (StrEq(token, (GLubyte *) "MUL") ||
+          StrEq(token, (GLubyte *) "ADD") ||
+          StrEq(token, (GLubyte *) "DP3") ||
+          StrEq(token, (GLubyte *) "DP4") ||
+          StrEq(token, (GLubyte *) "DST") ||
+          StrEq(token, (GLubyte *) "MIN") ||
+          StrEq(token, (GLubyte *) "MAX") ||
+          StrEq(token, (GLubyte *) "SLT") ||
+          StrEq(token, (GLubyte *) "SGE") ||
+          StrEq(token, (GLubyte *) "DPH") ||
+          StrEq(token, (GLubyte *) "SUB")) {
+         if (!Parse_BiOpInstruction(s, inst))
+            PARSE_ERROR;
+      }
+      else if (StrEq(token, (GLubyte *) "MAD")) {
+         if (!Parse_TriOpInstruction(s, inst))
+            PARSE_ERROR;
+      }
+      else if (StrEq(token, (GLubyte *) "RCP") ||
+               StrEq(token, (GLubyte *) "RSQ") ||
+               StrEq(token, (GLubyte *) "EXP") ||
+               StrEq(token, (GLubyte *) "LOG") ||
+               StrEq(token, (GLubyte *) "RCC")) {
+         if (!Parse_ScalarInstruction(s, inst))
+            PARSE_ERROR;
+      }
+      else if (StrEq(token, (GLubyte *) "ARL")) {
+         if (!Parse_AddressInstruction(s, inst))
+            PARSE_ERROR;
+      }
+      else if (StrEq(token, (GLubyte *) "END")) {
+         if (!Parse_EndInstruction(s, inst))
+            PARSE_ERROR;
+         else
+            return GL_TRUE;  /* all done */
+      }
+      else {
+         /* bad instruction name */
+         PARSE_ERROR2("Unexpected token: ", token);
+      }
+
+      count++;
+      if (count >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
+         PARSE_ERROR1("Program too long");
+   }
+
+   PARSE_ERROR;
+}
+
+
+static GLboolean
+Parse_Program(const GLubyte **s, struct vp_instruction instBuffer[])
+{
+   if (IsVersion1_1) {
+      if (!Parse_OptionSequence(s, instBuffer)) {
+         return GL_FALSE;
+      }
+   }
+   return Parse_InstructionSequence(s, instBuffer);
+}
+
+
+/**
+ * Parse/compile the 'str' returning the compiled 'program'.
+ * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
+ * indicates the position of the error in 'str'.
+ */
+void
+_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
+                              const GLubyte *str, GLsizei len,
+                              struct vertex_program *program)
+{
+   const GLubyte *s;
+   struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
+   struct vp_instruction *newInst;
+   GLenum target;
+   GLubyte *programString;
+
+   /* Make a null-terminated copy of the program string */
+   programString = (GLubyte *) MALLOC(len + 1);
+   if (!programString) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+      return;
+   }
+   MEMCPY(programString, str, len);
+   programString[len] = 0;
+
+   IsPositionInvariant = GL_FALSE;
+   IsVersion1_1 = GL_FALSE;
+
+   /* check the program header */
+   if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
+      target = GL_VERTEX_PROGRAM_NV;
+      s = programString + 7;
+      IsStateProgram = GL_FALSE;
+   }
+   else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
+      target = GL_VERTEX_PROGRAM_NV;
+      s = programString + 7;
+      IsStateProgram = GL_FALSE;
+      IsVersion1_1 = GL_TRUE;
+   }
+   else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
+      target = GL_VERTEX_STATE_PROGRAM_NV;
+      s = programString + 8;
+      IsStateProgram = GL_TRUE;
+   }
+   else {
+      /* invalid header */
+      ctx->Program.ErrorPos = 0;
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
+      return;
+   }
+
+   /* make sure target and header match */
+   if (target != dstTarget) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glLoadProgramNV(target mismatch)");
+      return;
+   }
+
+   if (Parse_Program(&s, instBuffer)) {
+      GLuint numInst;
+      GLuint inputsRead = 0;
+      GLuint outputsWritten = 0;
+      GLuint progRegsWritten = 0;
+
+      /* Find length of the program and compute bitmasks to indicate which
+       * vertex input registers are read, which vertex result registers are
+       * written to, and which program registers are written to.
+       * We could actually do this while we parse the program.
+       */
+      for (numInst = 0; instBuffer[numInst].Opcode != VP_OPCODE_END; numInst++) {
+         const GLint srcReg0 = instBuffer[numInst].SrcReg[0].Register;
+         const GLint srcReg1 = instBuffer[numInst].SrcReg[1].Register;
+         const GLint srcReg2 = instBuffer[numInst].SrcReg[2].Register;
+         const GLint dstReg = instBuffer[numInst].DstReg.Register;
+
+         if (IsOutputRegister(dstReg))
+            outputsWritten |= (1 << (dstReg - VP_OUTPUT_REG_START));
+         else if (IsProgRegister(dstReg))
+            progRegsWritten |= (1 << (dstReg - VP_PROG_REG_START));
+         if (IsInputRegister(srcReg0)
+             && !instBuffer[numInst].SrcReg[0].RelAddr)
+            inputsRead |= (1 << (srcReg0 - VP_INPUT_REG_START));
+         if (IsInputRegister(srcReg1)
+             && !instBuffer[numInst].SrcReg[1].RelAddr)
+            inputsRead |= (1 << (srcReg1 - VP_INPUT_REG_START));
+         if (IsInputRegister(srcReg2)
+             && !instBuffer[numInst].SrcReg[2].RelAddr)
+            inputsRead |= (1 << (srcReg2 - VP_INPUT_REG_START));
+      }
+      numInst++;
+
+      if (IsStateProgram) {
+         if (progRegsWritten == 0) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glLoadProgramNV(c[#] not written)");
+            return;
+         }
+      }
+      else {
+         if (!IsPositionInvariant && !(outputsWritten & 1)) {
+            /* bit 1 = HPOS register */
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glLoadProgramNV(HPOS not written)");
+            return;
+         }
+      }
+
+      program->InputsRead = inputsRead;
+      program->OutputsWritten = outputsWritten;
+      program->IsPositionInvariant = IsPositionInvariant;
+
+      /* copy the compiled instructions */
+      assert(numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
+      newInst = (struct vp_instruction *) MALLOC(numInst * sizeof(struct vp_instruction));
+      if (!newInst) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+         FREE(programString);
+         return;  /* out of memory */
+      }
+      MEMCPY(newInst, instBuffer, numInst * sizeof(struct vp_instruction));
+
+      /* install the program */
+      program->Base.Target = target;
+      if (program->Base.String) {
+         FREE(program->Base.String);
+      }
+      program->Base.String = programString;
+      if (program->Instructions) {
+         FREE(program->Instructions);
+      }
+      program->Instructions = newInst;
+
+#ifdef DEBUG_foo
+      _mesa_printf("--- glLoadProgramNV result ---\n");
+      _mesa_print_nv_vertex_program(program);
+      _mesa_printf("------------------------------\n");
+#endif
+   }
+   else {
+      /* Error! */
+#ifdef DEBUG
+      /* print a message showing the program line containing the error */
+      ctx->Program.ErrorPos = s - str;
+      {
+         const GLubyte *p = str, *line = str;
+         int lineNum = 1, statementNum = 1, column = 0;
+         char errorLine[1000];
+         int i;
+         while (*p && p < s) {  /* s is the error position */
+            if (*p == '\n') {
+               line = p + 1;
+               lineNum++;
+               column = 0;
+            }
+            else if (*p == ';') {
+               statementNum++;
+            }
+            else
+               column++;
+            p++;
+         }
+         if (p) {
+            /* Copy the line with the error into errorLine so we can null-
+             * terminate it.
+             */
+            for (i = 0; line[i] != '\n' && line[i]; i++)
+               errorLine[i] = (char) line[i];
+            errorLine[i] = 0;
+         }
+         /*
+         _mesa_debug("Error pos = %d  (%c) col %d\n",
+                 ctx->Program.ErrorPos, *s, column);
+         */
+         _mesa_debug(ctx, "Vertex program error on line %2d: %s\n", lineNum, errorLine);
+         _mesa_debug(ctx, "  (statement %2d) near column %2d: ", statementNum, column+1);
+         for (i = 0; i < column; i++)
+            _mesa_debug(ctx, " ");
+         _mesa_debug(ctx, "^\n");
+      }
+#endif
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
+   }
+}
+
+
+static void
+PrintSrcReg(const struct vp_src_register *src)
+{
+   static const char comps[5] = "xyzw";
+   if (src->Negate)
+      _mesa_printf("-");
+   if (src->RelAddr) {
+      if (src->Register > 0)
+         _mesa_printf("c[A0.x + %d]", src->Register);
+      else if (src->Register < 0)
+         _mesa_printf("c[A0.x - %d]", -src->Register);
+      else
+         _mesa_printf("c[A0.x]");
+   }
+   else if (src->Register >= VP_OUTPUT_REG_START
+       && src->Register <= VP_OUTPUT_REG_END) {
+      _mesa_printf("o[%s]", OutputRegisters[src->Register - VP_OUTPUT_REG_START]);
+   }
+   else if (src->Register >= VP_INPUT_REG_START
+            && src->Register <= VP_INPUT_REG_END) {
+      _mesa_printf("v[%s]", InputRegisters[src->Register - VP_INPUT_REG_START]);
+   }
+   else if (src->Register >= VP_PROG_REG_START
+            && src->Register <= VP_PROG_REG_END) {
+      _mesa_printf("c[%d]", src->Register - VP_PROG_REG_START);
+   }
+   else {
+      _mesa_printf("R%d", src->Register - VP_TEMP_REG_START);
+   }
+
+   if (src->Swizzle[0] == src->Swizzle[1] &&
+       src->Swizzle[0] == src->Swizzle[2] &&
+       src->Swizzle[0] == src->Swizzle[3]) {
+      _mesa_printf(".%c", comps[src->Swizzle[0]]);
+   }
+   else if (src->Swizzle[0] != 0 ||
+            src->Swizzle[1] != 1 ||
+            src->Swizzle[2] != 2 ||
+            src->Swizzle[3] != 3) {
+      _mesa_printf(".%c%c%c%c",
+             comps[src->Swizzle[0]],
+             comps[src->Swizzle[1]],
+             comps[src->Swizzle[2]],
+             comps[src->Swizzle[3]]);
+   }
+}
+
+
+static void
+PrintDstReg(const struct vp_dst_register *dst)
+{
+   GLint w = dst->WriteMask[0] + dst->WriteMask[1]
+           + dst->WriteMask[2] + dst->WriteMask[3];
+
+   if (dst->Register >= VP_OUTPUT_REG_START
+       && dst->Register <= VP_OUTPUT_REG_END) {
+      _mesa_printf("o[%s]", OutputRegisters[dst->Register - VP_OUTPUT_REG_START]);
+   }
+   else if (dst->Register >= VP_INPUT_REG_START
+            && dst->Register <= VP_INPUT_REG_END) {
+      _mesa_printf("v[%s]", InputRegisters[dst->Register - VP_INPUT_REG_START]);
+   }
+   else if (dst->Register >= VP_PROG_REG_START
+            && dst->Register <= VP_PROG_REG_END) {
+      _mesa_printf("c[%d]", dst->Register - VP_PROG_REG_START);
+   }
+   else {
+      _mesa_printf("R%d", dst->Register - VP_TEMP_REG_START);
+   }
+
+   if (w != 0 && w != 4) {
+      _mesa_printf(".");
+      if (dst->WriteMask[0])
+         _mesa_printf("x");
+      if (dst->WriteMask[1])
+         _mesa_printf("y");
+      if (dst->WriteMask[2])
+         _mesa_printf("z");
+      if (dst->WriteMask[3])
+         _mesa_printf("w");
+   }
+}
+
+
+/**
+ * Print (unparse) the given vertex program.  Just for debugging.
+ */
+void
+_mesa_print_nv_vertex_program(const struct vertex_program *program)
+{
+   const struct vp_instruction *inst;
+
+   for (inst = program->Instructions; ; inst++) {
+      switch (inst->Opcode) {
+      case VP_OPCODE_MOV:
+      case VP_OPCODE_LIT:
+      case VP_OPCODE_RCP:
+      case VP_OPCODE_RSQ:
+      case VP_OPCODE_EXP:
+      case VP_OPCODE_LOG:
+      case VP_OPCODE_RCC:
+      case VP_OPCODE_ABS:
+         _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
+         PrintDstReg(&inst->DstReg);
+         _mesa_printf(", ");
+         PrintSrcReg(&inst->SrcReg[0]);
+         _mesa_printf(";\n");
+         break;
+      case VP_OPCODE_MUL:
+      case VP_OPCODE_ADD:
+      case VP_OPCODE_DP3:
+      case VP_OPCODE_DP4:
+      case VP_OPCODE_DST:
+      case VP_OPCODE_MIN:
+      case VP_OPCODE_MAX:
+      case VP_OPCODE_SLT:
+      case VP_OPCODE_SGE:
+      case VP_OPCODE_DPH:
+      case VP_OPCODE_SUB:
+         _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
+         PrintDstReg(&inst->DstReg);
+         _mesa_printf(", ");
+         PrintSrcReg(&inst->SrcReg[0]);
+         _mesa_printf(", ");
+         PrintSrcReg(&inst->SrcReg[1]);
+         _mesa_printf(";\n");
+         break;
+      case VP_OPCODE_MAD:
+         _mesa_printf("MAD ");
+         PrintDstReg(&inst->DstReg);
+         _mesa_printf(", ");
+         PrintSrcReg(&inst->SrcReg[0]);
+         _mesa_printf(", ");
+         PrintSrcReg(&inst->SrcReg[1]);
+         _mesa_printf(", ");
+         PrintSrcReg(&inst->SrcReg[2]);
+         _mesa_printf(";\n");
+         break;
+      case VP_OPCODE_ARL:
+         _mesa_printf("ARL A0.x, ");
+         PrintSrcReg(&inst->SrcReg[0]);
+         _mesa_printf(";\n");
+         break;
+      case VP_OPCODE_END:
+         _mesa_printf("END\n");
+         return;
+      default:
+         _mesa_printf("BAD INSTRUCTION\n");
+      }
+   }
+}
+
diff --git a/src/mesa/main/nvvertparse.h b/src/mesa/main/nvvertparse.h
new file mode 100644 (file)
index 0000000..3901014
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id: nvvertparse.h,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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:
+ *    Brian Paul
+ */
+
+
+#ifndef NVVERTPARSE_H
+#define NVVERTPARSE_H
+
+
+extern void
+_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum target,
+                              const GLubyte *str, GLsizei len,
+                              struct vertex_program *program);
+
+
+extern void
+_mesa_print_nv_vertex_program(const struct vertex_program *program);
+
+
+#endif
diff --git a/src/mesa/main/nvvertprog.h b/src/mesa/main/nvvertprog.h
new file mode 100644 (file)
index 0000000..331d373
--- /dev/null
@@ -0,0 +1,107 @@
+/* $Id: nvvertprog.h,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.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.
+ */
+
+
+/* Private vertex program types and constants only used by files
+ * related to vertex programs.
+ */
+
+#ifndef NVVERTPROG_H
+#define NVVERTPROG_H
+
+
+#define VP_NUM_INPUT_REGS   MAX_NV_VERTEX_PROGRAM_INPUTS
+#define VP_NUM_OUTPUT_REGS  MAX_NV_VERTEX_PROGRAM_INPUTS
+#define VP_NUM_TEMP_REGS    MAX_NV_VERTEX_PROGRAM_TEMPS
+#define VP_NUM_PROG_REGS    MAX_NV_VERTEX_PROGRAM_PARAMS
+
+/* Location of register groups within the whole register file */
+#define VP_INPUT_REG_START  0
+#define VP_INPUT_REG_END    (VP_INPUT_REG_START + VP_NUM_INPUT_REGS - 1)
+#define VP_OUTPUT_REG_START (VP_INPUT_REG_END + 1)
+#define VP_OUTPUT_REG_END   (VP_OUTPUT_REG_START + VP_NUM_OUTPUT_REGS - 1)
+#define VP_TEMP_REG_START   (VP_OUTPUT_REG_END + 1)
+#define VP_TEMP_REG_END     (VP_TEMP_REG_START + VP_NUM_TEMP_REGS - 1)
+#define VP_PROG_REG_START   (VP_TEMP_REG_END + 1)
+#define VP_PROG_REG_END     (VP_PROG_REG_START + VP_NUM_PROG_REGS - 1)
+
+
+/* Vertex program opcodes */
+enum vp_opcode
+{
+   VP_OPCODE_MOV,
+   VP_OPCODE_LIT,
+   VP_OPCODE_RCP,
+   VP_OPCODE_RSQ,
+   VP_OPCODE_EXP,
+   VP_OPCODE_LOG,
+   VP_OPCODE_MUL,
+   VP_OPCODE_ADD,
+   VP_OPCODE_DP3,
+   VP_OPCODE_DP4,
+   VP_OPCODE_DST,
+   VP_OPCODE_MIN,
+   VP_OPCODE_MAX,
+   VP_OPCODE_SLT,
+   VP_OPCODE_SGE,
+   VP_OPCODE_MAD,
+   VP_OPCODE_ARL,
+   VP_OPCODE_DPH,
+   VP_OPCODE_RCC,
+   VP_OPCODE_SUB,
+   VP_OPCODE_ABS,
+   VP_OPCODE_END
+};
+
+
+/* Instruction source register */
+struct vp_src_register
+{
+   GLint Register;    /* or the offset from the address register */
+   GLuint Swizzle[4];
+   GLboolean Negate;
+   GLboolean RelAddr;
+};
+
+
+/* Instruction destination register */
+struct vp_dst_register
+{
+   GLint Register;
+   GLboolean WriteMask[4];
+};
+
+
+/* Vertex program instruction */
+struct vp_instruction
+{
+   enum vp_opcode Opcode;
+   struct vp_src_register SrcReg[3];
+   struct vp_dst_register DstReg;
+};
+
+
+#endif /* VERTPROG_H */
index 2b11d9b..14b62bc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: state.c,v 1.97 2002/11/06 15:16:23 brianp Exp $ */
+/* $Id: state.c,v 1.98 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -66,8 +66,8 @@
 #include "texstate.h"
 #include "mtypes.h"
 #include "varray.h"
-#if FEATURE_NV_vertex_program
-#include "vpstate.h"
+#if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program
+#include "nvprogram.h"
 #endif
 
 #include "math/m_matrix.h"
@@ -504,6 +504,21 @@ _mesa_init_exec_table(struct _glapi_table *exec, GLuint tableSize)
    exec->VertexAttribPointerNV = _mesa_VertexAttribPointerNV;
 #endif
 
+#if 0 && FEATURE_NV_fragment_program
+   exec->ProgramNamedParameter4fNV = _mesa_ProgramNamedParameter4fNV;
+   exec->ProgramNamedParameter4dNV = _mesa_ProgramNamedParameter4dNV;
+   exec->ProgramNamedParameter4fvNV = _mesa_ProgramNamedParameter4fvNV;
+   exec->ProgramNamedParameter4dvNV = _mesa_ProgramNamedParameter4dvNV;
+   exec->GetProgramNamedParameterfvNV = _mesa_GetProgramNamedParameterfvNV;
+   exec->GetProgramNamedParameterdvNV = _mesa_GetProgramNamedParameterdvNV;
+   exec->ProgramLocalParameter4dARB = _mesa_ProgramLocalParameter4dARB;
+   exec->ProgramLocalParameter4dvARB = _mesa_ProgramLocalParameter4dvARB;
+   exec->ProgramLocalParameter4fARB = _mesa_ProgramLocalParameter4fARB;
+   exec->ProgramLocalParameter4fvARB = _mesa_ProgramLocalParameter4fvARB;
+   exec->GetProgramLocalParameterdvARB = _mesa_GetProgramLocalParameterdvARB;
+   exec->GetProgramLocalParameterfvARB = _mesa_GetProgramLocalParameterfvARB;
+#endif
+
    /* 262. GL_NV_point_sprite */
    exec->PointParameteriNV = _mesa_PointParameteriNV;
    exec->PointParameterivNV = _mesa_PointParameterivNV;
index 40711cd..b5f8b28 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: texobj.c,v 1.64 2003/01/08 16:48:04 brianp Exp $ */
+/* $Id: texobj.c,v 1.65 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -564,7 +564,7 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *texName)
              * If so, unbind it and decrement the reference count.
              */
             GLuint u;
-            for (u = 0; u < MAX_TEXTURE_UNITS; u++) {
+            for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
                struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
                if (delObj == unit->Current1D) {
                   unit->Current1D = ctx->Shared->Default1D;
index 663d43e..c5994d6 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: s_aaline.c,v 1.16 2002/08/07 00:45:07 brianp Exp $ */
+/* $Id: s_aaline.c,v 1.17 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -69,12 +69,13 @@ struct LineInfo
    /* DO_SPEC */
    GLfloat srPlane[4], sgPlane[4], sbPlane[4];
    /* DO_TEX or DO_MULTITEX */
-   GLfloat sPlane[MAX_TEXTURE_UNITS][4];
-   GLfloat tPlane[MAX_TEXTURE_UNITS][4];
-   GLfloat uPlane[MAX_TEXTURE_UNITS][4];
-   GLfloat vPlane[MAX_TEXTURE_UNITS][4];
-   GLfloat lambda[MAX_TEXTURE_UNITS];
-   GLfloat texWidth[MAX_TEXTURE_UNITS], texHeight[MAX_TEXTURE_UNITS];
+   GLfloat sPlane[MAX_TEXTURE_COORD_UNITS][4];
+   GLfloat tPlane[MAX_TEXTURE_COORD_UNITS][4];
+   GLfloat uPlane[MAX_TEXTURE_COORD_UNITS][4];
+   GLfloat vPlane[MAX_TEXTURE_COORD_UNITS][4];
+   GLfloat lambda[MAX_TEXTURE_COORD_UNITS];
+   GLfloat texWidth[MAX_TEXTURE_COORD_UNITS];
+   GLfloat texHeight[MAX_TEXTURE_COORD_UNITS];
 
    struct sw_span span;
 };
index 0a70cf1..7a20ba6 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: s_aatritemp.h,v 1.30 2002/08/07 00:45:07 brianp Exp $ */
+/* $Id: s_aatritemp.h,v 1.31 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
    GLfloat sPlane[4], tPlane[4], uPlane[4], vPlane[4];
    GLfloat texWidth, texHeight;
 #elif defined(DO_MULTITEX)
-   GLfloat sPlane[MAX_TEXTURE_UNITS][4];  /* texture S */
-   GLfloat tPlane[MAX_TEXTURE_UNITS][4];  /* texture T */
-   GLfloat uPlane[MAX_TEXTURE_UNITS][4];  /* texture R */
-   GLfloat vPlane[MAX_TEXTURE_UNITS][4];  /* texture Q */
-   GLfloat texWidth[MAX_TEXTURE_UNITS], texHeight[MAX_TEXTURE_UNITS];
+   GLfloat sPlane[MAX_TEXTURE_COORD_UNITS][4];  /* texture S */
+   GLfloat tPlane[MAX_TEXTURE_COORD_UNITS][4];  /* texture T */
+   GLfloat uPlane[MAX_TEXTURE_COORD_UNITS][4];  /* texture R */
+   GLfloat vPlane[MAX_TEXTURE_COORD_UNITS][4];  /* texture Q */
+   GLfloat texWidth[MAX_TEXTURE_COORD_UNITS];
+   GLfloat texHeight[MAX_TEXTURE_COORD_UNITS];
 #endif
    GLfloat bf = SWRAST_CONTEXT(ctx)->_backface_sign;
    
index aa9620a..c4bc9de 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: s_context.c,v 1.42 2002/10/29 20:28:59 brianp Exp $ */
+/* $Id: s_context.c,v 1.43 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -516,7 +516,7 @@ _swrast_CreateContext( GLcontext *ctx )
    swrast->_IntegerAccumMode = GL_TRUE;
    swrast->_IntegerAccumScaler = 0.0;
 
-   for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
+   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
       swrast->TextureSample[i] = _swrast_validate_texture_sample;
 
    swrast->SpanArrays = MALLOC_STRUCT(span_arrays);
index e1c2297..3fd7f3c 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: s_context.h,v 1.22 2002/10/29 20:29:00 brianp Exp $ */
+/* $Id: s_context.h,v 1.23 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -121,7 +121,7 @@ typedef struct
     * _swrast_validate_derived():
     */
    GLuint _RasterMask;
-   GLfloat _MinMagThresh[MAX_TEXTURE_UNITS];
+   GLfloat _MinMagThresh[MAX_TEXTURE_IMAGE_UNITS];
    GLfloat _backface_sign;
    GLboolean _PreferPixelFog;
    GLboolean _AnyTextureCombine;
@@ -188,7 +188,7 @@ typedef struct
    /** Internal hooks, kept uptodate by the same mechanism as above.
     */
    blend_func BlendFunc;
-   TextureSampleFunc TextureSample[MAX_TEXTURE_UNITS];
+   TextureSampleFunc TextureSample[MAX_TEXTURE_IMAGE_UNITS];
 
    /** Buffer for saving the sampled texture colors.
     * Needed for GL_ARB_texture_env_crossbar implementation.
index f7bd124..d4c86ab 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: s_pointtemp.h,v 1.21 2002/11/09 21:26:41 brianp Exp $ */
+/* $Id: s_pointtemp.h,v 1.22 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  5.0
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -82,7 +82,7 @@ NAME ( GLcontext *ctx, const SWvertex *vert )
    const GLuint colorIndex = vert->index;
 #endif
 #if FLAGS & TEXTURE
-   GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+   GLfloat texcoord[MAX_TEXTURE_COORD_UNITS][4];
    GLuint u;
 #endif
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
index a03eec8..4e00c64 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: s_span.c,v 1.53 2002/11/26 03:00:04 brianp Exp $ */
+/* $Id: s_span.c,v 1.54 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -47,6 +47,7 @@
 #include "s_fog.h"
 #include "s_logic.h"
 #include "s_masking.h"
+#include "s_nvfragprog.h"
 #include "s_span.h"
 #include "s_stencil.h"
 #include "s_texture.h"
@@ -949,6 +950,18 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
       stipple_polygon_span(ctx, span);
    }
 
+   /* Fragment program */
+   if (ctx->FragmentProgram.Enabled) {
+      /* Now we may need to interpolate the colors */
+      if ((span->interpMask & SPAN_RGBA) &&
+          (span->arrayMask & SPAN_RGBA) == 0) {
+         interpolate_colors(ctx, span);
+         span->interpMask &= ~SPAN_RGBA;
+      }
+      _swrast_exec_nv_fragment_program(ctx, span);
+      monoColor = GL_FALSE;
+   }
+
    /* Do the alpha test */
    if (ctx->Color.AlphaEnabled) {
       if (!_mesa_alpha_test(ctx, span)) {
@@ -1183,7 +1196,10 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
       /* Texturing without alpha is done after depth-testing which
        * gives a potential speed-up.
        */
-      _swrast_texture_span( ctx, span );
+      if (ctx->FragmentProgram.Enabled)
+         _swrast_exec_nv_fragment_program( ctx, span );
+      else
+         _swrast_texture_span( ctx, span );
 
       /* Do the alpha test */
       if (!_mesa_alpha_test(ctx, span)) {
@@ -1232,7 +1248,10 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
       if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
          interpolate_colors(ctx, span);
 
-      _swrast_texture_span( ctx, span );
+      if (ctx->FragmentProgram.Enabled)
+         _swrast_exec_nv_fragment_program( ctx, span );
+      else
+         _swrast_texture_span( ctx, span );
    }
 
    ASSERT(span->arrayMask & SPAN_RGBA);
index 3876211..0dc4f89 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: s_tritemp.h,v 1.41 2002/11/13 16:51:02 brianp Exp $ */
+/* $Id: s_tritemp.h,v 1.42 2003/01/14 04:55:46 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -325,10 +325,10 @@ static void NAME(GLcontext *ctx, const SWvertex *v0,
       GLfloat dvdx, dvdy;
 #endif
 #ifdef INTERP_MULTITEX
-      GLfloat dsdx[MAX_TEXTURE_UNITS], dsdy[MAX_TEXTURE_UNITS];
-      GLfloat dtdx[MAX_TEXTURE_UNITS], dtdy[MAX_TEXTURE_UNITS];
-      GLfloat dudx[MAX_TEXTURE_UNITS], dudy[MAX_TEXTURE_UNITS];
-      GLfloat dvdx[MAX_TEXTURE_UNITS], dvdy[MAX_TEXTURE_UNITS];
+      GLfloat dsdx[MAX_TEXTURE_COORD_UNITS], dsdy[MAX_TEXTURE_COORD_UNITS];
+      GLfloat dtdx[MAX_TEXTURE_COORD_UNITS], dtdy[MAX_TEXTURE_COORD_UNITS];
+      GLfloat dudx[MAX_TEXTURE_COORD_UNITS], dudy[MAX_TEXTURE_COORD_UNITS];
+      GLfloat dvdx[MAX_TEXTURE_COORD_UNITS], dvdy[MAX_TEXTURE_COORD_UNITS];
 #endif
 
       /*
@@ -766,14 +766,14 @@ static void NAME(GLcontext *ctx, const SWvertex *v0,
          GLfloat vLeft=0, dvOuter=0, dvInner;
 #endif
 #ifdef INTERP_MULTITEX
-         GLfloat sLeft[MAX_TEXTURE_UNITS];
-         GLfloat tLeft[MAX_TEXTURE_UNITS];
-         GLfloat uLeft[MAX_TEXTURE_UNITS];
-         GLfloat vLeft[MAX_TEXTURE_UNITS];
-         GLfloat dsOuter[MAX_TEXTURE_UNITS], dsInner[MAX_TEXTURE_UNITS];
-         GLfloat dtOuter[MAX_TEXTURE_UNITS], dtInner[MAX_TEXTURE_UNITS];
-         GLfloat duOuter[MAX_TEXTURE_UNITS], duInner[MAX_TEXTURE_UNITS];
-         GLfloat dvOuter[MAX_TEXTURE_UNITS], dvInner[MAX_TEXTURE_UNITS];
+         GLfloat sLeft[MAX_TEXTURE_COORD_UNITS];
+         GLfloat tLeft[MAX_TEXTURE_COORD_UNITS];
+         GLfloat uLeft[MAX_TEXTURE_COORD_UNITS];
+         GLfloat vLeft[MAX_TEXTURE_COORD_UNITS];
+         GLfloat dsOuter[MAX_TEXTURE_COORD_UNITS], dsInner[MAX_TEXTURE_COORD_UNITS];
+         GLfloat dtOuter[MAX_TEXTURE_COORD_UNITS], dtInner[MAX_TEXTURE_COORD_UNITS];
+         GLfloat duOuter[MAX_TEXTURE_COORD_UNITS], duInner[MAX_TEXTURE_COORD_UNITS];
+         GLfloat dvOuter[MAX_TEXTURE_COORD_UNITS], dvInner[MAX_TEXTURE_COORD_UNITS];
 #endif
 
          for (subTriangle=0; subTriangle<=1; subTriangle++) {
index 55c1593..6113b86 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: swrast.h,v 1.33 2002/11/13 16:47:18 brianp Exp $ */
+/* $Id: swrast.h,v 1.34 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -66,7 +66,7 @@ typedef struct {
    /** win[0], win[1] are the screen-coords of SWvertex. win[2] is the
     * z-coord. what is win[3]? */
    GLfloat win[4];
-   GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+   GLfloat texcoord[MAX_TEXTURE_COORD_UNITS][4];
    GLchan color[4];
    GLchan specular[4];
    GLfloat fog;
@@ -138,8 +138,8 @@ struct span_arrays {
    GLint   y[MAX_WIDTH];  /**< X/Y used for point/line rendering only */
    GLdepth z[MAX_WIDTH];
    GLfloat fog[MAX_WIDTH];
-   GLfloat texcoords[MAX_TEXTURE_UNITS][MAX_WIDTH][4];
-   GLfloat lambda[MAX_TEXTURE_UNITS][MAX_WIDTH];
+   GLfloat texcoords[MAX_TEXTURE_COORD_UNITS][MAX_WIDTH][4];
+   GLfloat lambda[MAX_TEXTURE_COORD_UNITS][MAX_WIDTH];
    GLfloat coverage[MAX_WIDTH];
 
    /** This mask indicates if fragment is alive or culled */
@@ -189,10 +189,10 @@ struct sw_span {
    GLfixed index, indexStep;
    GLfixed z, zStep;
    GLfloat fog, fogStep;
-   GLfloat tex[MAX_TEXTURE_UNITS][4];
-   GLfloat texStepX[MAX_TEXTURE_UNITS][4];
-   GLfloat texStepY[MAX_TEXTURE_UNITS][4];
-   GLfixed intTex[2], intTexStep[2];
+   GLfloat tex[MAX_TEXTURE_COORD_UNITS][4];  /* s, t, r, q */
+   GLfloat texStepX[MAX_TEXTURE_COORD_UNITS][4];
+   GLfloat texStepY[MAX_TEXTURE_COORD_UNITS][4];
+   GLfixed intTex[2], intTexStep[2];  /* s, t only */
 
    /**
     * This bitmask (of \link SpanFlags SPAN_* flags\endlink) indicates
index 8d2c4db..fd0553f 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: ss_vbtmp.h,v 1.22 2002/10/29 20:29:01 brianp Exp $ */
+/* $Id: ss_vbtmp.h,v 1.23 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -35,14 +35,14 @@ static void TAG(emit)(GLcontext *ctx, GLuint start, GLuint end,
    struct vertex_buffer *VB = &tnl->vb;
    SWvertex *v;
    GLfloat *proj;              /* projected clip coordinates */
-   GLfloat *tc[MAX_TEXTURE_UNITS];
+   GLfloat *tc[MAX_TEXTURE_COORD_UNITS];
    GLchan *color;
    GLchan *spec;
    GLuint *index;
    GLfloat *fog;
    GLfloat *pointSize;
-   GLuint tsz[MAX_TEXTURE_UNITS];
-   GLuint tstride[MAX_TEXTURE_UNITS];
+   GLuint tsz[MAX_TEXTURE_COORD_UNITS];
+   GLuint tstride[MAX_TEXTURE_COORD_UNITS];
    GLuint proj_stride, color_stride, spec_stride, index_stride;
    GLuint fog_stride, pointSize_stride;
    GLuint i;
index db66479..1647fec 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: t_context.h,v 1.43 2002/10/09 19:45:53 brianp Exp $ */
+/* $Id: t_context.h,v 1.44 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
@@ -216,7 +216,7 @@ struct vertex_arrays
    struct gl_client_array SecondaryColor;
    GLvector1ui Index;
    GLvector1ub EdgeFlag;
-   GLvector4f  TexCoord[MAX_TEXTURE_UNITS];
+   GLvector4f  TexCoord[MAX_TEXTURE_COORD_UNITS];
    GLvector1ui Elt;
    GLvector4f  FogCoord;
    GLvector4f  Attribs[VERT_ATTRIB_MAX];
@@ -250,7 +250,7 @@ typedef struct vertex_buffer
    GLvector4f  *NormalPtr;                     /* VERT_BIT_NORMAL */
    GLfloat     *NormalLengthPtr;               /* VERT_BIT_NORMAL */
    GLboolean   *EdgeFlag;                      /* VERT_BIT_EDGEFLAG */
-   GLvector4f  *TexCoordPtr[MAX_TEXTURE_UNITS];        /* VERT_TEX_0..n */
+   GLvector4f  *TexCoordPtr[MAX_TEXTURE_COORD_UNITS]; /* VERT_TEX_0..n */
    GLvector1ui *IndexPtr[2];                   /* VERT_BIT_INDEX */
    struct gl_client_array *ColorPtr[2];                /* VERT_BIT_COLOR0 */
    struct gl_client_array *SecondaryColorPtr[2];/* VERT_BIT_COLOR1 */
index 0cd42d0..462d8db 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: t_imm_api.c,v 1.38 2002/12/05 11:49:46 keithw Exp $ */
+/* $Id: t_imm_api.c,v 1.39 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * 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"),
@@ -887,7 +887,7 @@ _tnl_Vertex4fv( const GLfloat *v )
  * don't crash.  We no-op on invalid targets.
  */
 
-#define MAX_TARGET (GL_TEXTURE0_ARB + MAX_TEXTURE_UNITS)
+#define MAX_TARGET (GL_TEXTURE0_ARB + MAX_TEXTURE_COORD_UNITS)
 
 #define MULTI_TEXCOORD1(target, s)                     \
 {                                                      \
index 14b4f7e..c87d97c 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: t_imm_debug.c,v 1.9 2002/10/24 23:57:25 brianp Exp $ */
+/* $Id: t_imm_debug.c,v 1.10 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  5.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * 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"),
@@ -127,7 +127,7 @@ void _tnl_print_cassette( struct immediate *IM )
 
       if (req & flags[i] & VERT_BITS_TEX_ANY) {
         GLuint j;
-        for (j = 0 ; j < MAX_TEXTURE_UNITS ; j++) {
+        for (j = 0 ; j < MAX_TEXTURE_COORD_UNITS ; j++) {
            if (req & flags[i] & VERT_BIT_TEX(j)) {
               _mesa_debug(NULL, "TC%d %f %f %f %f", j,
                       IM->Attrib[VERT_ATTRIB_TEX0 + j][i][0],
index fdd1cff..39cd0d4 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: t_imm_dlist.c,v 1.44 2002/10/29 20:29:02 brianp Exp $ */
+/* $Id: t_imm_dlist.c,v 1.45 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  5.1
  *
  * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
  *
@@ -569,7 +569,7 @@ static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM )
    GLuint orflag = IM->OrFlag;
    GLuint j;
    void (GLAPIENTRY *vertex)( const GLfloat * );
-   void (GLAPIENTRY *texcoordfv[MAX_TEXTURE_UNITS])( GLenum, const GLfloat * );
+   void (GLAPIENTRY *texcoordfv[MAX_TEXTURE_COORD_UNITS])( GLenum, const GLfloat * );
    GLuint maxtex = 0;
    GLuint p, length, prim = 0;
    
index 4776bb0..f445953 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: t_vb_program.c,v 1.16 2002/10/31 17:14:16 brianp Exp $ */
+/* $Id: t_vb_program.c,v 1.17 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  5.0
+ * Version:  5.1
  *
  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/*
- * -------- Regarding NV_vertex_program --------
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 
- * o Redistribution of the source code must contain a copyright notice
- *   and this list of conditions;
- * 
- * o Redistribution in binary and source code form must contain the
- *   following Notice in the software and any documentation and/or other
- *   materials provided with the distribution; and
- * 
- * o The name of Nvidia may not be used to promote or endorse software
- *   derived from the software.
- * 
- * NOTICE: Nvidia hereby grants to each recipient a non-exclusive worldwide
- * royalty free patent license under patent claims that are licensable by
- * Nvidia and which are necessarily required and for which no commercially
- * viable non infringing alternative exists to make, use, sell, offer to sell,
- * import and otherwise transfer the vertex extension for the Mesa 3D Graphics
- * Library as distributed in source code and object code form.  No hardware or
- * hardware implementation (including a semiconductor implementation and chips)
- * are licensed hereunder. If a recipient makes a patent claim or institutes
- * patent litigation against Nvidia or Nvidia's customers for use or sale of
- * Nvidia products, then this license grant as to such recipient shall
- * immediately terminate and recipient immediately agrees to cease use and
- * distribution of the Mesa Program and derivatives thereof. 
- * 
- * THE MESA 3D GRAPHICS LIBRARY IS PROVIDED ON AN "AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
- * WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-NFRINGEMENT
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- * 
- * NVIDIA SHALL NOT HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
- * LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE MESA 3D GRAPHICS
- * LIBRARY OR EVIDENCE OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDR, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * If you do not comply with this agreement, then Nvidia may cancel the license
- * and rights granted herein.
- * ---------------------------------------------
- */
 
 /**
  * \file tnl/t_vb_program.c
- * \brief Pipeline stage for executing vertex programs
+ * \brief Pipeline stage for executing NVIDIA vertex programs.
  * \author Brian Paul,  Keith Whitwell
  */
 
@@ -89,7 +44,9 @@
 #include "mmath.h"
 #include "simple_list.h"
 #include "mtypes.h"
-#include "vpexec.h"
+#include "nvvertprog.h"
+#include "nvvertexec.h"
+#include "nvprogram.h"
 
 #include "math/m_translate.h"
 
@@ -149,7 +106,7 @@ static GLboolean run_vp( GLcontext *ctx, struct gl_pipeline_stage *stage )
    struct vp_stage_data *store = VP_STAGE_DATA(stage);
    struct vertex_buffer *VB = &tnl->vb;
    struct vp_machine *machine = &(ctx->VertexProgram.Machine);
-   struct vp_program *program = ctx->VertexProgram.Current;
+   struct vertex_program *program = ctx->VertexProgram.Current;
    GLuint i;
 
    _mesa_init_tracked_matrices(ctx); /* load registers with matrices */
@@ -202,7 +159,7 @@ static GLboolean run_vp( GLcontext *ctx, struct gl_pipeline_stage *stage )
 
       /* execute the program */
       ASSERT(program);
-      _mesa_exec_program(ctx, program);
+      _mesa_exec_vertex_program(ctx, program);
 
 #if 0
       printf("Output %d: %f, %f, %f, %f\n", i,
index 4cf198b..f175970 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: t_vb_texgen.c,v 1.15 2002/10/29 20:29:04 brianp Exp $ */
+/* $Id: t_vb_texgen.c,v 1.16 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  5.1
  *
  * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
  *
@@ -59,9 +59,9 @@ struct texgen_stage_data {
 
    /* Per-texunit derived state.
     */
-   GLuint TexgenSize[MAX_TEXTURE_UNITS];
-   GLuint TexgenHoles[MAX_TEXTURE_UNITS];
-   texgen_func TexgenFunc[MAX_TEXTURE_UNITS];
+   GLuint TexgenSize[MAX_TEXTURE_COORD_UNITS];
+   GLuint TexgenHoles[MAX_TEXTURE_COORD_UNITS];
+   texgen_func TexgenFunc[MAX_TEXTURE_COORD_UNITS];
 
    /* Temporary values used in texgen.
     */
@@ -70,7 +70,7 @@ struct texgen_stage_data {
 
    /* Buffered outputs of the stage.
     */
-   GLvector4f texcoord[MAX_TEXTURE_UNITS];
+   GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS];
 };
 
 
@@ -662,7 +662,7 @@ static void free_texgen_data( struct gl_pipeline_stage *stage )
    GLuint i;
 
    if (store) {
-      for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
+      for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++)
         if (store->texcoord[i].data)
            _mesa_vector4f_free( &store->texcoord[i] );
 
index d4c62f4..06a678a 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: t_vb_texmat.c,v 1.10 2002/10/29 20:29:04 brianp Exp $ */
+/* $Id: t_vb_texmat.c,v 1.11 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  5.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * 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"),
@@ -50,7 +50,7 @@
  * is very appealing.
  */
 struct texmat_stage_data {
-   GLvector4f texcoord[MAX_TEXTURE_UNITS];
+   GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS];
 };
 
 #define TEXMAT_STAGE_DATA(stage) ((struct texmat_stage_data *)stage->privatePtr)
@@ -126,7 +126,7 @@ static void free_texmat_data( struct gl_pipeline_stage *stage )
    GLuint i;
 
    if (store) {
-      for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
+      for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
         if (store->texcoord[i].data)
            _mesa_vector4f_free( &store->texcoord[i] );
       FREE( store );