From 610d59981a9f43fefe29b34ef19c184d28e2bef5 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 14 Jan 2003 04:55:45 +0000 Subject: First batch of code for GL_NV_fragment_program. Re-org of some GL_NV_vertex_program code. Replace MAX_TEXTURE_UNITS with MAX_TEXTURE_COORD_UNITS and MAX_TEXTURE_IMAGE_UNITS. --- src/mesa/Makefile.X11 | 10 +- src/mesa/array_cache/ac_context.c | 12 +- src/mesa/array_cache/ac_context.h | 10 +- src/mesa/array_cache/ac_import.c | 4 +- src/mesa/main/Makefile.DJ | 15 +- src/mesa/main/Makefile.OSMesa16 | 10 +- src/mesa/main/Makefile.X11 | 10 +- src/mesa/main/Makefile.win | 60 +- src/mesa/main/api_arrayelt.c | 6 +- src/mesa/main/api_noop.c | 18 +- src/mesa/main/config.h | 31 +- src/mesa/main/context.c | 69 +- src/mesa/main/descrip.mms | 17 +- src/mesa/main/dlist.c | 4 +- src/mesa/main/enable.c | 20 +- src/mesa/main/extensions.c | 6 +- src/mesa/main/get.c | 144 +++- src/mesa/main/mtypes.h | 163 ++-- src/mesa/main/nvfragparse.c | 1619 +++++++++++++++++++++++++++++++++++++ src/mesa/main/nvfragparse.h | 45 ++ src/mesa/main/nvfragprog.h | 149 ++++ src/mesa/main/nvprogram.c | 1182 +++++++++++++++++++++++++++ src/mesa/main/nvprogram.h | 156 ++++ src/mesa/main/nvvertexec.c | 699 ++++++++++++++++ src/mesa/main/nvvertexec.h | 45 ++ src/mesa/main/nvvertparse.c | 1584 ++++++++++++++++++++++++++++++++++++ src/mesa/main/nvvertparse.h | 45 ++ src/mesa/main/nvvertprog.h | 107 +++ src/mesa/main/state.c | 21 +- src/mesa/main/texobj.c | 4 +- src/mesa/swrast/s_aaline.c | 17 +- src/mesa/swrast/s_aatritemp.h | 15 +- src/mesa/swrast/s_context.c | 6 +- src/mesa/swrast/s_context.h | 8 +- src/mesa/swrast/s_pointtemp.h | 6 +- src/mesa/swrast/s_span.c | 25 +- src/mesa/swrast/s_tritemp.h | 26 +- src/mesa/swrast/swrast.h | 16 +- src/mesa/swrast_setup/ss_vbtmp.h | 10 +- src/mesa/tnl/t_context.h | 8 +- src/mesa/tnl/t_imm_api.c | 8 +- src/mesa/tnl/t_imm_debug.c | 8 +- src/mesa/tnl/t_imm_dlist.c | 6 +- src/mesa/tnl/t_vb_program.c | 59 +- src/mesa/tnl/t_vb_texgen.c | 14 +- src/mesa/tnl/t_vb_texmat.c | 10 +- 46 files changed, 6150 insertions(+), 357 deletions(-) create mode 100644 src/mesa/main/nvfragparse.c create mode 100644 src/mesa/main/nvfragparse.h create mode 100644 src/mesa/main/nvfragprog.h create mode 100644 src/mesa/main/nvprogram.c create mode 100644 src/mesa/main/nvprogram.h create mode 100644 src/mesa/main/nvvertexec.c create mode 100644 src/mesa/main/nvvertexec.h create mode 100644 src/mesa/main/nvvertparse.c create mode 100644 src/mesa/main/nvvertparse.h create mode 100644 src/mesa/main/nvvertprog.h diff --git a/src/mesa/Makefile.X11 b/src/mesa/Makefile.X11 index 940135f511..9ccaafc9d8 100644 --- a/src/mesa/Makefile.X11 +++ b/src/mesa/Makefile.X11 @@ -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 \ diff --git a/src/mesa/array_cache/ac_context.c b/src/mesa/array_cache/ac_context.c index 03532e6260..a09a55cd53 100644 --- a/src/mesa/array_cache/ac_context.c +++ b/src/mesa/array_cache/ac_context.c @@ -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 ); } diff --git a/src/mesa/array_cache/ac_context.h b/src/mesa/array_cache/ac_context.h index 6b3e1a409c..fbc90743e3 100644 --- a/src/mesa/array_cache/ac_context.h +++ b/src/mesa/array_cache/ac_context.h @@ -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 */ }; diff --git a/src/mesa/array_cache/ac_import.c b/src/mesa/array_cache/ac_import.c index 1715e432ae..f8b92a4ee5 100644 --- a/src/mesa/array_cache/ac_import.c +++ b/src/mesa/array_cache/ac_import.c @@ -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 { diff --git a/src/mesa/main/Makefile.DJ b/src/mesa/main/Makefile.DJ index 5301eea352..9bbbec6bb2 100644 --- a/src/mesa/main/Makefile.DJ +++ b/src/mesa/main/Makefile.DJ @@ -1,7 +1,7 @@ # 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"), @@ -20,7 +20,7 @@ # 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. -# DOS/DJGPP core makefile v1.3 for Mesa 5.0 +# DOS/DJGPP core makefile v1.3 for Mesa 5.1 # # Copyright (C) 2002 - Borca Daniel # Email : dborca@yahoo.com @@ -119,6 +119,10 @@ CORE_SOURCES = \ lines.c \ matrix.c \ mmath.c \ + nvprogram.c \ + nvfragparse.c \ + nvvertexec.c \ + nvvertparse.c \ pixel.c \ points.c \ polygon.c \ @@ -132,10 +136,6 @@ CORE_SOURCES = \ texstate.c \ texstore.c \ texutil.c \ - varray.c \ - vpexec.c \ - vpparse.c \ - vpstate.c \ vtxfmt.c \ math/m_debug_clip.c \ math/m_debug_norm.c \ @@ -166,6 +166,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 \ diff --git a/src/mesa/main/Makefile.OSMesa16 b/src/mesa/main/Makefile.OSMesa16 index ce374d4b5b..c1899e70ac 100644 --- a/src/mesa/main/Makefile.OSMesa16 +++ b/src/mesa/main/Makefile.OSMesa16 @@ -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 \ diff --git a/src/mesa/main/Makefile.X11 b/src/mesa/main/Makefile.X11 index 940135f511..9ccaafc9d8 100644 --- a/src/mesa/main/Makefile.X11 +++ b/src/mesa/main/Makefile.X11 @@ -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 \ diff --git a/src/mesa/main/Makefile.win b/src/mesa/main/Makefile.win index 24c41d21a4..ebb59e76cd 100644 --- a/src/mesa/main/Makefile.win +++ b/src/mesa/main/Makefile.win @@ -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 \ diff --git a/src/mesa/main/api_arrayelt.c b/src/mesa/main/api_arrayelt.c index 154f6e525a..8d64b1edc3 100644 --- a/src/mesa/main/api_arrayelt.c +++ b/src/mesa/main/api_arrayelt.c @@ -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; diff --git a/src/mesa/main/api_noop.c b/src/mesa/main/api_noop.c index a44322749e..6a4226294c 100644 --- a/src/mesa/main/api_noop.c +++ b/src/mesa/main/api_noop.c @@ -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]); diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h index 985176f749..b9e58cde10 100644 --- a/src/mesa/main/config.h +++ b/src/mesa/main/config.h @@ -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"), @@ -118,6 +118,14 @@ /* 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 @@ -144,6 +152,21 @@ /* 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 + /* @@ -203,5 +226,7 @@ */ #define FEATURE_NV_vertex_program 1 +#define FEATURE_NV_fragment_program 1 + #endif /* CONFIG_H */ diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 2784fa82bd..2d43652c8a 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -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 @@ -50,7 +50,11 @@ #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; iCurrent.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 diff --git a/src/mesa/main/descrip.mms b/src/mesa/main/descrip.mms index 215ace488e..27f31caa4b 100644 --- a/src/mesa/main/descrip.mms +++ b/src/mesa/main/descrip.mms @@ -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 diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c index 2391d8dcdb..2fcfb4a703 100644 --- a/src/mesa/main/dlist.c +++ b/src/mesa/main/dlist.c @@ -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" diff --git a/src/mesa/main/enable.c b/src/mesa/main/enable.c index 744668fd29..84d0311216 100644 --- a/src/mesa/main/enable.c +++ b/src/mesa/main/enable.c @@ -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); diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index f387fb2c21..836216436c 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -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) }, @@ -190,6 +191,9 @@ _mesa_enable_sw_extensions(GLcontext *ctx) #if FEATURE_NV_vertex_program "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", diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 074972dffc..851f54fb6e 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -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; diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index fde7e3fab2..dfb3f1255e 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -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 index 0000000000..c4035f00b1 --- /dev/null +++ b/src/mesa/main/nvfragparse.c @@ -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 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, H, 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, H 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, H 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 index 0000000000..dd07be11ef --- /dev/null +++ b/src/mesa/main/nvfragparse.h @@ -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 index 0000000000..687ebb2a1c --- /dev/null +++ b/src/mesa/main/nvfragprog.h @@ -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 index 0000000000..87a1a17241 --- /dev/null +++ b/src/mesa/main/nvprogram.c @@ -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 index 0000000000..3ede705722 --- /dev/null +++ b/src/mesa/main/nvprogram.h @@ -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 index 0000000000..59fc9690d0 --- /dev/null +++ b/src/mesa/main/nvvertexec.c @@ -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 index 0000000000..76b2b66f0a --- /dev/null +++ b/src/mesa/main/nvvertexec.h @@ -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 index 0000000000..f0c51e2ddd --- /dev/null +++ b/src/mesa/main/nvvertparse.c @@ -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 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[] + */ +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 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, 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, 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 index 0000000000..3901014395 --- /dev/null +++ b/src/mesa/main/nvvertparse.h @@ -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 index 0000000000..331d373c48 --- /dev/null +++ b/src/mesa/main/nvvertprog.h @@ -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 */ diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index 2b11d9b26a..14b62bc434 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -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; diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index 40711cd13e..b5f8b287bf 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -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; diff --git a/src/mesa/swrast/s_aaline.c b/src/mesa/swrast/s_aaline.c index 663d43ec87..c5994d668f 100644 --- a/src/mesa/swrast/s_aaline.c +++ b/src/mesa/swrast/s_aaline.c @@ -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; }; diff --git a/src/mesa/swrast/s_aatritemp.h b/src/mesa/swrast/s_aatritemp.h index 0a70cf184f..7a20ba60e5 100644 --- a/src/mesa/swrast/s_aatritemp.h +++ b/src/mesa/swrast/s_aatritemp.h @@ -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. * @@ -76,11 +76,12 @@ 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; diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c index aa9620a055..c4bc9de9f1 100644 --- a/src/mesa/swrast/s_context.c +++ b/src/mesa/swrast/s_context.c @@ -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); diff --git a/src/mesa/swrast/s_context.h b/src/mesa/swrast/s_context.h index e1c22977dd..3fd7f3c3a9 100644 --- a/src/mesa/swrast/s_context.h +++ b/src/mesa/swrast/s_context.h @@ -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. diff --git a/src/mesa/swrast/s_pointtemp.h b/src/mesa/swrast/s_pointtemp.h index f7bd1240b1..d4c86ab00e 100644 --- a/src/mesa/swrast/s_pointtemp.h +++ b/src/mesa/swrast/s_pointtemp.h @@ -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); diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c index a03eec8b2a..4e00c645fa 100644 --- a/src/mesa/swrast/s_span.c +++ b/src/mesa/swrast/s_span.c @@ -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); diff --git a/src/mesa/swrast/s_tritemp.h b/src/mesa/swrast/s_tritemp.h index 38762112f0..0dc4f89182 100644 --- a/src/mesa/swrast/s_tritemp.h +++ b/src/mesa/swrast/s_tritemp.h @@ -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++) { diff --git a/src/mesa/swrast/swrast.h b/src/mesa/swrast/swrast.h index 55c1593246..6113b86061 100644 --- a/src/mesa/swrast/swrast.h +++ b/src/mesa/swrast/swrast.h @@ -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 diff --git a/src/mesa/swrast_setup/ss_vbtmp.h b/src/mesa/swrast_setup/ss_vbtmp.h index 8d2c4db41b..fd0553f2c3 100644 --- a/src/mesa/swrast_setup/ss_vbtmp.h +++ b/src/mesa/swrast_setup/ss_vbtmp.h @@ -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; diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h index db66479dc6..1647fec128 100644 --- a/src/mesa/tnl/t_context.h +++ b/src/mesa/tnl/t_context.h @@ -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 */ diff --git a/src/mesa/tnl/t_imm_api.c b/src/mesa/tnl/t_imm_api.c index 0cd42d0e48..462d8dbaf6 100644 --- a/src/mesa/tnl/t_imm_api.c +++ b/src/mesa/tnl/t_imm_api.c @@ -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) \ { \ diff --git a/src/mesa/tnl/t_imm_debug.c b/src/mesa/tnl/t_imm_debug.c index 14b4f7e4d7..c87d97cd9b 100644 --- a/src/mesa/tnl/t_imm_debug.c +++ b/src/mesa/tnl/t_imm_debug.c @@ -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], diff --git a/src/mesa/tnl/t_imm_dlist.c b/src/mesa/tnl/t_imm_dlist.c index fdd1cfffeb..39cd0d4f16 100644 --- a/src/mesa/tnl/t_imm_dlist.c +++ b/src/mesa/tnl/t_imm_dlist.c @@ -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; diff --git a/src/mesa/tnl/t_vb_program.c b/src/mesa/tnl/t_vb_program.c index 4776bb0c8b..f445953e9f 100644 --- a/src/mesa/tnl/t_vb_program.c +++ b/src/mesa/tnl/t_vb_program.c @@ -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. * @@ -24,55 +24,10 @@ * 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, diff --git a/src/mesa/tnl/t_vb_texgen.c b/src/mesa/tnl/t_vb_texgen.c index 4cf198bbac..f175970f4d 100644 --- a/src/mesa/tnl/t_vb_texgen.c +++ b/src/mesa/tnl/t_vb_texgen.c @@ -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] ); diff --git a/src/mesa/tnl/t_vb_texmat.c b/src/mesa/tnl/t_vb_texmat.c index d4c62f443a..06a678a18d 100644 --- a/src/mesa/tnl/t_vb_texmat.c +++ b/src/mesa/tnl/t_vb_texmat.c @@ -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 ); -- cgit v1.2.3