aboutsummaryrefslogtreecommitdiffstats
path: root/src/mesa/shader
diff options
context:
space:
mode:
authorThierry Reding <[email protected]>2006-10-14 03:46:41 +0000
committerThierry Reding <[email protected]>2006-10-14 03:46:41 +0000
commit1ddf606332a188e46a47607cd41eb5d81bdf4c8a (patch)
tree8cb51078803106d87aedeae7bbd7a762a0d369d1 /src/mesa/shader
Import Mesa 6.5.1 (MesaLib, MesaDemos, MesaGLUT).
Diffstat (limited to 'src/mesa/shader')
-rw-r--r--src/mesa/shader/arbprogparse.c4116
-rw-r--r--src/mesa/shader/arbprogparse.h41
-rw-r--r--src/mesa/shader/arbprogram.c763
-rw-r--r--src/mesa/shader/arbprogram.h138
-rw-r--r--src/mesa/shader/arbprogram_syn.h1327
-rw-r--r--src/mesa/shader/atifragshader.c757
-rw-r--r--src/mesa/shader/atifragshader.h121
-rw-r--r--src/mesa/shader/descrip.mms77
-rw-r--r--src/mesa/shader/grammar/descrip.mms41
-rw-r--r--src/mesa/shader/grammar/grammar.c3148
-rw-r--r--src/mesa/shader/grammar/grammar.h103
-rwxr-xr-xsrc/mesa/shader/grammar/grammar_crt.c64
-rwxr-xr-xsrc/mesa/shader/grammar/grammar_crt.h20
-rw-r--r--src/mesa/shader/grammar/grammar_mesa.c87
-rw-r--r--src/mesa/shader/grammar/grammar_mesa.h43
-rw-r--r--src/mesa/shader/grammar/grammar_syn.h202
-rw-r--r--src/mesa/shader/nvfragparse.c1834
-rw-r--r--src/mesa/shader/nvfragparse.h52
-rw-r--r--src/mesa/shader/nvprogram.c873
-rw-r--r--src/mesa/shader/nvprogram.h119
-rw-r--r--src/mesa/shader/nvvertexec.c852
-rw-r--r--src/mesa/shader/nvvertexec.h43
-rw-r--r--src/mesa/shader/nvvertparse.c1590
-rw-r--r--src/mesa/shader/nvvertparse.h50
-rw-r--r--src/mesa/shader/program.c2206
-rw-r--r--src/mesa/shader/program.h305
-rw-r--r--src/mesa/shader/program_instruction.h355
-rw-r--r--src/mesa/shader/programopt.c147
-rw-r--r--src/mesa/shader/programopt.h37
-rw-r--r--src/mesa/shader/shaderobjects.c1214
-rw-r--r--src/mesa/shader/shaderobjects.h278
-rwxr-xr-xsrc/mesa/shader/shaderobjects_3dlabs.c1982
-rwxr-xr-xsrc/mesa/shader/shaderobjects_3dlabs.h51
-rw-r--r--src/mesa/shader/slang/descrip.mms65
-rwxr-xr-xsrc/mesa/shader/slang/library/gc_to_bin.c87
-rw-r--r--src/mesa/shader/slang/library/slang_builtin_vec4_gc.h62
-rw-r--r--src/mesa/shader/slang/library/slang_common_builtin_gc.h647
-rw-r--r--src/mesa/shader/slang/library/slang_core_gc.h545
-rw-r--r--src/mesa/shader/slang/library/slang_fragment_builtin_gc.h79
-rw-r--r--src/mesa/shader/slang/library/slang_pp_version_syn.h69
-rw-r--r--src/mesa/shader/slang/library/slang_shader_syn.h758
-rw-r--r--src/mesa/shader/slang/library/slang_vertex_builtin_gc.h78
-rw-r--r--src/mesa/shader/slang/library/syn_to_c.c72
-rw-r--r--src/mesa/shader/slang/slang_analyse.c100
-rw-r--r--src/mesa/shader/slang/slang_analyse.h50
-rw-r--r--src/mesa/shader/slang/slang_assemble.c1503
-rw-r--r--src/mesa/shader/slang/slang_assemble.h228
-rw-r--r--src/mesa/shader/slang/slang_assemble_assignment.c217
-rw-r--r--src/mesa/shader/slang/slang_assemble_assignment.h42
-rw-r--r--src/mesa/shader/slang/slang_assemble_conditional.c448
-rw-r--r--src/mesa/shader/slang/slang_assemble_conditional.h51
-rw-r--r--src/mesa/shader/slang/slang_assemble_constructor.c379
-rw-r--r--src/mesa/shader/slang/slang_assemble_constructor.h64
-rw-r--r--src/mesa/shader/slang/slang_assemble_typeinfo.c587
-rw-r--r--src/mesa/shader/slang/slang_assemble_typeinfo.h116
-rw-r--r--src/mesa/shader/slang/slang_compile.c2082
-rw-r--r--src/mesa/shader/slang/slang_compile.h117
-rw-r--r--src/mesa/shader/slang/slang_compile_function.c188
-rw-r--r--src/mesa/shader/slang/slang_compile_function.h87
-rw-r--r--src/mesa/shader/slang/slang_compile_operation.c98
-rw-r--r--src/mesa/shader/slang/slang_compile_operation.h117
-rw-r--r--src/mesa/shader/slang/slang_compile_struct.c169
-rw-r--r--src/mesa/shader/slang/slang_compile_struct.h63
-rw-r--r--src/mesa/shader/slang/slang_compile_variable.c370
-rw-r--r--src/mesa/shader/slang/slang_compile_variable.h95
-rw-r--r--src/mesa/shader/slang/slang_execute.c729
-rw-r--r--src/mesa/shader/slang/slang_execute.h85
-rw-r--r--src/mesa/shader/slang/slang_execute_x86.c748
-rw-r--r--src/mesa/shader/slang/slang_export.c386
-rw-r--r--src/mesa/shader/slang/slang_export.h183
-rw-r--r--src/mesa/shader/slang/slang_library_noise.c501
-rw-r--r--src/mesa/shader/slang/slang_library_noise.h42
-rw-r--r--src/mesa/shader/slang/slang_library_texsample.c172
-rw-r--r--src/mesa/shader/slang/slang_library_texsample.h44
-rw-r--r--src/mesa/shader/slang/slang_link.c805
-rw-r--r--src/mesa/shader/slang/slang_link.h316
-rw-r--r--src/mesa/shader/slang/slang_mesa.h36
-rw-r--r--src/mesa/shader/slang/slang_preprocess.c77
-rw-r--r--src/mesa/shader/slang/slang_preprocess.h42
-rw-r--r--src/mesa/shader/slang/slang_storage.c342
-rw-r--r--src/mesa/shader/slang/slang_storage.h141
-rw-r--r--src/mesa/shader/slang/slang_utility.c112
-rw-r--r--src/mesa/shader/slang/slang_utility.h74
-rw-r--r--src/mesa/shader/slang/traverse_wrap.h112
84 files changed, 37616 insertions, 0 deletions
diff --git a/src/mesa/shader/arbprogparse.c b/src/mesa/shader/arbprogparse.c
new file mode 100644
index 00000000000..b8e5e4bd8ae
--- /dev/null
+++ b/src/mesa/shader/arbprogparse.c
@@ -0,0 +1,4116 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 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.
+ */
+
+#define DEBUG_PARSING 0
+
+/**
+ * \file arbprogparse.c
+ * ARB_*_program parser core
+ * \author Karl Rasche
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "arbprogparse.h"
+#include "grammar_mesa.h"
+#include "program.h"
+#include "context.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "program_instruction.h"
+
+
+/* For ARB programs, use the NV instruction limits */
+#define MAX_INSTRUCTIONS MAX2(MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS, \
+ MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
+
+
+/**
+ * This is basically a union of the vertex_program and fragment_program
+ * structs that we can use to parse the program into
+ *
+ * XXX we can probably get rid of this entirely someday.
+ */
+struct arb_program
+{
+ struct gl_program Base;
+
+ GLuint Position; /* Just used for error reporting while parsing */
+ GLuint MajorVersion;
+ GLuint MinorVersion;
+
+ /* ARB_vertex_progmra options */
+ GLboolean HintPositionInvariant;
+
+ /* ARB_fragment_progmra options */
+ GLenum PrecisionOption; /* GL_DONT_CARE, GL_NICEST or GL_FASTEST */
+ GLenum FogOption; /* GL_NONE, GL_LINEAR, GL_EXP or GL_EXP2 */
+
+ /* ARB_fragment_program specifics */
+ GLbitfield TexturesUsed[MAX_TEXTURE_IMAGE_UNITS];
+ GLuint NumAluInstructions;
+ GLuint NumTexInstructions;
+ GLuint NumTexIndirections;
+
+ GLboolean UsesKill;
+};
+
+
+#ifndef __extension__
+#if !defined(__GNUC__) || (__GNUC__ < 2) || \
+ ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 7))
+# define __extension__
+#endif
+#endif
+
+/* TODO:
+ * Fragment Program Stuff:
+ * -----------------------------------------------------
+ *
+ * - things from Michal's email
+ * + overflow on atoi
+ * + not-overflowing floats (don't use parse_integer..)
+ * + can remove range checking in arbparse.c
+ *
+ * - check all limits of number of various variables
+ * + parameters
+ *
+ * - test! test! test!
+ *
+ * Vertex Program Stuff:
+ * -----------------------------------------------------
+ * - Optimize param array usage and count limits correctly, see spec,
+ * section 2.14.3.7
+ * + Record if an array is reference absolutly or relatively (or both)
+ * + For absolute arrays, store a bitmap of accesses
+ * + For single parameters, store an access flag
+ * + After parsing, make a parameter cleanup and merging pass, where
+ * relative arrays are layed out first, followed by abs arrays, and
+ * finally single state.
+ * + Remap offsets for param src and dst registers
+ * + Now we can properly count parameter usage
+ *
+ * - Multiple state binding errors in param arrays (see spec, just before
+ * section 2.14.3.3)
+ * - grep for XXX
+ *
+ * Mesa Stuff
+ * -----------------------------------------------------
+ * - User clipping planes vs. PositionInvariant
+ * - Is it sufficient to just multiply by the mvp to transform in the
+ * PositionInvariant case? Or do we need something more involved?
+ *
+ * - vp_src swizzle is GLubyte, fp_src swizzle is GLuint
+ * - fetch state listed in program_parameters list
+ * + WTF should this go???
+ * + currently in nvvertexec.c and s_nvfragprog.c
+ *
+ * - allow for multiple address registers (and fetch address regs properly)
+ *
+ * Cosmetic Stuff
+ * -----------------------------------------------------
+ * - remove any leftover unused grammer.c stuff (dict_ ?)
+ * - fix grammer.c error handling so its not static
+ * - #ifdef around stuff pertaining to extentions
+ *
+ * Outstanding Questions:
+ * -----------------------------------------------------
+ * - ARB_matrix_palette / ARB_vertex_blend -- not supported
+ * what gets hacked off because of this:
+ * + VERTEX_ATTRIB_MATRIXINDEX
+ * + VERTEX_ATTRIB_WEIGHT
+ * + MATRIX_MODELVIEW
+ * + MATRIX_PALETTE
+ *
+ * - When can we fetch env/local params from their own register files, and
+ * when to we have to fetch them into the main state register file?
+ * (think arrays)
+ *
+ * Grammar Changes:
+ * -----------------------------------------------------
+ */
+
+/* Changes since moving the file to shader directory
+
+2004-III-4 ------------------------------------------------------------
+- added #include "grammar_mesa.h"
+- removed grammar specific code part (it resides now in grammar.c)
+- added GL_ARB_fragment_program_shadow tokens
+- modified #include "arbparse_syn.h"
+- major changes inside _mesa_parse_arb_program()
+- check the program string for '\0' characters
+- copy the program string to a one-byte-longer location to have
+ it null-terminated
+- position invariance test (not writing to result.position) moved
+ to syntax part
+*/
+
+typedef GLubyte *production;
+
+/**
+ * This is the text describing the rules to parse the grammar
+ */
+__extension__ static char arb_grammar_text[] =
+#include "arbprogram_syn.h"
+;
+
+/**
+ * These should match up with the values defined in arbprogram.syn
+ */
+
+/*
+ Changes:
+ - changed and merged V_* and F_* opcode values to OP_*.
+ - added GL_ARB_fragment_program_shadow specific tokens (michal)
+*/
+#define REVISION 0x09
+
+/* program type */
+#define FRAGMENT_PROGRAM 0x01
+#define VERTEX_PROGRAM 0x02
+
+/* program section */
+#define OPTION 0x01
+#define INSTRUCTION 0x02
+#define DECLARATION 0x03
+#define END 0x04
+
+/* GL_ARB_fragment_program option */
+#define ARB_PRECISION_HINT_FASTEST 0x00
+#define ARB_PRECISION_HINT_NICEST 0x01
+#define ARB_FOG_EXP 0x02
+#define ARB_FOG_EXP2 0x03
+#define ARB_FOG_LINEAR 0x04
+
+/* GL_ARB_vertex_program option */
+#define ARB_POSITION_INVARIANT 0x05
+
+/* GL_ARB_fragment_program_shadow option */
+#define ARB_FRAGMENT_PROGRAM_SHADOW 0x06
+
+/* GL_ARB_draw_buffers option */
+#define ARB_DRAW_BUFFERS 0x07
+
+/* GL_ARB_fragment_program instruction class */
+#define OP_ALU_INST 0x00
+#define OP_TEX_INST 0x01
+
+/* GL_ARB_vertex_program instruction class */
+/* OP_ALU_INST */
+
+/* GL_ARB_fragment_program instruction type */
+#define OP_ALU_VECTOR 0x00
+#define OP_ALU_SCALAR 0x01
+#define OP_ALU_BINSC 0x02
+#define OP_ALU_BIN 0x03
+#define OP_ALU_TRI 0x04
+#define OP_ALU_SWZ 0x05
+#define OP_TEX_SAMPLE 0x06
+#define OP_TEX_KIL 0x07
+
+/* GL_ARB_vertex_program instruction type */
+#define OP_ALU_ARL 0x08
+/* OP_ALU_VECTOR */
+/* OP_ALU_SCALAR */
+/* OP_ALU_BINSC */
+/* OP_ALU_BIN */
+/* OP_ALU_TRI */
+/* OP_ALU_SWZ */
+
+/* GL_ARB_fragment_program instruction code */
+#define OP_ABS 0x00
+#define OP_ABS_SAT 0x1B
+#define OP_FLR 0x09
+#define OP_FLR_SAT 0x26
+#define OP_FRC 0x0A
+#define OP_FRC_SAT 0x27
+#define OP_LIT 0x0C
+#define OP_LIT_SAT 0x2A
+#define OP_MOV 0x11
+#define OP_MOV_SAT 0x30
+#define OP_COS 0x1F
+#define OP_COS_SAT 0x20
+#define OP_EX2 0x07
+#define OP_EX2_SAT 0x25
+#define OP_LG2 0x0B
+#define OP_LG2_SAT 0x29
+#define OP_RCP 0x14
+#define OP_RCP_SAT 0x33
+#define OP_RSQ 0x15
+#define OP_RSQ_SAT 0x34
+#define OP_SIN 0x38
+#define OP_SIN_SAT 0x39
+#define OP_SCS 0x35
+#define OP_SCS_SAT 0x36
+#define OP_POW 0x13
+#define OP_POW_SAT 0x32
+#define OP_ADD 0x01
+#define OP_ADD_SAT 0x1C
+#define OP_DP3 0x03
+#define OP_DP3_SAT 0x21
+#define OP_DP4 0x04
+#define OP_DP4_SAT 0x22
+#define OP_DPH 0x05
+#define OP_DPH_SAT 0x23
+#define OP_DST 0x06
+#define OP_DST_SAT 0x24
+#define OP_MAX 0x0F
+#define OP_MAX_SAT 0x2E
+#define OP_MIN 0x10
+#define OP_MIN_SAT 0x2F
+#define OP_MUL 0x12
+#define OP_MUL_SAT 0x31
+#define OP_SGE 0x16
+#define OP_SGE_SAT 0x37
+#define OP_SLT 0x17
+#define OP_SLT_SAT 0x3A
+#define OP_SUB 0x18
+#define OP_SUB_SAT 0x3B
+#define OP_XPD 0x1A
+#define OP_XPD_SAT 0x43
+#define OP_CMP 0x1D
+#define OP_CMP_SAT 0x1E
+#define OP_LRP 0x2B
+#define OP_LRP_SAT 0x2C
+#define OP_MAD 0x0E
+#define OP_MAD_SAT 0x2D
+#define OP_SWZ 0x19
+#define OP_SWZ_SAT 0x3C
+#define OP_TEX 0x3D
+#define OP_TEX_SAT 0x3E
+#define OP_TXB 0x3F
+#define OP_TXB_SAT 0x40
+#define OP_TXP 0x41
+#define OP_TXP_SAT 0x42
+#define OP_KIL 0x28
+
+/* GL_ARB_vertex_program instruction code */
+#define OP_ARL 0x02
+/* OP_ABS */
+/* OP_FLR */
+/* OP_FRC */
+/* OP_LIT */
+/* OP_MOV */
+/* OP_EX2 */
+#define OP_EXP 0x08
+/* OP_LG2 */
+#define OP_LOG 0x0D
+/* OP_RCP */
+/* OP_RSQ */
+/* OP_POW */
+/* OP_ADD */
+/* OP_DP3 */
+/* OP_DP4 */
+/* OP_DPH */
+/* OP_DST */
+/* OP_MAX */
+/* OP_MIN */
+/* OP_MUL */
+/* OP_SGE */
+/* OP_SLT */
+/* OP_SUB */
+/* OP_XPD */
+/* OP_MAD */
+/* OP_SWZ */
+
+/* fragment attribute binding */
+#define FRAGMENT_ATTRIB_COLOR 0x01
+#define FRAGMENT_ATTRIB_TEXCOORD 0x02
+#define FRAGMENT_ATTRIB_FOGCOORD 0x03
+#define FRAGMENT_ATTRIB_POSITION 0x04
+
+/* vertex attribute binding */
+#define VERTEX_ATTRIB_POSITION 0x01
+#define VERTEX_ATTRIB_WEIGHT 0x02
+#define VERTEX_ATTRIB_NORMAL 0x03
+#define VERTEX_ATTRIB_COLOR 0x04
+#define VERTEX_ATTRIB_FOGCOORD 0x05
+#define VERTEX_ATTRIB_TEXCOORD 0x06
+#define VERTEX_ATTRIB_MATRIXINDEX 0x07
+#define VERTEX_ATTRIB_GENERIC 0x08
+
+/* fragment result binding */
+#define FRAGMENT_RESULT_COLOR 0x01
+#define FRAGMENT_RESULT_DEPTH 0x02
+
+/* vertex result binding */
+#define VERTEX_RESULT_POSITION 0x01
+#define VERTEX_RESULT_COLOR 0x02
+#define VERTEX_RESULT_FOGCOORD 0x03
+#define VERTEX_RESULT_POINTSIZE 0x04
+#define VERTEX_RESULT_TEXCOORD 0x05
+
+/* texture target */
+#define TEXTARGET_1D 0x01
+#define TEXTARGET_2D 0x02
+#define TEXTARGET_3D 0x03
+#define TEXTARGET_RECT 0x04
+#define TEXTARGET_CUBE 0x05
+/* GL_ARB_fragment_program_shadow */
+#define TEXTARGET_SHADOW1D 0x06
+#define TEXTARGET_SHADOW2D 0x07
+#define TEXTARGET_SHADOWRECT 0x08
+
+/* face type */
+#define FACE_FRONT 0x00
+#define FACE_BACK 0x01
+
+/* color type */
+#define COLOR_PRIMARY 0x00
+#define COLOR_SECONDARY 0x01
+
+/* component */
+#define COMPONENT_X 0x00
+#define COMPONENT_Y 0x01
+#define COMPONENT_Z 0x02
+#define COMPONENT_W 0x03
+#define COMPONENT_0 0x04
+#define COMPONENT_1 0x05
+
+/* array index type */
+#define ARRAY_INDEX_ABSOLUTE 0x00
+#define ARRAY_INDEX_RELATIVE 0x01
+
+/* matrix name */
+#define MATRIX_MODELVIEW 0x01
+#define MATRIX_PROJECTION 0x02
+#define MATRIX_MVP 0x03
+#define MATRIX_TEXTURE 0x04
+#define MATRIX_PALETTE 0x05
+#define MATRIX_PROGRAM 0x06
+
+/* matrix modifier */
+#define MATRIX_MODIFIER_IDENTITY 0x00
+#define MATRIX_MODIFIER_INVERSE 0x01
+#define MATRIX_MODIFIER_TRANSPOSE 0x02
+#define MATRIX_MODIFIER_INVTRANS 0x03
+
+/* constant type */
+#define CONSTANT_SCALAR 0x01
+#define CONSTANT_VECTOR 0x02
+
+/* program param type */
+#define PROGRAM_PARAM_ENV 0x01
+#define PROGRAM_PARAM_LOCAL 0x02
+
+/* register type */
+#define REGISTER_ATTRIB 0x01
+#define REGISTER_PARAM 0x02
+#define REGISTER_RESULT 0x03
+#define REGISTER_ESTABLISHED_NAME 0x04
+
+/* param binding */
+#define PARAM_NULL 0x00
+#define PARAM_ARRAY_ELEMENT 0x01
+#define PARAM_STATE_ELEMENT 0x02
+#define PARAM_PROGRAM_ELEMENT 0x03
+#define PARAM_PROGRAM_ELEMENTS 0x04
+#define PARAM_CONSTANT 0x05
+
+/* param state property */
+#define STATE_MATERIAL_PARSER 0x01
+#define STATE_LIGHT_PARSER 0x02
+#define STATE_LIGHT_MODEL 0x03
+#define STATE_LIGHT_PROD 0x04
+#define STATE_FOG 0x05
+#define STATE_MATRIX_ROWS 0x06
+/* GL_ARB_fragment_program */
+#define STATE_TEX_ENV 0x07
+#define STATE_DEPTH 0x08
+/* GL_ARB_vertex_program */
+#define STATE_TEX_GEN 0x09
+#define STATE_CLIP_PLANE 0x0A
+#define STATE_POINT 0x0B
+
+/* state material property */
+#define MATERIAL_AMBIENT 0x01
+#define MATERIAL_DIFFUSE 0x02
+#define MATERIAL_SPECULAR 0x03
+#define MATERIAL_EMISSION 0x04
+#define MATERIAL_SHININESS 0x05
+
+/* state light property */
+#define LIGHT_AMBIENT 0x01
+#define LIGHT_DIFFUSE 0x02
+#define LIGHT_SPECULAR 0x03
+#define LIGHT_POSITION 0x04
+#define LIGHT_ATTENUATION 0x05
+#define LIGHT_HALF 0x06
+#define LIGHT_SPOT_DIRECTION 0x07
+
+/* state light model property */
+#define LIGHT_MODEL_AMBIENT 0x01
+#define LIGHT_MODEL_SCENECOLOR 0x02
+
+/* state light product property */
+#define LIGHT_PROD_AMBIENT 0x01
+#define LIGHT_PROD_DIFFUSE 0x02
+#define LIGHT_PROD_SPECULAR 0x03
+
+/* state texture environment property */
+#define TEX_ENV_COLOR 0x01
+
+/* state texture generation coord property */
+#define TEX_GEN_EYE 0x01
+#define TEX_GEN_OBJECT 0x02
+
+/* state fog property */
+#define FOG_COLOR 0x01
+#define FOG_PARAMS 0x02
+
+/* state depth property */
+#define DEPTH_RANGE 0x01
+
+/* state point parameters property */
+#define POINT_SIZE 0x01
+#define POINT_ATTENUATION 0x02
+
+/* declaration */
+#define ATTRIB 0x01
+#define PARAM 0x02
+#define TEMP 0x03
+#define OUTPUT 0x04
+#define ALIAS 0x05
+/* GL_ARB_vertex_program */
+#define ADDRESS 0x06
+
+/*-----------------------------------------------------------------------
+ * From here on down is the semantic checking portion
+ *
+ */
+
+/**
+ * Variable Table Handling functions
+ */
+typedef enum
+{
+ vt_none,
+ vt_address,
+ vt_attrib,
+ vt_param,
+ vt_temp,
+ vt_output,
+ vt_alias
+} var_type;
+
+
+/**
+ * Setting an explicit field for each of the binding properties is a bit
+ * wasteful of space, but it should be much more clear when reading later on..
+ */
+struct var_cache
+{
+ const GLubyte *name; /* don't free() - no need */
+ var_type type;
+ GLuint address_binding; /* The index of the address register we should
+ * be using */
+ GLuint attrib_binding; /* For type vt_attrib, see nvfragprog.h for values */
+ GLuint attrib_is_generic; /* If the attrib was specified through a generic
+ * vertex attrib */
+ GLuint temp_binding; /* The index of the temp register we are to use */
+ GLuint output_binding; /* Output/result register number */
+ struct var_cache *alias_binding; /* For type vt_alias, points to the var_cache entry
+ * that this is aliased to */
+ GLuint param_binding_type; /* {PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM,
+ * PROGRAM_ENV_PARAM} */
+ GLuint param_binding_begin; /* This is the offset into the program_parameter_list where
+ * the tokens representing our bound state (or constants)
+ * start */
+ GLuint param_binding_length; /* This is how many entries in the the program_parameter_list
+ * we take up with our state tokens or constants. Note that
+ * this is _not_ the same as the number of param registers
+ * we eventually use */
+ struct var_cache *next;
+};
+
+static GLvoid
+var_cache_create (struct var_cache **va)
+{
+ *va = (struct var_cache *) _mesa_malloc (sizeof (struct var_cache));
+ if (*va) {
+ (**va).name = NULL;
+ (**va).type = vt_none;
+ (**va).attrib_binding = ~0;
+ (**va).attrib_is_generic = 0;
+ (**va).temp_binding = ~0;
+ (**va).output_binding = ~0;
+ (**va).param_binding_type = ~0;
+ (**va).param_binding_begin = ~0;
+ (**va).param_binding_length = ~0;
+ (**va).alias_binding = NULL;
+ (**va).next = NULL;
+ }
+}
+
+static GLvoid
+var_cache_destroy (struct var_cache **va)
+{
+ if (*va) {
+ var_cache_destroy (&(**va).next);
+ _mesa_free (*va);
+ *va = NULL;
+ }
+}
+
+static GLvoid
+var_cache_append (struct var_cache **va, struct var_cache *nv)
+{
+ if (*va)
+ var_cache_append (&(**va).next, nv);
+ else
+ *va = nv;
+}
+
+static struct var_cache *
+var_cache_find (struct var_cache *va, const GLubyte * name)
+{
+ /*struct var_cache *first = va;*/
+
+ while (va) {
+ if (!_mesa_strcmp ( (const char*) name, (const char*) va->name)) {
+ if (va->type == vt_alias)
+ return va->alias_binding;
+ return va;
+ }
+
+ va = va->next;
+ }
+
+ return NULL;
+}
+
+
+
+/**
+ * Called when an error is detected while parsing/compiling a program.
+ * Sets the ctx->Program.ErrorString field to descript and records a
+ * GL_INVALID_OPERATION error.
+ * \param position position of error in program string
+ * \param descrip verbose error description
+ */
+static void
+program_error(GLcontext *ctx, GLint position, const char *descrip)
+{
+ if (descrip) {
+ const char *prefix = "glProgramString(", *suffix = ")";
+ char *str = (char *) _mesa_malloc(_mesa_strlen(descrip) +
+ _mesa_strlen(prefix) +
+ _mesa_strlen(suffix) + 1);
+ if (str) {
+ _mesa_sprintf(str, "%s%s%s", prefix, descrip, suffix);
+ _mesa_error(ctx, GL_INVALID_OPERATION, str);
+ _mesa_free(str);
+ }
+ }
+ _mesa_set_program_error(ctx, position, descrip);
+}
+
+
+
+/**
+ * constructs an integer from 4 GLubytes in LE format
+ */
+static GLuint
+parse_position (const GLubyte ** inst)
+{
+ GLuint value;
+
+ value = (GLuint) (*(*inst)++);
+ value += (GLuint) (*(*inst)++) * 0x100;
+ value += (GLuint) (*(*inst)++) * 0x10000;
+ value += (GLuint) (*(*inst)++) * 0x1000000;
+
+ return value;
+}
+
+/**
+ * This will, given a string, lookup the string as a variable name in the
+ * var cache. If the name is found, the var cache node corresponding to the
+ * var name is returned. If it is not found, a new entry is allocated
+ *
+ * \param I Points into the binary array where the string identifier begins
+ * \param found 1 if the string was found in the var_cache, 0 if it was allocated
+ * \return The location on the var_cache corresponding the the string starting at I
+ */
+static struct var_cache *
+parse_string (const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program, GLuint * found)
+{
+ const GLubyte *i = *inst;
+ struct var_cache *va = NULL;
+ (void) Program;
+
+ *inst += _mesa_strlen ((char *) i) + 1;
+
+ va = var_cache_find (*vc_head, i);
+
+ if (va) {
+ *found = 1;
+ return va;
+ }
+
+ *found = 0;
+ var_cache_create (&va);
+ va->name = (const GLubyte *) i;
+
+ var_cache_append (vc_head, va);
+
+ return va;
+}
+
+static char *
+parse_string_without_adding (const GLubyte ** inst, struct arb_program *Program)
+{
+ const GLubyte *i = *inst;
+ (void) Program;
+
+ *inst += _mesa_strlen ((char *) i) + 1;
+
+ return (char *) i;
+}
+
+/**
+ * \return -1 if we parse '-', return 1 otherwise
+ */
+static GLint
+parse_sign (const GLubyte ** inst)
+{
+ /*return *(*inst)++ != '+'; */
+
+ if (**inst == '-') {
+ (*inst)++;
+ return -1;
+ }
+ else if (**inst == '+') {
+ (*inst)++;
+ return 1;
+ }
+
+ return 1;
+}
+
+/**
+ * parses and returns signed integer
+ */
+static GLint
+parse_integer (const GLubyte ** inst, struct arb_program *Program)
+{
+ GLint sign;
+ GLint value;
+
+ /* check if *inst points to '+' or '-'
+ * if yes, grab the sign and increment *inst
+ */
+ sign = parse_sign (inst);
+
+ /* now check if *inst points to 0
+ * if yes, increment the *inst and return the default value
+ */
+ if (**inst == 0) {
+ (*inst)++;
+ return 0;
+ }
+
+ /* parse the integer as you normally would do it */
+ value = _mesa_atoi (parse_string_without_adding (inst, Program));
+
+ /* now, after terminating 0 there is a position
+ * to parse it - parse_position()
+ */
+ Program->Position = parse_position (inst);
+
+ return value * sign;
+}
+
+/**
+ Accumulate this string of digits, and return them as
+ a large integer represented in floating point (for range).
+ If scale is not NULL, also accumulates a power-of-ten
+ integer scale factor that represents the number of digits
+ in the string.
+*/
+static GLdouble
+parse_float_string(const GLubyte ** inst, struct arb_program *Program, GLdouble *scale)
+{
+ GLdouble value = 0.0;
+ GLdouble oscale = 1.0;
+
+ if (**inst == 0) { /* this string of digits is empty-- do nothing */
+ (*inst)++;
+ }
+ else { /* nonempty string-- parse out the digits */
+ while (**inst >= '0' && **inst <= '9') {
+ GLubyte digit = *((*inst)++);
+ value = value * 10.0 + (GLint) (digit - '0');
+ oscale *= 10.0;
+ }
+ assert(**inst == 0); /* integer string should end with 0 */
+ (*inst)++; /* skip over terminating 0 */
+ Program->Position = parse_position(inst); /* skip position (from integer) */
+ }
+ if (scale)
+ *scale = oscale;
+ return value;
+}
+
+/**
+ Parse an unsigned floating-point number from this stream of tokenized
+ characters. Example floating-point formats supported:
+ 12.34
+ 12
+ 0.34
+ .34
+ 12.34e-4
+ */
+static GLfloat
+parse_float (const GLubyte ** inst, struct arb_program *Program)
+{
+ GLint exponent;
+ GLdouble whole, fraction, fracScale = 1.0;
+
+ whole = parse_float_string(inst, Program, 0);
+ fraction = parse_float_string(inst, Program, &fracScale);
+
+ /* Parse signed exponent */
+ exponent = parse_integer(inst, Program); /* This is the exponent */
+
+ /* Assemble parts of floating-point number: */
+ return (GLfloat) ((whole + fraction / fracScale) *
+ _mesa_pow(10.0, (GLfloat) exponent));
+}
+
+
+/**
+ */
+static GLfloat
+parse_signed_float (const GLubyte ** inst, struct arb_program *Program)
+{
+ GLint sign = parse_sign (inst);
+ GLfloat value = parse_float (inst, Program);
+ return value * sign;
+}
+
+/**
+ * This picks out a constant value from the parsed array. The constant vector is r
+ * returned in the *values array, which should be of length 4.
+ *
+ * \param values - The 4 component vector with the constant value in it
+ */
+static GLvoid
+parse_constant (const GLubyte ** inst, GLfloat *values, struct arb_program *Program,
+ GLboolean use)
+{
+ GLuint components, i;
+
+
+ switch (*(*inst)++) {
+ case CONSTANT_SCALAR:
+ if (use == GL_TRUE) {
+ values[0] =
+ values[1] =
+ values[2] = values[3] = parse_float (inst, Program);
+ }
+ else {
+ values[0] =
+ values[1] =
+ values[2] = values[3] = parse_signed_float (inst, Program);
+ }
+
+ break;
+ case CONSTANT_VECTOR:
+ values[0] = values[1] = values[2] = 0;
+ values[3] = 1;
+ components = *(*inst)++;
+ for (i = 0; i < components; i++) {
+ values[i] = parse_signed_float (inst, Program);
+ }
+ break;
+ }
+}
+
+/**
+ * \param offset The offset from the address register that we should
+ * address
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_relative_offset(GLcontext *ctx, const GLubyte **inst,
+ struct arb_program *Program, GLint *offset)
+{
+ (void) ctx;
+ *offset = parse_integer(inst, Program);
+ return 0;
+}
+
+/**
+ * \param color 0 if color type is primary, 1 if color type is secondary
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_color_type (GLcontext * ctx, const GLubyte ** inst, struct arb_program *Program,
+ GLint * color)
+{
+ (void) ctx; (void) Program;
+ *color = *(*inst)++ != COLOR_PRIMARY;
+ return 0;
+}
+
+/**
+ * Get an integer corresponding to a generic vertex attribute.
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_generic_attrib_num(GLcontext *ctx, const GLubyte ** inst,
+ struct arb_program *Program, GLuint *attrib)
+{
+ GLint i = parse_integer(inst, Program);
+
+ if ((i < 0) || (i >= MAX_VERTEX_PROGRAM_ATTRIBS))
+ {
+ program_error(ctx, Program->Position,
+ "Invalid generic vertex attribute index");
+ return 1;
+ }
+
+ *attrib = (GLuint) i;
+
+ return 0;
+}
+
+
+/**
+ * \param color The index of the color buffer to write into
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_output_color_num (GLcontext * ctx, const GLubyte ** inst,
+ struct arb_program *Program, GLuint * color)
+{
+ GLint i = parse_integer (inst, Program);
+
+ if ((i < 0) || (i >= (int)ctx->Const.MaxDrawBuffers)) {
+ program_error(ctx, Program->Position, "Invalid draw buffer index");
+ return 1;
+ }
+
+ *color = (GLuint) i;
+ return 0;
+}
+
+
+/**
+ * \param coord The texture unit index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_texcoord_num (GLcontext * ctx, const GLubyte ** inst,
+ struct arb_program *Program, GLuint * coord)
+{
+ GLint i = parse_integer (inst, Program);
+
+ if ((i < 0) || (i >= (int)ctx->Const.MaxTextureUnits)) {
+ program_error(ctx, Program->Position, "Invalid texture unit index");
+ return 1;
+ }
+
+ *coord = (GLuint) i;
+ return 0;
+}
+
+/**
+ * \param coord The weight index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_weight_num (GLcontext * ctx, const GLubyte ** inst, struct arb_program *Program,
+ GLint * coord)
+{
+ *coord = parse_integer (inst, Program);
+
+ if ((*coord < 0) || (*coord >= 1)) {
+ program_error(ctx, Program->Position, "Invalid weight index");
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * \param coord The clip plane index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_clipplane_num (GLcontext * ctx, const GLubyte ** inst,
+ struct arb_program *Program, GLint * coord)
+{
+ *coord = parse_integer (inst, Program);
+
+ if ((*coord < 0) || (*coord >= (GLint) ctx->Const.MaxClipPlanes)) {
+ program_error(ctx, Program->Position, "Invalid clip plane index");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * \return 0 on front face, 1 on back face
+ */
+static GLuint
+parse_face_type (const GLubyte ** inst)
+{
+ switch (*(*inst)++) {
+ case FACE_FRONT:
+ return 0;
+
+ case FACE_BACK:
+ return 1;
+ }
+ return 0;
+}
+
+
+/**
+ * Given a matrix and a modifier token on the binary array, return tokens
+ * that _mesa_fetch_state() [program.c] can understand.
+ *
+ * \param matrix - the matrix we are talking about
+ * \param matrix_idx - the index of the matrix we have (for texture & program matricies)
+ * \param matrix_modifier - the matrix modifier (trans, inv, etc)
+ * \return 0 on sucess, 1 on failure
+ */
+static GLuint
+parse_matrix (GLcontext * ctx, const GLubyte ** inst, struct arb_program *Program,
+ GLint * matrix, GLint * matrix_idx, GLint * matrix_modifier)
+{
+ GLubyte mat = *(*inst)++;
+
+ *matrix_idx = 0;
+
+ switch (mat) {
+ case MATRIX_MODELVIEW:
+ *matrix = STATE_MODELVIEW;
+ *matrix_idx = parse_integer (inst, Program);
+ if (*matrix_idx > 0) {
+ program_error(ctx, Program->Position,
+ "ARB_vertex_blend not supported");
+ return 1;
+ }
+ break;
+
+ case MATRIX_PROJECTION:
+ *matrix = STATE_PROJECTION;
+ break;
+
+ case MATRIX_MVP:
+ *matrix = STATE_MVP;
+ break;
+
+ case MATRIX_TEXTURE:
+ *matrix = STATE_TEXTURE;
+ *matrix_idx = parse_integer (inst, Program);
+ if (*matrix_idx >= (GLint) ctx->Const.MaxTextureUnits) {
+ program_error(ctx, Program->Position, "Invalid Texture Unit");
+ /* bad *matrix_id */
+ return 1;
+ }
+ break;
+
+ /* This is not currently supported (ARB_matrix_palette) */
+ case MATRIX_PALETTE:
+ *matrix_idx = parse_integer (inst, Program);
+ program_error(ctx, Program->Position,
+ "ARB_matrix_palette not supported");
+ return 1;
+ break;
+
+ case MATRIX_PROGRAM:
+ *matrix = STATE_PROGRAM;
+ *matrix_idx = parse_integer (inst, Program);
+ if (*matrix_idx >= (GLint) ctx->Const.MaxProgramMatrices) {
+ program_error(ctx, Program->Position, "Invalid Program Matrix");
+ /* bad *matrix_idx */
+ return 1;
+ }
+ break;
+ }
+
+ switch (*(*inst)++) {
+ case MATRIX_MODIFIER_IDENTITY:
+ *matrix_modifier = 0;
+ break;
+ case MATRIX_MODIFIER_INVERSE:
+ *matrix_modifier = STATE_MATRIX_INVERSE;
+ break;
+ case MATRIX_MODIFIER_TRANSPOSE:
+ *matrix_modifier = STATE_MATRIX_TRANSPOSE;
+ break;
+ case MATRIX_MODIFIER_INVTRANS:
+ *matrix_modifier = STATE_MATRIX_INVTRANS;
+ break;
+ }
+
+ return 0;
+}
+
+
+/**
+ * This parses a state string (rather, the binary version of it) into
+ * a 6-token sequence as described in _mesa_fetch_state() [program.c]
+ *
+ * \param inst - the start in the binary arry to start working from
+ * \param state_tokens - the storage for the 6-token state description
+ * \return - 0 on sucess, 1 on error
+ */
+static GLuint
+parse_state_single_item (GLcontext * ctx, const GLubyte ** inst,
+ struct arb_program *Program, GLint * state_tokens)
+{
+ switch (*(*inst)++) {
+ case STATE_MATERIAL_PARSER:
+ state_tokens[0] = STATE_MATERIAL;
+ state_tokens[1] = parse_face_type (inst);
+ switch (*(*inst)++) {
+ case MATERIAL_AMBIENT:
+ state_tokens[2] = STATE_AMBIENT;
+ break;
+ case MATERIAL_DIFFUSE:
+ state_tokens[2] = STATE_DIFFUSE;
+ break;
+ case MATERIAL_SPECULAR:
+ state_tokens[2] = STATE_SPECULAR;
+ break;
+ case MATERIAL_EMISSION:
+ state_tokens[2] = STATE_EMISSION;
+ break;
+ case MATERIAL_SHININESS:
+ state_tokens[2] = STATE_SHININESS;
+ break;
+ }
+ break;
+
+ case STATE_LIGHT_PARSER:
+ state_tokens[0] = STATE_LIGHT;
+ state_tokens[1] = parse_integer (inst, Program);
+
+ /* Check the value of state_tokens[1] against the # of lights */
+ if (state_tokens[1] >= (GLint) ctx->Const.MaxLights) {
+ program_error(ctx, Program->Position, "Invalid Light Number");
+ /* bad state_tokens[1] */
+ return 1;
+ }
+
+ switch (*(*inst)++) {
+ case LIGHT_AMBIENT:
+ state_tokens[2] = STATE_AMBIENT;
+ break;
+ case LIGHT_DIFFUSE:
+ state_tokens[2] = STATE_DIFFUSE;
+ break;
+ case LIGHT_SPECULAR:
+ state_tokens[2] = STATE_SPECULAR;
+ break;
+ case LIGHT_POSITION:
+ state_tokens[2] = STATE_POSITION;
+ break;
+ case LIGHT_ATTENUATION:
+ state_tokens[2] = STATE_ATTENUATION;
+ break;
+ case LIGHT_HALF:
+ state_tokens[2] = STATE_HALF;
+ break;
+ case LIGHT_SPOT_DIRECTION:
+ state_tokens[2] = STATE_SPOT_DIRECTION;
+ break;
+ }
+ break;
+
+ case STATE_LIGHT_MODEL:
+ switch (*(*inst)++) {
+ case LIGHT_MODEL_AMBIENT:
+ state_tokens[0] = STATE_LIGHTMODEL_AMBIENT;
+ break;
+ case LIGHT_MODEL_SCENECOLOR:
+ state_tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
+ state_tokens[1] = parse_face_type (inst);
+ break;
+ }
+ break;
+
+ case STATE_LIGHT_PROD:
+ state_tokens[0] = STATE_LIGHTPROD;
+ state_tokens[1] = parse_integer (inst, Program);
+
+ /* Check the value of state_tokens[1] against the # of lights */
+ if (state_tokens[1] >= (GLint) ctx->Const.MaxLights) {
+ program_error(ctx, Program->Position, "Invalid Light Number");
+ /* bad state_tokens[1] */
+ return 1;
+ }
+
+ state_tokens[2] = parse_face_type (inst);
+ switch (*(*inst)++) {
+ case LIGHT_PROD_AMBIENT:
+ state_tokens[3] = STATE_AMBIENT;
+ break;
+ case LIGHT_PROD_DIFFUSE:
+ state_tokens[3] = STATE_DIFFUSE;
+ break;
+ case LIGHT_PROD_SPECULAR:
+ state_tokens[3] = STATE_SPECULAR;
+ break;
+ }
+ break;
+
+
+ case STATE_FOG:
+ switch (*(*inst)++) {
+ case FOG_COLOR:
+ state_tokens[0] = STATE_FOG_COLOR;
+ break;
+ case FOG_PARAMS:
+ state_tokens[0] = STATE_FOG_PARAMS;
+ break;
+ }
+ break;
+
+ case STATE_TEX_ENV:
+ state_tokens[1] = parse_integer (inst, Program);
+ switch (*(*inst)++) {
+ case TEX_ENV_COLOR:
+ state_tokens[0] = STATE_TEXENV_COLOR;
+ break;
+ }
+ break;
+
+ case STATE_TEX_GEN:
+ {
+ GLuint type, coord;
+
+ state_tokens[0] = STATE_TEXGEN;
+ /*state_tokens[1] = parse_integer (inst, Program);*/ /* Texture Unit */
+
+ if (parse_texcoord_num (ctx, inst, Program, &coord))
+ return 1;
+ state_tokens[1] = coord;
+
+ /* EYE or OBJECT */
+ type = *(*inst++);
+
+ /* 0 - s, 1 - t, 2 - r, 3 - q */
+ coord = *(*inst++);
+
+ if (type == TEX_GEN_EYE) {
+ switch (coord) {
+ case COMPONENT_X:
+ state_tokens[2] = STATE_TEXGEN_EYE_S;
+ break;
+ case COMPONENT_Y:
+ state_tokens[2] = STATE_TEXGEN_EYE_T;
+ break;
+ case COMPONENT_Z:
+ state_tokens[2] = STATE_TEXGEN_EYE_R;
+ break;
+ case COMPONENT_W:
+ state_tokens[2] = STATE_TEXGEN_EYE_Q;
+ break;
+ }
+ }
+ else {
+ switch (coord) {
+ case COMPONENT_X:
+ state_tokens[2] = STATE_TEXGEN_OBJECT_S;
+ break;
+ case COMPONENT_Y:
+ state_tokens[2] = STATE_TEXGEN_OBJECT_T;
+ break;
+ case COMPONENT_Z:
+ state_tokens[2] = STATE_TEXGEN_OBJECT_R;
+ break;
+ case COMPONENT_W:
+ state_tokens[2] = STATE_TEXGEN_OBJECT_Q;
+ break;
+ }
+ }
+ }
+ break;
+
+ case STATE_DEPTH:
+ switch (*(*inst)++) {
+ case DEPTH_RANGE:
+ state_tokens[0] = STATE_DEPTH_RANGE;
+ break;
+ }
+ break;
+
+ case STATE_CLIP_PLANE:
+ state_tokens[0] = STATE_CLIPPLANE;
+ state_tokens[1] = parse_integer (inst, Program);
+ if (parse_clipplane_num (ctx, inst, Program, &state_tokens[1]))
+ return 1;
+ break;
+
+ case STATE_POINT:
+ switch (*(*inst++)) {
+ case POINT_SIZE:
+ state_tokens[0] = STATE_POINT_SIZE;
+ break;
+
+ case POINT_ATTENUATION:
+ state_tokens[0] = STATE_POINT_ATTENUATION;
+ break;
+ }
+ break;
+
+ /* XXX: I think this is the correct format for a matrix row */
+ case STATE_MATRIX_ROWS:
+ state_tokens[0] = STATE_MATRIX;
+ if (parse_matrix
+ (ctx, inst, Program, &state_tokens[1], &state_tokens[2],
+ &state_tokens[5]))
+ return 1;
+
+ state_tokens[3] = parse_integer (inst, Program); /* The first row to grab */
+
+ if ((**inst) != 0) { /* Either the last row, 0 */
+ state_tokens[4] = parse_integer (inst, Program);
+ if (state_tokens[4] < state_tokens[3]) {
+ program_error(ctx, Program->Position,
+ "Second matrix index less than the first");
+ /* state_tokens[4] vs. state_tokens[3] */
+ return 1;
+ }
+ }
+ else {
+ state_tokens[4] = state_tokens[3];
+ (*inst)++;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * This parses a state string (rather, the binary version of it) into
+ * a 6-token similar for the state fetching code in program.c
+ *
+ * One might ask, why fetch these parameters into just like you fetch
+ * state when they are already stored in other places?
+ *
+ * Because of array offsets -> We can stick env/local parameters in the
+ * middle of a parameter array and then index someplace into the array
+ * when we execute.
+ *
+ * One optimization might be to only do this for the cases where the
+ * env/local parameters end up inside of an array, and leave the
+ * single parameters (or arrays of pure env/local pareameters) in their
+ * respective register files.
+ *
+ * For ENV parameters, the format is:
+ * state_tokens[0] = STATE_FRAGMENT_PROGRAM / STATE_VERTEX_PROGRAM
+ * state_tokens[1] = STATE_ENV
+ * state_tokens[2] = the parameter index
+ *
+ * for LOCAL parameters, the format is:
+ * state_tokens[0] = STATE_FRAGMENT_PROGRAM / STATE_VERTEX_PROGRAM
+ * state_tokens[1] = STATE_LOCAL
+ * state_tokens[2] = the parameter index
+ *
+ * \param inst - the start in the binary arry to start working from
+ * \param state_tokens - the storage for the 6-token state description
+ * \return - 0 on sucess, 1 on failure
+ */
+static GLuint
+parse_program_single_item (GLcontext * ctx, const GLubyte ** inst,
+ struct arb_program *Program, GLint * state_tokens)
+{
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
+ state_tokens[0] = STATE_FRAGMENT_PROGRAM;
+ else
+ state_tokens[0] = STATE_VERTEX_PROGRAM;
+
+
+ switch (*(*inst)++) {
+ case PROGRAM_PARAM_ENV:
+ state_tokens[1] = STATE_ENV;
+ state_tokens[2] = parse_integer (inst, Program);
+
+ /* Check state_tokens[2] against the number of ENV parameters available */
+ if (((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) &&
+ (state_tokens[2] >= (GLint) ctx->Const.FragmentProgram.MaxEnvParams))
+ ||
+ ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
+ (state_tokens[2] >= (GLint) ctx->Const.VertexProgram.MaxEnvParams))) {
+ program_error(ctx, Program->Position,
+ "Invalid Program Env Parameter");
+ /* bad state_tokens[2] */
+ return 1;
+ }
+
+ break;
+
+ case PROGRAM_PARAM_LOCAL:
+ state_tokens[1] = STATE_LOCAL;
+ state_tokens[2] = parse_integer (inst, Program);
+
+ /* Check state_tokens[2] against the number of LOCAL parameters available */
+ if (((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) &&
+ (state_tokens[2] >= (GLint) ctx->Const.FragmentProgram.MaxLocalParams))
+ ||
+ ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
+ (state_tokens[2] >= (GLint) ctx->Const.VertexProgram.MaxLocalParams))) {
+ program_error(ctx, Program->Position,
+ "Invalid Program Local Parameter");
+ /* bad state_tokens[2] */
+ return 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * For ARB_vertex_program, programs are not allowed to use both an explicit
+ * vertex attribute and a generic vertex attribute corresponding to the same
+ * state. See section 2.14.3.1 of the GL_ARB_vertex_program spec.
+ *
+ * This will walk our var_cache and make sure that nobody does anything fishy.
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+generic_attrib_check(struct var_cache *vc_head)
+{
+ int a;
+ struct var_cache *curr;
+ GLboolean explicitAttrib[MAX_VERTEX_PROGRAM_ATTRIBS],
+ genericAttrib[MAX_VERTEX_PROGRAM_ATTRIBS];
+
+ for (a=0; a<MAX_VERTEX_PROGRAM_ATTRIBS; a++) {
+ explicitAttrib[a] = GL_FALSE;
+ genericAttrib[a] = GL_FALSE;
+ }
+
+ curr = vc_head;
+ while (curr) {
+ if (curr->type == vt_attrib) {
+ if (curr->attrib_is_generic)
+ genericAttrib[ curr->attrib_binding ] = GL_TRUE;
+ else
+ explicitAttrib[ curr->attrib_binding ] = GL_TRUE;
+ }
+
+ curr = curr->next;
+ }
+
+ for (a=0; a<MAX_VERTEX_PROGRAM_ATTRIBS; a++) {
+ if ((explicitAttrib[a]) && (genericAttrib[a]))
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * This will handle the binding side of an ATTRIB var declaration
+ *
+ * \param inputReg returns the input register index, one of the
+ * VERT_ATTRIB_* or FRAG_ATTRIB_* values.
+ * \return returns 0 on success, 1 on error
+ */
+static GLuint
+parse_attrib_binding(GLcontext * ctx, const GLubyte ** inst,
+ struct arb_program *Program,
+ GLuint *inputReg, GLuint *is_generic)
+{
+ GLint err = 0;
+
+ *is_generic = 0;
+
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+ switch (*(*inst)++) {
+ case FRAGMENT_ATTRIB_COLOR:
+ {
+ GLint coord;
+ err = parse_color_type (ctx, inst, Program, &coord);
+ *inputReg = FRAG_ATTRIB_COL0 + coord;
+ }
+ break;
+ case FRAGMENT_ATTRIB_TEXCOORD:
+ {
+ GLuint texcoord;
+ err = parse_texcoord_num (ctx, inst, Program, &texcoord);
+ *inputReg = FRAG_ATTRIB_TEX0 + texcoord;
+ }
+ break;
+ case FRAGMENT_ATTRIB_FOGCOORD:
+ *inputReg = FRAG_ATTRIB_FOGC;
+ break;
+ case FRAGMENT_ATTRIB_POSITION:
+ *inputReg = FRAG_ATTRIB_WPOS;
+ break;
+ default:
+ err = 1;
+ break;
+ }
+ }
+ else {
+ switch (*(*inst)++) {
+ case VERTEX_ATTRIB_POSITION:
+ *inputReg = VERT_ATTRIB_POS;
+ break;
+
+ case VERTEX_ATTRIB_WEIGHT:
+ {
+ GLint weight;
+ err = parse_weight_num (ctx, inst, Program, &weight);
+ *inputReg = VERT_ATTRIB_WEIGHT;
+#if 1
+ /* hack for Warcraft (see bug 8060) */
+ _mesa_warning(ctx, "Application error: vertex program uses 'vertex.weight' but GL_ARB_vertex_blend not supported.");
+ break;
+#else
+ program_error(ctx, Program->Position,
+ "ARB_vertex_blend not supported");
+ return 1;
+#endif
+ }
+
+ case VERTEX_ATTRIB_NORMAL:
+ *inputReg = VERT_ATTRIB_NORMAL;
+ break;
+
+ case VERTEX_ATTRIB_COLOR:
+ {
+ GLint color;
+ err = parse_color_type (ctx, inst, Program, &color);
+ if (color) {
+ *inputReg = VERT_ATTRIB_COLOR1;
+ }
+ else {
+ *inputReg = VERT_ATTRIB_COLOR0;
+ }
+ }
+ break;
+
+ case VERTEX_ATTRIB_FOGCOORD:
+ *inputReg = VERT_ATTRIB_FOG;
+ break;
+
+ case VERTEX_ATTRIB_TEXCOORD:
+ {
+ GLuint unit;
+ err = parse_texcoord_num (ctx, inst, Program, &unit);
+ *inputReg = VERT_ATTRIB_TEX0 + unit;
+ }
+ break;
+
+ case VERTEX_ATTRIB_MATRIXINDEX:
+ /* Not supported at this time */
+ {
+ const char *msg = "ARB_palette_matrix not supported";
+ parse_integer (inst, Program);
+ program_error(ctx, Program->Position, msg);
+ }
+ return 1;
+
+ case VERTEX_ATTRIB_GENERIC:
+ {
+ GLuint attrib;
+ err = parse_generic_attrib_num(ctx, inst, Program, &attrib);
+ if (!err) {
+ *is_generic = 1;
+ /* Add VERT_ATTRIB_GENERIC0 here because ARB_vertex_program's
+ * attributes do not alias the conventional vertex
+ * attributes.
+ */
+ if (attrib > 0)
+ *inputReg = attrib + VERT_ATTRIB_GENERIC0;
+ else
+ *inputReg = 0;
+ }
+ }
+ break;
+
+ default:
+ err = 1;
+ break;
+ }
+ }
+
+ if (err) {
+ program_error(ctx, Program->Position, "Bad attribute binding");
+ }
+
+ Program->Base.InputsRead |= (1 << *inputReg);
+
+ return err;
+}
+
+
+/**
+ * This translates between a binary token for an output variable type
+ * and the mesa token for the same thing.
+ *
+ * \param inst The parsed tokens
+ * \param outputReg Returned index/number of the output register,
+ * one of the VERT_RESULT_* or FRAG_RESULT_* values.
+ */
+static GLuint
+parse_result_binding(GLcontext *ctx, const GLubyte **inst,
+ GLuint *outputReg, struct arb_program *Program)
+{
+ const GLubyte token = *(*inst)++;
+
+ switch (token) {
+ case FRAGMENT_RESULT_COLOR:
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+ GLuint out_color;
+
+ /* This gets result of the color buffer we're supposed to
+ * draw into. This pertains to GL_ARB_draw_buffers.
+ */
+ parse_output_color_num(ctx, inst, Program, &out_color);
+ ASSERT(out_color < MAX_DRAW_BUFFERS);
+ *outputReg = FRAG_RESULT_COLR;
+ }
+ else {
+ /* for vtx programs, this is VERTEX_RESULT_POSITION */
+ *outputReg = VERT_RESULT_HPOS;
+ }
+ break;
+
+ case FRAGMENT_RESULT_DEPTH:
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+ /* for frag programs, this is FRAGMENT_RESULT_DEPTH */
+ *outputReg = FRAG_RESULT_DEPR;
+ }
+ else {
+ /* for vtx programs, this is VERTEX_RESULT_COLOR */
+ GLint color_type;
+ GLuint face_type = parse_face_type(inst);
+ GLint err = parse_color_type(ctx, inst, Program, &color_type);
+ if (err)
+ return 1;
+
+ if (face_type) {
+ /* back face */
+ if (color_type) {
+ *outputReg = VERT_RESULT_BFC1; /* secondary color */
+ }
+ else {
+ *outputReg = VERT_RESULT_BFC0; /* primary color */
+ }
+ }
+ else {
+ /* front face */
+ if (color_type) {
+ *outputReg = VERT_RESULT_COL1; /* secondary color */
+ }
+ /* primary color */
+ else {
+ *outputReg = VERT_RESULT_COL0; /* primary color */
+ }
+ }
+ }
+ break;
+
+ case VERTEX_RESULT_FOGCOORD:
+ *outputReg = VERT_RESULT_FOGC;
+ break;
+
+ case VERTEX_RESULT_POINTSIZE:
+ *outputReg = VERT_RESULT_PSIZ;
+ break;
+
+ case VERTEX_RESULT_TEXCOORD:
+ {
+ GLuint unit;
+ if (parse_texcoord_num (ctx, inst, Program, &unit))
+ return 1;
+ *outputReg = VERT_RESULT_TEX0 + unit;
+ }
+ break;
+ }
+
+ Program->Base.OutputsWritten |= (1 << *outputReg);
+
+ return 0;
+}
+
+
+/**
+ * This handles the declaration of ATTRIB variables
+ *
+ * XXX: Still needs
+ * parse_vert_attrib_binding(), or something like that
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLint
+parse_attrib (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program)
+{
+ GLuint found;
+ char *error_msg;
+ struct var_cache *attrib_var;
+
+ attrib_var = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+ if (found) {
+ error_msg = (char *)
+ _mesa_malloc (_mesa_strlen ((char *) attrib_var->name) + 40);
+ _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+ attrib_var->name);
+ program_error(ctx, Program->Position, error_msg);
+ _mesa_free (error_msg);
+ return 1;
+ }
+
+ attrib_var->type = vt_attrib;
+
+ if (parse_attrib_binding(ctx, inst, Program, &attrib_var->attrib_binding,
+ &attrib_var->attrib_is_generic))
+ return 1;
+
+ if (generic_attrib_check(*vc_head)) {
+ program_error(ctx, Program->Position,
+ "Cannot use both a generic vertex attribute "
+ "and a specific attribute of the same type");
+ return 1;
+ }
+
+ Program->Base.NumAttributes++;
+ return 0;
+}
+
+/**
+ * \param use -- TRUE if we're called when declaring implicit parameters,
+ * FALSE if we're declaraing variables. This has to do with
+ * if we get a signed or unsigned float for scalar constants
+ */
+static GLuint
+parse_param_elements (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache *param_var,
+ struct arb_program *Program, GLboolean use)
+{
+ GLint idx;
+ GLuint err = 0;
+ GLint state_tokens[6];
+ GLfloat const_values[4];
+
+ switch (*(*inst)++) {
+ case PARAM_STATE_ELEMENT:
+ if (parse_state_single_item (ctx, inst, Program, state_tokens))
+ return 1;
+
+ /* If we adding STATE_MATRIX that has multiple rows, we need to
+ * unroll it and call _mesa_add_state_reference() for each row
+ */
+ if ((state_tokens[0] == STATE_MATRIX)
+ && (state_tokens[3] != state_tokens[4])) {
+ GLint row;
+ GLint first_row = state_tokens[3];
+ GLint last_row = state_tokens[4];
+
+ for (row = first_row; row <= last_row; row++) {
+ state_tokens[3] = state_tokens[4] = row;
+
+ idx = _mesa_add_state_reference(Program->Base.Parameters,
+ state_tokens);
+ if (param_var->param_binding_begin == ~0U)
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_length++;
+ Program->Base.NumParameters++;
+ }
+ }
+ else {
+ idx = _mesa_add_state_reference(Program->Base.Parameters,
+ state_tokens);
+ if (param_var->param_binding_begin == ~0U)
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_length++;
+ Program->Base.NumParameters++;
+ }
+ break;
+
+ case PARAM_PROGRAM_ELEMENT:
+ if (parse_program_single_item (ctx, inst, Program, state_tokens))
+ return 1;
+ idx = _mesa_add_state_reference (Program->Base.Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U)
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_length++;
+ Program->Base.NumParameters++;
+
+ /* Check if there is more: 0 -> we're done, else its an integer */
+ if (**inst) {
+ GLuint out_of_range, new_idx;
+ GLuint start_idx = state_tokens[2] + 1;
+ GLuint end_idx = parse_integer (inst, Program);
+
+ out_of_range = 0;
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+ if (((state_tokens[1] == STATE_ENV)
+ && (end_idx >= ctx->Const.FragmentProgram.MaxEnvParams))
+ || ((state_tokens[1] == STATE_LOCAL)
+ && (end_idx >=
+ ctx->Const.FragmentProgram.MaxLocalParams)))
+ out_of_range = 1;
+ }
+ else {
+ if (((state_tokens[1] == STATE_ENV)
+ && (end_idx >= ctx->Const.VertexProgram.MaxEnvParams))
+ || ((state_tokens[1] == STATE_LOCAL)
+ && (end_idx >=
+ ctx->Const.VertexProgram.MaxLocalParams)))
+ out_of_range = 1;
+ }
+ if (out_of_range) {
+ program_error(ctx, Program->Position,
+ "Invalid Program Parameter"); /*end_idx*/
+ return 1;
+ }
+
+ for (new_idx = start_idx; new_idx <= end_idx; new_idx++) {
+ state_tokens[2] = new_idx;
+ idx = _mesa_add_state_reference(Program->Base.Parameters,
+ state_tokens);
+ param_var->param_binding_length++;
+ Program->Base.NumParameters++;
+ }
+ }
+ else {
+ (*inst)++;
+ }
+ break;
+
+ case PARAM_CONSTANT:
+ parse_constant (inst, const_values, Program, use);
+ idx = _mesa_add_named_constant(Program->Base.Parameters,
+ (char *) param_var->name,
+ const_values);
+ if (param_var->param_binding_begin == ~0U)
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_length++;
+ Program->Base.NumParameters++;
+ break;
+
+ default:
+ program_error(ctx, Program->Position,
+ "Unexpected token (in parse_param_elements())");
+ return 1;
+ }
+
+ /* Make sure we haven't blown past our parameter limits */
+ if (((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
+ (Program->Base.NumParameters >=
+ ctx->Const.VertexProgram.MaxLocalParams))
+ || ((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
+ && (Program->Base.NumParameters >=
+ ctx->Const.FragmentProgram.MaxLocalParams))) {
+ program_error(ctx, Program->Position, "Too many parameter variables");
+ return 1;
+ }
+
+ return err;
+}
+
+
+/**
+ * This picks out PARAM program parameter bindings.
+ *
+ * XXX: This needs to be stressed & tested
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_param (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program)
+{
+ GLuint found, err;
+ GLint specified_length;
+ struct var_cache *param_var;
+
+ err = 0;
+ param_var = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+
+ if (found) {
+ char *error_msg = (char *)
+ _mesa_malloc (_mesa_strlen ((char *) param_var->name) + 40);
+ _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+ param_var->name);
+ program_error (ctx, Program->Position, error_msg);
+ _mesa_free (error_msg);
+ return 1;
+ }
+
+ specified_length = parse_integer (inst, Program);
+
+ if (specified_length < 0) {
+ program_error(ctx, Program->Position, "Negative parameter array length");
+ return 1;
+ }
+
+ param_var->type = vt_param;
+ param_var->param_binding_length = 0;
+
+ /* Right now, everything is shoved into the main state register file.
+ *
+ * In the future, it would be nice to leave things ENV/LOCAL params
+ * in their respective register files, if possible
+ */
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+ /* Remember to:
+ * * - add each guy to the parameter list
+ * * - increment the param_var->param_binding_len
+ * * - store the param_var->param_binding_begin for the first one
+ * * - compare the actual len to the specified len at the end
+ */
+ while (**inst != PARAM_NULL) {
+ if (parse_param_elements (ctx, inst, param_var, Program, GL_FALSE))
+ return 1;
+ }
+
+ /* Test array length here! */
+ if (specified_length) {
+ if (specified_length != (int)param_var->param_binding_length) {
+ program_error(ctx, Program->Position,
+ "Declared parameter array length does not match parameter list");
+ }
+ }
+
+ (*inst)++;
+
+ return 0;
+}
+
+/**
+ *
+ */
+static GLuint
+parse_param_use (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program, struct var_cache **new_var)
+{
+ struct var_cache *param_var;
+
+ /* First, insert a dummy entry into the var_cache */
+ var_cache_create (&param_var);
+ param_var->name = (const GLubyte *) " ";
+ param_var->type = vt_param;
+
+ param_var->param_binding_length = 0;
+ /* Don't fill in binding_begin; We use the default value of -1
+ * to tell if its already initialized, elsewhere.
+ *
+ * param_var->param_binding_begin = 0;
+ */
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+ var_cache_append (vc_head, param_var);
+
+ /* Then fill it with juicy parameter goodness */
+ if (parse_param_elements (ctx, inst, param_var, Program, GL_TRUE))
+ return 1;
+
+ *new_var = param_var;
+
+ return 0;
+}
+
+
+/**
+ * This handles the declaration of TEMP variables
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_temp (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program)
+{
+ GLuint found;
+ struct var_cache *temp_var;
+
+ while (**inst != 0) {
+ temp_var = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+ if (found) {
+ char *error_msg = (char *)
+ _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+ _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+ temp_var->name);
+ program_error(ctx, Program->Position, error_msg);
+ _mesa_free (error_msg);
+ return 1;
+ }
+
+ temp_var->type = vt_temp;
+
+ if (((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) &&
+ (Program->Base.NumTemporaries >=
+ ctx->Const.FragmentProgram.MaxTemps))
+ || ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB)
+ && (Program->Base.NumTemporaries >=
+ ctx->Const.VertexProgram.MaxTemps))) {
+ program_error(ctx, Program->Position,
+ "Too many TEMP variables declared");
+ return 1;
+ }
+
+ temp_var->temp_binding = Program->Base.NumTemporaries;
+ Program->Base.NumTemporaries++;
+ }
+ (*inst)++;
+
+ return 0;
+}
+
+/**
+ * This handles variables of the OUTPUT variety
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_output (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program)
+{
+ GLuint found;
+ struct var_cache *output_var;
+ GLuint err;
+
+ output_var = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+ if (found) {
+ char *error_msg = (char *)
+ _mesa_malloc (_mesa_strlen ((char *) output_var->name) + 40);
+ _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+ output_var->name);
+ program_error (ctx, Program->Position, error_msg);
+ _mesa_free (error_msg);
+ return 1;
+ }
+
+ output_var->type = vt_output;
+
+ err = parse_result_binding(ctx, inst, &output_var->output_binding, Program);
+ return err;
+}
+
+/**
+ * This handles variables of the ALIAS kind
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_alias (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program)
+{
+ GLuint found;
+ struct var_cache *temp_var;
+
+ temp_var = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+
+ if (found) {
+ char *error_msg = (char *)
+ _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+ _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+ temp_var->name);
+ program_error(ctx, Program->Position, error_msg);
+ _mesa_free (error_msg);
+ return 1;
+ }
+
+ temp_var->type = vt_alias;
+ temp_var->alias_binding = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+
+ if (!found)
+ {
+ char *error_msg = (char *)
+ _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+ _mesa_sprintf (error_msg, "Alias value %s is not defined",
+ temp_var->alias_binding->name);
+ program_error (ctx, Program->Position, error_msg);
+ _mesa_free (error_msg);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * This handles variables of the ADDRESS kind
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_address (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program)
+{
+ GLuint found;
+ struct var_cache *temp_var;
+
+ while (**inst != 0) {
+ temp_var = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+ if (found) {
+ char *error_msg = (char *)
+ _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+ _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+ temp_var->name);
+ program_error (ctx, Program->Position, error_msg);
+ _mesa_free (error_msg);
+ return 1;
+ }
+
+ temp_var->type = vt_address;
+
+ if (Program->Base.NumAddressRegs >=
+ ctx->Const.VertexProgram.MaxAddressRegs) {
+ const char *msg = "Too many ADDRESS variables declared";
+ program_error(ctx, Program->Position, msg);
+ return 1;
+ }
+
+ temp_var->address_binding = Program->Base.NumAddressRegs;
+ Program->Base.NumAddressRegs++;
+ }
+ (*inst)++;
+
+ return 0;
+}
+
+/**
+ * Parse a program declaration
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLint
+parse_declaration (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
+ struct arb_program *Program)
+{
+ GLint err = 0;
+
+ switch (*(*inst)++) {
+ case ADDRESS:
+ err = parse_address (ctx, inst, vc_head, Program);
+ break;
+
+ case ALIAS:
+ err = parse_alias (ctx, inst, vc_head, Program);
+ break;
+
+ case ATTRIB:
+ err = parse_attrib (ctx, inst, vc_head, Program);
+ break;
+
+ case OUTPUT:
+ err = parse_output (ctx, inst, vc_head, Program);
+ break;
+
+ case PARAM:
+ err = parse_param (ctx, inst, vc_head, Program);
+ break;
+
+ case TEMP:
+ err = parse_temp (ctx, inst, vc_head, Program);
+ break;
+ }
+
+ return err;
+}
+
+/**
+ * Handle the parsing out of a masked destination register, either for a
+ * vertex or fragment program.
+ *
+ * If we are a vertex program, make sure we don't write to
+ * result.position if we have specified that the program is
+ * position invariant
+ *
+ * \param File - The register file we write to
+ * \param Index - The register index we write to
+ * \param WriteMask - The mask controlling which components we write (1->write)
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_masked_dst_reg (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head, struct arb_program *Program,
+ enum register_file *File, GLuint *Index, GLint *WriteMask)
+{
+ GLuint tmp, result;
+ struct var_cache *dst;
+
+ /* We either have a result register specified, or a
+ * variable that may or may not be writable
+ */
+ switch (*(*inst)++) {
+ case REGISTER_RESULT:
+ if (parse_result_binding(ctx, inst, Index, Program))
+ return 1;
+ *File = PROGRAM_OUTPUT;
+ break;
+
+ case REGISTER_ESTABLISHED_NAME:
+ dst = parse_string (inst, vc_head, Program, &result);
+ Program->Position = parse_position (inst);
+
+ /* If the name has never been added to our symbol table, we're hosed */
+ if (!result) {
+ program_error(ctx, Program->Position, "0: Undefined variable");
+ return 1;
+ }
+
+ switch (dst->type) {
+ case vt_output:
+ *File = PROGRAM_OUTPUT;
+ *Index = dst->output_binding;
+ break;
+
+ case vt_temp:
+ *File = PROGRAM_TEMPORARY;
+ *Index = dst->temp_binding;
+ break;
+
+ /* If the var type is not vt_output or vt_temp, no go */
+ default:
+ program_error(ctx, Program->Position,
+ "Destination register is read only");
+ return 1;
+ }
+ break;
+
+ default:
+ program_error(ctx, Program->Position,
+ "Unexpected opcode in parse_masked_dst_reg()");
+ return 1;
+ }
+
+
+ /* Position invariance test */
+ /* This test is done now in syntax portion - when position invariance OPTION
+ is specified, "result.position" rule is disabled so there is no way
+ to write the position
+ */
+ /*if ((Program->HintPositionInvariant) && (*File == PROGRAM_OUTPUT) &&
+ (*Index == 0)) {
+ program_error(ctx, Program->Position,
+ "Vertex program specified position invariance and wrote vertex position");
+ }*/
+
+ /* And then the mask.
+ * w,a -> bit 0
+ * z,b -> bit 1
+ * y,g -> bit 2
+ * x,r -> bit 3
+ *
+ * ==> Need to reverse the order of bits for this!
+ */
+ tmp = (GLint) *(*inst)++;
+ *WriteMask = (((tmp>>3) & 0x1) |
+ ((tmp>>1) & 0x2) |
+ ((tmp<<1) & 0x4) |
+ ((tmp<<3) & 0x8));
+
+ return 0;
+}
+
+
+/**
+ * Handle the parsing of a address register
+ *
+ * \param Index - The register index we write to
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_address_reg (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *Program, GLint * Index)
+{
+ struct var_cache *dst;
+ GLuint result;
+
+ *Index = 0; /* XXX */
+
+ dst = parse_string (inst, vc_head, Program, &result);
+ Program->Position = parse_position (inst);
+
+ /* If the name has never been added to our symbol table, we're hosed */
+ if (!result) {
+ program_error(ctx, Program->Position, "Undefined variable");
+ return 1;
+ }
+
+ if (dst->type != vt_address) {
+ program_error(ctx, Program->Position, "Variable is not of type ADDRESS");
+ return 1;
+ }
+
+ return 0;
+}
+
+#if 0 /* unused */
+/**
+ * Handle the parsing out of a masked address register
+ *
+ * \param Index - The register index we write to
+ * \param WriteMask - The mask controlling which components we write (1->write)
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_masked_address_reg (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *Program, GLint * Index,
+ GLboolean * WriteMask)
+{
+ if (parse_address_reg (ctx, inst, vc_head, Program, Index))
+ return 1;
+
+ /* This should be 0x8 */
+ (*inst)++;
+
+ /* Writemask of .x is implied */
+ WriteMask[0] = 1;
+ WriteMask[1] = WriteMask[2] = WriteMask[3] = 0;
+
+ return 0;
+}
+#endif
+
+/**
+ * Parse out a swizzle mask.
+ *
+ * Basically convert COMPONENT_X/Y/Z/W to SWIZZLE_X/Y/Z/W
+ *
+ * The len parameter allows us to grab 4 components for a vector
+ * swizzle, or just 1 component for a scalar src register selection
+ */
+static void
+parse_swizzle_mask(const GLubyte ** inst, GLubyte *swizzle, GLint len)
+{
+ GLint i;
+
+ for (i = 0; i < 4; i++)
+ swizzle[i] = i;
+
+ for (i = 0; i < len; i++) {
+ switch (*(*inst)++) {
+ case COMPONENT_X:
+ swizzle[i] = SWIZZLE_X;
+ break;
+ case COMPONENT_Y:
+ swizzle[i] = SWIZZLE_Y;
+ break;
+ case COMPONENT_Z:
+ swizzle[i] = SWIZZLE_Z;
+ break;
+ case COMPONENT_W:
+ swizzle[i] = SWIZZLE_W;
+ break;
+ default:
+ _mesa_problem(NULL, "bad component in parse_swizzle_mask()");
+ return;
+ }
+ }
+}
+
+
+/**
+ * Parse an extended swizzle mask which is a sequence of
+ * four x/y/z/w/0/1 tokens.
+ * \return swizzle four swizzle values
+ * \return negateMask four element bitfield
+ */
+static void
+parse_extended_swizzle_mask(const GLubyte **inst, GLubyte swizzle[4],
+ GLubyte *negateMask)
+{
+ GLint i;
+
+ *negateMask = 0x0;
+ for (i = 0; i < 4; i++) {
+ GLubyte swz;
+ if (parse_sign(inst) == -1)
+ *negateMask |= (1 << i);
+
+ swz = *(*inst)++;
+
+ switch (swz) {
+ case COMPONENT_0:
+ swizzle[i] = SWIZZLE_ZERO;
+ break;
+ case COMPONENT_1:
+ swizzle[i] = SWIZZLE_ONE;
+ break;
+ case COMPONENT_X:
+ swizzle[i] = SWIZZLE_X;
+ break;
+ case COMPONENT_Y:
+ swizzle[i] = SWIZZLE_Y;
+ break;
+ case COMPONENT_Z:
+ swizzle[i] = SWIZZLE_Z;
+ break;
+ case COMPONENT_W:
+ swizzle[i] = SWIZZLE_W;
+ break;
+ default:
+ _mesa_problem(NULL, "bad case in parse_extended_swizzle_mask()");
+ return;
+ }
+ }
+}
+
+
+static GLuint
+parse_src_reg (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *Program,
+ enum register_file * File, GLint * Index,
+ GLboolean *IsRelOffset )
+{
+ struct var_cache *src;
+ GLuint binding, is_generic, found;
+ GLint offset;
+
+ *IsRelOffset = 0;
+
+ /* And the binding for the src */
+ switch (*(*inst)++) {
+ case REGISTER_ATTRIB:
+ if (parse_attrib_binding
+ (ctx, inst, Program, &binding, &is_generic))
+ return 1;
+ *File = PROGRAM_INPUT;
+ *Index = binding;
+
+ /* We need to insert a dummy variable into the var_cache so we can
+ * catch generic vertex attrib aliasing errors
+ */
+ var_cache_create(&src);
+ src->type = vt_attrib;
+ src->name = (const GLubyte *) "Dummy Attrib Variable";
+ src->attrib_binding = binding;
+ src->attrib_is_generic = is_generic;
+ var_cache_append(vc_head, src);
+ if (generic_attrib_check(*vc_head)) {
+ program_error(ctx, Program->Position,
+ "Cannot use both a generic vertex attribute "
+ "and a specific attribute of the same type");
+ return 1;
+ }
+ break;
+
+ case REGISTER_PARAM:
+ switch (**inst) {
+ case PARAM_ARRAY_ELEMENT:
+ (*inst)++;
+ src = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+
+ if (!found) {
+ program_error(ctx, Program->Position,
+ "2: Undefined variable"); /* src->name */
+ return 1;
+ }
+
+ *File = (enum register_file) src->param_binding_type;
+
+ switch (*(*inst)++) {
+ case ARRAY_INDEX_ABSOLUTE:
+ offset = parse_integer (inst, Program);
+
+ if ((offset < 0)
+ || (offset >= (int)src->param_binding_length)) {
+ program_error(ctx, Program->Position,
+ "Index out of range");
+ /* offset, src->name */
+ return 1;
+ }
+
+ *Index = src->param_binding_begin + offset;
+ break;
+
+ case ARRAY_INDEX_RELATIVE:
+ {
+ GLint addr_reg_idx, rel_off;
+
+ /* First, grab the address regiseter */
+ if (parse_address_reg (ctx, inst, vc_head, Program, &addr_reg_idx))
+ return 1;
+
+ /* And the .x */
+ ((*inst)++);
+ ((*inst)++);
+ ((*inst)++);
+ ((*inst)++);
+
+ /* Then the relative offset */
+ if (parse_relative_offset(ctx, inst, Program, &rel_off)) return 1;
+
+ /* And store it properly */
+ *Index = src->param_binding_begin + rel_off;
+ *IsRelOffset = 1;
+ }
+ break;
+ }
+ break;
+
+ default:
+ if (parse_param_use (ctx, inst, vc_head, Program, &src))
+ return 1;
+
+ *File = (enum register_file) src->param_binding_type;
+ *Index = src->param_binding_begin;
+ break;
+ }
+ break;
+
+ case REGISTER_ESTABLISHED_NAME:
+ src = parse_string (inst, vc_head, Program, &found);
+ Program->Position = parse_position (inst);
+
+ /* If the name has never been added to our symbol table, we're hosed */
+ if (!found) {
+ program_error(ctx, Program->Position,
+ "3: Undefined variable"); /* src->name */
+ return 1;
+ }
+
+ switch (src->type) {
+ case vt_attrib:
+ *File = PROGRAM_INPUT;
+ *Index = src->attrib_binding;
+ break;
+
+ /* XXX: We have to handle offsets someplace in here! -- or are those above? */
+ case vt_param:
+ *File = (enum register_file) src->param_binding_type;
+ *Index = src->param_binding_begin;
+ break;
+
+ case vt_temp:
+ *File = PROGRAM_TEMPORARY;
+ *Index = src->temp_binding;
+ break;
+
+ /* If the var type is vt_output no go */
+ default:
+ program_error(ctx, Program->Position,
+ "destination register is read only");
+ /* bad src->name */
+ return 1;
+ }
+ break;
+
+ default:
+ program_error(ctx, Program->Position,
+ "Unknown token in parse_src_reg");
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse fragment program vector source register.
+ */
+static GLuint
+parse_fp_vector_src_reg(GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *program,
+ struct prog_src_register *reg)
+{
+ enum register_file file;
+ GLint index;
+ GLboolean negate;
+ GLubyte swizzle[4];
+ GLboolean isRelOffset;
+
+ /* Grab the sign */
+ negate = (parse_sign (inst) == -1) ? 0xf : 0x0;
+
+ /* And the src reg */
+ if (parse_src_reg(ctx, inst, vc_head, program, &file, &index, &isRelOffset))
+ return 1;
+
+ /* finally, the swizzle */
+ parse_swizzle_mask(inst, swizzle, 4);
+
+ reg->File = file;
+ reg->Index = index;
+ reg->Abs = 0; /* NV only */
+ reg->NegateAbs = 0; /* NV only */
+ reg->NegateBase = negate;
+ reg->Swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
+ return 0;
+}
+
+
+/**
+ * Parse fragment program destination register.
+ * \return 1 if error, 0 if no error.
+ */
+static GLuint
+parse_fp_dst_reg(GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head, struct arb_program *Program,
+ struct prog_dst_register *reg )
+{
+ GLint mask;
+ GLuint idx;
+ enum register_file file;
+
+ if (parse_masked_dst_reg (ctx, inst, vc_head, Program, &file, &idx, &mask))
+ return 1;
+
+ reg->CondMask = 0; /* NV only */
+ reg->CondSwizzle = 0; /* NV only */
+ reg->File = file;
+ reg->Index = idx;
+ reg->WriteMask = mask;
+ return 0;
+}
+
+
+/**
+ * Parse fragment program scalar src register.
+ * \return 1 if error, 0 if no error.
+ */
+static GLuint
+parse_fp_scalar_src_reg (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *Program,
+ struct prog_src_register *reg )
+{
+ enum register_file File;
+ GLint Index;
+ GLubyte Negate;
+ GLubyte Swizzle[4];
+ GLboolean IsRelOffset;
+
+ /* Grab the sign */
+ Negate = (parse_sign (inst) == -1) ? 0x1 : 0x0;
+
+ /* And the src reg */
+ if (parse_src_reg (ctx, inst, vc_head, Program, &File, &Index, &IsRelOffset))
+ return 1;
+
+ /* finally, the swizzle */
+ parse_swizzle_mask(inst, Swizzle, 1);
+
+ reg->File = File;
+ reg->Index = Index;
+ reg->Abs = 0; /* NV only */
+ reg->NegateAbs = 0; /* NV only */
+ reg->NegateBase = Negate;
+ reg->Swizzle = (Swizzle[0] << 0);
+
+ return 0;
+}
+
+
+/**
+ * This is a big mother that handles getting opcodes into the instruction
+ * and handling the src & dst registers for fragment program instructions
+ * \return 1 if error, 0 if no error
+ */
+static GLuint
+parse_fp_instruction (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head, struct arb_program *Program,
+ struct prog_instruction *fp)
+{
+ GLint a;
+ GLuint texcoord;
+ GLubyte instClass, type, code;
+ GLboolean rel;
+
+ _mesa_init_instruction(fp);
+
+ /* Record the position in the program string for debugging */
+ fp->StringPos = Program->Position;
+
+ /* OP_ALU_INST or OP_TEX_INST */
+ instClass = *(*inst)++;
+
+ /* OP_ALU_{VECTOR, SCALAR, BINSC, BIN, TRI, SWZ},
+ * OP_TEX_{SAMPLE, KIL}
+ */
+ type = *(*inst)++;
+
+ /* The actual opcode name */
+ code = *(*inst)++;
+
+ /* Increment the correct count */
+ switch (instClass) {
+ case OP_ALU_INST:
+ Program->NumAluInstructions++;
+ break;
+ case OP_TEX_INST:
+ Program->NumTexInstructions++;
+ break;
+ }
+
+ switch (type) {
+ case OP_ALU_VECTOR:
+ switch (code) {
+ case OP_ABS_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_ABS:
+ fp->Opcode = OPCODE_ABS;
+ break;
+
+ case OP_FLR_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_FLR:
+ fp->Opcode = OPCODE_FLR;
+ break;
+
+ case OP_FRC_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_FRC:
+ fp->Opcode = OPCODE_FRC;
+ break;
+
+ case OP_LIT_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_LIT:
+ fp->Opcode = OPCODE_LIT;
+ break;
+
+ case OP_MOV_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_MOV:
+ fp->Opcode = OPCODE_MOV;
+ break;
+ }
+
+ if (parse_fp_dst_reg (ctx, inst, vc_head, Program, &fp->DstReg))
+ return 1;
+
+ if (parse_fp_vector_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[0]))
+ return 1;
+ break;
+
+ case OP_ALU_SCALAR:
+ switch (code) {
+ case OP_COS_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_COS:
+ fp->Opcode = OPCODE_COS;
+ break;
+
+ case OP_EX2_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_EX2:
+ fp->Opcode = OPCODE_EX2;
+ break;
+
+ case OP_LG2_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_LG2:
+ fp->Opcode = OPCODE_LG2;
+ break;
+
+ case OP_RCP_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_RCP:
+ fp->Opcode = OPCODE_RCP;
+ break;
+
+ case OP_RSQ_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_RSQ:
+ fp->Opcode = OPCODE_RSQ;
+ break;
+
+ case OP_SIN_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_SIN:
+ fp->Opcode = OPCODE_SIN;
+ break;
+
+ case OP_SCS_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_SCS:
+
+ fp->Opcode = OPCODE_SCS;
+ break;
+ }
+
+ if (parse_fp_dst_reg (ctx, inst, vc_head, Program, &fp->DstReg))
+ return 1;
+
+ if (parse_fp_scalar_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[0]))
+ return 1;
+ break;
+
+ case OP_ALU_BINSC:
+ switch (code) {
+ case OP_POW_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_POW:
+ fp->Opcode = OPCODE_POW;
+ break;
+ }
+
+ if (parse_fp_dst_reg(ctx, inst, vc_head, Program, &fp->DstReg))
+ return 1;
+
+ for (a = 0; a < 2; a++) {
+ if (parse_fp_scalar_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[a]))
+ return 1;
+ }
+ break;
+
+
+ case OP_ALU_BIN:
+ switch (code) {
+ case OP_ADD_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_ADD:
+ fp->Opcode = OPCODE_ADD;
+ break;
+
+ case OP_DP3_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_DP3:
+ fp->Opcode = OPCODE_DP3;
+ break;
+
+ case OP_DP4_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_DP4:
+ fp->Opcode = OPCODE_DP4;
+ break;
+
+ case OP_DPH_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_DPH:
+ fp->Opcode = OPCODE_DPH;
+ break;
+
+ case OP_DST_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_DST:
+ fp->Opcode = OPCODE_DST;
+ break;
+
+ case OP_MAX_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_MAX:
+ fp->Opcode = OPCODE_MAX;
+ break;
+
+ case OP_MIN_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_MIN:
+ fp->Opcode = OPCODE_MIN;
+ break;
+
+ case OP_MUL_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_MUL:
+ fp->Opcode = OPCODE_MUL;
+ break;
+
+ case OP_SGE_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_SGE:
+ fp->Opcode = OPCODE_SGE;
+ break;
+
+ case OP_SLT_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_SLT:
+ fp->Opcode = OPCODE_SLT;
+ break;
+
+ case OP_SUB_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_SUB:
+ fp->Opcode = OPCODE_SUB;
+ break;
+
+ case OP_XPD_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_XPD:
+ fp->Opcode = OPCODE_XPD;
+ break;
+ }
+
+ if (parse_fp_dst_reg (ctx, inst, vc_head, Program, &fp->DstReg))
+ return 1;
+ for (a = 0; a < 2; a++) {
+ if (parse_fp_vector_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[a]))
+ return 1;
+ }
+ break;
+
+ case OP_ALU_TRI:
+ switch (code) {
+ case OP_CMP_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_CMP:
+ fp->Opcode = OPCODE_CMP;
+ break;
+
+ case OP_LRP_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_LRP:
+ fp->Opcode = OPCODE_LRP;
+ break;
+
+ case OP_MAD_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_MAD:
+ fp->Opcode = OPCODE_MAD;
+ break;
+ }
+
+ if (parse_fp_dst_reg (ctx, inst, vc_head, Program, &fp->DstReg))
+ return 1;
+
+ for (a = 0; a < 3; a++) {
+ if (parse_fp_vector_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[a]))
+ return 1;
+ }
+ break;
+
+ case OP_ALU_SWZ:
+ switch (code) {
+ case OP_SWZ_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_SWZ:
+ fp->Opcode = OPCODE_SWZ;
+ break;
+ }
+ if (parse_fp_dst_reg (ctx, inst, vc_head, Program, &fp->DstReg))
+ return 1;
+
+ {
+ GLubyte swizzle[4];
+ GLubyte negateMask;
+ enum register_file file;
+ GLint index;
+
+ if (parse_src_reg(ctx, inst, vc_head, Program, &file, &index, &rel))
+ return 1;
+ parse_extended_swizzle_mask(inst, swizzle, &negateMask);
+ fp->SrcReg[0].File = file;
+ fp->SrcReg[0].Index = index;
+ fp->SrcReg[0].NegateBase = negateMask;
+ fp->SrcReg[0].Swizzle = MAKE_SWIZZLE4(swizzle[0],
+ swizzle[1],
+ swizzle[2],
+ swizzle[3]);
+ }
+ break;
+
+ case OP_TEX_SAMPLE:
+ switch (code) {
+ case OP_TEX_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_TEX:
+ fp->Opcode = OPCODE_TEX;
+ break;
+
+ case OP_TXP_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_TXP:
+ fp->Opcode = OPCODE_TXP;
+ break;
+
+ case OP_TXB_SAT:
+ fp->SaturateMode = SATURATE_ZERO_ONE;
+ case OP_TXB:
+ fp->Opcode = OPCODE_TXB;
+ break;
+ }
+
+ if (parse_fp_dst_reg (ctx, inst, vc_head, Program, &fp->DstReg))
+ return 1;
+
+ if (parse_fp_vector_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[0]))
+ return 1;
+
+ /* texImageUnit */
+ if (parse_texcoord_num (ctx, inst, Program, &texcoord))
+ return 1;
+ fp->TexSrcUnit = texcoord;
+
+ /* texTarget */
+ switch (*(*inst)++) {
+ case TEXTARGET_1D:
+ fp->TexSrcTarget = TEXTURE_1D_INDEX;
+ break;
+ case TEXTARGET_2D:
+ fp->TexSrcTarget = TEXTURE_2D_INDEX;
+ break;
+ case TEXTARGET_3D:
+ fp->TexSrcTarget = TEXTURE_3D_INDEX;
+ break;
+ case TEXTARGET_RECT:
+ fp->TexSrcTarget = TEXTURE_RECT_INDEX;
+ break;
+ case TEXTARGET_CUBE:
+ fp->TexSrcTarget = TEXTURE_CUBE_INDEX;
+ break;
+ case TEXTARGET_SHADOW1D:
+ case TEXTARGET_SHADOW2D:
+ case TEXTARGET_SHADOWRECT:
+ /* TODO ARB_fragment_program_shadow code */
+ break;
+ }
+ Program->TexturesUsed[texcoord] |= (1 << fp->TexSrcTarget);
+ /* Check that both "2D" and "CUBE" (for example) aren't both used */
+ if (_mesa_bitcount(Program->TexturesUsed[texcoord]) > 1) {
+ program_error(ctx, Program->Position,
+ "multiple targets used on one texture image unit");
+ return 1;
+ }
+ break;
+
+ case OP_TEX_KIL:
+ Program->UsesKill = 1;
+ if (parse_fp_vector_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[0]))
+ return 1;
+ fp->Opcode = OPCODE_KIL;
+ break;
+ default:
+ _mesa_problem(ctx, "bad type 0x%x in parse_fp_instruction()", type);
+ return 1;
+ }
+
+ return 0;
+}
+
+static GLuint
+parse_vp_dst_reg(GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head, struct arb_program *Program,
+ struct prog_dst_register *reg )
+{
+ GLint mask;
+ GLuint idx;
+ enum register_file file;
+
+ if (parse_masked_dst_reg(ctx, inst, vc_head, Program, &file, &idx, &mask))
+ return 1;
+
+ reg->File = file;
+ reg->Index = idx;
+ reg->WriteMask = mask;
+ return 0;
+}
+
+/**
+ * Handle the parsing out of a masked address register
+ *
+ * \param Index - The register index we write to
+ * \param WriteMask - The mask controlling which components we write (1->write)
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_vp_address_reg (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *Program,
+ struct prog_dst_register *reg)
+{
+ GLint idx;
+
+ if (parse_address_reg (ctx, inst, vc_head, Program, &idx))
+ return 1;
+
+ /* This should be 0x8 */
+ (*inst)++;
+
+ reg->File = PROGRAM_ADDRESS;
+ reg->Index = idx;
+
+ /* Writemask of .x is implied */
+ reg->WriteMask = 0x1;
+ return 0;
+}
+
+/**
+ * Parse vertex program vector source register.
+ */
+static GLuint
+parse_vp_vector_src_reg(GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *program,
+ struct prog_src_register *reg )
+{
+ enum register_file file;
+ GLint index;
+ GLubyte negateMask;
+ GLubyte swizzle[4];
+ GLboolean isRelOffset;
+
+ /* Grab the sign */
+ negateMask = (parse_sign (inst) == -1) ? 0xf : 0x0;
+
+ /* And the src reg */
+ if (parse_src_reg (ctx, inst, vc_head, program, &file, &index, &isRelOffset))
+ return 1;
+
+ /* finally, the swizzle */
+ parse_swizzle_mask(inst, swizzle, 4);
+
+ reg->File = file;
+ reg->Index = index;
+ reg->Swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
+ swizzle[2], swizzle[3]);
+ reg->NegateBase = negateMask;
+ reg->RelAddr = isRelOffset;
+ return 0;
+}
+
+
+static GLuint
+parse_vp_scalar_src_reg (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head,
+ struct arb_program *Program,
+ struct prog_src_register *reg )
+{
+ enum register_file File;
+ GLint Index;
+ GLubyte Negate;
+ GLubyte Swizzle[4];
+ GLboolean IsRelOffset;
+
+ /* Grab the sign */
+ Negate = (parse_sign (inst) == -1) ? 0x1 : 0x0;
+
+ /* And the src reg */
+ if (parse_src_reg (ctx, inst, vc_head, Program, &File, &Index, &IsRelOffset))
+ return 1;
+
+ /* finally, the swizzle */
+ parse_swizzle_mask(inst, Swizzle, 1);
+
+ reg->File = File;
+ reg->Index = Index;
+ reg->Swizzle = (Swizzle[0] << 0);
+ reg->NegateBase = Negate;
+ reg->RelAddr = IsRelOffset;
+ return 0;
+}
+
+
+/**
+ * This is a big mother that handles getting opcodes into the instruction
+ * and handling the src & dst registers for vertex program instructions
+ */
+static GLuint
+parse_vp_instruction (GLcontext * ctx, const GLubyte ** inst,
+ struct var_cache **vc_head, struct arb_program *Program,
+ struct prog_instruction *vp)
+{
+ GLint a;
+ GLubyte type, code;
+
+ /* OP_ALU_{ARL, VECTOR, SCALAR, BINSC, BIN, TRI, SWZ} */
+ type = *(*inst)++;
+
+ /* The actual opcode name */
+ code = *(*inst)++;
+
+ _mesa_init_instruction(vp);
+ /* Record the position in the program string for debugging */
+ vp->StringPos = Program->Position;
+
+ switch (type) {
+ /* XXX: */
+ case OP_ALU_ARL:
+ vp->Opcode = OPCODE_ARL;
+
+ /* Remember to set SrcReg.RelAddr; */
+
+ /* Get the masked address register [dst] */
+ if (parse_vp_address_reg(ctx, inst, vc_head, Program, &vp->DstReg))
+ return 1;
+
+ vp->DstReg.File = PROGRAM_ADDRESS;
+
+ /* Get a scalar src register */
+ if (parse_vp_scalar_src_reg(ctx, inst, vc_head, Program, &vp->SrcReg[0]))
+ return 1;
+
+ break;
+
+ case OP_ALU_VECTOR:
+ switch (code) {
+ case OP_ABS:
+ vp->Opcode = OPCODE_ABS;
+ break;
+ case OP_FLR:
+ vp->Opcode = OPCODE_FLR;
+ break;
+ case OP_FRC:
+ vp->Opcode = OPCODE_FRC;
+ break;
+ case OP_LIT:
+ vp->Opcode = OPCODE_LIT;
+ break;
+ case OP_MOV:
+ vp->Opcode = OPCODE_MOV;
+ break;
+ }
+
+ if (parse_vp_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg))
+ return 1;
+
+ if (parse_vp_vector_src_reg(ctx, inst, vc_head, Program, &vp->SrcReg[0]))
+ return 1;
+ break;
+
+ case OP_ALU_SCALAR:
+ switch (code) {
+ case OP_EX2:
+ vp->Opcode = OPCODE_EX2;
+ break;
+ case OP_EXP:
+ vp->Opcode = OPCODE_EXP;
+ break;
+ case OP_LG2:
+ vp->Opcode = OPCODE_LG2;
+ break;
+ case OP_LOG:
+ vp->Opcode = OPCODE_LOG;
+ break;
+ case OP_RCP:
+ vp->Opcode = OPCODE_RCP;
+ break;
+ case OP_RSQ:
+ vp->Opcode = OPCODE_RSQ;
+ break;
+ }
+ if (parse_vp_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg))
+ return 1;
+
+ if (parse_vp_scalar_src_reg(ctx, inst, vc_head, Program, &vp->SrcReg[0]))
+ return 1;
+ break;
+
+ case OP_ALU_BINSC:
+ switch (code) {
+ case OP_POW:
+ vp->Opcode = OPCODE_POW;
+ break;
+ }
+ if (parse_vp_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg))
+ return 1;
+
+ for (a = 0; a < 2; a++) {
+ if (parse_vp_scalar_src_reg(ctx, inst, vc_head, Program, &vp->SrcReg[a]))
+ return 1;
+ }
+ break;
+
+ case OP_ALU_BIN:
+ switch (code) {
+ case OP_ADD:
+ vp->Opcode = OPCODE_ADD;
+ break;
+ case OP_DP3:
+ vp->Opcode = OPCODE_DP3;
+ break;
+ case OP_DP4:
+ vp->Opcode = OPCODE_DP4;
+ break;
+ case OP_DPH:
+ vp->Opcode = OPCODE_DPH;
+ break;
+ case OP_DST:
+ vp->Opcode = OPCODE_DST;
+ break;
+ case OP_MAX:
+ vp->Opcode = OPCODE_MAX;
+ break;
+ case OP_MIN:
+ vp->Opcode = OPCODE_MIN;
+ break;
+ case OP_MUL:
+ vp->Opcode = OPCODE_MUL;
+ break;
+ case OP_SGE:
+ vp->Opcode = OPCODE_SGE;
+ break;
+ case OP_SLT:
+ vp->Opcode = OPCODE_SLT;
+ break;
+ case OP_SUB:
+ vp->Opcode = OPCODE_SUB;
+ break;
+ case OP_XPD:
+ vp->Opcode = OPCODE_XPD;
+ break;
+ }
+ if (parse_vp_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg))
+ return 1;
+
+ for (a = 0; a < 2; a++) {
+ if (parse_vp_vector_src_reg(ctx, inst, vc_head, Program, &vp->SrcReg[a]))
+ return 1;
+ }
+ break;
+
+ case OP_ALU_TRI:
+ switch (code) {
+ case OP_MAD:
+ vp->Opcode = OPCODE_MAD;
+ break;
+ }
+
+ if (parse_vp_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg))
+ return 1;
+
+ for (a = 0; a < 3; a++) {
+ if (parse_vp_vector_src_reg(ctx, inst, vc_head, Program, &vp->SrcReg[a]))
+ return 1;
+ }
+ break;
+
+ case OP_ALU_SWZ:
+ switch (code) {
+ case OP_SWZ:
+ vp->Opcode = OPCODE_SWZ;
+ break;
+ }
+ {
+ GLubyte swizzle[4];
+ GLubyte negateMask;
+ GLboolean relAddr;
+ enum register_file file;
+ GLint index;
+
+ if (parse_vp_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg))
+ return 1;
+
+ if (parse_src_reg(ctx, inst, vc_head, Program, &file, &index, &relAddr))
+ return 1;
+ parse_extended_swizzle_mask (inst, swizzle, &negateMask);
+ vp->SrcReg[0].File = file;
+ vp->SrcReg[0].Index = index;
+ vp->SrcReg[0].NegateBase = negateMask;
+ vp->SrcReg[0].Swizzle = MAKE_SWIZZLE4(swizzle[0],
+ swizzle[1],
+ swizzle[2],
+ swizzle[3]);
+ vp->SrcReg[0].RelAddr = relAddr;
+ }
+ break;
+ }
+ return 0;
+}
+
+#if DEBUG_PARSING
+
+static GLvoid
+print_state_token (GLint token)
+{
+ switch (token) {
+ case STATE_MATERIAL:
+ fprintf (stderr, "STATE_MATERIAL ");
+ break;
+ case STATE_LIGHT:
+ fprintf (stderr, "STATE_LIGHT ");
+ break;
+
+ case STATE_LIGHTMODEL_AMBIENT:
+ fprintf (stderr, "STATE_AMBIENT ");
+ break;
+
+ case STATE_LIGHTMODEL_SCENECOLOR:
+ fprintf (stderr, "STATE_SCENECOLOR ");
+ break;
+
+ case STATE_LIGHTPROD:
+ fprintf (stderr, "STATE_LIGHTPROD ");
+ break;
+
+ case STATE_TEXGEN:
+ fprintf (stderr, "STATE_TEXGEN ");
+ break;
+
+ case STATE_FOG_COLOR:
+ fprintf (stderr, "STATE_FOG_COLOR ");
+ break;
+
+ case STATE_FOG_PARAMS:
+ fprintf (stderr, "STATE_FOG_PARAMS ");
+ break;
+
+ case STATE_CLIPPLANE:
+ fprintf (stderr, "STATE_CLIPPLANE ");
+ break;
+
+ case STATE_POINT_SIZE:
+ fprintf (stderr, "STATE_POINT_SIZE ");
+ break;
+
+ case STATE_POINT_ATTENUATION:
+ fprintf (stderr, "STATE_ATTENUATION ");
+ break;
+
+ case STATE_MATRIX:
+ fprintf (stderr, "STATE_MATRIX ");
+ break;
+
+ case STATE_MODELVIEW:
+ fprintf (stderr, "STATE_MODELVIEW ");
+ break;
+
+ case STATE_PROJECTION:
+ fprintf (stderr, "STATE_PROJECTION ");
+ break;
+
+ case STATE_MVP:
+ fprintf (stderr, "STATE_MVP ");
+ break;
+
+ case STATE_TEXTURE:
+ fprintf (stderr, "STATE_TEXTURE ");
+ break;
+
+ case STATE_PROGRAM:
+ fprintf (stderr, "STATE_PROGRAM ");
+ break;
+
+ case STATE_MATRIX_INVERSE:
+ fprintf (stderr, "STATE_INVERSE ");
+ break;
+
+ case STATE_MATRIX_TRANSPOSE:
+ fprintf (stderr, "STATE_TRANSPOSE ");
+ break;
+
+ case STATE_MATRIX_INVTRANS:
+ fprintf (stderr, "STATE_INVTRANS ");
+ break;
+
+ case STATE_AMBIENT:
+ fprintf (stderr, "STATE_AMBIENT ");
+ break;
+
+ case STATE_DIFFUSE:
+ fprintf (stderr, "STATE_DIFFUSE ");
+ break;
+
+ case STATE_SPECULAR:
+ fprintf (stderr, "STATE_SPECULAR ");
+ break;
+
+ case STATE_EMISSION:
+ fprintf (stderr, "STATE_EMISSION ");
+ break;
+
+ case STATE_SHININESS:
+ fprintf (stderr, "STATE_SHININESS ");
+ break;
+
+ case STATE_HALF:
+ fprintf (stderr, "STATE_HALF ");
+ break;
+
+ case STATE_POSITION:
+ fprintf (stderr, "STATE_POSITION ");
+ break;
+
+ case STATE_ATTENUATION:
+ fprintf (stderr, "STATE_ATTENUATION ");
+ break;
+
+ case STATE_SPOT_DIRECTION:
+ fprintf (stderr, "STATE_DIRECTION ");
+ break;
+
+ case STATE_TEXGEN_EYE_S:
+ fprintf (stderr, "STATE_TEXGEN_EYE_S ");
+ break;
+
+ case STATE_TEXGEN_EYE_T:
+ fprintf (stderr, "STATE_TEXGEN_EYE_T ");
+ break;
+
+ case STATE_TEXGEN_EYE_R:
+ fprintf (stderr, "STATE_TEXGEN_EYE_R ");
+ break;
+
+ case STATE_TEXGEN_EYE_Q:
+ fprintf (stderr, "STATE_TEXGEN_EYE_Q ");
+ break;
+
+ case STATE_TEXGEN_OBJECT_S:
+ fprintf (stderr, "STATE_TEXGEN_EYE_S ");
+ break;
+
+ case STATE_TEXGEN_OBJECT_T:
+ fprintf (stderr, "STATE_TEXGEN_OBJECT_T ");
+ break;
+
+ case STATE_TEXGEN_OBJECT_R:
+ fprintf (stderr, "STATE_TEXGEN_OBJECT_R ");
+ break;
+
+ case STATE_TEXGEN_OBJECT_Q:
+ fprintf (stderr, "STATE_TEXGEN_OBJECT_Q ");
+ break;
+
+ case STATE_TEXENV_COLOR:
+ fprintf (stderr, "STATE_TEXENV_COLOR ");
+ break;
+
+ case STATE_DEPTH_RANGE:
+ fprintf (stderr, "STATE_DEPTH_RANGE ");
+ break;
+
+ case STATE_VERTEX_PROGRAM:
+ fprintf (stderr, "STATE_VERTEX_PROGRAM ");
+ break;
+
+ case STATE_FRAGMENT_PROGRAM:
+ fprintf (stderr, "STATE_FRAGMENT_PROGRAM ");
+ break;
+
+ case STATE_ENV:
+ fprintf (stderr, "STATE_ENV ");
+ break;
+
+ case STATE_LOCAL:
+ fprintf (stderr, "STATE_LOCAL ");
+ break;
+
+ }
+ fprintf (stderr, "[%d] ", token);
+}
+
+
+static GLvoid
+debug_variables (GLcontext * ctx, struct var_cache *vc_head,
+ struct arb_program *Program)
+{
+ struct var_cache *vc;
+ GLint a, b;
+
+ fprintf (stderr, "debug_variables, vc_head: %x\n", vc_head);
+
+ /* First of all, print out the contents of the var_cache */
+ vc = vc_head;
+ while (vc) {
+ fprintf (stderr, "[%x]\n", vc);
+ switch (vc->type) {
+ case vt_none:
+ fprintf (stderr, "UNDEFINED %s\n", vc->name);
+ break;
+ case vt_attrib:
+ fprintf (stderr, "ATTRIB %s\n", vc->name);
+ fprintf (stderr, " binding: 0x%x\n", vc->attrib_binding);
+ break;
+ case vt_param:
+ fprintf (stderr, "PARAM %s begin: %d len: %d\n", vc->name,
+ vc->param_binding_begin, vc->param_binding_length);
+ b = vc->param_binding_begin;
+ for (a = 0; a < vc->param_binding_length; a++) {
+ fprintf (stderr, "%s\n",
+ Program->Parameters->Parameters[a + b].Name);
+ if (Program->Parameters->Parameters[a + b].Type == STATE) {
+ print_state_token (Program->Parameters->Parameters[a + b].
+ StateIndexes[0]);
+ print_state_token (Program->Parameters->Parameters[a + b].
+ StateIndexes[1]);
+ print_state_token (Program->Parameters->Parameters[a + b].
+ StateIndexes[2]);
+ print_state_token (Program->Parameters->Parameters[a + b].
+ StateIndexes[3]);
+ print_state_token (Program->Parameters->Parameters[a + b].
+ StateIndexes[4]);
+ print_state_token (Program->Parameters->Parameters[a + b].
+ StateIndexes[5]);
+ }
+ else
+ fprintf (stderr, "%f %f %f %f\n",
+ Program->Parameters->Parameters[a + b].Values[0],
+ Program->Parameters->Parameters[a + b].Values[1],
+ Program->Parameters->Parameters[a + b].Values[2],
+ Program->Parameters->Parameters[a + b].Values[3]);
+ }
+ break;
+ case vt_temp:
+ fprintf (stderr, "TEMP %s\n", vc->name);
+ fprintf (stderr, " binding: 0x%x\n", vc->temp_binding);
+ break;
+ case vt_output:
+ fprintf (stderr, "OUTPUT %s\n", vc->name);
+ fprintf (stderr, " binding: 0x%x\n", vc->output_binding);
+ break;
+ case vt_alias:
+ fprintf (stderr, "ALIAS %s\n", vc->name);
+ fprintf (stderr, " binding: 0x%x (%s)\n",
+ vc->alias_binding, vc->alias_binding->name);
+ break;
+ }
+ vc = vc->next;
+ }
+}
+
+#endif /* DEBUG_PARSING */
+
+
+/**
+ * The main loop for parsing a fragment or vertex program
+ *
+ * \return 1 on error, 0 on success
+ */
+static GLint
+parse_instructions(GLcontext * ctx, const GLubyte * inst,
+ struct var_cache **vc_head, struct arb_program *Program)
+{
+ const GLuint maxInst = (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
+ ? ctx->Const.FragmentProgram.MaxInstructions
+ : ctx->Const.VertexProgram.MaxInstructions;
+ GLint err = 0;
+
+ ASSERT(MAX_INSTRUCTIONS >= maxInst);
+
+ Program->MajorVersion = (GLuint) * inst++;
+ Program->MinorVersion = (GLuint) * inst++;
+
+ while (*inst != END) {
+ switch (*inst++) {
+
+ case OPTION:
+ switch (*inst++) {
+ case ARB_PRECISION_HINT_FASTEST:
+ Program->PrecisionOption = GL_FASTEST;
+ break;
+
+ case ARB_PRECISION_HINT_NICEST:
+ Program->PrecisionOption = GL_NICEST;
+ break;
+
+ case ARB_FOG_EXP:
+ Program->FogOption = GL_EXP;
+ break;
+
+ case ARB_FOG_EXP2:
+ Program->FogOption = GL_EXP2;
+ break;
+
+ case ARB_FOG_LINEAR:
+ Program->FogOption = GL_LINEAR;
+ break;
+
+ case ARB_POSITION_INVARIANT:
+ if (Program->Base.Target == GL_VERTEX_PROGRAM_ARB)
+ Program->HintPositionInvariant = GL_TRUE;
+ break;
+
+ case ARB_FRAGMENT_PROGRAM_SHADOW:
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+ /* TODO ARB_fragment_program_shadow code */
+ }
+ break;
+
+ case ARB_DRAW_BUFFERS:
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+ /* do nothing for now */
+ }
+ break;
+ }
+ break;
+
+ case INSTRUCTION:
+ /* check length */
+ if (Program->Base.NumInstructions + 1 >= maxInst) {
+ program_error(ctx, Program->Position,
+ "Max instruction count exceeded");
+ return 1;
+ }
+ Program->Position = parse_position (&inst);
+ /* parse the current instruction */
+ if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+ err = parse_fp_instruction (ctx, &inst, vc_head, Program,
+ &Program->Base.Instructions[Program->Base.NumInstructions]);
+ }
+ else {
+ err = parse_vp_instruction (ctx, &inst, vc_head, Program,
+ &Program->Base.Instructions[Program->Base.NumInstructions]);
+ }
+
+ /* increment instuction count */
+ Program->Base.NumInstructions++;
+ break;
+
+ case DECLARATION:
+ err = parse_declaration (ctx, &inst, vc_head, Program);
+ break;
+
+ default:
+ break;
+ }
+
+ if (err)
+ break;
+ }
+
+ /* Finally, tag on an OPCODE_END instruction */
+ {
+ const GLuint numInst = Program->Base.NumInstructions;
+ _mesa_init_instruction(Program->Base.Instructions + numInst);
+ Program->Base.Instructions[numInst].Opcode = OPCODE_END;
+ /* YYY Wrong Position in program, whatever, at least not random -> crash
+ Program->Position = parse_position (&inst);
+ */
+ Program->Base.Instructions[numInst].StringPos = Program->Position;
+ }
+ Program->Base.NumInstructions++;
+
+ /*
+ * Initialize native counts to logical counts. The device driver may
+ * change them if program is translated into a hardware program.
+ */
+ Program->Base.NumNativeInstructions = Program->Base.NumInstructions;
+ Program->Base.NumNativeTemporaries = Program->Base.NumTemporaries;
+ Program->Base.NumNativeParameters = Program->Base.NumParameters;
+ Program->Base.NumNativeAttributes = Program->Base.NumAttributes;
+ Program->Base.NumNativeAddressRegs = Program->Base.NumAddressRegs;
+
+ return err;
+}
+
+
+/* XXX temporary */
+__extension__ static char core_grammar_text[] =
+#include "grammar_syn.h"
+;
+
+
+/**
+ * Set a grammar parameter.
+ * \param name the grammar parameter
+ * \param value the new parameter value
+ * \return 0 if OK, 1 if error
+ */
+static int
+set_reg8 (GLcontext *ctx, grammar id, const char *name, GLubyte value)
+{
+ char error_msg[300];
+ GLint error_pos;
+
+ if (grammar_set_reg8 (id, (const byte *) name, value))
+ return 0;
+
+ grammar_get_last_error ((byte *) error_msg, 300, &error_pos);
+ _mesa_set_program_error (ctx, error_pos, error_msg);
+ _mesa_error (ctx, GL_INVALID_OPERATION, "Grammar Register Error");
+ return 1;
+}
+
+
+/**
+ * Enable support for the given language option in the parser.
+ * \return 1 if OK, 0 if error
+ */
+static int
+enable_ext(GLcontext *ctx, grammar id, const char *name)
+{
+ return !set_reg8(ctx, id, name, 1);
+}
+
+
+/**
+ * Enable parser extensions based on which OpenGL extensions are supported
+ * by this rendering context.
+ *
+ * \return GL_TRUE if OK, GL_FALSE if error.
+ */
+static GLboolean
+enable_parser_extensions(GLcontext *ctx, grammar id)
+{
+#if 0
+ /* These are not supported at this time */
+ if ((ctx->Extensions.ARB_vertex_blend ||
+ ctx->Extensions.EXT_vertex_weighting)
+ && !enable_ext(ctx, id, "vertex_blend"))
+ return GL_FALSE;
+ if (ctx->Extensions.ARB_matrix_palette
+ && !enable_ext(ctx, id, "matrix_palette"))
+ return GL_FALSE;
+ if (ctx->Extensions.ARB_fragment_program_shadow
+ && !enable_ext(ctx, id, "fragment_program_shadow"))
+ return GL_FALSE;
+#endif
+ if (ctx->Extensions.EXT_point_parameters
+ && !enable_ext(ctx, id, "point_parameters"))
+ return GL_FALSE;
+ if (ctx->Extensions.EXT_secondary_color
+ && !enable_ext(ctx, id, "secondary_color"))
+ return GL_FALSE;
+ if (ctx->Extensions.EXT_fog_coord
+ && !enable_ext(ctx, id, "fog_coord"))
+ return GL_FALSE;
+ if (ctx->Extensions.NV_texture_rectangle
+ && !enable_ext(ctx, id, "texture_rectangle"))
+ return GL_FALSE;
+ if (ctx->Extensions.ARB_draw_buffers
+ && !enable_ext(ctx, id, "draw_buffers"))
+ return GL_FALSE;
+
+#if 1
+ /* hack for Warcraft (see bug 8060) */
+ enable_ext(ctx, id, "vertex_blend");
+#endif
+
+ return GL_TRUE;
+}
+
+
+/**
+ * This kicks everything off.
+ *
+ * \param ctx - The GL Context
+ * \param str - The program string
+ * \param len - The program string length
+ * \param program - The arb_program struct to return all the parsed info in
+ * \return GL_TRUE on sucess, GL_FALSE on error
+ */
+static GLboolean
+_mesa_parse_arb_program(GLcontext *ctx, GLenum target,
+ const GLubyte *str, GLsizei len,
+ struct arb_program *program)
+{
+ GLint a, err, error_pos;
+ char error_msg[300];
+ GLuint parsed_len;
+ struct var_cache *vc_head;
+ grammar arbprogram_syn_id;
+ GLubyte *parsed, *inst;
+ GLubyte *strz = NULL;
+ static int arbprogram_syn_is_ok = 0; /* XXX temporary */
+
+ /* set the program target before parsing */
+ program->Base.Target = target;
+
+ /* Reset error state */
+ _mesa_set_program_error(ctx, -1, NULL);
+
+ /* check if arb_grammar_text (arbprogram.syn) is syntactically correct */
+ if (!arbprogram_syn_is_ok) {
+ /* One-time initialization of parsing system */
+ grammar grammar_syn_id;
+ GLuint parsed_len;
+
+ grammar_syn_id = grammar_load_from_text ((byte *) core_grammar_text);
+ if (grammar_syn_id == 0) {
+ grammar_get_last_error ((byte *) error_msg, 300, &error_pos);
+ /* XXX this is not a GL error - it's an implementation bug! - FIX */
+ _mesa_set_program_error (ctx, error_pos, error_msg);
+ _mesa_error (ctx, GL_INVALID_OPERATION,
+ "glProgramStringARB(Error loading grammar rule set)");
+ return GL_FALSE;
+ }
+
+ err = !grammar_check(grammar_syn_id, (byte *) arb_grammar_text,
+ &parsed, &parsed_len);
+
+ /* 'parsed' is unused here */
+ _mesa_free (parsed);
+ parsed = NULL;
+
+ /* NOTE: we can't destroy grammar_syn_id right here because
+ * grammar_destroy() can reset the last error
+ */
+ if (err) {
+ /* XXX this is not a GL error - it's an implementation bug! - FIX */
+ grammar_get_last_error ((byte *) error_msg, 300, &error_pos);
+ _mesa_set_program_error (ctx, error_pos, error_msg);
+ _mesa_error (ctx, GL_INVALID_OPERATION,
+ "glProgramString(Error loading grammar rule set");
+ grammar_destroy (grammar_syn_id);
+ return GL_FALSE;
+ }
+
+ grammar_destroy (grammar_syn_id);
+
+ arbprogram_syn_is_ok = 1;
+ }
+
+ /* create the grammar object */
+ arbprogram_syn_id = grammar_load_from_text ((byte *) arb_grammar_text);
+ if (arbprogram_syn_id == 0) {
+ /* XXX this is not a GL error - it's an implementation bug! - FIX */
+ grammar_get_last_error ((GLubyte *) error_msg, 300, &error_pos);
+ _mesa_set_program_error (ctx, error_pos, error_msg);
+ _mesa_error (ctx, GL_INVALID_OPERATION,
+ "glProgramString(Error loading grammer rule set)");
+ return GL_FALSE;
+ }
+
+ /* Set program_target register value */
+ if (set_reg8 (ctx, arbprogram_syn_id, "program_target",
+ program->Base.Target == GL_FRAGMENT_PROGRAM_ARB ? 0x10 : 0x20)) {
+ grammar_destroy (arbprogram_syn_id);
+ return GL_FALSE;
+ }
+
+ if (!enable_parser_extensions(ctx, arbprogram_syn_id)) {
+ grammar_destroy(arbprogram_syn_id);
+ return GL_FALSE;
+ }
+
+ /* check for NULL character occurences */
+ {
+ GLint i;
+ for (i = 0; i < len; i++) {
+ if (str[i] == '\0') {
+ program_error(ctx, i, "illegal character");
+ grammar_destroy (arbprogram_syn_id);
+ return GL_FALSE;
+ }
+ }
+ }
+
+ /* copy the program string to a null-terminated string */
+ strz = (GLubyte *) _mesa_malloc (len + 1);
+ if (!strz) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB");
+ grammar_destroy (arbprogram_syn_id);
+ return GL_FALSE;
+ }
+ _mesa_memcpy (strz, str, len);
+ strz[len] = '\0';
+
+ /* do a fast check on program string - initial production buffer is 4K */
+ err = !grammar_fast_check(arbprogram_syn_id, strz,
+ &parsed, &parsed_len, 0x1000);
+
+ /* Syntax parse error */
+ if (err) {
+ grammar_get_last_error((GLubyte *) error_msg, 300, &error_pos);
+ program_error(ctx, error_pos, error_msg);
+
+#if DEBUG_PARSING
+ /* useful for debugging */
+ do {
+ int line, col;
+ char *s;
+ fprintf(stderr, "program: %s\n", (char *) strz);
+ fprintf(stderr, "Error Pos: %d\n", ctx->program.ErrorPos);
+ s = (char *) _mesa_find_line_column(strz, strz+ctx->program.ErrorPos,
+ &line, &col);
+ fprintf(stderr, "line %d col %d: %s\n", line, col, s);
+ } while (0)
+#endif
+
+ _mesa_free(strz);
+ _mesa_free(parsed);
+
+ grammar_destroy (arbprogram_syn_id);
+ return GL_FALSE;
+ }
+
+ grammar_destroy (arbprogram_syn_id);
+
+ /*
+ * Program string is syntactically correct at this point
+ * Parse the tokenized version of the program now, generating
+ * vertex/fragment program instructions.
+ */
+
+ /* Initialize the arb_program struct */
+ program->Base.String = strz;
+ program->Base.Instructions = _mesa_alloc_instructions(MAX_INSTRUCTIONS);
+ program->Base.NumInstructions =
+ program->Base.NumTemporaries =
+ program->Base.NumParameters =
+ program->Base.NumAttributes = program->Base.NumAddressRegs = 0;
+ program->Base.Parameters = _mesa_new_parameter_list ();
+ program->Base.InputsRead = 0x0;
+ program->Base.OutputsWritten = 0x0;
+ program->Position = 0;
+ program->MajorVersion = program->MinorVersion = 0;
+ program->PrecisionOption = GL_DONT_CARE;
+ program->FogOption = GL_NONE;
+ program->HintPositionInvariant = GL_FALSE;
+ for (a = 0; a < MAX_TEXTURE_IMAGE_UNITS; a++)
+ program->TexturesUsed[a] = 0x0;
+ program->NumAluInstructions =
+ program->NumTexInstructions =
+ program->NumTexIndirections = 0;
+ program->UsesKill = 0;
+
+ vc_head = NULL;
+ err = GL_FALSE;
+
+ /* Start examining the tokens in the array */
+ inst = parsed;
+
+ /* Check the grammer rev */
+ if (*inst++ != REVISION) {
+ program_error (ctx, 0, "Grammar version mismatch");
+ err = GL_TRUE;
+ }
+ else {
+ /* ignore program target */
+ inst++;
+ err = parse_instructions(ctx, inst, &vc_head, program);
+ }
+
+ /*debug_variables(ctx, vc_head, program); */
+
+ /* We're done with the parsed binary array */
+ var_cache_destroy (&vc_head);
+
+ _mesa_free (parsed);
+
+ /* Reallocate the instruction array from size [MAX_INSTRUCTIONS]
+ * to size [ap.Base.NumInstructions].
+ */
+ program->Base.Instructions
+ = _mesa_realloc_instructions(program->Base.Instructions,
+ MAX_INSTRUCTIONS,
+ program->Base.NumInstructions);
+
+ return !err;
+}
+
+
+
+void
+_mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_fragment_program *program)
+{
+ struct arb_program ap;
+ GLuint i;
+
+ ASSERT(target == GL_FRAGMENT_PROGRAM_ARB);
+ if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, &ap)) {
+ /* Error in the program. Just return. */
+ return;
+ }
+
+ /* Copy the relevant contents of the arb_program struct into the
+ * fragment_program struct.
+ */
+ program->Base.String = ap.Base.String;
+ program->Base.NumInstructions = ap.Base.NumInstructions;
+ program->Base.NumTemporaries = ap.Base.NumTemporaries;
+ program->Base.NumParameters = ap.Base.NumParameters;
+ program->Base.NumAttributes = ap.Base.NumAttributes;
+ program->Base.NumAddressRegs = ap.Base.NumAddressRegs;
+ program->Base.NumNativeInstructions = ap.Base.NumNativeInstructions;
+ program->Base.NumNativeTemporaries = ap.Base.NumNativeTemporaries;
+ program->Base.NumNativeParameters = ap.Base.NumNativeParameters;
+ program->Base.NumNativeAttributes = ap.Base.NumNativeAttributes;
+ program->Base.NumNativeAddressRegs = ap.Base.NumNativeAddressRegs;
+ program->NumAluInstructions = ap.NumAluInstructions;
+ program->NumTexInstructions = ap.NumTexInstructions;
+ program->NumTexIndirections = ap.NumTexIndirections;
+ program->NumNativeAluInstructions = ap.NumAluInstructions;
+ program->NumNativeTexInstructions = ap.NumTexInstructions;
+ program->NumNativeTexIndirections = ap.NumTexIndirections;
+ program->Base.InputsRead = ap.Base.InputsRead;
+ program->Base.OutputsWritten = ap.Base.OutputsWritten;
+ for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
+ program->TexturesUsed[i] = ap.TexturesUsed[i];
+ program->FogOption = ap.FogOption;
+
+ if (program->Base.Instructions)
+ _mesa_free(program->Base.Instructions);
+ program->Base.Instructions = ap.Base.Instructions;
+
+ if (program->Base.Parameters)
+ _mesa_free_parameter_list(program->Base.Parameters);
+ program->Base.Parameters = ap.Base.Parameters;
+
+#if DEBUG_FP
+ _mesa_print_program(&program.Base);
+#endif
+}
+
+
+
+/**
+ * Parse the vertex program string. If success, update the given
+ * vertex_program object with the new program. Else, leave the vertex_program
+ * object unchanged.
+ */
+void
+_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_vertex_program *program)
+{
+ struct arb_program ap;
+
+ ASSERT(target == GL_VERTEX_PROGRAM_ARB);
+
+ if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, &ap)) {
+ /* Error in the program. Just return. */
+ return;
+ }
+
+ /* Copy the relevant contents of the arb_program struct into the
+ * vertex_program struct.
+ */
+ program->Base.String = ap.Base.String;
+ program->Base.NumInstructions = ap.Base.NumInstructions;
+ program->Base.NumTemporaries = ap.Base.NumTemporaries;
+ program->Base.NumParameters = ap.Base.NumParameters;
+ program->Base.NumAttributes = ap.Base.NumAttributes;
+ program->Base.NumAddressRegs = ap.Base.NumAddressRegs;
+ program->Base.NumNativeInstructions = ap.Base.NumNativeInstructions;
+ program->Base.NumNativeTemporaries = ap.Base.NumNativeTemporaries;
+ program->Base.NumNativeParameters = ap.Base.NumNativeParameters;
+ program->Base.NumNativeAttributes = ap.Base.NumNativeAttributes;
+ program->Base.NumNativeAddressRegs = ap.Base.NumNativeAddressRegs;
+ program->Base.InputsRead = ap.Base.InputsRead;
+ program->Base.OutputsWritten = ap.Base.OutputsWritten;
+ program->IsPositionInvariant = ap.HintPositionInvariant;
+
+ if (program->Base.Instructions)
+ _mesa_free(program->Base.Instructions);
+ program->Base.Instructions = ap.Base.Instructions;
+
+ if (program->Base.Parameters)
+ _mesa_free_parameter_list(program->Base.Parameters);
+ program->Base.Parameters = ap.Base.Parameters;
+
+#if DEBUG_VP
+ _mesa_print_program(&program->Base);
+#endif
+}
diff --git a/src/mesa/shader/arbprogparse.h b/src/mesa/shader/arbprogparse.h
new file mode 100644
index 00000000000..4574e5cd553
--- /dev/null
+++ b/src/mesa/shader/arbprogparse.h
@@ -0,0 +1,41 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2005 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.
+ */
+
+
+#ifndef ARBPROGPARSE_H
+#define ARBPROGPARSE_H
+
+#include "mtypes.h"
+
+extern void
+_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_vertex_program *program);
+
+extern void
+_mesa_parse_arb_fragment_program(GLcontext *ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_fragment_program *program);
+
+#endif
diff --git a/src/mesa/shader/arbprogram.c b/src/mesa/shader/arbprogram.c
new file mode 100644
index 00000000000..89f2d20cc9a
--- /dev/null
+++ b/src/mesa/shader/arbprogram.c
@@ -0,0 +1,763 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2006 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 arbprogram.c
+ * ARB_vertex/fragment_program state management functions.
+ * \author Brian Paul
+ */
+
+
+#include "glheader.h"
+#include "arbprogram.h"
+#include "arbprogparse.h"
+#include "context.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+
+
+void GLAPIENTRY
+_mesa_EnableVertexAttribArrayARB(GLuint index)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (index >= ctx->Const.VertexProgram.MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glEnableVertexAttribArrayARB(index)");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_ARRAY);
+ ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_TRUE;
+ ctx->Array.ArrayObj->_Enabled |= _NEW_ARRAY_ATTRIB(index);
+ ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
+}
+
+
+void GLAPIENTRY
+_mesa_DisableVertexAttribArrayARB(GLuint index)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (index >= ctx->Const.VertexProgram.MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glEnableVertexAttribArrayARB(index)");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_ARRAY);
+ ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_FALSE;
+ ctx->Array.ArrayObj->_Enabled &= ~_NEW_ARRAY_ATTRIB(index);
+ ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
+}
+
+
+void GLAPIENTRY
+_mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params)
+{
+ GLfloat fparams[4];
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ _mesa_GetVertexAttribfvARB(index, pname, fparams);
+ if (ctx->ErrorValue == GL_NO_ERROR) {
+ if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
+ COPY_4V(params, fparams);
+ }
+ else {
+ params[0] = fparams[0];
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (index == 0 || index >= MAX_VERTEX_PROGRAM_ATTRIBS) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribfvARB(index)");
+ return;
+ }
+
+ switch (pname) {
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB:
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Enabled;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB:
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Size;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB:
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Stride;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB:
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Type;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB:
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Normalized;
+ break;
+ case GL_CURRENT_VERTEX_ATTRIB_ARB:
+ FLUSH_CURRENT(ctx, 0);
+ COPY_4V(params, ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + index]);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
+ if (!ctx->Extensions.ARB_vertex_buffer_object) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribfvARB(pname)");
+ return;
+ }
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].BufferObj->Name;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribfvARB(pname)");
+ return;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params)
+{
+ GLfloat fparams[4];
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ _mesa_GetVertexAttribfvARB(index, pname, fparams);
+ if (ctx->ErrorValue == GL_NO_ERROR) {
+ if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
+ COPY_4V_CAST(params, fparams, GLint); /* float to int */
+ }
+ else {
+ params[0] = (GLint) fparams[0];
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (index >= ctx->Const.VertexProgram.MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerARB(index)");
+ return;
+ }
+
+ if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerARB(pname)");
+ return;
+ }
+
+ *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr;
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
+ const GLvoid *string)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
+ return;
+ }
+
+ if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ struct gl_vertex_program *prog = ctx->VertexProgram.Current;
+ _mesa_parse_arb_vertex_program(ctx, target, string, len, prog);
+
+ if (ctx->Driver.ProgramStringNotify)
+ ctx->Driver.ProgramStringNotify( ctx, target, &prog->Base );
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
+ _mesa_parse_arb_fragment_program(ctx, target, string, len, prog);
+
+ if (ctx->Driver.ProgramStringNotify)
+ ctx->Driver.ProgramStringNotify( ctx, target, &prog->Base );
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)");
+ return;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index,
+ GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+ _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
+ (GLfloat) z, (GLfloat) w);
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index,
+ const GLdouble *params)
+{
+ _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0],
+ (GLfloat) params[1], (GLfloat) params[2],
+ (GLfloat) params[3]);
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index,
+ GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
+ return;
+ }
+ ASSIGN_4V(ctx->FragmentProgram.Parameters[index], x, y, z, w);
+ }
+ else if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
+ return;
+ }
+ ASSIGN_4V(ctx->VertexProgram.Parameters[index], x, y, z, w);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter(target)");
+ return;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
+ const GLfloat *params)
+{
+ _mesa_ProgramEnvParameter4fARB(target, index, params[0], params[1],
+ params[2], params[3]);
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
+ const GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ unsigned i;
+ GLfloat * dest;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (count <= 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)");
+ }
+
+ if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
+ return;
+ }
+ dest = ctx->FragmentProgram.Parameters[index];
+ }
+ else if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
+ return;
+ }
+ dest = ctx->VertexProgram.Parameters[index];
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)");
+ return;
+ }
+
+ for ( i = 0 ; i < count ; i++ ) {
+ COPY_4V(dest, params);
+ params += 4;
+ dest += 4;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index,
+ GLdouble *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat fparams[4];
+
+ _mesa_GetProgramEnvParameterfvARB(target, index, fparams);
+ if (ctx->ErrorValue == GL_NO_ERROR) {
+ params[0] = fparams[0];
+ params[1] = fparams[1];
+ params[2] = fparams[2];
+ params[3] = fparams[3];
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index,
+ GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (!ctx->_CurrentProgram)
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
+ return;
+ }
+ COPY_4V(params, ctx->FragmentProgram.Parameters[index]);
+ }
+ else if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
+ return;
+ }
+ COPY_4V(params, ctx->VertexProgram.Parameters[index]);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramEnvParameter(target)");
+ return;
+ }
+}
+
+
+/**
+ * Note, this function is also used by the GL_NV_fragment_program extension.
+ */
+void GLAPIENTRY
+_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
+ GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_program *prog;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if ((target == GL_FRAGMENT_PROGRAM_NV
+ && ctx->Extensions.NV_fragment_program) ||
+ (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program)) {
+ if (index >= ctx->Const.FragmentProgram.MaxLocalParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
+ return;
+ }
+ prog = &(ctx->FragmentProgram.Current->Base);
+ }
+ else if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ if (index >= ctx->Const.VertexProgram.MaxLocalParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
+ return;
+ }
+ prog = &(ctx->VertexProgram.Current->Base);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
+ return;
+ }
+
+ ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
+ prog->LocalParams[index][0] = x;
+ prog->LocalParams[index][1] = y;
+ prog->LocalParams[index][2] = z;
+ prog->LocalParams[index][3] = w;
+}
+
+
+/**
+ * Note, this function is also used by the GL_NV_fragment_program extension.
+ */
+void GLAPIENTRY
+_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
+ const GLfloat *params)
+{
+ _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1],
+ params[2], params[3]);
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
+ const GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_program *prog;
+ unsigned i;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (count <= 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)");
+ }
+
+ if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ if ((index + count) > ctx->Const.FragmentProgram.MaxLocalParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
+ return;
+ }
+ prog = &(ctx->FragmentProgram.Current->Base);
+ }
+ else if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ if ((index + count) > ctx->Const.VertexProgram.MaxLocalParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
+ return;
+ }
+ prog = &(ctx->VertexProgram.Current->Base);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameters4fvEXT(target)");
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ ASSERT((index + i) < MAX_PROGRAM_LOCAL_PARAMS);
+ COPY_4V(prog->LocalParams[index + i], params);
+ params += 4;
+ }
+}
+
+
+/**
+ * Note, this function is also used by the GL_NV_fragment_program extension.
+ */
+void GLAPIENTRY
+_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
+ GLdouble x, GLdouble y,
+ GLdouble z, GLdouble w)
+{
+ _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
+ (GLfloat) z, (GLfloat) w);
+}
+
+
+/**
+ * Note, this function is also used by the GL_NV_fragment_program extension.
+ */
+void GLAPIENTRY
+_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
+ const GLdouble *params)
+{
+ _mesa_ProgramLocalParameter4fARB(target, index,
+ (GLfloat) params[0], (GLfloat) params[1],
+ (GLfloat) params[2], (GLfloat) params[3]);
+}
+
+
+/**
+ * Note, this function is also used by the GL_NV_fragment_program extension.
+ */
+void GLAPIENTRY
+_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
+ GLfloat *params)
+{
+ const struct gl_program *prog;
+ GLuint maxParams;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ prog = &(ctx->VertexProgram.Current->Base);
+ maxParams = ctx->Const.VertexProgram.MaxLocalParams;
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ prog = &(ctx->FragmentProgram.Current->Base);
+ maxParams = ctx->Const.FragmentProgram.MaxLocalParams;
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_NV
+ && ctx->Extensions.NV_fragment_program) {
+ prog = &(ctx->FragmentProgram.Current->Base);
+ maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetProgramLocalParameterARB(target)");
+ return;
+ }
+
+ if (index >= maxParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramLocalParameterARB(index)");
+ return;
+ }
+
+ ASSERT(prog);
+ ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
+ COPY_4V(params, prog->LocalParams[index]);
+}
+
+
+/**
+ * Note, this function is also used by the GL_NV_fragment_program extension.
+ */
+void GLAPIENTRY
+_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
+ GLdouble *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat floatParams[4];
+ _mesa_GetProgramLocalParameterfvARB(target, index, floatParams);
+ if (ctx->ErrorValue == GL_NO_ERROR) {
+ COPY_4V(params, floatParams);
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params)
+{
+ const struct gl_program_constants *limits;
+ struct gl_program *prog;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->_CurrentProgram)
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ prog = &(ctx->VertexProgram.Current->Base);
+ limits = &ctx->Const.VertexProgram;
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ prog = &(ctx->FragmentProgram.Current->Base);
+ limits = &ctx->Const.FragmentProgram;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
+ return;
+ }
+
+ ASSERT(prog);
+ ASSERT(limits);
+
+ /* Queries supported for both vertex and fragment programs */
+ switch (pname) {
+ case GL_PROGRAM_LENGTH_ARB:
+ *params
+ = prog->String ? (GLint) _mesa_strlen((char *) prog->String) : 0;
+ return;
+ case GL_PROGRAM_FORMAT_ARB:
+ *params = prog->Format;
+ return;
+ case GL_PROGRAM_BINDING_ARB:
+ *params = prog->Id;
+ return;
+ case GL_PROGRAM_INSTRUCTIONS_ARB:
+ *params = prog->NumInstructions;
+ return;
+ case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
+ *params = limits->MaxInstructions;
+ return;
+ case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
+ *params = prog->NumNativeInstructions;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
+ *params = limits->MaxNativeInstructions;
+ return;
+ case GL_PROGRAM_TEMPORARIES_ARB:
+ *params = prog->NumTemporaries;
+ return;
+ case GL_MAX_PROGRAM_TEMPORARIES_ARB:
+ *params = limits->MaxTemps;
+ return;
+ case GL_PROGRAM_NATIVE_TEMPORARIES_ARB:
+ *params = prog->NumNativeTemporaries;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
+ *params = limits->MaxNativeTemps;
+ return;
+ case GL_PROGRAM_PARAMETERS_ARB:
+ *params = prog->NumParameters;
+ return;
+ case GL_MAX_PROGRAM_PARAMETERS_ARB:
+ *params = limits->MaxParameters;
+ return;
+ case GL_PROGRAM_NATIVE_PARAMETERS_ARB:
+ *params = prog->NumNativeParameters;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
+ *params = limits->MaxNativeParameters;
+ return;
+ case GL_PROGRAM_ATTRIBS_ARB:
+ *params = prog->NumAttributes;
+ return;
+ case GL_MAX_PROGRAM_ATTRIBS_ARB:
+ *params = limits->MaxAttribs;
+ return;
+ case GL_PROGRAM_NATIVE_ATTRIBS_ARB:
+ *params = prog->NumNativeAttributes;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
+ *params = limits->MaxNativeAttribs;
+ return;
+ case GL_PROGRAM_ADDRESS_REGISTERS_ARB:
+ *params = prog->NumAddressRegs;
+ return;
+ case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
+ *params = limits->MaxAddressRegs;
+ return;
+ case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
+ *params = prog->NumNativeAddressRegs;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
+ *params = limits->MaxNativeAddressRegs;
+ return;
+ case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
+ *params = limits->MaxLocalParams;
+ return;
+ case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
+ *params = limits->MaxEnvParams;
+ return;
+ case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB:
+ /*
+ * XXX we may not really need a driver callback here.
+ * If the number of native instructions, registers, etc. used
+ * are all below the maximums, we could return true.
+ * The spec says that even if this query returns true, there's
+ * no guarantee that the program will run in hardware.
+ */
+ if (ctx->Driver.IsProgramNative)
+ *params = ctx->Driver.IsProgramNative( ctx, target, prog );
+ else
+ *params = GL_TRUE;
+ return;
+ default:
+ /* continue with fragment-program only queries below */
+ break;
+ }
+
+ /*
+ * The following apply to fragment programs only (at this time)
+ */
+ if (target == GL_FRAGMENT_PROGRAM_ARB) {
+ const struct gl_fragment_program *fp = ctx->FragmentProgram.Current;
+ switch (pname) {
+ case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
+ *params = fp->NumNativeAluInstructions;
+ return;
+ case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
+ *params = fp->NumAluInstructions;
+ return;
+ case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
+ *params = fp->NumTexInstructions;
+ return;
+ case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
+ *params = fp->NumNativeTexInstructions;
+ return;
+ case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
+ *params = fp->NumTexIndirections;
+ return;
+ case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
+ *params = fp->NumNativeTexIndirections;
+ return;
+ case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
+ *params = limits->MaxAluInstructions;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
+ *params = limits->MaxNativeAluInstructions;
+ return;
+ case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
+ *params = limits->MaxTexInstructions;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
+ *params = limits->MaxNativeTexInstructions;
+ return;
+ case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB:
+ *params = limits->MaxTexIndirections;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
+ *params = limits->MaxNativeTexIndirections;
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
+ return;
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string)
+{
+ const struct gl_program *prog;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->_CurrentProgram)
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (target == GL_VERTEX_PROGRAM_ARB) {
+ prog = &(ctx->VertexProgram.Current->Base);
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_ARB) {
+ prog = &(ctx->FragmentProgram.Current->Base);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)");
+ return;
+ }
+
+ ASSERT(prog);
+
+ if (pname != GL_PROGRAM_STRING_ARB) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)");
+ return;
+ }
+
+ _mesa_memcpy(string, prog->String, _mesa_strlen((char *) prog->String));
+}
diff --git a/src/mesa/shader/arbprogram.h b/src/mesa/shader/arbprogram.h
new file mode 100644
index 00000000000..54a14bbb9f8
--- /dev/null
+++ b/src/mesa/shader/arbprogram.h
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ARBPROGRAM_H
+#define ARBPROGRAM_H
+
+
+extern void GLAPIENTRY
+_mesa_EnableVertexAttribArrayARB(GLuint index);
+
+
+extern void GLAPIENTRY
+_mesa_DisableVertexAttribArrayARB(GLuint index);
+
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
+ const GLvoid *string);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index,
+ GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index,
+ const GLdouble *params);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index,
+ GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
+ const GLfloat *params);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
+ const GLfloat *params);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
+ GLdouble x, GLdouble y,
+ GLdouble z, GLdouble w);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
+ const GLdouble *params);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
+ GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
+ const GLfloat *params);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
+ const GLfloat *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index,
+ GLdouble *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index,
+ GLfloat *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
+ GLdouble *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
+ GLfloat *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params);
+
+
+extern void GLAPIENTRY
+_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string);
+
+
+#endif
diff --git a/src/mesa/shader/arbprogram_syn.h b/src/mesa/shader/arbprogram_syn.h
new file mode 100644
index 00000000000..c67afc67db9
--- /dev/null
+++ b/src/mesa/shader/arbprogram_syn.h
@@ -0,0 +1,1327 @@
+".syntax program;\n"
+".emtcode REVISION 0x09\n"
+".emtcode FRAGMENT_PROGRAM 0x01\n"
+".emtcode VERTEX_PROGRAM 0x02\n"
+".emtcode OPTION 0x01\n"
+".emtcode INSTRUCTION 0x02\n"
+".emtcode DECLARATION 0x03\n"
+".emtcode END 0x04\n"
+".emtcode ARB_PRECISION_HINT_FASTEST 0x00\n"
+".emtcode ARB_PRECISION_HINT_NICEST 0x01\n"
+".emtcode ARB_FOG_EXP 0x02\n"
+".emtcode ARB_FOG_EXP2 0x03\n"
+".emtcode ARB_FOG_LINEAR 0x04\n"
+".emtcode ARB_POSITION_INVARIANT 0x05\n"
+".emtcode ARB_FRAGMENT_PROGRAM_SHADOW 0x06\n"
+".emtcode ARB_DRAW_BUFFERS 0x07\n"
+".emtcode OP_ALU_INST 0x00\n"
+".emtcode OP_TEX_INST 0x01\n"
+".emtcode OP_ALU_VECTOR 0x00\n"
+".emtcode OP_ALU_SCALAR 0x01\n"
+".emtcode OP_ALU_BINSC 0x02\n"
+".emtcode OP_ALU_BIN 0x03\n"
+".emtcode OP_ALU_TRI 0x04\n"
+".emtcode OP_ALU_SWZ 0x05\n"
+".emtcode OP_TEX_SAMPLE 0x06\n"
+".emtcode OP_TEX_KIL 0x07\n"
+".emtcode OP_ALU_ARL 0x08\n"
+".emtcode OP_ABS 0x00\n"
+".emtcode OP_ABS_SAT 0x1B\n"
+".emtcode OP_FLR 0x09\n"
+".emtcode OP_FLR_SAT 0x26\n"
+".emtcode OP_FRC 0x0A\n"
+".emtcode OP_FRC_SAT 0x27\n"
+".emtcode OP_LIT 0x0C\n"
+".emtcode OP_LIT_SAT 0x2A\n"
+".emtcode OP_MOV 0x11\n"
+".emtcode OP_MOV_SAT 0x30\n"
+".emtcode OP_COS 0x1F\n"
+".emtcode OP_COS_SAT 0x20\n"
+".emtcode OP_EX2 0x07\n"
+".emtcode OP_EX2_SAT 0x25\n"
+".emtcode OP_LG2 0x0B\n"
+".emtcode OP_LG2_SAT 0x29\n"
+".emtcode OP_RCP 0x14\n"
+".emtcode OP_RCP_SAT 0x33\n"
+".emtcode OP_RSQ 0x15\n"
+".emtcode OP_RSQ_SAT 0x34\n"
+".emtcode OP_SIN 0x38\n"
+".emtcode OP_SIN_SAT 0x39\n"
+".emtcode OP_SCS 0x35\n"
+".emtcode OP_SCS_SAT 0x36\n"
+".emtcode OP_POW 0x13\n"
+".emtcode OP_POW_SAT 0x32\n"
+".emtcode OP_ADD 0x01\n"
+".emtcode OP_ADD_SAT 0x1C\n"
+".emtcode OP_DP3 0x03\n"
+".emtcode OP_DP3_SAT 0x21\n"
+".emtcode OP_DP4 0x04\n"
+".emtcode OP_DP4_SAT 0x22\n"
+".emtcode OP_DPH 0x05\n"
+".emtcode OP_DPH_SAT 0x23\n"
+".emtcode OP_DST 0x06\n"
+".emtcode OP_DST_SAT 0x24\n"
+".emtcode OP_MAX 0x0F\n"
+".emtcode OP_MAX_SAT 0x2E\n"
+".emtcode OP_MIN 0x10\n"
+".emtcode OP_MIN_SAT 0x2F\n"
+".emtcode OP_MUL 0x12\n"
+".emtcode OP_MUL_SAT 0x31\n"
+".emtcode OP_SGE 0x16\n"
+".emtcode OP_SGE_SAT 0x37\n"
+".emtcode OP_SLT 0x17\n"
+".emtcode OP_SLT_SAT 0x3A\n"
+".emtcode OP_SUB 0x18\n"
+".emtcode OP_SUB_SAT 0x3B\n"
+".emtcode OP_XPD 0x1A\n"
+".emtcode OP_XPD_SAT 0x43\n"
+".emtcode OP_CMP 0x1D\n"
+".emtcode OP_CMP_SAT 0x1E\n"
+".emtcode OP_LRP 0x2B\n"
+".emtcode OP_LRP_SAT 0x2C\n"
+".emtcode OP_MAD 0x0E\n"
+".emtcode OP_MAD_SAT 0x2D\n"
+".emtcode OP_SWZ 0x19\n"
+".emtcode OP_SWZ_SAT 0x3C\n"
+".emtcode OP_TEX 0x3D\n"
+".emtcode OP_TEX_SAT 0x3E\n"
+".emtcode OP_TXB 0x3F\n"
+".emtcode OP_TXB_SAT 0x40\n"
+".emtcode OP_TXP 0x41\n"
+".emtcode OP_TXP_SAT 0x42\n"
+".emtcode OP_KIL 0x28\n"
+".emtcode OP_ARL 0x02\n"
+".emtcode OP_EXP 0x08\n"
+".emtcode OP_LOG 0x0D\n"
+".emtcode FRAGMENT_ATTRIB_COLOR 0x01\n"
+".emtcode FRAGMENT_ATTRIB_TEXCOORD 0x02\n"
+".emtcode FRAGMENT_ATTRIB_FOGCOORD 0x03\n"
+".emtcode FRAGMENT_ATTRIB_POSITION 0x04\n"
+".emtcode VERTEX_ATTRIB_POSITION 0x01\n"
+".emtcode VERTEX_ATTRIB_WEIGHT 0x02\n"
+".emtcode VERTEX_ATTRIB_NORMAL 0x03\n"
+".emtcode VERTEX_ATTRIB_COLOR 0x04\n"
+".emtcode VERTEX_ATTRIB_FOGCOORD 0x05\n"
+".emtcode VERTEX_ATTRIB_TEXCOORD 0x06\n"
+".emtcode VERTEX_ATTRIB_MATRIXINDEX 0x07\n"
+".emtcode VERTEX_ATTRIB_GENERIC 0x08\n"
+".emtcode FRAGMENT_RESULT_COLOR 0x01\n"
+".emtcode FRAGMENT_RESULT_DEPTH 0x02\n"
+".emtcode VERTEX_RESULT_POSITION 0x01\n"
+".emtcode VERTEX_RESULT_COLOR 0x02\n"
+".emtcode VERTEX_RESULT_FOGCOORD 0x03\n"
+".emtcode VERTEX_RESULT_POINTSIZE 0x04\n"
+".emtcode VERTEX_RESULT_TEXCOORD 0x05\n"
+".emtcode TEXTARGET_1D 0x01\n"
+".emtcode TEXTARGET_2D 0x02\n"
+".emtcode TEXTARGET_3D 0x03\n"
+".emtcode TEXTARGET_RECT 0x04\n"
+".emtcode TEXTARGET_CUBE 0x05\n"
+".emtcode TEXTARGET_SHADOW1D 0x06\n"
+".emtcode TEXTARGET_SHADOW2D 0x07\n"
+".emtcode TEXTARGET_SHADOWRECT 0x08\n"
+".emtcode FACE_FRONT 0x00\n"
+".emtcode FACE_BACK 0x01\n"
+".emtcode COLOR_PRIMARY 0x00\n"
+".emtcode COLOR_SECONDARY 0x01\n"
+".emtcode COMPONENT_X 0x00\n"
+".emtcode COMPONENT_Y 0x01\n"
+".emtcode COMPONENT_Z 0x02\n"
+".emtcode COMPONENT_W 0x03\n"
+".emtcode COMPONENT_0 0x04\n"
+".emtcode COMPONENT_1 0x05\n"
+".emtcode ARRAY_INDEX_ABSOLUTE 0x00\n"
+".emtcode ARRAY_INDEX_RELATIVE 0x01\n"
+".emtcode MATRIX_MODELVIEW 0x01\n"
+".emtcode MATRIX_PROJECTION 0x02\n"
+".emtcode MATRIX_MVP 0x03\n"
+".emtcode MATRIX_TEXTURE 0x04\n"
+".emtcode MATRIX_PALETTE 0x05\n"
+".emtcode MATRIX_PROGRAM 0x06\n"
+".emtcode MATRIX_MODIFIER_IDENTITY 0x00\n"
+".emtcode MATRIX_MODIFIER_INVERSE 0x01\n"
+".emtcode MATRIX_MODIFIER_TRANSPOSE 0x02\n"
+".emtcode MATRIX_MODIFIER_INVTRANS 0x03\n"
+".emtcode CONSTANT_SCALAR 0x01\n"
+".emtcode CONSTANT_VECTOR 0x02\n"
+".emtcode PROGRAM_PARAM_ENV 0x01\n"
+".emtcode PROGRAM_PARAM_LOCAL 0x02\n"
+".emtcode REGISTER_ATTRIB 0x01\n"
+".emtcode REGISTER_PARAM 0x02\n"
+".emtcode REGISTER_RESULT 0x03\n"
+".emtcode REGISTER_ESTABLISHED_NAME 0x04\n"
+".emtcode PARAM_NULL 0x00\n"
+".emtcode PARAM_ARRAY_ELEMENT 0x01\n"
+".emtcode PARAM_STATE_ELEMENT 0x02\n"
+".emtcode PARAM_PROGRAM_ELEMENT 0x03\n"
+".emtcode PARAM_PROGRAM_ELEMENTS 0x04\n"
+".emtcode PARAM_CONSTANT 0x05\n"
+".emtcode STATE_MATERIAL 0x01\n"
+".emtcode STATE_LIGHT 0x02\n"
+".emtcode STATE_LIGHT_MODEL 0x03\n"
+".emtcode STATE_LIGHT_PROD 0x04\n"
+".emtcode STATE_FOG 0x05\n"
+".emtcode STATE_MATRIX_ROWS 0x06\n"
+".emtcode STATE_TEX_ENV 0x07\n"
+".emtcode STATE_DEPTH 0x08\n"
+".emtcode STATE_TEX_GEN 0x09\n"
+".emtcode STATE_CLIP_PLANE 0x0A\n"
+".emtcode STATE_POINT 0x0B\n"
+".emtcode MATERIAL_AMBIENT 0x01\n"
+".emtcode MATERIAL_DIFFUSE 0x02\n"
+".emtcode MATERIAL_SPECULAR 0x03\n"
+".emtcode MATERIAL_EMISSION 0x04\n"
+".emtcode MATERIAL_SHININESS 0x05\n"
+".emtcode LIGHT_AMBIENT 0x01\n"
+".emtcode LIGHT_DIFFUSE 0x02\n"
+".emtcode LIGHT_SPECULAR 0x03\n"
+".emtcode LIGHT_POSITION 0x04\n"
+".emtcode LIGHT_ATTENUATION 0x05\n"
+".emtcode LIGHT_HALF 0x06\n"
+".emtcode LIGHT_SPOT_DIRECTION 0x07\n"
+".emtcode LIGHT_MODEL_AMBIENT 0x01\n"
+".emtcode LIGHT_MODEL_SCENECOLOR 0x02\n"
+".emtcode LIGHT_PROD_AMBIENT 0x01\n"
+".emtcode LIGHT_PROD_DIFFUSE 0x02\n"
+".emtcode LIGHT_PROD_SPECULAR 0x03\n"
+".emtcode TEX_ENV_COLOR 0x01\n"
+".emtcode TEX_GEN_EYE 0x01\n"
+".emtcode TEX_GEN_OBJECT 0x02\n"
+".emtcode FOG_COLOR 0x01\n"
+".emtcode FOG_PARAMS 0x02\n"
+".emtcode DEPTH_RANGE 0x01\n"
+".emtcode POINT_SIZE 0x01\n"
+".emtcode POINT_ATTENUATION 0x02\n"
+".emtcode ATTRIB 0x01\n"
+".emtcode PARAM 0x02\n"
+".emtcode TEMP 0x03\n"
+".emtcode OUTPUT 0x04\n"
+".emtcode ALIAS 0x05\n"
+".emtcode ADDRESS 0x06\n"
+".errtext UNKNOWN_PROGRAM_SIGNATURE \"1001: '$e_signature$': unknown program signature\"\n"
+".errtext MISSING_END_OR_INVALID_STATEMENT \"1002: '$e_statement$': invalid statement\"\n"
+".errtext CODE_AFTER_END \"1003: '$e_statement$': code after 'END' keyword\"\n"
+".errtext INVALID_PROGRAM_OPTION \"1004: '$e_identifier$': invalid program option\"\n"
+".errtext EXT_SWIZ_COMP_EXPECTED \"1005: extended swizzle component expected but '$e_token$' found\"\n"
+".errtext TEX_TARGET_EXPECTED \"1006: texture target expected but '$e_token$' found\"\n"
+".errtext TEXTURE_EXPECTED \"1007: 'texture' expected but '$e_identifier$' found\"\n"
+".errtext SOURCE_REGISTER_EXPECTED \"1008: source register expected but '$e_token$' found\"\n"
+".errtext DESTINATION_REGISTER_EXPECTED \"1009: destination register expected but '$e_token$' found\"\n"
+".errtext INVALID_ADDRESS_COMPONENT \"1010: '$e_identifier$': invalid address component\"\n"
+".errtext INVALID_ADDRESS_WRITEMASK \"1011: '$e_identifier$': invalid address writemask\"\n"
+".errtext INVALID_COMPONENT \"1012: '$e_charordigit$': invalid component\"\n"
+".errtext INVALID_SUFFIX \"1013: '$e_identifier$': invalid suffix\"\n"
+".errtext INVALID_WRITEMASK \"1014: '$e_identifier$': invalid writemask\"\n"
+".errtext FRAGMENT_EXPECTED \"1015: 'fragment' expected but '$e_identifier$' found\"\n"
+".errtext VERTEX_EXPECTED \"1016: 'vertex' expected but '$e_identifier$' found\"\n"
+".errtext INVALID_FRAGMENT_PROPERTY \"1017: '$e_identifier$': invalid fragment property\"\n"
+".errtext INVALID_VERTEX_PROPERTY \"1018: '$e_identifier$': invalid vertex property\"\n"
+".errtext INVALID_STATE_PROPERTY \"1019: '$e_identifier$': invalid state property\"\n"
+".errtext INVALID_MATERIAL_PROPERTY \"1020: '$e_identifier$': invalid material property\"\n"
+".errtext INVALID_LIGHT_PROPERTY \"1021: '$e_identifier$': invalid light property\"\n"
+".errtext INVALID_SPOT_PROPERTY \"1022: '$e_identifier$': invalid spot property\"\n"
+".errtext INVALID_LIGHTMODEL_PROPERTY \"1023: '$e_identifier$': invalid light model property\"\n"
+".errtext INVALID_LIGHTPROD_PROPERTY \"1024: '$e_identifier$': invalid light product property\"\n"
+".errtext INVALID_TEXENV_PROPERTY \"1025: '$e_identifier$': invalid texture environment property\"\n"
+".errtext INVALID_TEXGEN_PROPERTY \"1026: '$e_identifier$': invalid texture generating property\"\n"
+".errtext INVALID_TEXGEN_COORD \"1027: '$e_identifier$': invalid texture generating coord\"\n"
+".errtext INVALID_FOG_PROPERTY \"1028: '$e_identifier$': invalid fog property\"\n"
+".errtext INVALID_DEPTH_PROPERTY \"1029: '$e_identifier$': invalid depth property\"\n"
+".errtext INVALID_CLIPPLANE_PROPERTY \"1030: '$e_identifier$': invalid clip plane property\"\n"
+".errtext INVALID_POINT_PROPERTY \"1031: '$e_identifier$': invalid point property\"\n"
+".errtext MATRIX_ROW_SELECTOR_OR_MODIFIER_EXPECTED \"1032: matrix row selector or modifier expected but '$e_token$' found\"\n"
+".errtext INVALID_MATRIX_NAME \"1033: '$e_identifier$': invalid matrix name\"\n"
+".errtext INVALID_PROGRAM_PROPERTY \"1034: '$e_identifier$': invalid program property\"\n"
+".errtext RESULT_EXPECTED \"1035: 'result' expected but '$e_token$' found\"\n"
+".errtext INVALID_RESULT_PROPERTY \"1036: '$e_identifier$': invalid result property\"\n"
+".errtext INVALID_FACE_PROPERTY \"1037: '$e_identifier$': invalid face property\"\n"
+".errtext INVALID_COLOR_PROPERTY \"1038: '$e_identifier$': invalid color property\"\n"
+".errtext IDENTIFIER_EXPECTED \"1039: identifier expected but '$e_token$' found\"\n"
+".errtext RESERVED_KEYWORD \"1040: use of reserved keyword as an identifier\"\n"
+".errtext INTEGER_EXPECTED \"1041: integer value expected but '$e_token$' found\"\n"
+".errtext MISSING_SEMICOLON \"1042: ';' expected but '$e_token$' found\"\n"
+".errtext MISSING_COMMA \"1043: ',' expected but '$e_token$' found\"\n"
+".errtext MISSING_LBRACKET \"1044: '[' expected but '$e_token$' found\"\n"
+".errtext MISSING_RBRACKET \"1045: ']' expected but '$e_token$' found\"\n"
+".errtext MISSING_DOT \"1046: '.' expected but '$e_token$' found\"\n"
+".errtext MISSING_EQUAL \"1047: '=' expected but '$e_token$' found\"\n"
+".errtext MISSING_LBRACE \"1048: '{' expected but '$e_token$' found\"\n"
+".errtext MISSING_RBRACE \"1049: '}' expected but '$e_token$' found\"\n"
+".errtext MISSING_DOTDOT \"1050: '..' expected but '$e_token$' found\"\n"
+".errtext MISSING_FRACTION_OR_EXPONENT \"1051: missing fraction part or exponent\"\n"
+".errtext MISSING_DOT_OR_EXPONENT \"1052: missing '.' or exponent\"\n"
+".errtext EXPONENT_VALUE_EXPECTED \"1053: exponent value expected\"\n"
+".errtext INTEGER_OUT_OF_RANGE \"1054: integer value out of range\"\n"
+".errtext OPERATION_NEEDS_DESTINATION_VARIABLE \"1055: operation needs destination variable\"\n"
+".errtext OPERATION_NEEDS_SOURCE_VARIABLE \"1056: operation needs source variable\"\n"
+".errtext ADDRESS_REGISTER_EXPECTED \"1057: address register expected but '$e_token$' found\"\n"
+".errtext ADDRESS_REGISTER_OR_INTEGER_EXPECTED \"1058: address register or integer literal expected but '$e_token$' found\"\n"
+".regbyte vertex_blend 0x00\n"
+".regbyte matrix_palette 0x00\n"
+".regbyte point_parameters 0x00\n"
+".regbyte secondary_color 0x00\n"
+".regbyte fog_coord 0x00\n"
+".regbyte texture_rectangle 0x00\n"
+".regbyte fragment_program_shadow 0x00\n"
+".regbyte draw_buffers 0x00\n"
+".regbyte ARB_precision_hint_fastest 0x00\n"
+".regbyte ARB_precision_hint_nicest 0x00\n"
+".regbyte ARB_fog_exp 0x00\n"
+".regbyte ARB_fog_exp2 0x00\n"
+".regbyte ARB_fog_linear 0x00\n"
+".regbyte ARB_position_invariant 0x00\n"
+".regbyte ARB_fragment_program_shadow 0x00\n"
+".regbyte ARB_draw_buffers 0x00\n"
+".regbyte program_target 0x00\n"
+"program\n"
+" programs .error UNKNOWN_PROGRAM_SIGNATURE .emit REVISION;\n"
+"programs\n"
+" .if (program_target == 0x10) frag_program_1_0 .emit FRAGMENT_PROGRAM .emit 0x01 .emit 0x00 .or\n"
+" .if (program_target == 0x20) vert_program_1_0 .emit VERTEX_PROGRAM .emit 0x01 .emit 0x00;\n"
+"frag_program_1_0\n"
+" '!' .and '!' .and 'A' .and 'R' .and 'B' .and 'f' .and 'p' .and '1' .and '.' .and '0' .and\n"
+" optional_space .and fp_optionSequence .and fp_statementSequence .and\n"
+" \"END\" .error MISSING_END_OR_INVALID_STATEMENT .emit END .and optional_space .and\n"
+" '\\0' .error CODE_AFTER_END;\n"
+"vert_program_1_0\n"
+" '!' .and '!' .and 'A' .and 'R' .and 'B' .and 'v' .and 'p' .and '1' .and '.' .and '0' .and\n"
+" optional_space .and vp_optionSequence .and vp_statementSequence .and\n"
+" \"END\" .error MISSING_END_OR_INVALID_STATEMENT .emit END .and optional_space .and\n"
+" '\\0' .error CODE_AFTER_END;\n"
+"fp_optionSequence\n"
+" .loop fp_option;\n"
+"vp_optionSequence\n"
+" .loop vp_option;\n"
+"fp_option\n"
+" \"OPTION\" .emit OPTION .and space .error IDENTIFIER_EXPECTED .and\n"
+" fp_optionString .error INVALID_PROGRAM_OPTION .and semicolon;\n"
+"vp_option\n"
+" \"OPTION\" .emit OPTION .and space .error IDENTIFIER_EXPECTED .and\n"
+" vp_optionString .error INVALID_PROGRAM_OPTION .and semicolon;\n"
+"fp_optionString\n"
+" .if (ARB_precision_hint_nicest == 0x00) \"ARB_precision_hint_fastest\"\n"
+" .emit ARB_PRECISION_HINT_FASTEST .load ARB_precision_hint_fastest 0x01 .or\n"
+" .if (ARB_precision_hint_fastest == 0x00) \"ARB_precision_hint_nicest\"\n"
+" .emit ARB_PRECISION_HINT_NICEST .load ARB_precision_hint_nicest 0x01 .or\n"
+" fp_ARB_fog_exp .emit ARB_FOG_EXP .load ARB_fog_exp 0x01 .or\n"
+" fp_ARB_fog_exp2 .emit ARB_FOG_EXP2 .load ARB_fog_exp2 0x01 .or\n"
+" fp_ARB_fog_linear .emit ARB_FOG_LINEAR .load ARB_fog_linear 0x01 .or\n"
+" .if (fragment_program_shadow != 0x00) \"ARB_fragment_program_shadow\"\n"
+" .emit ARB_FRAGMENT_PROGRAM_SHADOW .load ARB_fragment_program_shadow 0x01 .or\n"
+" .if (draw_buffers != 0x00) \"ARB_draw_buffers\" .emit ARB_DRAW_BUFFERS\n"
+" .load ARB_draw_buffers 0x01;\n"
+"vp_optionString\n"
+" \"ARB_position_invariant\" .emit ARB_POSITION_INVARIANT .load ARB_position_invariant 0x01;\n"
+"fp_ARB_fog_exp\n"
+" .if (ARB_fog_exp2 == 0x00) .true .and .if (ARB_fog_linear == 0x00) \"ARB_fog_exp\";\n"
+"fp_ARB_fog_exp2\n"
+" .if (ARB_fog_exp == 0x00) .true .and .if (ARB_fog_linear == 0x00) \"ARB_fog_exp2\";\n"
+"fp_ARB_fog_linear\n"
+" .if (ARB_fog_exp == 0x00) .true .and .if (ARB_fog_exp2 == 0x00) \"ARB_fog_linear\";\n"
+"fp_statementSequence\n"
+" .loop fp_statement;\n"
+"vp_statementSequence\n"
+" .loop vp_statement;\n"
+"fp_statement\n"
+" fp_statement_1 .or fp_statement_2;\n"
+"vp_statement\n"
+" vp_statement_1 .or vp_statement_2;\n"
+"fp_statement_1\n"
+" fp_instruction .emit INSTRUCTION .emit $ .and semicolon;\n"
+"fp_statement_2\n"
+" fp_namingStatement .emit DECLARATION .and semicolon;\n"
+"vp_statement_1\n"
+" vp_instruction .emit INSTRUCTION .emit $ .and semicolon;\n"
+"vp_statement_2\n"
+" vp_namingStatement .emit DECLARATION .and semicolon;\n"
+"fp_instruction\n"
+" ALUInstruction .emit OP_ALU_INST .or\n"
+" TexInstruction .emit OP_TEX_INST;\n"
+"vp_instruction\n"
+" ARL_instruction .emit OP_ALU_ARL .or\n"
+" vp_VECTORop_instruction .emit OP_ALU_VECTOR .or\n"
+" vp_SCALARop_instruction .emit OP_ALU_SCALAR .or\n"
+" vp_BINSCop_instruction .emit OP_ALU_BINSC .or\n"
+" vp_BINop_instruction .emit OP_ALU_BIN .or\n"
+" vp_TRIop_instruction .emit OP_ALU_TRI .or\n"
+" vp_SWZ_instruction .emit OP_ALU_SWZ;\n"
+"ALUInstruction\n"
+" fp_VECTORop_instruction .emit OP_ALU_VECTOR .or\n"
+" fp_SCALARop_instruction .emit OP_ALU_SCALAR .or\n"
+" fp_BINSCop_instruction .emit OP_ALU_BINSC .or\n"
+" fp_BINop_instruction .emit OP_ALU_BIN .or\n"
+" fp_TRIop_instruction .emit OP_ALU_TRI .or\n"
+" fp_SWZ_instruction .emit OP_ALU_SWZ;\n"
+"TexInstruction\n"
+" SAMPLE_instruction .emit OP_TEX_SAMPLE .or\n"
+" KIL_instruction .emit OP_TEX_KIL;\n"
+"ARL_instruction\n"
+" \"ARL\" .emit OP_ARL .and space_dst .and maskedAddrReg .and comma .and vp_scalarSrcReg;\n"
+"fp_VECTORop_instruction\n"
+" fp_VECTORop .and space_dst .and fp_maskedDstReg .and comma .and vectorSrcReg;\n"
+"vp_VECTORop_instruction\n"
+" vp_VECTORop .and space_dst .and vp_maskedDstReg .and comma .and swizzleSrcReg;\n"
+"fp_VECTORop\n"
+" \"ABS\" .emit OP_ABS .or \"ABS_SAT\" .emit OP_ABS_SAT .or\n"
+" \"FLR\" .emit OP_FLR .or \"FLR_SAT\" .emit OP_FLR_SAT .or\n"
+" \"FRC\" .emit OP_FRC .or \"FRC_SAT\" .emit OP_FRC_SAT .or\n"
+" \"LIT\" .emit OP_LIT .or \"LIT_SAT\" .emit OP_LIT_SAT .or\n"
+" \"MOV\" .emit OP_MOV .or \"MOV_SAT\" .emit OP_MOV_SAT;\n"
+"vp_VECTORop\n"
+" \"ABS\" .emit OP_ABS .or\n"
+" \"FLR\" .emit OP_FLR .or\n"
+" \"FRC\" .emit OP_FRC .or\n"
+" \"LIT\" .emit OP_LIT .or\n"
+" \"MOV\" .emit OP_MOV;\n"
+"fp_SCALARop_instruction\n"
+" fp_SCALARop .and space_dst .and fp_maskedDstReg .and comma .and fp_scalarSrcReg;\n"
+"vp_SCALARop_instruction\n"
+" vp_SCALARop .and space_dst .and vp_maskedDstReg .and comma .and vp_scalarSrcReg;\n"
+"fp_SCALARop\n"
+" \"COS\" .emit OP_COS .or \"COS_SAT\" .emit OP_COS_SAT .or\n"
+" \"EX2\" .emit OP_EX2 .or \"EX2_SAT\" .emit OP_EX2_SAT .or\n"
+" \"LG2\" .emit OP_LG2 .or \"LG2_SAT\" .emit OP_LG2_SAT .or\n"
+" \"RCP\" .emit OP_RCP .or \"RCP_SAT\" .emit OP_RCP_SAT .or\n"
+" \"RSQ\" .emit OP_RSQ .or \"RSQ_SAT\" .emit OP_RSQ_SAT .or\n"
+" \"SIN\" .emit OP_SIN .or \"SIN_SAT\" .emit OP_SIN_SAT .or\n"
+" \"SCS\" .emit OP_SCS .or \"SCS_SAT\" .emit OP_SCS_SAT;\n"
+"vp_SCALARop\n"
+" \"EX2\" .emit OP_EX2 .or\n"
+" \"EXP\" .emit OP_EXP .or\n"
+" \"LG2\" .emit OP_LG2 .or\n"
+" \"LOG\" .emit OP_LOG .or\n"
+" \"RCP\" .emit OP_RCP .or\n"
+" \"RSQ\" .emit OP_RSQ;\n"
+"fp_BINSCop_instruction\n"
+" fp_BINSCop .and space_dst .and fp_maskedDstReg .and comma .and fp_scalarSrcReg .and comma .and\n"
+" fp_scalarSrcReg;\n"
+"vp_BINSCop_instruction\n"
+" vp_BINSCop .and space_dst .and vp_maskedDstReg .and comma .and vp_scalarSrcReg .and comma .and\n"
+" vp_scalarSrcReg;\n"
+"fp_BINSCop\n"
+" \"POW\" .emit OP_POW .or \"POW_SAT\" .emit OP_POW_SAT;\n"
+"vp_BINSCop\n"
+" \"POW\" .emit OP_POW;\n"
+"fp_BINop_instruction\n"
+" fp_BINop .and space_dst .and fp_maskedDstReg .and comma .and vectorSrcReg .and comma .and\n"
+" vectorSrcReg;\n"
+"vp_BINop_instruction\n"
+" vp_BINop .and space_dst .and vp_maskedDstReg .and comma .and swizzleSrcReg .and comma .and\n"
+" swizzleSrcReg;\n"
+"fp_BINop\n"
+" \"ADD\" .emit OP_ADD .or \"ADD_SAT\" .emit OP_ADD_SAT .or\n"
+" \"DP3\" .emit OP_DP3 .or \"DP3_SAT\" .emit OP_DP3_SAT .or\n"
+" \"DP4\" .emit OP_DP4 .or \"DP4_SAT\" .emit OP_DP4_SAT .or\n"
+" \"DPH\" .emit OP_DPH .or \"DPH_SAT\" .emit OP_DPH_SAT .or\n"
+" \"DST\" .emit OP_DST .or \"DST_SAT\" .emit OP_DST_SAT .or\n"
+" \"MAX\" .emit OP_MAX .or \"MAX_SAT\" .emit OP_MAX_SAT .or\n"
+" \"MIN\" .emit OP_MIN .or \"MIN_SAT\" .emit OP_MIN_SAT .or\n"
+" \"MUL\" .emit OP_MUL .or \"MUL_SAT\" .emit OP_MUL_SAT .or\n"
+" \"SGE\" .emit OP_SGE .or \"SGE_SAT\" .emit OP_SGE_SAT .or\n"
+" \"SLT\" .emit OP_SLT .or \"SLT_SAT\" .emit OP_SLT_SAT .or\n"
+" \"SUB\" .emit OP_SUB .or \"SUB_SAT\" .emit OP_SUB_SAT .or\n"
+" \"XPD\" .emit OP_XPD .or \"XPD_SAT\" .emit OP_XPD_SAT;\n"
+"vp_BINop\n"
+" \"ADD\" .emit OP_ADD .or\n"
+" \"DP3\" .emit OP_DP3 .or\n"
+" \"DP4\" .emit OP_DP4 .or\n"
+" \"DPH\" .emit OP_DPH .or\n"
+" \"DST\" .emit OP_DST .or\n"
+" \"MAX\" .emit OP_MAX .or\n"
+" \"MIN\" .emit OP_MIN .or\n"
+" \"MUL\" .emit OP_MUL .or\n"
+" \"SGE\" .emit OP_SGE .or\n"
+" \"SLT\" .emit OP_SLT .or\n"
+" \"SUB\" .emit OP_SUB .or\n"
+" \"XPD\" .emit OP_XPD;\n"
+"fp_TRIop_instruction\n"
+" fp_TRIop .and space_dst .and fp_maskedDstReg .and comma .and vectorSrcReg .and comma .and\n"
+" vectorSrcReg .and comma .and vectorSrcReg;\n"
+"vp_TRIop_instruction\n"
+" vp_TRIop .and space_dst .and vp_maskedDstReg .and comma .and swizzleSrcReg .and comma .and\n"
+" swizzleSrcReg .and comma .and swizzleSrcReg;\n"
+"fp_TRIop\n"
+" \"CMP\" .emit OP_CMP .or \"CMP_SAT\" .emit OP_CMP_SAT .or\n"
+" \"LRP\" .emit OP_LRP .or \"LRP_SAT\" .emit OP_LRP_SAT .or\n"
+" \"MAD\" .emit OP_MAD .or \"MAD_SAT\" .emit OP_MAD_SAT;\n"
+"vp_TRIop\n"
+" \"MAD\" .emit OP_MAD;\n"
+"fp_SWZ_instruction\n"
+" SWZop .and space_dst .and fp_maskedDstReg .and comma .and fp_srcReg .and comma .and\n"
+" fp_extendedSwizzle .error EXT_SWIZ_COMP_EXPECTED;\n"
+"vp_SWZ_instruction\n"
+" \"SWZ\" .emit OP_SWZ .and space_dst .and vp_maskedDstReg .and comma .and vp_srcReg .and comma .and\n"
+" vp_extendedSwizzle .error EXT_SWIZ_COMP_EXPECTED;\n"
+"SWZop\n"
+" \"SWZ\" .emit OP_SWZ .or \"SWZ_SAT\" .emit OP_SWZ_SAT;\n"
+"SAMPLE_instruction\n"
+" SAMPLEop .and space_dst .and fp_maskedDstReg .and comma .and vectorSrcReg .and comma .and\n"
+" texImageUnit .and comma .and texTarget .error TEX_TARGET_EXPECTED;\n"
+"SAMPLEop\n"
+" \"TEX\" .emit OP_TEX .or \"TEX_SAT\" .emit OP_TEX_SAT .or\n"
+" \"TXB\" .emit OP_TXB .or \"TXB_SAT\" .emit OP_TXB_SAT .or\n"
+" \"TXP\" .emit OP_TXP .or \"TXP_SAT\" .emit OP_TXP_SAT;\n"
+"KIL_instruction\n"
+" \"KIL\" .emit OP_KIL .and space_src .and vectorSrcReg;\n"
+"texImageUnit\n"
+" \"texture\" .error TEXTURE_EXPECTED .and optTexImageUnitNum;\n"
+"texTarget\n"
+" \"1D\" .emit TEXTARGET_1D .or\n"
+" \"2D\" .emit TEXTARGET_2D .or\n"
+" \"3D\" .emit TEXTARGET_3D .or\n"
+" .if (texture_rectangle != 0x00) \"RECT\" .emit TEXTARGET_RECT .or\n"
+" \"CUBE\" .emit TEXTARGET_CUBE .or\n"
+" .if (ARB_fragment_program_shadow != 0x00) shadowTarget;\n"
+"shadowTarget\n"
+" \"SHADOW1D\" .emit TEXTARGET_SHADOW1D .or\n"
+" \"SHADOW2D\" .emit TEXTARGET_SHADOW2D .or\n"
+" .if (texture_rectangle != 0x00) \"SHADOWRECT\" .emit TEXTARGET_SHADOWRECT;\n"
+"optTexImageUnitNum\n"
+" optTexImageUnitNum_1 .or .true .emit 0x00;\n"
+"optTexImageUnitNum_1\n"
+" lbracket_ne .and texImageUnitNum .and rbracket;\n"
+"texImageUnitNum\n"
+" integer;\n"
+"fp_scalarSrcReg\n"
+" optionalSign .and fp_srcReg .and fp_scalarSuffix;\n"
+"vp_scalarSrcReg\n"
+" optionalSign .and vp_srcReg .and vp_scalarSuffix;\n"
+"swizzleSrcReg\n"
+" optionalSign .and vp_srcReg .and swizzleSuffix;\n"
+"vectorSrcReg\n"
+" optionalSign .and fp_srcReg .and optionalSuffix;\n"
+"fp_maskedDstReg\n"
+" fp_dstReg .and fp_optionalMask;\n"
+"vp_maskedDstReg\n"
+" vp_dstReg .and vp_optionalMask;\n"
+"maskedAddrReg\n"
+" addrReg .error ADDRESS_REGISTER_EXPECTED .and addrWriteMask;\n"
+"fp_extendedSwizzle\n"
+" rgbaExtendedSwizzle .or xyzwExtendedSwizzle;\n"
+"vp_extendedSwizzle\n"
+" extSwizComp .and comma .and\n"
+" extSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n"
+" extSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n"
+" extSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n"
+"xyzwExtendedSwizzle\n"
+" xyzwExtSwizComp .and comma .and\n"
+" xyzwExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n"
+" xyzwExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n"
+" xyzwExtSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n"
+"rgbaExtendedSwizzle\n"
+" rgbaExtendedSwizzle_1 .or rgbaExtendedSwizzle_2 .or rgbaExtendedSwizzle_3 .or\n"
+" rgbaExtendedSwizzle_4;\n"
+"rgbaExtendedSwizzle_1\n"
+" rgbaExtSwizComp_digit .and comma .and rgbaExtSwizComp_digit .and comma .and\n"
+" rgbaExtSwizComp_digit .and comma .and rgbaExtSwizComp;\n"
+"rgbaExtendedSwizzle_2\n"
+" rgbaExtSwizComp_digit .and comma .and rgbaExtSwizComp_digit .and comma .and\n"
+" rgbaExtSwizComp_alpha .and comma .and rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n"
+"rgbaExtendedSwizzle_3\n"
+" rgbaExtSwizComp_digit .and comma .and rgbaExtSwizComp_alpha .and comma .and\n"
+" rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n"
+" rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n"
+"rgbaExtendedSwizzle_4\n"
+" rgbaExtSwizComp_alpha .and comma .and \n"
+"rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n"
+" rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n"
+" rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n"
+"xyzwExtSwizComp\n"
+" optionalSign .and xyzwExtSwizSel;\n"
+"rgbaExtSwizComp\n"
+" optionalSign .and rgbaExtSwizSel;\n"
+"rgbaExtSwizComp_digit\n"
+" optionalSign .and rgbaExtSwizSel_digit;\n"
+"rgbaExtSwizComp_alpha\n"
+" optionalSign .and rgbaExtSwizSel_alpha;\n"
+"extSwizComp\n"
+" optionalSign .and extSwizSel;\n"
+"xyzwExtSwizSel\n"
+" \"0\" .emit COMPONENT_0 .or \"1\" .emit COMPONENT_1 .or xyzwComponent_single;\n"
+"rgbaExtSwizSel\n"
+" rgbaExtSwizSel_digit .or rgbaExtSwizSel_alpha;\n"
+"rgbaExtSwizSel_digit\n"
+" \"0\" .emit COMPONENT_0 .or \"1\" .emit COMPONENT_1;\n"
+"rgbaExtSwizSel_alpha\n"
+" rgbaComponent_single;\n"
+"extSwizSel\n"
+" \"0\" .emit COMPONENT_0 .or \"1\" .emit COMPONENT_1 .or vp_component_single;\n"
+"fp_srcReg\n"
+" fp_srcReg_1 .error SOURCE_REGISTER_EXPECTED;\n"
+"vp_srcReg\n"
+" vp_srcReg_1 .error SOURCE_REGISTER_EXPECTED;\n"
+"fp_srcReg_1\n"
+" fragmentAttribReg .emit REGISTER_ATTRIB .or\n"
+" fp_progParamReg .emit REGISTER_PARAM .or\n"
+" fp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n"
+"vp_srcReg_1\n"
+" vertexAttribReg .emit REGISTER_ATTRIB .or\n"
+" vp_progParamReg .emit REGISTER_PARAM .or\n"
+" vp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n"
+"fp_dstReg\n"
+" fp_dstReg_1 .error DESTINATION_REGISTER_EXPECTED;\n"
+"vp_dstReg\n"
+" vp_dstReg_1 .error DESTINATION_REGISTER_EXPECTED;\n"
+"fp_dstReg_1\n"
+" fragmentResultReg .emit REGISTER_RESULT .or\n"
+" fp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n"
+"vp_dstReg_1\n"
+" vertexResultReg .emit REGISTER_RESULT .or\n"
+" vp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n"
+"fragmentAttribReg\n"
+" fragAttribBinding;\n"
+"vertexAttribReg\n"
+" vtxAttribBinding;\n"
+"fp_temporaryReg\n"
+" fp_establishedName_no_error_on_identifier;\n"
+"vp_temporaryReg\n"
+" vp_establishedName_no_error_on_identifier;\n"
+"fp_progParamReg\n"
+" fp_paramSingleItemUse .or fp_progParamReg_1 .or fp_progParamSingle;\n"
+"vp_progParamReg\n"
+" vp_paramSingleItemUse .or vp_progParamReg_1 .or vp_progParamSingle;\n"
+"fp_progParamReg_1\n"
+" fp_progParamArray .emit PARAM_ARRAY_ELEMENT .and lbracket_ne .and progParamArrayAbs .and\n"
+" rbracket;\n"
+"vp_progParamReg_1\n"
+" vp_progParamArray .emit PARAM_ARRAY_ELEMENT .and lbracket_ne .and progParamArrayMem .and\n"
+" rbracket;\n"
+"fp_progParamSingle\n"
+" .false;\n"
+"vp_progParamSingle\n"
+" .false;\n"
+"fp_progParamArray\n"
+" fp_establishedName_no_error_on_identifier;\n"
+"vp_progParamArray\n"
+" vp_establishedName_no_error_on_identifier;\n"
+"progParamArrayMem\n"
+" progParamArrayAbs .or progParamArrayRel;\n"
+"progParamArrayAbs\n"
+" integer_ne .emit ARRAY_INDEX_ABSOLUTE;\n"
+"progParamArrayRel\n"
+" addrReg .error ADDRESS_REGISTER_OR_INTEGER_EXPECTED .emit ARRAY_INDEX_RELATIVE .and\n"
+" addrComponent .and addrRegRelOffset;\n"
+"addrRegRelOffset\n"
+" addrRegRelOffset_1 .or addrRegRelOffset_2 .or .true .emit 0x00;\n"
+"addrRegRelOffset_1\n"
+" plus_ne .and addrRegPosOffset;\n"
+"addrRegRelOffset_2\n"
+" minus_ne .and addrRegNegOffset;\n"
+"addrRegPosOffset\n"
+" integer_0_63;\n"
+"addrRegNegOffset\n"
+" integer_0_64;\n"
+"fragmentResultReg\n"
+" fp_resultBinding;\n"
+"vertexResultReg\n"
+" vp_resultBinding;\n"
+"addrReg\n"
+" vp_establishedName_no_error_on_identifier;\n"
+"addrComponent\n"
+" dot .and \"x\" .error INVALID_ADDRESS_COMPONENT .emit COMPONENT_X .emit COMPONENT_X\n"
+" .emit COMPONENT_X .emit COMPONENT_X;\n"
+"addrWriteMask\n"
+" dot .and \"x\" .error INVALID_ADDRESS_WRITEMASK .emit 0x08;\n"
+"fp_scalarSuffix\n"
+" dot .and fp_component_single .error INVALID_COMPONENT;\n"
+"vp_scalarSuffix\n"
+" dot .and vp_component_single .error INVALID_COMPONENT;\n"
+"swizzleSuffix\n"
+" swizzleSuffix_1 .or\n"
+" .true .emit COMPONENT_X .emit COMPONENT_Y .emit COMPONENT_Z .emit COMPONENT_W;\n"
+"swizzleSuffix_1\n"
+" dot_ne .and swizzleSuffix_2 .error INVALID_SUFFIX;\n"
+"swizzleSuffix_2\n"
+" swizzleSuffix_3 .or swizzleSuffix_4;\n"
+"swizzleSuffix_3\n"
+" vp_component_multi .and vp_component_multi .and vp_component_multi .error INVALID_COMPONENT .and\n"
+" vp_component_multi .error INVALID_COMPONENT;\n"
+"swizzleSuffix_4\n"
+" \"x\" .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .or\n"
+" \"y\" .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .or\n"
+" \"z\" .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .or\n"
+" \"w\" .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W;\n"
+"optionalSuffix\n"
+" optionalSuffix_1 .or\n"
+" .true .emit COMPONENT_X .emit COMPONENT_Y .emit COMPONENT_Z .emit COMPONENT_W;\n"
+"optionalSuffix_1\n"
+" dot_ne .and optionalSuffix_2 .error INVALID_SUFFIX;\n"
+"optionalSuffix_2\n"
+" optionalSuffix_3 .or optionalSuffix_4 .or optionalSuffix_5;\n"
+"optionalSuffix_3\n"
+" xyzwComponent_multi .and xyzwComponent_multi .and\n"
+" xyzwComponent_multi .error INVALID_COMPONENT .and xyzwComponent_multi .error INVALID_COMPONENT;\n"
+"optionalSuffix_4\n"
+" rgbaComponent_multi .and rgbaComponent_multi .and\n"
+" rgbaComponent_multi .error INVALID_COMPONENT .and rgbaComponent_multi .error INVALID_COMPONENT;\n"
+"optionalSuffix_5\n"
+" \"x\" .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .or\n"
+" \"y\" .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .or\n"
+" \"z\" .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .or\n"
+" \"w\" .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .or\n"
+" \"r\" .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .or\n"
+" \"g\" .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .or\n"
+" \"b\" .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .or\n"
+" \"a\" .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W;\n"
+"fp_component_single\n"
+" xyzwComponent_single .or rgbaComponent_single;\n"
+"vp_component_multi\n"
+" 'x' .emit COMPONENT_X .or 'y' .emit COMPONENT_Y .or 'z' .emit COMPONENT_Z .or\n"
+" 'w' .emit COMPONENT_W;\n"
+"vp_component_single\n"
+" \"x\" .emit COMPONENT_X .or \"y\" .emit COMPONENT_Y .or \"z\" .emit COMPONENT_Z .or\n"
+" \"w\" .emit COMPONENT_W;\n"
+"xyzwComponent_multi\n"
+" 'x' .emit COMPONENT_X .or 'y' .emit COMPONENT_Y .or 'z' .emit COMPONENT_Z .or\n"
+" 'w' .emit COMPONENT_W;\n"
+"xyzwComponent_single\n"
+" \"x\" .emit COMPONENT_X .or \"y\" .emit COMPONENT_Y .or \"z\" .emit COMPONENT_Z .or\n"
+" \"w\" .emit COMPONENT_W;\n"
+"rgbaComponent_multi\n"
+" 'r' .emit COMPONENT_X .or 'g' .emit COMPONENT_Y .or 'b' .emit COMPONENT_Z .or\n"
+" 'a' .emit COMPONENT_W;\n"
+"rgbaComponent_single\n"
+" \"r\" .emit COMPONENT_X .or \"g\" .emit COMPONENT_Y .or \"b\" .emit COMPONENT_Z .or\n"
+" \"a\" .emit COMPONENT_W;\n"
+"fp_optionalMask\n"
+" rgbaMask .or xyzwMask .or .true .emit 0x0F;\n"
+"vp_optionalMask\n"
+" xyzwMask .or .true .emit 0x0F;\n"
+"xyzwMask\n"
+" dot_ne .and xyzwMask_1 .error INVALID_WRITEMASK;\n"
+"xyzwMask_1\n"
+" \"xyzw\" .emit 0x0F .or \"xyz\" .emit 0x0E .or \"xyw\" .emit 0x0D .or \"xy\" .emit 0x0C .or\n"
+" \"xzw\" .emit 0x0B .or \"xz\" .emit 0x0A .or \"xw\" .emit 0x09 .or \"x\" .emit 0x08 .or\n"
+" \"yzw\" .emit 0x07 .or \"yz\" .emit 0x06 .or \"yw\" .emit 0x05 .or \"y\" .emit 0x04 .or\n"
+" \"zw\" .emit 0x03 .or \"z\" .emit 0x02 .or \"w\" .emit 0x01;\n"
+"rgbaMask\n"
+" dot_ne .and rgbaMask_1;\n"
+"rgbaMask_1\n"
+" \"rgba\" .emit 0x0F .or \"rgb\" .emit 0x0E .or \"rga\" .emit 0x0D .or \"rg\" .emit 0x0C .or\n"
+" \"rba\" .emit 0x0B .or \"rb\" .emit 0x0A .or \"ra\" .emit 0x09 .or \"r\" .emit 0x08 .or\n"
+" \"gba\" .emit 0x07 .or \"gb\" .emit 0x06 .or \"ga\" .emit 0x05 .or \"g\" .emit 0x04 .or\n"
+" \"ba\" .emit 0x03 .or \"b\" .emit 0x02 .or \"a\" .emit 0x01;\n"
+"fp_namingStatement\n"
+" fp_ATTRIB_statement .emit ATTRIB .or\n"
+" fp_PARAM_statement .emit PARAM .or\n"
+" fp_TEMP_statement .emit TEMP .or\n"
+" fp_OUTPUT_statement .emit OUTPUT .or\n"
+" fp_ALIAS_statement .emit ALIAS;\n"
+"vp_namingStatement\n"
+" vp_ATTRIB_statement .emit ATTRIB .or\n"
+" vp_PARAM_statement .emit PARAM .or\n"
+" vp_TEMP_statement .emit TEMP .or\n"
+" ADDRESS_statement .emit ADDRESS .or\n"
+" vp_OUTPUT_statement .emit OUTPUT .or\n"
+" vp_ALIAS_statement .emit ALIAS;\n"
+"fp_ATTRIB_statement\n"
+" \"ATTRIB\" .and space .and fp_establishName .and equal .and\n"
+" fragAttribBinding .error FRAGMENT_EXPECTED;\n"
+"vp_ATTRIB_statement\n"
+" \"ATTRIB\" .and space .and vp_establishName .and equal .and\n"
+" vtxAttribBinding .error VERTEX_EXPECTED;\n"
+"fragAttribBinding\n"
+" \"fragment\" .and dot .and fragAttribItem .error INVALID_FRAGMENT_PROPERTY;\n"
+"vtxAttribBinding\n"
+" \"vertex\" .and dot .and vtxAttribItem .error INVALID_VERTEX_PROPERTY;\n"
+"fragAttribItem\n"
+" fragAttribItem_1 .emit FRAGMENT_ATTRIB_COLOR .or\n"
+" fragAttribItem_2 .emit FRAGMENT_ATTRIB_TEXCOORD .or\n"
+" .if (fog_coord != 0x00) \"fogcoord\" .emit FRAGMENT_ATTRIB_FOGCOORD .or\n"
+" \"position\" .emit FRAGMENT_ATTRIB_POSITION;\n"
+"fragAttribItem_1\n"
+" \"color\" .and optColorType;\n"
+"fragAttribItem_2\n"
+" \"texcoord\" .and optTexCoordNum;\n"
+"vtxAttribItem\n"
+" \"position\" .emit VERTEX_ATTRIB_POSITION .or\n"
+" .if (vertex_blend != 0x00) vtxAttribItem_1 .emit VERTEX_ATTRIB_WEIGHT .or\n"
+" \"normal\" .emit VERTEX_ATTRIB_NORMAL .or\n"
+" vtxAttribItem_2 .emit VERTEX_ATTRIB_COLOR .or\n"
+" \"fogcoord\" .emit VERTEX_ATTRIB_FOGCOORD .or\n"
+" vtxAttribItem_3 .emit VERTEX_ATTRIB_TEXCOORD .or\n"
+" .if (matrix_palette != 0x00) vtxAttribItem_4 .emit VERTEX_ATTRIB_MATRIXINDEX .or\n"
+" vtxAttribItem_5 .emit VERTEX_ATTRIB_GENERIC;\n"
+"vtxAttribItem_1\n"
+" \"weight\" .and vtxOptWeightNum;\n"
+"vtxAttribItem_2\n"
+" \"color\" .and optColorType;\n"
+"vtxAttribItem_3\n"
+" \"texcoord\" .and optTexCoordNum;\n"
+"vtxAttribItem_4\n"
+" \"matrixindex\" .and lbracket .and vtxWeightNum .and rbracket;\n"
+"vtxAttribItem_5\n"
+" \"attrib\" .and lbracket .and vtxAttribNum .and rbracket;\n"
+"vtxAttribNum\n"
+" integer;\n"
+"vtxOptWeightNum\n"
+" vtxOptWeightNum_1 .or .true .emit 0x00;\n"
+"vtxOptWeightNum_1\n"
+" lbracket_ne .and vtxWeightNum .and rbracket;\n"
+"vtxWeightNum\n"
+" integer;\n"
+"fp_PARAM_statement\n"
+" fp_PARAM_multipleStmt .or fp_PARAM_singleStmt;\n"
+"vp_PARAM_statement\n"
+" vp_PARAM_multipleStmt .or vp_PARAM_singleStmt;\n"
+"fp_PARAM_singleStmt\n"
+" \"PARAM\" .and space .and fp_establishName .and .true .emit 0x00 .and fp_paramSingleInit .and\n"
+" .true .emit PARAM_NULL;\n"
+"vp_PARAM_singleStmt\n"
+" \"PARAM\" .and space .and vp_establishName .and .true .emit 0x00 .and vp_paramSingleInit .and\n"
+" .true .emit PARAM_NULL;\n"
+"fp_PARAM_multipleStmt\n"
+" \"PARAM\" .and space .and fp_establishName .and lbracket_ne .and optArraySize .and rbracket .and\n"
+" fp_paramMultipleInit .and .true .emit PARAM_NULL;\n"
+"vp_PARAM_multipleStmt\n"
+" \"PARAM\" .and space .and vp_establishName .and lbracket_ne .and optArraySize .and rbracket .and\n"
+" vp_paramMultipleInit .and .true .emit PARAM_NULL;\n"
+"optArraySize\n"
+" optional_integer;\n"
+"fp_paramSingleInit\n"
+" equal .and fp_paramSingleItemDecl;\n"
+"vp_paramSingleInit\n"
+" equal .and vp_paramSingleItemDecl;\n"
+"fp_paramMultipleInit\n"
+" equal .and lbrace .and fp_paramMultInitList .and rbrace;\n"
+"vp_paramMultipleInit\n"
+" equal .and lbrace .and vp_paramMultInitList .and rbrace;\n"
+"fp_paramMultInitList\n"
+" fp_paramMultInitList_1 .or fp_paramMultipleItem;\n"
+"vp_paramMultInitList\n"
+" vp_paramMultInitList_1 .or vp_paramMultipleItem;\n"
+"fp_paramMultInitList_1\n"
+" fp_paramMultipleItem .and comma_ne .and fp_paramMultInitList;\n"
+"vp_paramMultInitList_1\n"
+" vp_paramMultipleItem .and comma_ne .and vp_paramMultInitList;\n"
+"fp_paramSingleItemDecl\n"
+" fp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n"
+" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n"
+" paramConstDecl .emit PARAM_CONSTANT;\n"
+"vp_paramSingleItemDecl\n"
+" vp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n"
+" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n"
+" paramConstDecl .emit PARAM_CONSTANT;\n"
+"fp_paramSingleItemUse\n"
+" fp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n"
+" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n"
+" paramConstUse .emit PARAM_CONSTANT;\n"
+"vp_paramSingleItemUse\n"
+" vp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n"
+" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n"
+" paramConstUse .emit PARAM_CONSTANT;\n"
+"fp_paramMultipleItem\n"
+" fp_stateMultipleItem .emit PARAM_STATE_ELEMENT .or\n"
+" programMultipleItem .emit PARAM_PROGRAM_ELEMENT .or\n"
+" paramConstDecl .emit PARAM_CONSTANT;\n"
+"vp_paramMultipleItem\n"
+" vp_stateMultipleItem .emit PARAM_STATE_ELEMENT .or\n"
+" programMultipleItem .emit PARAM_PROGRAM_ELEMENT .or\n"
+" paramConstDecl .emit PARAM_CONSTANT;\n"
+"fp_stateMultipleItem\n"
+" stateMultipleItem_1 .or fp_stateSingleItem;\n"
+"vp_stateMultipleItem\n"
+" stateMultipleItem_1 .or vp_stateSingleItem;\n"
+"stateMultipleItem_1\n"
+" \"state\" .and dot .and stateMatrixRows .emit STATE_MATRIX_ROWS;\n"
+"fp_stateSingleItem\n"
+" \"state\" .and dot .and fp_stateSingleItem_1 .error INVALID_STATE_PROPERTY;\n"
+"vp_stateSingleItem\n"
+" \"state\" .and dot .and vp_stateSingleItem_1 .error INVALID_STATE_PROPERTY;\n"
+"fp_stateSingleItem_1\n"
+" stateSingleItem_1 .or stateSingleItem_2 .or stateSingleItem_3 .or stateSingleItem_4 .or\n"
+" stateSingleItem_5 .or stateSingleItem_7 .or stateSingleItem_8 .or stateSingleItem_11;\n"
+"vp_stateSingleItem_1\n"
+" stateSingleItem_1 .or stateSingleItem_2 .or stateSingleItem_3 .or stateSingleItem_4 .or\n"
+" stateSingleItem_6 .or stateSingleItem_7 .or stateSingleItem_9 .or stateSingleItem_10 .or\n"
+" stateSingleItem_11;\n"
+"stateSingleItem_1\n"
+" stateMaterialItem .emit STATE_MATERIAL;\n"
+"stateSingleItem_2\n"
+" stateLightItem .emit STATE_LIGHT;\n"
+"stateSingleItem_3\n"
+" stateLightModelItem .emit STATE_LIGHT_MODEL;\n"
+"stateSingleItem_4\n"
+" stateLightProdItem .emit STATE_LIGHT_PROD;\n"
+"stateSingleItem_5\n"
+" stateTexEnvItem .emit STATE_TEX_ENV;\n"
+"stateSingleItem_6\n"
+" stateTexGenItem .emit STATE_TEX_GEN;\n"
+"stateSingleItem_7\n"
+" stateFogItem .emit STATE_FOG;\n"
+"stateSingleItem_8\n"
+" stateDepthItem .emit STATE_DEPTH;\n"
+"stateSingleItem_9\n"
+" stateClipPlaneItem .emit STATE_CLIP_PLANE;\n"
+"stateSingleItem_10\n"
+" statePointItem .emit STATE_POINT;\n"
+"stateSingleItem_11\n"
+" stateMatrixRow .emit STATE_MATRIX_ROWS;\n"
+"stateMaterialItem\n"
+" \"material\" .and optFaceType .and dot .and stateMatProperty .error INVALID_MATERIAL_PROPERTY;\n"
+"stateMatProperty\n"
+" \"ambient\" .emit MATERIAL_AMBIENT .or\n"
+" \"diffuse\" .emit MATERIAL_DIFFUSE .or\n"
+" \"specular\" .emit MATERIAL_SPECULAR .or\n"
+" \"emission\" .emit MATERIAL_EMISSION .or\n"
+" \"shininess\" .emit MATERIAL_SHININESS;\n"
+"stateLightItem\n"
+" \"light\" .and lbracket .and stateLightNumber .and rbracket .and dot .and\n"
+" stateLightProperty .error INVALID_LIGHT_PROPERTY;\n"
+"stateLightProperty\n"
+" \"ambient\" .emit LIGHT_AMBIENT .or\n"
+" \"diffuse\" .emit LIGHT_DIFFUSE .or\n"
+" \"specular\" .emit LIGHT_SPECULAR .or\n"
+" \"position\" .emit LIGHT_POSITION .or\n"
+" \"attenuation\" .emit LIGHT_ATTENUATION .or\n"
+" stateLightProperty_1 .emit LIGHT_SPOT_DIRECTION .or\n"
+" \"half\" .emit LIGHT_HALF;\n"
+"stateLightProperty_1\n"
+" \"spot\" .and dot .and stateSpotProperty .error INVALID_SPOT_PROPERTY;\n"
+"stateSpotProperty\n"
+" \"direction\";\n"
+"stateLightModelItem\n"
+" \"lightmodel\" .and stateLModProperty .error INVALID_LIGHTMODEL_PROPERTY;\n"
+"stateLModProperty\n"
+" stateLModProperty_1 .or stateLModProperty_2;\n"
+"stateLModProperty_1\n"
+" dot .and \"ambient\" .emit LIGHT_MODEL_AMBIENT;\n"
+"stateLModProperty_2\n"
+" stateLModProperty_3 .emit LIGHT_MODEL_SCENECOLOR;\n"
+"stateLModProperty_3\n"
+" optFaceType .and dot .and \"scenecolor\";\n"
+"stateLightProdItem\n"
+" \"lightprod\" .and lbracket .and stateLightNumber .and rbracket .and optFaceType .and dot .and\n"
+" stateLProdProperty .error INVALID_LIGHTPROD_PROPERTY;\n"
+"stateLProdProperty\n"
+" \"ambient\" .emit LIGHT_PROD_AMBIENT .or\n"
+" \"diffuse\" .emit LIGHT_PROD_DIFFUSE .or\n"
+" \"specular\" .emit LIGHT_PROD_SPECULAR;\n"
+"stateLightNumber\n"
+" integer;\n"
+"stateTexEnvItem\n"
+" \"texenv\" .and optLegacyTexUnitNum .and dot .and\n"
+" stateTexEnvProperty .error INVALID_TEXENV_PROPERTY;\n"
+"stateTexEnvProperty\n"
+" \"color\" .emit TEX_ENV_COLOR;\n"
+"optLegacyTexUnitNum\n"
+" lbracket_ne .and legacyTexUnitNum .and rbracket;\n"
+"legacyTexUnitNum\n"
+" integer;\n"
+"stateTexGenItem\n"
+" \"texgen\" .and optTexCoordNum .and dot .and stateTexGenType .error INVALID_TEXGEN_PROPERTY .and\n"
+" dot .and stateTexGenCoord .error INVALID_TEXGEN_COORD;\n"
+"stateTexGenType\n"
+" \"eye\" .emit TEX_GEN_EYE .or\n"
+" \"object\" .emit TEX_GEN_OBJECT;\n"
+"stateTexGenCoord\n"
+" \"s\" .emit COMPONENT_X .or\n"
+" \"t\" .emit COMPONENT_Y .or\n"
+" \"r\" .emit COMPONENT_Z .or\n"
+" \"q\" .emit COMPONENT_W;\n"
+"stateFogItem\n"
+" \"fog\" .and dot .and stateFogProperty .error INVALID_FOG_PROPERTY;\n"
+"stateFogProperty\n"
+" \"color\" .emit FOG_COLOR .or\n"
+" \"params\" .emit FOG_PARAMS;\n"
+"stateDepthItem\n"
+" \"depth\" .and dot .and stateDepthProperty .error INVALID_DEPTH_PROPERTY;\n"
+"stateDepthProperty\n"
+" \"range\" .emit DEPTH_RANGE;\n"
+"stateClipPlaneItem\n"
+" \"clip\" .and lbracket .and stateClipPlaneNum .and rbracket .and dot .and\n"
+" \"plane\" .error INVALID_CLIPPLANE_PROPERTY;\n"
+"stateClipPlaneNum\n"
+" integer;\n"
+"statePointItem\n"
+" \"point\" .and dot .and statePointProperty .error INVALID_POINT_PROPERTY;\n"
+"statePointProperty\n"
+" \"size\" .emit POINT_SIZE .or\n"
+" .if (point_parameters != 0x00) \"attenuation\" .emit POINT_ATTENUATION;\n"
+"stateMatrixRow\n"
+" stateMatrixItem .and dot .and \"row\" .error MATRIX_ROW_SELECTOR_OR_MODIFIER_EXPECTED .and\n"
+" lbracket .and stateMatrixRowNum .and rbracket .emit 0x0;\n"
+"stateMatrixRows\n"
+" stateMatrixItem .and optMatrixRows;\n"
+"optMatrixRows\n"
+" optMatrixRows_1 .or .true .emit 0x0 .emit '3' .emit 0x0 .emit $;\n"
+"optMatrixRows_1\n"
+" dot_ne .and \"row\" .error MATRIX_ROW_SELECTOR_OR_MODIFIER_EXPECTED .and lbracket .and\n"
+" stateMatrixRowNum .and dotdot .and stateMatrixRowNum .and rbracket;\n"
+"stateMatrixItem\n"
+" \"matrix\" .and dot .and stateMatrixName .error INVALID_MATRIX_NAME .and stateOptMatModifier;\n"
+"stateOptMatModifier\n"
+" stateOptMatModifier_1 .or .true .emit MATRIX_MODIFIER_IDENTITY;\n"
+"stateOptMatModifier_1\n"
+" dot_ne .and stateMatModifier;\n"
+"stateMatModifier\n"
+" \"inverse\" .emit MATRIX_MODIFIER_INVERSE .or\n"
+" \"transpose\" .emit MATRIX_MODIFIER_TRANSPOSE .or\n"
+" \"invtrans\" .emit MATRIX_MODIFIER_INVTRANS;\n"
+"stateMatrixRowNum\n"
+" integer_0_3;\n"
+"stateMatrixName\n"
+" stateMatrixName_1_1 .emit MATRIX_MODELVIEW .or\n"
+" \"projection\" .emit MATRIX_PROJECTION .or\n"
+" \"mvp\" .emit MATRIX_MVP .or\n"
+" stateMatrixName_1_2 .emit MATRIX_TEXTURE .or\n"
+" .if (matrix_palette != 0x00) stateMatrixName_1_3 .emit MATRIX_PALETTE .or\n"
+" stateMatrixName_1_4 .emit MATRIX_PROGRAM;\n"
+"stateMatrixName_1_1\n"
+" \"modelview\" .and stateOptModMatNum;\n"
+"stateMatrixName_1_2\n"
+" \"texture\" .and optTexCoordNum;\n"
+"stateMatrixName_1_3\n"
+" \"palette\" .and lbracket .and statePaletteMatNum .and rbracket;\n"
+"stateMatrixName_1_4\n"
+" \"program\" .and lbracket .and stateProgramMatNum .and rbracket;\n"
+"stateOptModMatNum\n"
+" .if (vertex_blend != 0x00) stateOptModMatNum_1 .or\n"
+" .true .emit 0x00;\n"
+"stateOptModMatNum_1\n"
+" lbracket_ne .and stateModMatNum .and rbracket;\n"
+"stateModMatNum\n"
+" integer;\n"
+"optTexCoordNum\n"
+" optTexCoordNum_1 .or .true .emit 0x00;\n"
+"optTexCoordNum_1\n"
+" lbracket_ne .and texCoordNum .and rbracket;\n"
+"texCoordNum\n"
+" integer;\n"
+"statePaletteMatNum\n"
+" integer;\n"
+"stateProgramMatNum\n"
+" integer;\n"
+"programSingleItem\n"
+" \"program\" .and dot .and programSingleItem_1 .error INVALID_PROGRAM_PROPERTY;\n"
+"programSingleItem_1\n"
+" progEnvParam .or progLocalParam;\n"
+"programMultipleItem\n"
+" \"program\" .and dot .and programMultipleItem_1 .error INVALID_PROGRAM_PROPERTY;\n"
+"programMultipleItem_1\n"
+" progEnvParams .or progLocalParams;\n"
+"progEnvParams\n"
+" \"env\" .emit PROGRAM_PARAM_ENV .and lbracket .and progEnvParamNums .and rbracket;\n"
+"progEnvParamNums\n"
+" progEnvParamNums_1 .or progEnvParamNums_2;\n"
+"progEnvParamNums_1\n"
+" progEnvParamNum .and dotdot_ne .and progEnvParamNum;\n"
+"progEnvParamNums_2\n"
+" progEnvParamNum .and .true .emit 0x00;\n"
+"progEnvParam\n"
+" \"env\" .emit PROGRAM_PARAM_ENV .and lbracket .and progEnvParamNum .and rbracket .emit 0x00;\n"
+"progLocalParams\n"
+" \"local\" .emit PROGRAM_PARAM_LOCAL .and lbracket .and progLocalParamNums .and rbracket;\n"
+"progLocalParamNums\n"
+" progLocalParamNums_1 .or progLocalParamNums_2;\n"
+"progLocalParamNums_1\n"
+" progLocalParamNum .and dotdot_ne .and progLocalParamNum;\n"
+"progLocalParamNums_2\n"
+" progLocalParamNum .and .true .emit 0x00;\n"
+"progLocalParam\n"
+" \"local\" .emit PROGRAM_PARAM_LOCAL .and lbracket .and progLocalParamNum .and rbracket .emit 0x00;\n"
+"progEnvParamNum\n"
+" integer;\n"
+"progLocalParamNum\n"
+" integer;\n"
+"paramConstDecl\n"
+" paramConstScalarDecl .emit CONSTANT_SCALAR .or paramConstVector .emit CONSTANT_VECTOR;\n"
+"paramConstUse\n"
+" paramConstScalarUse .emit CONSTANT_SCALAR .or paramConstVector .emit CONSTANT_VECTOR;\n"
+"paramConstScalarDecl\n"
+" signedFloatConstant;\n"
+"paramConstScalarUse\n"
+" floatConstant;\n"
+"paramConstVector\n"
+" paramConstVector_4 .emit 0x04 .or paramConstVector_3 .emit 0x03 .or\n"
+" paramConstVector_2 .emit 0x02 .or paramConstVector_1 .emit 0x01;\n"
+"paramConstVector_1\n"
+" lbrace_ne .and signedFloatConstant .and rbrace;\n"
+"paramConstVector_2\n"
+" lbrace_ne .and signedFloatConstant .and comma_ne .and signedFloatConstant .and rbrace;\n"
+"paramConstVector_3\n"
+" lbrace_ne .and signedFloatConstant .and comma_ne .and signedFloatConstant .and comma_ne .and\n"
+" signedFloatConstant .and rbrace;\n"
+"paramConstVector_4\n"
+" lbrace_ne .and signedFloatConstant .and comma_ne .and signedFloatConstant .and comma_ne .and\n"
+" signedFloatConstant .and comma_ne .and signedFloatConstant .and rbrace;\n"
+"signedFloatConstant\n"
+" optionalSign .and floatConstant;\n"
+"floatConstant\n"
+" float;\n"
+"optionalSign\n"
+" optional_sign_ne;\n"
+"fp_TEMP_statement\n"
+" \"TEMP\" .and space .and fp_varNameList .and .true .emit 0x00;\n"
+"vp_TEMP_statement\n"
+" \"TEMP\" .and space .and vp_varNameList .and .true .emit 0x00;\n"
+"ADDRESS_statement\n"
+" \"ADDRESS\" .and space .and vp_varNameList .and .true .emit 0x00;\n"
+"fp_varNameList\n"
+" fp_varNameList_1 .or fp_establishName;\n"
+"vp_varNameList\n"
+" vp_varNameList_1 .or vp_establishName;\n"
+"fp_varNameList_1\n"
+" fp_establishName .and comma_ne .and fp_varNameList;\n"
+"vp_varNameList_1\n"
+" vp_establishName .and comma_ne .and vp_varNameList;\n"
+"fp_OUTPUT_statement\n"
+" \"OUTPUT\" .and space .and fp_establishName .and equal .and\n"
+" fp_resultBinding .error RESULT_EXPECTED;\n"
+"vp_OUTPUT_statement\n"
+" \"OUTPUT\" .and space .and vp_establishName .and equal .and\n"
+" vp_resultBinding .error RESULT_EXPECTED;\n"
+"fp_resultBinding\n"
+" \"result\" .and dot .and fp_resultBinding_1 .error INVALID_RESULT_PROPERTY;\n"
+"vp_resultBinding\n"
+" \"result\" .and dot .and vp_resultBinding_1 .error INVALID_RESULT_PROPERTY;\n"
+"fp_resultBinding_1\n"
+" fp_resultBinding_2 .emit FRAGMENT_RESULT_COLOR .or\n"
+" \"depth\" .emit FRAGMENT_RESULT_DEPTH;\n"
+"fp_resultBinding_2\n"
+" \"color\" .and optOutputColorNum;\n"
+"vp_resultBinding_1\n"
+" .if (ARB_position_invariant == 0x00) \"position\" .emit VERTEX_RESULT_POSITION .or\n"
+" resultColBinding .emit VERTEX_RESULT_COLOR .or\n"
+" \"fogcoord\" .emit VERTEX_RESULT_FOGCOORD .or\n"
+" \"pointsize\" .emit VERTEX_RESULT_POINTSIZE .or\n"
+" vp_resultBinding_2 .emit VERTEX_RESULT_TEXCOORD;\n"
+"vp_resultBinding_2\n"
+" \"texcoord\" .and optTexCoordNum;\n"
+"optOutputColorNum\n"
+" .if (ARB_draw_buffers != 0x00) optOutputColorNum_1 .or .true .emit 0x00;\n"
+"optOutputColorNum_1\n"
+" lbracket_ne .and outputColorNum .and rbracket;\n"
+"outputColorNum\n"
+" integer;\n"
+"resultColBinding\n"
+" \"color\" .and optFaceType .and optColorType;\n"
+"optFaceType\n"
+" FaceType .or .true .emit FACE_FRONT;\n"
+"FaceType\n"
+" dot_ne .and FaceProperty;\n"
+"FaceProperty\n"
+" \"front\" .emit FACE_FRONT .or \"back\" .emit FACE_BACK;\n"
+"optColorType\n"
+" ColorType .or .true .emit COLOR_PRIMARY;\n"
+"ColorType\n"
+" dot_ne .and ColorProperty;\n"
+"ColorProperty\n"
+" \"primary\" .emit COLOR_PRIMARY .or\n"
+" .if (secondary_color != 0x00) \"secondary\" .emit COLOR_SECONDARY;\n"
+"fp_ALIAS_statement\n"
+" \"ALIAS\" .and fp_ALIAS_statement_1 .error IDENTIFIER_EXPECTED .and equal .and fp_establishedName;\n"
+"vp_ALIAS_statement\n"
+" \"ALIAS\" .and vp_ALIAS_statement_1 .error IDENTIFIER_EXPECTED .and equal .and vp_establishedName;\n"
+"fp_ALIAS_statement_1\n"
+" space .and fp_establishName;\n"
+"vp_ALIAS_statement_1\n"
+" space .and vp_establishName;\n"
+"fp_establishName\n"
+" fp_identifier;\n"
+"vp_establishName\n"
+" vp_identifier;\n"
+"fp_establishedName\n"
+" fp_identifier;\n"
+"vp_establishedName\n"
+" vp_identifier;\n"
+"fp_establishedName_no_error_on_identifier\n"
+" fp_identifier_ne;\n"
+"vp_establishedName_no_error_on_identifier\n"
+" vp_identifier_ne;\n"
+"fp_identifier\n"
+" fp_identifier_ne .error IDENTIFIER_EXPECTED;\n"
+"vp_identifier\n"
+" vp_identifier_ne .error IDENTIFIER_EXPECTED;\n"
+"fp_identifier_ne\n"
+" fp_not_reserved_identifier .and identifier_ne;\n"
+"vp_identifier_ne\n"
+" vp_not_reserved_identifier .and identifier_ne;\n"
+"fp_not_reserved_identifier\n"
+" fp_not_reserved_identifier_1 .or .true;\n"
+"fp_not_reserved_identifier_1\n"
+" fp_reserved_identifier .and .false .error RESERVED_KEYWORD;\n"
+"vp_not_reserved_identifier\n"
+" vp_not_reserved_identifier_1 .or .true;\n"
+"vp_not_reserved_identifier_1\n"
+" vp_reserved_identifier .and .false .error RESERVED_KEYWORD;\n"
+"fp_reserved_identifier\n"
+" \"ABS\" .or \"ABS_SAT\" .or \"ADD\" .or \"ADD_SAT\" .or \"ALIAS\" .or \"ATTRIB\" .or \"CMP\" .or \"CMP_SAT\" .or\n"
+" \"COS\" .or \"COS_SAT\" .or \"DP3\" .or \"DP3_SAT\" .or \"DP4\" .or \"DP4_SAT\" .or \"DPH\" .or \"DPH_SAT\" .or\n"
+" \"DST\" .or \"DST_SAT\" .or \"END\" .or \"EX2\" .or \"EX2_SAT\" .or \"FLR\" .or \"FLR_SAT\" .or \"FRC\" .or\n"
+" \"FRC_SAT\" .or \"KIL\" .or \"LG2\" .or \"LG2_SAT\" .or \"LIT\" .or \"LIT_SAT\" .or \"LRP\" .or \"LRP_SAT\" .or\n"
+" \"MAD\" .or \"MAD_SAT\" .or \"MAX\" .or \"MAX_SAT\" .or \"MIN\" .or \"MIN_SAT\" .or \"MOV\" .or \"MOV_SAT\" .or\n"
+" \"MUL\" .or \"MUL_SAT\" .or \"OPTION\" .or \"OUTPUT\" .or \"PARAM\" .or \"POW\" .or \"POW_SAT\" .or \"RCP\" .or\n"
+" \"RCP_SAT\" .or \"RSQ\" .or \"RSQ_SAT\" .or \"SIN\" .or \"SIN_SAT\" .or \"SCS\" .or \"SCS_SAT\" .or \"SGE\" .or\n"
+" \"SGE_SAT\" .or \"SLT\" .or \"SLT_SAT\" .or \"SUB\" .or \"SUB_SAT\" .or \"SWZ\" .or \"SWZ_SAT\" .or \"TEMP\" .or\n"
+" \"TEX\" .or \"TEX_SAT\" .or \"TXB\" .or \"TXB_SAT\" .or \"TXP\" .or \"TXP_SAT\" .or \"XPD\" .or \"XPD_SAT\" .or\n"
+" \"fragment\" .or \"program\" .or \"result\" .or \"state\" .or \"texture\";\n"
+"vp_reserved_identifier\n"
+" \"ABS\" .or \"ADD\" .or \"ADDRESS\" .or \"ALIAS\" .or \"ARL\" .or \"ATTRIB\" .or \"DP3\" .or \"DP4\" .or\n"
+" \"DPH\" .or \"DST\" .or \"END\" .or \"EX2\" .or \"EXP\" .or \"FLR\" .or \"FRC\" .or \"LG2\" .or \"LIT\" .or\n"
+" \"LOG\" .or \"MAD\" .or \"MAX\" .or \"MIN\" .or \"MOV\" .or \"MUL\" .or \"OPTION\" .or \"OUTPUT\" .or\n"
+" \"PARAM\" .or \"POW\" .or \"RCP\" .or \"RSQ\" .or \"SGE\" .or \"SLT\" .or \"SUB\" .or \"SWZ\" .or \"TEMP\" .or\n"
+" \"XPD\" .or \"program\" .or \"result\" .or \"state\" .or \"vertex\";\n"
+"integer\n"
+" integer_ne .error INTEGER_EXPECTED;\n"
+"zero\n"
+" '0';\n"
+"leading_zeroes\n"
+" .loop zero;\n"
+"no_digit\n"
+" no_digit_1 .or .true;\n"
+"no_digit_1\n"
+" digit10 .and .false .error INTEGER_OUT_OF_RANGE;\n"
+"all_zeroes\n"
+" all_zeroes_1 .or no_digit_1;\n"
+"all_zeroes_1\n"
+" '0' .and .loop zero .and no_digit;\n"
+"integer_0_3\n"
+" integer_0_3_1 .error INTEGER_EXPECTED .and .true .emit 0x00 .emit $;\n"
+"integer_0_3_1\n"
+" integer_0_3_2 .or all_zeroes .emit '0';\n"
+"integer_0_3_2 \n"
+" leading_zeroes .and '1'-'3' .emit * .and no_digit;\n"
+"integer_0_63\n"
+" integer_0_63_1 .error INTEGER_EXPECTED .and .true .emit 0x00 .emit $;\n"
+"integer_0_63_1\n"
+" integer_0_63_2 .or integer_0_63_3 .or integer_0_63_4 .or integer_0_63_5 .or\n"
+" all_zeroes .emit '0';\n"
+"integer_0_63_2 \n"
+" leading_zeroes .and '7'-'9' .emit * .and no_digit;\n"
+"integer_0_63_3 \n"
+" leading_zeroes .and '1'-'5' .emit * .and '0'-'9' .emit * .and no_digit;\n"
+"integer_0_63_4 \n"
+" leading_zeroes .and '6' .emit * .and '0'-'3' .emit * .and no_digit;\n"
+"integer_0_63_5 \n"
+" leading_zeroes .and '1'-'6' .emit * .and no_digit;\n"
+"integer_0_64\n"
+" integer_0_64_1 .error INTEGER_EXPECTED .and .true .emit 0x00 .emit $;\n"
+"integer_0_64_1\n"
+" integer_0_64_2 .or integer_0_64_3 .or integer_0_64_4 .or integer_0_64_5 .or\n"
+" all_zeroes .emit '0';\n"
+"integer_0_64_2 \n"
+" leading_zeroes .and '7'-'9' .emit * .and no_digit;\n"
+"integer_0_64_3 \n"
+" leading_zeroes .and '1'-'5' .emit * .and '0'-'9' .emit * .and no_digit;\n"
+"integer_0_64_4 \n"
+" leading_zeroes .and '6' .emit * .and '0'-'4' .emit * .and no_digit;\n"
+"integer_0_64_5 \n"
+" leading_zeroes .and '1'-'6' .emit * .and no_digit;\n"
+"optional_space\n"
+" space .or .true;\n"
+"space_dst\n"
+" space .error OPERATION_NEEDS_DESTINATION_VARIABLE;\n"
+"space_src\n"
+" space .error OPERATION_NEEDS_SOURCE_VARIABLE;\n"
+"space\n"
+" single_space .and .loop single_space;\n"
+"single_space\n"
+" white_char .or comment_block;\n"
+"white_char\n"
+" ' ' .or '\\t' .or '\\n' .or '\\r';\n"
+"comment_block\n"
+" '#' .and .loop comment_char .and new_line;\n"
+"comment_char\n"
+" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n"
+"new_line\n"
+" '\\n' .or crlf .or '\\0';\n"
+"crlf\n"
+" '\\r' .and '\\n';\n"
+"semicolon\n"
+" optional_space .and ';' .error MISSING_SEMICOLON .and optional_space;\n"
+"comma\n"
+" optional_space .and ',' .error MISSING_COMMA .and optional_space;\n"
+"comma_ne\n"
+" optional_space .and ',' .and optional_space;\n"
+"lbracket\n"
+" optional_space .and '[' .error MISSING_LBRACKET .and optional_space;\n"
+"lbracket_ne\n"
+" optional_space .and '[' .and optional_space;\n"
+"rbracket\n"
+" optional_space .and ']' .error MISSING_RBRACKET .and optional_space;\n"
+"dot\n"
+" optional_space .and '.' .error MISSING_DOT .and optional_space;\n"
+"dot_ne\n"
+" optional_space .and '.' .and optional_space;\n"
+"equal\n"
+" optional_space .and '=' .error MISSING_EQUAL .and optional_space;\n"
+"lbrace\n"
+" optional_space .and '{' .error MISSING_LBRACE .and optional_space;\n"
+"lbrace_ne\n"
+" optional_space .and '{' .and optional_space;\n"
+"rbrace\n"
+" optional_space .and '}' .error MISSING_RBRACE .and optional_space;\n"
+"dotdot\n"
+" optional_space .and '.' .and '.' .error MISSING_DOTDOT .and optional_space;\n"
+"dotdot_ne\n"
+" optional_space .and '.' .and '.' .and optional_space;\n"
+"float\n"
+" float_1 .or float_2 .or float_legacy;\n"
+"float_1\n"
+" '.' .emit 0x00 .and integer_ne .error MISSING_FRACTION_OR_EXPONENT .and optional_exponent;\n"
+"float_2\n"
+" integer_ne .and float_3;\n"
+"float_3\n"
+" float_4 .or float_5;\n"
+"float_4\n"
+" '.' .and optional_integer .and optional_exponent;\n"
+"float_5\n"
+" exponent .emit 0x00;\n"
+"float_legacy\n"
+" integer_ne .and .true .emit 0x00 .emit 0x00;\n"
+"integer_ne\n"
+" integer_ne_1 .and .true .emit 0x00 .emit $;\n"
+"integer_ne_1\n"
+" digit10 .emit * .and .loop digit10 .emit *;\n"
+"optional_integer\n"
+" integer_ne .or .true .emit 0x00;\n"
+"optional_exponent\n"
+" exponent .or .true .emit 0x00;\n"
+"exponent\n"
+" exponent_1 .and optional_sign_ne .and integer_ne .error EXPONENT_VALUE_EXPECTED;\n"
+"exponent_1\n"
+" 'e' .or 'E';\n"
+"optional_sign_ne\n"
+" minus_ne .or plus_ne .or .true;\n"
+"plus_ne\n"
+" optional_space .and '+' .and optional_space;\n"
+"minus_ne\n"
+" optional_space .and '-' .emit '-' .and optional_space;\n"
+"identifier_ne\n"
+" first_idchar .emit * .and .loop follow_idchar .emit * .and .true .emit 0x00 .emit $;\n"
+"follow_idchar\n"
+" first_idchar .or digit10;\n"
+"first_idchar\n"
+" 'a'-'z' .or 'A'-'Z' .or '_' .or '$';\n"
+"digit10\n"
+" '0'-'9';\n"
+".string __string_filter;\n"
+"__string_filter\n"
+" .loop __identifier_char;\n"
+"__identifier_char\n"
+" 'a'-'z' .or 'A'-'Z' .or '_' .or '$' .or '0'-'9';\n"
+"e_signature\n"
+" e_signature_char .and .loop e_signature_char;\n"
+"e_signature_char\n"
+" '!' .or '.' .or 'A'-'Z' .or 'a'-'z' .or '0'-'9';\n"
+"e_statement\n"
+" .loop e_statement_not_term;\n"
+"e_statement_not_term\n"
+" '\\x3C'-'\\xFF' .or '\\x0E'-'\\x3A' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n"
+"e_identifier\n"
+" e_identifier_first .and .loop e_identifier_next;\n"
+"e_identifier_first\n"
+" 'a'-'z' .or 'A'-'Z' .or '_' .or '$';\n"
+"e_identifier_next\n"
+" e_identifier_first .or '0'-'9';\n"
+"e_token\n"
+" e_identifier .or e_token_number .or '[' .or ']' .or '.' .or '{' .or '}' .or '=' .or '+' .or\n"
+" '-' .or ',' .or ';';\n"
+"e_token_number\n"
+" e_token_digit .and .loop e_token_digit;\n"
+"e_token_digit\n"
+" '0'-'9';\n"
+"e_charordigit\n"
+" 'A'-'Z' .or 'a'-'z' .or '0'-'9';\n"
+""
diff --git a/src/mesa/shader/atifragshader.c b/src/mesa/shader/atifragshader.c
new file mode 100644
index 00000000000..d349a496dc7
--- /dev/null
+++ b/src/mesa/shader/atifragshader.c
@@ -0,0 +1,757 @@
+/**
+ * \file atifragshader.c
+ * \author David Airlie
+ * Copyright (C) 2004 David Airlie 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
+ * DAVID AIRLIE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "enums.h"
+#include "mtypes.h"
+#include "atifragshader.h"
+
+#define MESA_DEBUG_ATI_FS 0
+
+static struct ati_fragment_shader DummyShader;
+
+
+/**
+ * Allocate and initialize a new ATI fragment shader object.
+ */
+struct ati_fragment_shader *
+_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id)
+{
+ struct ati_fragment_shader *s = CALLOC_STRUCT(ati_fragment_shader);
+ (void) ctx;
+ if (s) {
+ s->Id = id;
+ s->RefCount = 1;
+ }
+ return s;
+}
+
+
+/**
+ * Delete the given ati fragment shader
+ */
+void
+_mesa_delete_ati_fragment_shader(GLcontext *ctx, struct ati_fragment_shader *s)
+{
+ GLuint i;
+ for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
+ if (s->Instructions[i])
+ _mesa_free(s->Instructions[i]);
+ if (s->SetupInst[i])
+ _mesa_free(s->SetupInst[i]);
+ }
+ _mesa_free(s);
+}
+
+
+
+static void
+new_arith_inst(struct ati_fragment_shader *prog)
+{
+/* set "default" instruction as not all may get defined.
+ there is no specified way to express a nop with ati fragment shaders we use
+ GL_NONE as the op enum and just set some params to 0 - so nothing to do here */
+ prog->numArithInstr[prog->cur_pass >> 1]++;
+}
+
+static void
+new_tex_inst(struct ati_fragment_shader *prog)
+{
+}
+
+static void match_pair_inst(struct ati_fragment_shader *curProg, GLuint optype)
+{
+ if (optype == curProg->last_optype) {
+ curProg->last_optype = 1;
+ }
+}
+
+#if MESA_DEBUG_ATI_FS
+static char *
+create_dst_mod_str(GLuint mod)
+{
+ static char ret_str[1024];
+
+ _mesa_memset(ret_str, 0, 1024);
+ if (mod & GL_2X_BIT_ATI)
+ _mesa_strncat(ret_str, "|2X", 1024);
+
+ if (mod & GL_4X_BIT_ATI)
+ _mesa_strncat(ret_str, "|4X", 1024);
+
+ if (mod & GL_8X_BIT_ATI)
+ _mesa_strncat(ret_str, "|8X", 1024);
+ if (mod & GL_HALF_BIT_ATI)
+ _mesa_strncat(ret_str, "|HA", 1024);
+ if (mod & GL_QUARTER_BIT_ATI)
+ _mesa_strncat(ret_str, "|QU", 1024);
+ if (mod & GL_EIGHTH_BIT_ATI)
+ _mesa_strncat(ret_str, "|EI", 1024);
+
+ if (mod & GL_SATURATE_BIT_ATI)
+ _mesa_strncat(ret_str, "|SAT", 1024);
+
+ if (_mesa_strlen(ret_str) == 0)
+ _mesa_strncat(ret_str, "NONE", 1024);
+ return ret_str;
+}
+
+static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
+ "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
+
+static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
+ GLuint dstMask, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
+ GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
+ GLuint arg3Rep, GLuint arg3Mod)
+{
+ char *op_name;
+
+ op_name = atifs_ops[(arg_count-1)+(optype?3:0)];
+
+ fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op),
+ _mesa_lookup_enum_by_nr(dst));
+ if (!optype)
+ fprintf(stderr, ", %d", dstMask);
+
+ fprintf(stderr, ", %s", create_dst_mod_str(dstMod));
+
+ fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1),
+ _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod);
+ if (arg_count>1)
+ fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2),
+ _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod);
+ if (arg_count>2)
+ fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3),
+ _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod);
+
+ fprintf(stderr,")\n");
+
+}
+#endif
+
+static int check_arith_arg(struct ati_fragment_shader *curProg,
+ GLuint optype, GLuint arg, GLuint argRep)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (((arg < GL_CON_0_ATI) || (arg > GL_CON_7_ATI)) &&
+ ((arg < GL_REG_0_ATI) || (arg > GL_REG_5_ATI)) &&
+ (arg != GL_ZERO) && (arg != GL_ONE) &&
+ (arg != GL_PRIMARY_COLOR_ARB) && (arg != GL_SECONDARY_INTERPOLATOR_ATI)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(arg)");
+ return 0;
+ }
+ if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
+ ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
+ return 0;
+ }
+ if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
+ ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
+ return 0;
+ }
+ if ((curProg->cur_pass == 1) &&
+ ((arg == GL_PRIMARY_COLOR_ARB) || (arg == GL_SECONDARY_INTERPOLATOR_ATI))) {
+ curProg->interpinp1 = GL_TRUE;
+ }
+ return 1;
+}
+
+GLuint GLAPIENTRY
+_mesa_GenFragmentShadersATI(GLuint range)
+{
+ GLuint first;
+ GLuint i;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (range == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGenFragmentShadersATI(range)");
+ return 0;
+ }
+
+ if (ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGenFragmentShadersATI(insideShader)");
+ return 0;
+ }
+
+ first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ATIShaders, range);
+ for (i = 0; i < range; i++) {
+ _mesa_HashInsert(ctx->Shared->ATIShaders, first + i, &DummyShader);
+ }
+
+ return first;
+}
+
+void GLAPIENTRY
+_mesa_BindFragmentShaderATI(GLuint id)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
+ struct ati_fragment_shader *newProg;
+
+ if (ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragmentShaderATI(insideShader)");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (curProg->Id == id) {
+ return;
+ }
+
+ /* unbind current */
+ if (curProg->Id != 0) {
+ curProg->RefCount--;
+ if (curProg->RefCount <= 0) {
+ _mesa_HashRemove(ctx->Shared->ATIShaders, id);
+ }
+ }
+
+ /* find new shader */
+ if (id == 0) {
+ newProg = ctx->Shared->DefaultFragmentShader;
+ }
+ else {
+ newProg = (struct ati_fragment_shader *)
+ _mesa_HashLookup(ctx->Shared->ATIShaders, id);
+ if (!newProg || newProg == &DummyShader) {
+ /* allocate a new program now */
+ newProg = _mesa_new_ati_fragment_shader(ctx, id);
+ if (!newProg) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFragmentShaderATI");
+ return;
+ }
+ _mesa_HashInsert(ctx->Shared->ATIShaders, id, newProg);
+ }
+
+ }
+
+ /* do actual bind */
+ ctx->ATIFragmentShader.Current = newProg;
+
+ ASSERT(ctx->ATIFragmentShader.Current);
+ if (newProg)
+ newProg->RefCount++;
+
+ /*if (ctx->Driver.BindProgram)
+ ctx->Driver.BindProgram(ctx, target, prog); */
+}
+
+void GLAPIENTRY
+_mesa_DeleteFragmentShaderATI(GLuint id)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteFragmentShaderATI(insideShader)");
+ return;
+ }
+
+ if (id != 0) {
+ struct ati_fragment_shader *prog = (struct ati_fragment_shader *)
+ _mesa_HashLookup(ctx->Shared->ATIShaders, id);
+ if (prog == &DummyShader) {
+ _mesa_HashRemove(ctx->Shared->ATIShaders, id);
+ }
+ else if (prog) {
+ if (ctx->ATIFragmentShader.Current &&
+ ctx->ATIFragmentShader.Current->Id == id) {
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ _mesa_BindFragmentShaderATI(0);
+ }
+ }
+
+ /* The ID is immediately available for re-use now */
+ _mesa_HashRemove(ctx->Shared->ATIShaders, id);
+ prog->RefCount--;
+ if (prog->RefCount <= 0) {
+ _mesa_free(prog);
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_BeginFragmentShaderATI(void)
+{
+ GLint i;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginFragmentShaderATI(insideShader)");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ /* if the shader was already defined free instructions and get new ones
+ (or, could use the same mem but would need to reinitialize) */
+ /* no idea if it's allowed to redefine a shader */
+ for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
+ if (ctx->ATIFragmentShader.Current->Instructions[i])
+ _mesa_free(ctx->ATIFragmentShader.Current->Instructions[i]);
+ if (ctx->ATIFragmentShader.Current->SetupInst[i])
+ _mesa_free(ctx->ATIFragmentShader.Current->SetupInst[i]);
+ }
+
+ /* malloc the instructions here - not sure if the best place but its
+ a start */
+ for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
+ ctx->ATIFragmentShader.Current->Instructions[i] =
+ (struct atifs_instruction *)
+ _mesa_calloc(sizeof(struct atifs_instruction) *
+ (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI));
+ ctx->ATIFragmentShader.Current->SetupInst[i] =
+ (struct atifs_setupinst *)
+ _mesa_calloc(sizeof(struct atifs_setupinst) *
+ (MAX_NUM_FRAGMENT_REGISTERS_ATI));
+ }
+
+/* can't rely on calloc for initialization as it's possible to redefine a shader (?) */
+ ctx->ATIFragmentShader.Current->LocalConstDef = 0;
+ ctx->ATIFragmentShader.Current->numArithInstr[0] = 0;
+ ctx->ATIFragmentShader.Current->numArithInstr[1] = 0;
+ ctx->ATIFragmentShader.Current->regsAssigned[0] = 0;
+ ctx->ATIFragmentShader.Current->regsAssigned[1] = 0;
+ ctx->ATIFragmentShader.Current->NumPasses = 0;
+ ctx->ATIFragmentShader.Current->cur_pass = 0;
+ ctx->ATIFragmentShader.Current->last_optype = 0;
+ ctx->ATIFragmentShader.Current->interpinp1 = GL_FALSE;
+ ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
+ ctx->ATIFragmentShader.Current->swizzlerq = 0;
+ ctx->ATIFragmentShader.Compiling = 1;
+}
+
+void GLAPIENTRY
+_mesa_EndFragmentShaderATI(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
+#if MESA_DEBUG_ATI_FS
+ GLint i, j;
+#endif
+
+ if (!ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(outsideShader)");
+ return;
+ }
+ if (curProg->interpinp1 && (ctx->ATIFragmentShader.Current->cur_pass > 1)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(interpinfirstpass)");
+ /* according to spec, DON'T return here */
+ }
+
+ match_pair_inst(curProg, 0);
+ ctx->ATIFragmentShader.Compiling = 0;
+ ctx->ATIFragmentShader.Current->isValid = GL_TRUE;
+ if ((ctx->ATIFragmentShader.Current->cur_pass == 0) ||
+ (ctx->ATIFragmentShader.Current->cur_pass == 2)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(noarithinst)");
+ }
+ if (ctx->ATIFragmentShader.Current->cur_pass > 1)
+ ctx->ATIFragmentShader.Current->NumPasses = 2;
+ else ctx->ATIFragmentShader.Current->NumPasses = 1;
+ ctx->ATIFragmentShader.Current->cur_pass=0;
+#if MESA_DEBUG_ATI_FS
+ for (j = 0; j < MAX_NUM_PASSES_ATI; j++) {
+ for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) {
+ GLuint op = curProg->SetupInst[j][i].Opcode;
+ const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0";
+ GLuint src = curProg->SetupInst[j][i].src;
+ GLuint swizzle = curProg->SetupInst[j][i].swizzle;
+ fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src,
+ swizzle);
+ }
+ for (i = 0; i < curProg->numArithInstr[j]; i++) {
+ GLuint op0 = curProg->Instructions[j][i].Opcode[0];
+ GLuint op1 = curProg->Instructions[j][i].Opcode[1];
+ const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0";
+ const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0";
+ GLuint count0 = curProg->Instructions[j][i].ArgCount[0];
+ GLuint count1 = curProg->Instructions[j][i].ArgCount[1];
+ fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0,
+ op1, op1_enum, count1);
+ }
+ }
+#endif
+}
+
+void GLAPIENTRY
+_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
+ struct atifs_setupinst *curI;
+
+ if (!ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)");
+ return;
+ }
+
+ if (curProg->cur_pass == 1) {
+ match_pair_inst(curProg, 0);
+ curProg->cur_pass = 2;
+ }
+ if ((curProg->cur_pass > 2) ||
+ ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)");
+ return;
+ }
+ if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
+ ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(dst)");
+ return;
+ }
+ if (((coord < GL_REG_0_ATI) || (coord > GL_REG_5_ATI)) &&
+ ((coord < GL_TEXTURE0_ARB) || (coord > GL_TEXTURE7_ARB) ||
+ ((coord - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)");
+ return;
+ }
+ if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)");
+ return;
+ }
+ if ((swizzle < GL_SWIZZLE_STR_ATI) && (swizzle > GL_SWIZZLE_STQ_DQ_ATI)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(swizzle)");
+ return;
+ }
+ if ((swizzle & 1) && (coord >= GL_REG_0_ATI)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
+ return;
+ }
+ if (coord <= GL_TEXTURE7_ARB) {
+ GLuint tmp = coord - GL_TEXTURE0_ARB;
+ if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
+ (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
+ return;
+ } else {
+ curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
+ }
+ }
+
+ curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
+ new_tex_inst(curProg);
+
+ /* add the instructions */
+ curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
+
+ curI->Opcode = ATI_FRAGMENT_SHADER_PASS_OP;
+ curI->src = coord;
+ curI->swizzle = swizzle;
+
+#if MESA_DEBUG_ATI_FS
+ _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord),
+ _mesa_lookup_enum_by_nr(swizzle));
+#endif
+}
+
+void GLAPIENTRY
+_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
+ struct atifs_setupinst *curI;
+
+ if (!ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)");
+ return;
+ }
+
+ if (curProg->cur_pass == 1) {
+ match_pair_inst(curProg, 0);
+ curProg->cur_pass = 2;
+ }
+ if ((curProg->cur_pass > 2) ||
+ ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)");
+ return;
+ }
+ if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
+ ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(dst)");
+ return;
+ }
+ if (((interp < GL_REG_0_ATI) || (interp > GL_REG_5_ATI)) &&
+ ((interp < GL_TEXTURE0_ARB) || (interp > GL_TEXTURE7_ARB) ||
+ ((interp - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
+ /* is this texture5 or texture7? spec is a bit unclear there */
+ _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)");
+ return;
+ }
+ if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)");
+ return;
+ }
+ if ((swizzle < GL_SWIZZLE_STR_ATI) && (swizzle > GL_SWIZZLE_STQ_DQ_ATI)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(swizzle)");
+ return;
+ }
+ if ((swizzle & 1) && (interp >= GL_REG_0_ATI)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
+ return;
+ }
+ if (interp <= GL_TEXTURE7_ARB) {
+ GLuint tmp = interp - GL_TEXTURE0_ARB;
+ if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
+ (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
+ return;
+ } else {
+ curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
+ }
+ }
+
+ curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
+ new_tex_inst(curProg);
+
+ /* add the instructions */
+ curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
+
+ curI->Opcode = ATI_FRAGMENT_SHADER_SAMPLE_OP;
+ curI->src = interp;
+ curI->swizzle = swizzle;
+
+#if MESA_DEBUG_ATI_FS
+ _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp),
+ _mesa_lookup_enum_by_nr(swizzle));
+#endif
+}
+
+static void
+_mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
+ GLuint dstMask, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
+ GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
+ GLuint arg3Rep, GLuint arg3Mod)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
+ GLint ci;
+ struct atifs_instruction *curI;
+ GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI;
+
+ if (!ctx->ATIFragmentShader.Compiling) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)");
+ return;
+ }
+
+ if (curProg->cur_pass==0)
+ curProg->cur_pass=1;
+
+ else if (curProg->cur_pass==2)
+ curProg->cur_pass=3;
+
+ /* decide whether this is a new instruction or not ... all color instructions are new,
+ and alpha instructions might also be new if there was no preceding color inst */
+ if ((optype == 0) || (curProg->last_optype == optype)) {
+ if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)");
+ return;
+ }
+ /* easier to do that here slight side effect invalid instr will still be inserted as nops */
+ match_pair_inst(curProg, optype);
+ new_arith_inst(curProg);
+ }
+ curProg->last_optype = optype;
+ ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1;
+
+ /* add the instructions */
+ curI = &curProg->Instructions[curProg->cur_pass >> 1][ci];
+
+ /* error checking */
+ if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dst)");
+ return;
+ }
+ if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) &&
+ (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) &&
+ (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) &&
+ (modtemp != GL_EIGHTH_BIT_ATI)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp);
+ return;
+ }
+ /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */
+ if (((op < GL_ADD_ATI) || (op > GL_DOT2_ADD_ATI)) && !(op == GL_MOV_ATI)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)");
+ return;
+ }
+ if (optype == 1) {
+ if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) ||
+ ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) ||
+ ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) ||
+ ((op != GL_DOT4_ATI) && (curI->Opcode[0] == GL_DOT4_ATI))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(op)");
+ return;
+ }
+ }
+ if ((op == GL_DOT4_ATI) &&
+ (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) ||
+ (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
+ }
+
+ if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) {
+ return;
+ }
+ if (arg2) {
+ if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) {
+ return;
+ }
+ }
+ if (arg3) {
+ if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) {
+ return;
+ }
+ if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) &&
+ (arg2 >= GL_CON_0_ATI) && (arg2 <= GL_CON_7_ATI) &&
+ (arg3 >= GL_CON_0_ATI) && (arg3 <= GL_CON_7_ATI) &&
+ (arg1 != arg2) && (arg1 != arg3) && (arg2 != arg3)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(3Consts)");
+ return;
+ }
+ }
+
+ /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */
+
+ curI->Opcode[optype] = op;
+ curI->SrcReg[optype][0].Index = arg1;
+ curI->SrcReg[optype][0].argRep = arg1Rep;
+ curI->SrcReg[optype][0].argMod = arg1Mod;
+ curI->ArgCount[optype] = arg_count;
+
+ if (arg2) {
+ curI->SrcReg[optype][1].Index = arg2;
+ curI->SrcReg[optype][1].argRep = arg2Rep;
+ curI->SrcReg[optype][1].argMod = arg2Mod;
+ }
+
+ if (arg3) {
+ curI->SrcReg[optype][2].Index = arg3;
+ curI->SrcReg[optype][2].argRep = arg3Rep;
+ curI->SrcReg[optype][2].argMod = arg3Mod;
+ }
+
+ curI->DstReg[optype].Index = dst;
+ curI->DstReg[optype].dstMod = dstMod;
+ curI->DstReg[optype].dstMask = dstMask;
+
+#if MESA_DEBUG_ATI_FS
+ debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod);
+#endif
+
+}
+
+void GLAPIENTRY
+_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask,
+ GLuint dstMod, GLuint arg1, GLuint arg1Rep,
+ GLuint arg1Mod)
+{
+ _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask,
+ dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
+}
+
+void GLAPIENTRY
+_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask,
+ GLuint dstMod, GLuint arg1, GLuint arg1Rep,
+ GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
+ GLuint arg2Mod)
+{
+ _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask,
+ dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
+ arg2Mod, 0, 0, 0);
+}
+
+void GLAPIENTRY
+_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask,
+ GLuint dstMod, GLuint arg1, GLuint arg1Rep,
+ GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
+ GLuint arg2Mod, GLuint arg3, GLuint arg3Rep,
+ GLuint arg3Mod)
+{
+ _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask,
+ dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
+ arg2Mod, arg3, arg3Rep, arg3Mod);
+}
+
+void GLAPIENTRY
+_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod)
+{
+ _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod,
+ arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
+}
+
+void GLAPIENTRY
+_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
+ GLuint arg2Rep, GLuint arg2Mod)
+{
+ _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod,
+ arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0,
+ 0);
+}
+
+void GLAPIENTRY
+_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
+ GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
+ GLuint arg3Rep, GLuint arg3Mod)
+{
+ _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod,
+ arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3,
+ arg3Rep, arg3Mod);
+}
+
+void GLAPIENTRY
+_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value)
+{
+ GLuint dstindex;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ((dst < GL_CON_0_ATI) || (dst > GL_CON_7_ATI)) {
+ /* spec says nothing about what should happen here but we can't just segfault...*/
+ _mesa_error(ctx, GL_INVALID_ENUM, "glSetFragmentShaderConstantATI(dst)");
+ return;
+ }
+
+ dstindex = dst - GL_CON_0_ATI;
+ if (ctx->ATIFragmentShader.Compiling) {
+ struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
+ COPY_4V(curProg->Constants[dstindex], value);
+ curProg->LocalConstDef |= 1 << dstindex;
+ }
+ else {
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value);
+ }
+}
diff --git a/src/mesa/shader/atifragshader.h b/src/mesa/shader/atifragshader.h
new file mode 100644
index 00000000000..32fb3a80190
--- /dev/null
+++ b/src/mesa/shader/atifragshader.h
@@ -0,0 +1,121 @@
+/*
+ * Mesa 3-D graphics library ATI Fragment Shader
+ *
+ * Copyright (C) 2004 David Airlie All Rights Reserved.
+ *
+ */
+
+#ifndef ATIFRAGSHADER_H
+#define ATIFRAGSHADER_H
+
+#define MAX_NUM_INSTRUCTIONS_PER_PASS_ATI 8
+#define MAX_NUM_PASSES_ATI 2
+#define MAX_NUM_FRAGMENT_REGISTERS_ATI 6
+
+struct ati_fs_opcode_st
+{
+ GLenum opcode;
+ GLint num_src_args;
+};
+
+extern struct ati_fs_opcode_st ati_fs_opcodes[];
+
+struct atifragshader_src_register
+{
+ GLuint Index;
+ GLuint argRep;
+ GLuint argMod;
+};
+
+struct atifragshader_dst_register
+{
+ GLuint Index;
+ GLuint dstMod;
+ GLuint dstMask;
+};
+
+#define ATI_FRAGMENT_SHADER_COLOR_OP 0
+#define ATI_FRAGMENT_SHADER_ALPHA_OP 1
+#define ATI_FRAGMENT_SHADER_PASS_OP 2
+#define ATI_FRAGMENT_SHADER_SAMPLE_OP 3
+
+/* two opcodes - one for color/one for alpha */
+/* up to three source registers for most ops */
+struct atifs_instruction
+{
+ GLenum Opcode[2];
+ GLuint ArgCount[2];
+ struct atifragshader_src_register SrcReg[2][3];
+ struct atifragshader_dst_register DstReg[2];
+};
+
+/* different from arithmetic shader instruction */
+struct atifs_setupinst
+{
+ GLenum Opcode;
+ GLuint src;
+ GLenum swizzle;
+};
+
+
+extern struct ati_fragment_shader *
+_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id);
+
+extern void
+_mesa_delete_ati_fragment_shader(GLcontext *ctx,
+ struct ati_fragment_shader *s);
+
+
+extern GLuint GLAPIENTRY _mesa_GenFragmentShadersATI(GLuint range);
+
+extern void GLAPIENTRY _mesa_BindFragmentShaderATI(GLuint id);
+
+extern void GLAPIENTRY _mesa_DeleteFragmentShaderATI(GLuint id);
+
+extern void GLAPIENTRY _mesa_BeginFragmentShaderATI(void);
+
+extern void GLAPIENTRY _mesa_EndFragmentShaderATI(void);
+
+extern void GLAPIENTRY
+_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle);
+
+extern void GLAPIENTRY
+_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle);
+
+extern void GLAPIENTRY
+_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask,
+ GLuint dstMod, GLuint arg1, GLuint arg1Rep,
+ GLuint arg1Mod);
+
+extern void GLAPIENTRY
+_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask,
+ GLuint dstMod, GLuint arg1, GLuint arg1Rep,
+ GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
+ GLuint arg2Mod);
+
+extern void GLAPIENTRY
+_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask,
+ GLuint dstMod, GLuint arg1, GLuint arg1Rep,
+ GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
+ GLuint arg2Mod, GLuint arg3, GLuint arg3Rep,
+ GLuint arg3Mod);
+
+extern void GLAPIENTRY
+_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod);
+
+extern void GLAPIENTRY
+_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
+ GLuint arg2Rep, GLuint arg2Mod);
+
+extern void GLAPIENTRY
+_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
+ GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
+ GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
+ GLuint arg3Rep, GLuint arg3Mod);
+
+extern void GLAPIENTRY
+_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value);
+
+#endif
diff --git a/src/mesa/shader/descrip.mms b/src/mesa/shader/descrip.mms
new file mode 100644
index 00000000000..95569a6f25c
--- /dev/null
+++ b/src/mesa/shader/descrip.mms
@@ -0,0 +1,77 @@
+# Makefile for core library for VMS
+# contributed by Jouk Jansen [email protected]
+# Last revision : 1 June 2005
+
+.first
+ define gl [---.include.gl]
+ define math [-.math]
+ define swrast [-.swrast]
+ define array_cache [-.array_cache]
+
+.include [---]mms-config.
+
+##### MACROS #####
+
+VPATH = RCS
+
+INCDIR = [---.include],[.grammar],[-.main],[-.glapi],[.slang]
+LIBDIR = [---.lib]
+CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm
+
+SOURCES = \
+ atifragshader.c \
+ arbprogparse.c \
+ arbprogram.c \
+ nvfragparse.c \
+ nvprogram.c \
+ nvvertexec.c \
+ nvvertparse.c \
+ program.c \
+ shaderobjects.c \
+ shaderobjects_3dlabs.c
+
+OBJECTS = \
+ atifragshader.obj,\
+ arbprogparse.obj,\
+ arbprogram.obj,\
+ nvfragparse.obj,\
+ nvprogram.obj,\
+ nvvertexec.obj,\
+ nvvertparse.obj,\
+ program.obj,\
+ shaderobjects.obj,\
+ shaderobjects_3dlabs.obj
+
+
+##### RULES #####
+
+VERSION=Mesa V3.4
+
+##### TARGETS #####
+all :
+ $(MMS)$(MMSQUALIFIERS) $(LIBDIR)$(GL_LIB)
+ set def [.slang]
+ $(MMS)$(MMSQUALIFIERS)
+ set def [-.grammar]
+ $(MMS)$(MMSQUALIFIERS)
+ set def [-]
+
+# Make the library
+$(LIBDIR)$(GL_LIB) : $(OBJECTS)
+ @ library $(LIBDIR)$(GL_LIB) $(OBJECTS)
+
+clean :
+ purge
+ delete *.obj;*
+
+atifragshader.obj : atifragshader.c
+arbprogparse.obj : arbprogparse.c
+arbprogram.obj : arbprogram.c
+nvfragparse.obj : nvfragparse.c
+nvprogram.obj : nvprogram.c
+nvvertexec.obj : nvvertexec.c
+nvvertparse.obj : nvvertparse.c
+program.obj : program.c
+shaderobjects.obj : shaderobjects.c
+ cc$(CFLAGS)/nowarn shaderobjects.c
+shaderobjects_3dlabs.obj : shaderobjects_3dlabs.c
diff --git a/src/mesa/shader/grammar/descrip.mms b/src/mesa/shader/grammar/descrip.mms
new file mode 100644
index 00000000000..f7fbee96bcd
--- /dev/null
+++ b/src/mesa/shader/grammar/descrip.mms
@@ -0,0 +1,41 @@
+# Makefile for core library for VMS
+# contributed by Jouk Jansen [email protected]
+# Last revision : 1 June 2005
+
+.first
+ define gl [----.include.gl]
+ define math [--.math]
+ define swrast [--.swrast]
+ define array_cache [--.array_cache]
+
+.include [----]mms-config.
+
+##### MACROS #####
+
+VPATH = RCS
+
+INCDIR = [----.include],[],[--.main],[--.glapi],[-.slang]
+LIBDIR = [----.lib]
+CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm
+
+SOURCES = grammar_mesa.c
+
+OBJECTS = grammar_mesa.obj
+
+##### RULES #####
+
+VERSION=Mesa V3.4
+
+##### TARGETS #####
+all :
+ $(MMS)$(MMSQUALIFIERS) $(LIBDIR)$(GL_LIB)
+
+# Make the library
+$(LIBDIR)$(GL_LIB) : $(OBJECTS)
+ @ library $(LIBDIR)$(GL_LIB) $(OBJECTS)
+
+clean :
+ purge
+ delete *.obj;*
+
+grammar_mesa.obj : grammar_mesa.c grammar.c
diff --git a/src/mesa/shader/grammar/grammar.c b/src/mesa/shader/grammar/grammar.c
new file mode 100644
index 00000000000..0b767c02cd3
--- /dev/null
+++ b/src/mesa/shader/grammar/grammar.c
@@ -0,0 +1,3148 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.2
+ *
+ * Copyright (C) 1999-2004 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 grammar.c
+ * syntax parsing engine
+ * \author Michal Krol
+ */
+
+#ifndef GRAMMAR_PORT_BUILD
+#error Do not build this file directly, build your grammar_XXX.c instead, which includes this file
+#endif
+
+/*
+*/
+
+/*
+ INTRODUCTION
+ ------------
+
+ The task is to check the syntax of an input string. Input string is a stream of ASCII
+ characters terminated with a null-character ('\0'). Checking it using C language is
+ difficult and hard to implement without bugs. It is hard to maintain and make changes when
+ the syntax changes.
+
+ This is because of a high redundancy of the C code. Large blocks of code are duplicated with
+ only small changes. Even use of macros does not solve the problem because macros cannot
+ erase the complexity of the problem.
+
+ The resolution is to create a new language that will be highly oriented to our task. Once
+ we describe a particular syntax, we are done. We can then focus on the code that implements
+ the language. The size and complexity of it is relatively small than the code that directly
+ checks the syntax.
+
+ First, we must implement our new language. Here, the language is implemented in C, but it
+ could also be implemented in any other language. The code is listed below. We must take
+ a good care that it is bug free. This is simple because the code is simple and clean.
+
+ Next, we must describe the syntax of our new language in itself. Once created and checked
+ manually that it is correct, we can use it to check another scripts.
+
+ Note that our new language loading code does not have to check the syntax. It is because we
+ assume that the script describing itself is correct, and other scripts can be syntactically
+ checked by the former script. The loading code must only do semantic checking which leads us to
+ simple resolving references.
+
+ THE LANGUAGE
+ ------------
+
+ Here I will describe the syntax of the new language (further called "Synek"). It is mainly a
+ sequence of declarations terminated by a semicolon. The declaration consists of a symbol,
+ which is an identifier, and its definition. A definition is in turn a sequence of specifiers
+ connected with ".and" or ".or" operator. These operators cannot be mixed together in a one
+ definition. Specifier can be a symbol, string, character, character range or a special
+ keyword ".true" or ".false".
+
+ On the very beginning of the script there is a declaration of a root symbol and is in the form:
+ .syntax <root_symbol>;
+ The <root_symbol> must be on of the symbols in declaration sequence. The syntax is correct if
+ the root symbol evaluates to true. A symbol evaluates to true if the definition associated with
+ the symbol evaluates to true. Definition evaluation depends on the operator used to connect
+ specifiers in the definition. If ".and" operator is used, definition evaluates to true if and
+ only if all the specifiers evaluate to true. If ".or" operator is used, definition evalutes to
+ true if any of the specifiers evaluates to true. If definition contains only one specifier,
+ it is evaluated as if it was connected with ".true" keyword by ".and" operator.
+
+ If specifier is a ".true" keyword, it always evaluates to true.
+
+ If specifier is a ".false" keyword, it always evaluates to false. Specifier evaluates to false
+ when it does not evaluate to true.
+
+ Character range specifier is in the form:
+ '<first_character>' - '<second_character>'
+ If specifier is a character range, it evaluates to true if character in the stream is greater
+ or equal to <first_character> and less or equal to <second_character>. In that situation
+ the stream pointer is advanced to point to next character in the stream. All C-style escape
+ sequences are supported although trigraph sequences are not. The comparisions are performed
+ on 8-bit unsigned integers.
+
+ Character specifier is in the form:
+ '<single_character>'
+ It evaluates to true if the following character range specifier evaluates to true:
+ '<single_character>' - '<single_character>'
+
+ String specifier is in the form:
+ "<string>"
+ Let N be the number of characters in <string>. Let <string>[i] designate i-th character in
+ <string>. Then the string specifier evaluates to true if and only if for i in the range [0, N)
+ the following character specifier evaluates to true:
+ '<string>[i]'
+ If <string>[i] is a quotation mark, '<string>[i]' is replaced with '\<string>[i]'.
+
+ Symbol specifier can be optionally preceded by a ".loop" keyword in the form:
+ .loop <symbol> (1)
+ where <symbol> is defined as follows:
+ <symbol> <definition>; (2)
+ Construction (1) is replaced by the following code:
+ <symbol$1>
+ and declaration (2) is replaced by the following:
+ <symbol$1> <symbol$2> .or .true;
+ <symbol$2> <symbol> .and <symbol$1>;
+ <symbol> <definition>;
+
+ Synek supports also a register mechanizm. User can, in its SYN file, declare a number of
+ registers that can be accessed in the syn body. Each reg has its name and a default value.
+ The register is one byte wide. The C code can change the default value by calling
+ grammar_set_reg8() with grammar id, register name and a new value. As we know, each rule is
+ a sequence of specifiers joined with .and or .or operator. And now each specifier can be
+ prefixed with a condition expression in a form ".if (<reg_name> <operator> <hex_literal>)"
+ where <operator> can be == or !=. If the condition evaluates to false, the specifier
+ evaluates to .false. Otherwise it evalutes to the specifier.
+
+ ESCAPE SEQUENCES
+ ----------------
+
+ Synek supports all escape sequences in character specifiers. The mapping table is listed below.
+ All occurences of the characters in the first column are replaced with the corresponding
+ character in the second column.
+
+ Escape sequence Represents
+ ------------------------------------------------------------------------------------------------
+ \a Bell (alert)
+ \b Backspace
+ \f Formfeed
+ \n New line
+ \r Carriage return
+ \t Horizontal tab
+ \v Vertical tab
+ \' Single quotation mark
+ \" Double quotation mark
+ \\ Backslash
+ \? Literal question mark
+ \ooo ASCII character in octal notation
+ \xhhh ASCII character in hexadecimal notation
+ ------------------------------------------------------------------------------------------------
+
+ RAISING ERRORS
+ --------------
+
+ Any specifier can be followed by a special construction that is executed when the specifier
+ evaluates to false. The construction is in the form:
+ .error <ERROR_TEXT>
+ <ERROR_TEXT> is an identifier declared earlier by error text declaration. The declaration is
+ in the form:
+ .errtext <ERROR_TEXT> "<error_desc>"
+ When specifier evaluates to false and this construction is present, parsing is stopped
+ immediately and <error_desc> is returned as a result of parsing. The error position is also
+ returned and it is meant as an offset from the beggining of the stream to the character that
+ was valid so far. Example:
+
+ (**** syntax script ****)
+
+ .syntax program;
+ .errtext MISSING_SEMICOLON "missing ';'"
+ program declaration .and .loop space .and ';' .error MISSING_SEMICOLON .and
+ .loop space .and '\0';
+ declaration "declare" .and .loop space .and identifier;
+ space ' ';
+
+ (**** sample code ****)
+
+ declare foo ,
+
+ In the example above checking the sample code will result in error message "missing ';'" and
+ error position 12. The sample code is not correct. Note the presence of '\0' specifier to
+ assure that there is no code after semicolon - only spaces.
+ <error_desc> can optionally contain identifier surrounded by dollar signs $. In such a case,
+ the identifier and dollar signs are replaced by a string retrieved by invoking symbol with
+ the identifier name. The starting position is the error position. The lenght of the resulting
+ string is the position after invoking the symbol.
+
+ PRODUCTION
+ ----------
+
+ Synek not only checks the syntax but it can also produce (emit) bytes associated with specifiers
+ that evaluate to true. That is, every specifier and optional error construction can be followed
+ by a number of emit constructions that are in the form:
+ .emit <parameter>
+ <paramater> can be a HEX number, identifier, a star * or a dollar $. HEX number is preceded by
+ 0x or 0X. If <parameter> is an identifier, it must be earlier declared by emit code declaration
+ in the form:
+ .emtcode <identifier> <hex_number>
+
+ When given specifier evaluates to true, all emits associated with the specifier are output
+ in order they were declared. A star means that last-read character should be output instead
+ of constant value. Example:
+
+ (**** syntax script ****)
+
+ .syntax foobar;
+ .emtcode WORD_FOO 0x01
+ .emtcode WORD_BAR 0x02
+ foobar FOO .emit WORD_FOO .or BAR .emit WORD_BAR .or .true .emit 0x00;
+ FOO "foo" .and SPACE;
+ BAR "bar" .and SPACE;
+ SPACE ' ' .or '\0';
+
+ (**** sample text 1 ****)
+
+ foo
+
+ (**** sample text 2 ****)
+
+ foobar
+
+ For both samples the result will be one-element array. For first sample text it will be
+ value 1, for second - 0. Note that every text will be accepted because of presence of
+ .true as an alternative.
+
+ Another example:
+
+ (**** syntax script ****)
+
+ .syntax declaration;
+ .emtcode VARIABLE 0x01
+ declaration "declare" .and .loop space .and
+ identifier .emit VARIABLE .and (1)
+ .true .emit 0x00 .and (2)
+ .loop space .and ';';
+ space ' ' .or '\t';
+ identifier .loop id_char .emit *; (3)
+ id_char 'a'-'z' .or 'A'-'Z' .or '_';
+
+ (**** sample code ****)
+
+ declare fubar;
+
+ In specifier (1) symbol <identifier> is followed by .emit VARIABLE. If it evaluates to
+ true, VARIABLE constant and then production of the symbol is output. Specifier (2) is used
+ to terminate the string with null to signal when the string ends. Specifier (3) outputs
+ all characters that make declared identifier. The result of sample code will be the
+ following array:
+ { 1, 'f', 'u', 'b', 'a', 'r', 0 }
+
+ If .emit is followed by dollar $, it means that current position should be output. Current
+ position is a 32-bit unsigned integer distance from the very beginning of the parsed string to
+ first character consumed by the specifier associated with the .emit instruction. Current
+ position is stored in the output buffer in Little-Endian convention (the lowest byte comes
+ first).
+*/
+
+static void mem_free (void **);
+
+/*
+ internal error messages
+*/
+static const byte *OUT_OF_MEMORY = (byte *) "internal error 1001: out of physical memory";
+static const byte *UNRESOLVED_REFERENCE = (byte *) "internal error 1002: unresolved reference '$'";
+static const byte *INVALID_GRAMMAR_ID = (byte *) "internal error 1003: invalid grammar object";
+static const byte *INVALID_REGISTER_NAME = (byte *) "internal error 1004: invalid register name: '$'";
+/*static const byte *DUPLICATE_IDENTIFIER = (byte *) "internal error 1005: identifier '$' already defined";*/
+static const byte *UNREFERENCED_IDENTIFIER =(byte *) "internal error 1006: unreferenced identifier '$'";
+
+static const byte *error_message = NULL; /* points to one of the error messages above */
+static byte *error_param = NULL; /* this is inserted into error_message in place of $ */
+static int error_position = -1;
+
+static byte *unknown = (byte *) "???";
+
+static void clear_last_error (void)
+{
+ /* reset error message */
+ error_message = NULL;
+
+ /* free error parameter - if error_param is a "???" don't free it - it's static */
+ if (error_param != unknown)
+ mem_free ((void **) (void *) &error_param);
+ else
+ error_param = NULL;
+
+ /* reset error position */
+ error_position = -1;
+}
+
+static void set_last_error (const byte *msg, byte *param, int pos)
+{
+ /* error message can be set only once */
+ if (error_message != NULL)
+ {
+ mem_free ((void **) (void *) &param);
+ return;
+ }
+
+ error_message = msg;
+
+ /* if param is NULL, set error_param to unknown ("???") */
+ /* note: do not try to strdup the "???" - it may be that we are here because of */
+ /* out of memory error so strdup can fail */
+ if (param != NULL)
+ error_param = param;
+ else
+ error_param = unknown;
+
+ error_position = pos;
+}
+
+/*
+ memory management routines
+*/
+static void *mem_alloc (size_t size)
+{
+ void *ptr = grammar_alloc_malloc (size);
+ if (ptr == NULL)
+ set_last_error (OUT_OF_MEMORY, NULL, -1);
+ return ptr;
+}
+
+static void *mem_copy (void *dst, const void *src, size_t size)
+{
+ return grammar_memory_copy (dst, src, size);
+}
+
+static void mem_free (void **ptr)
+{
+ grammar_alloc_free (*ptr);
+ *ptr = NULL;
+}
+
+static void *mem_realloc (void *ptr, size_t old_size, size_t new_size)
+{
+ void *ptr2 = grammar_alloc_realloc (ptr, old_size, new_size);
+ if (ptr2 == NULL)
+ set_last_error (OUT_OF_MEMORY, NULL, -1);
+ return ptr2;
+}
+
+static byte *str_copy_n (byte *dst, const byte *src, size_t max_len)
+{
+ return grammar_string_copy_n (dst, src, max_len);
+}
+
+static byte *str_duplicate (const byte *str)
+{
+ byte *new_str = grammar_string_duplicate (str);
+ if (new_str == NULL)
+ set_last_error (OUT_OF_MEMORY, NULL, -1);
+ return new_str;
+}
+
+static int str_equal (const byte *str1, const byte *str2)
+{
+ return grammar_string_compare (str1, str2) == 0;
+}
+
+static int str_equal_n (const byte *str1, const byte *str2, unsigned int n)
+{
+ return grammar_string_compare_n (str1, str2, n) == 0;
+}
+
+static unsigned int str_length (const byte *str)
+{
+ return grammar_string_length (str);
+}
+
+/*
+ useful macros
+*/
+#define GRAMMAR_IMPLEMENT_LIST_APPEND(_Ty)\
+ static void _Ty##_append (_Ty **x, _Ty *nx) {\
+ while (*x) x = &(**x).next;\
+ *x = nx;\
+ }
+
+/*
+ string to byte map typedef
+*/
+typedef struct map_byte_
+{
+ byte *key;
+ byte data;
+ struct map_byte_ *next;
+} map_byte;
+
+static void map_byte_create (map_byte **ma)
+{
+ *ma = (map_byte *) mem_alloc (sizeof (map_byte));
+ if (*ma)
+ {
+ (**ma).key = NULL;
+ (**ma).data = '\0';
+ (**ma).next = NULL;
+ }
+}
+
+static void map_byte_destroy (map_byte **ma)
+{
+ if (*ma)
+ {
+ map_byte_destroy (&(**ma).next);
+ mem_free ((void **) &(**ma).key);
+ mem_free ((void **) ma);
+ }
+}
+
+GRAMMAR_IMPLEMENT_LIST_APPEND(map_byte)
+
+/*
+ searches the map for the specified key,
+ returns pointer to the element with the specified key if it exists
+ returns NULL otherwise
+*/
+static map_byte *map_byte_locate (map_byte **ma, const byte *key)
+{
+ while (*ma)
+ {
+ if (str_equal ((**ma).key, key))
+ return *ma;
+
+ ma = &(**ma).next;
+ }
+
+ set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1);
+ return NULL;
+}
+
+/*
+ searches the map for specified key,
+ if the key is matched, *data is filled with data associated with the key,
+ returns 0 if the key is matched,
+ returns 1 otherwise
+*/
+static int map_byte_find (map_byte **ma, const byte *key, byte *data)
+{
+ map_byte *found = map_byte_locate (ma, key);
+ if (found != NULL)
+ {
+ *data = found->data;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ regbyte context typedef
+
+ Each regbyte consists of its name and a default value. These are static and created at
+ grammar script compile-time, for example the following line:
+ .regbyte vertex_blend 0x00
+ adds a new regbyte named "vertex_blend" to the static list and initializes it to 0.
+ When the script is executed, this regbyte can be accessed by name for read and write. When a
+ particular regbyte is written, a new regbyte_ctx entry is added to the top of the regbyte_ctx
+ stack. The new entry contains information abot which regbyte it references and its new value.
+ When a given regbyte is accessed for read, the stack is searched top-down to find an
+ entry that references the regbyte. The first matching entry is used to return the current
+ value it holds. If no entry is found, the default value is returned.
+*/
+typedef struct regbyte_ctx_
+{
+ map_byte *m_regbyte;
+ byte m_current_value;
+ struct regbyte_ctx_ *m_prev;
+} regbyte_ctx;
+
+static void regbyte_ctx_create (regbyte_ctx **re)
+{
+ *re = (regbyte_ctx *) mem_alloc (sizeof (regbyte_ctx));
+ if (*re)
+ {
+ (**re).m_regbyte = NULL;
+ (**re).m_prev = NULL;
+ }
+}
+
+static void regbyte_ctx_destroy (regbyte_ctx **re)
+{
+ if (*re)
+ {
+ mem_free ((void **) re);
+ }
+}
+
+static byte regbyte_ctx_extract (regbyte_ctx **re, map_byte *reg)
+{
+ /* first lookup in the register stack */
+ while (*re != NULL)
+ {
+ if ((**re).m_regbyte == reg)
+ return (**re).m_current_value;
+
+ re = &(**re).m_prev;
+ }
+
+ /* if not found - return the default value */
+ return reg->data;
+}
+
+/*
+ emit type typedef
+*/
+typedef enum emit_type_
+{
+ et_byte, /* explicit number */
+ et_stream, /* eaten character */
+ et_position /* current position */
+} emit_type;
+
+/*
+ emit destination typedef
+*/
+typedef enum emit_dest_
+{
+ ed_output, /* write to the output buffer */
+ ed_regbyte /* write a particular regbyte */
+} emit_dest;
+
+/*
+ emit typedef
+*/
+typedef struct emit_
+{
+ emit_dest m_emit_dest;
+ emit_type m_emit_type; /* ed_output */
+ byte m_byte; /* et_byte */
+ map_byte *m_regbyte; /* ed_regbyte */
+ byte *m_regname; /* ed_regbyte - temporary */
+ struct emit_ *m_next;
+} emit;
+
+static void emit_create (emit **em)
+{
+ *em = (emit *) mem_alloc (sizeof (emit));
+ if (*em)
+ {
+ (**em).m_emit_dest = ed_output;
+ (**em).m_emit_type = et_byte;
+ (**em).m_byte = '\0';
+ (**em).m_regbyte = NULL;
+ (**em).m_regname = NULL;
+ (**em).m_next = NULL;
+ }
+}
+
+static void emit_destroy (emit **em)
+{
+ if (*em)
+ {
+ emit_destroy (&(**em).m_next);
+ mem_free ((void **) &(**em).m_regname);
+ mem_free ((void **) em);
+ }
+}
+
+static unsigned int emit_size (emit *_E)
+{
+ unsigned int n = 0;
+
+ while (_E != NULL)
+ {
+ if (_E->m_emit_dest == ed_output)
+ {
+ if (_E->m_emit_type == et_position)
+ n += 4; /* position is a 32-bit unsigned integer */
+ else
+ n++;
+ }
+ _E = _E->m_next;
+ }
+
+ return n;
+}
+
+static int emit_push (emit *_E, byte *_P, byte c, unsigned int _Pos, regbyte_ctx **_Ctx)
+{
+ while (_E != NULL)
+ {
+ if (_E->m_emit_dest == ed_output)
+ {
+ if (_E->m_emit_type == et_byte)
+ *_P++ = _E->m_byte;
+ else if (_E->m_emit_type == et_stream)
+ *_P++ = c;
+ else /* _Em->type == et_position */
+ {
+ *_P++ = (byte) (_Pos);
+ *_P++ = (byte) (_Pos >> 8);
+ *_P++ = (byte) (_Pos >> 16);
+ *_P++ = (byte) (_Pos >> 24);
+ }
+ }
+ else
+ {
+ regbyte_ctx *new_rbc;
+ regbyte_ctx_create (&new_rbc);
+ if (new_rbc == NULL)
+ return 1;
+
+ new_rbc->m_prev = *_Ctx;
+ new_rbc->m_regbyte = _E->m_regbyte;
+ *_Ctx = new_rbc;
+
+ if (_E->m_emit_type == et_byte)
+ new_rbc->m_current_value = _E->m_byte;
+ else if (_E->m_emit_type == et_stream)
+ new_rbc->m_current_value = c;
+ }
+
+ _E = _E->m_next;
+ }
+
+ return 0;
+}
+
+/*
+ error typedef
+*/
+typedef struct error_
+{
+ byte *m_text;
+ byte *m_token_name;
+ struct rule_ *m_token;
+} error;
+
+static void error_create (error **er)
+{
+ *er = (error *) mem_alloc (sizeof (error));
+ if (*er)
+ {
+ (**er).m_text = NULL;
+ (**er).m_token_name = NULL;
+ (**er).m_token = NULL;
+ }
+}
+
+static void error_destroy (error **er)
+{
+ if (*er)
+ {
+ mem_free ((void **) &(**er).m_text);
+ mem_free ((void **) &(**er).m_token_name);
+ mem_free ((void **) er);
+ }
+}
+
+struct dict_;
+static byte *error_get_token (error *, struct dict_ *, const byte *, unsigned int);
+
+/*
+ condition operand type typedef
+*/
+typedef enum cond_oper_type_
+{
+ cot_byte, /* constant 8-bit unsigned integer */
+ cot_regbyte /* pointer to byte register containing the current value */
+} cond_oper_type;
+
+/*
+ condition operand typedef
+*/
+typedef struct cond_oper_
+{
+ cond_oper_type m_type;
+ byte m_byte; /* cot_byte */
+ map_byte *m_regbyte; /* cot_regbyte */
+ byte *m_regname; /* cot_regbyte - temporary */
+} cond_oper;
+
+/*
+ condition type typedef
+*/
+typedef enum cond_type_
+{
+ ct_equal,
+ ct_not_equal
+} cond_type;
+
+/*
+ condition typedef
+*/
+typedef struct cond_
+{
+ cond_type m_type;
+ cond_oper m_operands[2];
+} cond;
+
+static void cond_create (cond **co)
+{
+ *co = (cond *) mem_alloc (sizeof (cond));
+ if (*co)
+ {
+ (**co).m_operands[0].m_regname = NULL;
+ (**co).m_operands[1].m_regname = NULL;
+ }
+}
+
+static void cond_destroy (cond **co)
+{
+ if (*co)
+ {
+ mem_free ((void **) &(**co).m_operands[0].m_regname);
+ mem_free ((void **) &(**co).m_operands[1].m_regname);
+ mem_free ((void **) co);
+ }
+}
+
+/*
+ specifier type typedef
+*/
+typedef enum spec_type_
+{
+ st_false,
+ st_true,
+ st_byte,
+ st_byte_range,
+ st_string,
+ st_identifier,
+ st_identifier_loop,
+ st_debug
+} spec_type;
+
+/*
+ specifier typedef
+*/
+typedef struct spec_
+{
+ spec_type m_spec_type;
+ byte m_byte[2]; /* st_byte, st_byte_range */
+ byte *m_string; /* st_string */
+ struct rule_ *m_rule; /* st_identifier, st_identifier_loop */
+ emit *m_emits;
+ error *m_errtext;
+ cond *m_cond;
+ struct spec_ *next;
+} spec;
+
+static void spec_create (spec **sp)
+{
+ *sp = (spec *) mem_alloc (sizeof (spec));
+ if (*sp)
+ {
+ (**sp).m_spec_type = st_false;
+ (**sp).m_byte[0] = '\0';
+ (**sp).m_byte[1] = '\0';
+ (**sp).m_string = NULL;
+ (**sp).m_rule = NULL;
+ (**sp).m_emits = NULL;
+ (**sp).m_errtext = NULL;
+ (**sp).m_cond = NULL;
+ (**sp).next = NULL;
+ }
+}
+
+static void spec_destroy (spec **sp)
+{
+ if (*sp)
+ {
+ spec_destroy (&(**sp).next);
+ emit_destroy (&(**sp).m_emits);
+ error_destroy (&(**sp).m_errtext);
+ mem_free ((void **) &(**sp).m_string);
+ cond_destroy (&(**sp).m_cond);
+ mem_free ((void **) sp);
+ }
+}
+
+GRAMMAR_IMPLEMENT_LIST_APPEND(spec)
+
+/*
+ operator typedef
+*/
+typedef enum oper_
+{
+ op_none,
+ op_and,
+ op_or
+} oper;
+
+/*
+ rule typedef
+*/
+typedef struct rule_
+{
+ oper m_oper;
+ spec *m_specs;
+ struct rule_ *next;
+ int m_referenced;
+} rule;
+
+static void rule_create (rule **ru)
+{
+ *ru = (rule *) mem_alloc (sizeof (rule));
+ if (*ru)
+ {
+ (**ru).m_oper = op_none;
+ (**ru).m_specs = NULL;
+ (**ru).next = NULL;
+ (**ru).m_referenced = 0;
+ }
+}
+
+static void rule_destroy (rule **ru)
+{
+ if (*ru)
+ {
+ rule_destroy (&(**ru).next);
+ spec_destroy (&(**ru).m_specs);
+ mem_free ((void **) ru);
+ }
+}
+
+GRAMMAR_IMPLEMENT_LIST_APPEND(rule)
+
+/*
+ returns unique grammar id
+*/
+static grammar next_valid_grammar_id (void)
+{
+ static grammar id = 0;
+
+ return ++id;
+}
+
+/*
+ dictionary typedef
+*/
+typedef struct dict_
+{
+ rule *m_rulez;
+ rule *m_syntax;
+ rule *m_string;
+ map_byte *m_regbytes;
+ grammar m_id;
+ struct dict_ *next;
+} dict;
+
+static void dict_create (dict **di)
+{
+ *di = (dict *) mem_alloc (sizeof (dict));
+ if (*di)
+ {
+ (**di).m_rulez = NULL;
+ (**di).m_syntax = NULL;
+ (**di).m_string = NULL;
+ (**di).m_regbytes = NULL;
+ (**di).m_id = next_valid_grammar_id ();
+ (**di).next = NULL;
+ }
+}
+
+static void dict_destroy (dict **di)
+{
+ if (*di)
+ {
+ rule_destroy (&(**di).m_rulez);
+ map_byte_destroy (&(**di).m_regbytes);
+ mem_free ((void **) di);
+ }
+}
+
+GRAMMAR_IMPLEMENT_LIST_APPEND(dict)
+
+static void dict_find (dict **di, grammar key, dict **data)
+{
+ while (*di)
+ {
+ if ((**di).m_id == key)
+ {
+ *data = *di;
+ return;
+ }
+
+ di = &(**di).next;
+ }
+
+ *data = NULL;
+}
+
+static dict *g_dicts = NULL;
+
+/*
+ byte array typedef
+*/
+typedef struct barray_
+{
+ byte *data;
+ unsigned int len;
+} barray;
+
+static void barray_create (barray **ba)
+{
+ *ba = (barray *) mem_alloc (sizeof (barray));
+ if (*ba)
+ {
+ (**ba).data = NULL;
+ (**ba).len = 0;
+ }
+}
+
+static void barray_destroy (barray **ba)
+{
+ if (*ba)
+ {
+ mem_free ((void **) &(**ba).data);
+ mem_free ((void **) ba);
+ }
+}
+
+/*
+ reallocates byte array to requested size,
+ returns 0 on success,
+ returns 1 otherwise
+*/
+static int barray_resize (barray **ba, unsigned int nlen)
+{
+ byte *new_pointer;
+
+ if (nlen == 0)
+ {
+ mem_free ((void **) &(**ba).data);
+ (**ba).data = NULL;
+ (**ba).len = 0;
+
+ return 0;
+ }
+ else
+ {
+ new_pointer = (byte *) mem_realloc ((**ba).data, (**ba).len * sizeof (byte),
+ nlen * sizeof (byte));
+ if (new_pointer)
+ {
+ (**ba).data = new_pointer;
+ (**ba).len = nlen;
+
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ adds byte array pointed by *nb to the end of array pointed by *ba,
+ returns 0 on success,
+ returns 1 otherwise
+*/
+static int barray_append (barray **ba, barray **nb)
+{
+ const unsigned int len = (**ba).len;
+
+ if (barray_resize (ba, (**ba).len + (**nb).len))
+ return 1;
+
+ mem_copy ((**ba).data + len, (**nb).data, (**nb).len);
+
+ return 0;
+}
+
+/*
+ adds emit chain pointed by em to the end of array pointed by *ba,
+ returns 0 on success,
+ returns 1 otherwise
+*/
+static int barray_push (barray **ba, emit *em, byte c, unsigned int pos, regbyte_ctx **rbc)
+{
+ unsigned int count = emit_size (em);
+
+ if (barray_resize (ba, (**ba).len + count))
+ return 1;
+
+ return emit_push (em, (**ba).data + ((**ba).len - count), c, pos, rbc);
+}
+
+/*
+ byte pool typedef
+*/
+typedef struct bytepool_
+{
+ byte *_F;
+ unsigned int _Siz;
+} bytepool;
+
+static void bytepool_destroy (bytepool **by)
+{
+ if (*by != NULL)
+ {
+ mem_free ((void **) &(**by)._F);
+ mem_free ((void **) by);
+ }
+}
+
+static void bytepool_create (bytepool **by, int len)
+{
+ *by = (bytepool *) (mem_alloc (sizeof (bytepool)));
+ if (*by != NULL)
+ {
+ (**by)._F = (byte *) (mem_alloc (sizeof (byte) * len));
+ (**by)._Siz = len;
+
+ if ((**by)._F == NULL)
+ bytepool_destroy (by);
+ }
+}
+
+static int bytepool_reserve (bytepool *by, unsigned int n)
+{
+ byte *_P;
+
+ if (n <= by->_Siz)
+ return 0;
+
+ /* byte pool can only grow and at least by doubling its size */
+ n = n >= by->_Siz * 2 ? n : by->_Siz * 2;
+
+ /* reallocate the memory and adjust pointers to the new memory location */
+ _P = (byte *) (mem_realloc (by->_F, sizeof (byte) * by->_Siz, sizeof (byte) * n));
+ if (_P != NULL)
+ {
+ by->_F = _P;
+ by->_Siz = n;
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ string to string map typedef
+*/
+typedef struct map_str_
+{
+ byte *key;
+ byte *data;
+ struct map_str_ *next;
+} map_str;
+
+static void map_str_create (map_str **ma)
+{
+ *ma = (map_str *) mem_alloc (sizeof (map_str));
+ if (*ma)
+ {
+ (**ma).key = NULL;
+ (**ma).data = NULL;
+ (**ma).next = NULL;
+ }
+}
+
+static void map_str_destroy (map_str **ma)
+{
+ if (*ma)
+ {
+ map_str_destroy (&(**ma).next);
+ mem_free ((void **) &(**ma).key);
+ mem_free ((void **) &(**ma).data);
+ mem_free ((void **) ma);
+ }
+}
+
+GRAMMAR_IMPLEMENT_LIST_APPEND(map_str)
+
+/*
+ searches the map for specified key,
+ if the key is matched, *data is filled with data associated with the key,
+ returns 0 if the key is matched,
+ returns 1 otherwise
+*/
+static int map_str_find (map_str **ma, const byte *key, byte **data)
+{
+ while (*ma)
+ {
+ if (str_equal ((**ma).key, key))
+ {
+ *data = str_duplicate ((**ma).data);
+ if (*data == NULL)
+ return 1;
+
+ return 0;
+ }
+
+ ma = &(**ma).next;
+ }
+
+ set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1);
+ return 1;
+}
+
+/*
+ string to rule map typedef
+*/
+typedef struct map_rule_
+{
+ byte *key;
+ rule *data;
+ struct map_rule_ *next;
+} map_rule;
+
+static void map_rule_create (map_rule **ma)
+{
+ *ma = (map_rule *) mem_alloc (sizeof (map_rule));
+ if (*ma)
+ {
+ (**ma).key = NULL;
+ (**ma).data = NULL;
+ (**ma).next = NULL;
+ }
+}
+
+static void map_rule_destroy (map_rule **ma)
+{
+ if (*ma)
+ {
+ map_rule_destroy (&(**ma).next);
+ mem_free ((void **) &(**ma).key);
+ mem_free ((void **) ma);
+ }
+}
+
+GRAMMAR_IMPLEMENT_LIST_APPEND(map_rule)
+
+/*
+ searches the map for specified key,
+ if the key is matched, *data is filled with data associated with the key,
+ returns 0 if the is matched,
+ returns 1 otherwise
+*/
+static int map_rule_find (map_rule **ma, const byte *key, rule **data)
+{
+ while (*ma)
+ {
+ if (str_equal ((**ma).key, key))
+ {
+ *data = (**ma).data;
+
+ return 0;
+ }
+
+ ma = &(**ma).next;
+ }
+
+ set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1);
+ return 1;
+}
+
+/*
+ returns 1 if given character is a white space,
+ returns 0 otherwise
+*/
+static int is_space (byte c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+}
+
+/*
+ advances text pointer by 1 if character pointed by *text is a space,
+ returns 1 if a space has been eaten,
+ returns 0 otherwise
+*/
+static int eat_space (const byte **text)
+{
+ if (is_space (**text))
+ {
+ (*text)++;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ returns 1 if text points to C-style comment start string,
+ returns 0 otherwise
+*/
+static int is_comment_start (const byte *text)
+{
+ return text[0] == '/' && text[1] == '*';
+}
+
+/*
+ advances text pointer to first character after C-style comment block - if any,
+ returns 1 if C-style comment block has been encountered and eaten,
+ returns 0 otherwise
+*/
+static int eat_comment (const byte **text)
+{
+ if (is_comment_start (*text))
+ {
+ /* *text points to comment block - skip two characters to enter comment body */
+ *text += 2;
+ /* skip any character except consecutive '*' and '/' */
+ while (!((*text)[0] == '*' && (*text)[1] == '/'))
+ (*text)++;
+ /* skip those two terminating characters */
+ *text += 2;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ advances text pointer to first character that is neither space nor C-style comment block
+*/
+static void eat_spaces (const byte **text)
+{
+ while (eat_space (text) || eat_comment (text))
+ ;
+}
+
+/*
+ resizes string pointed by *ptr to successfully add character c to the end of the string,
+ returns 0 on success,
+ returns 1 otherwise
+*/
+static int string_grow (byte **ptr, unsigned int *len, byte c)
+{
+ /* reallocate the string in 16-byte increments */
+ if ((*len & 0x0F) == 0x0F || *ptr == NULL)
+ {
+ byte *tmp = (byte *) mem_realloc (*ptr, ((*len + 1) & ~0x0F) * sizeof (byte),
+ ((*len + 1 + 0x10) & ~0x0F) * sizeof (byte));
+ if (tmp == NULL)
+ return 1;
+
+ *ptr = tmp;
+ }
+
+ if (c)
+ {
+ /* append given character */
+ (*ptr)[*len] = c;
+ (*len)++;
+ }
+ (*ptr)[*len] = '\0';
+
+ return 0;
+}
+
+/*
+ returns 1 if given character is a valid identifier character a-z, A-Z, 0-9 or _
+ returns 0 otherwise
+*/
+static int is_identifier (byte c)
+{
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
+}
+
+/*
+ copies characters from *text to *id until non-identifier character is encountered,
+ assumes that *id points to NULL object - caller is responsible for later freeing the string,
+ text pointer is advanced to point past the copied identifier,
+ returns 0 if identifier was successfully copied,
+ returns 1 otherwise
+*/
+static int get_identifier (const byte **text, byte **id)
+{
+ const byte *t = *text;
+ byte *p = NULL;
+ unsigned int len = 0;
+
+ if (string_grow (&p, &len, '\0'))
+ return 1;
+
+ /* loop while next character in buffer is valid for identifiers */
+ while (is_identifier (*t))
+ {
+ if (string_grow (&p, &len, *t++))
+ {
+ mem_free ((void **) (void *) &p);
+ return 1;
+ }
+ }
+
+ *text = t;
+ *id = p;
+
+ return 0;
+}
+
+/*
+ converts sequence of DEC digits pointed by *text until non-DEC digit is encountered,
+ advances text pointer past the converted sequence,
+ returns the converted value
+*/
+static unsigned int dec_convert (const byte **text)
+{
+ unsigned int value = 0;
+
+ while (**text >= '0' && **text <= '9')
+ {
+ value = value * 10 + **text - '0';
+ (*text)++;
+ }
+
+ return value;
+}
+
+/*
+ returns 1 if given character is HEX digit 0-9, A-F or a-f,
+ returns 0 otherwise
+*/
+static int is_hex (byte c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+}
+
+/*
+ returns value of passed character as if it was HEX digit
+*/
+static unsigned int hex2dec (byte c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return c - 'a' + 10;
+}
+
+/*
+ converts sequence of HEX digits pointed by *text until non-HEX digit is encountered,
+ advances text pointer past the converted sequence,
+ returns the converted value
+*/
+static unsigned int hex_convert (const byte **text)
+{
+ unsigned int value = 0;
+
+ while (is_hex (**text))
+ {
+ value = value * 0x10 + hex2dec (**text);
+ (*text)++;
+ }
+
+ return value;
+}
+
+/*
+ returns 1 if given character is OCT digit 0-7,
+ returns 0 otherwise
+*/
+static int is_oct (byte c)
+{
+ return c >= '0' && c <= '7';
+}
+
+/*
+ returns value of passed character as if it was OCT digit
+*/
+static int oct2dec (byte c)
+{
+ return c - '0';
+}
+
+static byte get_escape_sequence (const byte **text)
+{
+ int value = 0;
+
+ /* skip '\' character */
+ (*text)++;
+
+ switch (*(*text)++)
+ {
+ case '\'':
+ return '\'';
+ case '"':
+ return '\"';
+ case '?':
+ return '\?';
+ case '\\':
+ return '\\';
+ case 'a':
+ return '\a';
+ case 'b':
+ return '\b';
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case 'x':
+ return (byte) hex_convert (text);
+ }
+
+ (*text)--;
+ if (is_oct (**text))
+ {
+ value = oct2dec (*(*text)++);
+ if (is_oct (**text))
+ {
+ value = value * 010 + oct2dec (*(*text)++);
+ if (is_oct (**text))
+ value = value * 010 + oct2dec (*(*text)++);
+ }
+ }
+
+ return (byte) value;
+}
+
+/*
+ copies characters from *text to *str until " or ' character is encountered,
+ assumes that *str points to NULL object - caller is responsible for later freeing the string,
+ assumes that *text points to " or ' character that starts the string,
+ text pointer is advanced to point past the " or ' character,
+ returns 0 if string was successfully copied,
+ returns 1 otherwise
+*/
+static int get_string (const byte **text, byte **str)
+{
+ const byte *t = *text;
+ byte *p = NULL;
+ unsigned int len = 0;
+ byte term_char;
+
+ if (string_grow (&p, &len, '\0'))
+ return 1;
+
+ /* read " or ' character that starts the string */
+ term_char = *t++;
+ /* while next character is not the terminating character */
+ while (*t && *t != term_char)
+ {
+ byte c;
+
+ if (*t == '\\')
+ c = get_escape_sequence (&t);
+ else
+ c = *t++;
+
+ if (string_grow (&p, &len, c))
+ {
+ mem_free ((void **) (void *) &p);
+ return 1;
+ }
+ }
+ /* skip " or ' character that ends the string */
+ t++;
+
+ *text = t;
+ *str = p;
+ return 0;
+}
+
+/*
+ gets emit code, the syntax is:
+ ".emtcode" " " <symbol> " " (("0x" | "0X") <hex_value>) | <dec_value> | <character>
+ assumes that *text already points to <symbol>,
+ returns 0 if emit code is successfully read,
+ returns 1 otherwise
+*/
+static int get_emtcode (const byte **text, map_byte **ma)
+{
+ const byte *t = *text;
+ map_byte *m = NULL;
+
+ map_byte_create (&m);
+ if (m == NULL)
+ return 1;
+
+ if (get_identifier (&t, &m->key))
+ {
+ map_byte_destroy (&m);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ if (*t == '\'')
+ {
+ byte *c;
+
+ if (get_string (&t, &c))
+ {
+ map_byte_destroy (&m);
+ return 1;
+ }
+
+ m->data = (byte) c[0];
+ mem_free ((void **) (void *) &c);
+ }
+ else if (t[0] == '0' && (t[1] == 'x' || t[1] == 'X'))
+ {
+ /* skip HEX "0x" or "0X" prefix */
+ t += 2;
+ m->data = (byte) hex_convert (&t);
+ }
+ else
+ {
+ m->data = (byte) dec_convert (&t);
+ }
+
+ eat_spaces (&t);
+
+ *text = t;
+ *ma = m;
+ return 0;
+}
+
+/*
+ gets regbyte declaration, the syntax is:
+ ".regbyte" " " <symbol> " " (("0x" | "0X") <hex_value>) | <dec_value> | <character>
+ assumes that *text already points to <symbol>,
+ returns 0 if regbyte is successfully read,
+ returns 1 otherwise
+*/
+static int get_regbyte (const byte **text, map_byte **ma)
+{
+ /* pass it to the emtcode parser as it has the same syntax starting at <symbol> */
+ return get_emtcode (text, ma);
+}
+
+/*
+ returns 0 on success,
+ returns 1 otherwise
+*/
+static int get_errtext (const byte **text, map_str **ma)
+{
+ const byte *t = *text;
+ map_str *m = NULL;
+
+ map_str_create (&m);
+ if (m == NULL)
+ return 1;
+
+ if (get_identifier (&t, &m->key))
+ {
+ map_str_destroy (&m);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ if (get_string (&t, &m->data))
+ {
+ map_str_destroy (&m);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ *text = t;
+ *ma = m;
+ return 0;
+}
+
+/*
+ returns 0 on success,
+ returns 1 otherwise,
+*/
+static int get_error (const byte **text, error **er, map_str *maps)
+{
+ const byte *t = *text;
+ byte *temp = NULL;
+
+ if (*t != '.')
+ return 0;
+
+ t++;
+ if (get_identifier (&t, &temp))
+ return 1;
+ eat_spaces (&t);
+
+ if (!str_equal ((byte *) "error", temp))
+ {
+ mem_free ((void **) (void *) &temp);
+ return 0;
+ }
+
+ mem_free ((void **) (void *) &temp);
+
+ error_create (er);
+ if (*er == NULL)
+ return 1;
+
+ if (*t == '\"')
+ {
+ if (get_string (&t, &(**er).m_text))
+ {
+ error_destroy (er);
+ return 1;
+ }
+ eat_spaces (&t);
+ }
+ else
+ {
+ if (get_identifier (&t, &temp))
+ {
+ error_destroy (er);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ if (map_str_find (&maps, temp, &(**er).m_text))
+ {
+ mem_free ((void **) (void *) &temp);
+ error_destroy (er);
+ return 1;
+ }
+
+ mem_free ((void **) (void *) &temp);
+ }
+
+ /* try to extract "token" from "...$token$..." */
+ {
+ byte *processed = NULL;
+ unsigned int len = 0, i = 0;
+
+ if (string_grow (&processed, &len, '\0'))
+ {
+ error_destroy (er);
+ return 1;
+ }
+
+ while (i < str_length ((**er).m_text))
+ {
+ /* check if the dollar sign is repeated - if so skip it */
+ if ((**er).m_text[i] == '$' && (**er).m_text[i + 1] == '$')
+ {
+ if (string_grow (&processed, &len, '$'))
+ {
+ mem_free ((void **) (void *) &processed);
+ error_destroy (er);
+ return 1;
+ }
+
+ i += 2;
+ }
+ else if ((**er).m_text[i] != '$')
+ {
+ if (string_grow (&processed, &len, (**er).m_text[i]))
+ {
+ mem_free ((void **) (void *) &processed);
+ error_destroy (er);
+ return 1;
+ }
+
+ i++;
+ }
+ else
+ {
+ if (string_grow (&processed, &len, '$'))
+ {
+ mem_free ((void **) (void *) &processed);
+ error_destroy (er);
+ return 1;
+ }
+
+ {
+ /* length of token being extracted */
+ unsigned int tlen = 0;
+
+ if (string_grow (&(**er).m_token_name, &tlen, '\0'))
+ {
+ mem_free ((void **) (void *) &processed);
+ error_destroy (er);
+ return 1;
+ }
+
+ /* skip the dollar sign */
+ i++;
+
+ while ((**er).m_text[i] != '$')
+ {
+ if (string_grow (&(**er).m_token_name, &tlen, (**er).m_text[i]))
+ {
+ mem_free ((void **) (void *) &processed);
+ error_destroy (er);
+ return 1;
+ }
+
+ i++;
+ }
+
+ /* skip the dollar sign */
+ i++;
+ }
+ }
+ }
+
+ mem_free ((void **) &(**er).m_text);
+ (**er).m_text = processed;
+ }
+
+ *text = t;
+ return 0;
+}
+
+/*
+ returns 0 on success,
+ returns 1 otherwise,
+*/
+static int get_emits (const byte **text, emit **em, map_byte *mapb)
+{
+ const byte *t = *text;
+ byte *temp = NULL;
+ emit *e = NULL;
+ emit_dest dest;
+
+ if (*t != '.')
+ return 0;
+
+ t++;
+ if (get_identifier (&t, &temp))
+ return 1;
+ eat_spaces (&t);
+
+ /* .emit */
+ if (str_equal ((byte *) "emit", temp))
+ dest = ed_output;
+ /* .load */
+ else if (str_equal ((byte *) "load", temp))
+ dest = ed_regbyte;
+ else
+ {
+ mem_free ((void **) (void *) &temp);
+ return 0;
+ }
+
+ mem_free ((void **) (void *) &temp);
+
+ emit_create (&e);
+ if (e == NULL)
+ return 1;
+
+ e->m_emit_dest = dest;
+
+ if (dest == ed_regbyte)
+ {
+ if (get_identifier (&t, &e->m_regname))
+ {
+ emit_destroy (&e);
+ return 1;
+ }
+ eat_spaces (&t);
+ }
+
+ /* 0xNN */
+ if (*t == '0' && (t[1] == 'x' || t[1] == 'X'))
+ {
+ t += 2;
+ e->m_byte = (byte) hex_convert (&t);
+
+ e->m_emit_type = et_byte;
+ }
+ /* NNN */
+ else if (*t >= '0' && *t <= '9')
+ {
+ e->m_byte = (byte) dec_convert (&t);
+
+ e->m_emit_type = et_byte;
+ }
+ /* * */
+ else if (*t == '*')
+ {
+ t++;
+
+ e->m_emit_type = et_stream;
+ }
+ /* $ */
+ else if (*t == '$')
+ {
+ t++;
+
+ e->m_emit_type = et_position;
+ }
+ /* 'c' */
+ else if (*t == '\'')
+ {
+ if (get_string (&t, &temp))
+ {
+ emit_destroy (&e);
+ return 1;
+ }
+ e->m_byte = (byte) temp[0];
+
+ mem_free ((void **) (void *) &temp);
+
+ e->m_emit_type = et_byte;
+ }
+ else
+ {
+ if (get_identifier (&t, &temp))
+ {
+ emit_destroy (&e);
+ return 1;
+ }
+
+ if (map_byte_find (&mapb, temp, &e->m_byte))
+ {
+ mem_free ((void **) (void *) &temp);
+ emit_destroy (&e);
+ return 1;
+ }
+
+ mem_free ((void **) (void *) &temp);
+
+ e->m_emit_type = et_byte;
+ }
+
+ eat_spaces (&t);
+
+ if (get_emits (&t, &e->m_next, mapb))
+ {
+ emit_destroy (&e);
+ return 1;
+ }
+
+ *text = t;
+ *em = e;
+ return 0;
+}
+
+/*
+ returns 0 on success,
+ returns 1 otherwise,
+*/
+static int get_spec (const byte **text, spec **sp, map_str *maps, map_byte *mapb)
+{
+ const byte *t = *text;
+ spec *s = NULL;
+
+ spec_create (&s);
+ if (s == NULL)
+ return 1;
+
+ /* first - read optional .if statement */
+ if (*t == '.')
+ {
+ const byte *u = t;
+ byte *keyword = NULL;
+
+ /* skip the dot */
+ u++;
+
+ if (get_identifier (&u, &keyword))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+
+ /* .if */
+ if (str_equal ((byte *) "if", keyword))
+ {
+ cond_create (&s->m_cond);
+ if (s->m_cond == NULL)
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+
+ /* skip the left paren */
+ eat_spaces (&u);
+ u++;
+
+ /* get the left operand */
+ eat_spaces (&u);
+ if (get_identifier (&u, &s->m_cond->m_operands[0].m_regname))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+ s->m_cond->m_operands[0].m_type = cot_regbyte;
+
+ /* get the operator (!= or ==) */
+ eat_spaces (&u);
+ if (*u == '!')
+ s->m_cond->m_type = ct_not_equal;
+ else
+ s->m_cond->m_type = ct_equal;
+ u += 2;
+ eat_spaces (&u);
+
+ if (u[0] == '0' && (u[1] == 'x' || u[1] == 'X'))
+ {
+ /* skip the 0x prefix */
+ u += 2;
+
+ /* get the right operand */
+ s->m_cond->m_operands[1].m_byte = hex_convert (&u);
+ s->m_cond->m_operands[1].m_type = cot_byte;
+ }
+ else /*if (*u >= '0' && *u <= '9')*/
+ {
+ /* get the right operand */
+ s->m_cond->m_operands[1].m_byte = dec_convert (&u);
+ s->m_cond->m_operands[1].m_type = cot_byte;
+ }
+
+ /* skip the right paren */
+ eat_spaces (&u);
+ u++;
+
+ eat_spaces (&u);
+
+ t = u;
+ }
+
+ mem_free ((void **) (void *) &keyword);
+ }
+
+ if (*t == '\'')
+ {
+ byte *temp = NULL;
+
+ if (get_string (&t, &temp))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ if (*t == '-')
+ {
+ byte *temp2 = NULL;
+
+ /* skip the '-' character */
+ t++;
+ eat_spaces (&t);
+
+ if (get_string (&t, &temp2))
+ {
+ mem_free ((void **) (void *) &temp);
+ spec_destroy (&s);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ s->m_spec_type = st_byte_range;
+ s->m_byte[0] = *temp;
+ s->m_byte[1] = *temp2;
+
+ mem_free ((void **) (void *) &temp2);
+ }
+ else
+ {
+ s->m_spec_type = st_byte;
+ *s->m_byte = *temp;
+ }
+
+ mem_free ((void **) (void *) &temp);
+ }
+ else if (*t == '"')
+ {
+ if (get_string (&t, &s->m_string))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ s->m_spec_type = st_string;
+ }
+ else if (*t == '.')
+ {
+ byte *keyword = NULL;
+
+ /* skip the dot */
+ t++;
+
+ if (get_identifier (&t, &keyword))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ /* .true */
+ if (str_equal ((byte *) "true", keyword))
+ {
+ s->m_spec_type = st_true;
+ }
+ /* .false */
+ else if (str_equal ((byte *) "false", keyword))
+ {
+ s->m_spec_type = st_false;
+ }
+ /* .debug */
+ else if (str_equal ((byte *) "debug", keyword))
+ {
+ s->m_spec_type = st_debug;
+ }
+ /* .loop */
+ else if (str_equal ((byte *) "loop", keyword))
+ {
+ if (get_identifier (&t, &s->m_string))
+ {
+ mem_free ((void **) (void *) &keyword);
+ spec_destroy (&s);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ s->m_spec_type = st_identifier_loop;
+ }
+ mem_free ((void **) (void *) &keyword);
+ }
+ else
+ {
+ if (get_identifier (&t, &s->m_string))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ s->m_spec_type = st_identifier;
+ }
+
+ if (get_error (&t, &s->m_errtext, maps))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+
+ if (get_emits (&t, &s->m_emits, mapb))
+ {
+ spec_destroy (&s);
+ return 1;
+ }
+
+ *text = t;
+ *sp = s;
+ return 0;
+}
+
+/*
+ returns 0 on success,
+ returns 1 otherwise,
+*/
+static int get_rule (const byte **text, rule **ru, map_str *maps, map_byte *mapb)
+{
+ const byte *t = *text;
+ rule *r = NULL;
+
+ rule_create (&r);
+ if (r == NULL)
+ return 1;
+
+ if (get_spec (&t, &r->m_specs, maps, mapb))
+ {
+ rule_destroy (&r);
+ return 1;
+ }
+
+ while (*t != ';')
+ {
+ byte *op = NULL;
+ spec *sp = NULL;
+
+ /* skip the dot that precedes "and" or "or" */
+ t++;
+
+ /* read "and" or "or" keyword */
+ if (get_identifier (&t, &op))
+ {
+ rule_destroy (&r);
+ return 1;
+ }
+ eat_spaces (&t);
+
+ if (r->m_oper == op_none)
+ {
+ /* .and */
+ if (str_equal ((byte *) "and", op))
+ r->m_oper = op_and;
+ /* .or */
+ else
+ r->m_oper = op_or;
+ }
+
+ mem_free ((void **) (void *) &op);
+
+ if (get_spec (&t, &sp, maps, mapb))
+ {
+ rule_destroy (&r);
+ return 1;
+ }
+
+ spec_append (&r->m_specs, sp);
+ }
+
+ /* skip the semicolon */
+ t++;
+ eat_spaces (&t);
+
+ *text = t;
+ *ru = r;
+ return 0;
+}
+
+/*
+ returns 0 on success,
+ returns 1 otherwise,
+*/
+static int update_dependency (map_rule *mapr, byte *symbol, rule **ru)
+{
+ if (map_rule_find (&mapr, symbol, ru))
+ return 1;
+
+ (**ru).m_referenced = 1;
+
+ return 0;
+}
+
+/*
+ returns 0 on success,
+ returns 1 otherwise,
+*/
+static int update_dependencies (dict *di, map_rule *mapr, byte **syntax_symbol,
+ byte **string_symbol, map_byte *regbytes)
+{
+ rule *rulez = di->m_rulez;
+
+ /* update dependecies for the root and lexer symbols */
+ if (update_dependency (mapr, *syntax_symbol, &di->m_syntax) ||
+ (*string_symbol != NULL && update_dependency (mapr, *string_symbol, &di->m_string)))
+ return 1;
+
+ mem_free ((void **) syntax_symbol);
+ mem_free ((void **) string_symbol);
+
+ /* update dependecies for the rest of the rules */
+ while (rulez)
+ {
+ spec *sp = rulez->m_specs;
+
+ /* iterate through all the specifiers */
+ while (sp)
+ {
+ /* update dependency for identifier */
+ if (sp->m_spec_type == st_identifier || sp->m_spec_type == st_identifier_loop)
+ {
+ if (update_dependency (mapr, sp->m_string, &sp->m_rule))
+ return 1;
+
+ mem_free ((void **) &sp->m_string);
+ }
+
+ /* some errtexts reference to a rule */
+ if (sp->m_errtext && sp->m_errtext->m_token_name)
+ {
+ if (update_dependency (mapr, sp->m_errtext->m_token_name, &sp->m_errtext->m_token))
+ return 1;
+
+ mem_free ((void **) &sp->m_errtext->m_token_name);
+ }
+
+ /* update dependency for condition */
+ if (sp->m_cond)
+ {
+ int i;
+ for (i = 0; i < 2; i++)
+ if (sp->m_cond->m_operands[i].m_type == cot_regbyte)
+ {
+ sp->m_cond->m_operands[i].m_regbyte = map_byte_locate (&regbytes,
+ sp->m_cond->m_operands[i].m_regname);
+
+ if (sp->m_cond->m_operands[i].m_regbyte == NULL)
+ return 1;
+
+ mem_free ((void **) &sp->m_cond->m_operands[i].m_regname);
+ }
+ }
+
+ /* update dependency for all .load instructions */
+ if (sp->m_emits)
+ {
+ emit *em = sp->m_emits;
+ while (em != NULL)
+ {
+ if (em->m_emit_dest == ed_regbyte)
+ {
+ em->m_regbyte = map_byte_locate (&regbytes, em->m_regname);
+
+ if (em->m_regbyte == NULL)
+ return 1;
+
+ mem_free ((void **) &em->m_regname);
+ }
+
+ em = em->m_next;
+ }
+ }
+
+ sp = sp->next;
+ }
+
+ rulez = rulez->next;
+ }
+
+ /* check for unreferenced symbols */
+ rulez = di->m_rulez;
+ while (rulez != NULL)
+ {
+ if (!rulez->m_referenced)
+ {
+ map_rule *ma = mapr;
+ while (ma)
+ {
+ if (ma->data == rulez)
+ {
+ set_last_error (UNREFERENCED_IDENTIFIER, str_duplicate (ma->key), -1);
+ return 1;
+ }
+ ma = ma->next;
+ }
+ }
+ rulez = rulez->next;
+ }
+
+ return 0;
+}
+
+static int satisfies_condition (cond *co, regbyte_ctx *ctx)
+{
+ byte values[2];
+ int i;
+
+ if (co == NULL)
+ return 1;
+
+ for (i = 0; i < 2; i++)
+ switch (co->m_operands[i].m_type)
+ {
+ case cot_byte:
+ values[i] = co->m_operands[i].m_byte;
+ break;
+ case cot_regbyte:
+ values[i] = regbyte_ctx_extract (&ctx, co->m_operands[i].m_regbyte);
+ break;
+ }
+
+ switch (co->m_type)
+ {
+ case ct_equal:
+ return values[0] == values[1];
+ case ct_not_equal:
+ return values[0] != values[1];
+ }
+
+ return 0;
+}
+
+static void free_regbyte_ctx_stack (regbyte_ctx *top, regbyte_ctx *limit)
+{
+ while (top != limit)
+ {
+ regbyte_ctx *rbc = top->m_prev;
+ regbyte_ctx_destroy (&top);
+ top = rbc;
+ }
+}
+
+typedef enum match_result_
+{
+ mr_not_matched, /* the examined string does not match */
+ mr_matched, /* the examined string matches */
+ mr_error_raised, /* mr_not_matched + error has been raised */
+ mr_dont_emit, /* used by identifier loops only */
+ mr_internal_error /* an internal error has occured such as out of memory */
+} match_result;
+
+/*
+ This function does the main job. It parses the text and generates output data.
+*/
+static match_result match (dict *di, const byte *text, unsigned int *index, rule *ru, barray **ba,
+ int filtering_string, regbyte_ctx **rbc)
+{
+ unsigned int ind = *index;
+ match_result status = mr_not_matched;
+ spec *sp = ru->m_specs;
+ regbyte_ctx *ctx = *rbc;
+
+ /* for every specifier in the rule */
+ while (sp)
+ {
+ unsigned int i, len, save_ind = ind;
+ barray *array = NULL;
+
+ if (satisfies_condition (sp->m_cond, ctx))
+ {
+ switch (sp->m_spec_type)
+ {
+ case st_identifier:
+ barray_create (&array);
+ if (array == NULL)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+
+ status = match (di, text, &ind, sp->m_rule, &array, filtering_string, &ctx);
+
+ if (status == mr_internal_error)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&array);
+ return mr_internal_error;
+ }
+ break;
+ case st_string:
+ len = str_length (sp->m_string);
+
+ /* prefilter the stream */
+ if (!filtering_string && di->m_string)
+ {
+ barray *ba;
+ unsigned int filter_index = 0;
+ match_result result;
+ regbyte_ctx *null_ctx = NULL;
+
+ barray_create (&ba);
+ if (ba == NULL)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+
+ result = match (di, text + ind, &filter_index, di->m_string, &ba, 1, &null_ctx);
+
+ if (result == mr_internal_error)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&ba);
+ return mr_internal_error;
+ }
+
+ if (result != mr_matched)
+ {
+ barray_destroy (&ba);
+ status = mr_not_matched;
+ break;
+ }
+
+ barray_destroy (&ba);
+
+ if (filter_index != len || !str_equal_n (sp->m_string, text + ind, len))
+ {
+ status = mr_not_matched;
+ break;
+ }
+
+ status = mr_matched;
+ ind += len;
+ }
+ else
+ {
+ status = mr_matched;
+ for (i = 0; status == mr_matched && i < len; i++)
+ if (text[ind + i] != sp->m_string[i])
+ status = mr_not_matched;
+
+ if (status == mr_matched)
+ ind += len;
+ }
+ break;
+ case st_byte:
+ status = text[ind] == *sp->m_byte ? mr_matched : mr_not_matched;
+ if (status == mr_matched)
+ ind++;
+ break;
+ case st_byte_range:
+ status = (text[ind] >= sp->m_byte[0] && text[ind] <= sp->m_byte[1]) ?
+ mr_matched : mr_not_matched;
+ if (status == mr_matched)
+ ind++;
+ break;
+ case st_true:
+ status = mr_matched;
+ break;
+ case st_false:
+ status = mr_not_matched;
+ break;
+ case st_debug:
+ status = ru->m_oper == op_and ? mr_matched : mr_not_matched;
+ break;
+ case st_identifier_loop:
+ barray_create (&array);
+ if (array == NULL)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+
+ status = mr_dont_emit;
+ for (;;)
+ {
+ match_result result;
+
+ save_ind = ind;
+ result = match (di, text, &ind, sp->m_rule, &array, filtering_string, &ctx);
+
+ if (result == mr_error_raised)
+ {
+ status = result;
+ break;
+ }
+ else if (result == mr_matched)
+ {
+ if (barray_push (ba, sp->m_emits, text[ind - 1], save_ind, &ctx) ||
+ barray_append (ba, &array))
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&array);
+ return mr_internal_error;
+ }
+ barray_destroy (&array);
+ barray_create (&array);
+ if (array == NULL)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+ }
+ else if (result == mr_internal_error)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&array);
+ return mr_internal_error;
+ }
+ else
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ status = mr_not_matched;
+ }
+
+ if (status == mr_error_raised)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&array);
+
+ return mr_error_raised;
+ }
+
+ if (ru->m_oper == op_and && status != mr_matched && status != mr_dont_emit)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&array);
+
+ if (sp->m_errtext)
+ {
+ set_last_error (sp->m_errtext->m_text, error_get_token (sp->m_errtext, di, text,
+ ind), ind);
+
+ return mr_error_raised;
+ }
+
+ return mr_not_matched;
+ }
+
+ if (status == mr_matched)
+ {
+ if (sp->m_emits)
+ if (barray_push (ba, sp->m_emits, text[ind - 1], save_ind, &ctx))
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&array);
+ return mr_internal_error;
+ }
+
+ if (array)
+ if (barray_append (ba, &array))
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ barray_destroy (&array);
+ return mr_internal_error;
+ }
+ }
+
+ barray_destroy (&array);
+
+ /* if the rule operator is a logical or, we pick up the first matching specifier */
+ if (ru->m_oper == op_or && (status == mr_matched || status == mr_dont_emit))
+ {
+ *index = ind;
+ *rbc = ctx;
+ return mr_matched;
+ }
+
+ sp = sp->next;
+ }
+
+ /* everything went fine - all specifiers match up */
+ if (ru->m_oper == op_and && (status == mr_matched || status == mr_dont_emit))
+ {
+ *index = ind;
+ *rbc = ctx;
+ return mr_matched;
+ }
+
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_not_matched;
+}
+
+static match_result fast_match (dict *di, const byte *text, unsigned int *index, rule *ru, int *_PP, bytepool *_BP,
+ int filtering_string, regbyte_ctx **rbc)
+{
+ unsigned int ind = *index;
+ int _P = filtering_string ? 0 : *_PP;
+ int _P2;
+ match_result status = mr_not_matched;
+ spec *sp = ru->m_specs;
+ regbyte_ctx *ctx = *rbc;
+
+ /* for every specifier in the rule */
+ while (sp)
+ {
+ unsigned int i, len, save_ind = ind;
+
+ _P2 = _P + (sp->m_emits ? emit_size (sp->m_emits) : 0);
+ if (bytepool_reserve (_BP, _P2))
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+
+ if (satisfies_condition (sp->m_cond, ctx))
+ {
+ switch (sp->m_spec_type)
+ {
+ case st_identifier:
+ status = fast_match (di, text, &ind, sp->m_rule, &_P2, _BP, filtering_string, &ctx);
+
+ if (status == mr_internal_error)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+ break;
+ case st_string:
+ len = str_length (sp->m_string);
+
+ /* prefilter the stream */
+ if (!filtering_string && di->m_string)
+ {
+ unsigned int filter_index = 0;
+ match_result result;
+ regbyte_ctx *null_ctx = NULL;
+
+ result = fast_match (di, text + ind, &filter_index, di->m_string, NULL, _BP, 1, &null_ctx);
+
+ if (result == mr_internal_error)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+
+ if (result != mr_matched)
+ {
+ status = mr_not_matched;
+ break;
+ }
+
+ if (filter_index != len || !str_equal_n (sp->m_string, text + ind, len))
+ {
+ status = mr_not_matched;
+ break;
+ }
+
+ status = mr_matched;
+ ind += len;
+ }
+ else
+ {
+ status = mr_matched;
+ for (i = 0; status == mr_matched && i < len; i++)
+ if (text[ind + i] != sp->m_string[i])
+ status = mr_not_matched;
+
+ if (status == mr_matched)
+ ind += len;
+ }
+ break;
+ case st_byte:
+ status = text[ind] == *sp->m_byte ? mr_matched : mr_not_matched;
+ if (status == mr_matched)
+ ind++;
+ break;
+ case st_byte_range:
+ status = (text[ind] >= sp->m_byte[0] && text[ind] <= sp->m_byte[1]) ?
+ mr_matched : mr_not_matched;
+ if (status == mr_matched)
+ ind++;
+ break;
+ case st_true:
+ status = mr_matched;
+ break;
+ case st_false:
+ status = mr_not_matched;
+ break;
+ case st_debug:
+ status = ru->m_oper == op_and ? mr_matched : mr_not_matched;
+ break;
+ case st_identifier_loop:
+ status = mr_dont_emit;
+ for (;;)
+ {
+ match_result result;
+
+ save_ind = ind;
+ result = fast_match (di, text, &ind, sp->m_rule, &_P2, _BP, filtering_string, &ctx);
+
+ if (result == mr_error_raised)
+ {
+ status = result;
+ break;
+ }
+ else if (result == mr_matched)
+ {
+ if (!filtering_string)
+ {
+ if (sp->m_emits != NULL)
+ {
+ if (emit_push (sp->m_emits, _BP->_F + _P, text[ind - 1], save_ind, &ctx))
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+ }
+
+ _P = _P2;
+ _P2 += sp->m_emits ? emit_size (sp->m_emits) : 0;
+ if (bytepool_reserve (_BP, _P2))
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+ }
+ }
+ else if (result == mr_internal_error)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+ else
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ status = mr_not_matched;
+ }
+
+ if (status == mr_error_raised)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+
+ return mr_error_raised;
+ }
+
+ if (ru->m_oper == op_and && status != mr_matched && status != mr_dont_emit)
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+
+ if (sp->m_errtext)
+ {
+ set_last_error (sp->m_errtext->m_text, error_get_token (sp->m_errtext, di, text,
+ ind), ind);
+
+ return mr_error_raised;
+ }
+
+ return mr_not_matched;
+ }
+
+ if (status == mr_matched)
+ {
+ if (sp->m_emits != NULL)
+ if (emit_push (sp->m_emits, _BP->_F + _P, text[ind - 1], save_ind, &ctx))
+ {
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_internal_error;
+ }
+
+ _P = _P2;
+ }
+
+ /* if the rule operator is a logical or, we pick up the first matching specifier */
+ if (ru->m_oper == op_or && (status == mr_matched || status == mr_dont_emit))
+ {
+ *index = ind;
+ *rbc = ctx;
+ if (!filtering_string)
+ *_PP = _P;
+ return mr_matched;
+ }
+
+ sp = sp->next;
+ }
+
+ /* everything went fine - all specifiers match up */
+ if (ru->m_oper == op_and && (status == mr_matched || status == mr_dont_emit))
+ {
+ *index = ind;
+ *rbc = ctx;
+ if (!filtering_string)
+ *_PP = _P;
+ return mr_matched;
+ }
+
+ free_regbyte_ctx_stack (ctx, *rbc);
+ return mr_not_matched;
+}
+
+static byte *error_get_token (error *er, dict *di, const byte *text, unsigned int ind)
+{
+ byte *str = NULL;
+
+ if (er->m_token)
+ {
+ barray *ba;
+ unsigned int filter_index = 0;
+ regbyte_ctx *ctx = NULL;
+
+ barray_create (&ba);
+ if (ba != NULL)
+ {
+ if (match (di, text + ind, &filter_index, er->m_token, &ba, 0, &ctx) == mr_matched &&
+ filter_index)
+ {
+ str = (byte *) mem_alloc (filter_index + 1);
+ if (str != NULL)
+ {
+ str_copy_n (str, text + ind, filter_index);
+ str[filter_index] = '\0';
+ }
+ }
+ barray_destroy (&ba);
+ }
+ }
+
+ return str;
+}
+
+typedef struct grammar_load_state_
+{
+ dict *di;
+ byte *syntax_symbol;
+ byte *string_symbol;
+ map_str *maps;
+ map_byte *mapb;
+ map_rule *mapr;
+} grammar_load_state;
+
+static void grammar_load_state_create (grammar_load_state **gr)
+{
+ *gr = (grammar_load_state *) mem_alloc (sizeof (grammar_load_state));
+ if (*gr)
+ {
+ (**gr).di = NULL;
+ (**gr).syntax_symbol = NULL;
+ (**gr).string_symbol = NULL;
+ (**gr).maps = NULL;
+ (**gr).mapb = NULL;
+ (**gr).mapr = NULL;
+ }
+}
+
+static void grammar_load_state_destroy (grammar_load_state **gr)
+{
+ if (*gr)
+ {
+ dict_destroy (&(**gr).di);
+ mem_free ((void **) &(**gr).syntax_symbol);
+ mem_free ((void **) &(**gr).string_symbol);
+ map_str_destroy (&(**gr).maps);
+ map_byte_destroy (&(**gr).mapb);
+ map_rule_destroy (&(**gr).mapr);
+ mem_free ((void **) gr);
+ }
+}
+
+/*
+ the API
+*/
+
+grammar grammar_load_from_text (const byte *text)
+{
+ grammar_load_state *g = NULL;
+ grammar id = 0;
+
+ clear_last_error ();
+
+ grammar_load_state_create (&g);
+ if (g == NULL)
+ return 0;
+
+ dict_create (&g->di);
+ if (g->di == NULL)
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ eat_spaces (&text);
+
+ /* skip ".syntax" keyword */
+ text += 7;
+ eat_spaces (&text);
+
+ /* retrieve root symbol */
+ if (get_identifier (&text, &g->syntax_symbol))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+ eat_spaces (&text);
+
+ /* skip semicolon */
+ text++;
+ eat_spaces (&text);
+
+ while (*text)
+ {
+ byte *symbol = NULL;
+ int is_dot = *text == '.';
+
+ if (is_dot)
+ text++;
+
+ if (get_identifier (&text, &symbol))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+ eat_spaces (&text);
+
+ /* .emtcode */
+ if (is_dot && str_equal (symbol, (byte *) "emtcode"))
+ {
+ map_byte *ma = NULL;
+
+ mem_free ((void **) (void *) &symbol);
+
+ if (get_emtcode (&text, &ma))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ map_byte_append (&g->mapb, ma);
+ }
+ /* .regbyte */
+ else if (is_dot && str_equal (symbol, (byte *) "regbyte"))
+ {
+ map_byte *ma = NULL;
+
+ mem_free ((void **) (void *) &symbol);
+
+ if (get_regbyte (&text, &ma))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ map_byte_append (&g->di->m_regbytes, ma);
+ }
+ /* .errtext */
+ else if (is_dot && str_equal (symbol, (byte *) "errtext"))
+ {
+ map_str *ma = NULL;
+
+ mem_free ((void **) (void *) &symbol);
+
+ if (get_errtext (&text, &ma))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ map_str_append (&g->maps, ma);
+ }
+ /* .string */
+ else if (is_dot && str_equal (symbol, (byte *) "string"))
+ {
+ mem_free ((void **) (void *) &symbol);
+
+ if (g->di->m_string != NULL)
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ if (get_identifier (&text, &g->string_symbol))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ /* skip semicolon */
+ eat_spaces (&text);
+ text++;
+ eat_spaces (&text);
+ }
+ else
+ {
+ rule *ru = NULL;
+ map_rule *ma = NULL;
+
+ if (get_rule (&text, &ru, g->maps, g->mapb))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ rule_append (&g->di->m_rulez, ru);
+
+ /* if a rule consist of only one specifier, give it an ".and" operator */
+ if (ru->m_oper == op_none)
+ ru->m_oper = op_and;
+
+ map_rule_create (&ma);
+ if (ma == NULL)
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ ma->key = symbol;
+ ma->data = ru;
+ map_rule_append (&g->mapr, ma);
+ }
+ }
+
+ if (update_dependencies (g->di, g->mapr, &g->syntax_symbol, &g->string_symbol,
+ g->di->m_regbytes))
+ {
+ grammar_load_state_destroy (&g);
+ return 0;
+ }
+
+ dict_append (&g_dicts, g->di);
+ id = g->di->m_id;
+ g->di = NULL;
+
+ grammar_load_state_destroy (&g);
+
+ return id;
+}
+
+int grammar_set_reg8 (grammar id, const byte *name, byte value)
+{
+ dict *di = NULL;
+ map_byte *reg = NULL;
+
+ clear_last_error ();
+
+ dict_find (&g_dicts, id, &di);
+ if (di == NULL)
+ {
+ set_last_error (INVALID_GRAMMAR_ID, NULL, -1);
+ return 0;
+ }
+
+ reg = map_byte_locate (&di->m_regbytes, name);
+ if (reg == NULL)
+ {
+ set_last_error (INVALID_REGISTER_NAME, str_duplicate (name), -1);
+ return 0;
+ }
+
+ reg->data = value;
+ return 1;
+}
+
+/*
+ internal checking function used by both grammar_check and grammar_fast_check functions
+*/
+static int _grammar_check (grammar id, const byte *text, byte **prod, unsigned int *size,
+ unsigned int estimate_prod_size, int use_fast_path)
+{
+ dict *di = NULL;
+ unsigned int index = 0;
+
+ clear_last_error ();
+
+ dict_find (&g_dicts, id, &di);
+ if (di == NULL)
+ {
+ set_last_error (INVALID_GRAMMAR_ID, NULL, -1);
+ return 0;
+ }
+
+ *prod = NULL;
+ *size = 0;
+
+ if (use_fast_path)
+ {
+ regbyte_ctx *rbc = NULL;
+ bytepool *bp = NULL;
+ int _P = 0;
+
+ bytepool_create (&bp, estimate_prod_size);
+ if (bp == NULL)
+ return 0;
+
+ if (fast_match (di, text, &index, di->m_syntax, &_P, bp, 0, &rbc) != mr_matched)
+ {
+ bytepool_destroy (&bp);
+ free_regbyte_ctx_stack (rbc, NULL);
+ return 0;
+ }
+
+ free_regbyte_ctx_stack (rbc, NULL);
+
+ *prod = bp->_F;
+ *size = _P;
+ bp->_F = NULL;
+ bytepool_destroy (&bp);
+ }
+ else
+ {
+ regbyte_ctx *rbc = NULL;
+ barray *ba = NULL;
+
+ barray_create (&ba);
+ if (ba == NULL)
+ return 0;
+
+ if (match (di, text, &index, di->m_syntax, &ba, 0, &rbc) != mr_matched)
+ {
+ barray_destroy (&ba);
+ free_regbyte_ctx_stack (rbc, NULL);
+ return 0;
+ }
+
+ free_regbyte_ctx_stack (rbc, NULL);
+
+ *prod = (byte *) mem_alloc (ba->len * sizeof (byte));
+ if (*prod == NULL)
+ {
+ barray_destroy (&ba);
+ return 0;
+ }
+
+ mem_copy (*prod, ba->data, ba->len * sizeof (byte));
+ *size = ba->len;
+ barray_destroy (&ba);
+ }
+
+ return 1;
+}
+
+int grammar_check (grammar id, const byte *text, byte **prod, unsigned int *size)
+{
+ return _grammar_check (id, text, prod, size, 0, 0);
+}
+
+int grammar_fast_check (grammar id, const byte *text, byte **prod, unsigned int *size,
+ unsigned int estimate_prod_size)
+{
+ return _grammar_check (id, text, prod, size, estimate_prod_size, 1);
+}
+
+int grammar_destroy (grammar id)
+{
+ dict **di = &g_dicts;
+
+ clear_last_error ();
+
+ while (*di != NULL)
+ {
+ if ((**di).m_id == id)
+ {
+ dict *tmp = *di;
+ *di = (**di).next;
+ dict_destroy (&tmp);
+ return 1;
+ }
+
+ di = &(**di).next;
+ }
+
+ set_last_error (INVALID_GRAMMAR_ID, NULL, -1);
+ return 0;
+}
+
+static void append_character (const char x, byte *text, int *dots_made, int *len, int size)
+{
+ if (*dots_made == 0)
+ {
+ if (*len < size - 1)
+ {
+ text[(*len)++] = x;
+ text[*len] = '\0';
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < 3; i++)
+ if (--(*len) >= 0)
+ text[*len] = '.';
+ *dots_made = 1;
+ }
+ }
+}
+
+void grammar_get_last_error (byte *text, unsigned int size, int *pos)
+{
+ int len = 0, dots_made = 0;
+ const byte *p = error_message;
+
+ *text = '\0';
+
+ if (p)
+ {
+ while (*p)
+ {
+ if (*p == '$')
+ {
+ const byte *r = error_param;
+
+ while (*r)
+ {
+ append_character (*r++, text, &dots_made, &len, (int) size);
+ }
+
+ p++;
+ }
+ else
+ {
+ append_character (*p++, text, &dots_made, &len, size);
+ }
+ }
+ }
+
+ *pos = error_position;
+}
diff --git a/src/mesa/shader/grammar/grammar.h b/src/mesa/shader/grammar/grammar.h
new file mode 100644
index 00000000000..591e38aefa6
--- /dev/null
+++ b/src/mesa/shader/grammar/grammar.h
@@ -0,0 +1,103 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.2
+ *
+ * Copyright (C) 1999-2004 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.
+ */
+
+#ifndef GRAMMAR_H
+#define GRAMMAR_H
+
+
+#ifndef GRAMMAR_PORT_INCLUDE
+#error Do not include this file directly, include your grammar_XXX.h instead
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grammar_alloc_free (void *);
+void *grammar_alloc_malloc (size_t);
+void *grammar_alloc_realloc (void *, size_t, size_t);
+void *grammar_memory_copy (void *, const void *, size_t);
+int grammar_string_compare (const byte *, const byte *);
+int grammar_string_compare_n (const byte *, const byte *, size_t);
+byte *grammar_string_copy (byte *, const byte *);
+byte *grammar_string_copy_n (byte *, const byte *, size_t);
+byte *grammar_string_duplicate (const byte *);
+unsigned int grammar_string_length (const byte *);
+
+/*
+ loads grammar script from null-terminated ASCII <text>
+ returns unique grammar id to grammar object
+ returns 0 if an error occurs (call grammar_get_last_error to retrieve the error text)
+*/
+grammar grammar_load_from_text (const byte *text);
+
+/*
+ sets a new <value> to a register <name> for grammar <id>
+ returns 0 on error (call grammar_get_last_error to retrieve the error text)
+ returns 1 on success
+*/
+int grammar_set_reg8 (grammar id, const byte *name, byte value);
+
+/*
+ this function is obsolete, use only for debugging purposes
+
+ checks if a null-terminated <text> matches given grammar <id>
+ returns 0 on error (call grammar_get_last_error to retrieve the error text)
+ returns 1 on success, the <prod> points to newly allocated buffer with production and <size>
+ is filled with the production size
+ call grammar_alloc_free to free the memory block pointed by <prod>
+*/
+int grammar_check (grammar id, const byte *text, byte **prod, unsigned int *size);
+
+/*
+ does the same what grammar_check does but much more (approx. 4 times) faster
+ use this function instead of grammar_check
+ <estimate_prod_size> is a hint - the initial production buffer size will be of this size,
+ but if more room is needed it will be safely resized; set it to 0x1000 or so
+*/
+int grammar_fast_check (grammar id, const byte *text, byte **prod, unsigned int *size,
+ unsigned int estimate_prod_size);
+
+/*
+ destroys grammar object identified by <id>
+ returns 0 on error (call grammar_get_last_error to retrieve the error text)
+ returns 1 on success
+*/
+int grammar_destroy (grammar id);
+
+/*
+ retrieves last grammar error reported either by grammar_load_from_text, grammar_check
+ or grammar_destroy
+ the user allocated <text> buffer receives error description, <pos> points to error position,
+ <size> is the size of the text buffer to fill in - it must be at least 4 bytes long,
+*/
+void grammar_get_last_error (byte *text, unsigned int size, int *pos);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/grammar/grammar_crt.c b/src/mesa/shader/grammar/grammar_crt.c
new file mode 100755
index 00000000000..bdf2da9b2e2
--- /dev/null
+++ b/src/mesa/shader/grammar/grammar_crt.c
@@ -0,0 +1,64 @@
+#include "grammar_crt.h"
+
+#define GRAMMAR_PORT_BUILD 1
+#include "grammar.c"
+#undef GRAMMAR_PORT_BUILD
+
+
+void grammar_alloc_free (void *ptr)
+{
+ free (ptr);
+}
+
+void *grammar_alloc_malloc (unsigned int size)
+{
+ return malloc (size);
+}
+
+void *grammar_alloc_realloc (void *ptr, unsigned int old_size, unsigned int size)
+{
+ return realloc (ptr, size);
+}
+
+void *grammar_memory_copy (void *dst, const void * src, unsigned int size)
+{
+ return memcpy (dst, src, size);
+}
+
+int grammar_string_compare (const byte *str1, const byte *str2)
+{
+ return strcmp ((const char *) str1, (const char *) str2);
+}
+
+int grammar_string_compare_n (const byte *str1, const byte *str2, unsigned int n)
+{
+ return strncmp ((const char *) str1, (const char *) str2, n);
+}
+
+byte *grammar_string_copy (byte *dst, const byte *src)
+{
+ return (byte *) strcpy ((char *) dst, (const char *) src);
+}
+
+byte *grammar_string_copy_n (byte *dst, const byte *src, unsigned int n)
+{
+ return (byte *) strncpy ((char *) dst, (const char *) src, n);
+}
+
+unsigned int grammar_string_length (const byte *str)
+{
+ return strlen ((const char *) str);
+}
+
+byte *grammar_string_duplicate (const byte *src)
+{
+ const unsigned int size = grammar_string_length (src);
+ byte *str = grammar_alloc_malloc (size + 1);
+ if (str != NULL)
+ {
+ grammar_memory_copy (str, src, size);
+ str[size] = '\0';
+ }
+ return str;
+}
+
diff --git a/src/mesa/shader/grammar/grammar_crt.h b/src/mesa/shader/grammar/grammar_crt.h
new file mode 100755
index 00000000000..492711e96ae
--- /dev/null
+++ b/src/mesa/shader/grammar/grammar_crt.h
@@ -0,0 +1,20 @@
+#ifndef GRAMMAR_CRT_H
+#define GRAMMAR_CRT_H
+
+
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+
+
+typedef unsigned long grammar;
+typedef unsigned char byte;
+
+
+#define GRAMMAR_PORT_INCLUDE 1
+#include "grammar.h"
+#undef GRAMMAR_PORT_INCLUDE
+
+
+#endif
+
diff --git a/src/mesa/shader/grammar/grammar_mesa.c b/src/mesa/shader/grammar/grammar_mesa.c
new file mode 100644
index 00000000000..eb962505bfe
--- /dev/null
+++ b/src/mesa/shader/grammar/grammar_mesa.c
@@ -0,0 +1,87 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 grammar_mesa.c
+ * mesa3d port to syntax parsing engine
+ * \author Michal Krol
+ */
+
+#include "grammar_mesa.h"
+
+#define GRAMMAR_PORT_BUILD 1
+#include "grammar.c"
+#undef GRAMMAR_PORT_BUILD
+
+
+void grammar_alloc_free (void *ptr)
+{
+ _mesa_free (ptr);
+}
+
+void *grammar_alloc_malloc (size_t size)
+{
+ return _mesa_malloc (size);
+}
+
+void *grammar_alloc_realloc (void *ptr, size_t old_size, size_t size)
+{
+ return _mesa_realloc (ptr, old_size, size);
+}
+
+void *grammar_memory_copy (void *dst, const void * src, size_t size)
+{
+ return _mesa_memcpy (dst, src, size);
+}
+
+int grammar_string_compare (const byte *str1, const byte *str2)
+{
+ return _mesa_strcmp ((const char *) str1, (const char *) str2);
+}
+
+int grammar_string_compare_n (const byte *str1, const byte *str2, size_t n)
+{
+ return _mesa_strncmp ((const char *) str1, (const char *) str2, n);
+}
+
+byte *grammar_string_copy (byte *dst, const byte *src)
+{
+ return (byte *) _mesa_strcpy ((char *) dst, (const char *) src);
+}
+
+byte *grammar_string_copy_n (byte *dst, const byte *src, size_t n)
+{
+ return (byte *) _mesa_strncpy ((char *) dst, (const char *) src, n);
+}
+
+byte *grammar_string_duplicate (const byte *src)
+{
+ return (byte *) _mesa_strdup ((const char *) src);
+}
+
+unsigned int grammar_string_length (const byte *str)
+{
+ return (unsigned int)_mesa_strlen ((const char *) str);
+}
+
diff --git a/src/mesa/shader/grammar/grammar_mesa.h b/src/mesa/shader/grammar/grammar_mesa.h
new file mode 100644
index 00000000000..c14033a9d45
--- /dev/null
+++ b/src/mesa/shader/grammar/grammar_mesa.h
@@ -0,0 +1,43 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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.
+ */
+
+#ifndef GRAMMAR_MESA_H
+#define GRAMMAR_MESA_H
+
+
+#include "imports.h"
+/* NOTE: include Mesa 3-D specific headers here */
+
+
+typedef GLuint grammar;
+typedef GLubyte byte;
+
+
+#define GRAMMAR_PORT_INCLUDE 1
+#include "grammar.h"
+#undef GRAMMAR_PORT_INCLUDE
+
+
+#endif
+
diff --git a/src/mesa/shader/grammar/grammar_syn.h b/src/mesa/shader/grammar/grammar_syn.h
new file mode 100644
index 00000000000..840a1ab62c2
--- /dev/null
+++ b/src/mesa/shader/grammar/grammar_syn.h
@@ -0,0 +1,202 @@
+".syntax grammar;\n"
+".emtcode DECLARATION_END 0\n"
+".emtcode DECLARATION_EMITCODE 1\n"
+".emtcode DECLARATION_ERRORTEXT 2\n"
+".emtcode DECLARATION_REGBYTE 3\n"
+".emtcode DECLARATION_LEXER 4\n"
+".emtcode DECLARATION_RULE 5\n"
+".emtcode SPECIFIER_END 0\n"
+".emtcode SPECIFIER_AND_TAG 1\n"
+".emtcode SPECIFIER_OR_TAG 2\n"
+".emtcode SPECIFIER_CHARACTER_RANGE 3\n"
+".emtcode SPECIFIER_CHARACTER 4\n"
+".emtcode SPECIFIER_STRING 5\n"
+".emtcode SPECIFIER_IDENTIFIER 6\n"
+".emtcode SPECIFIER_TRUE 7\n"
+".emtcode SPECIFIER_FALSE 8\n"
+".emtcode SPECIFIER_DEBUG 9\n"
+".emtcode IDENTIFIER_SIMPLE 0\n"
+".emtcode IDENTIFIER_LOOP 1\n"
+".emtcode ERROR_NOT_PRESENT 0\n"
+".emtcode ERROR_PRESENT 1\n"
+".emtcode EMIT_NULL 0\n"
+".emtcode EMIT_INTEGER 1\n"
+".emtcode EMIT_IDENTIFIER 2\n"
+".emtcode EMIT_CHARACTER 3\n"
+".emtcode EMIT_LAST_CHARACTER 4\n"
+".emtcode EMIT_CURRENT_POSITION 5\n"
+".errtext INVALID_GRAMMAR \"internal error 2001: invalid grammar script\"\n"
+".errtext SYNTAX_EXPECTED \"internal error 2002: '.syntax' keyword expected\"\n"
+".errtext IDENTIFIER_EXPECTED \"internal error 2003: identifier expected\"\n"
+".errtext MISSING_SEMICOLON \"internal error 2004: missing ';'\"\n"
+".errtext INTEGER_EXPECTED \"internal error 2005: integer value expected\"\n"
+".errtext STRING_EXPECTED \"internal error 2006: string expected\"\n"
+"grammar\n"
+" grammar_1 .error INVALID_GRAMMAR;\n"
+"grammar_1\n"
+" optional_space .and \".syntax\" .error SYNTAX_EXPECTED .and space .and identifier .and\n"
+" semicolon .and declaration_list .and optional_space .and '\\0' .emit DECLARATION_END;\n"
+"optional_space\n"
+" space .or .true;\n"
+"space\n"
+" single_space .and .loop single_space;\n"
+"single_space\n"
+" white_char .or comment_block;\n"
+"white_char\n"
+" ' ' .or '\\t' .or '\\n' .or '\\r';\n"
+"comment_block\n"
+" '/' .and '*' .and comment_rest;\n"
+"comment_rest\n"
+" .loop comment_char_no_star .and comment_rest_1;\n"
+"comment_rest_1\n"
+" comment_end .or comment_rest_2;\n"
+"comment_rest_2\n"
+" '*' .and comment_rest;\n"
+"comment_char_no_star\n"
+" '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n"
+"comment_end\n"
+" '*' .and '/';\n"
+"identifier\n"
+" identifier_ne .error IDENTIFIER_EXPECTED;\n"
+"identifier_ne\n"
+" first_idchar .emit * .and .loop follow_idchar .emit * .and .true .emit '\\0';\n"
+"first_idchar\n"
+" 'a'-'z' .or 'A'-'Z' .or '_';\n"
+"follow_idchar\n"
+" first_idchar .or digit_dec;\n"
+"digit_dec\n"
+" '0'-'9';\n"
+"semicolon\n"
+" optional_space .and ';' .error MISSING_SEMICOLON .and optional_space;\n"
+"declaration_list\n"
+" declaration .and .loop declaration;\n"
+"declaration\n"
+" emitcode_definition .emit DECLARATION_EMITCODE .or\n"
+" errortext_definition .emit DECLARATION_ERRORTEXT .or\n"
+" regbyte_definition .emit DECLARATION_REGBYTE .or\n"
+" lexer_definition .emit DECLARATION_LEXER .or\n"
+" rule_definition .emit DECLARATION_RULE;\n"
+"emitcode_definition\n"
+" \".emtcode\" .and space .and identifier .and space .and integer .and space_or_null;\n"
+"integer\n"
+" integer_ne .error INTEGER_EXPECTED;\n"
+"integer_ne\n"
+" hex_integer .emit 0x10 .or dec_integer .emit 10;\n"
+"hex_integer\n"
+" hex_prefix .and digit_hex .emit * .and .loop digit_hex .emit * .and .true .emit '\\0';\n"
+"hex_prefix\n"
+" '0' .and hex_prefix_1;\n"
+"hex_prefix_1\n"
+" 'x' .or 'X';\n"
+"digit_hex\n"
+" '0'-'9' .or 'a'-'f' .or 'A'-'F';\n"
+"dec_integer\n"
+" digit_dec .emit * .and .loop digit_dec .emit * .and .true .emit '\\0';\n"
+"space_or_null\n"
+" space .or '\\0';\n"
+"errortext_definition\n"
+" \".errtext\" .and space .and identifier .and space .and string .and space_or_null;\n"
+"string\n"
+" string_ne .error STRING_EXPECTED;\n"
+"string_ne\n"
+" '\"' .and .loop string_char_double_quotes .and '\"' .emit '\\0';\n"
+"string_char_double_quotes\n"
+" escape_sequence .or string_char .emit * .or '\\'' .emit *;\n"
+"string_char\n"
+" '\\x5D'-'\\xFF' .or '\\x28'-'\\x5B' .or '\\x23'-'\\x26' .or '\\x0E'-'\\x21' .or '\\x0B'-'\\x0C' .or\n"
+" '\\x01'-'\\x09';\n"
+"escape_sequence\n"
+" '\\\\' .emit * .and escape_code;\n"
+"escape_code\n"
+" simple_escape_code .emit * .or hex_escape_code .or oct_escape_code;\n"
+"simple_escape_code\n"
+" '\\'' .or '\"' .or '?' .or '\\\\' .or 'a' .or 'b' .or 'f' .or 'n' .or 'r' .or 't' .or 'v';\n"
+"hex_escape_code\n"
+" 'x' .emit * .and digit_hex .emit * .and .loop digit_hex .emit *;\n"
+"oct_escape_code\n"
+" digit_oct .emit * .and optional_digit_oct .and optional_digit_oct;\n"
+"digit_oct\n"
+" '0'-'7';\n"
+"optional_digit_oct\n"
+" digit_oct .emit * .or .true;\n"
+"regbyte_definition\n"
+" \".regbyte\" .and space .and identifier .and space .and integer .and space_or_null;\n"
+"lexer_definition\n"
+" \".string\" .and space .and identifier .and semicolon;\n"
+"rule_definition\n"
+" identifier_ne .and space .and definition;\n"
+"definition\n"
+" specifier .and optional_specifiers_and_or .and semicolon .emit SPECIFIER_END;\n"
+"optional_specifiers_and_or\n"
+" and_specifiers .emit SPECIFIER_AND_TAG .or or_specifiers .emit SPECIFIER_OR_TAG .or .true;\n"
+"specifier\n"
+" specifier_condition .and optional_space .and specifier_rule;\n"
+"specifier_condition\n"
+" specifier_condition_1 .or .true;\n"
+"specifier_condition_1\n"
+" \".if\" .and optional_space .and '(' .and optional_space .and left_operand .and operator .and\n"
+" right_operand .and optional_space .and ')';\n"
+"left_operand\n"
+" identifier;\n"
+"operator\n"
+" operator_1 .or operator_2;\n"
+"operator_1\n"
+" optional_space .and '!' .and '=' .and optional_space;\n"
+"operator_2\n"
+" optional_space .and '=' .and '=' .and optional_space;\n"
+"right_operand\n"
+" integer;\n"
+"specifier_rule\n"
+" specifier_rule_1 .and optional_error .and .loop emit .and .true .emit EMIT_NULL;\n"
+"specifier_rule_1\n"
+" character_range .emit SPECIFIER_CHARACTER_RANGE .or\n"
+" character .emit SPECIFIER_CHARACTER .or\n"
+" string_ne .emit SPECIFIER_STRING .or\n"
+" \".true\" .emit SPECIFIER_TRUE .or\n"
+" \".false\" .emit SPECIFIER_FALSE .or\n"
+" \".debug\" .emit SPECIFIER_DEBUG .or\n"
+" advanced_identifier .emit SPECIFIER_IDENTIFIER;\n"
+"character\n"
+" '\\'' .and string_char_single_quotes .and '\\'' .emit '\\0';\n"
+"string_char_single_quotes\n"
+" escape_sequence .or string_char .emit * .or '\"' .emit *;\n"
+"character_range\n"
+" character .and optional_space .and '-' .and optional_space .and character;\n"
+"advanced_identifier\n"
+" optional_loop .and identifier;\n"
+"optional_loop\n"
+" optional_loop_1 .emit IDENTIFIER_LOOP .or .true .emit IDENTIFIER_SIMPLE;\n"
+"optional_loop_1\n"
+" \".loop\" .and space;\n"
+"optional_error\n"
+" error .emit ERROR_PRESENT .or .true .emit ERROR_NOT_PRESENT;\n"
+"error\n"
+" space .and \".error\" .and space .and identifier;\n"
+"emit\n"
+" emit_output .or emit_regbyte;\n"
+"emit_output\n"
+" space .and \".emit\" .and space .and emit_param;\n"
+"emit_param\n"
+" integer_ne .emit EMIT_INTEGER .or\n"
+" identifier_ne .emit EMIT_IDENTIFIER .or\n"
+" character .emit EMIT_CHARACTER .or\n"
+" '*' .emit EMIT_LAST_CHARACTER .or\n"
+" '$' .emit EMIT_CURRENT_POSITION;\n"
+"emit_regbyte\n"
+" space .and \".load\" .and space .and identifier .and space .and emit_param;\n"
+"and_specifiers\n"
+" and_specifier .and .loop and_specifier;\n"
+"or_specifiers\n"
+" or_specifier .and .loop or_specifier;\n"
+"and_specifier\n"
+" space .and \".and\" .and space .and specifier;\n"
+"or_specifier\n"
+" space .and \".or\" .and space .and specifier;\n"
+".string __string_filter;\n"
+"__string_filter\n"
+" __first_identifier_char .and .loop __next_identifier_char;\n"
+"__first_identifier_char\n"
+" 'a'-'z' .or 'A'-'Z' .or '_' .or '.';\n"
+"__next_identifier_char\n"
+" 'a'-'z' .or 'A'-'Z' .or '_' .or '0'-'9';\n"
+""
diff --git a/src/mesa/shader/nvfragparse.c b/src/mesa/shader/nvfragparse.c
new file mode 100644
index 00000000000..49ce220944e
--- /dev/null
+++ b/src/mesa/shader/nvfragparse.c
@@ -0,0 +1,1834 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2005 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
+ * NVIDIA fragment program parser.
+ * \author Brian Paul
+ */
+
+/*
+ * Regarding GL_NV_fragment_program:
+ *
+ * Portions of this software may use or implement intellectual
+ * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
+ * any and all warranties with respect to such intellectual property,
+ * including any use thereof or modifications thereto.
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "program_instruction.h"
+#include "nvfragparse.h"
+#include "nvprogram.h"
+#include "program.h"
+
+
+#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 INPUT_1V_S 10 /* a string and a vector register */
+#define OUTPUT_V 20
+#define OUTPUT_S 21
+#define OUTPUT_NONE 22
+
+/* IRIX defines some of these */
+#undef _R
+#undef _H
+#undef _X
+#undef _C
+#undef _S
+
+/* Optional suffixes */
+#define _R FLOAT32 /* float */
+#define _H FLOAT16 /* half-float */
+#define _X FIXED12 /* fixed */
+#define _C 0x08 /* set cond codes */
+#define _S 0x10 /* saturate, clamp result to [0,1] */
+
+struct instruction_pattern {
+ const char *name;
+ enum prog_opcode opcode;
+ GLuint inputs;
+ GLuint outputs;
+ GLuint suffixes;
+};
+
+static const struct instruction_pattern Instructions[] = {
+ { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
+ { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
+ { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
+ { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
+ { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
+ { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
+ { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
+ { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 },
+ { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
+ { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
+ { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 },
+ { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 },
+ { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 },
+ { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 },
+ { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S },
+ { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
+ { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
+ { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
+ { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
+ { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
+ { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S },
+ { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S },
+ { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S },
+ { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S },
+ { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S },
+ { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S },
+ { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S },
+ { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S },
+ { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 },
+ { NULL, (enum prog_opcode) -1, 0, 0, 0 }
+};
+
+
+/*
+ * Information needed or computed during parsing.
+ * Remember, we can't modify the target program object until we've
+ * _successfully_ parsed the program text.
+ */
+struct parse_state {
+ GLcontext *ctx;
+ const GLubyte *start; /* start of program string */
+ const GLubyte *pos; /* current position */
+ const GLubyte *curLine;
+ struct gl_fragment_program *program; /* current program */
+
+ struct gl_program_parameter_list *parameters;
+
+ GLuint numInst; /* number of instructions parsed */
+ GLuint inputsRead; /* bitmask of input registers used */
+ GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */
+ GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
+};
+
+
+
+/*
+ * Called whenever we find an error during parsing.
+ */
+static void
+record_error(struct parse_state *parseState, const char *msg, int lineNo)
+{
+#ifdef DEBUG
+ GLint line, column;
+ const GLubyte *lineStr;
+ lineStr = _mesa_find_line_column(parseState->start,
+ parseState->pos, &line, &column);
+ _mesa_debug(parseState->ctx,
+ "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
+ lineNo, line, column, (char *) lineStr, msg);
+ _mesa_free((void *) lineStr);
+#else
+ (void) lineNo;
+#endif
+
+ /* Check that no error was already recorded. Only record the first one. */
+ if (parseState->ctx->Program.ErrorString[0] == 0) {
+ _mesa_set_program_error(parseState->ctx,
+ parseState->pos - parseState->start,
+ msg);
+ }
+}
+
+
+#define RETURN_ERROR \
+do { \
+ record_error(parseState, "Unexpected end of input.", __LINE__); \
+ return GL_FALSE; \
+} while(0)
+
+#define RETURN_ERROR1(msg) \
+do { \
+ record_error(parseState, msg, __LINE__); \
+ return GL_FALSE; \
+} while(0)
+
+#define RETURN_ERROR2(msg1, msg2) \
+do { \
+ char err[1000]; \
+ _mesa_sprintf(err, "%s %s", msg1, msg2); \
+ record_error(parseState, err, __LINE__); \
+ return GL_FALSE; \
+} while(0)
+
+
+
+
+/*
+ * Search a list of instruction structures for a match.
+ */
+static struct instruction_pattern
+MatchInstruction(const GLubyte *token)
+{
+ const struct instruction_pattern *inst;
+ struct instruction_pattern result;
+
+ for (inst = Instructions; inst->name; inst++) {
+ if (_mesa_strncmp((const char *) 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 = MAX_OPCODE; /* i.e. invalid instruction */
+ return result;
+}
+
+
+
+
+/**********************************************************************/
+
+
+static GLboolean IsLetter(GLubyte b)
+{
+ return (b >= 'a' && b <= 'z') ||
+ (b >= 'A' && b <= 'Z') ||
+ (b == '_') ||
+ (b == '$');
+}
+
+
+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(struct parse_state *parseState, GLubyte *token)
+{
+ const GLubyte *str = parseState->pos;
+ 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++;
+ }
+ if (str[i] == '\n' || str[i] == '\r')
+ parseState->curLine = str + i + 1;
+ }
+ else {
+ /* skip whitespace */
+ if (str[i] == '\n' || str[i] == '\r')
+ parseState->curLine = str + i + 1;
+ 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 character */
+ 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(struct parse_state *parseState, GLubyte *token)
+{
+ GLint i;
+ i = GetToken(parseState, token);
+ if (i <= 0) {
+ parseState->pos += (-i);
+ return GL_FALSE;
+ }
+ parseState->pos += i;
+ return GL_TRUE;
+}
+
+
+/**
+ * Get next token from input stream but don't increment stream pointer.
+ */
+static GLboolean
+Peek_Token(struct parse_state *parseState, GLubyte *token)
+{
+ GLint i, len;
+ i = GetToken(parseState, token);
+ if (i <= 0) {
+ parseState->pos += (-i);
+ return GL_FALSE;
+ }
+ len = (GLint)_mesa_strlen((const char *) token);
+ parseState->pos += (i - len);
+ return GL_TRUE;
+}
+
+
+/**********************************************************************/
+
+static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
+ "WPOS", "COL0", "COL1", "FOGC",
+ "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
+};
+
+static const char *OutputRegisters[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS + 1] = {
+ "COLR", "COLH",
+ /* These are only allows for register combiners */
+ /*
+ "TEX0", "TEX1", "TEX2", "TEX3",
+ */
+ "DEPR", NULL
+};
+
+
+
+
+/**********************************************************************/
+
+/**
+ * Try to match 'pattern' as the next token after any whitespace/comments.
+ */
+static GLboolean
+Parse_String(struct parse_state *parseState, const char *pattern)
+{
+ const GLubyte *m;
+ GLint i;
+
+ /* skip whitespace and comments */
+ while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
+ if (*parseState->pos == '#') {
+ while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
+ parseState->pos += 1;
+ }
+ if (*parseState->pos == '\n' || *parseState->pos == '\r')
+ parseState->curLine = parseState->pos + 1;
+ }
+ else {
+ /* skip whitespace */
+ if (*parseState->pos == '\n' || *parseState->pos == '\r')
+ parseState->curLine = parseState->pos + 1;
+ parseState->pos += 1;
+ }
+ }
+
+ /* Try to match the pattern */
+ m = parseState->pos;
+ for (i = 0; pattern[i]; i++) {
+ if (*m != (GLubyte) pattern[i])
+ return GL_FALSE;
+ m += 1;
+ }
+ parseState->pos = m;
+
+ return GL_TRUE; /* success */
+}
+
+
+static GLboolean
+Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
+{
+ if (!Parse_Token(parseState, ident))
+ RETURN_ERROR;
+ if (IsLetter(ident[0]))
+ return GL_TRUE;
+ else
+ RETURN_ERROR1("Expected an identfier");
+}
+
+
+/**
+ * Parse a floating point constant, or a defined symbol name.
+ * [+/-]N[.N[eN]]
+ * Output: number[0 .. 3] will get the value.
+ */
+static GLboolean
+Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
+{
+ char *end = NULL;
+
+ *number = (GLfloat) _mesa_strtod((const char *) parseState->pos, &end);
+
+ if (end && end > (char *) parseState->pos) {
+ /* got a number */
+ parseState->pos = (GLubyte *) end;
+ number[1] = *number;
+ number[2] = *number;
+ number[3] = *number;
+ return GL_TRUE;
+ }
+ else {
+ /* should be an identifier */
+ GLubyte ident[100];
+ const GLfloat *constant;
+ if (!Parse_Identifier(parseState, ident))
+ RETURN_ERROR1("Expected an identifier");
+ constant = _mesa_lookup_parameter_value(parseState->parameters,
+ -1, (const char *) ident);
+ /* XXX Check that it's a constant and not a parameter */
+ if (!constant) {
+ RETURN_ERROR1("Undefined symbol");
+ }
+ else {
+ COPY_4V(number, constant);
+ return GL_TRUE;
+ }
+ }
+}
+
+
+
+/**
+ * Parse a vector constant, one of:
+ * { float }
+ * { float, float }
+ * { float, float, float }
+ * { float, float, float, float }
+ */
+static GLboolean
+Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
+{
+ /* "{" was already consumed */
+
+ ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
+
+ if (!Parse_ScalarConstant(parseState, vec+0)) /* X */
+ return GL_FALSE;
+
+ if (Parse_String(parseState, "}")) {
+ return GL_TRUE;
+ }
+
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected comma in vector constant");
+
+ if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */
+ return GL_FALSE;
+
+ if (Parse_String(parseState, "}")) {
+ return GL_TRUE;
+ }
+
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected comma in vector constant");
+
+ if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */
+ return GL_FALSE;
+
+ if (Parse_String(parseState, "}")) {
+ return GL_TRUE;
+ }
+
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected comma in vector constant");
+
+ if (!Parse_ScalarConstant(parseState, vec+3)) /* W */
+ return GL_FALSE;
+
+ if (!Parse_String(parseState, "}"))
+ RETURN_ERROR1("Expected closing brace in vector constant");
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse <number>, <varname> or {a, b, c, d}.
+ * Return number of values in the vector or scalar, or zero if parse error.
+ */
+static GLuint
+Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
+{
+ if (Parse_String(parseState, "{")) {
+ return Parse_VectorConstant(parseState, vec);
+ }
+ else {
+ GLboolean b = Parse_ScalarConstant(parseState, vec);
+ if (b) {
+ vec[1] = vec[2] = vec[3] = vec[0];
+ }
+ return b;
+ }
+}
+
+
+/**
+ * Parse a texture image source:
+ * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
+ */
+static GLboolean
+Parse_TextureImageId(struct parse_state *parseState,
+ GLubyte *texUnit, GLubyte *texTargetBit)
+{
+ GLubyte imageSrc[100];
+ GLint unit;
+
+ if (!Parse_Token(parseState, imageSrc))
+ RETURN_ERROR;
+
+ if (imageSrc[0] != 'T' ||
+ imageSrc[1] != 'E' ||
+ imageSrc[2] != 'X') {
+ RETURN_ERROR1("Expected TEX# source");
+ }
+ unit = _mesa_atoi((const char *) imageSrc + 3);
+ if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
+ (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
+ RETURN_ERROR1("Invalied TEX# source index");
+ }
+ *texUnit = unit;
+
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+
+ if (Parse_String(parseState, "1D")) {
+ *texTargetBit = TEXTURE_1D_BIT;
+ }
+ else if (Parse_String(parseState, "2D")) {
+ *texTargetBit = TEXTURE_2D_BIT;
+ }
+ else if (Parse_String(parseState, "3D")) {
+ *texTargetBit = TEXTURE_3D_BIT;
+ }
+ else if (Parse_String(parseState, "CUBE")) {
+ *texTargetBit = TEXTURE_CUBE_BIT;
+ }
+ else if (Parse_String(parseState, "RECT")) {
+ *texTargetBit = TEXTURE_RECT_BIT;
+ }
+ else {
+ RETURN_ERROR1("Invalid texture target token");
+ }
+
+ /* update record of referenced texture units */
+ parseState->texturesUsed[*texUnit] |= *texTargetBit;
+ if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
+ RETURN_ERROR1("Only one texture target can be used per texture unit.");
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
+ * like .wxyz, .xxyy, etc and return the swizzle indexes.
+ */
+static GLboolean
+Parse_SwizzleSuffix(const GLubyte *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(struct parse_state *parseState,
+ struct prog_dst_register *dstReg)
+{
+ if (Parse_String(parseState, "EQ"))
+ dstReg->CondMask = COND_EQ;
+ else if (Parse_String(parseState, "GE"))
+ dstReg->CondMask = COND_GE;
+ else if (Parse_String(parseState, "GT"))
+ dstReg->CondMask = COND_GT;
+ else if (Parse_String(parseState, "LE"))
+ dstReg->CondMask = COND_LE;
+ else if (Parse_String(parseState, "LT"))
+ dstReg->CondMask = COND_LT;
+ else if (Parse_String(parseState, "NE"))
+ dstReg->CondMask = COND_NE;
+ else if (Parse_String(parseState, "TR"))
+ dstReg->CondMask = COND_TR;
+ else if (Parse_String(parseState, "FL"))
+ dstReg->CondMask = COND_FL;
+ else
+ RETURN_ERROR1("Invalid condition code mask");
+
+ /* look for optional .xyzw swizzle */
+ if (Parse_String(parseState, ".")) {
+ GLubyte token[100];
+ GLuint swz[4];
+
+ if (!Parse_Token(parseState, token)) /* get xyzw suffix */
+ RETURN_ERROR;
+
+ if (!Parse_SwizzleSuffix(token, swz))
+ RETURN_ERROR1("Invalid swizzle suffix");
+
+ dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse a temporary register: Rnn or Hnn
+ */
+static GLboolean
+Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
+{
+ GLubyte token[100];
+
+ /* Should be 'R##' or 'H##' */
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+ if (token[0] != 'R' && token[0] != 'H')
+ RETURN_ERROR1("Expected R## or H##");
+
+ if (IsDigit(token[1])) {
+ GLint reg = _mesa_atoi((const char *) (token + 1));
+ if (token[0] == 'H')
+ reg += 32;
+ if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
+ RETURN_ERROR1("Invalid temporary register name");
+ *tempRegNum = reg;
+ }
+ else {
+ RETURN_ERROR1("Invalid temporary register name");
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse a write-only dummy register: RC or HC.
+ */
+static GLboolean
+Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
+{
+ if (Parse_String(parseState, "RC")) {
+ *regNum = 0;
+ }
+ else if (Parse_String(parseState, "HC")) {
+ *regNum = 1;
+ }
+ else {
+ RETURN_ERROR1("Invalid write-only register name");
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse a program local parameter register "p[##]"
+ */
+static GLboolean
+Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
+{
+ GLubyte token[100];
+
+ if (!Parse_String(parseState, "p["))
+ RETURN_ERROR1("Expected p[");
+
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (IsDigit(token[0])) {
+ /* a numbered program parameter register */
+ GLint reg = _mesa_atoi((const char *) token);
+ if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
+ RETURN_ERROR1("Invalid constant program number");
+ *regNum = reg;
+ }
+ else {
+ RETURN_ERROR;
+ }
+
+ if (!Parse_String(parseState, "]"))
+ RETURN_ERROR1("Expected ]");
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse f[name] - fragment input register
+ */
+static GLboolean
+Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
+{
+ GLubyte token[100];
+ GLint j;
+
+ /* Match 'f[' */
+ if (!Parse_String(parseState, "f["))
+ RETURN_ERROR1("Expected f[");
+
+ /* get <name> and look for match */
+ if (!Parse_Token(parseState, token)) {
+ RETURN_ERROR;
+ }
+ for (j = 0; InputRegisters[j]; j++) {
+ if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
+ *tempRegNum = j;
+ parseState->inputsRead |= (1 << j);
+ break;
+ }
+ }
+ if (!InputRegisters[j]) {
+ /* unknown input register label */
+ RETURN_ERROR2("Invalid register name", token);
+ }
+
+ /* Match '[' */
+ if (!Parse_String(parseState, "]"))
+ RETURN_ERROR1("Expected ]");
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
+{
+ GLubyte token[100];
+ GLint j;
+
+ /* Match "o[" */
+ if (!Parse_String(parseState, "o["))
+ RETURN_ERROR1("Expected o[");
+
+ /* Get output reg name */
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ /* try to match an output register name */
+ for (j = 0; OutputRegisters[j]; j++) {
+ if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
+ static GLuint bothColors = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_COLH);
+ *outputRegNum = j;
+ parseState->outputsWritten |= (1 << j);
+ if ((parseState->outputsWritten & bothColors) == bothColors) {
+ RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
+ }
+ break;
+ }
+ }
+ if (!OutputRegisters[j])
+ RETURN_ERROR1("Invalid output register name");
+
+ /* Match ']' */
+ if (!Parse_String(parseState, "]"))
+ RETURN_ERROR1("Expected ]");
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_MaskedDstReg(struct parse_state *parseState,
+ struct prog_dst_register *dstReg)
+{
+ GLubyte token[100];
+ GLint idx;
+
+ /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (_mesa_strcmp((const char *) token, "RC") == 0 ||
+ _mesa_strcmp((const char *) token, "HC") == 0) {
+ /* a write-only register */
+ dstReg->File = PROGRAM_WRITE_ONLY;
+ if (!Parse_DummyReg(parseState, &idx))
+ RETURN_ERROR;
+ dstReg->Index = idx;
+ }
+ else if (token[0] == 'R' || token[0] == 'H') {
+ /* a temporary register */
+ dstReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &idx))
+ RETURN_ERROR;
+ dstReg->Index = idx;
+ }
+ else if (token[0] == 'o') {
+ /* an output register */
+ dstReg->File = PROGRAM_OUTPUT;
+ if (!Parse_OutputReg(parseState, &idx))
+ RETURN_ERROR;
+ dstReg->Index = idx;
+ }
+ else {
+ RETURN_ERROR1("Invalid destination register name");
+ }
+
+ /* Parse optional write mask */
+ if (Parse_String(parseState, ".")) {
+ /* got a mask */
+ GLint k = 0;
+
+ if (!Parse_Token(parseState, token)) /* get xyzw writemask */
+ RETURN_ERROR;
+
+ dstReg->WriteMask = 0;
+
+ if (token[k] == 'x') {
+ dstReg->WriteMask |= WRITEMASK_X;
+ k++;
+ }
+ if (token[k] == 'y') {
+ dstReg->WriteMask |= WRITEMASK_Y;
+ k++;
+ }
+ if (token[k] == 'z') {
+ dstReg->WriteMask |= WRITEMASK_Z;
+ k++;
+ }
+ if (token[k] == 'w') {
+ dstReg->WriteMask |= WRITEMASK_W;
+ k++;
+ }
+ if (k == 0) {
+ RETURN_ERROR1("Invalid writemask character");
+ }
+
+ }
+ else {
+ dstReg->WriteMask = WRITEMASK_XYZW;
+ }
+
+ /* optional condition code mask */
+ if (Parse_String(parseState, "(")) {
+ /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
+ /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
+ if (!Parse_CondCodeMask(parseState, dstReg))
+ RETURN_ERROR;
+
+ if (!Parse_String(parseState, ")")) /* consume ")" */
+ RETURN_ERROR1("Expected )");
+
+ return GL_TRUE;
+ }
+ else {
+ /* no cond code mask */
+ dstReg->CondMask = COND_TR;
+ dstReg->CondSwizzle = SWIZZLE_NOOP;
+ return GL_TRUE;
+ }
+}
+
+
+/**
+ * Parse a vector source (register, constant, etc):
+ * <vectorSrc> ::= <absVectorSrc>
+ * | <baseVectorSrc>
+ * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
+ */
+static GLboolean
+Parse_VectorSrc(struct parse_state *parseState,
+ struct prog_src_register *srcReg)
+{
+ GLfloat sign = 1.0F;
+ GLubyte token[100];
+ GLint idx;
+
+ /*
+ * First, take care of +/- and absolute value stuff.
+ */
+ if (Parse_String(parseState, "-"))
+ sign = -1.0F;
+ else if (Parse_String(parseState, "+"))
+ sign = +1.0F;
+
+ if (Parse_String(parseState, "|")) {
+ srcReg->Abs = GL_TRUE;
+ srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
+
+ if (Parse_String(parseState, "-"))
+ srcReg->NegateBase = NEGATE_XYZW;
+ else if (Parse_String(parseState, "+"))
+ srcReg->NegateBase = NEGATE_NONE;
+ else
+ srcReg->NegateBase = NEGATE_NONE;
+ }
+ else {
+ srcReg->Abs = GL_FALSE;
+ srcReg->NegateAbs = GL_FALSE;
+ srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
+ }
+
+ /* This should be the real src vector/register name */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
+ * literal or vector literal.
+ */
+ if (token[0] == 'R' || token[0] == 'H') {
+ srcReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == 'f') {
+ /* XXX this might be an identifier! */
+ srcReg->File = PROGRAM_INPUT;
+ if (!Parse_FragReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == 'p') {
+ /* XXX this might be an identifier! */
+ srcReg->File = PROGRAM_LOCAL_PARAM;
+ if (!Parse_ProgramParamReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (IsLetter(token[0])){
+ GLubyte ident[100];
+ GLint paramIndex;
+ if (!Parse_Identifier(parseState, ident))
+ RETURN_ERROR;
+ paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
+ -1, (const char *) ident);
+ if (paramIndex < 0) {
+ RETURN_ERROR2("Undefined constant or parameter: ", ident);
+ }
+ srcReg->File = PROGRAM_NAMED_PARAM;
+ srcReg->Index = paramIndex;
+ }
+ else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
+ /* literal scalar constant */
+ GLfloat values[4];
+ GLuint paramIndex;
+ if (!Parse_ScalarConstant(parseState, values))
+ RETURN_ERROR;
+ paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
+ srcReg->File = PROGRAM_NAMED_PARAM;
+ srcReg->Index = paramIndex;
+ }
+ else if (token[0] == '{'){
+ /* literal vector constant */
+ GLfloat values[4];
+ GLuint paramIndex;
+ (void) Parse_String(parseState, "{");
+ if (!Parse_VectorConstant(parseState, values))
+ RETURN_ERROR;
+ paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
+ srcReg->File = PROGRAM_NAMED_PARAM;
+ srcReg->Index = paramIndex;
+ }
+ else {
+ RETURN_ERROR2("Invalid source register name", token);
+ }
+
+ /* init swizzle fields */
+ srcReg->Swizzle = SWIZZLE_NOOP;
+
+ /* Look for optional swizzle suffix */
+ if (Parse_String(parseState, ".")) {
+ GLuint swz[4];
+
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (!Parse_SwizzleSuffix(token, swz))
+ RETURN_ERROR1("Invalid swizzle suffix");
+
+ srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
+ }
+
+ /* Finish absolute value */
+ if (srcReg->Abs && !Parse_String(parseState, "|")) {
+ RETURN_ERROR1("Expected |");
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ScalarSrcReg(struct parse_state *parseState,
+ struct prog_src_register *srcReg)
+{
+ GLubyte token[100];
+ GLfloat sign = 1.0F;
+ GLboolean needSuffix = GL_TRUE;
+ GLint idx;
+
+ /*
+ * First, take care of +/- and absolute value stuff.
+ */
+ if (Parse_String(parseState, "-"))
+ sign = -1.0F;
+ else if (Parse_String(parseState, "+"))
+ sign = +1.0F;
+
+ if (Parse_String(parseState, "|")) {
+ srcReg->Abs = GL_TRUE;
+ srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
+
+ if (Parse_String(parseState, "-"))
+ srcReg->NegateBase = NEGATE_XYZW;
+ else if (Parse_String(parseState, "+"))
+ srcReg->NegateBase = NEGATE_NONE;
+ else
+ srcReg->NegateBase = NEGATE_NONE;
+ }
+ else {
+ srcReg->Abs = GL_FALSE;
+ srcReg->NegateAbs = GL_FALSE;
+ srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
+ }
+
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ /* Src reg can be R<n>, H<n> or a named fragment attrib */
+ if (token[0] == 'R' || token[0] == 'H') {
+ srcReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == 'f') {
+ srcReg->File = PROGRAM_INPUT;
+ if (!Parse_FragReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == '{') {
+ /* vector literal */
+ GLfloat values[4];
+ GLuint paramIndex;
+ (void) Parse_String(parseState, "{");
+ if (!Parse_VectorConstant(parseState, values))
+ RETURN_ERROR;
+ paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
+ srcReg->File = PROGRAM_NAMED_PARAM;
+ srcReg->Index = paramIndex;
+ }
+ else if (IsLetter(token[0])){
+ /* named param/constant */
+ GLubyte ident[100];
+ GLint paramIndex;
+ if (!Parse_Identifier(parseState, ident))
+ RETURN_ERROR;
+ paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
+ -1, (const char *) ident);
+ if (paramIndex < 0) {
+ RETURN_ERROR2("Undefined constant or parameter: ", ident);
+ }
+ srcReg->File = PROGRAM_NAMED_PARAM;
+ srcReg->Index = paramIndex;
+ }
+ else if (IsDigit(token[0])) {
+ /* scalar literal */
+ GLfloat values[4];
+ GLuint paramIndex;
+ if (!Parse_ScalarConstant(parseState, values))
+ RETURN_ERROR;
+ paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
+ srcReg->Index = paramIndex;
+ srcReg->File = PROGRAM_NAMED_PARAM;
+ needSuffix = GL_FALSE;
+ }
+ else {
+ RETURN_ERROR2("Invalid scalar source argument", token);
+ }
+
+ srcReg->Swizzle = 0;
+ if (needSuffix) {
+ /* parse .[xyzw] suffix */
+ if (!Parse_String(parseState, "."))
+ RETURN_ERROR1("Expected .");
+
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (token[0] == 'x' && token[1] == 0) {
+ srcReg->Swizzle = 0;
+ }
+ else if (token[0] == 'y' && token[1] == 0) {
+ srcReg->Swizzle = 1;
+ }
+ else if (token[0] == 'z' && token[1] == 0) {
+ srcReg->Swizzle = 2;
+ }
+ else if (token[0] == 'w' && token[1] == 0) {
+ srcReg->Swizzle = 3;
+ }
+ else {
+ RETURN_ERROR1("Invalid scalar source suffix");
+ }
+ }
+
+ /* Finish absolute value */
+ if (srcReg->Abs && !Parse_String(parseState, "|")) {
+ RETURN_ERROR1("Expected |");
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_PrintInstruction(struct parse_state *parseState,
+ struct prog_instruction *inst)
+{
+ const GLubyte *str;
+ GLubyte *msg;
+ GLuint len;
+ GLint idx;
+
+ /* The first argument is a literal string 'just like this' */
+ if (!Parse_String(parseState, "'"))
+ RETURN_ERROR1("Expected '");
+
+ str = parseState->pos;
+ for (len = 0; str[len] != '\''; len++) /* find closing quote */
+ ;
+ parseState->pos += len + 1;
+ msg = (GLubyte*) _mesa_malloc(len + 1);
+
+ _mesa_memcpy(msg, str, len);
+ msg[len] = 0;
+ inst->Data = msg;
+
+ if (Parse_String(parseState, ",")) {
+ /* got an optional register to print */
+ GLubyte token[100];
+ GetToken(parseState, token);
+ if (token[0] == 'o') {
+ /* dst reg */
+ if (!Parse_OutputReg(parseState, &idx))
+ RETURN_ERROR;
+ inst->SrcReg[0].Index = idx;
+ inst->SrcReg[0].File = PROGRAM_OUTPUT;
+ }
+ else {
+ /* src reg */
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ }
+ }
+ else {
+ inst->SrcReg[0].File = PROGRAM_UNDEFINED;
+ }
+
+ inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
+ inst->SrcReg[0].NegateBase = NEGATE_NONE;
+ inst->SrcReg[0].Abs = GL_FALSE;
+ inst->SrcReg[0].NegateAbs = GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_InstructionSequence(struct parse_state *parseState,
+ struct prog_instruction program[])
+{
+ while (1) {
+ struct prog_instruction *inst = program + parseState->numInst;
+ struct instruction_pattern instMatch;
+ GLubyte token[100];
+
+ /* Initialize the instruction */
+ _mesa_init_instruction(inst);
+
+ /* special instructions */
+ if (Parse_String(parseState, "DEFINE")) {
+ GLubyte id[100];
+ GLfloat value[7]; /* yes, 7 to be safe */
+ if (!Parse_Identifier(parseState, id))
+ RETURN_ERROR;
+ /* XXX make sure id is not a reserved identifer, like R9 */
+ if (!Parse_String(parseState, "="))
+ RETURN_ERROR1("Expected =");
+ if (!Parse_VectorOrScalarConstant(parseState, value))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR1("Expected ;");
+ if (_mesa_lookup_parameter_index(parseState->parameters,
+ -1, (const char *) id) >= 0) {
+ RETURN_ERROR2(id, "already defined");
+ }
+ _mesa_add_named_parameter(parseState->parameters,
+ (const char *) id, value);
+ }
+ else if (Parse_String(parseState, "DECLARE")) {
+ GLubyte id[100];
+ GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
+ if (!Parse_Identifier(parseState, id))
+ RETURN_ERROR;
+ /* XXX make sure id is not a reserved identifer, like R9 */
+ if (Parse_String(parseState, "=")) {
+ if (!Parse_VectorOrScalarConstant(parseState, value))
+ RETURN_ERROR;
+ }
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR1("Expected ;");
+ if (_mesa_lookup_parameter_index(parseState->parameters,
+ -1, (const char *) id) >= 0) {
+ RETURN_ERROR2(id, "already declared");
+ }
+ _mesa_add_named_parameter(parseState->parameters,
+ (const char *) id, value);
+ }
+ else if (Parse_String(parseState, "END")) {
+ inst->Opcode = OPCODE_END;
+ inst->StringPos = parseState->curLine - parseState->start;
+ assert(inst->StringPos >= 0);
+ parseState->numInst++;
+ if (Parse_Token(parseState, token)) {
+ RETURN_ERROR1("Code after END opcode.");
+ }
+ break;
+ }
+ else {
+ /* general/arithmetic instruction */
+
+ /* get token */
+ if (!Parse_Token(parseState, token)) {
+ RETURN_ERROR1("Missing END instruction.");
+ }
+
+ /* try to find matching instuction */
+ instMatch = MatchInstruction(token);
+ if (instMatch.opcode >= MAX_OPCODE) {
+ /* bad instruction name */
+ RETURN_ERROR2("Unexpected token: ", token);
+ }
+
+ inst->Opcode = instMatch.opcode;
+ inst->Precision = instMatch.suffixes & (_R | _H | _X);
+ inst->SaturateMode = (instMatch.suffixes & (_S))
+ ? SATURATE_ZERO_ONE : SATURATE_OFF;
+ inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
+ inst->StringPos = parseState->curLine - parseState->start;
+ assert(inst->StringPos >= 0);
+
+ /*
+ * parse the input and output operands
+ */
+ if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
+ if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ }
+ else if (instMatch.outputs == OUTPUT_NONE) {
+ if (instMatch.opcode == OPCODE_KIL_NV) {
+ /* This is a little weird, the cond code info is in
+ * the dest register.
+ */
+ if (!Parse_CondCodeMask(parseState, &inst->DstReg))
+ RETURN_ERROR;
+ }
+ else {
+ ASSERT(instMatch.opcode == OPCODE_PRINT);
+ }
+ }
+
+ if (instMatch.inputs == INPUT_1V) {
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ }
+ else if (instMatch.inputs == INPUT_2V) {
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
+ RETURN_ERROR;
+ }
+ else if (instMatch.inputs == INPUT_3V) {
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
+ RETURN_ERROR;
+ }
+ else if (instMatch.inputs == INPUT_1S) {
+ if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ }
+ else if (instMatch.inputs == INPUT_2S) {
+ if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
+ RETURN_ERROR;
+ }
+ else if (instMatch.inputs == INPUT_CC) {
+ /* XXX to-do */
+ }
+ else if (instMatch.inputs == INPUT_1V_T) {
+ GLubyte unit, idx;
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_TextureImageId(parseState, &unit, &idx))
+ RETURN_ERROR;
+ inst->TexSrcUnit = unit;
+ inst->TexSrcTarget = idx;
+ }
+ else if (instMatch.inputs == INPUT_3V_T) {
+ GLubyte unit, idx;
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
+ RETURN_ERROR;
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR1("Expected ,");
+ if (!Parse_TextureImageId(parseState, &unit, &idx))
+ RETURN_ERROR;
+ inst->TexSrcUnit = unit;
+ inst->TexSrcTarget = idx;
+ }
+ else if (instMatch.inputs == INPUT_1V_S) {
+ if (!Parse_PrintInstruction(parseState, inst))
+ RETURN_ERROR;
+ }
+
+ /* end of statement semicolon */
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR1("Expected ;");
+
+ parseState->numInst++;
+
+ if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
+ RETURN_ERROR1("Program too long");
+ }
+ }
+ return GL_TRUE;
+}
+
+
+
+/**
+ * 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 gl_fragment_program *program)
+{
+ struct parse_state parseState;
+ struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
+ struct prog_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;
+
+ /* Get ready to parse */
+ _mesa_bzero(&parseState, sizeof(struct parse_state));
+ parseState.ctx = ctx;
+ parseState.start = programString;
+ parseState.program = program;
+ parseState.numInst = 0;
+ parseState.curLine = programString;
+ parseState.parameters = _mesa_new_parameter_list();
+
+ /* Reset error state */
+ _mesa_set_program_error(ctx, -1, NULL);
+
+ /* check the program header */
+ if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
+ target = GL_FRAGMENT_PROGRAM_NV;
+ parseState.pos = programString + 7;
+ }
+ else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
+ /* fragment / register combiner program - not supported */
+ _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
+ return;
+ }
+ 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_InstructionSequence(&parseState, instBuffer)) {
+ GLuint u;
+ /* successful parse! */
+
+ if (parseState.outputsWritten == 0) {
+ /* must write at least one output! */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "Invalid fragment program - no outputs written.");
+ return;
+ }
+
+ /* copy the compiled instructions */
+ assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
+ newInst = _mesa_alloc_instructions(parseState.numInst);
+ if (!newInst) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+ return; /* out of memory */
+ }
+ _mesa_memcpy(newInst, instBuffer,
+ parseState.numInst * sizeof(struct prog_instruction));
+
+ /* install the program */
+ program->Base.Target = target;
+ if (program->Base.String) {
+ FREE(program->Base.String);
+ }
+ program->Base.String = programString;
+ program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
+ if (program->Base.Instructions) {
+ _mesa_free(program->Base.Instructions);
+ }
+ program->Base.Instructions = newInst;
+ program->Base.NumInstructions = parseState.numInst;
+ program->Base.InputsRead = parseState.inputsRead;
+ program->Base.OutputsWritten = parseState.outputsWritten;
+ for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
+ program->TexturesUsed[u] = parseState.texturesUsed[u];
+
+ /* save program parameters */
+ program->Base.Parameters = parseState.parameters;
+
+ /* allocate registers for declared program parameters */
+#if 00
+ _mesa_assign_program_registers(&(program->SymbolTable));
+#endif
+
+#ifdef DEBUG_foo
+ _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
+ _mesa_print_nv_fragment_program(program);
+ _mesa_printf("----------------------------------\n");
+#endif
+ }
+ else {
+ /* Error! */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
+ /* NOTE: _mesa_set_program_error would have been called already */
+ }
+}
+
+
+static void
+PrintSrcReg(const struct gl_fragment_program *program,
+ const struct prog_src_register *src)
+{
+ static const char comps[5] = "xyzw";
+
+ if (src->NegateAbs) {
+ _mesa_printf("-");
+ }
+ if (src->Abs) {
+ _mesa_printf("|");
+ }
+ if (src->NegateBase) {
+ _mesa_printf("-");
+ }
+ if (src->File == PROGRAM_NAMED_PARAM) {
+ if (program->Base.Parameters->Parameters[src->Index].Type
+ == PROGRAM_CONSTANT) {
+ const GLfloat *v;
+ v = program->Base.Parameters->ParameterValues[src->Index];
+ _mesa_printf("{%g, %g, %g, %g}", v[0], v[1], v[2], v[3]);
+ }
+ else {
+ ASSERT(program->Base.Parameters->Parameters[src->Index].Type
+ == PROGRAM_NAMED_PARAM);
+ _mesa_printf("%s", program->Base.Parameters->Parameters[src->Index].Name);
+ }
+ }
+ else if (src->File == PROGRAM_OUTPUT) {
+ _mesa_printf("o[%s]", OutputRegisters[src->Index]);
+ }
+ else if (src->File == PROGRAM_INPUT) {
+ _mesa_printf("f[%s]", InputRegisters[src->Index]);
+ }
+ else if (src->File == PROGRAM_LOCAL_PARAM) {
+ _mesa_printf("p[%d]", src->Index);
+ }
+ else if (src->File == PROGRAM_TEMPORARY) {
+ if (src->Index >= 32)
+ _mesa_printf("H%d", src->Index);
+ else
+ _mesa_printf("R%d", src->Index);
+ }
+ else if (src->File == PROGRAM_WRITE_ONLY) {
+ _mesa_printf("%cC", "HR"[src->Index]);
+ }
+ else {
+ _mesa_problem(NULL, "Invalid fragment register %d", src->Index);
+ return;
+ }
+ if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
+ GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
+ GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
+ _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
+ }
+ else if (src->Swizzle != SWIZZLE_NOOP) {
+ _mesa_printf(".%c%c%c%c",
+ comps[GET_SWZ(src->Swizzle, 0)],
+ comps[GET_SWZ(src->Swizzle, 1)],
+ comps[GET_SWZ(src->Swizzle, 2)],
+ comps[GET_SWZ(src->Swizzle, 3)]);
+ }
+ if (src->Abs) {
+ _mesa_printf("|");
+ }
+}
+
+static void
+PrintTextureSrc(const struct prog_instruction *inst)
+{
+ _mesa_printf("TEX%d, ", inst->TexSrcUnit);
+ switch (inst->TexSrcTarget) {
+ case TEXTURE_1D_INDEX:
+ _mesa_printf("1D");
+ break;
+ case TEXTURE_2D_INDEX:
+ _mesa_printf("2D");
+ break;
+ case TEXTURE_3D_INDEX:
+ _mesa_printf("3D");
+ break;
+ case TEXTURE_RECT_INDEX:
+ _mesa_printf("RECT");
+ break;
+ case TEXTURE_CUBE_INDEX:
+ _mesa_printf("CUBE");
+ break;
+ default:
+ _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc");
+ }
+}
+
+static void
+PrintCondCode(const struct prog_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 (GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 1) &&
+ GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 2) &&
+ GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 3)) {
+ _mesa_printf(".%c", comps[GET_SWZ(dst->CondSwizzle, 0)]);
+ }
+ else if (dst->CondSwizzle != SWIZZLE_NOOP) {
+ _mesa_printf(".%c%c%c%c",
+ comps[GET_SWZ(dst->CondSwizzle, 0)],
+ comps[GET_SWZ(dst->CondSwizzle, 1)],
+ comps[GET_SWZ(dst->CondSwizzle, 2)],
+ comps[GET_SWZ(dst->CondSwizzle, 3)]);
+ }
+}
+
+
+static void
+PrintDstReg(const struct prog_dst_register *dst)
+{
+ if (dst->File == PROGRAM_OUTPUT) {
+ _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
+ }
+ else if (dst->File == PROGRAM_TEMPORARY) {
+ if (dst->Index >= 32)
+ _mesa_printf("H%d", dst->Index);
+ else
+ _mesa_printf("R%d", dst->Index);
+ }
+ else if (dst->File == PROGRAM_LOCAL_PARAM) {
+ _mesa_printf("p[%d]", dst->Index);
+ }
+ else if (dst->File == PROGRAM_WRITE_ONLY) {
+ _mesa_printf("%cC", "HR"[dst->Index]);
+ }
+ else {
+ _mesa_printf("???");
+ }
+
+ if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
+ _mesa_printf(".");
+ if (dst->WriteMask & WRITEMASK_X)
+ _mesa_printf("x");
+ if (dst->WriteMask & WRITEMASK_Y)
+ _mesa_printf("y");
+ if (dst->WriteMask & WRITEMASK_Z)
+ _mesa_printf("z");
+ if (dst->WriteMask & WRITEMASK_W)
+ _mesa_printf("w");
+ }
+
+ if (dst->CondMask != COND_TR ||
+ dst->CondSwizzle != SWIZZLE_NOOP) {
+ _mesa_printf(" (");
+ PrintCondCode(dst);
+ _mesa_printf(")");
+ }
+}
+
+
+/**
+ * Print (unparse) the given vertex program. Just for debugging.
+ */
+void
+_mesa_print_nv_fragment_program(const struct gl_fragment_program *program)
+{
+ const struct prog_instruction *inst;
+
+ for (inst = program->Base.Instructions; inst->Opcode != 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 == FLOAT16)
+ _mesa_printf("H");
+ else if (inst->Precision == FIXED12)
+ _mesa_printf("X");
+ if (inst->CondUpdate)
+ _mesa_printf("C");
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ _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(program, &inst->SrcReg[0]);
+ }
+ else if (Instructions[i].inputs == INPUT_2V ||
+ Instructions[i].inputs == INPUT_2S) {
+ PrintSrcReg(program, &inst->SrcReg[0]);
+ _mesa_printf(", ");
+ PrintSrcReg(program, &inst->SrcReg[1]);
+ }
+ else if (Instructions[i].inputs == INPUT_3V) {
+ PrintSrcReg(program, &inst->SrcReg[0]);
+ _mesa_printf(", ");
+ PrintSrcReg(program, &inst->SrcReg[1]);
+ _mesa_printf(", ");
+ PrintSrcReg(program, &inst->SrcReg[2]);
+ }
+ else if (Instructions[i].inputs == INPUT_1V_T) {
+ PrintSrcReg(program, &inst->SrcReg[0]);
+ _mesa_printf(", ");
+ PrintTextureSrc(inst);
+ }
+ else if (Instructions[i].inputs == INPUT_3V_T) {
+ PrintSrcReg(program, &inst->SrcReg[0]);
+ _mesa_printf(", ");
+ PrintSrcReg(program, &inst->SrcReg[1]);
+ _mesa_printf(", ");
+ PrintSrcReg(program, &inst->SrcReg[2]);
+ _mesa_printf(", ");
+ PrintTextureSrc(inst);
+ }
+ _mesa_printf(";\n");
+ break;
+ }
+ }
+ if (!Instructions[i].name) {
+ _mesa_printf("Invalid opcode %d\n", inst->Opcode);
+ }
+ }
+ _mesa_printf("END\n");
+}
+
+
+const char *
+_mesa_nv_fragment_input_register_name(GLuint i)
+{
+ ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
+ return InputRegisters[i];
+}
+
+
+const char *
+_mesa_nv_fragment_output_register_name(GLuint i)
+{
+ ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_OUTPUTS);
+ return OutputRegisters[i];
+}
diff --git a/src/mesa/shader/nvfragparse.h b/src/mesa/shader/nvfragparse.h
new file mode 100644
index 00000000000..de45cf543db
--- /dev/null
+++ b/src/mesa/shader/nvfragparse.h
@@ -0,0 +1,52 @@
+
+/*
+ * 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 gl_fragment_program *program);
+
+
+extern void
+_mesa_print_nv_fragment_program(const struct gl_fragment_program *program);
+
+
+extern const char *
+_mesa_nv_fragment_input_register_name(GLuint i);
+
+
+extern const char *
+_mesa_nv_fragment_output_register_name(GLuint i);
+
+
+#endif
diff --git a/src/mesa/shader/nvprogram.c b/src/mesa/shader/nvprogram.c
new file mode 100644
index 00000000000..4e29e0b3f88
--- /dev/null
+++ b/src/mesa/shader/nvprogram.c
@@ -0,0 +1,873 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 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
+ * NVIDIA vertex/fragment program state management functions.
+ * \author Brian Paul
+ */
+
+/*
+ * Regarding GL_NV_fragment/vertex_program, GL_NV_vertex_program1_1, etc:
+ *
+ * Portions of this software may use or implement intellectual
+ * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
+ * any and all warranties with respect to such intellectual property,
+ * including any use thereof or modifications thereto.
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "nvfragparse.h"
+#include "program_instruction.h"
+#include "nvvertexec.h"
+#include "nvvertparse.h"
+#include "nvprogram.h"
+#include "program.h"
+
+
+
+/**
+ * Execute a vertex state program.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params)
+{
+ struct gl_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;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ vprog = (struct gl_vertex_program *) _mesa_lookup_program(ctx, id);
+
+ if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV");
+ return;
+ }
+
+ _mesa_init_vp_per_vertex_registers(ctx);
+ _mesa_init_vp_per_primitive_registers(ctx);
+ COPY_4V(ctx->VertexProgram.Inputs[VERT_ATTRIB_POS], params);
+ _mesa_exec_vertex_program(ctx, vprog);
+}
+
+
+/**
+ * Determine if a set of programs is resident in hardware.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+GLboolean GLAPIENTRY _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids,
+ GLboolean *residences)
+{
+ GLint i, j;
+ GLboolean allResident = 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++) {
+ const struct gl_program *prog;
+ if (ids[i] == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
+ return GL_FALSE;
+ }
+ prog = _mesa_lookup_program(ctx, ids[i]);
+ if (!prog) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
+ return GL_FALSE;
+ }
+ if (prog->Resident) {
+ if (!allResident)
+ residences[i] = GL_TRUE;
+ }
+ else {
+ if (allResident) {
+ allResident = GL_FALSE;
+ for (j = 0; j < i; j++)
+ residences[j] = GL_TRUE;
+ }
+ residences[i] = GL_FALSE;
+ }
+ }
+
+ return allResident;
+}
+
+
+/**
+ * Request that a set of programs be resident in hardware.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_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 gl_program *prog;
+
+ if (ids[i] == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
+ return;
+ }
+
+ prog = _mesa_lookup_program(ctx, ids[i]);
+ if (!prog) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
+ return;
+ }
+
+ /* XXX this is really a hardware thing we should hook out */
+ prog->Resident = GL_TRUE;
+ }
+}
+
+
+/**
+ * Get a program parameter register.
+ * \note Not compiled into display lists.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_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) {
+ COPY_4V(params, ctx->VertexProgram.Parameters[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 GLAPIENTRY
+_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) {
+ COPY_4V(params, ctx->VertexProgram.Parameters[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 GLAPIENTRY
+_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
+{
+ struct gl_program *prog;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->_CurrentProgram)
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ prog = _mesa_lookup_program(ctx, 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 ?(GLint)_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 GLAPIENTRY
+_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
+{
+ struct gl_program *prog;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->_CurrentProgram)
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (pname != GL_PROGRAM_STRING_NV) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)");
+ return;
+ }
+
+ prog = _mesa_lookup_program(ctx, id);
+ if (!prog) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV");
+ 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 GLAPIENTRY
+_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
+ && ctx->Extensions.NV_vertex_program) {
+ 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 GLAPIENTRY
+_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (index == 0 || index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
+ return;
+ }
+
+ switch (pname) {
+ case GL_ATTRIB_ARRAY_SIZE_NV:
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Size;
+ break;
+ case GL_ATTRIB_ARRAY_STRIDE_NV:
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Stride;
+ break;
+ case GL_ATTRIB_ARRAY_TYPE_NV:
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Type;
+ break;
+ case GL_CURRENT_ATTRIB_NV:
+ FLUSH_CURRENT(ctx, 0);
+ 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 GLAPIENTRY
+_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (index == 0 || index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
+ return;
+ }
+
+ switch (pname) {
+ case GL_ATTRIB_ARRAY_SIZE_NV:
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Size;
+ break;
+ case GL_ATTRIB_ARRAY_STRIDE_NV:
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Stride;
+ break;
+ case GL_ATTRIB_ARRAY_TYPE_NV:
+ params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Type;
+ break;
+ case GL_CURRENT_ATTRIB_NV:
+ FLUSH_CURRENT(ctx, 0);
+ 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 GLAPIENTRY
+_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (index == 0 || index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
+ return;
+ }
+
+ switch (pname) {
+ case GL_ATTRIB_ARRAY_SIZE_NV:
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Size;
+ break;
+ case GL_ATTRIB_ARRAY_STRIDE_NV:
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Stride;
+ break;
+ case GL_ATTRIB_ARRAY_TYPE_NV:
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Type;
+ break;
+ case GL_CURRENT_ATTRIB_NV:
+ FLUSH_CURRENT(ctx, 0);
+ params[0] = (GLint) ctx->Current.Attrib[index][0];
+ params[1] = (GLint) ctx->Current.Attrib[index][1];
+ params[2] = (GLint) ctx->Current.Attrib[index][2];
+ params[3] = (GLint) ctx->Current.Attrib[index][3];
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
+ if (!ctx->Extensions.ARB_vertex_buffer_object) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
+ return;
+ }
+ params[0] = ctx->Array.ArrayObj->VertexAttrib[index].BufferObj->Name;
+ 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 GLAPIENTRY
+_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 = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr;
+}
+
+
+
+/**
+ * Load/parse/compile a program.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
+ const GLubyte *program)
+{
+ struct gl_program *prog;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (id == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
+ return;
+ }
+
+ if (len < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ prog = _mesa_lookup_program(ctx, id);
+
+ if (prog && prog->Target != 0 && prog->Target != target) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
+ return;
+ }
+
+ if ((target == GL_VERTEX_PROGRAM_NV ||
+ target == GL_VERTEX_STATE_PROGRAM_NV)
+ && ctx->Extensions.NV_vertex_program) {
+ struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
+ if (!vprog || prog == &_mesa_DummyProgram) {
+ vprog = (struct gl_vertex_program *)
+ ctx->Driver.NewProgram(ctx, target, id);
+ if (!vprog) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+ return;
+ }
+ _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
+ }
+ _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_NV
+ && ctx->Extensions.NV_fragment_program) {
+ struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
+ if (!fprog || prog == &_mesa_DummyProgram) {
+ fprog = (struct gl_fragment_program *)
+ ctx->Driver.NewProgram(ctx, target, id);
+ if (!fprog) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+ return;
+ }
+ _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
+ }
+ _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
+ }
+}
+
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_mesa_ProgramParameter4dNV(GLenum target, GLuint index,
+ GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+ _mesa_ProgramParameter4fNV(target, index,
+ (GLfloat)x, (GLfloat)y, (GLfloat)z, (GLfloat)w);
+}
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_mesa_ProgramParameter4dvNV(GLenum target, GLuint index,
+ const GLdouble *params)
+{
+ _mesa_ProgramParameter4fNV(target, index,
+ (GLfloat)params[0], (GLfloat)params[1],
+ (GLfloat)params[2], (GLfloat)params[3]);
+}
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_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 && ctx->Extensions.NV_vertex_program) {
+ if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ ASSIGN_4V(ctx->VertexProgram.Parameters[index], x, y, z, w);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameterNV(index)");
+ return;
+ }
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameterNV");
+ return;
+ }
+}
+
+
+/**
+ * Set a program parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_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 GLAPIENTRY
+_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 && ctx->Extensions.NV_vertex_program) {
+ GLuint i;
+ if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV");
+ return;
+ }
+ for (i = 0; i < num; i++) {
+ ctx->VertexProgram.Parameters[index + i][0] = (GLfloat) params[0];
+ ctx->VertexProgram.Parameters[index + i][1] = (GLfloat) params[1];
+ ctx->VertexProgram.Parameters[index + i][2] = (GLfloat) params[2];
+ ctx->VertexProgram.Parameters[index + i][3] = (GLfloat) params[3];
+ 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 GLAPIENTRY
+_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 && ctx->Extensions.NV_vertex_program) {
+ GLuint i;
+ if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
+ return;
+ }
+ for (i = 0; i < num; i++) {
+ COPY_4V(ctx->VertexProgram.Parameters[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 GLAPIENTRY
+_mesa_TrackMatrixNV(GLenum target, GLuint address,
+ GLenum matrix, GLenum transform)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
+ 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;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ struct gl_program *prog;
+ struct gl_fragment_program *fragProg;
+ GLfloat *v;
+
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ prog = _mesa_lookup_program(ctx, 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(len)");
+ return;
+ }
+
+ fragProg = (struct gl_fragment_program *) prog;
+ v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len,
+ (char *) name);
+ if (v) {
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+ v[3] = w;
+ return;
+ }
+
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)");
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
+ const float v[])
+{
+ _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+ _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y,
+ (GLfloat)z, (GLfloat)w);
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
+ const double v[])
+{
+ _mesa_ProgramNamedParameter4fNV(id, len, name,
+ (GLfloat)v[0], (GLfloat)v[1],
+ (GLfloat)v[2], (GLfloat)v[3]);
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLfloat *params)
+{
+ struct gl_program *prog;
+ struct gl_fragment_program *fragProg;
+ const GLfloat *v;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->_CurrentProgram)
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ prog = _mesa_lookup_program(ctx, 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;
+ }
+
+ fragProg = (struct gl_fragment_program *) prog;
+ v = _mesa_lookup_parameter_value(fragProg->Base.Parameters,
+ len, (char *) name);
+ if (v) {
+ params[0] = v[0];
+ params[1] = v[1];
+ params[2] = v[2];
+ params[3] = v[3];
+ return;
+ }
+
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLdouble *params)
+{
+ GLfloat floatParams[4];
+ _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams);
+ COPY_4V(params, floatParams);
+}
diff --git a/src/mesa/shader/nvprogram.h b/src/mesa/shader/nvprogram.h
new file mode 100644
index 00000000000..dcea7727e04
--- /dev/null
+++ b/src/mesa/shader/nvprogram.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Brian Paul
+ */
+
+
+#ifndef NVPROGRAM_H
+#define NVPROGRAM_H
+
+
+extern void GLAPIENTRY
+_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params);
+
+extern GLboolean GLAPIENTRY
+_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, GLboolean *residences);
+
+extern void GLAPIENTRY
+_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids);
+
+extern void GLAPIENTRY
+_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, GLenum pname, GLfloat *params);
+
+extern void GLAPIENTRY
+_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, GLenum pname, GLdouble *params);
+
+extern void GLAPIENTRY
+_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params);
+
+extern void GLAPIENTRY
+_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program);
+
+extern void GLAPIENTRY
+_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, GLenum pname, GLint *params);
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params);
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params);
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params);
+
+extern void GLAPIENTRY
+_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer);
+
+extern void GLAPIENTRY
+_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+
+extern void GLAPIENTRY
+_mesa_ProgramParameter4dNV(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+
+extern void GLAPIENTRY
+_mesa_ProgramParameter4dvNV(GLenum target, GLuint index, const GLdouble *params);
+
+extern void GLAPIENTRY
+_mesa_ProgramParameter4fNV(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+extern void GLAPIENTRY
+_mesa_ProgramParameter4fvNV(GLenum target, GLuint index, const GLfloat *params);
+
+extern void GLAPIENTRY
+_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, GLuint num, const GLdouble *params);
+
+extern void GLAPIENTRY
+_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, GLuint num, const GLfloat *params);
+
+extern void GLAPIENTRY
+_mesa_TrackMatrixNV(GLenum target, GLuint address, GLenum matrix, GLenum transform);
+
+
+extern void GLAPIENTRY
+_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+extern void GLAPIENTRY
+_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
+ const float v[]);
+
+extern void GLAPIENTRY
+_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+
+extern void GLAPIENTRY
+_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
+ const double v[]);
+
+extern void GLAPIENTRY
+_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLfloat *params);
+
+extern void GLAPIENTRY
+_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
+ GLdouble *params);
+
+
+#endif
diff --git a/src/mesa/shader/nvvertexec.c b/src/mesa/shader/nvvertexec.c
new file mode 100644
index 00000000000..c436f4f0451
--- /dev/null
+++ b/src/mesa/shader/nvvertexec.c
@@ -0,0 +1,852 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2006 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
+ * 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 "program_instruction.h"
+#include "program.h"
+#include "math/m_matrix.h"
+
+
+static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
+
+
+/**
+ * Load/initialize the vertex program registers which need to be set
+ * per-vertex.
+ */
+void
+_mesa_init_vp_per_vertex_registers(GLcontext *ctx)
+{
+ /* Input registers get initialized from the current vertex attribs */
+ MEMCPY(ctx->VertexProgram.Inputs, ctx->Current.Attrib,
+ MAX_VERTEX_PROGRAM_ATTRIBS * 4 * sizeof(GLfloat));
+
+ if (ctx->VertexProgram.Current->IsNVProgram) {
+ GLuint i;
+ /* Output/result regs are initialized to [0,0,0,1] */
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) {
+ ASSIGN_4V(ctx->VertexProgram.Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F);
+ }
+ /* Temp regs are initialized to [0,0,0,0] */
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) {
+ ASSIGN_4V(ctx->VertexProgram.Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F);
+ }
+ ASSIGN_4V(ctx->VertexProgram.AddressReg, 0, 0, 0, 0);
+ }
+}
+
+
+
+/**
+ * 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;
+ 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])
+{
+ MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat));
+}
+
+
+/**
+ * Load program parameter registers with tracked matrices (if NV program)
+ * or GL state values (if ARB program).
+ * This needs to be done per glBegin/glEnd, not per-vertex.
+ */
+void
+_mesa_init_vp_per_primitive_registers(GLcontext *ctx)
+{
+ if (ctx->VertexProgram.Current->IsNVProgram) {
+ GLuint i;
+
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 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.Parameters, i*4, mat->m);
+ }
+ else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) {
+ _math_matrix_analyse(mat); /* update the inverse */
+ ASSERT(!_math_matrix_is_dirty(mat));
+ load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
+ }
+ else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) {
+ load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m);
+ }
+ else {
+ assert(ctx->VertexProgram.TrackMatrixTransform[i]
+ == GL_INVERSE_TRANSPOSE_NV);
+ _math_matrix_analyse(mat); /* update the inverse */
+ ASSERT(!_math_matrix_is_dirty(mat));
+ load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
+ }
+ }
+ }
+ else {
+ /* Using and ARB vertex program */
+ if (ctx->VertexProgram.Current->Base.Parameters) {
+ /* Grab the state GL state and put into registers */
+ _mesa_load_state_parameters(ctx,
+ ctx->VertexProgram.Current->Base.Parameters);
+ }
+ }
+}
+
+
+
+/**
+ * For debugging. Dump the current vertex program machine registers.
+ */
+void
+_mesa_dump_vp_state( const struct gl_vertex_program_state *state )
+{
+ int i;
+ _mesa_printf("VertexIn:\n");
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_INPUTS; i++) {
+ _mesa_printf("%d: %f %f %f %f ", i,
+ state->Inputs[i][0],
+ state->Inputs[i][1],
+ state->Inputs[i][2],
+ state->Inputs[i][3]);
+ }
+ _mesa_printf("\n");
+
+ _mesa_printf("VertexOut:\n");
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) {
+ _mesa_printf("%d: %f %f %f %f ", i,
+ state->Outputs[i][0],
+ state->Outputs[i][1],
+ state->Outputs[i][2],
+ state->Outputs[i][3]);
+ }
+ _mesa_printf("\n");
+
+ _mesa_printf("Registers:\n");
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) {
+ _mesa_printf("%d: %f %f %f %f ", i,
+ state->Temporaries[i][0],
+ state->Temporaries[i][1],
+ state->Temporaries[i][2],
+ state->Temporaries[i][3]);
+ }
+ _mesa_printf("\n");
+
+ _mesa_printf("Parameters:\n");
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) {
+ _mesa_printf("%d: %f %f %f %f ", i,
+ state->Parameters[i][0],
+ state->Parameters[i][1],
+ state->Parameters[i][2],
+ state->Parameters[i][3]);
+ }
+ _mesa_printf("\n");
+}
+
+
+
+/**
+ * Return a pointer to the 4-element float vector specified by the given
+ * source register.
+ */
+static INLINE const GLfloat *
+get_register_pointer( const struct prog_src_register *source,
+ const struct gl_vertex_program_state *state )
+{
+ if (source->RelAddr) {
+ const GLint reg = source->Index + state->AddressReg[0];
+ ASSERT( (source->File == PROGRAM_ENV_PARAM) ||
+ (source->File == PROGRAM_STATE_VAR) );
+ if (reg < 0 || reg > MAX_NV_VERTEX_PROGRAM_PARAMS)
+ return ZeroVec;
+ else if (source->File == PROGRAM_ENV_PARAM)
+ return state->Parameters[reg];
+ else
+ return state->Current->Base.Parameters->ParameterValues[reg];
+ }
+ else {
+ switch (source->File) {
+ case PROGRAM_TEMPORARY:
+ ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_TEMPS);
+ return state->Temporaries[source->Index];
+ case PROGRAM_INPUT:
+ ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_INPUTS);
+ return state->Inputs[source->Index];
+ case PROGRAM_OUTPUT:
+ /* This is only needed for the PRINT instruction */
+ ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
+ return state->Outputs[source->Index];
+ case PROGRAM_LOCAL_PARAM:
+ ASSERT(source->Index < MAX_PROGRAM_LOCAL_PARAMS);
+ return state->Current->Base.LocalParams[source->Index];
+ case PROGRAM_ENV_PARAM:
+ ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_PARAMS);
+ return state->Parameters[source->Index];
+ case PROGRAM_STATE_VAR:
+ ASSERT(source->Index < state->Current->Base.Parameters->NumParameters);
+ return state->Current->Base.Parameters->ParameterValues[source->Index];
+ default:
+ _mesa_problem(NULL,
+ "Bad source register file in get_register_pointer");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Fetch a 4-element float vector from the given source register.
+ * Apply swizzling and negating as needed.
+ */
+static INLINE void
+fetch_vector4( const struct prog_src_register *source,
+ const struct gl_vertex_program_state *state,
+ GLfloat result[4] )
+{
+ const GLfloat *src = get_register_pointer(source, state);
+
+ if (source->NegateBase) {
+ result[0] = -src[GET_SWZ(source->Swizzle, 0)];
+ result[1] = -src[GET_SWZ(source->Swizzle, 1)];
+ result[2] = -src[GET_SWZ(source->Swizzle, 2)];
+ result[3] = -src[GET_SWZ(source->Swizzle, 3)];
+ }
+ else {
+ result[0] = src[GET_SWZ(source->Swizzle, 0)];
+ result[1] = src[GET_SWZ(source->Swizzle, 1)];
+ result[2] = src[GET_SWZ(source->Swizzle, 2)];
+ result[3] = src[GET_SWZ(source->Swizzle, 3)];
+ }
+}
+
+
+
+/**
+ * As above, but only return result[0] element.
+ */
+static INLINE void
+fetch_vector1( const struct prog_src_register *source,
+ const struct gl_vertex_program_state *state,
+ GLfloat result[4] )
+{
+ const GLfloat *src = get_register_pointer(source, state);
+
+ if (source->NegateBase) {
+ result[0] = -src[GET_SWZ(source->Swizzle, 0)];
+ }
+ else {
+ result[0] = src[GET_SWZ(source->Swizzle, 0)];
+ }
+}
+
+
+/**
+ * Store 4 floats into a register.
+ */
+static void
+store_vector4( const struct prog_dst_register *dest,
+ struct gl_vertex_program_state *state,
+ const GLfloat value[4] )
+{
+ GLfloat *dst;
+ switch (dest->File) {
+ case PROGRAM_TEMPORARY:
+ dst = state->Temporaries[dest->Index];
+ break;
+ case PROGRAM_OUTPUT:
+ dst = state->Outputs[dest->Index];
+ break;
+ case PROGRAM_ENV_PARAM:
+ {
+ /* a slight hack */
+ GET_CURRENT_CONTEXT(ctx);
+ dst = ctx->VertexProgram.Parameters[dest->Index];
+ }
+ break;
+ default:
+ _mesa_problem(NULL, "Invalid register file in store_vector4(file=%d)",
+ dest->File);
+ return;
+ }
+
+ if (dest->WriteMask & WRITEMASK_X)
+ dst[0] = value[0];
+ if (dest->WriteMask & WRITEMASK_Y)
+ dst[1] = value[1];
+ if (dest->WriteMask & WRITEMASK_Z)
+ dst[2] = value[2];
+ if (dest->WriteMask & WRITEMASK_W)
+ dst[3] = value[3];
+}
+
+
+/**
+ * Set x to positive or negative infinity.
+ */
+#if defined(USE_IEEE) || defined(_WIN32)
+#define SET_POS_INFINITY(x) ( *((GLuint *) (void *)&x) = 0x7F800000 )
+#define SET_NEG_INFINITY(x) ( *((GLuint *) (void *)&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 *) (void *) &(x))->i = bits
+
+
+/**
+ * Execute the given vertex program
+ */
+void
+_mesa_exec_vertex_program(GLcontext *ctx, const struct gl_vertex_program *program)
+{
+ struct gl_vertex_program_state *state = &ctx->VertexProgram;
+ const struct prog_instruction *inst;
+
+ ctx->_CurrentProgram = GL_VERTEX_PROGRAM_ARB; /* or NV, doesn't matter */
+
+ /* If the program is position invariant, multiply the input position
+ * by the MVP matrix and store in the vertex position result register.
+ */
+ if (ctx->VertexProgram.Current->IsPositionInvariant) {
+ TRANSFORM_POINT( ctx->VertexProgram.Outputs[VERT_RESULT_HPOS],
+ ctx->_ModelProjectMatrix.m,
+ ctx->VertexProgram.Inputs[VERT_ATTRIB_POS]);
+
+ /* XXX: This could go elsewhere */
+ ctx->VertexProgram.Current->Base.OutputsWritten |= VERT_BIT_POS;
+ }
+
+ for (inst = program->Base.Instructions; ; inst++) {
+
+ if (ctx->VertexProgram.CallbackEnabled &&
+ ctx->VertexProgram.Callback) {
+ ctx->VertexProgram.CurrentPosition = inst->StringPos;
+ ctx->VertexProgram.Callback(program->Base.Target,
+ ctx->VertexProgram.CallbackData);
+ }
+
+ switch (inst->Opcode) {
+ case OPCODE_MOV:
+ {
+ GLfloat t[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ store_vector4( &inst->DstReg, state, t );
+ }
+ break;
+ case OPCODE_LIT:
+ {
+ const GLfloat epsilon = 1.0F / 256.0F; /* per NV spec */
+ GLfloat t[4], lit[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ t[0] = MAX2(t[0], 0.0F);
+ t[1] = MAX2(t[1], 0.0F);
+ t[3] = CLAMP(t[3], -(128.0F - epsilon), (128.0F - epsilon));
+ lit[0] = 1.0;
+ lit[1] = t[0];
+ lit[2] = (t[0] > 0.0) ? (GLfloat) _mesa_pow(t[1], t[3]) : 0.0F;
+ lit[3] = 1.0;
+ store_vector4( &inst->DstReg, state, lit );
+ }
+ break;
+ case OPCODE_RCP:
+ {
+ GLfloat t[4];
+ fetch_vector1( &inst->SrcReg[0], state, 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, state, t );
+ }
+ break;
+ case OPCODE_RSQ:
+ {
+ GLfloat t[4];
+ fetch_vector1( &inst->SrcReg[0], state, t );
+ t[0] = INV_SQRTF(FABSF(t[0]));
+ t[1] = t[2] = t[3] = t[0];
+ store_vector4( &inst->DstReg, state, t );
+ }
+ break;
+ case OPCODE_EXP:
+ {
+ GLfloat t[4], q[4], floor_t0;
+ fetch_vector1( &inst->SrcReg[0], state, t );
+ floor_t0 = FLOORF(t[0]);
+ if (floor_t0 > FLT_MAX_EXP) {
+ SET_POS_INFINITY(q[0]);
+ SET_POS_INFINITY(q[2]);
+ }
+ else if (floor_t0 < FLT_MIN_EXP) {
+ q[0] = 0.0F;
+ q[2] = 0.0F;
+ }
+ else {
+#ifdef USE_IEEE
+ GLint ii = (GLint) floor_t0;
+ ii = (ii < 23) + 0x3f800000;
+ SET_FLOAT_BITS(q[0], ii);
+ q[0] = *((GLfloat *) (void *)&ii);
+#else
+ q[0] = (GLfloat) pow(2.0, floor_t0);
+#endif
+ q[2] = (GLfloat) (q[0] * LOG2(q[1]));
+ }
+ q[1] = t[0] - floor_t0;
+ q[3] = 1.0F;
+ store_vector4( &inst->DstReg, state, q );
+ }
+ break;
+ case OPCODE_LOG:
+ {
+ GLfloat t[4], q[4], abs_t0;
+ fetch_vector1( &inst->SrcReg[0], state, t );
+ abs_t0 = FABSF(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;
+ GLfloat mantissa = FREXPF(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, state, q );
+ }
+ break;
+ case OPCODE_MUL:
+ {
+ GLfloat t[4], u[4], prod[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, prod );
+ }
+ break;
+ case OPCODE_ADD:
+ {
+ GLfloat t[4], u[4], sum[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, sum );
+ }
+ break;
+ case OPCODE_DP3:
+ {
+ GLfloat t[4], u[4], dot[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, dot );
+ }
+ break;
+ case OPCODE_DP4:
+ {
+ GLfloat t[4], u[4], dot[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, dot );
+ }
+ break;
+ case OPCODE_DST:
+ {
+ GLfloat t[4], u[4], dst[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, u );
+ dst[0] = 1.0F;
+ dst[1] = t[1] * u[1];
+ dst[2] = t[2];
+ dst[3] = u[3];
+ store_vector4( &inst->DstReg, state, dst );
+ }
+ break;
+ case OPCODE_MIN:
+ {
+ GLfloat t[4], u[4], min[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, min );
+ }
+ break;
+ case OPCODE_MAX:
+ {
+ GLfloat t[4], u[4], max[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, max );
+ }
+ break;
+ case OPCODE_SLT:
+ {
+ GLfloat t[4], u[4], slt[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, slt );
+ }
+ break;
+ case OPCODE_SGE:
+ {
+ GLfloat t[4], u[4], sge[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, sge );
+ }
+ break;
+ case OPCODE_MAD:
+ {
+ GLfloat t[4], u[4], v[4], sum[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, u );
+ fetch_vector4( &inst->SrcReg[2], state, 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, state, sum );
+ }
+ break;
+ case OPCODE_ARL:
+ {
+ GLfloat t[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ state->AddressReg[0] = (GLint) FLOORF(t[0]);
+ }
+ break;
+ case OPCODE_DPH:
+ {
+ GLfloat t[4], u[4], dot[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, dot );
+ }
+ break;
+ case OPCODE_RCC:
+ {
+ GLfloat t[4], u;
+ fetch_vector1( &inst->SrcReg[0], state, 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, state, t );
+ }
+ break;
+ case OPCODE_SUB: /* GL_NV_vertex_program1_1 */
+ {
+ GLfloat t[4], u[4], sum[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, 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, state, sum );
+ }
+ break;
+ case OPCODE_ABS: /* GL_NV_vertex_program1_1 */
+ {
+ GLfloat t[4];
+ fetch_vector4( &inst->SrcReg[0], state, 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, state, t );
+ }
+ break;
+ case OPCODE_FLR: /* GL_ARB_vertex_program */
+ {
+ GLfloat t[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ t[0] = FLOORF(t[0]);
+ t[1] = FLOORF(t[1]);
+ t[2] = FLOORF(t[2]);
+ t[3] = FLOORF(t[3]);
+ store_vector4( &inst->DstReg, state, t );
+ }
+ break;
+ case OPCODE_FRC: /* GL_ARB_vertex_program */
+ {
+ GLfloat t[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ t[0] = t[0] - FLOORF(t[0]);
+ t[1] = t[1] - FLOORF(t[1]);
+ t[2] = t[2] - FLOORF(t[2]);
+ t[3] = t[3] - FLOORF(t[3]);
+ store_vector4( &inst->DstReg, state, t );
+ }
+ break;
+ case OPCODE_EX2: /* GL_ARB_vertex_program */
+ {
+ GLfloat t[4];
+ fetch_vector1( &inst->SrcReg[0], state, t );
+ t[0] = t[1] = t[2] = t[3] = (GLfloat)_mesa_pow(2.0, t[0]);
+ store_vector4( &inst->DstReg, state, t );
+ }
+ break;
+ case OPCODE_LG2: /* GL_ARB_vertex_program */
+ {
+ GLfloat t[4];
+ fetch_vector1( &inst->SrcReg[0], state, t );
+ t[0] = t[1] = t[2] = t[3] = LOG2(t[0]);
+ store_vector4( &inst->DstReg, state, t );
+ }
+ break;
+ case OPCODE_POW: /* GL_ARB_vertex_program */
+ {
+ GLfloat t[4], u[4];
+ fetch_vector1( &inst->SrcReg[0], state, t );
+ fetch_vector1( &inst->SrcReg[1], state, u );
+ t[0] = t[1] = t[2] = t[3] = (GLfloat)_mesa_pow(t[0], u[0]);
+ store_vector4( &inst->DstReg, state, t );
+ }
+ break;
+ case OPCODE_XPD: /* GL_ARB_vertex_program */
+ {
+ GLfloat t[4], u[4], cross[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ fetch_vector4( &inst->SrcReg[1], state, u );
+ cross[0] = t[1] * u[2] - t[2] * u[1];
+ cross[1] = t[2] * u[0] - t[0] * u[2];
+ cross[2] = t[0] * u[1] - t[1] * u[0];
+ store_vector4( &inst->DstReg, state, cross );
+ }
+ break;
+ case OPCODE_SWZ: /* GL_ARB_vertex_program */
+ {
+ const struct prog_src_register *source = &inst->SrcReg[0];
+ const GLfloat *src = get_register_pointer(source, state);
+ GLfloat result[4];
+ GLuint i;
+
+ /* do extended swizzling here */
+ for (i = 0; i < 4; i++) {
+ if (GET_SWZ(source->Swizzle, i) == SWIZZLE_ZERO)
+ result[i] = 0.0;
+ else if (GET_SWZ(source->Swizzle, i) == SWIZZLE_ONE)
+ result[i] = 1.0;
+ else
+ result[i] = src[GET_SWZ(source->Swizzle, i)];
+ if (source->NegateBase & (1 << i))
+ result[i] = -result[i];
+ }
+ store_vector4( &inst->DstReg, state, result );
+ }
+ break;
+ case OPCODE_PRINT:
+ if (inst->SrcReg[0].File) {
+ GLfloat t[4];
+ fetch_vector4( &inst->SrcReg[0], state, t );
+ _mesa_printf("%s%g, %g, %g, %g\n",
+ (char *) inst->Data, t[0], t[1], t[2], t[3]);
+ }
+ else {
+ _mesa_printf("%s\n", (char *) inst->Data);
+ }
+ break;
+ case OPCODE_END:
+ ctx->_CurrentProgram = 0;
+ return;
+ default:
+ /* bad instruction opcode */
+ _mesa_problem(ctx, "Bad VP Opcode in _mesa_exec_vertex_program");
+ ctx->_CurrentProgram = 0;
+ return;
+ } /* switch */
+ } /* for */
+
+ ctx->_CurrentProgram = 0;
+}
+
+
+
+/**
+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 prog_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/shader/nvvertexec.h b/src/mesa/shader/nvvertexec.h
new file mode 100644
index 00000000000..e0fd46a7662
--- /dev/null
+++ b/src/mesa/shader/nvvertexec.h
@@ -0,0 +1,43 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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_per_vertex_registers(GLcontext *ctx);
+
+extern void
+_mesa_init_vp_per_primitive_registers(GLcontext *ctx);
+
+extern void
+_mesa_exec_vertex_program(GLcontext *ctx, const struct gl_vertex_program *program);
+
+extern void
+_mesa_dump_vp_state( const struct gl_vertex_program_state *state );
+
+#endif
diff --git a/src/mesa/shader/nvvertparse.c b/src/mesa/shader/nvvertparse.c
new file mode 100644
index 00000000000..3840dca2220
--- /dev/null
+++ b/src/mesa/shader/nvvertparse.c
@@ -0,0 +1,1590 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2005 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
+ * NVIDIA vertex program parser.
+ * \author Brian Paul
+ */
+
+/*
+ * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
+ *
+ * Portions of this software may use or implement intellectual
+ * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
+ * any and all warranties with respect to such intellectual property,
+ * including any use thereof or modifications thereto.
+ */
+
+#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 "program_instruction.h"
+#include "program.h"
+
+
+/**
+ * Current parsing state. This structure is passed among the parsing
+ * functions and keeps track of the current parser position and various
+ * program attributes.
+ */
+struct parse_state {
+ GLcontext *ctx;
+ const GLubyte *start;
+ const GLubyte *pos;
+ const GLubyte *curLine;
+ GLboolean isStateProgram;
+ GLboolean isPositionInvariant;
+ GLboolean isVersion1_1;
+ GLuint inputsRead;
+ GLuint outputsWritten;
+ GLboolean anyProgRegsWritten;
+ GLuint numInst; /* number of instructions parsed */
+};
+
+
+/*
+ * Called whenever we find an error during parsing.
+ */
+static void
+record_error(struct parse_state *parseState, const char *msg, int lineNo)
+{
+#ifdef DEBUG
+ GLint line, column;
+ const GLubyte *lineStr;
+ lineStr = _mesa_find_line_column(parseState->start,
+ parseState->pos, &line, &column);
+ _mesa_debug(parseState->ctx,
+ "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
+ lineNo, line, column, (char *) lineStr, msg);
+ _mesa_free((void *) lineStr);
+#else
+ (void) lineNo;
+#endif
+
+ /* Check that no error was already recorded. Only record the first one. */
+ if (parseState->ctx->Program.ErrorString[0] == 0) {
+ _mesa_set_program_error(parseState->ctx,
+ parseState->pos - parseState->start,
+ msg);
+ }
+}
+
+
+#define RETURN_ERROR \
+do { \
+ record_error(parseState, "Unexpected end of input.", __LINE__); \
+ return GL_FALSE; \
+} while(0)
+
+#define RETURN_ERROR1(msg) \
+do { \
+ record_error(parseState, msg, __LINE__); \
+ return GL_FALSE; \
+} while(0)
+
+#define RETURN_ERROR2(msg1, msg2) \
+do { \
+ char err[1000]; \
+ _mesa_sprintf(err, "%s %s", msg1, msg2); \
+ record_error(parseState, err, __LINE__); \
+ return GL_FALSE; \
+} while(0)
+
+
+
+
+
+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(struct parse_state *parseState, GLubyte *token)
+{
+ const GLubyte *str = parseState->pos;
+ 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++;
+ }
+ if (str[i] == '\n' || str[i] == '\r')
+ parseState->curLine = str + i + 1;
+ }
+ else {
+ /* skip whitespace */
+ if (str[i] == '\n' || str[i] == '\r')
+ parseState->curLine = str + i + 1;
+ 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 character */
+ 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(struct parse_state *parseState, GLubyte *token)
+{
+ GLint i;
+ i = GetToken(parseState, token);
+ if (i <= 0) {
+ parseState->pos += (-i);
+ return GL_FALSE;
+ }
+ parseState->pos += i;
+ return GL_TRUE;
+}
+
+
+/**
+ * Get next token from input stream but don't increment stream pointer.
+ */
+static GLboolean
+Peek_Token(struct parse_state *parseState, GLubyte *token)
+{
+ GLint i, len;
+ i = GetToken(parseState, token);
+ if (i <= 0) {
+ parseState->pos += (-i);
+ return GL_FALSE;
+ }
+ len = (GLint)_mesa_strlen((const char *) token);
+ parseState->pos += (i - len);
+ return GL_TRUE;
+}
+
+
+/**
+ * Try to match 'pattern' as the next token after any whitespace/comments.
+ * Advance the current parsing position only if we match the pattern.
+ * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
+ */
+static GLboolean
+Parse_String(struct parse_state *parseState, const char *pattern)
+{
+ const GLubyte *m;
+ GLint i;
+
+ /* skip whitespace and comments */
+ while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
+ if (*parseState->pos == '#') {
+ while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
+ parseState->pos += 1;
+ }
+ if (*parseState->pos == '\n' || *parseState->pos == '\r')
+ parseState->curLine = parseState->pos + 1;
+ }
+ else {
+ /* skip whitespace */
+ if (*parseState->pos == '\n' || *parseState->pos == '\r')
+ parseState->curLine = parseState->pos + 1;
+ parseState->pos += 1;
+ }
+ }
+
+ /* Try to match the pattern */
+ m = parseState->pos;
+ for (i = 0; pattern[i]; i++) {
+ if (*m != (GLubyte) pattern[i])
+ return GL_FALSE;
+ m += 1;
+ }
+ parseState->pos = m;
+
+ return GL_TRUE; /* success */
+}
+
+
+/**********************************************************************/
+
+static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = {
+ "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
+ "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
+};
+
+static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
+ "HPOS", "COL0", "COL1", "FOGC",
+ "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
+ "PSIZ", "BFC0", "BFC1", NULL
+};
+
+
+
+/**
+ * Parse a temporary register: Rnn
+ */
+static GLboolean
+Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
+{
+ GLubyte token[100];
+
+ /* Should be 'R##' */
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+ if (token[0] != 'R')
+ RETURN_ERROR1("Expected R##");
+
+ if (IsDigit(token[1])) {
+ GLint reg = _mesa_atoi((char *) (token + 1));
+ if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
+ RETURN_ERROR1("Bad temporary register name");
+ *tempRegNum = reg;
+ }
+ else {
+ RETURN_ERROR1("Bad temporary register name");
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse address register "A0.x"
+ */
+static GLboolean
+Parse_AddrReg(struct parse_state *parseState)
+{
+ /* match 'A0' */
+ if (!Parse_String(parseState, "A0"))
+ RETURN_ERROR;
+
+ /* match '.' */
+ if (!Parse_String(parseState, "."))
+ RETURN_ERROR;
+
+ /* match 'x' */
+ if (!Parse_String(parseState, "x"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse absolute program parameter register "c[##]"
+ */
+static GLboolean
+Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
+{
+ GLubyte token[100];
+
+ if (!Parse_String(parseState, "c"))
+ RETURN_ERROR;
+
+ if (!Parse_String(parseState, "["))
+ RETURN_ERROR;
+
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (IsDigit(token[0])) {
+ /* a numbered program parameter register */
+ GLint reg = _mesa_atoi((char *) token);
+ if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
+ RETURN_ERROR1("Bad program parameter number");
+ *regNum = reg;
+ }
+ else {
+ RETURN_ERROR;
+ }
+
+ if (!Parse_String(parseState, "]"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg)
+{
+ GLubyte token[100];
+
+ if (!Parse_String(parseState, "c"))
+ RETURN_ERROR;
+
+ if (!Parse_String(parseState, "["))
+ RETURN_ERROR;
+
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (IsDigit(token[0])) {
+ /* a numbered program parameter register */
+ GLint reg;
+ (void) Parse_Token(parseState, token);
+ reg = _mesa_atoi((char *) token);
+ if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
+ RETURN_ERROR1("Bad program parameter number");
+ srcReg->File = PROGRAM_ENV_PARAM;
+ srcReg->Index = reg;
+ }
+ else if (_mesa_strcmp((const char *) token, "A0") == 0) {
+ /* address register "A0.x" */
+ if (!Parse_AddrReg(parseState))
+ RETURN_ERROR;
+
+ srcReg->RelAddr = GL_TRUE;
+ srcReg->File = PROGRAM_ENV_PARAM;
+ /* Look for +/-N offset */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (token[0] == '-' || token[0] == '+') {
+ const GLubyte sign = token[0];
+ (void) Parse_Token(parseState, token); /* consume +/- */
+
+ /* an integer should be next */
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (IsDigit(token[0])) {
+ const GLint k = _mesa_atoi((char *) token);
+ if (sign == '-') {
+ if (k > 64)
+ RETURN_ERROR1("Bad address offset");
+ srcReg->Index = -k;
+ }
+ else {
+ if (k > 63)
+ RETURN_ERROR1("Bad address offset");
+ srcReg->Index = k;
+ }
+ }
+ else {
+ RETURN_ERROR;
+ }
+ }
+ else {
+ /* probably got a ']', catch it below */
+ }
+ }
+ else {
+ RETURN_ERROR;
+ }
+
+ /* Match closing ']' */
+ if (!Parse_String(parseState, "]"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Parse v[#] or v[<name>]
+ */
+static GLboolean
+Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
+{
+ GLubyte token[100];
+ GLint j;
+
+ /* Match 'v' */
+ if (!Parse_String(parseState, "v"))
+ RETURN_ERROR;
+
+ /* Match '[' */
+ if (!Parse_String(parseState, "["))
+ RETURN_ERROR;
+
+ /* match number or named register */
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (parseState->isStateProgram && token[0] != '0')
+ RETURN_ERROR1("Only v[0] accessible in vertex state programs");
+
+ if (IsDigit(token[0])) {
+ GLint reg = _mesa_atoi((char *) token);
+ if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
+ RETURN_ERROR1("Bad vertex attribute register name");
+ *tempRegNum = reg;
+ }
+ else {
+ for (j = 0; InputRegisters[j]; j++) {
+ if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
+ *tempRegNum = j;
+ break;
+ }
+ }
+ if (!InputRegisters[j]) {
+ /* unknown input register label */
+ RETURN_ERROR2("Bad register name", token);
+ }
+ }
+
+ /* Match '[' */
+ if (!Parse_String(parseState, "]"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
+{
+ GLubyte token[100];
+ GLint start, j;
+
+ /* Match 'o' */
+ if (!Parse_String(parseState, "o"))
+ RETURN_ERROR;
+
+ /* Match '[' */
+ if (!Parse_String(parseState, "["))
+ RETURN_ERROR;
+
+ /* Get output reg name */
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (parseState->isPositionInvariant)
+ start = 1; /* skip HPOS register name */
+ else
+ start = 0;
+
+ /* try to match an output register name */
+ for (j = start; OutputRegisters[j]; j++) {
+ if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
+ *outputRegNum = j;
+ break;
+ }
+ }
+ if (!OutputRegisters[j])
+ RETURN_ERROR1("Unrecognized output register name");
+
+ /* Match ']' */
+ if (!Parse_String(parseState, "]"))
+ RETURN_ERROR1("Expected ]");
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
+{
+ GLubyte token[100];
+ GLint idx;
+
+ /* Dst reg can be R<n> or o[n] */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (token[0] == 'R') {
+ /* a temporary register */
+ dstReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &idx))
+ RETURN_ERROR;
+ dstReg->Index = idx;
+ }
+ else if (!parseState->isStateProgram && token[0] == 'o') {
+ /* an output register */
+ dstReg->File = PROGRAM_OUTPUT;
+ if (!Parse_OutputReg(parseState, &idx))
+ RETURN_ERROR;
+ dstReg->Index = idx;
+ }
+ else if (parseState->isStateProgram && token[0] == 'c' &&
+ parseState->isStateProgram) {
+ /* absolute program parameter register */
+ /* Only valid for vertex state programs */
+ dstReg->File = PROGRAM_ENV_PARAM;
+ if (!Parse_AbsParamReg(parseState, &idx))
+ RETURN_ERROR;
+ dstReg->Index = idx;
+ }
+ else {
+ RETURN_ERROR1("Bad destination register name");
+ }
+
+ /* Parse optional write mask */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (token[0] == '.') {
+ /* got a mask */
+ GLint k = 0;
+
+ if (!Parse_String(parseState, "."))
+ RETURN_ERROR;
+
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ dstReg->WriteMask = 0;
+
+ if (token[k] == 'x') {
+ dstReg->WriteMask |= WRITEMASK_X;
+ k++;
+ }
+ if (token[k] == 'y') {
+ dstReg->WriteMask |= WRITEMASK_Y;
+ k++;
+ }
+ if (token[k] == 'z') {
+ dstReg->WriteMask |= WRITEMASK_Z;
+ k++;
+ }
+ if (token[k] == 'w') {
+ dstReg->WriteMask |= WRITEMASK_W;
+ k++;
+ }
+ if (k == 0) {
+ RETURN_ERROR1("Bad writemask character");
+ }
+ return GL_TRUE;
+ }
+ else {
+ dstReg->WriteMask = WRITEMASK_XYZW;
+ return GL_TRUE;
+ }
+}
+
+
+static GLboolean
+Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
+{
+ GLubyte token[100];
+ GLint idx;
+
+ srcReg->RelAddr = GL_FALSE;
+
+ /* check for '-' */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+ if (token[0] == '-') {
+ (void) Parse_String(parseState, "-");
+ srcReg->NegateBase = NEGATE_XYZW;
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+ }
+ else {
+ srcReg->NegateBase = NEGATE_NONE;
+ }
+
+ /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
+ if (token[0] == 'R') {
+ srcReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == 'c') {
+ if (!Parse_ParamReg(parseState, srcReg))
+ RETURN_ERROR;
+ }
+ else if (token[0] == 'v') {
+ srcReg->File = PROGRAM_INPUT;
+ if (!Parse_AttribReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else {
+ RETURN_ERROR2("Bad source register name", token);
+ }
+
+ /* init swizzle fields */
+ srcReg->Swizzle = SWIZZLE_NOOP;
+
+ /* Look for optional swizzle suffix */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+ if (token[0] == '.') {
+ (void) Parse_String(parseState, "."); /* consume . */
+
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (token[1] == 0) {
+ /* single letter swizzle */
+ if (token[0] == 'x')
+ srcReg->Swizzle = MAKE_SWIZZLE4(0, 0, 0, 0);
+ else if (token[0] == 'y')
+ srcReg->Swizzle = MAKE_SWIZZLE4(1, 1, 1, 1);
+ else if (token[0] == 'z')
+ srcReg->Swizzle = MAKE_SWIZZLE4(2, 2, 2, 2);
+ else if (token[0] == 'w')
+ srcReg->Swizzle = MAKE_SWIZZLE4(3, 3, 3, 3);
+ else
+ RETURN_ERROR1("Expected x, y, z, or w");
+ }
+ else {
+ /* 2, 3 or 4-component swizzle */
+ GLint k;
+
+ srcReg->Swizzle = 0;
+
+ for (k = 0; token[k] && k < 5; k++) {
+ if (token[k] == 'x')
+ srcReg->Swizzle |= 0 << (k*3);
+ else if (token[k] == 'y')
+ srcReg->Swizzle |= 1 << (k*3);
+ else if (token[k] == 'z')
+ srcReg->Swizzle |= 2 << (k*3);
+ else if (token[k] == 'w')
+ srcReg->Swizzle |= 3 << (k*3);
+ else
+ RETURN_ERROR;
+ }
+ if (k >= 5)
+ RETURN_ERROR;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
+{
+ GLubyte token[100];
+ GLint idx;
+
+ srcReg->RelAddr = GL_FALSE;
+
+ /* check for '-' */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+ if (token[0] == '-') {
+ srcReg->NegateBase = NEGATE_XYZW;
+ (void) Parse_String(parseState, "-"); /* consume '-' */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+ }
+ else {
+ srcReg->NegateBase = NEGATE_NONE;
+ }
+
+ /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
+ if (token[0] == 'R') {
+ srcReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == 'c') {
+ if (!Parse_ParamReg(parseState, srcReg))
+ RETURN_ERROR;
+ }
+ else if (token[0] == 'v') {
+ srcReg->File = PROGRAM_INPUT;
+ if (!Parse_AttribReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else {
+ RETURN_ERROR2("Bad source register name", token);
+ }
+
+ /* Look for .[xyzw] suffix */
+ if (!Parse_String(parseState, "."))
+ RETURN_ERROR;
+
+ if (!Parse_Token(parseState, token))
+ RETURN_ERROR;
+
+ if (token[0] == 'x' && token[1] == 0) {
+ srcReg->Swizzle = 0;
+ }
+ else if (token[0] == 'y' && token[1] == 0) {
+ srcReg->Swizzle = 1;
+ }
+ else if (token[0] == 'z' && token[1] == 0) {
+ srcReg->Swizzle = 2;
+ }
+ else if (token[0] == 'w' && token[1] == 0) {
+ srcReg->Swizzle = 3;
+ }
+ else {
+ RETURN_ERROR1("Bad scalar source suffix");
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLint
+Parse_UnaryOpInstruction(struct parse_state *parseState,
+ struct prog_instruction *inst,
+ enum prog_opcode opcode)
+{
+ if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
+ RETURN_ERROR1("ABS illegal for vertex program 1.0");
+
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
+
+ /* dest reg */
+ if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* src arg */
+ if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+
+ /* semicolon */
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_BiOpInstruction(struct parse_state *parseState,
+ struct prog_instruction *inst,
+ enum prog_opcode opcode)
+{
+ if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
+ RETURN_ERROR1("DPH illegal for vertex program 1.0");
+ if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
+ RETURN_ERROR1("SUB illegal for vertex program 1.0");
+
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
+
+ /* dest reg */
+ if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* first src arg */
+ if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* second src arg */
+ if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
+ RETURN_ERROR;
+
+ /* semicolon */
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR;
+
+ /* make sure we don't reference more than one program parameter register */
+ if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[0].Index != inst->SrcReg[1].Index)
+ RETURN_ERROR1("Can't reference two program parameter registers");
+
+ /* make sure we don't reference more than one vertex attribute register */
+ if (inst->SrcReg[0].File == PROGRAM_INPUT &&
+ inst->SrcReg[1].File == PROGRAM_INPUT &&
+ inst->SrcReg[0].Index != inst->SrcReg[1].Index)
+ RETURN_ERROR1("Can't reference two vertex attribute registers");
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_TriOpInstruction(struct parse_state *parseState,
+ struct prog_instruction *inst,
+ enum prog_opcode opcode)
+{
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
+
+ /* dest reg */
+ if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* first src arg */
+ if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* second src arg */
+ if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* third src arg */
+ if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
+ RETURN_ERROR;
+
+ /* semicolon */
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR;
+
+ /* make sure we don't reference more than one program parameter register */
+ if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
+ (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
+ (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
+ inst->SrcReg[1].Index != inst->SrcReg[2].Index))
+ RETURN_ERROR1("Can only reference one program register");
+
+ /* make sure we don't reference more than one vertex attribute register */
+ if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
+ inst->SrcReg[1].File == PROGRAM_INPUT &&
+ inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
+ (inst->SrcReg[0].File == PROGRAM_INPUT &&
+ inst->SrcReg[2].File == PROGRAM_INPUT &&
+ inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
+ (inst->SrcReg[1].File == PROGRAM_INPUT &&
+ inst->SrcReg[2].File == PROGRAM_INPUT &&
+ inst->SrcReg[1].Index != inst->SrcReg[2].Index))
+ RETURN_ERROR1("Can only reference one input register");
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_ScalarInstruction(struct parse_state *parseState,
+ struct prog_instruction *inst,
+ enum prog_opcode opcode)
+{
+ if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
+ RETURN_ERROR1("RCC illegal for vertex program 1.0");
+
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
+
+ /* dest reg */
+ if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* first src arg */
+ if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+
+ /* semicolon */
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
+{
+ inst->Opcode = OPCODE_ARL;
+ inst->StringPos = parseState->curLine - parseState->start;
+
+ /* Make ARB_vp backends happy */
+ inst->DstReg.File = PROGRAM_ADDRESS;
+ inst->DstReg.WriteMask = WRITEMASK_X;
+ inst->DstReg.Index = 0;
+
+ /* dest A0 reg */
+ if (!Parse_AddrReg(parseState))
+ RETURN_ERROR;
+
+ /* comma */
+ if (!Parse_String(parseState, ","))
+ RETURN_ERROR;
+
+ /* parse src reg */
+ if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
+ RETURN_ERROR;
+
+ /* semicolon */
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
+{
+ GLubyte token[100];
+
+ inst->Opcode = OPCODE_END;
+ inst->StringPos = parseState->curLine - parseState->start;
+
+ /* this should fail! */
+ if (Parse_Token(parseState, token))
+ RETURN_ERROR2("Unexpected token after END:", token);
+ else
+ return GL_TRUE;
+}
+
+
+/**
+ * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
+ * the vertex program developer.
+ * The NV_vertex_program extension grammar is modified as follows:
+ *
+ * <instruction> ::= <ARL-instruction>
+ * | ...
+ * | <PRINT-instruction>
+ *
+ * <PRINT-instruction> ::= "PRINT" <string literal>
+ * | "PRINT" <string literal> "," <srcReg>
+ * | "PRINT" <string literal> "," <dstReg>
+ */
+static GLboolean
+Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
+{
+ const GLubyte *str;
+ GLubyte *msg;
+ GLuint len;
+ GLubyte token[100];
+ struct prog_src_register *srcReg = &inst->SrcReg[0];
+ GLint idx;
+
+ inst->Opcode = OPCODE_PRINT;
+ inst->StringPos = parseState->curLine - parseState->start;
+
+ /* The first argument is a literal string 'just like this' */
+ if (!Parse_String(parseState, "'"))
+ RETURN_ERROR;
+
+ str = parseState->pos;
+ for (len = 0; str[len] != '\''; len++) /* find closing quote */
+ ;
+ parseState->pos += len + 1;
+ msg = (GLubyte*) _mesa_malloc(len + 1);
+
+ _mesa_memcpy(msg, str, len);
+ msg[len] = 0;
+ inst->Data = msg;
+
+ /* comma */
+ if (Parse_String(parseState, ",")) {
+
+ /* The second argument is a register name */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+
+ srcReg->RelAddr = GL_FALSE;
+ srcReg->NegateBase = NEGATE_NONE;
+ srcReg->Swizzle = SWIZZLE_NOOP;
+
+ /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
+ * or an o[n] output register.
+ */
+ if (token[0] == 'R') {
+ srcReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == 'c') {
+ srcReg->File = PROGRAM_ENV_PARAM;
+ if (!Parse_ParamReg(parseState, srcReg))
+ RETURN_ERROR;
+ }
+ else if (token[0] == 'v') {
+ srcReg->File = PROGRAM_INPUT;
+ if (!Parse_AttribReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else if (token[0] == 'o') {
+ srcReg->File = PROGRAM_OUTPUT;
+ if (!Parse_OutputReg(parseState, &idx))
+ RETURN_ERROR;
+ srcReg->Index = idx;
+ }
+ else {
+ RETURN_ERROR2("Bad source register name", token);
+ }
+ }
+ else {
+ srcReg->File = 0;
+ }
+
+ /* semicolon */
+ if (!Parse_String(parseState, ";"))
+ RETURN_ERROR;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+Parse_OptionSequence(struct parse_state *parseState,
+ struct prog_instruction program[])
+{
+ (void) program;
+ while (1) {
+ if (!Parse_String(parseState, "OPTION"))
+ return GL_TRUE; /* ok, not an OPTION statement */
+ if (Parse_String(parseState, "NV_position_invariant")) {
+ parseState->isPositionInvariant = GL_TRUE;
+ }
+ else {
+ RETURN_ERROR1("unexpected OPTION statement");
+ }
+ if (!Parse_String(parseState, ";"))
+ return GL_FALSE;
+ }
+}
+
+
+static GLboolean
+Parse_InstructionSequence(struct parse_state *parseState,
+ struct prog_instruction program[])
+{
+ while (1) {
+ struct prog_instruction *inst = program + parseState->numInst;
+
+ /* Initialize the instruction */
+ _mesa_init_instruction(inst);
+
+ if (Parse_String(parseState, "MOV")) {
+ if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "LIT")) {
+ if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "ABS")) {
+ if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "MUL")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "ADD")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "DP3")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "DP4")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "DST")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "MIN")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "MAX")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "SLT")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "SGE")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "DPH")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "SUB")) {
+ if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "MAD")) {
+ if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "RCP")) {
+ if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "RSQ")) {
+ if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "EXP")) {
+ if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "LOG")) {
+ if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "RCC")) {
+ if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "ARL")) {
+ if (!Parse_AddressInstruction(parseState, inst))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "PRINT")) {
+ if (!Parse_PrintInstruction(parseState, inst))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "END")) {
+ if (!Parse_EndInstruction(parseState, inst))
+ RETURN_ERROR;
+ else {
+ parseState->numInst++;
+ return GL_TRUE; /* all done */
+ }
+ }
+ else {
+ /* bad instruction name */
+ RETURN_ERROR1("Unexpected token");
+ }
+
+ /* examine input/output registers */
+ if (inst->DstReg.File == PROGRAM_OUTPUT)
+ parseState->outputsWritten |= (1 << inst->DstReg.Index);
+ else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
+ parseState->anyProgRegsWritten = GL_TRUE;
+
+ if (inst->SrcReg[0].File == PROGRAM_INPUT)
+ parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
+ if (inst->SrcReg[1].File == PROGRAM_INPUT)
+ parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
+ if (inst->SrcReg[2].File == PROGRAM_INPUT)
+ parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
+
+ parseState->numInst++;
+
+ if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
+ RETURN_ERROR1("Program too long");
+ }
+
+ RETURN_ERROR;
+}
+
+
+static GLboolean
+Parse_Program(struct parse_state *parseState,
+ struct prog_instruction instBuffer[])
+{
+ if (parseState->isVersion1_1) {
+ if (!Parse_OptionSequence(parseState, instBuffer)) {
+ return GL_FALSE;
+ }
+ }
+ return Parse_InstructionSequence(parseState, 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 gl_vertex_program *program)
+{
+ struct parse_state parseState;
+ struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
+ struct prog_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;
+
+ /* Get ready to parse */
+ parseState.ctx = ctx;
+ parseState.start = programString;
+ parseState.isPositionInvariant = GL_FALSE;
+ parseState.isVersion1_1 = GL_FALSE;
+ parseState.numInst = 0;
+ parseState.inputsRead = 0;
+ parseState.outputsWritten = 0;
+ parseState.anyProgRegsWritten = GL_FALSE;
+
+ /* Reset error state */
+ _mesa_set_program_error(ctx, -1, NULL);
+
+ /* check the program header */
+ if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
+ target = GL_VERTEX_PROGRAM_NV;
+ parseState.pos = programString + 7;
+ parseState.isStateProgram = GL_FALSE;
+ }
+ else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
+ target = GL_VERTEX_PROGRAM_NV;
+ parseState.pos = programString + 7;
+ parseState.isStateProgram = GL_FALSE;
+ parseState.isVersion1_1 = GL_TRUE;
+ }
+ else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
+ target = GL_VERTEX_STATE_PROGRAM_NV;
+ parseState.pos = programString + 8;
+ parseState.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(&parseState, instBuffer)) {
+ /* successful parse! */
+
+ if (parseState.isStateProgram) {
+ if (!parseState.anyProgRegsWritten) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glLoadProgramNV(c[#] not written)");
+ return;
+ }
+ }
+ else {
+ if (!parseState.isPositionInvariant &&
+ !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
+ /* bit 1 = HPOS register */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glLoadProgramNV(HPOS not written)");
+ return;
+ }
+ }
+
+ /* copy the compiled instructions */
+ assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
+ newInst = _mesa_alloc_instructions(parseState.numInst);
+ if (!newInst) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
+ _mesa_free(programString);
+ return; /* out of memory */
+ }
+ _mesa_memcpy(newInst, instBuffer,
+ parseState.numInst * sizeof(struct prog_instruction));
+
+ /* install the program */
+ program->Base.Target = target;
+ if (program->Base.String) {
+ _mesa_free(program->Base.String);
+ }
+ program->Base.String = programString;
+ program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
+ if (program->Base.Instructions) {
+ _mesa_free(program->Base.Instructions);
+ }
+ program->Base.Instructions = newInst;
+ program->Base.InputsRead = parseState.inputsRead;
+ program->Base.NumInstructions = parseState.numInst;
+ program->Base.OutputsWritten = parseState.outputsWritten;
+ program->IsPositionInvariant = parseState.isPositionInvariant;
+ program->IsNVProgram = GL_TRUE;
+
+#ifdef DEBUG_foo
+ _mesa_printf("--- glLoadProgramNV result ---\n");
+ _mesa_print_nv_vertex_program(program);
+ _mesa_printf("------------------------------\n");
+#endif
+ }
+ else {
+ /* Error! */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
+ /* NOTE: _mesa_set_program_error would have been called already */
+ /* GL_NV_vertex_program isn't supposed to set the error string
+ * so we reset it here.
+ */
+ _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
+ }
+}
+
+
+static void
+PrintSrcReg(const struct prog_src_register *src)
+{
+ static const char comps[5] = "xyzw";
+ if (src->NegateBase)
+ _mesa_printf("-");
+ if (src->RelAddr) {
+ if (src->Index > 0)
+ _mesa_printf("c[A0.x + %d]", src->Index);
+ else if (src->Index < 0)
+ _mesa_printf("c[A0.x - %d]", -src->Index);
+ else
+ _mesa_printf("c[A0.x]");
+ }
+ else if (src->File == PROGRAM_OUTPUT) {
+ _mesa_printf("o[%s]", OutputRegisters[src->Index]);
+ }
+ else if (src->File == PROGRAM_INPUT) {
+ _mesa_printf("v[%s]", InputRegisters[src->Index]);
+ }
+ else if (src->File == PROGRAM_ENV_PARAM) {
+ _mesa_printf("c[%d]", src->Index);
+ }
+ else {
+ ASSERT(src->File == PROGRAM_TEMPORARY);
+ _mesa_printf("R%d", src->Index);
+ }
+
+ if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
+ GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
+ GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
+ _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
+ }
+ else if (src->Swizzle != SWIZZLE_NOOP) {
+ _mesa_printf(".%c%c%c%c",
+ comps[GET_SWZ(src->Swizzle, 0)],
+ comps[GET_SWZ(src->Swizzle, 1)],
+ comps[GET_SWZ(src->Swizzle, 2)],
+ comps[GET_SWZ(src->Swizzle, 3)]);
+ }
+}
+
+
+static void
+PrintDstReg(const struct prog_dst_register *dst)
+{
+ if (dst->File == PROGRAM_OUTPUT) {
+ _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
+ }
+ else if (dst->File == PROGRAM_INPUT) {
+ _mesa_printf("v[%s]", InputRegisters[dst->Index]);
+ }
+ else if (dst->File == PROGRAM_ENV_PARAM) {
+ _mesa_printf("c[%d]", dst->Index);
+ }
+ else {
+ ASSERT(dst->File == PROGRAM_TEMPORARY);
+ _mesa_printf("R%d", dst->Index);
+ }
+
+ if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
+ _mesa_printf(".");
+ if (dst->WriteMask & WRITEMASK_X)
+ _mesa_printf("x");
+ if (dst->WriteMask & WRITEMASK_Y)
+ _mesa_printf("y");
+ if (dst->WriteMask & WRITEMASK_Z)
+ _mesa_printf("z");
+ if (dst->WriteMask & WRITEMASK_W)
+ _mesa_printf("w");
+ }
+}
+
+
+/**
+ * Print a single NVIDIA vertex program instruction.
+ */
+void
+_mesa_print_nv_vertex_instruction(const struct prog_instruction *inst)
+{
+ GLuint i, n;
+
+ switch (inst->Opcode) {
+ case OPCODE_MOV:
+ case OPCODE_LIT:
+ case OPCODE_RCP:
+ case OPCODE_RSQ:
+ case OPCODE_EXP:
+ case OPCODE_LOG:
+ case OPCODE_RCC:
+ case OPCODE_ABS:
+ case OPCODE_MUL:
+ case OPCODE_ADD:
+ case OPCODE_DP3:
+ case OPCODE_DP4:
+ case OPCODE_DST:
+ case OPCODE_MIN:
+ case OPCODE_MAX:
+ case OPCODE_SLT:
+ case OPCODE_SGE:
+ case OPCODE_DPH:
+ case OPCODE_SUB:
+ case OPCODE_MAD:
+ _mesa_printf("%s ", _mesa_opcode_string(inst->Opcode));
+ PrintDstReg(&inst->DstReg);
+ _mesa_printf(", ");
+ n = _mesa_num_inst_src_regs(inst->Opcode);
+ for (i = 0; i < n; i++) {
+ PrintSrcReg(&inst->SrcReg[i]);
+ if (i + 1 < n)
+ _mesa_printf(", ");
+ }
+ _mesa_printf(";\n");
+ break;
+ case OPCODE_ARL:
+ _mesa_printf("ARL A0.x, ");
+ PrintSrcReg(&inst->SrcReg[0]);
+ _mesa_printf(";\n");
+ break;
+ case OPCODE_PRINT:
+ _mesa_printf("PRINT '%s'", inst->Data);
+ if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+ _mesa_printf(", ");
+ PrintSrcReg(&inst->SrcReg[0]);
+ _mesa_printf(";\n");
+ }
+ else {
+ _mesa_printf("\n");
+ }
+ break;
+ case OPCODE_END:
+ _mesa_printf("END\n");
+ break;
+ default:
+ _mesa_printf("BAD INSTRUCTION\n");
+ }
+}
+
+
+/**
+ * Print (unparse) the given vertex program. Just for debugging.
+ */
+void
+_mesa_print_nv_vertex_program(const struct gl_vertex_program *program)
+{
+ const struct prog_instruction *inst;
+
+ for (inst = program->Base.Instructions; ; inst++) {
+ _mesa_print_nv_vertex_instruction(inst);
+ if (inst->Opcode == OPCODE_END)
+ return;
+ }
+}
+
+
+const char *
+_mesa_nv_vertex_input_register_name(GLuint i)
+{
+ ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
+ return InputRegisters[i];
+}
+
+
+const char *
+_mesa_nv_vertex_output_register_name(GLuint i)
+{
+ ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
+ return OutputRegisters[i];
+}
+
diff --git a/src/mesa/shader/nvvertparse.h b/src/mesa/shader/nvvertparse.h
new file mode 100644
index 00000000000..15fb03cd4e4
--- /dev/null
+++ b/src/mesa/shader/nvvertparse.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ * 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 gl_vertex_program *program);
+
+extern void
+_mesa_print_nv_vertex_instruction(const struct prog_instruction *inst);
+
+extern void
+_mesa_print_nv_vertex_program(const struct gl_vertex_program *program);
+
+extern const char *
+_mesa_nv_vertex_input_register_name(GLuint i);
+
+extern const char *
+_mesa_nv_vertex_output_register_name(GLuint i);
+
+#endif
diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c
new file mode 100644
index 00000000000..590f357b636
--- /dev/null
+++ b/src/mesa/shader/program.c
@@ -0,0 +1,2206 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 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 program.c
+ * Vertex and fragment program support functions.
+ * \author Brian Paul
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "program.h"
+#include "nvfragparse.h"
+#include "program_instruction.h"
+#include "nvvertparse.h"
+#include "atifragshader.h"
+
+
+static const char *
+make_state_string(const GLint stateTokens[6]);
+
+static GLuint
+make_state_flags(const GLint state[]);
+
+
+/**********************************************************************/
+/* Utility functions */
+/**********************************************************************/
+
+
+/* A pointer to this dummy program is put into the hash table when
+ * glGenPrograms is called.
+ */
+struct gl_program _mesa_DummyProgram;
+
+
+/**
+ * Init context's vertex/fragment program state
+ */
+void
+_mesa_init_program(GLcontext *ctx)
+{
+ GLuint i;
+
+ ctx->Program.ErrorPos = -1;
+ ctx->Program.ErrorString = _mesa_strdup("");
+
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ ctx->VertexProgram.Enabled = GL_FALSE;
+ ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
+ ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
+ ctx->VertexProgram.Current = (struct gl_vertex_program *) ctx->Shared->DefaultVertexProgram;
+ assert(ctx->VertexProgram.Current);
+ ctx->VertexProgram.Current->Base.RefCount++;
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
+ ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
+ ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
+ }
+#endif
+
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ ctx->FragmentProgram.Enabled = GL_FALSE;
+ ctx->FragmentProgram.Current = (struct gl_fragment_program *) ctx->Shared->DefaultFragmentProgram;
+ assert(ctx->FragmentProgram.Current);
+ ctx->FragmentProgram.Current->Base.RefCount++;
+#endif
+
+ /* XXX probably move this stuff */
+#if FEATURE_ATI_fragment_shader
+ ctx->ATIFragmentShader.Enabled = GL_FALSE;
+ ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
+ assert(ctx->ATIFragmentShader.Current);
+ ctx->ATIFragmentShader.Current->RefCount++;
+#endif
+}
+
+
+/**
+ * Free a context's vertex/fragment program state
+ */
+void
+_mesa_free_program_data(GLcontext *ctx)
+{
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ if (ctx->VertexProgram.Current) {
+ ctx->VertexProgram.Current->Base.RefCount--;
+ if (ctx->VertexProgram.Current->Base.RefCount <= 0)
+ ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base));
+ }
+#endif
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ if (ctx->FragmentProgram.Current) {
+ ctx->FragmentProgram.Current->Base.RefCount--;
+ if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
+ ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
+ }
+#endif
+ /* XXX probably move this stuff */
+#if FEATURE_ATI_fragment_shader
+ if (ctx->ATIFragmentShader.Current) {
+ ctx->ATIFragmentShader.Current->RefCount--;
+ if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
+ _mesa_free(ctx->ATIFragmentShader.Current);
+ }
+ }
+#endif
+ _mesa_free((void *) ctx->Program.ErrorString);
+}
+
+
+
+
+/**
+ * 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);
+}
+
+
+/**
+ * Find the line number and column for 'pos' within 'string'.
+ * Return a copy of the line which contains 'pos'. Free the line with
+ * _mesa_free().
+ * \param string the program string
+ * \param pos the position within the string
+ * \param line returns the line number corresponding to 'pos'.
+ * \param col returns the column number corresponding to 'pos'.
+ * \return copy of the line containing 'pos'.
+ */
+const GLubyte *
+_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
+ GLint *line, GLint *col)
+{
+ const GLubyte *lineStart = string;
+ const GLubyte *p = string;
+ GLubyte *s;
+ int len;
+
+ *line = 1;
+
+ while (p != pos) {
+ if (*p == (GLubyte) '\n') {
+ (*line)++;
+ lineStart = p + 1;
+ }
+ p++;
+ }
+
+ *col = (pos - lineStart) + 1;
+
+ /* return copy of this line */
+ while (*p != 0 && *p != '\n')
+ p++;
+ len = p - lineStart;
+ s = (GLubyte *) _mesa_malloc(len + 1);
+ _mesa_memcpy(s, lineStart, len);
+ s[len] = 0;
+
+ return s;
+}
+
+
+/**
+ * Initialize a new vertex/fragment program object.
+ */
+static struct gl_program *
+_mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog,
+ GLenum target, GLuint id)
+{
+ (void) ctx;
+ if (prog) {
+ prog->Id = id;
+ prog->Target = target;
+ prog->Resident = GL_TRUE;
+ prog->RefCount = 1;
+ }
+
+ return prog;
+}
+
+
+/**
+ * Initialize a new fragment program object.
+ */
+struct gl_program *
+_mesa_init_fragment_program( GLcontext *ctx, struct gl_fragment_program *prog,
+ GLenum target, GLuint id)
+{
+ if (prog)
+ return _mesa_init_program_struct( ctx, &prog->Base, target, id );
+ else
+ return NULL;
+}
+
+
+/**
+ * Initialize a new vertex program object.
+ */
+struct gl_program *
+_mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog,
+ GLenum target, GLuint id)
+{
+ if (prog)
+ return _mesa_init_program_struct( ctx, &prog->Base, target, id );
+ else
+ return NULL;
+}
+
+
+/**
+ * Allocate and initialize a new fragment/vertex program object but
+ * don't put it into the program hash table. Called via
+ * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a
+ * device driver function to implement OO deriviation with additional
+ * types not understood by this function.
+ *
+ * \param ctx context
+ * \param id program id/number
+ * \param target program target/type
+ * \return pointer to new program object
+ */
+struct gl_program *
+_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
+{
+ switch (target) {
+ case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
+ return _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
+ target, id );
+ case GL_FRAGMENT_PROGRAM_NV:
+ case GL_FRAGMENT_PROGRAM_ARB:
+ return _mesa_init_fragment_program(ctx,
+ CALLOC_STRUCT(gl_fragment_program),
+ target, id );
+ default:
+ _mesa_problem(ctx, "bad target in _mesa_new_program");
+ return NULL;
+ }
+}
+
+
+/**
+ * Delete a program and remove it from the hash table, ignoring the
+ * reference count.
+ * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation)
+ * by a device driver function.
+ */
+void
+_mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
+{
+ (void) ctx;
+ ASSERT(prog);
+
+ if (prog->String)
+ _mesa_free(prog->String);
+
+ if (prog->Instructions) {
+ GLuint i;
+ for (i = 0; i < prog->NumInstructions; i++) {
+ if (prog->Instructions[i].Data)
+ _mesa_free(prog->Instructions[i].Data);
+ }
+ _mesa_free(prog->Instructions);
+ }
+
+ if (prog->Parameters) {
+ _mesa_free_parameter_list(prog->Parameters);
+ }
+
+ /* XXX this is a little ugly */
+ if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
+ struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
+ if (vprog->TnlData)
+ _mesa_free(vprog->TnlData);
+ }
+
+ _mesa_free(prog);
+}
+
+
+/**
+ * Return the gl_program object for a given ID.
+ * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
+ * casts elsewhere.
+ */
+struct gl_program *
+_mesa_lookup_program(GLcontext *ctx, GLuint id)
+{
+ if (id)
+ return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+ else
+ return NULL;
+}
+
+
+/**********************************************************************/
+/* Program parameter functions */
+/**********************************************************************/
+
+struct gl_program_parameter_list *
+_mesa_new_parameter_list(void)
+{
+ return (struct gl_program_parameter_list *)
+ _mesa_calloc(sizeof(struct gl_program_parameter_list));
+}
+
+
+/**
+ * Free a parameter list and all its parameters
+ */
+void
+_mesa_free_parameter_list(struct gl_program_parameter_list *paramList)
+{
+ GLuint i;
+ for (i = 0; i < paramList->NumParameters; i++) {
+ if (paramList->Parameters[i].Name)
+ _mesa_free((void *) paramList->Parameters[i].Name);
+ }
+ _mesa_free(paramList->Parameters);
+ if (paramList->ParameterValues)
+ _mesa_align_free(paramList->ParameterValues);
+ _mesa_free(paramList);
+}
+
+
+/**
+ * Add a new parameter to a parameter list.
+ * \param paramList the list to add the parameter to
+ * \param name the parameter name, will be duplicated/copied!
+ * \param values initial parameter value, 4 GLfloats
+ * \param type type of parameter, such as
+ * \return index of new parameter in the list, or -1 if error (out of mem)
+ */
+static GLint
+add_parameter(struct gl_program_parameter_list *paramList,
+ const char *name, const GLfloat values[4],
+ enum register_file type)
+{
+ const GLuint n = paramList->NumParameters;
+
+ if (n == paramList->Size) {
+ /* Need to grow the parameter list array */
+ if (paramList->Size == 0)
+ paramList->Size = 8;
+ else
+ paramList->Size *= 2;
+
+ /* realloc arrays */
+ paramList->Parameters = (struct gl_program_parameter *)
+ _mesa_realloc(paramList->Parameters,
+ n * sizeof(struct gl_program_parameter),
+ paramList->Size * sizeof(struct gl_program_parameter));
+
+ paramList->ParameterValues = (GLfloat (*)[4])
+ _mesa_align_realloc(paramList->ParameterValues, /* old buf */
+ n * 4 * sizeof(GLfloat), /* old size */
+ paramList->Size * 4 *sizeof(GLfloat), /* new sz */
+ 16);
+ }
+
+ if (!paramList->Parameters ||
+ !paramList->ParameterValues) {
+ /* out of memory */
+ paramList->NumParameters = 0;
+ paramList->Size = 0;
+ return -1;
+ }
+ else {
+ paramList->NumParameters = n + 1;
+
+ _mesa_memset(&paramList->Parameters[n], 0,
+ sizeof(struct gl_program_parameter));
+
+ paramList->Parameters[n].Name = name ? _mesa_strdup(name) : NULL;
+ paramList->Parameters[n].Type = type;
+ if (values)
+ COPY_4V(paramList->ParameterValues[n], values);
+ return (GLint) n;
+ }
+}
+
+
+/**
+ * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
+ * \return index of the new entry in the parameter list
+ */
+GLint
+_mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
+ const char *name, const GLfloat values[4])
+{
+ return add_parameter(paramList, name, values, PROGRAM_NAMED_PARAM);
+}
+
+
+/**
+ * Add a new named constant to the parameter list.
+ * This will be used when the program contains something like this:
+ * PARAM myVals = { 0, 1, 2, 3 };
+ *
+ * \param paramList - the parameter list
+ * \param values - four float values
+ * \return index of the new parameter.
+ */
+GLint
+_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
+ const char *name, const GLfloat values[4])
+{
+ return add_parameter(paramList, name, values, PROGRAM_CONSTANT);
+}
+
+
+/**
+ * Add a new unnamed constant to the parameter list.
+ * This will be used when the program contains something like this:
+ * MOV r, { 0, 1, 2, 3 };
+ *
+ * \param paramList - the parameter list
+ * \param values - four float values
+ * \return index of the new parameter.
+ */
+GLint
+_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
+ const GLfloat values[4])
+{
+ return add_parameter(paramList, NULL, values, PROGRAM_CONSTANT);
+}
+
+
+/**
+ * Add a new state reference to the parameter list.
+ * This will be used when the program contains something like this:
+ * PARAM ambient = state.material.front.ambient;
+ *
+ * \param paramList - the parameter list
+ * \param state - an array of 6 state tokens
+ * \return index of the new parameter.
+ */
+GLint
+_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
+ const GLint *stateTokens)
+{
+ /* XXX we should probably search the current parameter list to see if
+ * the new state reference is already present.
+ */
+ GLint index;
+ const char *name = make_state_string(stateTokens);
+
+ index = add_parameter(paramList, name, NULL, PROGRAM_STATE_VAR);
+ if (index >= 0) {
+ GLuint i;
+ for (i = 0; i < 6; i++) {
+ paramList->Parameters[index].StateIndexes[i]
+ = (enum state_index) stateTokens[i];
+ }
+ paramList->StateFlags |=
+ make_state_flags(stateTokens);
+ }
+
+ /* free name string here since we duplicated it in add_parameter() */
+ _mesa_free((void *) name);
+
+ return index;
+}
+
+
+/**
+ * Lookup a parameter value by name in the given parameter list.
+ * \return pointer to the float[4] values.
+ */
+GLfloat *
+_mesa_lookup_parameter_value(struct gl_program_parameter_list *paramList,
+ GLsizei nameLen, const char *name)
+{
+ GLuint i;
+
+ if (!paramList)
+ return NULL;
+
+ if (nameLen == -1) {
+ /* name is null-terminated */
+ for (i = 0; i < paramList->NumParameters; i++) {
+ if (paramList->Parameters[i].Name &&
+ _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
+ return paramList->ParameterValues[i];
+ }
+ }
+ else {
+ /* name is not null-terminated, use nameLen */
+ for (i = 0; i < paramList->NumParameters; i++) {
+ if (paramList->Parameters[i].Name &&
+ _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
+ && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
+ return paramList->ParameterValues[i];
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Lookup a parameter index by name in the given parameter list.
+ * \return index of parameter in the list.
+ */
+GLint
+_mesa_lookup_parameter_index(struct gl_program_parameter_list *paramList,
+ GLsizei nameLen, const char *name)
+{
+ GLint i;
+
+ if (!paramList)
+ return -1;
+
+ if (nameLen == -1) {
+ /* name is null-terminated */
+ for (i = 0; i < (GLint) paramList->NumParameters; i++) {
+ if (paramList->Parameters[i].Name &&
+ _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
+ return i;
+ }
+ }
+ else {
+ /* name is not null-terminated, use nameLen */
+ for (i = 0; i < (GLint) paramList->NumParameters; i++) {
+ if (paramList->Parameters[i].Name &&
+ _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
+ && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * Use the list of tokens in the state[] array to find global GL state
+ * and return it in <value>. Usually, four values are returned in <value>
+ * but matrix queries may return as many as 16 values.
+ * This function is used for ARB vertex/fragment programs.
+ * The program parser will produce the state[] values.
+ */
+static void
+_mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
+ GLfloat *value)
+{
+ switch (state[0]) {
+ case STATE_MATERIAL:
+ {
+ /* state[1] is either 0=front or 1=back side */
+ const GLuint face = (GLuint) state[1];
+ /* state[2] is the material attribute */
+ switch (state[2]) {
+ case STATE_AMBIENT:
+ if (face == 0)
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
+ else
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]);
+ return;
+ case STATE_DIFFUSE:
+ if (face == 0)
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]);
+ else
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]);
+ return;
+ case STATE_SPECULAR:
+ if (face == 0)
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]);
+ else
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]);
+ return;
+ case STATE_EMISSION:
+ if (face == 0)
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
+ else
+ COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]);
+ return;
+ case STATE_SHININESS:
+ if (face == 0)
+ value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
+ else
+ value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
+ value[1] = 0.0F;
+ value[2] = 0.0F;
+ value[3] = 1.0F;
+ return;
+ default:
+ _mesa_problem(ctx, "Invalid material state in fetch_state");
+ return;
+ }
+ }
+ case STATE_LIGHT:
+ {
+ /* state[1] is the light number */
+ const GLuint ln = (GLuint) state[1];
+ /* state[2] is the light attribute */
+ switch (state[2]) {
+ case STATE_AMBIENT:
+ COPY_4V(value, ctx->Light.Light[ln].Ambient);
+ return;
+ case STATE_DIFFUSE:
+ COPY_4V(value, ctx->Light.Light[ln].Diffuse);
+ return;
+ case STATE_SPECULAR:
+ COPY_4V(value, ctx->Light.Light[ln].Specular);
+ return;
+ case STATE_POSITION:
+ COPY_4V(value, ctx->Light.Light[ln].EyePosition);
+ return;
+ case STATE_ATTENUATION:
+ value[0] = ctx->Light.Light[ln].ConstantAttenuation;
+ value[1] = ctx->Light.Light[ln].LinearAttenuation;
+ value[2] = ctx->Light.Light[ln].QuadraticAttenuation;
+ value[3] = ctx->Light.Light[ln].SpotExponent;
+ return;
+ case STATE_SPOT_DIRECTION:
+ COPY_3V(value, ctx->Light.Light[ln].EyeDirection);
+ value[3] = ctx->Light.Light[ln]._CosCutoff;
+ return;
+ case STATE_HALF:
+ {
+ GLfloat eye_z[] = {0, 0, 1};
+
+ /* Compute infinite half angle vector:
+ * half-vector = light_position + (0, 0, 1)
+ * and then normalize. w = 0
+ *
+ * light.EyePosition.w should be 0 for infinite lights.
+ */
+ ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
+ NORMALIZE_3FV(value);
+ value[3] = 0;
+ }
+ return;
+ case STATE_POSITION_NORMALIZED:
+ COPY_4V(value, ctx->Light.Light[ln].EyePosition);
+ NORMALIZE_3FV( value );
+ return;
+ default:
+ _mesa_problem(ctx, "Invalid light state in fetch_state");
+ return;
+ }
+ }
+ case STATE_LIGHTMODEL_AMBIENT:
+ COPY_4V(value, ctx->Light.Model.Ambient);
+ return;
+ case STATE_LIGHTMODEL_SCENECOLOR:
+ if (state[1] == 0) {
+ /* front */
+ GLint i;
+ for (i = 0; i < 3; i++) {
+ value[i] = ctx->Light.Model.Ambient[i]
+ * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
+ + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
+ }
+ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+ }
+ else {
+ /* back */
+ GLint i;
+ for (i = 0; i < 3; i++) {
+ value[i] = ctx->Light.Model.Ambient[i]
+ * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
+ + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
+ }
+ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+ }
+ return;
+ case STATE_LIGHTPROD:
+ {
+ const GLuint ln = (GLuint) state[1];
+ const GLuint face = (GLuint) state[2];
+ GLint i;
+ ASSERT(face == 0 || face == 1);
+ switch (state[3]) {
+ case STATE_AMBIENT:
+ for (i = 0; i < 3; i++) {
+ value[i] = ctx->Light.Light[ln].Ambient[i] *
+ ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i];
+ }
+ /* [3] = material alpha */
+ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
+ return;
+ case STATE_DIFFUSE:
+ for (i = 0; i < 3; i++) {
+ value[i] = ctx->Light.Light[ln].Diffuse[i] *
+ ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i];
+ }
+ /* [3] = material alpha */
+ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
+ return;
+ case STATE_SPECULAR:
+ for (i = 0; i < 3; i++) {
+ value[i] = ctx->Light.Light[ln].Specular[i] *
+ ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i];
+ }
+ /* [3] = material alpha */
+ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
+ return;
+ default:
+ _mesa_problem(ctx, "Invalid lightprod state in fetch_state");
+ return;
+ }
+ }
+ case STATE_TEXGEN:
+ {
+ /* state[1] is the texture unit */
+ const GLuint unit = (GLuint) state[1];
+ /* state[2] is the texgen attribute */
+ switch (state[2]) {
+ case STATE_TEXGEN_EYE_S:
+ COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneS);
+ return;
+ case STATE_TEXGEN_EYE_T:
+ COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneT);
+ return;
+ case STATE_TEXGEN_EYE_R:
+ COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneR);
+ return;
+ case STATE_TEXGEN_EYE_Q:
+ COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneQ);
+ return;
+ case STATE_TEXGEN_OBJECT_S:
+ COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneS);
+ return;
+ case STATE_TEXGEN_OBJECT_T:
+ COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneT);
+ return;
+ case STATE_TEXGEN_OBJECT_R:
+ COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneR);
+ return;
+ case STATE_TEXGEN_OBJECT_Q:
+ COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneQ);
+ return;
+ default:
+ _mesa_problem(ctx, "Invalid texgen state in fetch_state");
+ return;
+ }
+ }
+ case STATE_TEXENV_COLOR:
+ {
+ /* state[1] is the texture unit */
+ const GLuint unit = (GLuint) state[1];
+ COPY_4V(value, ctx->Texture.Unit[unit].EnvColor);
+ }
+ return;
+ case STATE_FOG_COLOR:
+ COPY_4V(value, ctx->Fog.Color);
+ return;
+ case STATE_FOG_PARAMS:
+ value[0] = ctx->Fog.Density;
+ value[1] = ctx->Fog.Start;
+ value[2] = ctx->Fog.End;
+ value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
+ return;
+ case STATE_CLIPPLANE:
+ {
+ const GLuint plane = (GLuint) state[1];
+ COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
+ }
+ return;
+ case STATE_POINT_SIZE:
+ value[0] = ctx->Point.Size;
+ value[1] = ctx->Point.MinSize;
+ value[2] = ctx->Point.MaxSize;
+ value[3] = ctx->Point.Threshold;
+ return;
+ case STATE_POINT_ATTENUATION:
+ value[0] = ctx->Point.Params[0];
+ value[1] = ctx->Point.Params[1];
+ value[2] = ctx->Point.Params[2];
+ value[3] = 1.0F;
+ return;
+ case STATE_MATRIX:
+ {
+ /* state[1] = modelview, projection, texture, etc. */
+ /* state[2] = which texture matrix or program matrix */
+ /* state[3] = first column to fetch */
+ /* state[4] = last column to fetch */
+ /* state[5] = transpose, inverse or invtrans */
+
+ const GLmatrix *matrix;
+ const enum state_index mat = state[1];
+ const GLuint index = (GLuint) state[2];
+ const GLuint first = (GLuint) state[3];
+ const GLuint last = (GLuint) state[4];
+ const enum state_index modifier = state[5];
+ const GLfloat *m;
+ GLuint row, i;
+ if (mat == STATE_MODELVIEW) {
+ matrix = ctx->ModelviewMatrixStack.Top;
+ }
+ else if (mat == STATE_PROJECTION) {
+ matrix = ctx->ProjectionMatrixStack.Top;
+ }
+ else if (mat == STATE_MVP) {
+ matrix = &ctx->_ModelProjectMatrix;
+ }
+ else if (mat == STATE_TEXTURE) {
+ matrix = ctx->TextureMatrixStack[index].Top;
+ }
+ else if (mat == STATE_PROGRAM) {
+ matrix = ctx->ProgramMatrixStack[index].Top;
+ }
+ else {
+ _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()");
+ return;
+ }
+ if (modifier == STATE_MATRIX_INVERSE ||
+ modifier == STATE_MATRIX_INVTRANS) {
+ /* Be sure inverse is up to date:
+ */
+ _math_matrix_alloc_inv( (GLmatrix *) matrix );
+ _math_matrix_analyse( (GLmatrix*) matrix );
+ m = matrix->inv;
+ }
+ else {
+ m = matrix->m;
+ }
+ if (modifier == STATE_MATRIX_TRANSPOSE ||
+ modifier == STATE_MATRIX_INVTRANS) {
+ for (i = 0, row = first; row <= last; row++) {
+ value[i++] = m[row * 4 + 0];
+ value[i++] = m[row * 4 + 1];
+ value[i++] = m[row * 4 + 2];
+ value[i++] = m[row * 4 + 3];
+ }
+ }
+ else {
+ for (i = 0, row = first; row <= last; row++) {
+ value[i++] = m[row + 0];
+ value[i++] = m[row + 4];
+ value[i++] = m[row + 8];
+ value[i++] = m[row + 12];
+ }
+ }
+ }
+ return;
+ case STATE_DEPTH_RANGE:
+ value[0] = ctx->Viewport.Near; /* near */
+ value[1] = ctx->Viewport.Far; /* far */
+ value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
+ value[3] = 0;
+ return;
+ case STATE_FRAGMENT_PROGRAM:
+ {
+ /* state[1] = {STATE_ENV, STATE_LOCAL} */
+ /* state[2] = parameter index */
+ const int idx = (int) state[2];
+ switch (state[1]) {
+ case STATE_ENV:
+ COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
+ break;
+ case STATE_LOCAL:
+ COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
+ return;
+ }
+ }
+ return;
+
+ case STATE_VERTEX_PROGRAM:
+ {
+ /* state[1] = {STATE_ENV, STATE_LOCAL} */
+ /* state[2] = parameter index */
+ const int idx = (int) state[2];
+ switch (state[1]) {
+ case STATE_ENV:
+ COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
+ break;
+ case STATE_LOCAL:
+ COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
+ return;
+ }
+ }
+ return;
+
+ case STATE_INTERNAL:
+ {
+ switch (state[1]) {
+ case STATE_NORMAL_SCALE:
+ ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
+ return;
+ }
+ }
+ return;
+
+ default:
+ _mesa_problem(ctx, "Invalid state in _mesa_fetch_state");
+ return;
+ }
+}
+
+
+/**
+ * Return a bit mask of the Mesa state flags under which a parameter's
+ * value might change.
+ */
+static GLuint make_state_flags(const GLint state[])
+{
+ switch (state[0]) {
+ case STATE_MATERIAL:
+ case STATE_LIGHT:
+ case STATE_LIGHTMODEL_AMBIENT:
+ case STATE_LIGHTMODEL_SCENECOLOR:
+ case STATE_LIGHTPROD:
+ return _NEW_LIGHT;
+
+ case STATE_TEXGEN:
+ case STATE_TEXENV_COLOR:
+ return _NEW_TEXTURE;
+
+ case STATE_FOG_COLOR:
+ case STATE_FOG_PARAMS:
+ return _NEW_FOG;
+
+ case STATE_CLIPPLANE:
+ return _NEW_TRANSFORM;
+
+ case STATE_POINT_SIZE:
+ case STATE_POINT_ATTENUATION:
+ return _NEW_POINT;
+
+ case STATE_MATRIX:
+ switch (state[1]) {
+ case STATE_MODELVIEW:
+ return _NEW_MODELVIEW;
+ case STATE_PROJECTION:
+ return _NEW_PROJECTION;
+ case STATE_MVP:
+ return _NEW_MODELVIEW | _NEW_PROJECTION;
+ case STATE_TEXTURE:
+ return _NEW_TEXTURE_MATRIX;
+ case STATE_PROGRAM:
+ return _NEW_TRACK_MATRIX;
+ default:
+ _mesa_problem(NULL, "unexpected matrix in make_state_flags()");
+ return 0;
+ }
+
+ case STATE_DEPTH_RANGE:
+ return _NEW_VIEWPORT;
+
+ case STATE_FRAGMENT_PROGRAM:
+ case STATE_VERTEX_PROGRAM:
+ return _NEW_PROGRAM;
+
+ case STATE_INTERNAL:
+ switch (state[1]) {
+ case STATE_NORMAL_SCALE:
+ return _NEW_MODELVIEW;
+ default:
+ _mesa_problem(NULL, "unexpected int. state in make_state_flags()");
+ return 0;
+ }
+
+ default:
+ _mesa_problem(NULL, "unexpected state[0] in make_state_flags()");
+ return 0;
+ }
+}
+
+
+static void
+append(char *dst, const char *src)
+{
+ while (*dst)
+ dst++;
+ while (*src)
+ *dst++ = *src++;
+ *dst = 0;
+}
+
+
+static void
+append_token(char *dst, enum state_index k)
+{
+ switch (k) {
+ case STATE_MATERIAL:
+ append(dst, "material.");
+ break;
+ case STATE_LIGHT:
+ append(dst, "light");
+ break;
+ case STATE_LIGHTMODEL_AMBIENT:
+ append(dst, "lightmodel.ambient");
+ break;
+ case STATE_LIGHTMODEL_SCENECOLOR:
+ break;
+ case STATE_LIGHTPROD:
+ append(dst, "lightprod");
+ break;
+ case STATE_TEXGEN:
+ append(dst, "texgen");
+ break;
+ case STATE_FOG_COLOR:
+ append(dst, "fog.color");
+ break;
+ case STATE_FOG_PARAMS:
+ append(dst, "fog.params");
+ break;
+ case STATE_CLIPPLANE:
+ append(dst, "clip");
+ break;
+ case STATE_POINT_SIZE:
+ append(dst, "point.size");
+ break;
+ case STATE_POINT_ATTENUATION:
+ append(dst, "point.attenuation");
+ break;
+ case STATE_MATRIX:
+ append(dst, "matrix.");
+ break;
+ case STATE_MODELVIEW:
+ append(dst, "modelview");
+ break;
+ case STATE_PROJECTION:
+ append(dst, "projection");
+ break;
+ case STATE_MVP:
+ append(dst, "mvp");
+ break;
+ case STATE_TEXTURE:
+ append(dst, "texture");
+ break;
+ case STATE_PROGRAM:
+ append(dst, "program");
+ break;
+ case STATE_MATRIX_INVERSE:
+ append(dst, ".inverse");
+ break;
+ case STATE_MATRIX_TRANSPOSE:
+ append(dst, ".transpose");
+ break;
+ case STATE_MATRIX_INVTRANS:
+ append(dst, ".invtrans");
+ break;
+ case STATE_AMBIENT:
+ append(dst, "ambient");
+ break;
+ case STATE_DIFFUSE:
+ append(dst, "diffuse");
+ break;
+ case STATE_SPECULAR:
+ append(dst, "specular");
+ break;
+ case STATE_EMISSION:
+ append(dst, "emission");
+ break;
+ case STATE_SHININESS:
+ append(dst, "shininess");
+ break;
+ case STATE_HALF:
+ append(dst, "half");
+ break;
+ case STATE_POSITION:
+ append(dst, ".position");
+ break;
+ case STATE_ATTENUATION:
+ append(dst, ".attenuation");
+ break;
+ case STATE_SPOT_DIRECTION:
+ append(dst, ".spot.direction");
+ break;
+ case STATE_TEXGEN_EYE_S:
+ append(dst, "eye.s");
+ break;
+ case STATE_TEXGEN_EYE_T:
+ append(dst, "eye.t");
+ break;
+ case STATE_TEXGEN_EYE_R:
+ append(dst, "eye.r");
+ break;
+ case STATE_TEXGEN_EYE_Q:
+ append(dst, "eye.q");
+ break;
+ case STATE_TEXGEN_OBJECT_S:
+ append(dst, "object.s");
+ break;
+ case STATE_TEXGEN_OBJECT_T:
+ append(dst, "object.t");
+ break;
+ case STATE_TEXGEN_OBJECT_R:
+ append(dst, "object.r");
+ break;
+ case STATE_TEXGEN_OBJECT_Q:
+ append(dst, "object.q");
+ break;
+ case STATE_TEXENV_COLOR:
+ append(dst, "texenv");
+ break;
+ case STATE_DEPTH_RANGE:
+ append(dst, "depth.range");
+ break;
+ case STATE_VERTEX_PROGRAM:
+ case STATE_FRAGMENT_PROGRAM:
+ break;
+ case STATE_ENV:
+ append(dst, "env");
+ break;
+ case STATE_LOCAL:
+ append(dst, "local");
+ break;
+ case STATE_INTERNAL:
+ case STATE_NORMAL_SCALE:
+ case STATE_POSITION_NORMALIZED:
+ append(dst, "(internal)");
+ break;
+ default:
+ ;
+ }
+}
+
+static void
+append_face(char *dst, GLint face)
+{
+ if (face == 0)
+ append(dst, "front.");
+ else
+ append(dst, "back.");
+}
+
+static void
+append_index(char *dst, GLint index)
+{
+ char s[20];
+ _mesa_sprintf(s, "[%d].", index);
+ append(dst, s);
+}
+
+/**
+ * Make a string from the given state vector.
+ * For example, return "state.matrix.texture[2].inverse".
+ * Use _mesa_free() to deallocate the string.
+ */
+static const char *
+make_state_string(const GLint state[6])
+{
+ char str[1000] = "";
+ char tmp[30];
+
+ append(str, "state.");
+ append_token(str, (enum state_index) state[0]);
+
+ switch (state[0]) {
+ case STATE_MATERIAL:
+ append_face(str, state[1]);
+ append_token(str, (enum state_index) state[2]);
+ break;
+ case STATE_LIGHT:
+ append(str, "light");
+ append_index(str, state[1]); /* light number [i]. */
+ append_token(str, (enum state_index) state[2]); /* coefficients */
+ break;
+ case STATE_LIGHTMODEL_AMBIENT:
+ append(str, "lightmodel.ambient");
+ break;
+ case STATE_LIGHTMODEL_SCENECOLOR:
+ if (state[1] == 0) {
+ append(str, "lightmodel.front.scenecolor");
+ }
+ else {
+ append(str, "lightmodel.back.scenecolor");
+ }
+ break;
+ case STATE_LIGHTPROD:
+ append_index(str, state[1]); /* light number [i]. */
+ append_face(str, state[2]);
+ append_token(str, (enum state_index) state[3]);
+ break;
+ case STATE_TEXGEN:
+ append_index(str, state[1]); /* tex unit [i] */
+ append_token(str, (enum state_index) state[2]); /* plane coef */
+ break;
+ case STATE_TEXENV_COLOR:
+ append_index(str, state[1]); /* tex unit [i] */
+ append(str, "color");
+ break;
+ case STATE_FOG_COLOR:
+ case STATE_FOG_PARAMS:
+ break;
+ case STATE_CLIPPLANE:
+ append_index(str, state[1]); /* plane [i] */
+ append(str, "plane");
+ break;
+ case STATE_POINT_SIZE:
+ case STATE_POINT_ATTENUATION:
+ break;
+ case STATE_MATRIX:
+ {
+ /* state[1] = modelview, projection, texture, etc. */
+ /* state[2] = which texture matrix or program matrix */
+ /* state[3] = first column to fetch */
+ /* state[4] = last column to fetch */
+ /* state[5] = transpose, inverse or invtrans */
+ const enum state_index mat = (enum state_index) state[1];
+ const GLuint index = (GLuint) state[2];
+ const GLuint first = (GLuint) state[3];
+ const GLuint last = (GLuint) state[4];
+ const enum state_index modifier = (enum state_index) state[5];
+ append_token(str, mat);
+ if (index)
+ append_index(str, index);
+ if (modifier)
+ append_token(str, modifier);
+ if (first == last)
+ _mesa_sprintf(tmp, ".row[%d]", first);
+ else
+ _mesa_sprintf(tmp, ".row[%d..%d]", first, last);
+ append(str, tmp);
+ }
+ break;
+ case STATE_DEPTH_RANGE:
+ break;
+ case STATE_FRAGMENT_PROGRAM:
+ case STATE_VERTEX_PROGRAM:
+ /* state[1] = {STATE_ENV, STATE_LOCAL} */
+ /* state[2] = parameter index */
+ append_token(str, (enum state_index) state[1]);
+ append_index(str, state[2]);
+ break;
+ case STATE_INTERNAL:
+ break;
+ default:
+ _mesa_problem(NULL, "Invalid state in maka_state_string");
+ break;
+ }
+
+ return _mesa_strdup(str);
+}
+
+
+/**
+ * Loop over all the parameters in a parameter list. If the parameter
+ * is a GL state reference, look up the current value of that state
+ * variable and put it into the parameter's Value[4] array.
+ * This would be called at glBegin time when using a fragment program.
+ */
+void
+_mesa_load_state_parameters(GLcontext *ctx,
+ struct gl_program_parameter_list *paramList)
+{
+ GLuint i;
+
+ if (!paramList)
+ return;
+
+ for (i = 0; i < paramList->NumParameters; i++) {
+ if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) {
+ _mesa_fetch_state(ctx,
+ paramList->Parameters[i].StateIndexes,
+ paramList->ParameterValues[i]);
+ }
+ }
+}
+
+
+/**
+ * Initialize program instruction fields to defaults.
+ */
+void
+_mesa_init_instruction(struct prog_instruction *inst)
+{
+ _mesa_bzero(inst, sizeof(struct prog_instruction));
+
+ inst->SrcReg[0].File = PROGRAM_UNDEFINED;
+ inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
+ inst->SrcReg[1].File = PROGRAM_UNDEFINED;
+ inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
+ inst->SrcReg[2].File = PROGRAM_UNDEFINED;
+ inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
+
+ inst->DstReg.File = PROGRAM_UNDEFINED;
+ inst->DstReg.WriteMask = WRITEMASK_XYZW;
+ inst->DstReg.CondMask = COND_TR;
+ inst->DstReg.CondSwizzle = SWIZZLE_NOOP;
+
+ inst->SaturateMode = SATURATE_OFF;
+ inst->Precision = FLOAT32;
+}
+
+
+/**
+ * Allocate an array of program instructions.
+ * \param numInst number of instructions
+ * \return pointer to instruction memory
+ */
+struct prog_instruction *
+_mesa_alloc_instructions(GLuint numInst)
+{
+ return (struct prog_instruction *)
+ _mesa_calloc(numInst * sizeof(struct prog_instruction));
+}
+
+
+/**
+ * Reallocate memory storing an array of program instructions.
+ * This is used when we need to append additional instructions onto an
+ * program.
+ * \param oldInst pointer to first of old/src instructions
+ * \param numOldInst number of instructions at <oldInst>
+ * \param numNewInst desired size of new instruction array.
+ * \return pointer to start of new instruction array.
+ */
+struct prog_instruction *
+_mesa_realloc_instructions(struct prog_instruction *oldInst,
+ GLuint numOldInst, GLuint numNewInst)
+{
+ struct prog_instruction *newInst;
+
+ newInst = (struct prog_instruction *)
+ _mesa_realloc(oldInst,
+ numOldInst * sizeof(struct prog_instruction),
+ numNewInst * sizeof(struct prog_instruction));
+
+ return newInst;
+}
+
+
+/**
+ * Basic info about each instruction
+ */
+struct instruction_info
+{
+ enum prog_opcode Opcode;
+ const char *Name;
+ GLuint NumSrcRegs;
+};
+
+/**
+ * Instruction info
+ * \note Opcode should equal array index!
+ */
+static const struct instruction_info InstInfo[MAX_OPCODE] = {
+ { OPCODE_ABS, "ABS", 1 },
+ { OPCODE_ADD, "ADD", 2 },
+ { OPCODE_ARA, "ARA", 1 },
+ { OPCODE_ARL, "ARL", 1 },
+ { OPCODE_ARL_NV, "ARL", 1 },
+ { OPCODE_ARR, "ARL", 1 },
+ { OPCODE_BRA, "BRA", 1 },
+ { OPCODE_CAL, "CAL", 1 },
+ { OPCODE_CMP, "CMP", 3 },
+ { OPCODE_COS, "COS", 1 },
+ { OPCODE_DDX, "DDX", 1 },
+ { OPCODE_DDY, "DDY", 1 },
+ { OPCODE_DP3, "DP3", 2 },
+ { OPCODE_DP4, "DP4", 2 },
+ { OPCODE_DPH, "DPH", 2 },
+ { OPCODE_DST, "DST", 2 },
+ { OPCODE_END, "END", 0 },
+ { OPCODE_EX2, "EX2", 1 },
+ { OPCODE_EXP, "EXP", 1 },
+ { OPCODE_FLR, "FLR", 1 },
+ { OPCODE_FRC, "FRC", 1 },
+ { OPCODE_KIL, "KIL", 1 },
+ { OPCODE_KIL_NV, "KIL", 0 },
+ { OPCODE_LG2, "LG2", 1 },
+ { OPCODE_LIT, "LIT", 1 },
+ { OPCODE_LOG, "LOG", 1 },
+ { OPCODE_LRP, "LRP", 3 },
+ { OPCODE_MAD, "MAD", 3 },
+ { OPCODE_MAX, "MAX", 2 },
+ { OPCODE_MIN, "MIN", 2 },
+ { OPCODE_MOV, "MOV", 1 },
+ { OPCODE_MUL, "MUL", 2 },
+ { OPCODE_PK2H, "PK2H", 1 },
+ { OPCODE_PK2US, "PK2US", 1 },
+ { OPCODE_PK4B, "PK4B", 1 },
+ { OPCODE_PK4UB, "PK4UB", 1 },
+ { OPCODE_POW, "POW", 2 },
+ { OPCODE_POPA, "POPA", 0 },
+ { OPCODE_PRINT, "PRINT", 1 },
+ { OPCODE_PUSHA, "PUSHA", 0 },
+ { OPCODE_RCC, "RCC", 1 },
+ { OPCODE_RCP, "RCP", 1 },
+ { OPCODE_RET, "RET", 1 },
+ { OPCODE_RFL, "RFL", 1 },
+ { OPCODE_RSQ, "RSQ", 1 },
+ { OPCODE_SCS, "SCS", 1 },
+ { OPCODE_SEQ, "SEQ", 2 },
+ { OPCODE_SFL, "SFL", 0 },
+ { OPCODE_SGE, "SGE", 2 },
+ { OPCODE_SGT, "SGT", 2 },
+ { OPCODE_SIN, "SIN", 1 },
+ { OPCODE_SLE, "SLE", 2 },
+ { OPCODE_SLT, "SLT", 2 },
+ { OPCODE_SNE, "SNE", 2 },
+ { OPCODE_SSG, "SSG", 1 },
+ { OPCODE_STR, "STR", 0 },
+ { OPCODE_SUB, "SUB", 2 },
+ { OPCODE_SWZ, "SWZ", 1 },
+ { OPCODE_TEX, "TEX", 1 },
+ { OPCODE_TXB, "TXB", 1 },
+ { OPCODE_TXD, "TXD", 3 },
+ { OPCODE_TXL, "TXL", 1 },
+ { OPCODE_TXP, "TXP", 1 },
+ { OPCODE_TXP_NV, "TXP", 1 },
+ { OPCODE_UP2H, "UP2H", 1 },
+ { OPCODE_UP2US, "UP2US", 1 },
+ { OPCODE_UP4B, "UP4B", 1 },
+ { OPCODE_UP4UB, "UP4UB", 1 },
+ { OPCODE_X2D, "X2D", 3 },
+ { OPCODE_XPD, "XPD", 2 }
+};
+
+
+/**
+ * Return the number of src registers for the given instruction/opcode.
+ */
+GLuint
+_mesa_num_inst_src_regs(enum prog_opcode opcode)
+{
+ GLuint i;
+#ifdef DEBUG
+ for (i = 0; i < MAX_OPCODE; i++) {
+ ASSERT(i == InstInfo[i].Opcode);
+ }
+#endif
+ for (i = 0; i < MAX_OPCODE; i++) {
+ if (InstInfo[i].Opcode == opcode) {
+ return InstInfo[i].NumSrcRegs;
+ }
+ }
+ _mesa_problem(NULL, "invalid opcode in _mesa_num_inst_src_regs");
+ return 0;
+}
+
+
+/**
+ * Return string name for given program opcode.
+ */
+const char *
+_mesa_opcode_string(enum prog_opcode opcode)
+{
+ ASSERT(opcode < MAX_OPCODE);
+ return InstInfo[opcode].Name;
+}
+
+/**
+ * Return string name for given program/register file.
+ */
+static const char *
+program_file_string(enum register_file f)
+{
+ switch (f) {
+ case PROGRAM_TEMPORARY:
+ return "TEMP";
+ case PROGRAM_LOCAL_PARAM:
+ return "LOCAL";
+ case PROGRAM_ENV_PARAM:
+ return "ENV";
+ case PROGRAM_STATE_VAR:
+ return "STATE";
+ case PROGRAM_INPUT:
+ return "INPUT";
+ case PROGRAM_OUTPUT:
+ return "OUTPUT";
+ case PROGRAM_NAMED_PARAM:
+ return "NAMED";
+ case PROGRAM_CONSTANT:
+ return "CONST";
+ case PROGRAM_WRITE_ONLY:
+ return "WRITE_ONLY";
+ case PROGRAM_ADDRESS:
+ return "ADDR";
+ default:
+ return "!unkown!";
+ }
+}
+
+
+/**
+ * Return a string representation of the given swizzle word.
+ * If extended is true, use extended (comma-separated) format.
+ */
+static const char *
+swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended)
+{
+ static const char swz[] = "xyzw01";
+ static char s[20];
+ GLuint i = 0;
+
+ if (!extended && swizzle == SWIZZLE_NOOP && negateBase == 0)
+ return ""; /* no swizzle/negation */
+
+ if (!extended)
+ s[i++] = '.';
+
+ if (negateBase & 0x1)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 0)];
+
+ if (extended) {
+ s[i++] = ',';
+ }
+
+ if (negateBase & 0x2)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 1)];
+
+ if (extended) {
+ s[i++] = ',';
+ }
+
+ if (negateBase & 0x4)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 2)];
+
+ if (extended) {
+ s[i++] = ',';
+ }
+
+ if (negateBase & 0x8)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 3)];
+
+ s[i] = 0;
+ return s;
+}
+
+
+static const char *
+writemask_string(GLuint writeMask)
+{
+ static char s[10];
+ GLuint i = 0;
+
+ if (writeMask == WRITEMASK_XYZW)
+ return "";
+
+ s[i++] = '.';
+ if (writeMask & WRITEMASK_X)
+ s[i++] = 'x';
+ if (writeMask & WRITEMASK_Y)
+ s[i++] = 'y';
+ if (writeMask & WRITEMASK_Z)
+ s[i++] = 'z';
+ if (writeMask & WRITEMASK_W)
+ s[i++] = 'w';
+
+ s[i] = 0;
+ return s;
+}
+
+static void
+print_dst_reg(const struct prog_dst_register *dstReg)
+{
+ _mesa_printf(" %s[%d]%s",
+ program_file_string((enum register_file) dstReg->File),
+ dstReg->Index,
+ writemask_string(dstReg->WriteMask));
+}
+
+static void
+print_src_reg(const struct prog_src_register *srcReg)
+{
+ _mesa_printf("%s[%d]%s",
+ program_file_string((enum register_file) srcReg->File),
+ srcReg->Index,
+ swizzle_string(srcReg->Swizzle,
+ srcReg->NegateBase, GL_FALSE));
+}
+
+
+/**
+ * Print a single vertex/fragment program instruction.
+ */
+void
+_mesa_print_instruction(const struct prog_instruction *inst)
+{
+ switch (inst->Opcode) {
+ case OPCODE_PRINT:
+ _mesa_printf("PRINT '%s'", inst->Data);
+ if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+ _mesa_printf(", ");
+ _mesa_printf("%s[%d]%s",
+ program_file_string((enum register_file) inst->SrcReg[0].File),
+ inst->SrcReg[0].Index,
+ swizzle_string(inst->SrcReg[0].Swizzle,
+ inst->SrcReg[0].NegateBase, GL_FALSE));
+ }
+ _mesa_printf(";\n");
+ break;
+ case OPCODE_SWZ:
+ _mesa_printf("SWZ");
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ _mesa_printf("_SAT");
+ print_dst_reg(&inst->DstReg);
+ _mesa_printf("%s[%d], %s;\n",
+ program_file_string((enum register_file) inst->SrcReg[0].File),
+ inst->SrcReg[0].Index,
+ swizzle_string(inst->SrcReg[0].Swizzle,
+ inst->SrcReg[0].NegateBase, GL_TRUE));
+ break;
+ case OPCODE_TEX:
+ case OPCODE_TXP:
+ case OPCODE_TXB:
+ _mesa_printf("%s", _mesa_opcode_string(inst->Opcode));
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ _mesa_printf("_SAT");
+ _mesa_printf(" ");
+ print_dst_reg(&inst->DstReg);
+ _mesa_printf(", ");
+ print_src_reg(&inst->SrcReg[0]);
+ _mesa_printf(", texture[%d], ", inst->TexSrcUnit);
+ switch (inst->TexSrcTarget) {
+ case TEXTURE_1D_INDEX: _mesa_printf("1D"); break;
+ case TEXTURE_2D_INDEX: _mesa_printf("2D"); break;
+ case TEXTURE_3D_INDEX: _mesa_printf("3D"); break;
+ case TEXTURE_CUBE_INDEX: _mesa_printf("CUBE"); break;
+ case TEXTURE_RECT_INDEX: _mesa_printf("RECT"); break;
+ default:
+ ;
+ }
+ _mesa_printf("\n");
+ break;
+ case OPCODE_ARL:
+ _mesa_printf("ARL addr.x, ");
+ print_src_reg(&inst->SrcReg[0]);
+ _mesa_printf(";\n");
+ break;
+ /* XXX may need for other special-case instructions */
+ default:
+ /* typical alu instruction */
+ {
+ const GLuint numRegs = _mesa_num_inst_src_regs(inst->Opcode);
+ GLuint j;
+
+ _mesa_printf("%s", _mesa_opcode_string(inst->Opcode));
+
+ /* frag prog only */
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ _mesa_printf("_SAT");
+
+ if (inst->DstReg.File != PROGRAM_UNDEFINED) {
+ _mesa_printf(" %s[%d]%s",
+ program_file_string((enum register_file) inst->DstReg.File),
+ inst->DstReg.Index,
+ writemask_string(inst->DstReg.WriteMask));
+ }
+
+ if (numRegs > 0)
+ _mesa_printf(", ");
+
+ for (j = 0; j < numRegs; j++) {
+ print_src_reg(inst->SrcReg + j);
+ if (j + 1 < numRegs)
+ _mesa_printf(", ");
+ }
+
+ _mesa_printf(";\n");
+ }
+ }
+}
+
+
+/**
+ * Print a vertx/fragment program to stdout.
+ * XXX this function could be greatly improved.
+ */
+void
+_mesa_print_program(const struct gl_program *prog)
+{
+ GLuint i;
+ for (i = 0; i < prog->NumInstructions; i++) {
+ _mesa_printf("%3d: ", i);
+ _mesa_print_instruction(prog->Instructions + i);
+ }
+}
+
+
+/**
+ * Print all of a program's parameters.
+ */
+void
+_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog)
+{
+ GLint i;
+
+ _mesa_printf("NumInstructions=%d\n", prog->NumInstructions);
+ _mesa_printf("NumTemporaries=%d\n", prog->NumTemporaries);
+ _mesa_printf("NumParameters=%d\n", prog->NumParameters);
+ _mesa_printf("NumAttributes=%d\n", prog->NumAttributes);
+ _mesa_printf("NumAddressRegs=%d\n", prog->NumAddressRegs);
+
+ _mesa_load_state_parameters(ctx, prog->Parameters);
+
+#if 0
+ _mesa_printf("Local Params:\n");
+ for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){
+ const GLfloat *p = prog->LocalParams[i];
+ _mesa_printf("%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]);
+ }
+#endif
+
+ for (i = 0; i < prog->Parameters->NumParameters; i++){
+ struct gl_program_parameter *param = prog->Parameters->Parameters + i;
+ const GLfloat *v = prog->Parameters->ParameterValues[i];
+ _mesa_printf("param[%d] %s = {%.3f, %.3f, %.3f, %.3f};\n",
+ i, param->Name, v[0], v[1], v[2], v[3]);
+ }
+}
+
+
+/**
+ * Mixing ARB and NV vertex/fragment programs can be tricky.
+ * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV
+ * but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV
+ * The two different fragment program targets are supposed to be compatible
+ * to some extent (see GL_ARB_fragment_program spec).
+ * This function does the compatibility check.
+ */
+static GLboolean
+compatible_program_targets(GLenum t1, GLenum t2)
+{
+ if (t1 == t2)
+ return GL_TRUE;
+ if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV)
+ return GL_TRUE;
+ if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB)
+ return GL_TRUE;
+ return GL_FALSE;
+}
+
+
+
+/**********************************************************************/
+/* API functions */
+/**********************************************************************/
+
+
+/**
+ * Bind a program (make it current)
+ * \note Called from the GL API dispatcher by both glBindProgramNV
+ * and glBindProgramARB.
+ */
+void GLAPIENTRY
+_mesa_BindProgram(GLenum target, GLuint id)
+{
+ struct gl_program *curProg, *newProg;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ /* Error-check target and get curProg */
+ if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
+ (ctx->Extensions.NV_vertex_program ||
+ ctx->Extensions.ARB_vertex_program)) {
+ curProg = &ctx->VertexProgram.Current->Base;
+ }
+ else if ((target == GL_FRAGMENT_PROGRAM_NV
+ && ctx->Extensions.NV_fragment_program) ||
+ (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program)) {
+ curProg = &ctx->FragmentProgram.Current->Base;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
+ return;
+ }
+
+ /*
+ * Get pointer to new program to bind.
+ * NOTE: binding to a non-existant program is not an error.
+ * That's supposed to be caught in glBegin.
+ */
+ if (id == 0) {
+ /* Bind a default program */
+ newProg = NULL;
+ if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
+ newProg = ctx->Shared->DefaultVertexProgram;
+ else
+ newProg = ctx->Shared->DefaultFragmentProgram;
+ }
+ else {
+ /* Bind a user program */
+ newProg = _mesa_lookup_program(ctx, id);
+ if (!newProg || newProg == &_mesa_DummyProgram) {
+ /* allocate a new program now */
+ newProg = ctx->Driver.NewProgram(ctx, target, id);
+ if (!newProg) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
+ return;
+ }
+ _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
+ }
+ else if (!compatible_program_targets(newProg->Target, target)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindProgramNV/ARB(target mismatch)");
+ return;
+ }
+ }
+
+ /** All error checking is complete now **/
+
+ if (curProg->Id == id) {
+ /* binding same program - no change */
+ return;
+ }
+
+ /* unbind/delete oldProg */
+ if (curProg->Id != 0) {
+ /* decrement refcount on previously bound fragment program */
+ curProg->RefCount--;
+ /* and delete if refcount goes below one */
+ if (curProg->RefCount <= 0) {
+ /* the program ID was already removed from the hash table */
+ ctx->Driver.DeleteProgram(ctx, curProg);
+ }
+ }
+
+ /* bind newProg */
+ if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
+ ctx->VertexProgram.Current = (struct gl_vertex_program *) newProg;
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_NV ||
+ target == GL_FRAGMENT_PROGRAM_ARB) {
+ ctx->FragmentProgram.Current = (struct gl_fragment_program *) newProg;
+ }
+ newProg->RefCount++;
+
+ /* Never null pointers */
+ ASSERT(ctx->VertexProgram.Current);
+ ASSERT(ctx->FragmentProgram.Current);
+
+ if (ctx->Driver.BindProgram)
+ ctx->Driver.BindProgram(ctx, target, newProg);
+}
+
+
+/**
+ * Delete a list of programs.
+ * \note Not compiled into display lists.
+ * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
+ */
+void GLAPIENTRY
+_mesa_DeletePrograms(GLsizei n, const GLuint *ids)
+{
+ GLint i;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+ if (n < 0) {
+ _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ids[i] != 0) {
+ struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]);
+ if (prog == &_mesa_DummyProgram) {
+ _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
+ }
+ else if (prog) {
+ /* Unbind program if necessary */
+ if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == 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_BindProgram(prog->Target, 0);
+ }
+ }
+ else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
+ prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
+ if (ctx->FragmentProgram.Current &&
+ ctx->FragmentProgram.Current->Base.Id == ids[i]) {
+ /* unbind this currently bound program */
+ _mesa_BindProgram(prog->Target, 0);
+ }
+ }
+ else {
+ _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
+ return;
+ }
+ /* The ID is immediately available for re-use now */
+ _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
+ prog->RefCount--;
+ if (prog->RefCount <= 0) {
+ ctx->Driver.DeleteProgram(ctx, prog);
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Generate a list of new program identifiers.
+ * \note Not compiled into display lists.
+ * \note Called by both glGenProgramsNV and glGenProgramsARB.
+ */
+void GLAPIENTRY
+_mesa_GenPrograms(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, "glGenPrograms");
+ return;
+ }
+
+ if (!ids)
+ return;
+
+ first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
+
+ /* Insert pointer to dummy program as placeholder */
+ for (i = 0; i < (GLuint) n; i++) {
+ _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
+ }
+
+ /* Return the program names */
+ for (i = 0; i < (GLuint) n; i++) {
+ ids[i] = first + i;
+ }
+}
+
+
+/**
+ * Determine if id names a vertex or fragment program.
+ * \note Not compiled into display lists.
+ * \note Called from both glIsProgramNV and glIsProgramARB.
+ * \param id is the program identifier
+ * \return GL_TRUE if id is a program, else GL_FALSE.
+ */
+GLboolean GLAPIENTRY
+_mesa_IsProgram(GLuint id)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ if (id == 0)
+ return GL_FALSE;
+
+ if (_mesa_lookup_program(ctx, id))
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
+
+
+
+/**********************************************************************/
+/* GL_MESA_program_debug extension */
+/**********************************************************************/
+
+
+/* XXX temporary */
+GLAPI void GLAPIENTRY
+glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
+ GLvoid *data)
+{
+ _mesa_ProgramCallbackMESA(target, callback, data);
+}
+
+
+void
+_mesa_ProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
+ GLvoid *data)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (target) {
+ case GL_FRAGMENT_PROGRAM_ARB:
+ if (!ctx->Extensions.ARB_fragment_program) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
+ return;
+ }
+ ctx->FragmentProgram.Callback = callback;
+ ctx->FragmentProgram.CallbackData = data;
+ break;
+ case GL_FRAGMENT_PROGRAM_NV:
+ if (!ctx->Extensions.NV_fragment_program) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
+ return;
+ }
+ ctx->FragmentProgram.Callback = callback;
+ ctx->FragmentProgram.CallbackData = data;
+ break;
+ case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
+ if (!ctx->Extensions.ARB_vertex_program &&
+ !ctx->Extensions.NV_vertex_program) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
+ return;
+ }
+ ctx->VertexProgram.Callback = callback;
+ ctx->VertexProgram.CallbackData = data;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
+ return;
+ }
+}
+
+
+/* XXX temporary */
+GLAPI void GLAPIENTRY
+glGetProgramRegisterfvMESA(GLenum target,
+ GLsizei len, const GLubyte *registerName,
+ GLfloat *v)
+{
+ _mesa_GetProgramRegisterfvMESA(target, len, registerName, v);
+}
+
+
+void
+_mesa_GetProgramRegisterfvMESA(GLenum target,
+ GLsizei len, const GLubyte *registerName,
+ GLfloat *v)
+{
+ char reg[1000];
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* We _should_ be inside glBegin/glEnd */
+#if 0
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramRegisterfvMESA");
+ return;
+ }
+#endif
+
+ /* make null-terminated copy of registerName */
+ len = MIN2((unsigned int) len, sizeof(reg) - 1);
+ _mesa_memcpy(reg, registerName, len);
+ reg[len] = 0;
+
+ switch (target) {
+ case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
+ if (!ctx->Extensions.ARB_vertex_program &&
+ !ctx->Extensions.NV_vertex_program) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetProgramRegisterfvMESA(target)");
+ return;
+ }
+ if (!ctx->VertexProgram._Enabled) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramRegisterfvMESA");
+ return;
+ }
+ /* GL_NV_vertex_program */
+ if (reg[0] == 'R') {
+ /* Temp register */
+ GLint i = _mesa_atoi(reg + 1);
+ if (i >= (GLint)ctx->Const.VertexProgram.MaxTemps) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramRegisterfvMESA(registerName)");
+ return;
+ }
+ COPY_4V(v, ctx->VertexProgram.Temporaries[i]);
+ }
+ else if (reg[0] == 'v' && reg[1] == '[') {
+ /* Vertex Input attribute */
+ GLuint i;
+ for (i = 0; i < ctx->Const.VertexProgram.MaxAttribs; i++) {
+ const char *name = _mesa_nv_vertex_input_register_name(i);
+ char number[10];
+ _mesa_sprintf(number, "%d", i);
+ if (_mesa_strncmp(reg + 2, name, 4) == 0 ||
+ _mesa_strncmp(reg + 2, number, _mesa_strlen(number)) == 0) {
+ COPY_4V(v, ctx->VertexProgram.Inputs[i]);
+ return;
+ }
+ }
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramRegisterfvMESA(registerName)");
+ return;
+ }
+ else if (reg[0] == 'o' && reg[1] == '[') {
+ /* Vertex output attribute */
+ }
+ /* GL_ARB_vertex_program */
+ else if (_mesa_strncmp(reg, "vertex.", 7) == 0) {
+
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramRegisterfvMESA(registerName)");
+ return;
+ }
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ if (!ctx->Extensions.ARB_fragment_program) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetProgramRegisterfvMESA(target)");
+ return;
+ }
+ if (!ctx->FragmentProgram._Enabled) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramRegisterfvMESA");
+ return;
+ }
+ /* XXX to do */
+ break;
+ case GL_FRAGMENT_PROGRAM_NV:
+ if (!ctx->Extensions.NV_fragment_program) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetProgramRegisterfvMESA(target)");
+ return;
+ }
+ if (!ctx->FragmentProgram._Enabled) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramRegisterfvMESA");
+ return;
+ }
+ if (reg[0] == 'R') {
+ /* Temp register */
+ GLint i = _mesa_atoi(reg + 1);
+ if (i >= (GLint)ctx->Const.FragmentProgram.MaxTemps) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramRegisterfvMESA(registerName)");
+ return;
+ }
+ COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]);
+ }
+ else if (reg[0] == 'f' && reg[1] == '[') {
+ /* Fragment input attribute */
+ GLuint i;
+ for (i = 0; i < ctx->Const.FragmentProgram.MaxAttribs; i++) {
+ const char *name = _mesa_nv_fragment_input_register_name(i);
+ if (_mesa_strncmp(reg + 2, name, 4) == 0) {
+ COPY_4V(v, ctx->FragmentProgram.Machine.Inputs[i]);
+ return;
+ }
+ }
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramRegisterfvMESA(registerName)");
+ return;
+ }
+ else if (_mesa_strcmp(reg, "o[COLR]") == 0) {
+ /* Fragment output color */
+ COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLR]);
+ }
+ else if (_mesa_strcmp(reg, "o[COLH]") == 0) {
+ /* Fragment output color */
+ COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLH]);
+ }
+ else if (_mesa_strcmp(reg, "o[DEPR]") == 0) {
+ /* Fragment output depth */
+ COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_DEPR]);
+ }
+ else {
+ /* try user-defined identifiers */
+ const GLfloat *value = _mesa_lookup_parameter_value(
+ ctx->FragmentProgram.Current->Base.Parameters, -1, reg);
+ if (value) {
+ COPY_4V(v, value);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramRegisterfvMESA(registerName)");
+ return;
+ }
+ }
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetProgramRegisterfvMESA(target)");
+ return;
+ }
+
+}
diff --git a/src/mesa/shader/program.h b/src/mesa/shader/program.h
new file mode 100644
index 00000000000..6a345339aff
--- /dev/null
+++ b/src/mesa/shader/program.h
@@ -0,0 +1,305 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 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 program.c
+ * Vertex and fragment program support functions.
+ * \author Brian Paul
+ */
+
+
+/**
+ * \mainpage Mesa vertex and fragment program module
+ *
+ * This module or directory contains most of the code for vertex and
+ * fragment programs and shaders, including state management, parsers,
+ * and (some) software routines for executing programs
+ */
+
+#ifndef PROGRAM_H
+#define PROGRAM_H
+
+#include "mtypes.h"
+
+
+/* for GL_ARB_v_p and GL_ARB_f_p SWZ instruction */
+#define SWIZZLE_X 0
+#define SWIZZLE_Y 1
+#define SWIZZLE_Z 2
+#define SWIZZLE_W 3
+#define SWIZZLE_ZERO 4 /* keep these values together: KW */
+#define SWIZZLE_ONE 5 /* keep these values together: KW */
+
+#define MAKE_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9))
+#define SWIZZLE_NOOP MAKE_SWIZZLE4(0,1,2,3)
+#define GET_SWZ(swz, idx) (((swz) >> ((idx)*3)) & 0x7)
+#define GET_BIT(msk, idx) (((msk) >> (idx)) & 0x1)
+
+
+#define WRITEMASK_X 0x1
+#define WRITEMASK_Y 0x2
+#define WRITEMASK_XY 0x3
+#define WRITEMASK_Z 0x4
+#define WRITEMASK_XZ 0x5
+#define WRITEMASK_YZ 0x6
+#define WRITEMASK_XYZ 0x7
+#define WRITEMASK_W 0x8
+#define WRITEMASK_XW 0x9
+#define WRITEMASK_YW 0xa
+#define WRITEMASK_XYW 0xb
+#define WRITEMASK_ZW 0xc
+#define WRITEMASK_XZW 0xd
+#define WRITEMASK_YZW 0xe
+#define WRITEMASK_XYZW 0xf
+
+
+extern struct gl_program _mesa_DummyProgram;
+
+
+/*
+ * Internal functions
+ */
+
+extern void
+_mesa_init_program(GLcontext *ctx);
+
+extern void
+_mesa_free_program_data(GLcontext *ctx);
+
+extern void
+_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string);
+
+extern const GLubyte *
+_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
+ GLint *line, GLint *col);
+
+
+extern struct gl_program *
+_mesa_init_vertex_program(GLcontext *ctx,
+ struct gl_vertex_program *prog,
+ GLenum target, GLuint id);
+
+extern struct gl_program *
+_mesa_init_fragment_program(GLcontext *ctx,
+ struct gl_fragment_program *prog,
+ GLenum target, GLuint id);
+
+extern struct gl_program *
+_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id);
+
+extern void
+_mesa_delete_program(GLcontext *ctx, struct gl_program *prog);
+
+extern struct gl_program *
+_mesa_lookup_program(GLcontext *ctx, GLuint id);
+
+extern struct prog_instruction *
+_mesa_alloc_instructions(GLuint numInst);
+
+extern struct prog_instruction *
+_mesa_realloc_instructions(struct prog_instruction *oldInst,
+ GLuint numOldInst, GLuint numNewInst);
+
+
+/**
+ * Used for describing GL state referenced from inside ARB vertex and
+ * fragment programs.
+ * A string such as "state.light[0].ambient" gets translated into a
+ * sequence of tokens such as [ STATE_LIGHT, 0, STATE_AMBIENT ].
+ */
+enum state_index {
+ STATE_MATERIAL,
+
+ STATE_LIGHT,
+ STATE_LIGHTMODEL_AMBIENT,
+ STATE_LIGHTMODEL_SCENECOLOR,
+ STATE_LIGHTPROD,
+
+ STATE_TEXGEN,
+
+ STATE_FOG_COLOR,
+ STATE_FOG_PARAMS,
+
+ STATE_CLIPPLANE,
+
+ STATE_POINT_SIZE,
+ STATE_POINT_ATTENUATION,
+
+ STATE_MATRIX,
+ STATE_MODELVIEW,
+ STATE_PROJECTION,
+ STATE_MVP,
+ STATE_TEXTURE,
+ STATE_PROGRAM,
+ STATE_MATRIX_INVERSE,
+ STATE_MATRIX_TRANSPOSE,
+ STATE_MATRIX_INVTRANS,
+
+ STATE_AMBIENT,
+ STATE_DIFFUSE,
+ STATE_SPECULAR,
+ STATE_EMISSION,
+ STATE_SHININESS,
+ STATE_HALF,
+
+ STATE_POSITION,
+ STATE_ATTENUATION,
+ STATE_SPOT_DIRECTION,
+
+ STATE_TEXGEN_EYE_S,
+ STATE_TEXGEN_EYE_T,
+ STATE_TEXGEN_EYE_R,
+ STATE_TEXGEN_EYE_Q,
+ STATE_TEXGEN_OBJECT_S,
+ STATE_TEXGEN_OBJECT_T,
+ STATE_TEXGEN_OBJECT_R,
+ STATE_TEXGEN_OBJECT_Q,
+
+ STATE_TEXENV_COLOR,
+
+ STATE_DEPTH_RANGE,
+
+ STATE_VERTEX_PROGRAM,
+ STATE_FRAGMENT_PROGRAM,
+
+ STATE_ENV,
+ STATE_LOCAL,
+
+ STATE_INTERNAL, /* Mesa additions */
+ STATE_NORMAL_SCALE,
+ STATE_POSITION_NORMALIZED /* normalized light position */
+};
+
+
+
+/**
+ * Named program parameters
+ * Used for NV_fragment_program "DEFINE"d constants and "DECLARE"d parameters,
+ * and ARB_fragment_program global state references. For the later, Name
+ * might be "state.light[0].diffuse", for example.
+ */
+struct gl_program_parameter
+{
+ const char *Name; /**< Null-terminated string */
+ enum register_file Type; /**< PROGRAM_NAMED_PARAM, CONSTANT or STATE_VAR */
+ enum state_index StateIndexes[6]; /**< Global state reference */
+};
+
+
+/**
+ * A list of the above program_parameter instances.
+ */
+struct gl_program_parameter_list
+{
+ GLuint Size; /**< allocated size of Parameters, ParameterValues */
+ GLuint NumParameters; /**< number of parameters in arrays */
+ struct gl_program_parameter *Parameters; /**< Array [Size] */
+ GLfloat (*ParameterValues)[4]; /**< Array [Size] of GLfloat[4] */
+ GLbitfield StateFlags; /**< _NEW_* flags indicating which state changes
+ might invalidate ParameterValues[] */
+};
+
+
+/*
+ * Program parameter functions
+ */
+
+extern struct gl_program_parameter_list *
+_mesa_new_parameter_list(void);
+
+extern void
+_mesa_free_parameter_list(struct gl_program_parameter_list *paramList);
+
+extern GLint
+_mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
+ const char *name, const GLfloat values[4]);
+
+extern GLint
+_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
+ const char *name, const GLfloat values[4]);
+
+extern GLint
+_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
+ const GLfloat values[4]);
+
+extern GLint
+_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
+ const GLint *stateTokens);
+
+extern GLfloat *
+_mesa_lookup_parameter_value(struct gl_program_parameter_list *paramList,
+ GLsizei nameLen, const char *name);
+
+extern GLint
+_mesa_lookup_parameter_index(struct gl_program_parameter_list *paramList,
+ GLsizei nameLen, const char *name);
+
+extern void
+_mesa_load_state_parameters(GLcontext *ctx,
+ struct gl_program_parameter_list *paramList);
+
+
+
+extern void
+_mesa_print_instruction(const struct prog_instruction *inst);
+
+extern void
+_mesa_print_program(const struct gl_program *prog);
+
+extern void
+_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog);
+
+
+/*
+ * API functions common to ARB/NV_vertex/fragment_program
+ */
+
+extern void GLAPIENTRY
+_mesa_BindProgram(GLenum target, GLuint id);
+
+extern void GLAPIENTRY
+_mesa_DeletePrograms(GLsizei n, const GLuint *ids);
+
+extern void GLAPIENTRY
+_mesa_GenPrograms(GLsizei n, GLuint *ids);
+
+extern GLboolean GLAPIENTRY
+_mesa_IsProgram(GLuint id);
+
+
+
+/*
+ * GL_MESA_program_debug
+ */
+
+extern void
+_mesa_ProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
+ GLvoid *data);
+
+extern void
+_mesa_GetProgramRegisterfvMESA(GLenum target, GLsizei len,
+ const GLubyte *registerName, GLfloat *v);
+
+
+#endif /* PROGRAM_H */
diff --git a/src/mesa/shader/program_instruction.h b/src/mesa/shader/program_instruction.h
new file mode 100644
index 00000000000..93bcfc240a9
--- /dev/null
+++ b/src/mesa/shader/program_instruction.h
@@ -0,0 +1,355 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2005 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 prog_instruction.h
+ *
+ * Private vertex program types and constants only used by files
+ * related to vertex programs.
+ *
+ * \author Brian Paul
+ * \author Keith Whitwell
+ * \author Ian Romanick <[email protected]>
+ */
+
+
+#ifndef PROG_INSTRUCTION_H
+#define PROG_INSTRUCTION_H
+
+/**
+ * Condition codes for GL_NV_fragment_program
+ */
+/*@{*/
+#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 */
+/*@}*/
+
+
+/**
+ * Instruction precision for GL_NV_fragment_program
+ */
+/*@{*/
+#define FLOAT32 0x1
+#define FLOAT16 0x2
+#define FIXED12 0x4
+/*@}*/
+
+
+/**
+ * Saturation modes when storing values.
+ */
+/*@{*/
+#define SATURATE_OFF 0
+#define SATURATE_ZERO_ONE 1
+#define SATURATE_PLUS_MINUS_ONE 2
+/*@}*/
+
+
+/**
+ * Per-component negation masks
+ */
+/*@{*/
+#define NEGATE_X 0x1
+#define NEGATE_Y 0x2
+#define NEGATE_Z 0x4
+#define NEGATE_W 0x8
+#define NEGATE_XYZW 0xf
+#define NEGATE_NONE 0x0
+/*@}*/
+
+
+/**
+ * Program instruction opcodes, for both vertex and fragment programs.
+ * \note changes to this opcode list must be reflected in t_vb_arbprogram.c
+ */
+ /* ARB_vp ARB_fp NV_vp NV_fp */
+enum prog_opcode { /*---------------------------------*/
+ OPCODE_ABS, /* X X 1.1 */
+ OPCODE_ADD, /* X X X X */
+ OPCODE_ARA, /* 2 */
+ OPCODE_ARL, /* X X */
+ OPCODE_ARL_NV, /* 2 */
+ OPCODE_ARR, /* 2 */
+ OPCODE_BRA, /* 2 */
+ OPCODE_CAL, /* 2 2 */
+ OPCODE_CMP, /* X */
+ OPCODE_COS, /* X 2 X */
+ OPCODE_DDX, /* X */
+ OPCODE_DDY, /* X */
+ OPCODE_DP3, /* X X X X */
+ OPCODE_DP4, /* X X X X */
+ OPCODE_DPH, /* X X 1.1 */
+ OPCODE_DST, /* X X X X */
+ OPCODE_END, /* X X X X */
+ OPCODE_EX2, /* X X 2 X */
+ OPCODE_EXP, /* X X */
+ OPCODE_FLR, /* X X 2 X */
+ OPCODE_FRC, /* X X 2 X */
+ OPCODE_KIL, /* X */
+ OPCODE_KIL_NV, /* X */
+ OPCODE_LG2, /* X X 2 X */
+ OPCODE_LIT, /* X X X X */
+ OPCODE_LOG, /* X X */
+ OPCODE_LRP, /* X X */
+ OPCODE_MAD, /* X X X X */
+ OPCODE_MAX, /* X X X X */
+ OPCODE_MIN, /* X X X X */
+ OPCODE_MOV, /* X X X X */
+ OPCODE_MUL, /* X X X X */
+ OPCODE_PK2H, /* X */
+ OPCODE_PK2US, /* X */
+ OPCODE_PK4B, /* X */
+ OPCODE_PK4UB, /* X */
+ OPCODE_POW, /* X X X */
+ OPCODE_POPA, /* 3 */
+ OPCODE_PRINT, /* X X */
+ OPCODE_PUSHA, /* 3 */
+ OPCODE_RCC, /* 1.1 */
+ OPCODE_RCP, /* X X X X */
+ OPCODE_RET, /* 2 2 */
+ OPCODE_RFL, /* X X */
+ OPCODE_RSQ, /* X X X X */
+ OPCODE_SCS, /* X */
+ OPCODE_SEQ, /* 2 X */
+ OPCODE_SFL, /* 2 X */
+ OPCODE_SGE, /* X X X X */
+ OPCODE_SGT, /* 2 X */
+ OPCODE_SIN, /* X 2 X */
+ OPCODE_SLE, /* 2 X */
+ OPCODE_SLT, /* X X X X */
+ OPCODE_SNE, /* 2 X */
+ OPCODE_SSG, /* 2 */
+ OPCODE_STR, /* 2 X */
+ OPCODE_SUB, /* X X 1.1 X */
+ OPCODE_SWZ, /* X X */
+ OPCODE_TEX, /* X 3 X */
+ OPCODE_TXB, /* X 3 */
+ OPCODE_TXD, /* X */
+ OPCODE_TXL, /* 3 2 */
+ OPCODE_TXP, /* X */
+ OPCODE_TXP_NV, /* 3 X */
+ OPCODE_UP2H, /* X */
+ OPCODE_UP2US, /* X */
+ OPCODE_UP4B, /* X */
+ OPCODE_UP4UB, /* X */
+ OPCODE_X2D, /* X */
+ OPCODE_XPD, /* X X */
+ MAX_OPCODE
+};
+
+
+/**
+ * Instruction source register.
+ */
+struct prog_src_register
+{
+ GLuint File:4; /**< One of the PROGRAM_* register file values. */
+ GLint Index:9; /**< May be negative for relative addressing. */
+ GLuint Swizzle:12;
+ GLuint RelAddr:1;
+
+ /**
+ * \name Source register "sign" control.
+ *
+ * The ARB and NV extensions allow varrying degrees of control over the
+ * sign of the source vector components. These values allow enough control
+ * for all flavors of the extensions.
+ */
+ /*@{*/
+ /**
+ * Per-component negation for the SWZ instruction. For non-SWZ
+ * instructions the only possible values are NEGATE_XYZW and NEGATE_NONE.
+ *
+ * \since
+ * ARB_vertex_program, ARB_fragment_program
+ */
+ GLuint NegateBase:4;
+
+ /**
+ * Take the component-wise absolute value.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+ * NV_vertex_program2_option.
+ */
+ GLuint Abs:1;
+
+ /**
+ * Post-absolute value negation (all components).
+ */
+ GLuint NegateAbs:1;
+ /*@}*/
+};
+
+
+/**
+ * Instruction destination register.
+ */
+struct prog_dst_register
+{
+ /**
+ * One of the PROGRAM_* register file values.
+ */
+ GLuint File:4;
+
+ GLuint Index:8;
+ GLuint WriteMask:4;
+
+ /**
+ * \name Conditional destination update control.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+ * NV_vertex_program2_option.
+ */
+ /*@{*/
+ /**
+ * Takes one of the 9 possible condition values (EQ, FL, GT, GE, LE, LT,
+ * NE, TR, or UN). Destination update is enabled if the matching
+ * (swizzled) condition code value passes. When a conditional update mask
+ * is not specified, this will be \c COND_TR.
+ */
+ GLuint CondMask:4;
+
+ /**
+ * Condition code swizzle value.
+ */
+ GLuint CondSwizzle:12;
+
+ /**
+ * Selects the condition code register to use for conditional destination
+ * update masking. In NV_fragmnet_program or NV_vertex_program2 mode, only
+ * condition code register 0 is available. In NV_vertex_program3 mode,
+ * condition code registers 0 and 1 are available.
+ */
+ GLuint CondSrc:1;
+ /*@}*/
+
+ GLuint pad:31;
+};
+
+
+/**
+ * Vertex/fragment program instruction.
+ */
+struct prog_instruction
+{
+ enum prog_opcode Opcode;
+#if FEATURE_MESA_program_debug
+ GLshort StringPos;
+#endif
+ /**
+ * Arbitrary data. Used for the PRINT, CAL, and BRA instructions.
+ */
+ void *Data;
+
+ struct prog_src_register SrcReg[3];
+ struct prog_dst_register DstReg;
+
+ /**
+ * Indicates that the instruction should update the condition code
+ * register.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+ * NV_vertex_program2_option.
+ */
+ GLuint CondUpdate:1;
+
+ /**
+ * If prog_instruction::cc_update is \c GL_TRUE, this value selects the
+ * condition code register that is to be updated.
+ *
+ * In GL_NV_fragment_program or GL_NV_vertex_program2 mode, only condition
+ * code register 0 is available. In GL_NV_vertex_program3 mode, condition
+ * code registers 0 and 1 are available.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+ * NV_vertex_program2_option.
+ */
+ GLuint CondDst:1;
+
+ /**
+ * Saturate each value of the vectored result to the range [0,1] or the
+ * range [-1,1]. \c SSAT mode (i.e., saturation to the range [-1,1]) is
+ * only available in NV_fragment_program2 mode.
+ * Value is one of the SATURATE_* tokens.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program3.
+ */
+ GLuint SaturateMode:2;
+
+ /**
+ * Per-instruction selectable precision.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option.
+ */
+ GLuint Precision:3;
+
+ /**
+ * \name Texture source controls.
+ *
+ * The texture source controls are only used with the \c TEX, \c TXD,
+ * \c TXL, and \c TXP instructions.
+ *
+ * \since
+ * ARB_fragment_program, NV_fragment_program, NV_vertex_program3.
+ */
+ /*@{*/
+ /**
+ * Source texture unit. OpenGL supports a maximum of 32 texture
+ * units.
+ */
+ GLuint TexSrcUnit:5;
+
+ /**
+ * Source texture target, one of TEXTURE_{1D,2D,3D,CUBE,RECT}_INDEX.
+ */
+ GLuint TexSrcTarget:3;
+ /*@}*/
+};
+
+
+extern void
+_mesa_init_instruction(struct prog_instruction *inst);
+
+extern GLuint
+_mesa_num_inst_src_regs(enum prog_opcode opcode);
+
+extern const char *
+_mesa_opcode_string(enum prog_opcode opcode);
+
+
+#endif /* PROG_INSTRUCTION_H */
diff --git a/src/mesa/shader/programopt.c b/src/mesa/shader/programopt.c
new file mode 100644
index 00000000000..199202edf77
--- /dev/null
+++ b/src/mesa/shader/programopt.c
@@ -0,0 +1,147 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 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 programopt.c
+ * Vertex/Fragment program optimizations and transformations for program
+ * options, etc.
+ *
+ * \author Brian Paul
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "imports.h"
+#include "mtypes.h"
+#include "program.h"
+#include "programopt.h"
+#include "program_instruction.h"
+
+
+/**
+ * This function inserts instructions for coordinate modelview * projection
+ * into a vertex program.
+ * May be used to implement the position_invariant option.
+ */
+void
+_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog)
+{
+ struct prog_instruction *newInst;
+ const GLuint origLen = vprog->Base.NumInstructions;
+ const GLuint newLen = origLen + 4;
+ GLuint i;
+
+ /*
+ * Setup state references for the modelview/projection matrix.
+ * XXX we should check if these state vars are already declared.
+ */
+ static const GLint mvpState[4][5] = {
+ { STATE_MATRIX, STATE_MVP, 0, 0, 0 }, /* state.matrix.mvp.row[0] */
+ { STATE_MATRIX, STATE_MVP, 0, 1, 1 }, /* state.matrix.mvp.row[1] */
+ { STATE_MATRIX, STATE_MVP, 0, 2, 2 }, /* state.matrix.mvp.row[2] */
+ { STATE_MATRIX, STATE_MVP, 0, 3, 3 }, /* state.matrix.mvp.row[3] */
+ };
+ GLint mvpRef[4];
+
+ for (i = 0; i < 4; i++) {
+ mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
+ mvpState[i]);
+ }
+
+ /* Alloc storage for new instructions */
+ newInst = _mesa_alloc_instructions(newLen);
+ if (!newInst) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "glProgramString(inserting position_invariant code)");
+ return;
+ }
+
+ /*
+ * Generated instructions:
+ * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position;
+ * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position;
+ * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position;
+ * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position;
+ */
+ for (i = 0; i < 4; i++) {
+ _mesa_init_instruction(newInst + i);
+ newInst[i].Opcode = OPCODE_DP4;
+ newInst[i].DstReg.File = PROGRAM_OUTPUT;
+ newInst[i].DstReg.Index = VERT_RESULT_HPOS;
+ newInst[i].DstReg.WriteMask = (WRITEMASK_X << i);
+ newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR;
+ newInst[i].SrcReg[0].Index = mvpRef[i];
+ newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
+ newInst[i].SrcReg[1].File = PROGRAM_INPUT;
+ newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS;
+ newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
+ }
+
+ /* Append original instructions after new instructions */
+ _mesa_memcpy(newInst + 4, vprog->Base.Instructions,
+ origLen * sizeof(struct prog_instruction));
+
+ /* free old instructions */
+ _mesa_free(vprog->Base.Instructions);
+
+ /* install new instructions */
+ vprog->Base.Instructions = newInst;
+ vprog->Base.NumInstructions = newLen;
+ vprog->Base.InputsRead |= VERT_BIT_POS;
+ vprog->Base.OutputsWritten |= (1 << VERT_RESULT_HPOS);
+}
+
+
+
+/**
+ * Append extra instructions onto the given fragment program to implement
+ * the fog mode specified by program->FogOption.
+ * XXX incomplete.
+ */
+void
+_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog)
+{
+ struct prog_instruction newInst[10];
+
+ switch (fprog->FogOption) {
+ case GL_LINEAR:
+ /* lerp */
+ break;
+ case GL_EXP:
+ break;
+ case GL_EXP2:
+ break;
+ case GL_NONE:
+ /* no-op */
+ return;
+ default:
+ _mesa_problem(ctx, "Invalid fog option");
+ return;
+ }
+
+
+ (void) newInst;
+
+}
diff --git a/src/mesa/shader/programopt.h b/src/mesa/shader/programopt.h
new file mode 100644
index 00000000000..8799da435b3
--- /dev/null
+++ b/src/mesa/shader/programopt.h
@@ -0,0 +1,37 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 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.
+ */
+
+
+#ifndef PROGRAMOPT_H
+#define PROGRAMOPT_H 1
+
+
+extern void
+_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog);
+
+extern void
+_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog);
+
+
+#endif /* PROGRAMOPT_H */
diff --git a/src/mesa/shader/shaderobjects.c b/src/mesa/shader/shaderobjects.c
new file mode 100644
index 00000000000..f26ff12adf1
--- /dev/null
+++ b/src/mesa/shader/shaderobjects.c
@@ -0,0 +1,1214 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2004-2006 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 shaderobjects.c
+ * ARB_shader_objects state management functions
+ * \author Michal Krol
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "shaderobjects.h"
+#include "shaderobjects_3dlabs.h"
+
+
+#if FEATURE_ARB_shader_objects
+
+#define RELEASE_GENERIC(x)\
+ (**x)._unknown.Release ((struct gl2_unknown_intf **) (x))
+
+#define RELEASE_CONTAINER(x)\
+ (**x)._generic._unknown.Release ((struct gl2_unknown_intf **) (x))
+
+#define RELEASE_PROGRAM(x)\
+ (**x)._container._generic._unknown.Release ((struct gl2_unknown_intf **) (x))
+
+#define RELEASE_SHADER(x)\
+ (**x)._generic._unknown.Release ((struct gl2_unknown_intf **) (x))
+
+static struct gl2_unknown_intf **
+lookup_handle (GLcontext *ctx, GLhandleARB handle, enum gl2_uiid uiid, const char *function)
+{
+ struct gl2_unknown_intf **unk;
+
+ /*
+ * Note: _mesa_HashLookup() requires non-zero input values, so the passed-in handle value
+ * must be checked beforehand.
+ */
+ if (handle == 0) {
+ _mesa_error (ctx, GL_INVALID_VALUE, function);
+ return NULL;
+ }
+ _glthread_LOCK_MUTEX (ctx->Shared->Mutex);
+ unk = (struct gl2_unknown_intf **) (_mesa_HashLookup (ctx->Shared->GL2Objects, handle));
+ _glthread_UNLOCK_MUTEX (ctx->Shared->Mutex);
+ if (unk == NULL)
+ _mesa_error (ctx, GL_INVALID_VALUE, function);
+ else {
+ unk = (**unk).QueryInterface (unk, uiid);
+ if (unk == NULL)
+ _mesa_error (ctx, GL_INVALID_OPERATION, function);
+ }
+ return unk;
+}
+
+#define GET_GENERIC(x, handle, function)\
+ struct gl2_generic_intf **x = (struct gl2_generic_intf **)\
+ lookup_handle (ctx, handle, UIID_GENERIC, function);
+
+#define GET_CONTAINER(x, handle, function)\
+ struct gl2_container_intf **x = (struct gl2_container_intf **)\
+ lookup_handle (ctx, handle, UIID_CONTAINER, function);
+
+#define GET_PROGRAM(x, handle, function)\
+ struct gl2_program_intf **x = (struct gl2_program_intf **)\
+ lookup_handle (ctx, handle, UIID_PROGRAM, function);
+
+#define GET_SHADER(x, handle, function)\
+ struct gl2_shader_intf **x = (struct gl2_shader_intf **)\
+ lookup_handle (ctx, handle, UIID_SHADER, function);
+
+#define GET_LINKED_PROGRAM(x, handle, function)\
+ GET_PROGRAM(x, handle, function);\
+ if (x != NULL && (**x).GetLinkStatus (x) == GL_FALSE) {\
+ RELEASE_PROGRAM(x);\
+ x = NULL;\
+ _mesa_error (ctx, GL_INVALID_OPERATION, function);\
+ }
+
+#define GET_CURRENT_LINKED_PROGRAM(x, function)\
+ struct gl2_program_intf **x = NULL;\
+ if (ctx->ShaderObjects.CurrentProgram == NULL)\
+ _mesa_error (ctx, GL_INVALID_OPERATION, function);\
+ else {\
+ x = ctx->ShaderObjects.CurrentProgram;\
+ if (x != NULL && (**x).GetLinkStatus (x) == GL_FALSE) {\
+ x = NULL;\
+ _mesa_error (ctx, GL_INVALID_OPERATION, function);\
+ }\
+ }
+
+#define IS_NAME_WITH_GL_PREFIX(x) ((x)[0] == 'g' && (x)[1] == 'l' && (x)[2] == '_')
+
+
+GLvoid GLAPIENTRY
+_mesa_DeleteObjectARB (GLhandleARB obj)
+{
+ if (obj != 0)
+ {
+ GET_CURRENT_CONTEXT(ctx);
+ GET_GENERIC(gen, obj, "glDeleteObjectARB");
+
+ if (gen != NULL)
+ {
+ (**gen).Delete (gen);
+ RELEASE_GENERIC(gen);
+ }
+ }
+}
+
+GLhandleARB GLAPIENTRY
+_mesa_GetHandleARB (GLenum pname)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (pname)
+ {
+ case GL_PROGRAM_OBJECT_ARB:
+ {
+ struct gl2_program_intf **pro = ctx->ShaderObjects.CurrentProgram;
+
+ if (pro != NULL)
+ return (**pro)._container._generic.GetName ((struct gl2_generic_intf **) (pro));
+ }
+ break;
+ default:
+ _mesa_error (ctx, GL_INVALID_ENUM, "glGetHandleARB");
+ }
+
+ return 0;
+}
+
+GLvoid GLAPIENTRY
+_mesa_DetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CONTAINER(con, containerObj, "glDetachObjectARB");
+
+ if (con != NULL)
+ {
+ GET_GENERIC(att, attachedObj, "glDetachObjectARB");
+
+ if (att != NULL)
+ {
+ (**con).Detach (con, att);
+ RELEASE_GENERIC(att);
+ }
+ RELEASE_CONTAINER(con);
+ }
+}
+
+GLhandleARB GLAPIENTRY
+_mesa_CreateShaderObjectARB (GLenum shaderType)
+{
+ return _mesa_3dlabs_create_shader_object (shaderType);
+}
+
+GLvoid GLAPIENTRY
+_mesa_ShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string,
+ const GLint *length)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint *offsets;
+ GLsizei i;
+ GLcharARB *source;
+ GET_SHADER(sha, shaderObj, "glShaderSourceARB");
+
+ if (sha == NULL)
+ return;
+
+ if (string == NULL)
+ {
+ RELEASE_SHADER(sha);
+ _mesa_error (ctx, GL_INVALID_VALUE, "glShaderSourceARB");
+ return;
+ }
+
+ /*
+ * This array holds offsets of where the appropriate string ends, thus the last
+ * element will be set to the total length of the source code.
+ */
+ offsets = (GLint *) _mesa_malloc (count * sizeof (GLint));
+ if (offsets == NULL)
+ {
+ RELEASE_SHADER(sha);
+ _mesa_error (ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
+ return;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (string[i] == NULL)
+ {
+ _mesa_free ((GLvoid *) offsets);
+ RELEASE_SHADER(sha);
+ _mesa_error (ctx, GL_INVALID_VALUE, "glShaderSourceARB");
+ return;
+ }
+ if (length == NULL || length[i] < 0)
+ offsets[i] = _mesa_strlen (string[i]);
+ else
+ offsets[i] = length[i];
+ /* accumulate string lengths */
+ if (i > 0)
+ offsets[i] += offsets[i - 1];
+ }
+
+ source = (GLcharARB *) _mesa_malloc ((offsets[count - 1] + 1) * sizeof (GLcharARB));
+ if (source == NULL)
+ {
+ _mesa_free ((GLvoid *) offsets);
+ RELEASE_SHADER(sha);
+ _mesa_error (ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
+ return;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ GLint start = (i > 0) ? offsets[i - 1] : 0;
+ _mesa_memcpy (source + start, string[i], (offsets[i] - start) * sizeof (GLcharARB));
+ }
+ source[offsets[count - 1]] = '\0';
+
+ (**sha).SetSource (sha, source, offsets, count);
+ RELEASE_SHADER(sha);
+}
+
+GLvoid GLAPIENTRY
+_mesa_CompileShaderARB (GLhandleARB shaderObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_SHADER(sha, shaderObj, "glCompileShaderARB");
+
+ if (sha != NULL)
+ {
+ (**sha).Compile (sha);
+ RELEASE_SHADER(sha);
+ }
+}
+
+GLhandleARB GLAPIENTRY
+_mesa_CreateProgramObjectARB (GLvoid)
+{
+ return _mesa_3dlabs_create_program_object ();
+}
+
+GLvoid GLAPIENTRY
+_mesa_AttachObjectARB (GLhandleARB containerObj, GLhandleARB obj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CONTAINER(con, containerObj, "glAttachObjectARB");
+
+ if (con != NULL)
+ {
+ GET_GENERIC(att, obj, "glAttachObjectARB");
+
+ if (att != NULL)
+ {
+ (**con).Attach (con, att);
+ RELEASE_GENERIC(att);
+ }
+ RELEASE_CONTAINER(con);
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_LinkProgramARB (GLhandleARB programObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_PROGRAM(pro, programObj, "glLinkProgramARB");
+
+ if (pro != NULL)
+ {
+ (**pro).Link (pro);
+ if (pro == ctx->ShaderObjects.CurrentProgram)
+ {
+ if ((**pro).GetLinkStatus (pro))
+ _mesa_UseProgramObjectARB (programObj);
+ else
+ _mesa_UseProgramObjectARB (0);
+ }
+ RELEASE_PROGRAM(pro);
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_UseProgramObjectARB (GLhandleARB programObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_program_intf **program = NULL;
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (programObj != 0)
+ {
+ GET_PROGRAM(pro, programObj, "glUseProgramObjectARB");
+
+ if (pro == NULL)
+ return;
+
+ if ((**pro).GetLinkStatus (pro) == GL_FALSE)
+ {
+ RELEASE_PROGRAM(pro);
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUseProgramObjectARB");
+ return;
+ }
+
+ program = pro;
+
+ ctx->ShaderObjects._VertexShaderPresent = (**pro).IsShaderPresent (pro, GL_VERTEX_SHADER_ARB);
+ ctx->ShaderObjects._FragmentShaderPresent = (**pro).IsShaderPresent (pro,
+ GL_FRAGMENT_SHADER_ARB);
+ }
+ else
+ {
+ ctx->ShaderObjects._VertexShaderPresent = GL_FALSE;
+ ctx->ShaderObjects._FragmentShaderPresent = GL_FALSE;
+ }
+
+ if (ctx->ShaderObjects.CurrentProgram != NULL)
+ RELEASE_PROGRAM(ctx->ShaderObjects.CurrentProgram);
+ ctx->ShaderObjects.CurrentProgram = program;
+}
+
+GLvoid GLAPIENTRY
+_mesa_ValidateProgramARB (GLhandleARB programObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_PROGRAM(pro, programObj, "glValidateProgramARB");
+
+ if (pro != NULL)
+ {
+ (**pro).Validate (pro);
+ RELEASE_PROGRAM(pro);
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform1fARB (GLint location, GLfloat v0)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform1fARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, 1, &v0, GL_FLOAT))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform1fARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform2fARB (GLint location, GLfloat v0, GLfloat v1)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform2fARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ GLfloat v[2];
+ v[0] = v0;
+ v[1] = v1;
+
+ if (!(**pro).WriteUniform (pro, location, 1, v, GL_FLOAT_VEC2))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform2fARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform3fARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ GLfloat v[3];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+
+ if (!(**pro).WriteUniform (pro, location, 1, v, GL_FLOAT_VEC3))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform3fARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform4fARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ GLfloat v[4];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+
+ if (!(**pro).WriteUniform (pro, location, 1, v, GL_FLOAT_VEC4))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform4fARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform1iARB (GLint location, GLint v0)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform1iARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, 1, &v0, GL_INT))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform1iARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform2iARB (GLint location, GLint v0, GLint v1)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform2iARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ GLint v[2];
+ v[0] = v0;
+ v[1] = v1;
+
+ if (!(**pro).WriteUniform (pro, location, 1, v, GL_INT_VEC2))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform2iARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform3iARB (GLint location, GLint v0, GLint v1, GLint v2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform3iARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ GLint v[3];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+
+ if (!(**pro).WriteUniform (pro, location, 1, v, GL_INT_VEC3))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform3iARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform4iARB");
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ GLint v[4];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+
+ if (!(**pro).WriteUniform (pro, location, 1, v, GL_INT_VEC4))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform4iARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform1fvARB (GLint location, GLsizei count, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform1fvARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform1fvARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_FLOAT))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform1fvARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform2fvARB (GLint location, GLsizei count, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform2fvARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform2fvARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_FLOAT_VEC2))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform2fvARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform3fvARB (GLint location, GLsizei count, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform3fvARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform3fvARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_FLOAT_VEC3))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform3fvARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform4fvARB (GLint location, GLsizei count, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform4fvARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform4fvARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_FLOAT_VEC4))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform4fvARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform1ivARB (GLint location, GLsizei count, const GLint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform1ivARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform1ivARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_INT))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform1ivARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform2ivARB (GLint location, GLsizei count, const GLint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform2ivARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform2ivARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_INT_VEC2))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform2ivARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform3ivARB (GLint location, GLsizei count, const GLint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform3ivARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform3ivARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_INT_VEC3))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform3ivARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_Uniform4ivARB (GLint location, GLsizei count, const GLint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniform4ivARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniform4ivARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_INT_VEC4))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniform4ivARB");
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_UniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniformMatrix2fvARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniformMatrix2fvARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (transpose)
+ {
+ GLfloat *trans, *pt;
+ const GLfloat *pv;
+
+ trans = (GLfloat *) _mesa_malloc (count * 4 * sizeof (GLfloat));
+ if (trans == NULL)
+ {
+ _mesa_error (ctx, GL_OUT_OF_MEMORY, "glUniformMatrix2fvARB");
+ return;
+ }
+ for (pt = trans, pv = value; pt != trans + count * 4; pt += 4, pv += 4)
+ {
+ pt[0] = pv[0];
+ pt[1] = pv[2];
+ pt[2] = pv[1];
+ pt[3] = pv[3];
+ }
+ if (!(**pro).WriteUniform (pro, location, count, trans, GL_FLOAT_MAT2))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniformMatrix2fvARB");
+ _mesa_free (trans);
+ }
+ else
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_FLOAT_MAT2))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniformMatrix2fvARB");
+ }
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_UniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniformMatrix3fvARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniformMatrix3fvARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (transpose)
+ {
+ GLfloat *trans, *pt;
+ const GLfloat *pv;
+
+ trans = (GLfloat *) _mesa_malloc (count * 9 * sizeof (GLfloat));
+ if (trans == NULL)
+ {
+ _mesa_error (ctx, GL_OUT_OF_MEMORY, "glUniformMatrix3fvARB");
+ return;
+ }
+ for (pt = trans, pv = value; pt != trans + count * 9; pt += 9, pv += 9)
+ {
+ pt[0] = pv[0];
+ pt[1] = pv[3];
+ pt[2] = pv[6];
+ pt[3] = pv[1];
+ pt[4] = pv[4];
+ pt[5] = pv[7];
+ pt[6] = pv[2];
+ pt[7] = pv[5];
+ pt[8] = pv[8];
+ }
+ if (!(**pro).WriteUniform (pro, location, count, trans, GL_FLOAT_MAT3))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniformMatrix3fvARB");
+ _mesa_free (trans);
+ }
+ else
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_FLOAT_MAT3))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniformMatrix3fvARB");
+ }
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_UniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CURRENT_LINKED_PROGRAM(pro, "glUniformMatrix4fvARB");
+
+ if (value == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glUniformMatrix4fvARB");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (pro != NULL)
+ {
+ if (transpose)
+ {
+ GLfloat *trans, *pt;
+ const GLfloat *pv;
+
+ trans = (GLfloat *) _mesa_malloc (count * 16 * sizeof (GLfloat));
+ if (trans == NULL)
+ {
+ _mesa_error (ctx, GL_OUT_OF_MEMORY, "glUniformMatrix4fvARB");
+ return;
+ }
+ for (pt = trans, pv = value; pt != trans + count * 16; pt += 16, pv += 16)
+ {
+ _math_transposef (pt, pv);
+ }
+ if (!(**pro).WriteUniform (pro, location, count, trans, GL_FLOAT_MAT4))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniformMatrix4fvARB");
+ _mesa_free (trans);
+ }
+ else
+ {
+ if (!(**pro).WriteUniform (pro, location, count, value, GL_FLOAT_MAT4))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glUniformMatrix4fvARB");
+ }
+ }
+}
+
+static GLboolean
+_mesa_get_object_parameter (GLhandleARB obj, GLenum pname, GLvoid *params, GLboolean *integral,
+ GLint *size)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint *ipar = (GLint *) params;
+
+ /* set default values */
+ *integral = GL_TRUE; /* indicates param type, TRUE: GLint, FALSE: GLfloat */
+ *size = 1; /* param array size */
+
+ switch (pname)
+ {
+ case GL_OBJECT_TYPE_ARB:
+ case GL_OBJECT_DELETE_STATUS_ARB:
+ case GL_OBJECT_INFO_LOG_LENGTH_ARB:
+ {
+ GET_GENERIC(gen, obj, "glGetObjectParameterivARB");
+
+ if (gen == NULL)
+ return GL_FALSE;
+
+ switch (pname)
+ {
+ case GL_OBJECT_TYPE_ARB:
+ *ipar = (**gen).GetType (gen);
+ break;
+ case GL_OBJECT_DELETE_STATUS_ARB:
+ *ipar = (**gen).GetDeleteStatus (gen);
+ break;
+ case GL_OBJECT_INFO_LOG_LENGTH_ARB:
+ *ipar = (**gen).GetInfoLogLength (gen);
+ break;
+ }
+
+ RELEASE_GENERIC(gen);
+ }
+ break;
+ case GL_OBJECT_SUBTYPE_ARB:
+ case GL_OBJECT_COMPILE_STATUS_ARB:
+ case GL_OBJECT_SHADER_SOURCE_LENGTH_ARB:
+ {
+ GET_SHADER(sha, obj, "glGetObjectParameterivARB");
+
+ if (sha == NULL)
+ return GL_FALSE;
+
+ switch (pname)
+ {
+ case GL_OBJECT_SUBTYPE_ARB:
+ *ipar = (**sha).GetSubType (sha);
+ break;
+ case GL_OBJECT_COMPILE_STATUS_ARB:
+ *ipar = (**sha).GetCompileStatus (sha);
+ break;
+ case GL_OBJECT_SHADER_SOURCE_LENGTH_ARB:
+ {
+ const GLcharARB *src = (**sha).GetSource (sha);
+
+ if (src == NULL)
+ *ipar = 0;
+ else
+ *ipar = _mesa_strlen (src) + 1;
+ }
+ break;
+ }
+
+ RELEASE_SHADER(sha);
+ }
+ break;
+ case GL_OBJECT_LINK_STATUS_ARB:
+ case GL_OBJECT_VALIDATE_STATUS_ARB:
+ case GL_OBJECT_ATTACHED_OBJECTS_ARB:
+ case GL_OBJECT_ACTIVE_UNIFORMS_ARB:
+ case GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB:
+ {
+ GET_PROGRAM(pro, obj, "glGetObjectParameterivARB");
+
+ if (pro == NULL)
+ return GL_FALSE;
+
+ switch (pname)
+ {
+ case GL_OBJECT_LINK_STATUS_ARB:
+ *ipar = (**pro).GetLinkStatus (pro);
+ break;
+ case GL_OBJECT_VALIDATE_STATUS_ARB:
+ *ipar = (**pro).GetValidateStatus (pro);
+ break;
+ case GL_OBJECT_ATTACHED_OBJECTS_ARB:
+ *ipar = (**pro)._container.GetAttachedCount ((struct gl2_container_intf **) (pro));
+ break;
+ case GL_OBJECT_ACTIVE_UNIFORMS_ARB:
+ *ipar = (**pro).GetActiveUniformCount (pro);
+ break;
+ case GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB:
+ *ipar = (**pro).GetActiveUniformMaxLength (pro);
+ break;
+ case GL_OBJECT_ACTIVE_ATTRIBUTES_ARB:
+ *ipar = (**pro).GetActiveAttribCount (pro);
+ break;
+ case GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB:
+ *ipar = (**pro).GetActiveAttribMaxLength (pro);
+ break;
+ }
+
+ RELEASE_PROGRAM(pro);
+ }
+ break;
+ default:
+ _mesa_error (ctx, GL_INVALID_ENUM, "glGetObjectParameterivARB");
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLboolean integral;
+ GLint size;
+
+ if (params == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetObjectParameterfvARB");
+ return;
+ }
+
+ assert (sizeof (GLfloat) == sizeof (GLint));
+
+ if (_mesa_get_object_parameter (obj, pname, (GLvoid *) params, &integral, &size))
+ if (integral)
+ {
+ GLint i;
+
+ for (i = 0; i < size; i++)
+ params[i] = (GLfloat) ((GLint *) params)[i];
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLboolean integral;
+ GLint size;
+
+ if (params == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB");
+ return;
+ }
+
+ assert (sizeof (GLfloat) == sizeof (GLint));
+
+ if (_mesa_get_object_parameter (obj, pname, (GLvoid *) params, &integral, &size))
+ if (!integral)
+ {
+ GLint i;
+
+ for (i = 0; i < size; i++)
+ params[i] = (GLint) ((GLfloat *) params)[i];
+ }
+}
+
+
+/**
+ * Copy string from <src> to <dst>, up to maxLength characters, returning
+ * length of <dst> in <length>.
+ * \param src the strings source
+ * \param maxLength max chars to copy
+ * \param length returns numberof chars copied
+ * \param dst the string destination
+ */
+static GLvoid
+copy_string(const GLcharARB *src, GLsizei maxLength, GLsizei *length,
+ GLcharARB *dst)
+{
+ GLsizei len;
+ for (len = 0; len < maxLength - 1 && src && src[len]; len++)
+ dst[len] = src[len];
+ if (maxLength > 0)
+ dst[len] = 0;
+ if (length)
+ *length = len;
+}
+
+
+GLvoid GLAPIENTRY
+_mesa_GetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_GENERIC(gen, obj, "glGetInfoLogARB");
+
+ if (gen == NULL)
+ return;
+
+ if (infoLog == NULL)
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetInfoLogARB");
+ else {
+ GLsizei actualsize = (**gen).GetInfoLogLength (gen);
+ if (actualsize > maxLength)
+ actualsize = maxLength;
+ (**gen).GetInfoLog (gen, actualsize, infoLog);
+ if (length != NULL)
+ *length = (actualsize > 0) ? actualsize - 1 : 0;
+ }
+ RELEASE_GENERIC(gen);
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count,
+ GLhandleARB *obj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_CONTAINER(con, containerObj, "glGetAttachedObjectsARB");
+
+ if (con == NULL)
+ return;
+
+ if (obj == NULL)
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetAttachedObjectsARB");
+ else
+ {
+ GLsizei cnt, i;
+
+ cnt = (**con).GetAttachedCount (con);
+ if (cnt > maxCount)
+ cnt = maxCount;
+ if (count != NULL)
+ *count = cnt;
+
+ for (i = 0; i < cnt; i++)
+ {
+ struct gl2_generic_intf **x = (**con).GetAttached (con, i);
+ obj[i] = (**x).GetName (x);
+ RELEASE_GENERIC(x);
+ }
+ }
+ RELEASE_CONTAINER(con);
+}
+
+GLint GLAPIENTRY
+_mesa_GetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint loc = -1;
+ GET_LINKED_PROGRAM(pro, programObj, "glGetUniformLocationARB");
+
+ if (pro == NULL)
+ return -1;
+
+ if (name == NULL)
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetUniformLocationARB");
+ else
+ {
+ if (!IS_NAME_WITH_GL_PREFIX(name))
+ loc = (**pro).GetUniformLocation (pro, name);
+ }
+ RELEASE_PROGRAM(pro);
+ return loc;
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length,
+ GLint *size, GLenum *type, GLcharARB *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_PROGRAM(pro, programObj, "glGetActiveUniformARB");
+
+ if (pro == NULL)
+ return;
+
+ if (size == NULL || type == NULL || name == NULL)
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetActiveUniformARB");
+ else
+ {
+ if (index < (**pro).GetActiveUniformCount (pro))
+ (**pro).GetActiveUniform (pro, index, maxLength, length, size, type, name);
+ else
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetActiveUniformARB");
+ }
+ RELEASE_PROGRAM(pro);
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_LINKED_PROGRAM(pro, programObj, "glGetUniformfvARB");
+
+ if (pro != NULL)
+ {
+ /* TODO */
+ RELEASE_PROGRAM(pro);
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetUniformivARB (GLhandleARB programObj, GLint location, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_LINKED_PROGRAM(pro, programObj, "glGetUniformivARB");
+
+ if (pro != NULL)
+ {
+ /* TODO */
+ RELEASE_PROGRAM(pro);
+ }
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_SHADER(sha, obj, "glGetShaderSourceARB");
+
+ if (sha == NULL)
+ return;
+
+ if (source == NULL)
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetShaderSourceARB");
+ else
+ copy_string ((**sha).GetSource (sha), maxLength, length, source);
+ RELEASE_SHADER(sha);
+}
+
+/* GL_ARB_vertex_shader */
+
+GLvoid GLAPIENTRY
+_mesa_BindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_PROGRAM(pro, programObj, "glBindAttribLocationARB");
+
+ if (pro == NULL)
+ return;
+
+ if (name == NULL || index >= MAX_VERTEX_ATTRIBS)
+ _mesa_error (ctx, GL_INVALID_VALUE, "glBindAttribLocationARB");
+ else if (IS_NAME_WITH_GL_PREFIX(name))
+ _mesa_error (ctx, GL_INVALID_OPERATION, "glBindAttribLocationARB");
+ else
+ (**pro).OverrideAttribBinding (pro, index, name);
+ RELEASE_PROGRAM(pro);
+}
+
+GLvoid GLAPIENTRY
+_mesa_GetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length,
+ GLint *size, GLenum *type, GLcharARB *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GET_PROGRAM(pro, programObj, "glGetActiveAttribARB");
+
+ if (pro == NULL)
+ return;
+
+ if (name == NULL || index >= (**pro).GetActiveAttribCount (pro))
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetActiveAttribARB");
+ else
+ (**pro).GetActiveAttrib (pro, index, maxLength, length, size, type, name);
+ RELEASE_PROGRAM(pro);
+}
+
+GLint GLAPIENTRY
+_mesa_GetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint loc = -1;
+ GET_LINKED_PROGRAM(pro, programObj, "glGetAttribLocationARB");
+
+ if (pro == NULL)
+ return -1;
+
+ if (name == NULL)
+ _mesa_error (ctx, GL_INVALID_VALUE, "glGetAttribLocationARB");
+ else if (!IS_NAME_WITH_GL_PREFIX(name))
+ loc = (**pro).GetAttribLocation (pro, name);
+ RELEASE_PROGRAM(pro);
+ return loc;
+}
+
+#endif
+
+GLvoid
+_mesa_init_shaderobjects (GLcontext *ctx)
+{
+ ctx->ShaderObjects.CurrentProgram = NULL;
+ ctx->ShaderObjects._FragmentShaderPresent = GL_FALSE;
+ ctx->ShaderObjects._VertexShaderPresent = GL_FALSE;
+
+ _mesa_init_shaderobjects_3dlabs (ctx);
+}
+
diff --git a/src/mesa/shader/shaderobjects.h b/src/mesa/shader/shaderobjects.h
new file mode 100644
index 00000000000..cc670216292
--- /dev/null
+++ b/src/mesa/shader/shaderobjects.h
@@ -0,0 +1,278 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2004-2006 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.
+ */
+
+#ifndef SHADEROBJECTS_H
+#define SHADEROBJECTS_H
+
+#include "context.h"
+
+#if FEATURE_ARB_shader_objects
+
+/**
+ * gl2 unique interface identifier.
+ * Each gl2 interface has its own interface id used for object queries.
+ */
+enum gl2_uiid
+{
+ UIID_UNKNOWN, /* supported by all objects */
+ UIID_GENERIC, /* generic object */
+ UIID_CONTAINER, /* contains generic objects */
+ UIID_SHADER, /* shader object */
+ UIID_FRAGMENT_SHADER, /* fragment shader */
+ UIID_VERTEX_SHADER, /* vertex shader */
+ UIID_PROGRAM, /* program object */
+ UIID_3DLABS_SHHANDLE, /* encapsulates 3DLabs' ShHandle */
+ UIID_DEBUG /* debug object */
+};
+
+struct gl2_unknown_intf
+{
+ GLvoid (* AddRef) (struct gl2_unknown_intf **);
+ GLvoid (* Release) (struct gl2_unknown_intf **);
+ struct gl2_unknown_intf **(* QueryInterface) (struct gl2_unknown_intf **, enum gl2_uiid uiid);
+};
+
+struct gl2_generic_intf
+{
+ struct gl2_unknown_intf _unknown;
+ GLvoid (* Delete) (struct gl2_generic_intf **);
+ GLenum (* GetType) (struct gl2_generic_intf **);
+ GLhandleARB (* GetName) (struct gl2_generic_intf **);
+ GLboolean (* GetDeleteStatus) (struct gl2_generic_intf **);
+ GLvoid (* GetInfoLog) (struct gl2_generic_intf **, GLsizei, GLcharARB *);
+ GLsizei (* GetInfoLogLength) (struct gl2_generic_intf **);
+};
+
+struct gl2_container_intf
+{
+ struct gl2_generic_intf _generic;
+ GLboolean (* Attach) (struct gl2_container_intf **, struct gl2_generic_intf **);
+ GLboolean (* Detach) (struct gl2_container_intf **, struct gl2_generic_intf **);
+ GLsizei (* GetAttachedCount) (struct gl2_container_intf **);
+ struct gl2_generic_intf **(* GetAttached) (struct gl2_container_intf **, GLuint);
+};
+
+struct gl2_shader_intf
+{
+ struct gl2_generic_intf _generic;
+ GLenum (* GetSubType) (struct gl2_shader_intf **);
+ GLboolean (* GetCompileStatus) (struct gl2_shader_intf **);
+ GLvoid (* SetSource) (struct gl2_shader_intf **, GLcharARB *, GLint *, GLsizei);
+ const GLcharARB *(* GetSource) (struct gl2_shader_intf **);
+ GLvoid (* Compile) (struct gl2_shader_intf **);
+};
+
+struct gl2_program_intf
+{
+ struct gl2_container_intf _container;
+ GLboolean (* GetLinkStatus) (struct gl2_program_intf **);
+ GLboolean (* GetValidateStatus) (struct gl2_program_intf **);
+ GLvoid (* Link) (struct gl2_program_intf **);
+ GLvoid (* Validate) (struct gl2_program_intf **);
+ GLvoid (* UpdateFixedUniforms) (struct gl2_program_intf **);
+ GLvoid (* UpdateFixedAttrib) (struct gl2_program_intf **, GLuint, GLvoid *, GLuint, GLuint,
+ GLboolean);
+ GLvoid (* UpdateFixedVarying) (struct gl2_program_intf **, GLuint, GLvoid *, GLuint, GLuint,
+ GLboolean);
+ GLvoid (* GetTextureImageUsage) (struct gl2_program_intf **, GLbitfield *);
+ GLboolean (* IsShaderPresent) (struct gl2_program_intf **, GLenum);
+ GLvoid (* GetActiveUniform) (struct gl2_program_intf **, GLuint index, GLsizei maxLength,
+ GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+ GLuint (* GetActiveUniformMaxLength) (struct gl2_program_intf **);
+ GLuint (* GetActiveUniformCount) (struct gl2_program_intf **);
+ GLint (* GetUniformLocation) (struct gl2_program_intf **, const GLchar *name);
+ GLboolean (* WriteUniform) (struct gl2_program_intf **, GLint loc, GLsizei count,
+ const GLvoid *data, GLenum type);
+ GLvoid (* GetActiveAttrib) (struct gl2_program_intf **, GLuint index, GLsizei maxLength,
+ GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+ GLuint (* GetActiveAttribMaxLength) (struct gl2_program_intf **);
+ GLuint (* GetActiveAttribCount) (struct gl2_program_intf **);
+ GLint (* GetAttribLocation) (struct gl2_program_intf **, const GLchar *name);
+ GLvoid (* OverrideAttribBinding) (struct gl2_program_intf **, GLuint, const GLchar *);
+ GLvoid (* WriteAttrib) (struct gl2_program_intf **, GLuint, const GLfloat *);
+ GLvoid (* UpdateVarying) (struct gl2_program_intf **, GLuint, GLfloat *, GLboolean);
+};
+
+struct gl2_fragment_shader_intf
+{
+ struct gl2_shader_intf _shader;
+};
+
+struct gl2_vertex_shader_intf
+{
+ struct gl2_shader_intf _shader;
+};
+
+struct gl2_3dlabs_shhandle_intf
+{
+ struct gl2_unknown_intf _unknown;
+ GLvoid *(* GetShHandle) (struct gl2_3dlabs_shhandle_intf **);
+};
+
+struct gl2_debug_intf
+{
+ struct gl2_generic_intf _generic;
+ GLvoid (* ClearDebugLog) (struct gl2_debug_intf **, GLenum logType, GLenum shaderType);
+ GLvoid (* GetDebugLog) (struct gl2_debug_intf **, GLenum logType, GLenum shaderType,
+ GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+ GLsizei (* GetDebugLogLength) (struct gl2_debug_intf **, GLenum logType, GLenum shaderType);
+};
+
+
+extern void GLAPIENTRY
+_mesa_DeleteObjectARB(GLhandleARB obj);
+
+extern GLhandleARB GLAPIENTRY
+_mesa_GetHandleARB(GLenum pname);
+
+extern void GLAPIENTRY
+_mesa_DetachObjectARB (GLhandleARB, GLhandleARB);
+
+extern GLhandleARB GLAPIENTRY
+_mesa_CreateShaderObjectARB (GLenum);
+
+extern void GLAPIENTRY
+_mesa_ShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *);
+
+extern void GLAPIENTRY
+_mesa_CompileShaderARB (GLhandleARB);
+
+extern GLhandleARB GLAPIENTRY
+_mesa_CreateProgramObjectARB (void);
+
+extern void GLAPIENTRY
+_mesa_AttachObjectARB (GLhandleARB, GLhandleARB);
+
+extern void GLAPIENTRY
+_mesa_LinkProgramARB (GLhandleARB);
+
+extern void GLAPIENTRY
+_mesa_UseProgramObjectARB (GLhandleARB);
+
+extern void GLAPIENTRY
+_mesa_ValidateProgramARB (GLhandleARB);
+
+extern void GLAPIENTRY
+_mesa_Uniform1fARB (GLint, GLfloat);
+
+extern void GLAPIENTRY
+_mesa_Uniform2fARB (GLint, GLfloat, GLfloat);
+
+extern void GLAPIENTRY
+_mesa_Uniform3fARB (GLint, GLfloat, GLfloat, GLfloat);
+
+extern void GLAPIENTRY
+_mesa_Uniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+
+extern void GLAPIENTRY
+_mesa_Uniform1iARB (GLint, GLint);
+
+extern void GLAPIENTRY
+_mesa_Uniform2iARB (GLint, GLint, GLint);
+
+extern void GLAPIENTRY
+_mesa_Uniform3iARB (GLint, GLint, GLint, GLint);
+
+extern void GLAPIENTRY
+_mesa_Uniform4iARB (GLint, GLint, GLint, GLint, GLint);
+
+extern void GLAPIENTRY
+_mesa_Uniform1fvARB (GLint, GLsizei, const GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_Uniform2fvARB (GLint, GLsizei, const GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_Uniform3fvARB (GLint, GLsizei, const GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_Uniform4fvARB (GLint, GLsizei, const GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_Uniform1ivARB (GLint, GLsizei, const GLint *);
+
+extern void GLAPIENTRY
+_mesa_Uniform2ivARB (GLint, GLsizei, const GLint *);
+
+extern void GLAPIENTRY
+_mesa_Uniform3ivARB (GLint, GLsizei, const GLint *);
+
+extern void GLAPIENTRY
+_mesa_Uniform4ivARB (GLint, GLsizei, const GLint *);
+
+extern void GLAPIENTRY
+_mesa_UniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_UniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_UniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_GetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_GetObjectParameterivARB (GLhandleARB, GLenum, GLint *);
+
+extern void GLAPIENTRY
+_mesa_GetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+
+extern void GLAPIENTRY
+_mesa_GetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);
+
+extern GLint GLAPIENTRY
+_mesa_GetUniformLocationARB (GLhandleARB, const GLcharARB *);
+
+extern void GLAPIENTRY
+_mesa_GetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+
+extern void GLAPIENTRY
+_mesa_GetUniformfvARB (GLhandleARB, GLint, GLfloat *);
+
+extern void GLAPIENTRY
+_mesa_GetUniformivARB (GLhandleARB, GLint, GLint *);
+
+extern void GLAPIENTRY
+_mesa_GetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+
+#if FEATURE_ARB_vertex_shader
+
+extern void GLAPIENTRY
+_mesa_BindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *);
+
+extern void GLAPIENTRY
+_mesa_GetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+
+extern GLint GLAPIENTRY
+_mesa_GetAttribLocationARB (GLhandleARB, const GLcharARB *);
+
+#endif /* FEATURE_ARB_vertex_shader */
+
+#endif /* FEATURE_ARB_shader_objects */
+
+extern void
+_mesa_init_shaderobjects (GLcontext *ctx);
+
+#endif /* SHADEROBJECTS_H */
diff --git a/src/mesa/shader/shaderobjects_3dlabs.c b/src/mesa/shader/shaderobjects_3dlabs.c
new file mode 100755
index 00000000000..0def13d3b81
--- /dev/null
+++ b/src/mesa/shader/shaderobjects_3dlabs.c
@@ -0,0 +1,1982 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 shaderobjects_3dlabs.c
+ * shader objects definitions for 3dlabs compiler
+ * \author Michal Krol
+ */
+
+/* Set this to 1 when we are ready to use 3dlabs' front-end */
+#define USE_3DLABS_FRONTEND 0
+
+#include "imports.h"
+#include "hash.h"
+#include "macros.h"
+#include "shaderobjects.h"
+#include "shaderobjects_3dlabs.h"
+
+#if USE_3DLABS_FRONTEND
+#include "slang_mesa.h"
+#include "Public/ShaderLang.h"
+#else
+#include "slang_link.h"
+#endif
+
+#if FEATURE_ARB_shader_objects
+
+struct gl2_unknown_obj
+{
+ GLuint reference_count;
+ void (* _destructor) (struct gl2_unknown_intf **);
+};
+
+struct gl2_unknown_impl
+{
+ struct gl2_unknown_intf *_vftbl;
+ struct gl2_unknown_obj _obj;
+};
+
+static void
+_unknown_destructor (struct gl2_unknown_intf **intf)
+{
+}
+
+static void
+_unknown_AddRef (struct gl2_unknown_intf **intf)
+{
+ struct gl2_unknown_impl *impl = (struct gl2_unknown_impl *) intf;
+
+ impl->_obj.reference_count++;
+}
+
+static void
+_unknown_Release (struct gl2_unknown_intf **intf)
+{
+ struct gl2_unknown_impl *impl = (struct gl2_unknown_impl *) intf;
+
+ impl->_obj.reference_count--;
+ if (impl->_obj.reference_count == 0)
+ {
+ impl->_obj._destructor (intf);
+ _mesa_free ((void *) intf);
+ }
+}
+
+static struct gl2_unknown_intf **
+_unknown_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ if (uiid == UIID_UNKNOWN)
+ {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+ return NULL;
+}
+
+static struct gl2_unknown_intf _unknown_vftbl = {
+ _unknown_AddRef,
+ _unknown_Release,
+ _unknown_QueryInterface
+};
+
+static void
+_unknown_constructor (struct gl2_unknown_impl *impl)
+{
+ impl->_vftbl = &_unknown_vftbl;
+ impl->_obj.reference_count = 1;
+ impl->_obj._destructor = _unknown_destructor;
+}
+
+struct gl2_unkinner_obj
+{
+ struct gl2_unknown_intf **unkouter;
+};
+
+struct gl2_unkinner_impl
+{
+ struct gl2_unknown_intf *_vftbl;
+ struct gl2_unkinner_obj _obj;
+};
+
+static void
+_unkinner_destructor (struct gl2_unknown_intf **intf)
+{
+}
+
+static void
+_unkinner_AddRef (struct gl2_unknown_intf **intf)
+{
+ struct gl2_unkinner_impl *impl = (struct gl2_unkinner_impl *) intf;
+
+ (**impl->_obj.unkouter).AddRef (impl->_obj.unkouter);
+}
+
+static void
+_unkinner_Release (struct gl2_unknown_intf **intf)
+{
+ struct gl2_unkinner_impl *impl = (struct gl2_unkinner_impl *) intf;
+
+ (**impl->_obj.unkouter).Release (impl->_obj.unkouter);
+}
+
+static struct gl2_unknown_intf **
+_unkinner_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ struct gl2_unkinner_impl *impl = (struct gl2_unkinner_impl *) intf;
+
+ return (**impl->_obj.unkouter).QueryInterface (impl->_obj.unkouter, uiid);
+}
+
+static struct gl2_unknown_intf _unkinner_vftbl = {
+ _unkinner_AddRef,
+ _unkinner_Release,
+ _unkinner_QueryInterface
+};
+
+static void
+_unkinner_constructor (struct gl2_unkinner_impl *impl, struct gl2_unknown_intf **outer)
+{
+ impl->_vftbl = &_unkinner_vftbl;
+ impl->_obj.unkouter = outer;
+}
+
+struct gl2_generic_obj
+{
+ struct gl2_unknown_obj _unknown;
+ GLhandleARB name;
+ GLboolean delete_status;
+ GLcharARB *info_log;
+};
+
+struct gl2_generic_impl
+{
+ struct gl2_generic_intf *_vftbl;
+ struct gl2_generic_obj _obj;
+};
+
+static void
+_generic_destructor (struct gl2_unknown_intf **intf)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_generic_impl *impl = (struct gl2_generic_impl *) intf;
+
+ _mesa_free ((void *) impl->_obj.info_log);
+
+ _glthread_LOCK_MUTEX (ctx->Shared->Mutex);
+ _mesa_HashRemove (ctx->Shared->GL2Objects, impl->_obj.name);
+ _glthread_UNLOCK_MUTEX (ctx->Shared->Mutex);
+
+ _unknown_destructor (intf);
+}
+
+static struct gl2_unknown_intf **
+_generic_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ if (uiid == UIID_GENERIC)
+ {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+ return _unknown_QueryInterface (intf, uiid);
+}
+
+static void
+_generic_Delete (struct gl2_generic_intf **intf)
+{
+ struct gl2_generic_impl *impl = (struct gl2_generic_impl *) intf;
+
+ if (impl->_obj.delete_status == GL_FALSE)
+ {
+ impl->_obj.delete_status = GL_TRUE;
+ (**intf)._unknown.Release ((struct gl2_unknown_intf **) intf);
+ }
+}
+
+static GLhandleARB
+_generic_GetName (struct gl2_generic_intf **intf)
+{
+ struct gl2_generic_impl *impl = (struct gl2_generic_impl *) intf;
+
+ return impl->_obj.name;
+}
+
+static GLboolean
+_generic_GetDeleteStatus (struct gl2_generic_intf **intf)
+{
+ struct gl2_generic_impl *impl = (struct gl2_generic_impl *) intf;
+
+ return impl->_obj.delete_status;
+}
+
+static GLvoid
+_generic_GetInfoLog (struct gl2_generic_intf **intf, GLsizei maxlen, GLcharARB *infolog)
+{
+ struct gl2_generic_impl *impl = (struct gl2_generic_impl *) (intf);
+
+ if (maxlen > 0) {
+ _mesa_strncpy (infolog, impl->_obj.info_log, maxlen - 1);
+ infolog[maxlen - 1] = '\0';
+ }
+}
+
+static GLsizei
+_generic_GetInfoLogLength (struct gl2_generic_intf **intf)
+{
+ struct gl2_generic_impl *impl = (struct gl2_generic_impl *) (intf);
+
+ if (impl->_obj.info_log == NULL)
+ return 1;
+ return _mesa_strlen (impl->_obj.info_log) + 1;
+}
+
+static struct gl2_generic_intf _generic_vftbl = {
+ {
+ _unknown_AddRef,
+ _unknown_Release,
+ _generic_QueryInterface
+ },
+ _generic_Delete,
+ NULL, /* abstract GetType */
+ _generic_GetName,
+ _generic_GetDeleteStatus,
+ _generic_GetInfoLog,
+ _generic_GetInfoLogLength
+};
+
+static void
+_generic_constructor (struct gl2_generic_impl *impl)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ _unknown_constructor ((struct gl2_unknown_impl *) impl);
+ impl->_vftbl = &_generic_vftbl;
+ impl->_obj._unknown._destructor = _generic_destructor;
+ impl->_obj.delete_status = GL_FALSE;
+ impl->_obj.info_log = NULL;
+
+ _glthread_LOCK_MUTEX (ctx->Shared->Mutex);
+ impl->_obj.name = _mesa_HashFindFreeKeyBlock (ctx->Shared->GL2Objects, 1);
+ _mesa_HashInsert (ctx->Shared->GL2Objects, impl->_obj.name, (void *) impl);
+ _glthread_UNLOCK_MUTEX (ctx->Shared->Mutex);
+}
+
+struct gl2_container_obj
+{
+ struct gl2_generic_obj _generic;
+ struct gl2_generic_intf ***attached;
+ GLuint attached_count;
+};
+
+struct gl2_container_impl
+{
+ struct gl2_container_intf *_vftbl;
+ struct gl2_container_obj _obj;
+};
+
+static void
+_container_destructor (struct gl2_unknown_intf **intf)
+{
+ struct gl2_container_impl *impl = (struct gl2_container_impl *) intf;
+ GLuint i;
+
+ for (i = 0; i < impl->_obj.attached_count; i++)
+ {
+ struct gl2_generic_intf **x = impl->_obj.attached[i];
+ (**x)._unknown.Release ((struct gl2_unknown_intf **) x);
+ }
+
+ _generic_destructor (intf);
+}
+
+static struct gl2_unknown_intf **
+_container_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ if (uiid == UIID_CONTAINER)
+ {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+ return _generic_QueryInterface (intf, uiid);
+}
+
+static GLboolean
+_container_Attach (struct gl2_container_intf **intf, struct gl2_generic_intf **att)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_container_impl *impl = (struct gl2_container_impl *) intf;
+ GLuint i;
+
+ for (i = 0; i < impl->_obj.attached_count; i++)
+ if (impl->_obj.attached[i] == att)
+ {
+ _mesa_error (ctx, GL_INVALID_OPERATION, "_container_Attach");
+ return GL_FALSE;
+ }
+
+ impl->_obj.attached = (struct gl2_generic_intf ***) _mesa_realloc (impl->_obj.attached,
+ impl->_obj.attached_count * sizeof (*impl->_obj.attached), (impl->_obj.attached_count + 1) *
+ sizeof (*impl->_obj.attached));
+ if (impl->_obj.attached == NULL)
+ return GL_FALSE;
+
+ impl->_obj.attached[impl->_obj.attached_count] = att;
+ impl->_obj.attached_count++;
+ (**att)._unknown.AddRef ((struct gl2_unknown_intf **) att);
+ return GL_TRUE;
+}
+
+static GLboolean
+_container_Detach (struct gl2_container_intf **intf, struct gl2_generic_intf **att)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_container_impl *impl = (struct gl2_container_impl *) intf;
+ GLuint i, j;
+
+ for (i = 0; i < impl->_obj.attached_count; i++)
+ if (impl->_obj.attached[i] == att)
+ {
+ for (j = i; j < impl->_obj.attached_count - 1; j++)
+ impl->_obj.attached[j] = impl->_obj.attached[j + 1];
+ impl->_obj.attached = (struct gl2_generic_intf ***) _mesa_realloc (impl->_obj.attached,
+ impl->_obj.attached_count * sizeof (*impl->_obj.attached),
+ (impl->_obj.attached_count - 1) * sizeof (*impl->_obj.attached));
+ impl->_obj.attached_count--;
+ (**att)._unknown.Release ((struct gl2_unknown_intf **) att);
+ return GL_TRUE;
+ }
+
+ _mesa_error (ctx, GL_INVALID_OPERATION, "_container_Detach");
+ return GL_FALSE;
+}
+
+static GLsizei
+_container_GetAttachedCount (struct gl2_container_intf **intf)
+{
+ struct gl2_container_impl *impl = (struct gl2_container_impl *) intf;
+
+ return impl->_obj.attached_count;
+}
+
+static struct gl2_generic_intf **
+_container_GetAttached (struct gl2_container_intf **intf, GLuint index)
+{
+ struct gl2_container_impl *impl = (struct gl2_container_impl *) intf;
+
+ (**impl->_obj.attached[index])._unknown.AddRef (
+ (struct gl2_unknown_intf **)impl->_obj.attached[index]);
+ return impl->_obj.attached[index];
+}
+
+static struct gl2_container_intf _container_vftbl = {
+ {
+ {
+ _unknown_AddRef,
+ _unknown_Release,
+ _container_QueryInterface
+ },
+ _generic_Delete,
+ NULL, /* abstract GetType */
+ _generic_GetName,
+ _generic_GetDeleteStatus,
+ _generic_GetInfoLog,
+ _generic_GetInfoLogLength
+ },
+ _container_Attach,
+ _container_Detach,
+ _container_GetAttachedCount,
+ _container_GetAttached
+};
+
+static void
+_container_constructor (struct gl2_container_impl *impl)
+{
+ _generic_constructor ((struct gl2_generic_impl *) impl);
+ impl->_vftbl = &_container_vftbl;
+ impl->_obj._generic._unknown._destructor = _container_destructor;
+ impl->_obj.attached = NULL;
+ impl->_obj.attached_count = 0;
+}
+
+struct gl2_3dlabs_shhandle_obj
+{
+ struct gl2_unkinner_obj _unknown;
+#if USE_3DLABS_FRONTEND
+ ShHandle handle;
+#endif
+};
+
+struct gl2_3dlabs_shhandle_impl
+{
+ struct gl2_3dlabs_shhandle_intf *_vftbl;
+ struct gl2_3dlabs_shhandle_obj _obj;
+};
+
+static void
+_3dlabs_shhandle_destructor (struct gl2_unknown_intf **intf)
+{
+#if USE_3DLABS_FRONTEND
+ struct gl2_3dlabs_shhandle_impl *impl = (struct gl2_3dlabs_shhandle_impl *) intf;
+ ShDestruct (impl->_obj.handle);
+#endif
+ _unkinner_destructor (intf);
+}
+
+static GLvoid *
+_3dlabs_shhandle_GetShHandle (struct gl2_3dlabs_shhandle_intf **intf)
+{
+#if USE_3DLABS_FRONTEND
+ struct gl2_3dlabs_shhandle_impl *impl = (struct gl2_3dlabs_shhandle_impl *) intf;
+ return impl->_obj.handle;
+#else
+ return NULL;
+#endif
+}
+
+static struct gl2_3dlabs_shhandle_intf _3dlabs_shhandle_vftbl = {
+ {
+ _unkinner_AddRef,
+ _unkinner_Release,
+ _unkinner_QueryInterface
+ },
+ _3dlabs_shhandle_GetShHandle
+};
+
+static void
+_3dlabs_shhandle_constructor (struct gl2_3dlabs_shhandle_impl *impl, struct gl2_unknown_intf **outer)
+{
+ _unkinner_constructor ((struct gl2_unkinner_impl *) impl, outer);
+ impl->_vftbl = &_3dlabs_shhandle_vftbl;
+#if USE_3DLABS_FRONTEND
+ impl->_obj.handle = NULL;
+#endif
+}
+
+struct gl2_shader_obj
+{
+ struct gl2_generic_obj _generic;
+ struct gl2_3dlabs_shhandle_impl _3dlabs_shhandle;
+ GLboolean compile_status;
+ GLcharARB *source;
+ GLint *offsets;
+ GLsizei offset_count;
+ slang_code_object code;
+};
+
+struct gl2_shader_impl
+{
+ struct gl2_shader_intf *_vftbl;
+ struct gl2_shader_obj _obj;
+};
+
+static void
+_shader_destructor (struct gl2_unknown_intf **intf)
+{
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) intf;
+
+ _mesa_free ((void *) impl->_obj.source);
+ _mesa_free ((void *) impl->_obj.offsets);
+ _slang_code_object_dtr (&impl->_obj.code);
+ _3dlabs_shhandle_destructor ((struct gl2_unknown_intf **) &impl->_obj._3dlabs_shhandle._vftbl);
+ _generic_destructor (intf);
+}
+
+static struct gl2_unknown_intf **
+_shader_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+#if USE_3DLABS_FRONTEND
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) intf;
+#endif
+
+ if (uiid == UIID_SHADER)
+ {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+#if USE_3DLABS_FRONTEND
+ if (uiid == UIID_3DLABS_SHHANDLE)
+ {
+ (**intf).AddRef (intf);
+ return (struct gl2_unknown_intf **) &impl->_obj._3dlabs_shhandle._vftbl;
+ }
+#endif
+ return _generic_QueryInterface (intf, uiid);
+}
+
+static GLenum
+_shader_GetType (struct gl2_generic_intf **intf)
+{
+ return GL_SHADER_OBJECT_ARB;
+}
+
+static GLvoid
+_shader_GetInfoLog (struct gl2_generic_intf **intf, GLsizei maxlen, GLcharARB *infolog)
+{
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) (intf);
+
+ if (maxlen > 0) {
+ if (impl->_obj._generic.info_log != NULL) {
+ GLsizei len = _mesa_strlen (impl->_obj._generic.info_log);
+ if (len > maxlen - 1)
+ len = maxlen - 1;
+ _mesa_memcpy (infolog, impl->_obj._generic.info_log, len);
+ infolog += len;
+ maxlen -= len;
+ }
+ if (impl->_obj.code.machine.infolog != NULL &&
+ impl->_obj.code.machine.infolog->text != NULL) {
+ GLsizei len = _mesa_strlen (impl->_obj.code.machine.infolog->text);
+ if (len > maxlen - 1)
+ len = maxlen - 1;
+ _mesa_memcpy (infolog, impl->_obj.code.machine.infolog->text, len);
+ }
+ infolog[maxlen - 1] = '\0';
+ }
+}
+
+static GLsizei
+_shader_GetInfoLogLength (struct gl2_generic_intf **intf)
+{
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) (intf);
+ GLsizei length = 1;
+
+ if (impl->_obj._generic.info_log != NULL)
+ length += _mesa_strlen (impl->_obj._generic.info_log);
+ if (impl->_obj.code.machine.infolog != NULL &&
+ impl->_obj.code.machine.infolog->text != NULL)
+ length += _mesa_strlen (impl->_obj.code.machine.infolog->text);
+ return length;
+}
+
+static GLboolean
+_shader_GetCompileStatus (struct gl2_shader_intf **intf)
+{
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) intf;
+
+ return impl->_obj.compile_status;
+}
+
+static GLvoid
+_shader_SetSource (struct gl2_shader_intf **intf, GLcharARB *src, GLint *off, GLsizei cnt)
+{
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) intf;
+
+ _mesa_free ((void *) impl->_obj.source);
+ impl->_obj.source = src;
+ _mesa_free ((void *) impl->_obj.offsets);
+ impl->_obj.offsets = off;
+ impl->_obj.offset_count = cnt;
+}
+
+static const GLcharARB *
+_shader_GetSource (struct gl2_shader_intf **intf)
+{
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) intf;
+
+ return impl->_obj.source;
+}
+
+static GLvoid
+_shader_Compile (struct gl2_shader_intf **intf)
+{
+ struct gl2_shader_impl *impl = (struct gl2_shader_impl *) intf;
+#if USE_3DLABS_FRONTEND
+ char **strings;
+ TBuiltInResource res;
+#else
+ slang_unit_type type;
+ slang_info_log info_log;
+#endif
+
+ impl->_obj.compile_status = GL_FALSE;
+ _mesa_free ((void *) impl->_obj._generic.info_log);
+ impl->_obj._generic.info_log = NULL;
+
+#if USE_3DLABS_FRONTEND
+ /* 3dlabs compiler expects us to feed it with null-terminated string array,
+ we've got only one big string with offsets, so we must split it; but when
+ there's only one string to deal with, we pass its address directly */
+
+ if (impl->_obj.offset_count <= 1)
+ strings = &impl->_obj.source;
+ else
+ {
+ GLsizei i, offset = 0;
+
+ strings = (char **) _mesa_malloc (impl->_obj.offset_count * sizeof (char *));
+ if (strings == NULL)
+ return;
+
+ for (i = 0; i < impl->_obj.offset_count; i++)
+ {
+ GLsizei size = impl->_obj.offsets[i] - offset;
+
+ strings[i] = (char *) _mesa_malloc ((size + 1) * sizeof (char));
+ if (strings[i] == NULL)
+ {
+ GLsizei j;
+
+ for (j = 0; j < i; j++)
+ _mesa_free (strings[j]);
+ _mesa_free (strings);
+ return;
+ }
+
+ _mesa_memcpy (strings[i], impl->_obj.source + offset, size * sizeof (char));
+ strings[i][size] = '\0';
+ offset = impl->_obj.offsets[i];
+ }
+ }
+
+ /* TODO set these fields to some REAL numbers */
+ res.maxLights = 8;
+ res.maxClipPlanes = 6;
+ res.maxTextureUnits = 2;
+ res.maxTextureCoords = 2;
+ res.maxVertexAttribs = 8;
+ res.maxVertexUniformComponents = 64;
+ res.maxVaryingFloats = 8;
+ res.maxVertexTextureImageUnits = 2;
+ res.maxCombinedTextureImageUnits = 2;
+ res.maxTextureImageUnits = 2;
+ res.maxFragmentUniformComponents = 64;
+ res.maxDrawBuffers = 1;
+
+ if (ShCompile (impl->_obj._3dlabs_shhandle._obj.handle, strings, impl->_obj.offset_count,
+ EShOptFull, &res, 0))
+ impl->_obj.compile_status = GL_TRUE;
+ if (impl->_obj.offset_count > 1)
+ {
+ GLsizei i;
+
+ for (i = 0; i < impl->_obj.offset_count; i++)
+ _mesa_free (strings[i]);
+ _mesa_free (strings);
+ }
+
+ impl->_obj._generic.info_log = _mesa_strdup (ShGetInfoLog (
+ impl->_obj._3dlabs_shhandle._obj.handle));
+#else
+ if (impl->_vftbl->GetSubType (intf) == GL_FRAGMENT_SHADER)
+ type = slang_unit_fragment_shader;
+ else
+ type = slang_unit_vertex_shader;
+ slang_info_log_construct (&info_log);
+ if (_slang_compile (impl->_obj.source, &impl->_obj.code, type, &info_log))
+ impl->_obj.compile_status = GL_TRUE;
+ if (info_log.text != NULL)
+ impl->_obj._generic.info_log = _mesa_strdup (info_log.text);
+ else if (impl->_obj.compile_status)
+ impl->_obj._generic.info_log = _mesa_strdup ("Compile OK.\n");
+ else
+ impl->_obj._generic.info_log = _mesa_strdup ("Compile failed.\n");
+ slang_info_log_destruct (&info_log);
+#endif
+}
+
+static struct gl2_shader_intf _shader_vftbl = {
+ {
+ {
+ _unknown_AddRef,
+ _unknown_Release,
+ _shader_QueryInterface
+ },
+ _generic_Delete,
+ _shader_GetType,
+ _generic_GetName,
+ _generic_GetDeleteStatus,
+ _shader_GetInfoLog,
+ _shader_GetInfoLogLength
+ },
+ NULL, /* abstract GetSubType */
+ _shader_GetCompileStatus,
+ _shader_SetSource,
+ _shader_GetSource,
+ _shader_Compile
+};
+
+static void
+_shader_constructor (struct gl2_shader_impl *impl)
+{
+ _generic_constructor ((struct gl2_generic_impl *) impl);
+ _3dlabs_shhandle_constructor (&impl->_obj._3dlabs_shhandle, (struct gl2_unknown_intf **)
+ &impl->_vftbl);
+ impl->_vftbl = &_shader_vftbl;
+ impl->_obj._generic._unknown._destructor = _shader_destructor;
+ impl->_obj.compile_status = GL_FALSE;
+ impl->_obj.source = NULL;
+ impl->_obj.offsets = NULL;
+ impl->_obj.offset_count = 0;
+ _slang_code_object_ctr (&impl->_obj.code);
+}
+
+struct gl2_program_obj
+{
+ struct gl2_container_obj _container;
+ GLboolean link_status;
+ GLboolean validate_status;
+#if USE_3DLABS_FRONTEND
+ ShHandle linker;
+ ShHandle uniforms;
+#endif
+ slang_program prog;
+};
+
+struct gl2_program_impl
+{
+ struct gl2_program_intf *_vftbl;
+ struct gl2_program_obj _obj;
+};
+
+static void
+_program_destructor (struct gl2_unknown_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+#if USE_3DLABS_FRONTEND
+ ShDestruct (impl->_obj.linker);
+ ShDestruct (impl->_obj.uniforms);
+#endif
+ _container_destructor (intf);
+ slang_program_dtr (&impl->_obj.prog);
+}
+
+static struct gl2_unknown_intf **
+_program_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ if (uiid == UIID_PROGRAM)
+ {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+ return _container_QueryInterface (intf, uiid);
+}
+
+static GLenum
+_program_GetType (struct gl2_generic_intf **intf)
+{
+ return GL_PROGRAM_OBJECT_ARB;
+}
+
+static GLboolean
+_program_Attach (struct gl2_container_intf **intf, struct gl2_generic_intf **att)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_unknown_intf **sha;
+
+ sha = (**att)._unknown.QueryInterface ((struct gl2_unknown_intf **) att, UIID_SHADER);
+ if (sha == NULL)
+ {
+ _mesa_error (ctx, GL_INVALID_OPERATION, "_program_Attach");
+ return GL_FALSE;
+ }
+
+ (**sha).Release (sha);
+ return _container_Attach (intf, att);
+}
+
+static GLboolean
+_program_GetLinkStatus (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+
+ return impl->_obj.link_status;
+}
+
+static GLboolean
+_program_GetValidateStatus (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+
+ return impl->_obj.validate_status;
+}
+
+static GLvoid
+_program_Link (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+#if USE_3DLABS_FRONTEND
+ ShHandle *handles;
+#endif
+ GLuint i, count;
+ slang_code_object *code[2];
+ GLboolean all_compiled = GL_TRUE;
+
+ impl->_obj.link_status = GL_FALSE;
+ _mesa_free ((void *) impl->_obj._container._generic.info_log);
+ impl->_obj._container._generic.info_log = NULL;
+ slang_program_rst (&impl->_obj.prog);
+
+#if USE_3DLABS_FRONTEND
+ handles = (ShHandle *) _mesa_malloc (impl->_obj._container.attached_count * sizeof (ShHandle));
+ if (handles == NULL)
+ return;
+
+ for (i = 0; i < impl->_obj._container.attached_count; i++)
+ {
+ struct gl2_generic_intf **gen = impl->_obj._container.attached[i];
+ struct gl2_3dlabs_shhandle_intf **sh;
+
+ sh = (struct gl2_3dlabs_shhandle_intf **) (**gen)._unknown.QueryInterface (
+ (struct gl2_unknown_intf **) gen, UIID_3DLABS_SHHANDLE);
+ if (sh != NULL)
+ {
+ handles[i] = (**sh).GetShHandle (sh);
+ (**sh)._unknown.Release ((struct gl2_unknown_intf **) sh);
+ }
+ else
+ {
+ _mesa_free (handles);
+ return;
+ }
+ }
+
+ if (ShLink (impl->_obj.linker, handles, impl->_obj._container.attached_count,
+ impl->_obj.uniforms, NULL, NULL))
+ impl->_obj.link_status = GL_TRUE;
+
+ impl->_obj._container._generic.info_log = _mesa_strdup (ShGetInfoLog (impl->_obj.linker));
+#else
+ count = impl->_obj._container.attached_count;
+ if (count > 2)
+ return;
+ for (i = 0; i < count; i++)
+ {
+ struct gl2_generic_intf **obj;
+ struct gl2_unknown_intf **unk;
+ struct gl2_shader_impl *sha;
+
+ obj = impl->_obj._container.attached[i];
+ unk = (**obj)._unknown.QueryInterface ((struct gl2_unknown_intf **) obj, UIID_SHADER);
+ if (unk == NULL)
+ return;
+ sha = (struct gl2_shader_impl *) unk;
+ code[i] = &sha->_obj.code;
+ all_compiled = all_compiled && sha->_obj.compile_status;
+ (**unk).Release (unk);
+ }
+
+ impl->_obj.link_status = all_compiled;
+ if (!impl->_obj.link_status)
+ {
+ impl->_obj._container._generic.info_log = _mesa_strdup (
+ "Error: One or more shaders has not successfully compiled.\n");
+ return;
+ }
+
+ impl->_obj.link_status = _slang_link (&impl->_obj.prog, code, count);
+ if (!impl->_obj.link_status)
+ {
+ impl->_obj._container._generic.info_log = _mesa_strdup ("Link failed.\n");
+ return;
+ }
+
+ impl->_obj._container._generic.info_log = _mesa_strdup ("Link OK.\n");
+#endif
+}
+
+static GLvoid
+_program_Validate (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+
+ impl->_obj.validate_status = GL_FALSE;
+ _mesa_free ((void *) impl->_obj._container._generic.info_log);
+ impl->_obj._container._generic.info_log = NULL;
+
+ /* TODO validate */
+}
+
+static GLvoid
+write_common_fixed (slang_program *pro, GLuint index, const GLvoid *src, GLuint off, GLuint size)
+{
+ GLuint i;
+
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ {
+ GLuint addr;
+
+ addr = pro->common_fixed_entries[i][index];
+ if (addr != ~0)
+ {
+ GLubyte *dst;
+
+ dst = (GLubyte *) pro->machines[i]->mem + addr + off * size;
+ _mesa_memcpy (dst, src, size);
+ }
+ }
+}
+
+static GLvoid
+write_common_fixed_mat4 (slang_program *pro, GLmatrix *matrix, GLuint off, GLuint i, GLuint ii,
+ GLuint it, GLuint iit)
+{
+ GLfloat mat[16];
+
+ /* we want inverse matrix */
+ if (!matrix->inv)
+ {
+ /* allocate inverse matrix and make it dirty */
+ _math_matrix_alloc_inv (matrix);
+ _math_matrix_loadf (matrix, matrix->m);
+ }
+ _math_matrix_analyse (matrix);
+
+ write_common_fixed (pro, i, matrix->m, off, 16 * sizeof (GLfloat));
+
+ /* inverse */
+ write_common_fixed (pro, ii, matrix->inv, off, 16 * sizeof (GLfloat));
+
+ /* transpose */
+ _math_transposef (mat, matrix->m);
+ write_common_fixed (pro, it, mat, off, 16 * sizeof (GLfloat));
+
+ /* inverse transpose */
+ _math_transposef (mat, matrix->inv);
+ write_common_fixed (pro, iit, mat, off, 16 * sizeof (GLfloat));
+}
+
+static GLvoid
+write_common_fixed_material (GLcontext *ctx, slang_program *pro, GLuint i, GLuint e, GLuint a,
+ GLuint d, GLuint sp, GLuint sh)
+{
+ GLfloat v[17];
+
+ COPY_4FV(v, ctx->Light.Material.Attrib[e]);
+ COPY_4FV((v + 4), ctx->Light.Material.Attrib[a]);
+ COPY_4FV((v + 8), ctx->Light.Material.Attrib[d]);
+ COPY_4FV((v + 12), ctx->Light.Material.Attrib[sp]);
+ v[16] = ctx->Light.Material.Attrib[sh][0];
+ write_common_fixed (pro, i, v, 0, 17 * sizeof (GLfloat));
+}
+
+static GLvoid
+write_common_fixed_light_model_product (GLcontext *ctx, slang_program *pro, GLuint i, GLuint e,
+ GLuint a)
+{
+ GLfloat v[4];
+
+ SCALE_4V(v, ctx->Light.Material.Attrib[a], ctx->Light.Model.Ambient);
+ ACC_4V(v, ctx->Light.Material.Attrib[e]);
+ write_common_fixed (pro, i, v, 0, 4 * sizeof (GLfloat));
+}
+
+static GLvoid
+write_common_fixed_light_product (GLcontext *ctx, slang_program *pro, GLuint off, GLuint i, GLuint a,
+ GLuint d, GLuint s)
+{
+ GLfloat v[12];
+
+ SCALE_4V(v, ctx->Light.Light[off].Ambient, ctx->Light.Material.Attrib[a]);
+ SCALE_4V((v + 4), ctx->Light.Light[off].Diffuse, ctx->Light.Material.Attrib[d]);
+ SCALE_4V((v + 8), ctx->Light.Light[off].Specular, ctx->Light.Material.Attrib[s]);
+ write_common_fixed (pro, i, v, off, 12 * sizeof (GLfloat));
+}
+
+static GLvoid
+_program_UpdateFixedUniforms (struct gl2_program_intf **intf)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+ slang_program *pro = &impl->_obj.prog;
+ GLuint i;
+ GLfloat v[29];
+ GLfloat *p;
+
+ /* MODELVIEW matrix */
+ write_common_fixed_mat4 (pro, ctx->ModelviewMatrixStack.Top, 0,
+ SLANG_COMMON_FIXED_MODELVIEWMATRIX,
+ SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSE,
+ SLANG_COMMON_FIXED_MODELVIEWMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSETRANSPOSE);
+
+ /* PROJECTION matrix */
+ write_common_fixed_mat4 (pro, ctx->ProjectionMatrixStack.Top, 0,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIX,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSE,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSETRANSPOSE);
+
+ /* MVP matrix */
+ write_common_fixed_mat4 (pro, &ctx->_ModelProjectMatrix, 0,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIX,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSE,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSETRANSPOSE);
+
+ for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++)
+ {
+ /* TEXTURE matrix */
+ write_common_fixed_mat4 (pro, ctx->TextureMatrixStack[i].Top, i,
+ SLANG_COMMON_FIXED_TEXTUREMATRIX,
+ SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSE,
+ SLANG_COMMON_FIXED_TEXTUREMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSETRANSPOSE);
+
+ /* EYE_PLANE texture-coordinate generation */
+ write_common_fixed (pro, SLANG_COMMON_FIXED_EYEPLANES, ctx->Texture.Unit[i].EyePlaneS,
+ i, 4 * sizeof (GLfloat));
+ write_common_fixed (pro, SLANG_COMMON_FIXED_EYEPLANET, ctx->Texture.Unit[i].EyePlaneT,
+ i, 4 * sizeof (GLfloat));
+ write_common_fixed (pro, SLANG_COMMON_FIXED_EYEPLANER, ctx->Texture.Unit[i].EyePlaneR,
+ i, 4 * sizeof (GLfloat));
+ write_common_fixed (pro, SLANG_COMMON_FIXED_EYEPLANEQ, ctx->Texture.Unit[i].EyePlaneQ,
+ i, 4 * sizeof (GLfloat));
+
+ /* OBJECT_PLANE texture-coordinate generation */
+ write_common_fixed (pro, SLANG_COMMON_FIXED_OBJECTPLANES, ctx->Texture.Unit[i].ObjectPlaneS,
+ i, 4 * sizeof (GLfloat));
+ write_common_fixed (pro, SLANG_COMMON_FIXED_OBJECTPLANET, ctx->Texture.Unit[i].ObjectPlaneT,
+ i, 4 * sizeof (GLfloat));
+ write_common_fixed (pro, SLANG_COMMON_FIXED_OBJECTPLANER, ctx->Texture.Unit[i].ObjectPlaneR,
+ i, 4 * sizeof (GLfloat));
+ write_common_fixed (pro, SLANG_COMMON_FIXED_OBJECTPLANEQ, ctx->Texture.Unit[i].ObjectPlaneQ,
+ i, 4 * sizeof (GLfloat));
+ }
+
+ /* NORMAL matrix - upper 3x3 inverse transpose of MODELVIEW matrix */
+ p = ctx->ModelviewMatrixStack.Top->inv;
+ v[0] = p[0];
+ v[1] = p[4];
+ v[2] = p[8];
+ v[3] = p[1];
+ v[4] = p[5];
+ v[5] = p[9];
+ v[6] = p[2];
+ v[7] = p[6];
+ v[8] = p[10];
+ write_common_fixed (pro, SLANG_COMMON_FIXED_NORMALMATRIX, v, 0, 9 * sizeof (GLfloat));
+
+ /* normal scale */
+ write_common_fixed (pro, SLANG_COMMON_FIXED_NORMALSCALE, &ctx->_ModelViewInvScale, 0, sizeof (GLfloat));
+
+ /* depth range parameters */
+ v[0] = ctx->Viewport.Near;
+ v[1] = ctx->Viewport.Far;
+ v[2] = ctx->Viewport.Far - ctx->Viewport.Near;
+ write_common_fixed (pro, SLANG_COMMON_FIXED_DEPTHRANGE, v, 0, 3 * sizeof (GLfloat));
+
+ /* CLIP_PLANEi */
+ for (i = 0; i < ctx->Const.MaxClipPlanes; i++)
+ {
+ write_common_fixed (pro, SLANG_COMMON_FIXED_CLIPPLANE, ctx->Transform.EyeUserPlane[i], i,
+ 4 * sizeof (GLfloat));
+ }
+
+ /* point parameters */
+ v[0] = ctx->Point.Size;
+ v[1] = ctx->Point.MinSize;
+ v[2] = ctx->Point.MaxSize;
+ v[3] = ctx->Point.Threshold;
+ COPY_3FV((v + 4), ctx->Point.Params);
+ write_common_fixed (pro, SLANG_COMMON_FIXED_POINT, v, 0, 7 * sizeof (GLfloat));
+
+ /* material parameters */
+ write_common_fixed_material (ctx, pro, SLANG_COMMON_FIXED_FRONTMATERIAL,
+ MAT_ATTRIB_FRONT_EMISSION,
+ MAT_ATTRIB_FRONT_AMBIENT,
+ MAT_ATTRIB_FRONT_DIFFUSE,
+ MAT_ATTRIB_FRONT_SPECULAR,
+ MAT_ATTRIB_FRONT_SHININESS);
+ write_common_fixed_material (ctx, pro, SLANG_COMMON_FIXED_BACKMATERIAL,
+ MAT_ATTRIB_BACK_EMISSION,
+ MAT_ATTRIB_BACK_AMBIENT,
+ MAT_ATTRIB_BACK_DIFFUSE,
+ MAT_ATTRIB_BACK_SPECULAR,
+ MAT_ATTRIB_BACK_SHININESS);
+
+ for (i = 0; i < ctx->Const.MaxLights; i++)
+ {
+ /* light source parameters */
+ COPY_4FV(v, ctx->Light.Light[i].Ambient);
+ COPY_4FV((v + 4), ctx->Light.Light[i].Diffuse);
+ COPY_4FV((v + 8), ctx->Light.Light[i].Specular);
+ COPY_4FV((v + 12), ctx->Light.Light[i].EyePosition);
+ COPY_2FV((v + 16), ctx->Light.Light[i].EyePosition);
+ v[18] = ctx->Light.Light[i].EyePosition[2] + 1.0f;
+ NORMALIZE_3FV((v + 16));
+ v[19] = 0.0f;
+ COPY_3V((v + 20), ctx->Light.Light[i].EyeDirection);
+ v[23] = ctx->Light.Light[i].SpotExponent;
+ v[24] = ctx->Light.Light[i].SpotCutoff;
+ v[25] = ctx->Light.Light[i]._CosCutoffNeg;
+ v[26] = ctx->Light.Light[i].ConstantAttenuation;
+ v[27] = ctx->Light.Light[i].LinearAttenuation;
+ v[28] = ctx->Light.Light[i].QuadraticAttenuation;
+ write_common_fixed (pro, SLANG_COMMON_FIXED_LIGHTSOURCE, v, i, 29 * sizeof (GLfloat));
+
+ /* light product */
+ write_common_fixed_light_product (ctx, pro, i, SLANG_COMMON_FIXED_FRONTLIGHTPRODUCT,
+ MAT_ATTRIB_FRONT_AMBIENT,
+ MAT_ATTRIB_FRONT_DIFFUSE,
+ MAT_ATTRIB_FRONT_SPECULAR);
+ write_common_fixed_light_product (ctx, pro, i, SLANG_COMMON_FIXED_BACKLIGHTPRODUCT,
+ MAT_ATTRIB_BACK_AMBIENT,
+ MAT_ATTRIB_BACK_DIFFUSE,
+ MAT_ATTRIB_BACK_SPECULAR);
+ }
+
+ /* light model parameters */
+ write_common_fixed (pro, SLANG_COMMON_FIXED_LIGHTMODEL, ctx->Light.Model.Ambient, 0, 4 * sizeof (GLfloat));
+
+ /* light model product */
+ write_common_fixed_light_model_product (ctx, pro, SLANG_COMMON_FIXED_FRONTLIGHTMODELPRODUCT,
+ MAT_ATTRIB_FRONT_EMISSION,
+ MAT_ATTRIB_FRONT_AMBIENT);
+ write_common_fixed_light_model_product (ctx, pro, SLANG_COMMON_FIXED_BACKLIGHTMODELPRODUCT,
+ MAT_ATTRIB_BACK_EMISSION,
+ MAT_ATTRIB_BACK_AMBIENT);
+
+ /* TEXTURE_ENV_COLOR */
+ for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++)
+ {
+ write_common_fixed (pro, SLANG_COMMON_FIXED_TEXTUREENVCOLOR, ctx->Texture.Unit[i].EnvColor,
+ i, 4 * sizeof (GLfloat));
+ }
+
+ /* fog parameters */
+ COPY_4FV(v, ctx->Fog.Color);
+ v[4] = ctx->Fog.Density;
+ v[5] = ctx->Fog.Start;
+ v[6] = ctx->Fog.End;
+ v[7] = ctx->Fog._Scale;
+ write_common_fixed (pro, SLANG_COMMON_FIXED_FOG, v, 0, 8 * sizeof (GLfloat));
+}
+
+static GLvoid
+_program_UpdateFixedAttrib (struct gl2_program_intf **intf, GLuint index, GLvoid *data,
+ GLuint offset, GLuint size, GLboolean write)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+ slang_program *pro = &impl->_obj.prog;
+ GLuint addr;
+
+ addr = pro->vertex_fixed_entries[index];
+ if (addr != ~0)
+ {
+ GLubyte *mem;
+
+ mem = (GLubyte *) pro->machines[SLANG_SHADER_VERTEX]->mem + addr + offset * size;
+ if (write)
+ _mesa_memcpy (mem, data, size);
+ else
+ _mesa_memcpy (data, mem, size);
+ }
+}
+
+static GLvoid
+_program_UpdateFixedVarying (struct gl2_program_intf **intf, GLuint index, GLvoid *data,
+ GLuint offset, GLuint size, GLboolean write)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+ slang_program *pro = &impl->_obj.prog;
+ GLuint addr;
+
+ addr = pro->fragment_fixed_entries[index];
+ if (addr != ~0)
+ {
+ GLubyte *mem;
+
+ mem = (GLubyte *) pro->machines[SLANG_SHADER_FRAGMENT]->mem + addr + offset * size;
+ if (write)
+ _mesa_memcpy (mem, data, size);
+ else
+ _mesa_memcpy (data, mem, size);
+ }
+}
+
+static GLvoid
+_program_GetTextureImageUsage (struct gl2_program_intf **intf, GLbitfield *teximageusage)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+ slang_program *pro = &impl->_obj.prog;
+ GLuint i;
+
+ for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++)
+ teximageusage[i] = 0;
+
+ for (i = 0; i < pro->texture_usage.count; i++)
+ {
+ GLuint n, addr, j;
+
+ n = slang_export_data_quant_elements (pro->texture_usage.table[i].quant);
+ addr = pro->texture_usage.table[i].frag_address;
+ for (j = 0; j < n; j++)
+ {
+ GLubyte *mem;
+ GLuint image;
+
+ mem = (GLubyte *) pro->machines[SLANG_SHADER_FRAGMENT]->mem + addr + j * 4;
+ image = (GLuint) *((GLfloat *) mem);
+ if (image >= 0 && image < ctx->Const.MaxTextureImageUnits)
+ {
+ switch (slang_export_data_quant_type (pro->texture_usage.table[i].quant))
+ {
+ case GL_SAMPLER_1D_ARB:
+ case GL_SAMPLER_1D_SHADOW_ARB:
+ teximageusage[image] |= TEXTURE_1D_BIT;
+ break;
+ case GL_SAMPLER_2D_ARB:
+ case GL_SAMPLER_2D_SHADOW_ARB:
+ teximageusage[image] |= TEXTURE_2D_BIT;
+ break;
+ case GL_SAMPLER_3D_ARB:
+ teximageusage[image] |= TEXTURE_3D_BIT;
+ break;
+ case GL_SAMPLER_CUBE_ARB:
+ teximageusage[image] |= TEXTURE_CUBE_BIT;
+ break;
+ }
+ }
+ }
+ }
+
+ /* TODO: make sure that for 0<=i<=MaxTextureImageUint bitcount(teximageuint[i])<=0 */
+}
+
+static GLboolean
+_program_IsShaderPresent (struct gl2_program_intf **intf, GLenum subtype)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+ slang_program *pro = &impl->_obj.prog;
+
+ switch (subtype)
+ {
+ case GL_VERTEX_SHADER_ARB:
+ return pro->machines[SLANG_SHADER_VERTEX] != NULL;
+ case GL_FRAGMENT_SHADER_ARB:
+ return pro->machines[SLANG_SHADER_FRAGMENT] != NULL;
+ default:
+ return GL_FALSE;
+ }
+}
+
+static GLvoid
+get_active_variable (slang_active_variable *var, GLsizei maxLength, GLsizei *length, GLint *size,
+ GLenum *type, GLchar *name)
+{
+ GLsizei len;
+
+ len = _mesa_strlen (var->name);
+ if (len >= maxLength)
+ len = maxLength - 1;
+ if (length != NULL)
+ *length = len;
+ *size = slang_export_data_quant_elements (var->quant);
+ *type = slang_export_data_quant_type (var->quant);
+ _mesa_memcpy (name, var->name, len);
+ name[len] = '\0';
+}
+
+static GLuint
+get_active_variable_max_length (slang_active_variables *vars)
+{
+ GLuint i, len = 0;
+
+ for (i = 0; i < vars->count; i++)
+ {
+ GLuint n = _mesa_strlen (vars->table[i].name);
+ if (n > len)
+ len = n;
+ }
+ return len;
+}
+
+static GLvoid
+_program_GetActiveUniform (struct gl2_program_intf **intf, GLuint index, GLsizei maxLength,
+ GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+ slang_active_variable *u = &impl->_obj.prog.active_uniforms.table[index];
+
+ get_active_variable (u, maxLength, length, size, type, name);
+}
+
+static GLuint
+_program_GetActiveUniformMaxLength (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+
+ return get_active_variable_max_length (&impl->_obj.prog.active_uniforms);
+}
+
+static GLuint
+_program_GetActiveUniformCount (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+
+ return impl->_obj.prog.active_uniforms.count;
+}
+
+static GLint
+_program_GetUniformLocation (struct gl2_program_intf **intf, const GLchar *name)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+ slang_uniform_bindings *bind = &impl->_obj.prog.uniforms;
+ GLuint i;
+
+ for (i = 0; i < bind->count; i++)
+ if (_mesa_strcmp (bind->table[i].name, name) == 0)
+ return i;
+ return -1;
+}
+
+static GLboolean
+_program_WriteUniform (struct gl2_program_intf **intf, GLint loc, GLsizei count, const GLvoid *data,
+ GLenum type)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+ slang_uniform_bindings *uniforms = &impl->_obj.prog.uniforms;
+ slang_uniform_binding *uniform;
+ GLuint i;
+ GLboolean convert_float_to_bool = GL_FALSE;
+ GLboolean convert_int_to_bool = GL_FALSE;
+ GLboolean convert_int_to_float = GL_FALSE;
+ GLboolean types_match = GL_FALSE;
+
+ if (loc == -1)
+ return GL_TRUE;
+ if (loc >= uniforms->count)
+ return GL_FALSE;
+
+ uniform = &uniforms->table[loc];
+ /* TODO: check sizes */
+ if (slang_export_data_quant_struct (uniform->quant))
+ return GL_FALSE;
+
+ switch (slang_export_data_quant_type (uniform->quant))
+ {
+ case GL_BOOL_ARB:
+ types_match = (type == GL_FLOAT) || (type == GL_INT);
+ if (type == GL_FLOAT)
+ convert_float_to_bool = GL_TRUE;
+ else
+ convert_int_to_bool = GL_TRUE;
+ break;
+ case GL_BOOL_VEC2_ARB:
+ types_match = (type == GL_FLOAT_VEC2_ARB) || (type == GL_INT_VEC2_ARB);
+ if (type == GL_FLOAT_VEC2_ARB)
+ convert_float_to_bool = GL_TRUE;
+ else
+ convert_int_to_bool = GL_TRUE;
+ break;
+ case GL_BOOL_VEC3_ARB:
+ types_match = (type == GL_FLOAT_VEC3_ARB) || (type == GL_INT_VEC3_ARB);
+ if (type == GL_FLOAT_VEC3_ARB)
+ convert_float_to_bool = GL_TRUE;
+ else
+ convert_int_to_bool = GL_TRUE;
+ break;
+ case GL_BOOL_VEC4_ARB:
+ types_match = (type == GL_FLOAT_VEC4_ARB) || (type == GL_INT_VEC4_ARB);
+ if (type == GL_FLOAT_VEC4_ARB)
+ convert_float_to_bool = GL_TRUE;
+ else
+ convert_int_to_bool = GL_TRUE;
+ break;
+ case GL_SAMPLER_1D_ARB:
+ case GL_SAMPLER_2D_ARB:
+ case GL_SAMPLER_3D_ARB:
+ case GL_SAMPLER_CUBE_ARB:
+ case GL_SAMPLER_1D_SHADOW_ARB:
+ case GL_SAMPLER_2D_SHADOW_ARB:
+ types_match = (type == GL_INT);
+ break;
+ default:
+ types_match = (type == slang_export_data_quant_type (uniform->quant));
+ break;
+ }
+
+ if (!types_match)
+ return GL_FALSE;
+
+ switch (type)
+ {
+ case GL_INT:
+ case GL_INT_VEC2_ARB:
+ case GL_INT_VEC3_ARB:
+ case GL_INT_VEC4_ARB:
+ convert_int_to_float = GL_TRUE;
+ break;
+ }
+
+ if (convert_float_to_bool)
+ {
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ if (uniform->address[i] != ~0)
+ {
+ const GLfloat *src = (GLfloat *) (data);
+ GLfloat *dst = (GLfloat *)
+ (&impl->_obj.prog.machines[i]->mem[uniform->address[i] / 4]);
+ GLuint j;
+ GLuint total = count * slang_export_data_quant_components (uniform->quant);
+
+ for (j = 0; j < total; j++)
+ dst[j] = src[j] != 0.0f ? 1.0f : 0.0f;
+ }
+ }
+ else if (convert_int_to_bool)
+ {
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ if (uniform->address[i] != ~0)
+ {
+ const GLuint *src = (GLuint *) (data);
+ GLfloat *dst = (GLfloat *)
+ (&impl->_obj.prog.machines[i]->mem[uniform->address[i] / 4]);
+ GLuint j;
+ GLuint total = count * slang_export_data_quant_components (uniform->quant);
+
+ for (j = 0; j < total; j++)
+ dst[j] = src[j] ? 1.0f : 0.0f;
+ }
+ }
+ else if (convert_int_to_float)
+ {
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ if (uniform->address[i] != ~0)
+ {
+ const GLuint *src = (GLuint *) (data);
+ GLfloat *dst = (GLfloat *)
+ (&impl->_obj.prog.machines[i]->mem[uniform->address[i] / 4]);
+ GLuint j;
+ GLuint total = count * slang_export_data_quant_components (uniform->quant);
+
+ for (j = 0; j < total; j++)
+ dst[j] = (GLfloat) src[j];
+ }
+ }
+ else
+ {
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ if (uniform->address[i] != ~0)
+ {
+ _mesa_memcpy (&impl->_obj.prog.machines[i]->mem[uniform->address[i] / 4], data,
+ count * slang_export_data_quant_size (uniform->quant));
+ }
+ }
+ return GL_TRUE;
+}
+
+static GLvoid
+_program_GetActiveAttrib (struct gl2_program_intf **intf, GLuint index, GLsizei maxLength,
+ GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+ slang_active_variable *a = &impl->_obj.prog.active_attribs.table[index];
+
+ get_active_variable (a, maxLength, length, size, type, name);
+}
+
+static GLuint
+_program_GetActiveAttribMaxLength (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+
+ return get_active_variable_max_length (&impl->_obj.prog.active_attribs);
+}
+
+static GLuint
+_program_GetActiveAttribCount (struct gl2_program_intf **intf)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+
+ return impl->_obj.prog.active_attribs.count;
+}
+
+static GLint
+_program_GetAttribLocation (struct gl2_program_intf **intf, const GLchar *name)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+ slang_attrib_bindings *attribs = &impl->_obj.prog.attribs;
+ GLuint i;
+
+ for (i = 0; i < attribs->binding_count; i++)
+ if (_mesa_strcmp (attribs->bindings[i].name, name) == 0)
+ return attribs->bindings[i].first_slot_index;
+ return -1;
+}
+
+static GLvoid
+_program_OverrideAttribBinding (struct gl2_program_intf **intf, GLuint index, const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+ slang_program *pro = &impl->_obj.prog;
+
+ if (!slang_attrib_overrides_add (&pro->attrib_overrides, index, name))
+ _mesa_error (ctx, GL_OUT_OF_MEMORY, "_program_OverrideAttribBinding");
+}
+
+static GLvoid
+_program_WriteAttrib (struct gl2_program_intf **intf, GLuint index, const GLfloat *value)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) (intf);
+ slang_program *pro = &impl->_obj.prog;
+ slang_attrib_slot *slot = &pro->attribs.slots[index];
+
+ /*
+ * Generic attributes can be allocated in a shader with scalar, vec or mat type.
+ * For scalar and vec types (specifically float, vec2 and vec3) this is simple - just
+ * ignore the extra components. For mat type this is more complicated - the vertex_shader
+ * spec requires to store every column of a matrix in a separate attrib slot.
+ * To prvent from overwriting data from neighbouring matrix columns, the "fill" information
+ * is kept to know how many components to copy.
+ */
+
+ if (slot->addr != ~0)
+ _mesa_memcpy (&pro->machines[SLANG_SHADER_VERTEX]->mem[slot->addr / 4]._float, value,
+ slot->fill * sizeof (GLfloat));
+}
+
+static GLvoid
+_program_UpdateVarying (struct gl2_program_intf **intf, GLuint index, GLfloat *value,
+ GLboolean vert)
+{
+ struct gl2_program_impl *impl = (struct gl2_program_impl *) intf;
+ slang_program *pro = &impl->_obj.prog;
+ GLuint addr;
+
+ if (index >= pro->varyings.slot_count)
+ return;
+ if (vert)
+ addr = pro->varyings.slots[index].vert_addr / 4;
+ else
+ addr = pro->varyings.slots[index].frag_addr / 4;
+ if (addr != ~0)
+ {
+ if (vert)
+ *value = pro->machines[SLANG_SHADER_VERTEX]->mem[addr]._float;
+ else
+ pro->machines[SLANG_SHADER_FRAGMENT]->mem[addr]._float = *value;
+ }
+}
+
+static struct gl2_program_intf _program_vftbl = {
+ {
+ {
+ {
+ _unknown_AddRef,
+ _unknown_Release,
+ _program_QueryInterface
+ },
+ _generic_Delete,
+ _program_GetType,
+ _generic_GetName,
+ _generic_GetDeleteStatus,
+ _generic_GetInfoLog,
+ _generic_GetInfoLogLength
+ },
+ _program_Attach,
+ _container_Detach,
+ _container_GetAttachedCount,
+ _container_GetAttached
+ },
+ _program_GetLinkStatus,
+ _program_GetValidateStatus,
+ _program_Link,
+ _program_Validate,
+ _program_UpdateFixedUniforms,
+ _program_UpdateFixedAttrib,
+ _program_UpdateFixedVarying,
+ _program_GetTextureImageUsage,
+ _program_IsShaderPresent,
+ _program_GetActiveUniform,
+ _program_GetActiveUniformMaxLength,
+ _program_GetActiveUniformCount,
+ _program_GetUniformLocation,
+ _program_WriteUniform,
+ _program_GetActiveAttrib,
+ _program_GetActiveAttribMaxLength,
+ _program_GetActiveAttribCount,
+ _program_GetAttribLocation,
+ _program_OverrideAttribBinding,
+ _program_WriteAttrib,
+ _program_UpdateVarying
+};
+
+static void
+_program_constructor (struct gl2_program_impl *impl)
+{
+ _container_constructor ((struct gl2_container_impl *) impl);
+ impl->_vftbl = &_program_vftbl;
+ impl->_obj._container._generic._unknown._destructor = _program_destructor;
+ impl->_obj.link_status = GL_FALSE;
+ impl->_obj.validate_status = GL_FALSE;
+#if USE_3DLABS_FRONTEND
+ impl->_obj.linker = ShConstructLinker (EShExVertexFragment, 0);
+ impl->_obj.uniforms = ShConstructUniformMap ();
+#endif
+ slang_program_ctr (&impl->_obj.prog);
+}
+
+struct gl2_fragment_shader_obj
+{
+ struct gl2_shader_obj _shader;
+};
+
+struct gl2_fragment_shader_impl
+{
+ struct gl2_fragment_shader_intf *_vftbl;
+ struct gl2_fragment_shader_obj _obj;
+};
+
+static void
+_fragment_shader_destructor (struct gl2_unknown_intf **intf)
+{
+ struct gl2_fragment_shader_impl *impl = (struct gl2_fragment_shader_impl *) intf;
+
+ (void) impl;
+ /* TODO free fragment shader data */
+
+ _shader_destructor (intf);
+}
+
+static struct gl2_unknown_intf **
+_fragment_shader_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ if (uiid == UIID_FRAGMENT_SHADER)
+ {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+ return _shader_QueryInterface (intf, uiid);
+}
+
+static GLenum
+_fragment_shader_GetSubType (struct gl2_shader_intf **intf)
+{
+ return GL_FRAGMENT_SHADER_ARB;
+}
+
+static struct gl2_fragment_shader_intf _fragment_shader_vftbl = {
+ {
+ {
+ {
+ _unknown_AddRef,
+ _unknown_Release,
+ _fragment_shader_QueryInterface
+ },
+ _generic_Delete,
+ _shader_GetType,
+ _generic_GetName,
+ _generic_GetDeleteStatus,
+ _shader_GetInfoLog,
+ _shader_GetInfoLogLength
+ },
+ _fragment_shader_GetSubType,
+ _shader_GetCompileStatus,
+ _shader_SetSource,
+ _shader_GetSource,
+ _shader_Compile
+ }
+};
+
+static void
+_fragment_shader_constructor (struct gl2_fragment_shader_impl *impl)
+{
+ _shader_constructor ((struct gl2_shader_impl *) impl);
+ impl->_vftbl = &_fragment_shader_vftbl;
+ impl->_obj._shader._generic._unknown._destructor = _fragment_shader_destructor;
+#if USE_3DLABS_FRONTEND
+ impl->_obj._shader._3dlabs_shhandle._obj.handle = ShConstructCompiler (EShLangFragment, 0);
+#endif
+}
+
+struct gl2_vertex_shader_obj
+{
+ struct gl2_shader_obj _shader;
+};
+
+struct gl2_vertex_shader_impl
+{
+ struct gl2_vertex_shader_intf *_vftbl;
+ struct gl2_vertex_shader_obj _obj;
+};
+
+static void
+_vertex_shader_destructor (struct gl2_unknown_intf **intf)
+{
+ struct gl2_vertex_shader_impl *impl = (struct gl2_vertex_shader_impl *) intf;
+
+ (void) impl;
+ /* TODO free vertex shader data */
+
+ _shader_destructor (intf);
+}
+
+static struct gl2_unknown_intf **
+_vertex_shader_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ if (uiid == UIID_VERTEX_SHADER)
+ {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+ return _shader_QueryInterface (intf, uiid);
+}
+
+static GLenum
+_vertex_shader_GetSubType (struct gl2_shader_intf **intf)
+{
+ return GL_VERTEX_SHADER_ARB;
+}
+
+static struct gl2_vertex_shader_intf _vertex_shader_vftbl = {
+ {
+ {
+ {
+ _unknown_AddRef,
+ _unknown_Release,
+ _vertex_shader_QueryInterface
+ },
+ _generic_Delete,
+ _shader_GetType,
+ _generic_GetName,
+ _generic_GetDeleteStatus,
+ _shader_GetInfoLog,
+ _shader_GetInfoLogLength
+ },
+ _vertex_shader_GetSubType,
+ _shader_GetCompileStatus,
+ _shader_SetSource,
+ _shader_GetSource,
+ _shader_Compile
+ }
+};
+
+static void
+_vertex_shader_constructor (struct gl2_vertex_shader_impl *impl)
+{
+ _shader_constructor ((struct gl2_shader_impl *) impl);
+ impl->_vftbl = &_vertex_shader_vftbl;
+ impl->_obj._shader._generic._unknown._destructor = _vertex_shader_destructor;
+#if USE_3DLABS_FRONTEND
+ impl->_obj._shader._3dlabs_shhandle._obj.handle = ShConstructCompiler (EShLangVertex, 0);
+#endif
+}
+
+struct gl2_debug_obj
+{
+ struct gl2_generic_obj _generic;
+};
+
+struct gl2_debug_impl
+{
+ struct gl2_debug_intf *_vftbl;
+ struct gl2_debug_obj _obj;
+};
+
+static GLvoid
+_debug_destructor (struct gl2_unknown_intf **intf)
+{
+ struct gl2_debug_impl *impl = (struct gl2_debug_impl *) (intf);
+
+ (void) (impl);
+ /* TODO */
+
+ _generic_destructor (intf);
+}
+
+static struct gl2_unknown_intf **
+_debug_QueryInterface (struct gl2_unknown_intf **intf, enum gl2_uiid uiid)
+{
+ if (uiid == UIID_DEBUG) {
+ (**intf).AddRef (intf);
+ return intf;
+ }
+ return _generic_QueryInterface (intf, uiid);
+}
+
+static GLenum
+_debug_GetType (struct gl2_generic_intf **intf)
+{
+ return /*GL_DEBUG_OBJECT_MESA*/0;
+}
+
+static GLvoid
+_debug_ClearDebugLog (struct gl2_debug_intf **intf, GLenum logType, GLenum shaderType)
+{
+ struct gl2_debug_impl *impl = (struct gl2_debug_impl *) (intf);
+
+ (void) (impl);
+ /* TODO */
+}
+
+static GLvoid
+_debug_GetDebugLog (struct gl2_debug_intf **intf, GLenum logType, GLenum shaderType,
+ GLsizei maxLength, GLsizei *length, GLcharARB *infoLog)
+{
+ struct gl2_debug_impl *impl = (struct gl2_debug_impl *) (intf);
+
+ (void) (impl);
+ /* TODO */
+}
+
+static GLsizei
+_debug_GetDebugLogLength (struct gl2_debug_intf **intf, GLenum logType, GLenum shaderType)
+{
+ struct gl2_debug_impl *impl = (struct gl2_debug_impl *) (intf);
+
+ (void) (impl);
+ /* TODO */
+
+ return 0;
+}
+
+static struct gl2_debug_intf _debug_vftbl = {
+ {
+ {
+ _unknown_AddRef,
+ _unknown_Release,
+ _debug_QueryInterface
+ },
+ _generic_Delete,
+ _debug_GetType,
+ _generic_GetName,
+ _generic_GetDeleteStatus,
+ _generic_GetInfoLog,
+ _generic_GetInfoLogLength
+ },
+ _debug_ClearDebugLog,
+ _debug_GetDebugLog,
+ _debug_GetDebugLogLength
+};
+
+static GLvoid
+_debug_constructor (struct gl2_debug_impl *impl)
+{
+ _generic_constructor ((struct gl2_generic_impl *) (impl));
+ impl->_vftbl = &_debug_vftbl;
+ impl->_obj._generic._unknown._destructor = _debug_destructor;
+}
+
+GLhandleARB
+_mesa_3dlabs_create_shader_object (GLenum shaderType)
+{
+ switch (shaderType)
+ {
+ case GL_FRAGMENT_SHADER_ARB:
+ {
+ struct gl2_fragment_shader_impl *x = (struct gl2_fragment_shader_impl *)
+ _mesa_malloc (sizeof (struct gl2_fragment_shader_impl));
+
+ if (x != NULL)
+ {
+ _fragment_shader_constructor (x);
+ return x->_obj._shader._generic.name;
+ }
+ }
+ break;
+ case GL_VERTEX_SHADER_ARB:
+ {
+ struct gl2_vertex_shader_impl *x = (struct gl2_vertex_shader_impl *)
+ _mesa_malloc (sizeof (struct gl2_vertex_shader_impl));
+
+ if (x != NULL)
+ {
+ _vertex_shader_constructor (x);
+ return x->_obj._shader._generic.name;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+GLhandleARB
+_mesa_3dlabs_create_program_object (void)
+{
+ struct gl2_program_impl *x = (struct gl2_program_impl *)
+ _mesa_malloc (sizeof (struct gl2_program_impl));
+
+ if (x != NULL)
+ {
+ _program_constructor (x);
+ return x->_obj._container._generic.name;
+ }
+
+ return 0;
+}
+
+GLhandleARB
+_mesa_3dlabs_create_debug_object (GLvoid)
+{
+ struct gl2_debug_impl *obj;
+
+ obj = (struct gl2_debug_impl *) (_mesa_malloc (sizeof (struct gl2_debug_impl)));
+ if (obj != NULL) {
+ _debug_constructor (obj);
+ return obj->_obj._generic.name;
+ }
+ return 0;
+}
+
+#include "slang_assemble.h"
+#include "slang_execute.h"
+
+int _slang_fetch_discard (struct gl2_program_intf **pro, GLboolean *val)
+{
+ struct gl2_program_impl *impl;
+
+ impl = (struct gl2_program_impl *) pro;
+ *val = impl->_obj.prog.machines[SLANG_SHADER_FRAGMENT]->kill ? GL_TRUE : GL_FALSE;
+ return 1;
+}
+
+static GLvoid exec_shader (struct gl2_program_intf **pro, GLuint i)
+{
+ struct gl2_program_impl *impl;
+ slang_program *p;
+
+ impl = (struct gl2_program_impl *) pro;
+ p = &impl->_obj.prog;
+
+ slang_machine_init (p->machines[i]);
+ p->machines[i]->ip = p->code[i][SLANG_COMMON_CODE_MAIN];
+
+ _slang_execute2 (p->assemblies[i], p->machines[i]);
+}
+
+GLvoid _slang_exec_fragment_shader (struct gl2_program_intf **pro)
+{
+ exec_shader (pro, SLANG_SHADER_FRAGMENT);
+}
+
+GLvoid _slang_exec_vertex_shader (struct gl2_program_intf **pro)
+{
+ exec_shader (pro, SLANG_SHADER_VERTEX);
+}
+
+#endif
+
+void
+_mesa_init_shaderobjects_3dlabs (GLcontext *ctx)
+{
+#if USE_3DLABS_FRONTEND
+ _glslang_3dlabs_InitProcess ();
+ _glslang_3dlabs_ShInitialize ();
+#endif
+}
+
diff --git a/src/mesa/shader/shaderobjects_3dlabs.h b/src/mesa/shader/shaderobjects_3dlabs.h
new file mode 100755
index 00000000000..2092dd923e6
--- /dev/null
+++ b/src/mesa/shader/shaderobjects_3dlabs.h
@@ -0,0 +1,51 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#ifndef SHADEROBJECTS_3DLABS_H
+#define SHADEROBJECTS_3DLABS_H
+
+#if FEATURE_ARB_shader_objects
+
+extern int _slang_fetch_discard (struct gl2_program_intf **pro, GLboolean *val);
+
+extern GLvoid _slang_exec_fragment_shader (struct gl2_program_intf **pro);
+
+extern GLvoid _slang_exec_vertex_shader (struct gl2_program_intf **pro);
+
+extern GLhandleARB
+_mesa_3dlabs_create_shader_object (GLenum);
+
+extern GLhandleARB
+_mesa_3dlabs_create_program_object (GLvoid);
+
+extern GLhandleARB
+_mesa_3dlabs_create_debug_object (GLvoid);
+
+#endif /* FEATURE_ARB_shader_objects */
+
+extern void
+_mesa_init_shaderobjects_3dlabs (GLcontext *ctx);
+
+#endif
+
diff --git a/src/mesa/shader/slang/descrip.mms b/src/mesa/shader/slang/descrip.mms
new file mode 100644
index 00000000000..c86763718ac
--- /dev/null
+++ b/src/mesa/shader/slang/descrip.mms
@@ -0,0 +1,65 @@
+# Makefile for core library for VMS
+# contributed by Jouk Jansen [email protected]
+# Last revision : 17 March 2006
+
+.first
+ define gl [----.include.gl]
+ define math [--.math]
+ define swrast [--.swrast]
+ define array_cache [--.array_cache]
+
+.include [----]mms-config.
+
+##### MACROS #####
+
+VPATH = RCS
+
+INCDIR = [----.include],[--.main],[--.glapi],[-.slang],[-.grammar],[-]
+LIBDIR = [----.lib]
+CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm
+
+SOURCES = \
+ slang_compile.c,slang_preprocess.c
+
+OBJECTS = \
+ slang_compile.obj,slang_preprocess.obj,slang_utility.obj,\
+ slang_execute.obj,slang_assemble.obj,slang_assemble_conditional.obj,\
+ slang_assemble_constructor.obj,slang_assemble_typeinfo.obj,\
+ slang_storage.obj,slang_assemble_assignment.obj,\
+ slang_compile_function.obj,slang_compile_struct.obj,\
+ slang_compile_variable.obj,slang_compile_operation.obj,\
+ slang_library_noise.obj,slang_link.obj,slang_export.obj,\
+ slang_analyse.obj,slang_library_texsample.obj
+
+##### RULES #####
+
+VERSION=Mesa V3.4
+
+##### TARGETS #####
+# Make the library
+$(LIBDIR)$(GL_LIB) : $(OBJECTS)
+ @ library $(LIBDIR)$(GL_LIB) $(OBJECTS)
+
+clean :
+ purge
+ delete *.obj;*
+
+slang_compile.obj : slang_compile.c
+slang_preprocess.obj : slang_preprocess.c
+slang_utility.obj : slang_utility.c
+slang_execute.obj : slang_execute.c
+slang_assemble.obj : slang_assemble.c
+slang_assemble_conditional.obj : slang_assemble_conditional.c
+slang_assemble_constructor.obj : slang_assemble_constructor.c
+slang_assemble_typeinfo.obj : slang_assemble_typeinfo.c
+slang_storage.obj : slang_storage.c
+slang_assemble_assignment.obj : slang_assemble_assignment.c
+slang_compile_function.obj : slang_compile_function.c
+slang_compile_struct.obj : slang_compile_struct.c
+slang_compile_variable.obj : slang_compile_variable.c
+slang_compile_operation.obj : slang_compile_operation.c
+slang_library_noise.obj : slang_library_noise.c
+slang_link.obj : slang_link.c
+slang_export.obj : slang_export.c
+slang_analyse.obj : slang_analyse.c
+slang_library_texsample.obj : slang_library_texsample.c
diff --git a/src/mesa/shader/slang/library/gc_to_bin.c b/src/mesa/shader/slang/library/gc_to_bin.c
new file mode 100755
index 00000000000..69895d84bfd
--- /dev/null
+++ b/src/mesa/shader/slang/library/gc_to_bin.c
@@ -0,0 +1,87 @@
+#include "../../grammar/grammar_crt.h"
+#include "../../grammar/grammar_crt.c"
+#include <stdio.h>
+
+static const char *slang_shader_syn =
+#include "slang_shader_syn.h"
+;
+
+static void gc_to_bin (grammar id, const char *in, const char *out)
+{
+ FILE *f;
+ byte *source, *prod;
+ unsigned int size, i, line = 0;
+
+ printf ("Precompiling %s\n", in);
+
+ f = fopen (in, "r");
+ if (f == NULL)
+ return;
+ fseek (f, 0, SEEK_END);
+ size = ftell (f);
+ fseek (f, 0, SEEK_SET);
+ source = (byte *) grammar_alloc_malloc (size + 1);
+ source[fread (source, 1, size, f)] = '\0';
+ fclose (f);
+
+ if (!grammar_fast_check (id, source, &prod, &size, 65536))
+ {
+ grammar_alloc_free (source);
+ return;
+ }
+
+ f = fopen (out, "w");
+ fprintf (f, "\n");
+ fprintf (f, "/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */\n");
+ fprintf (f, "/* %s */\n", in);
+ fprintf (f, "\n");
+ for (i = 0; i < size; i++)
+ {
+ unsigned int a;
+ if (prod[i] < 10)
+ a = 1;
+ else if (prod[i] < 100)
+ a = 2;
+ else
+ a = 3;
+ if (i < size - 1)
+ a++;
+ if (line + a >= 100)
+ {
+ fprintf (f, "\n");
+ line = 0;
+ }
+ line += a;
+ fprintf (f, "%d", prod[i]);
+ if (i < size - 1)
+ fprintf (f, ",");
+ }
+ fprintf (f, "\n");
+ fclose (f);
+ grammar_alloc_free (prod);
+}
+
+int main ()
+{
+ grammar id;
+
+ id = grammar_load_from_text ((const byte *) slang_shader_syn);
+ if (id == 0)
+ return 1;
+
+ grammar_set_reg8 (id, (const byte *) "parsing_builtin", 1);
+
+ grammar_set_reg8 (id, (const byte *) "shader_type", 1);
+ gc_to_bin (id, "slang_core.gc", "slang_core_gc.h");
+ gc_to_bin (id, "slang_common_builtin.gc", "slang_common_builtin_gc.h");
+ gc_to_bin (id, "slang_fragment_builtin.gc", "slang_fragment_builtin_gc.h");
+ gc_to_bin (id, "slang_builtin_vec4.gc", "slang_builtin_vec4_gc.h");
+
+ grammar_set_reg8 (id, (const byte *) "shader_type", 2);
+ gc_to_bin (id, "slang_vertex_builtin.gc", "slang_vertex_builtin_gc.h");
+
+ grammar_destroy (id);
+
+ return 0;
+}
+
diff --git a/src/mesa/shader/slang/library/slang_builtin_vec4_gc.h b/src/mesa/shader/slang/library/slang_builtin_vec4_gc.h
new file mode 100644
index 00000000000..9c3bae2644c
--- /dev/null
+++ b/src/mesa/shader/slang/library/slang_builtin_vec4_gc.h
@@ -0,0 +1,62 @@
+
+/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */
+/* slang_builtin_vec4.gc */
+
+3,1,0,12,1,1,1,0,9,102,0,0,0,1,3,2,0,12,1,118,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,
+52,0,18,118,0,0,18,102,0,0,0,8,18,118,0,0,0,1,0,0,2,1,1,0,2,12,118,0,0,1,1,0,12,117,0,0,0,1,4,118,
+101,99,52,95,97,100,100,0,18,118,0,0,18,117,0,0,0,0,1,0,0,2,2,1,0,2,12,118,0,0,1,1,0,12,117,0,0,0,
+1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,118,0,0,18,117,0,0,0,0,1,0,0,2,3,1,0,2,12,
+118,0,0,1,1,0,12,117,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,118,0,0,18,
+117,0,0,0,0,1,0,0,2,4,1,0,2,12,118,0,0,1,1,0,12,117,0,0,0,1,4,118,101,99,52,95,100,105,118,105,100,
+101,0,18,118,0,0,18,117,0,0,0,0,1,0,0,2,1,1,0,2,12,118,0,0,1,1,0,9,97,0,0,0,1,3,2,0,12,1,117,0,0,0,
+4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,117,0,0,18,97,0,0,0,4,118,101,99,52,95,97,
+100,100,0,18,118,0,0,18,117,0,0,0,0,1,0,0,2,2,1,0,2,12,118,0,0,1,1,0,9,97,0,0,0,1,3,2,0,12,1,117,0,
+0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,117,0,0,18,97,0,0,0,4,118,101,99,52,95,
+115,117,98,116,114,97,99,116,0,18,118,0,0,18,117,0,0,0,0,1,0,0,2,3,1,0,2,12,118,0,0,1,1,0,9,97,0,0,
+0,1,3,2,0,12,1,117,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,117,0,0,18,97,0,0,0,
+4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,118,0,0,18,117,0,0,0,0,1,0,0,2,4,1,0,2,12,
+118,0,0,1,1,0,9,97,0,0,0,1,3,2,0,12,1,117,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,
+18,117,0,0,18,97,0,0,0,4,118,101,99,52,95,100,105,118,105,100,101,0,18,118,0,0,18,117,0,0,0,0,1,0,
+12,2,26,1,0,0,12,118,0,0,1,1,0,12,117,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,118,0,0,18,117,0,
+0,0,8,18,118,0,0,0,1,0,12,2,27,1,0,0,12,118,0,0,1,1,0,12,117,0,0,0,1,4,118,101,99,52,95,115,117,98,
+116,114,97,99,116,0,18,118,0,0,18,117,0,0,0,8,18,118,0,0,0,1,0,12,2,21,1,0,0,12,118,0,0,1,1,0,12,
+117,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,118,0,0,18,117,0,0,0,8,18,118,
+0,0,0,1,0,12,2,22,1,0,0,12,118,0,0,1,1,0,12,117,0,0,0,1,4,118,101,99,52,95,100,105,118,105,100,101,
+0,18,118,0,0,18,117,0,0,0,8,18,118,0,0,0,1,0,12,2,26,1,1,0,9,97,0,0,1,1,0,12,117,0,0,0,1,3,2,0,12,
+1,118,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,118,0,0,18,97,0,0,0,4,118,101,99,
+52,95,97,100,100,0,18,118,0,0,18,117,0,0,0,8,18,118,0,0,0,1,0,12,2,26,1,1,0,12,118,0,0,1,1,0,9,98,
+0,0,0,1,3,2,0,12,1,117,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,117,0,0,18,98,0,
+0,0,4,118,101,99,52,95,97,100,100,0,18,117,0,0,18,118,0,0,0,8,18,117,0,0,0,1,0,12,2,27,1,1,0,9,97,
+0,0,1,1,0,12,117,0,0,0,1,3,2,0,12,1,118,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,
+18,118,0,0,18,97,0,0,0,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,118,0,0,18,117,0,0,0,8,
+18,118,0,0,0,1,0,12,2,27,1,0,0,12,118,0,0,1,1,0,9,98,0,0,0,1,3,2,0,12,1,117,0,0,0,4,102,108,111,97,
+116,95,116,111,95,118,101,99,52,0,18,117,0,0,18,98,0,0,0,4,118,101,99,52,95,115,117,98,116,114,97,
+99,116,0,18,118,0,0,18,117,0,0,0,8,18,118,0,0,0,1,0,12,2,21,1,1,0,9,97,0,0,1,1,0,12,117,0,0,0,1,3,
+2,0,12,1,118,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,118,0,0,18,97,0,0,0,4,118,
+101,99,52,95,109,117,108,116,105,112,108,121,0,18,118,0,0,18,117,0,0,0,8,18,118,0,0,0,1,0,12,2,21,
+1,1,0,12,118,0,0,1,1,0,9,98,0,0,0,1,3,2,0,12,1,117,0,0,0,4,102,108,111,97,116,95,116,111,95,118,
+101,99,52,0,18,117,0,0,18,98,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,117,0,0,
+18,118,0,0,0,8,18,117,0,0,0,1,0,12,2,22,1,1,0,9,97,0,0,1,1,0,12,117,0,0,0,1,3,2,0,12,1,118,0,0,0,4,
+102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,118,0,0,18,97,0,0,0,4,118,101,99,52,95,100,105,
+118,105,100,101,0,18,118,0,0,18,117,0,0,0,8,18,118,0,0,0,1,0,12,2,22,1,0,0,12,118,0,0,1,1,0,9,98,0,
+0,0,1,3,2,0,12,1,117,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,117,0,0,18,98,0,0,
+0,4,118,101,99,52,95,100,105,118,105,100,101,0,18,118,0,0,18,117,0,0,0,8,18,118,0,0,0,1,0,12,2,27,
+1,0,0,12,118,0,0,0,1,4,118,101,99,52,95,110,101,103,97,116,101,0,18,118,0,0,0,8,18,118,0,0,0,1,0,9,
+0,100,111,116,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,3,2,0,12,1,118,52,0,2,58,118,101,99,52,0,18,
+118,0,0,17,48,0,48,0,0,0,0,0,0,3,2,0,12,1,117,52,0,2,58,118,101,99,52,0,18,117,0,0,17,48,0,48,0,0,
+0,0,0,0,4,118,101,99,52,95,100,111,116,0,18,118,52,0,0,18,117,52,0,0,0,8,18,118,52,0,59,120,0,0,0,
+1,0,9,0,100,111,116,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,4,118,101,99,52,95,100,111,116,0,18,
+118,0,0,18,117,0,0,0,8,18,118,0,59,120,0,0,0,1,0,9,0,108,101,110,103,116,104,0,1,0,0,11,118,0,0,0,
+1,3,2,0,12,1,117,0,2,58,118,101,99,52,0,18,118,0,0,17,48,0,48,0,0,0,0,0,0,4,118,101,99,52,95,100,
+111,116,0,18,117,0,0,18,117,0,0,0,8,58,115,113,114,116,0,18,117,0,59,120,0,0,0,0,0,1,0,9,0,108,101,
+110,103,116,104,0,1,0,0,12,118,0,0,0,1,4,118,101,99,52,95,100,111,116,0,18,118,0,0,18,118,0,0,0,8,
+58,115,113,114,116,0,18,118,0,59,120,0,0,0,0,0,1,0,11,0,110,111,114,109,97,108,105,122,101,0,1,0,0,
+11,118,0,0,0,1,3,2,0,12,1,117,0,2,58,118,101,99,52,0,18,118,0,0,17,48,0,48,0,0,0,0,0,0,3,2,0,12,1,
+119,0,2,18,117,0,0,0,4,118,101,99,52,95,100,111,116,0,18,117,0,0,18,117,0,0,0,3,2,0,9,1,108,0,2,58,
+115,113,114,116,0,18,117,0,59,120,0,0,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,18,
+117,0,0,18,108,0,0,0,4,118,101,99,52,95,100,105,118,105,100,101,0,18,119,0,0,18,117,0,0,0,8,18,119,
+0,59,120,121,122,0,0,0,1,0,12,0,110,111,114,109,97,108,105,122,101,0,1,0,0,12,118,0,0,0,1,3,2,0,12,
+1,119,0,2,18,118,0,0,0,4,118,101,99,52,95,100,111,116,0,18,118,0,0,18,118,0,0,0,3,2,0,9,1,108,0,2,
+58,115,113,114,116,0,18,118,0,59,120,0,0,0,0,0,4,102,108,111,97,116,95,116,111,95,118,101,99,52,0,
+18,118,0,0,18,108,0,0,0,4,118,101,99,52,95,100,105,118,105,100,101,0,18,119,0,0,18,118,0,0,0,8,18,
+119,0,0,0,0
diff --git a/src/mesa/shader/slang/library/slang_common_builtin_gc.h b/src/mesa/shader/slang/library/slang_common_builtin_gc.h
new file mode 100644
index 00000000000..e5876528e1c
--- /dev/null
+++ b/src/mesa/shader/slang/library/slang_common_builtin_gc.h
@@ -0,0 +1,647 @@
+
+/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */
+/* slang_common_builtin.gc */
+
+3,2,2,1,5,1,103,108,95,77,97,120,76,105,103,104,116,115,0,2,16,10,56,0,0,0,2,2,1,5,1,103,108,95,77,
+97,120,67,108,105,112,80,108,97,110,101,115,0,2,16,10,54,0,0,0,2,2,1,5,1,103,108,95,77,97,120,84,
+101,120,116,117,114,101,85,110,105,116,115,0,2,16,10,56,0,0,0,2,2,1,5,1,103,108,95,77,97,120,84,
+101,120,116,117,114,101,67,111,111,114,100,115,0,2,16,10,56,0,0,0,2,2,1,5,1,103,108,95,77,97,120,
+86,101,114,116,101,120,65,116,116,114,105,98,115,0,2,16,10,49,54,0,0,0,2,2,1,5,1,103,108,95,77,97,
+120,86,101,114,116,101,120,85,110,105,102,111,114,109,67,111,109,112,111,110,101,110,116,115,0,2,
+16,10,53,49,50,0,0,0,2,2,1,5,1,103,108,95,77,97,120,86,97,114,121,105,110,103,70,108,111,97,116,
+115,0,2,16,10,51,50,0,0,0,2,2,1,5,1,103,108,95,77,97,120,86,101,114,116,101,120,84,101,120,116,117,
+114,101,73,109,97,103,101,85,110,105,116,115,0,2,16,8,48,0,0,0,2,2,1,5,1,103,108,95,77,97,120,67,
+111,109,98,105,110,101,100,84,101,120,116,117,114,101,73,109,97,103,101,85,110,105,116,115,0,2,16,
+10,50,0,0,0,2,2,1,5,1,103,108,95,77,97,120,84,101,120,116,117,114,101,73,109,97,103,101,85,110,105,
+116,115,0,2,16,10,50,0,0,0,2,2,1,5,1,103,108,95,77,97,120,70,114,97,103,109,101,110,116,85,110,105,
+102,111,114,109,67,111,109,112,111,110,101,110,116,115,0,2,16,10,54,52,0,0,0,2,2,1,5,1,103,108,95,
+77,97,120,68,114,97,119,66,117,102,102,101,114,115,0,2,16,10,49,0,0,0,2,2,4,15,1,103,108,95,77,111,
+100,101,108,86,105,101,119,77,97,116,114,105,120,0,0,0,2,2,4,15,1,103,108,95,80,114,111,106,101,99,
+116,105,111,110,77,97,116,114,105,120,0,0,0,2,2,4,15,1,103,108,95,77,111,100,101,108,86,105,101,
+119,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,0,0,0,2,2,4,15,1,103,108,95,84,101,
+120,116,117,114,101,77,97,116,114,105,120,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,
+67,111,111,114,100,115,0,0,0,2,2,4,14,1,103,108,95,78,111,114,109,97,108,77,97,116,114,105,120,0,0,
+0,2,2,4,15,1,103,108,95,77,111,100,101,108,86,105,101,119,77,97,116,114,105,120,73,110,118,101,114,
+115,101,0,0,0,2,2,4,15,1,103,108,95,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,73,
+110,118,101,114,115,101,0,0,0,2,2,4,15,1,103,108,95,77,111,100,101,108,86,105,101,119,80,114,111,
+106,101,99,116,105,111,110,77,97,116,114,105,120,73,110,118,101,114,115,101,0,0,0,2,2,4,15,1,103,
+108,95,84,101,120,116,117,114,101,77,97,116,114,105,120,73,110,118,101,114,115,101,0,3,18,103,108,
+95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,4,15,1,103,108,95,77,111,
+100,101,108,86,105,101,119,77,97,116,114,105,120,84,114,97,110,115,112,111,115,101,0,0,0,2,2,4,15,
+1,103,108,95,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,84,114,97,110,115,112,111,
+115,101,0,0,0,2,2,4,15,1,103,108,95,77,111,100,101,108,86,105,101,119,80,114,111,106,101,99,116,
+105,111,110,77,97,116,114,105,120,84,114,97,110,115,112,111,115,101,0,0,0,2,2,4,15,1,103,108,95,84,
+101,120,116,117,114,101,77,97,116,114,105,120,84,114,97,110,115,112,111,115,101,0,3,18,103,108,95,
+77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,4,15,1,103,108,95,77,111,100,
+101,108,86,105,101,119,77,97,116,114,105,120,73,110,118,101,114,115,101,84,114,97,110,115,112,111,
+115,101,0,0,0,2,2,4,15,1,103,108,95,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,73,
+110,118,101,114,115,101,84,114,97,110,115,112,111,115,101,0,0,0,2,2,4,15,1,103,108,95,77,111,100,
+101,108,86,105,101,119,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,73,110,118,101,
+114,115,101,84,114,97,110,115,112,111,115,101,0,0,0,2,2,4,15,1,103,108,95,84,101,120,116,117,114,
+101,77,97,116,114,105,120,73,110,118,101,114,115,101,84,114,97,110,115,112,111,115,101,0,3,18,103,
+108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,4,9,1,103,108,95,78,
+111,114,109,97,108,83,99,97,108,101,0,0,0,2,2,0,22,103,108,95,68,101,112,116,104,82,97,110,103,101,
+80,97,114,97,109,101,116,101,114,115,0,9,110,101,97,114,0,0,0,1,9,102,97,114,0,0,0,1,9,100,105,102,
+102,0,0,0,0,0,0,2,2,4,23,103,108,95,68,101,112,116,104,82,97,110,103,101,80,97,114,97,109,101,116,
+101,114,115,0,1,103,108,95,68,101,112,116,104,82,97,110,103,101,0,0,0,2,2,4,12,1,103,108,95,67,108,
+105,112,80,108,97,110,101,0,3,18,103,108,95,77,97,120,67,108,105,112,80,108,97,110,101,115,0,0,0,2,
+2,0,22,103,108,95,80,111,105,110,116,80,97,114,97,109,101,116,101,114,115,0,9,115,105,122,101,0,0,
+0,1,9,115,105,122,101,77,105,110,0,0,0,1,9,115,105,122,101,77,97,120,0,0,0,1,9,102,97,100,101,84,
+104,114,101,115,104,111,108,100,83,105,122,101,0,0,0,1,9,100,105,115,116,97,110,99,101,67,111,110,
+115,116,97,110,116,65,116,116,101,110,117,97,116,105,111,110,0,0,0,1,9,100,105,115,116,97,110,99,
+101,76,105,110,101,97,114,65,116,116,101,110,117,97,116,105,111,110,0,0,0,1,9,100,105,115,116,97,
+110,99,101,81,117,97,100,114,97,116,105,99,65,116,116,101,110,117,97,116,105,111,110,0,0,0,0,0,0,2,
+2,4,23,103,108,95,80,111,105,110,116,80,97,114,97,109,101,116,101,114,115,0,1,103,108,95,80,111,
+105,110,116,0,0,0,2,2,0,22,103,108,95,77,97,116,101,114,105,97,108,80,97,114,97,109,101,116,101,
+114,115,0,12,101,109,105,115,115,105,111,110,0,0,0,1,12,97,109,98,105,101,110,116,0,0,0,1,12,100,
+105,102,102,117,115,101,0,0,0,1,12,115,112,101,99,117,108,97,114,0,0,0,1,9,115,104,105,110,105,110,
+101,115,115,0,0,0,0,0,0,2,2,4,23,103,108,95,77,97,116,101,114,105,97,108,80,97,114,97,109,101,116,
+101,114,115,0,1,103,108,95,70,114,111,110,116,77,97,116,101,114,105,97,108,0,0,0,2,2,4,23,103,108,
+95,77,97,116,101,114,105,97,108,80,97,114,97,109,101,116,101,114,115,0,1,103,108,95,66,97,99,107,
+77,97,116,101,114,105,97,108,0,0,0,2,2,0,22,103,108,95,76,105,103,104,116,83,111,117,114,99,101,80,
+97,114,97,109,101,116,101,114,115,0,12,97,109,98,105,101,110,116,0,0,0,1,12,100,105,102,102,117,
+115,101,0,0,0,1,12,115,112,101,99,117,108,97,114,0,0,0,1,12,112,111,115,105,116,105,111,110,0,0,0,
+1,12,104,97,108,102,86,101,99,116,111,114,0,0,0,1,11,115,112,111,116,68,105,114,101,99,116,105,111,
+110,0,0,0,1,9,115,112,111,116,69,120,112,111,110,101,110,116,0,0,0,1,9,115,112,111,116,67,117,116,
+111,102,102,0,0,0,1,9,115,112,111,116,67,111,115,67,117,116,111,102,102,0,0,0,1,9,99,111,110,115,
+116,97,110,116,65,116,116,101,110,117,97,116,105,111,110,0,0,0,1,9,108,105,110,101,97,114,65,116,
+116,101,110,117,97,116,105,111,110,0,0,0,1,9,113,117,97,100,114,97,116,105,99,65,116,116,101,110,
+117,97,116,105,111,110,0,0,0,0,0,0,2,2,4,23,103,108,95,76,105,103,104,116,83,111,117,114,99,101,80,
+97,114,97,109,101,116,101,114,115,0,1,103,108,95,76,105,103,104,116,83,111,117,114,99,101,0,3,18,
+103,108,95,77,97,120,76,105,103,104,116,115,0,0,0,2,2,0,22,103,108,95,76,105,103,104,116,77,111,
+100,101,108,80,97,114,97,109,101,116,101,114,115,0,12,97,109,98,105,101,110,116,0,0,0,0,0,0,2,2,4,
+23,103,108,95,76,105,103,104,116,77,111,100,101,108,80,97,114,97,109,101,116,101,114,115,0,1,103,
+108,95,76,105,103,104,116,77,111,100,101,108,0,0,0,2,2,0,22,103,108,95,76,105,103,104,116,77,111,
+100,101,108,80,114,111,100,117,99,116,115,0,12,115,99,101,110,101,67,111,108,111,114,0,0,0,0,0,0,2,
+2,4,23,103,108,95,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,115,0,1,103,108,
+95,70,114,111,110,116,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,0,0,0,2,2,4,
+23,103,108,95,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,115,0,1,103,108,95,
+66,97,99,107,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,0,0,0,2,2,0,22,103,
+108,95,76,105,103,104,116,80,114,111,100,117,99,116,115,0,12,97,109,98,105,101,110,116,0,0,0,1,12,
+100,105,102,102,117,115,101,0,0,0,1,12,115,112,101,99,117,108,97,114,0,0,0,0,0,0,2,2,4,23,103,108,
+95,76,105,103,104,116,80,114,111,100,117,99,116,115,0,1,103,108,95,70,114,111,110,116,76,105,103,
+104,116,80,114,111,100,117,99,116,0,3,18,103,108,95,77,97,120,76,105,103,104,116,115,0,0,0,2,2,4,
+23,103,108,95,76,105,103,104,116,80,114,111,100,117,99,116,115,0,1,103,108,95,66,97,99,107,76,105,
+103,104,116,80,114,111,100,117,99,116,0,3,18,103,108,95,77,97,120,76,105,103,104,116,115,0,0,0,2,2,
+4,12,1,103,108,95,84,101,120,116,117,114,101,69,110,118,67,111,108,111,114,0,3,18,103,108,95,77,97,
+120,84,101,120,116,117,114,101,73,109,97,103,101,85,110,105,116,115,0,0,0,2,2,4,12,1,103,108,95,69,
+121,101,80,108,97,110,101,83,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,
+100,115,0,0,0,2,2,4,12,1,103,108,95,69,121,101,80,108,97,110,101,84,0,3,18,103,108,95,77,97,120,84,
+101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,4,12,1,103,108,95,69,121,101,80,108,97,
+110,101,82,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,
+4,12,1,103,108,95,69,121,101,80,108,97,110,101,81,0,3,18,103,108,95,77,97,120,84,101,120,116,117,
+114,101,67,111,111,114,100,115,0,0,0,2,2,4,12,1,103,108,95,79,98,106,101,99,116,80,108,97,110,101,
+83,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,4,12,1,
+103,108,95,79,98,106,101,99,116,80,108,97,110,101,84,0,3,18,103,108,95,77,97,120,84,101,120,116,
+117,114,101,67,111,111,114,100,115,0,0,0,2,2,4,12,1,103,108,95,79,98,106,101,99,116,80,108,97,110,
+101,82,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,4,
+12,1,103,108,95,79,98,106,101,99,116,80,108,97,110,101,81,0,3,18,103,108,95,77,97,120,84,101,120,
+116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,0,22,103,108,95,70,111,103,80,97,114,97,109,101,
+116,101,114,115,0,12,99,111,108,111,114,0,0,0,1,9,100,101,110,115,105,116,121,0,0,0,1,9,115,116,97,
+114,116,0,0,0,1,9,101,110,100,0,0,0,1,9,115,99,97,108,101,0,0,0,0,0,0,2,2,4,23,103,108,95,70,111,
+103,80,97,114,97,109,101,116,101,114,115,0,1,103,108,95,70,111,103,0,0,0,1,0,9,0,114,97,100,105,97,
+110,115,0,1,0,0,9,100,101,103,0,0,0,1,8,17,51,0,49,52,49,53,57,51,0,0,18,100,101,103,0,48,17,49,56,
+48,0,48,0,0,49,0,0,1,0,10,0,114,97,100,105,97,110,115,0,1,0,0,10,100,101,103,0,0,0,1,8,58,118,101,
+99,50,0,17,51,0,49,52,49,53,57,51,0,0,0,0,18,100,101,103,0,48,58,118,101,99,50,0,17,49,56,48,0,48,
+0,0,0,0,49,0,0,1,0,11,0,114,97,100,105,97,110,115,0,1,0,0,11,100,101,103,0,0,0,1,8,58,118,101,99,
+51,0,17,51,0,49,52,49,53,57,51,0,0,0,0,18,100,101,103,0,48,58,118,101,99,51,0,17,49,56,48,0,48,0,0,
+0,0,49,0,0,1,0,12,0,114,97,100,105,97,110,115,0,1,0,0,12,100,101,103,0,0,0,1,8,58,118,101,99,52,0,
+17,51,0,49,52,49,53,57,51,0,0,0,0,18,100,101,103,0,48,58,118,101,99,52,0,17,49,56,48,0,48,0,0,0,0,
+49,0,0,1,0,9,0,100,101,103,114,101,101,115,0,1,0,0,9,114,97,100,0,0,0,1,8,17,49,56,48,0,48,0,0,18,
+114,97,100,0,48,17,51,0,49,52,49,53,57,51,0,0,49,0,0,1,0,10,0,100,101,103,114,101,101,115,0,1,0,0,
+10,114,97,100,0,0,0,1,8,58,118,101,99,50,0,17,49,56,48,0,48,0,0,0,0,18,114,97,100,0,48,58,118,101,
+99,50,0,17,51,0,49,52,49,53,57,51,0,0,0,0,49,0,0,1,0,11,0,100,101,103,114,101,101,115,0,1,0,0,11,
+114,97,100,0,0,0,1,8,58,118,101,99,51,0,17,49,56,48,0,48,0,0,0,0,18,114,97,100,0,48,58,118,101,99,
+51,0,17,51,0,49,52,49,53,57,51,0,0,0,0,49,0,0,1,0,12,0,100,101,103,114,101,101,115,0,1,0,0,12,114,
+97,100,0,0,0,1,8,58,118,101,99,52,0,17,49,56,48,0,48,0,0,0,0,18,114,97,100,0,48,58,118,101,99,52,0,
+17,51,0,49,52,49,53,57,51,0,0,0,0,49,0,0,1,0,9,0,115,105,110,0,1,0,0,9,97,110,103,108,101,0,0,0,1,
+3,2,0,9,1,120,0,0,0,4,102,108,111,97,116,95,115,105,110,101,0,18,120,0,0,18,97,110,103,108,101,0,0,
+0,8,18,120,0,0,0,1,0,10,0,115,105,110,0,1,0,0,10,97,110,103,108,101,0,0,0,1,8,58,118,101,99,50,0,
+58,115,105,110,0,18,97,110,103,108,101,0,59,120,0,0,0,0,58,115,105,110,0,18,97,110,103,108,101,0,
+59,121,0,0,0,0,0,0,0,1,0,11,0,115,105,110,0,1,0,0,11,97,110,103,108,101,0,0,0,1,8,58,118,101,99,51,
+0,58,115,105,110,0,18,97,110,103,108,101,0,59,120,0,0,0,0,58,115,105,110,0,18,97,110,103,108,101,0,
+59,121,0,0,0,0,58,115,105,110,0,18,97,110,103,108,101,0,59,122,0,0,0,0,0,0,0,1,0,12,0,115,105,110,
+0,1,0,0,12,97,110,103,108,101,0,0,0,1,8,58,118,101,99,52,0,58,115,105,110,0,18,97,110,103,108,101,
+0,59,120,0,0,0,0,58,115,105,110,0,18,97,110,103,108,101,0,59,121,0,0,0,0,58,115,105,110,0,18,97,
+110,103,108,101,0,59,122,0,0,0,0,58,115,105,110,0,18,97,110,103,108,101,0,59,119,0,0,0,0,0,0,0,1,0,
+9,0,99,111,115,0,1,0,0,9,97,110,103,108,101,0,0,0,1,8,58,115,105,110,0,18,97,110,103,108,101,0,17,
+49,0,53,55,48,56,0,0,46,0,0,0,0,1,0,10,0,99,111,115,0,1,0,0,10,97,110,103,108,101,0,0,0,1,8,58,118,
+101,99,50,0,58,99,111,115,0,18,97,110,103,108,101,0,59,120,0,0,0,0,58,99,111,115,0,18,97,110,103,
+108,101,0,59,121,0,0,0,0,0,0,0,1,0,11,0,99,111,115,0,1,0,0,11,97,110,103,108,101,0,0,0,1,8,58,118,
+101,99,51,0,58,99,111,115,0,18,97,110,103,108,101,0,59,120,0,0,0,0,58,99,111,115,0,18,97,110,103,
+108,101,0,59,121,0,0,0,0,58,99,111,115,0,18,97,110,103,108,101,0,59,122,0,0,0,0,0,0,0,1,0,12,0,99,
+111,115,0,1,0,0,12,97,110,103,108,101,0,0,0,1,8,58,118,101,99,52,0,58,99,111,115,0,18,97,110,103,
+108,101,0,59,120,0,0,0,0,58,99,111,115,0,18,97,110,103,108,101,0,59,121,0,0,0,0,58,99,111,115,0,18,
+97,110,103,108,101,0,59,122,0,0,0,0,58,99,111,115,0,18,97,110,103,108,101,0,59,119,0,0,0,0,0,0,0,1,
+0,9,0,116,97,110,0,1,0,0,9,97,110,103,108,101,0,0,0,1,8,58,115,105,110,0,18,97,110,103,108,101,0,0,
+0,58,99,111,115,0,18,97,110,103,108,101,0,0,0,49,0,0,1,0,10,0,116,97,110,0,1,0,0,10,97,110,103,108,
+101,0,0,0,1,8,58,118,101,99,50,0,58,116,97,110,0,18,97,110,103,108,101,0,59,120,0,0,0,0,58,116,97,
+110,0,18,97,110,103,108,101,0,59,121,0,0,0,0,0,0,0,1,0,11,0,116,97,110,0,1,0,0,11,97,110,103,108,
+101,0,0,0,1,8,58,118,101,99,51,0,58,116,97,110,0,18,97,110,103,108,101,0,59,120,0,0,0,0,58,116,97,
+110,0,18,97,110,103,108,101,0,59,121,0,0,0,0,58,116,97,110,0,18,97,110,103,108,101,0,59,122,0,0,0,
+0,0,0,0,1,0,12,0,116,97,110,0,1,0,0,12,97,110,103,108,101,0,0,0,1,8,58,118,101,99,52,0,58,116,97,
+110,0,18,97,110,103,108,101,0,59,120,0,0,0,0,58,116,97,110,0,18,97,110,103,108,101,0,59,121,0,0,0,
+0,58,116,97,110,0,18,97,110,103,108,101,0,59,122,0,0,0,0,58,116,97,110,0,18,97,110,103,108,101,0,
+59,119,0,0,0,0,0,0,0,1,0,9,0,97,115,105,110,0,1,0,0,9,120,0,0,0,1,3,2,0,9,1,121,0,0,0,4,102,108,
+111,97,116,95,97,114,99,115,105,110,101,0,18,121,0,0,18,120,0,0,0,8,18,121,0,0,0,1,0,10,0,97,115,
+105,110,0,1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,0,58,97,115,105,110,0,18,118,0,59,120,0,0,0,0,58,
+97,115,105,110,0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,97,115,105,110,0,1,0,0,11,118,0,0,0,1,8,58,
+118,101,99,51,0,58,97,115,105,110,0,18,118,0,59,120,0,0,0,0,58,97,115,105,110,0,18,118,0,59,121,0,
+0,0,0,58,97,115,105,110,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,97,115,105,110,0,1,0,0,12,118,0,0,
+0,1,8,58,118,101,99,52,0,58,97,115,105,110,0,18,118,0,59,120,0,0,0,0,58,97,115,105,110,0,18,118,0,
+59,121,0,0,0,0,58,97,115,105,110,0,18,118,0,59,122,0,0,0,0,58,97,115,105,110,0,18,118,0,59,119,0,0,
+0,0,0,0,0,1,0,9,0,97,99,111,115,0,1,0,0,9,120,0,0,0,1,8,17,49,0,53,55,48,56,0,0,58,97,115,105,110,
+0,18,120,0,0,0,47,0,0,1,0,10,0,97,99,111,115,0,1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,0,58,97,99,
+111,115,0,18,118,0,59,120,0,0,0,0,58,97,99,111,115,0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,97,99,
+111,115,0,1,0,0,11,118,0,0,0,1,8,58,118,101,99,51,0,58,97,99,111,115,0,18,118,0,59,120,0,0,0,0,58,
+97,99,111,115,0,18,118,0,59,121,0,0,0,0,58,97,99,111,115,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,
+97,99,111,115,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,58,97,99,111,115,0,18,118,0,59,120,0,0,0,
+0,58,97,99,111,115,0,18,118,0,59,121,0,0,0,0,58,97,99,111,115,0,18,118,0,59,122,0,0,0,0,58,97,99,
+111,115,0,18,118,0,59,119,0,0,0,0,0,0,0,1,0,9,0,97,116,97,110,0,1,0,0,9,121,95,111,118,101,114,95,
+120,0,0,0,1,3,2,0,9,1,122,0,0,0,4,102,108,111,97,116,95,97,114,99,116,97,110,0,18,122,0,0,18,121,
+95,111,118,101,114,95,120,0,0,0,8,18,122,0,0,0,1,0,10,0,97,116,97,110,0,1,0,0,10,121,95,111,118,
+101,114,95,120,0,0,0,1,8,58,118,101,99,50,0,58,97,116,97,110,0,18,121,95,111,118,101,114,95,120,0,
+59,120,0,0,0,0,58,97,116,97,110,0,18,121,95,111,118,101,114,95,120,0,59,121,0,0,0,0,0,0,0,1,0,11,0,
+97,116,97,110,0,1,0,0,11,121,95,111,118,101,114,95,120,0,0,0,1,8,58,118,101,99,51,0,58,97,116,97,
+110,0,18,121,95,111,118,101,114,95,120,0,59,120,0,0,0,0,58,97,116,97,110,0,18,121,95,111,118,101,
+114,95,120,0,59,121,0,0,0,0,58,97,116,97,110,0,18,121,95,111,118,101,114,95,120,0,59,122,0,0,0,0,0,
+0,0,1,0,12,0,97,116,97,110,0,1,0,0,12,121,95,111,118,101,114,95,120,0,0,0,1,8,58,118,101,99,52,0,
+58,97,116,97,110,0,18,121,95,111,118,101,114,95,120,0,59,120,0,0,0,0,58,97,116,97,110,0,18,121,95,
+111,118,101,114,95,120,0,59,121,0,0,0,0,58,97,116,97,110,0,18,121,95,111,118,101,114,95,120,0,59,
+122,0,0,0,0,58,97,116,97,110,0,18,121,95,111,118,101,114,95,120,0,59,119,0,0,0,0,0,0,0,1,0,9,0,97,
+116,97,110,0,1,0,0,9,121,0,0,1,0,0,9,120,0,0,0,1,3,2,0,9,1,122,0,2,58,97,116,97,110,0,18,121,0,18,
+120,0,49,0,0,0,0,10,18,120,0,17,48,0,48,0,0,40,0,2,10,18,121,0,17,48,0,48,0,0,40,0,8,18,122,0,17,
+51,0,49,52,49,53,57,51,0,0,47,0,9,14,0,8,18,122,0,17,51,0,49,52,49,53,57,51,0,0,46,0,0,9,14,0,8,18,
+122,0,0,0,1,0,10,0,97,116,97,110,0,1,0,0,10,117,0,0,1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,0,58,
+97,116,97,110,0,18,117,0,59,120,0,0,18,118,0,59,120,0,0,0,0,58,97,116,97,110,0,18,117,0,59,121,0,0,
+18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,97,116,97,110,0,1,0,0,11,117,0,0,1,0,0,11,118,0,0,0,1,8,58,
+118,101,99,51,0,58,97,116,97,110,0,18,117,0,59,120,0,0,18,118,0,59,120,0,0,0,0,58,97,116,97,110,0,
+18,117,0,59,121,0,0,18,118,0,59,121,0,0,0,0,58,97,116,97,110,0,18,117,0,59,122,0,0,18,118,0,59,122,
+0,0,0,0,0,0,0,1,0,12,0,97,116,97,110,0,1,0,0,12,117,0,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,
+58,97,116,97,110,0,18,117,0,59,120,0,0,18,118,0,59,120,0,0,0,0,58,97,116,97,110,0,18,117,0,59,121,
+0,0,18,118,0,59,121,0,0,0,0,58,97,116,97,110,0,18,117,0,59,122,0,0,18,118,0,59,122,0,0,0,0,58,97,
+116,97,110,0,18,117,0,59,119,0,0,18,118,0,59,119,0,0,0,0,0,0,0,1,0,9,0,112,111,119,0,1,0,0,9,120,0,
+0,1,0,0,9,121,0,0,0,1,3,2,0,9,1,112,0,0,0,4,102,108,111,97,116,95,112,111,119,101,114,0,18,112,0,0,
+18,120,0,0,18,121,0,0,0,8,18,112,0,0,0,1,0,10,0,112,111,119,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,
+1,8,58,118,101,99,50,0,58,112,111,119,0,18,118,0,59,120,0,0,18,117,0,59,120,0,0,0,0,58,112,111,119,
+0,18,118,0,59,121,0,0,18,117,0,59,121,0,0,0,0,0,0,0,1,0,11,0,112,111,119,0,1,0,0,11,118,0,0,1,0,0,
+11,117,0,0,0,1,8,58,118,101,99,51,0,58,112,111,119,0,18,118,0,59,120,0,0,18,117,0,59,120,0,0,0,0,
+58,112,111,119,0,18,118,0,59,121,0,0,18,117,0,59,121,0,0,0,0,58,112,111,119,0,18,118,0,59,122,0,0,
+18,117,0,59,122,0,0,0,0,0,0,0,1,0,12,0,112,111,119,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,58,
+118,101,99,52,0,58,112,111,119,0,18,118,0,59,120,0,0,18,117,0,59,120,0,0,0,0,58,112,111,119,0,18,
+118,0,59,121,0,0,18,117,0,59,121,0,0,0,0,58,112,111,119,0,18,118,0,59,122,0,0,18,117,0,59,122,0,0,
+0,0,58,112,111,119,0,18,118,0,59,119,0,0,18,117,0,59,119,0,0,0,0,0,0,0,1,0,9,0,101,120,112,0,1,0,0,
+9,120,0,0,0,1,8,58,112,111,119,0,17,50,0,55,49,56,50,56,49,56,51,0,0,0,18,120,0,0,0,0,0,1,0,10,0,
+101,120,112,0,1,0,0,10,118,0,0,0,1,8,58,112,111,119,0,58,118,101,99,50,0,17,50,0,55,49,56,50,56,49,
+56,51,0,0,0,0,0,18,118,0,0,0,0,0,1,0,11,0,101,120,112,0,1,0,0,11,118,0,0,0,1,8,58,112,111,119,0,58,
+118,101,99,51,0,17,50,0,55,49,56,50,56,49,56,51,0,0,0,0,0,18,118,0,0,0,0,0,1,0,12,0,101,120,112,0,
+1,0,0,12,118,0,0,0,1,8,58,112,111,119,0,58,118,101,99,52,0,17,50,0,55,49,56,50,56,49,56,51,0,0,0,0,
+0,18,118,0,0,0,0,0,1,0,9,0,108,111,103,50,0,1,0,0,9,120,0,0,0,1,3,2,0,9,1,121,0,0,0,4,102,108,111,
+97,116,95,108,111,103,50,0,18,121,0,0,18,120,0,0,0,8,18,121,0,0,0,1,0,10,0,108,111,103,50,0,1,0,0,
+10,118,0,0,0,1,8,58,118,101,99,50,0,58,108,111,103,50,0,18,118,0,59,120,0,0,0,0,58,108,111,103,50,
+0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,108,111,103,50,0,1,0,0,11,118,0,0,0,1,8,58,118,101,99,51,
+0,58,108,111,103,50,0,18,118,0,59,120,0,0,0,0,58,108,111,103,50,0,18,118,0,59,121,0,0,0,0,58,108,
+111,103,50,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,108,111,103,50,0,1,0,0,12,118,0,0,0,1,8,58,118,
+101,99,52,0,58,108,111,103,50,0,18,118,0,59,120,0,0,0,0,58,108,111,103,50,0,18,118,0,59,121,0,0,0,
+0,58,108,111,103,50,0,18,118,0,59,122,0,0,0,0,58,108,111,103,50,0,18,118,0,59,119,0,0,0,0,0,0,0,1,
+0,9,0,108,111,103,0,1,0,0,9,120,0,0,0,1,8,58,108,111,103,50,0,18,120,0,0,0,58,108,111,103,50,0,17,
+50,0,55,49,56,50,56,49,56,51,0,0,0,0,49,0,0,1,0,10,0,108,111,103,0,1,0,0,10,118,0,0,0,1,8,58,108,
+111,103,50,0,18,118,0,0,0,58,108,111,103,50,0,58,118,101,99,50,0,17,50,0,55,49,56,50,56,49,56,51,0,
+0,0,0,0,0,49,0,0,1,0,11,0,108,111,103,0,1,0,0,11,118,0,0,0,1,8,58,108,111,103,50,0,18,118,0,0,0,58,
+108,111,103,50,0,58,118,101,99,51,0,17,50,0,55,49,56,50,56,49,56,51,0,0,0,0,0,0,49,0,0,1,0,12,0,
+108,111,103,0,1,0,0,12,118,0,0,0,1,8,58,108,111,103,50,0,18,118,0,0,0,58,108,111,103,50,0,58,118,
+101,99,52,0,17,50,0,55,49,56,50,56,49,56,51,0,0,0,0,0,0,49,0,0,1,0,9,0,101,120,112,50,0,1,0,0,9,
+120,0,0,0,1,8,58,112,111,119,0,17,50,0,48,0,0,0,18,120,0,0,0,0,0,1,0,10,0,101,120,112,50,0,1,0,0,
+10,118,0,0,0,1,8,58,112,111,119,0,58,118,101,99,50,0,17,50,0,48,0,0,0,0,0,18,118,0,0,0,0,0,1,0,11,
+0,101,120,112,50,0,1,0,0,11,118,0,0,0,1,8,58,112,111,119,0,58,118,101,99,51,0,17,50,0,48,0,0,0,0,0,
+18,118,0,0,0,0,0,1,0,12,0,101,120,112,50,0,1,0,0,12,118,0,0,0,1,8,58,112,111,119,0,58,118,101,99,
+52,0,17,50,0,48,0,0,0,0,0,18,118,0,0,0,0,0,1,0,9,0,115,113,114,116,0,1,0,0,9,120,0,0,0,1,8,58,112,
+111,119,0,18,120,0,0,17,48,0,53,0,0,0,0,0,0,1,0,10,0,115,113,114,116,0,1,0,0,10,118,0,0,0,1,8,58,
+112,111,119,0,18,118,0,0,58,118,101,99,50,0,17,48,0,53,0,0,0,0,0,0,0,0,1,0,11,0,115,113,114,116,0,
+1,0,0,11,118,0,0,0,1,8,58,112,111,119,0,18,118,0,0,58,118,101,99,51,0,17,48,0,53,0,0,0,0,0,0,0,0,1,
+0,12,0,115,113,114,116,0,1,0,0,12,118,0,0,0,1,8,58,112,111,119,0,18,118,0,0,58,118,101,99,52,0,17,
+48,0,53,0,0,0,0,0,0,0,0,1,0,9,0,105,110,118,101,114,115,101,115,113,114,116,0,1,0,0,9,120,0,0,0,1,
+8,17,49,0,48,0,0,58,115,113,114,116,0,18,120,0,0,0,49,0,0,1,0,10,0,105,110,118,101,114,115,101,115,
+113,114,116,0,1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,0,17,49,0,48,0,0,0,0,58,115,113,114,116,0,18,
+118,0,0,0,49,0,0,1,0,11,0,105,110,118,101,114,115,101,115,113,114,116,0,1,0,0,11,118,0,0,0,1,8,58,
+118,101,99,51,0,17,49,0,48,0,0,0,0,58,115,113,114,116,0,18,118,0,0,0,49,0,0,1,0,12,0,105,110,118,
+101,114,115,101,115,113,114,116,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,17,49,0,48,0,0,0,0,58,
+115,113,114,116,0,18,118,0,0,0,49,0,0,1,0,9,0,97,98,115,0,1,0,0,9,120,0,0,0,1,8,18,120,0,17,48,0,
+48,0,0,43,18,120,0,18,120,0,54,31,0,0,1,0,10,0,97,98,115,0,1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,
+0,58,97,98,115,0,18,118,0,59,120,0,0,0,0,58,97,98,115,0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,97,
+98,115,0,1,0,0,11,118,0,0,0,1,8,58,118,101,99,51,0,58,97,98,115,0,18,118,0,59,120,0,0,0,0,58,97,98,
+115,0,18,118,0,59,121,0,0,0,0,58,97,98,115,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,97,98,115,0,1,
+0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,58,97,98,115,0,18,118,0,59,120,0,0,0,0,58,97,98,115,0,18,
+118,0,59,121,0,0,0,0,58,97,98,115,0,18,118,0,59,122,0,0,0,0,58,97,98,115,0,18,118,0,59,119,0,0,0,0,
+0,0,0,1,0,9,0,115,105,103,110,0,1,0,0,9,120,0,0,0,1,8,18,120,0,17,48,0,48,0,0,41,17,49,0,48,0,0,18,
+120,0,17,48,0,48,0,0,40,17,49,0,48,0,0,54,17,48,0,48,0,0,31,31,0,0,1,0,10,0,115,105,103,110,0,1,0,
+0,10,118,0,0,0,1,8,58,118,101,99,50,0,58,115,105,103,110,0,18,118,0,59,120,0,0,0,0,58,115,105,103,
+110,0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,115,105,103,110,0,1,0,0,11,118,0,0,0,1,8,58,118,101,
+99,51,0,58,115,105,103,110,0,18,118,0,59,120,0,0,0,0,58,115,105,103,110,0,18,118,0,59,121,0,0,0,0,
+58,115,105,103,110,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,115,105,103,110,0,1,0,0,12,118,0,0,0,1,
+8,58,118,101,99,52,0,58,115,105,103,110,0,18,118,0,59,120,0,0,0,0,58,115,105,103,110,0,18,118,0,59,
+121,0,0,0,0,58,115,105,103,110,0,18,118,0,59,122,0,0,0,0,58,115,105,103,110,0,18,118,0,59,119,0,0,
+0,0,0,0,0,1,0,9,0,102,108,111,111,114,0,1,0,0,9,120,0,0,0,1,3,2,0,9,1,121,0,0,0,4,102,108,111,97,
+116,95,102,108,111,111,114,0,18,121,0,0,18,120,0,0,0,8,18,121,0,0,0,1,0,10,0,102,108,111,111,114,0,
+1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,0,58,102,108,111,111,114,0,18,118,0,59,120,0,0,0,0,58,102,
+108,111,111,114,0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,102,108,111,111,114,0,1,0,0,11,118,0,0,0,
+1,8,58,118,101,99,51,0,58,102,108,111,111,114,0,18,118,0,59,120,0,0,0,0,58,102,108,111,111,114,0,
+18,118,0,59,121,0,0,0,0,58,102,108,111,111,114,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,102,108,
+111,111,114,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,58,102,108,111,111,114,0,18,118,0,59,120,0,
+0,0,0,58,102,108,111,111,114,0,18,118,0,59,121,0,0,0,0,58,102,108,111,111,114,0,18,118,0,59,122,0,
+0,0,0,58,102,108,111,111,114,0,18,118,0,59,119,0,0,0,0,0,0,0,1,0,9,0,99,101,105,108,0,1,0,0,9,120,
+0,0,0,1,3,2,0,9,1,121,0,0,0,4,102,108,111,97,116,95,99,101,105,108,0,18,121,0,0,18,120,0,0,0,8,18,
+121,0,0,0,1,0,10,0,99,101,105,108,0,1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,0,58,99,101,105,108,0,
+18,118,0,59,120,0,0,0,0,58,99,101,105,108,0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,99,101,105,108,
+0,1,0,0,11,118,0,0,0,1,8,58,118,101,99,51,0,58,99,101,105,108,0,18,118,0,59,120,0,0,0,0,58,99,101,
+105,108,0,18,118,0,59,121,0,0,0,0,58,99,101,105,108,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,99,
+101,105,108,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,58,99,101,105,108,0,18,118,0,59,120,0,0,0,
+0,58,99,101,105,108,0,18,118,0,59,121,0,0,0,0,58,99,101,105,108,0,18,118,0,59,122,0,0,0,0,58,99,
+101,105,108,0,18,118,0,59,119,0,0,0,0,0,0,0,1,0,9,0,102,114,97,99,116,0,1,0,0,9,120,0,0,0,1,8,18,
+120,0,58,102,108,111,111,114,0,18,120,0,0,0,47,0,0,1,0,10,0,102,114,97,99,116,0,1,0,0,10,118,0,0,0,
+1,8,18,118,0,58,102,108,111,111,114,0,18,118,0,0,0,47,0,0,1,0,11,0,102,114,97,99,116,0,1,0,0,11,
+118,0,0,0,1,8,18,118,0,58,102,108,111,111,114,0,18,118,0,0,0,47,0,0,1,0,12,0,102,114,97,99,116,0,1,
+0,0,12,118,0,0,0,1,8,18,118,0,58,102,108,111,111,114,0,18,118,0,0,0,47,0,0,1,0,9,0,109,111,100,0,1,
+0,0,9,120,0,0,1,0,0,9,121,0,0,0,1,8,18,120,0,18,121,0,58,102,108,111,111,114,0,18,120,0,18,121,0,
+49,0,0,48,47,0,0,1,0,10,0,109,111,100,0,1,0,0,10,118,0,0,1,0,0,9,117,0,0,0,1,8,18,118,0,18,117,0,
+58,102,108,111,111,114,0,18,118,0,18,117,0,49,0,0,48,47,0,0,1,0,11,0,109,111,100,0,1,0,0,11,118,0,
+0,1,0,0,9,117,0,0,0,1,8,18,118,0,18,117,0,58,102,108,111,111,114,0,18,118,0,18,117,0,49,0,0,48,47,
+0,0,1,0,12,0,109,111,100,0,1,0,0,12,118,0,0,1,0,0,9,117,0,0,0,1,8,18,118,0,18,117,0,58,102,108,111,
+111,114,0,18,118,0,18,117,0,49,0,0,48,47,0,0,1,0,10,0,109,111,100,0,1,0,0,10,118,0,0,1,0,0,10,117,
+0,0,0,1,8,18,118,0,18,117,0,58,102,108,111,111,114,0,18,118,0,18,117,0,49,0,0,48,47,0,0,1,0,11,0,
+109,111,100,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,18,118,0,18,117,0,58,102,108,111,111,114,0,
+18,118,0,18,117,0,49,0,0,48,47,0,0,1,0,12,0,109,111,100,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,
+18,118,0,18,117,0,58,102,108,111,111,114,0,18,118,0,18,117,0,49,0,0,48,47,0,0,1,0,9,0,109,105,110,
+0,1,0,0,9,120,0,0,1,0,0,9,121,0,0,0,1,8,18,120,0,18,121,0,40,18,120,0,18,121,0,31,0,0,1,0,10,0,109,
+105,110,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,1,8,58,118,101,99,50,0,58,109,105,110,0,18,118,0,59,
+120,0,0,18,117,0,59,120,0,0,0,0,58,109,105,110,0,18,118,0,59,121,0,0,18,117,0,59,121,0,0,0,0,0,0,0,
+1,0,11,0,109,105,110,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,118,101,99,51,0,58,109,105,110,0,
+18,118,0,59,120,0,0,18,117,0,59,120,0,0,0,0,58,109,105,110,0,18,118,0,59,121,0,0,18,117,0,59,121,0,
+0,0,0,58,109,105,110,0,18,118,0,59,122,0,0,18,117,0,59,122,0,0,0,0,0,0,0,1,0,12,0,109,105,110,0,1,
+0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,58,118,101,99,52,0,58,109,105,110,0,18,118,0,59,120,0,0,18,
+117,0,59,120,0,0,0,0,58,109,105,110,0,18,118,0,59,121,0,0,18,117,0,59,121,0,0,0,0,58,109,105,110,0,
+18,118,0,59,122,0,0,18,117,0,59,122,0,0,0,0,58,109,105,110,0,18,118,0,59,119,0,0,18,117,0,59,119,0,
+0,0,0,0,0,0,1,0,10,0,109,105,110,0,1,0,0,10,118,0,0,1,0,0,9,121,0,0,0,1,8,58,109,105,110,0,18,118,
+0,0,58,118,101,99,50,0,18,121,0,0,0,0,0,0,0,1,0,11,0,109,105,110,0,1,0,0,11,118,0,0,1,0,0,9,121,0,
+0,0,1,8,58,109,105,110,0,18,118,0,0,58,118,101,99,51,0,18,121,0,0,0,0,0,0,0,1,0,12,0,109,105,110,0,
+1,0,0,12,118,0,0,1,0,0,9,121,0,0,0,1,8,58,109,105,110,0,18,118,0,0,58,118,101,99,52,0,18,121,0,0,0,
+0,0,0,0,1,0,9,0,109,97,120,0,1,0,0,9,120,0,0,1,0,0,9,121,0,0,0,1,8,18,120,0,18,121,0,40,18,121,0,
+18,120,0,31,0,0,1,0,10,0,109,97,120,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,1,8,58,118,101,99,50,0,
+58,109,97,120,0,18,118,0,59,120,0,0,18,117,0,59,120,0,0,0,0,58,109,97,120,0,18,118,0,59,121,0,0,18,
+117,0,59,121,0,0,0,0,0,0,0,1,0,11,0,109,97,120,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,118,
+101,99,51,0,58,109,97,120,0,18,118,0,59,120,0,0,18,117,0,59,120,0,0,0,0,58,109,97,120,0,18,118,0,
+59,121,0,0,18,117,0,59,121,0,0,0,0,58,109,97,120,0,18,118,0,59,122,0,0,18,117,0,59,122,0,0,0,0,0,0,
+0,1,0,12,0,109,97,120,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,58,118,101,99,52,0,58,109,97,120,0,
+18,118,0,59,120,0,0,18,117,0,59,120,0,0,0,0,58,109,97,120,0,18,118,0,59,121,0,0,18,117,0,59,121,0,
+0,0,0,58,109,97,120,0,18,118,0,59,122,0,0,18,117,0,59,122,0,0,0,0,58,109,97,120,0,18,118,0,59,119,
+0,0,18,117,0,59,119,0,0,0,0,0,0,0,1,0,10,0,109,97,120,0,1,0,0,10,118,0,0,1,0,0,9,121,0,0,0,1,8,58,
+109,97,120,0,18,118,0,0,58,118,101,99,50,0,18,121,0,0,0,0,0,0,0,1,0,11,0,109,97,120,0,1,0,0,11,118,
+0,0,1,0,0,9,121,0,0,0,1,8,58,109,97,120,0,18,118,0,0,58,118,101,99,51,0,18,121,0,0,0,0,0,0,0,1,0,
+12,0,109,97,120,0,1,0,0,12,118,0,0,1,0,0,9,121,0,0,0,1,8,58,109,97,120,0,18,118,0,0,58,118,101,99,
+52,0,18,121,0,0,0,0,0,0,0,1,0,9,0,99,108,97,109,112,0,1,0,0,9,120,0,0,1,0,0,9,109,105,110,86,97,
+108,0,0,1,0,0,9,109,97,120,86,97,108,0,0,0,1,8,58,109,105,110,0,58,109,97,120,0,18,120,0,0,18,109,
+105,110,86,97,108,0,0,0,0,18,109,97,120,86,97,108,0,0,0,0,0,1,0,10,0,99,108,97,109,112,0,1,0,0,10,
+120,0,0,1,0,0,9,109,105,110,86,97,108,0,0,1,0,0,9,109,97,120,86,97,108,0,0,0,1,8,58,109,105,110,0,
+58,109,97,120,0,18,120,0,0,18,109,105,110,86,97,108,0,0,0,0,18,109,97,120,86,97,108,0,0,0,0,0,1,0,
+11,0,99,108,97,109,112,0,1,0,0,11,120,0,0,1,0,0,9,109,105,110,86,97,108,0,0,1,0,0,9,109,97,120,86,
+97,108,0,0,0,1,8,58,109,105,110,0,58,109,97,120,0,18,120,0,0,18,109,105,110,86,97,108,0,0,0,0,18,
+109,97,120,86,97,108,0,0,0,0,0,1,0,12,0,99,108,97,109,112,0,1,0,0,12,120,0,0,1,0,0,9,109,105,110,
+86,97,108,0,0,1,0,0,9,109,97,120,86,97,108,0,0,0,1,8,58,109,105,110,0,58,109,97,120,0,18,120,0,0,
+18,109,105,110,86,97,108,0,0,0,0,18,109,97,120,86,97,108,0,0,0,0,0,1,0,10,0,99,108,97,109,112,0,1,
+0,0,10,120,0,0,1,0,0,10,109,105,110,86,97,108,0,0,1,0,0,10,109,97,120,86,97,108,0,0,0,1,8,58,109,
+105,110,0,58,109,97,120,0,18,120,0,0,18,109,105,110,86,97,108,0,0,0,0,18,109,97,120,86,97,108,0,0,
+0,0,0,1,0,11,0,99,108,97,109,112,0,1,0,0,11,120,0,0,1,0,0,11,109,105,110,86,97,108,0,0,1,0,0,11,
+109,97,120,86,97,108,0,0,0,1,8,58,109,105,110,0,58,109,97,120,0,18,120,0,0,18,109,105,110,86,97,
+108,0,0,0,0,18,109,97,120,86,97,108,0,0,0,0,0,1,0,12,0,99,108,97,109,112,0,1,0,0,12,120,0,0,1,0,0,
+12,109,105,110,86,97,108,0,0,1,0,0,12,109,97,120,86,97,108,0,0,0,1,8,58,109,105,110,0,58,109,97,
+120,0,18,120,0,0,18,109,105,110,86,97,108,0,0,0,0,18,109,97,120,86,97,108,0,0,0,0,0,1,0,9,0,109,
+105,120,0,1,0,0,9,120,0,0,1,0,0,9,121,0,0,1,0,0,9,97,0,0,0,1,8,18,120,0,17,49,0,48,0,0,18,97,0,47,
+48,18,121,0,18,97,0,48,46,0,0,1,0,10,0,109,105,120,0,1,0,0,10,120,0,0,1,0,0,10,121,0,0,1,0,0,9,97,
+0,0,0,1,8,18,120,0,17,49,0,48,0,0,18,97,0,47,48,18,121,0,18,97,0,48,46,0,0,1,0,11,0,109,105,120,0,
+1,0,0,11,120,0,0,1,0,0,11,121,0,0,1,0,0,9,97,0,0,0,1,8,18,120,0,17,49,0,48,0,0,18,97,0,47,48,18,
+121,0,18,97,0,48,46,0,0,1,0,12,0,109,105,120,0,1,0,0,12,120,0,0,1,0,0,12,121,0,0,1,0,0,9,97,0,0,0,
+1,8,18,120,0,17,49,0,48,0,0,18,97,0,47,48,18,121,0,18,97,0,48,46,0,0,1,0,10,0,109,105,120,0,1,0,0,
+10,120,0,0,1,0,0,10,121,0,0,1,0,0,10,97,0,0,0,1,8,18,120,0,17,49,0,48,0,0,18,97,0,47,48,18,121,0,
+18,97,0,48,46,0,0,1,0,11,0,109,105,120,0,1,0,0,11,120,0,0,1,0,0,11,121,0,0,1,0,0,11,97,0,0,0,1,8,
+18,120,0,17,49,0,48,0,0,18,97,0,47,48,18,121,0,18,97,0,48,46,0,0,1,0,12,0,109,105,120,0,1,0,0,12,
+120,0,0,1,0,0,12,121,0,0,1,0,0,12,97,0,0,0,1,8,18,120,0,17,49,0,48,0,0,18,97,0,47,48,18,121,0,18,
+97,0,48,46,0,0,1,0,9,0,115,116,101,112,0,1,0,0,9,101,100,103,101,0,0,1,0,0,9,120,0,0,0,1,8,18,120,
+0,18,101,100,103,101,0,40,17,48,0,48,0,0,17,49,0,48,0,0,31,0,0,1,0,10,0,115,116,101,112,0,1,0,0,10,
+101,100,103,101,0,0,1,0,0,10,118,0,0,0,1,8,58,118,101,99,50,0,58,115,116,101,112,0,18,101,100,103,
+101,0,59,120,0,0,18,118,0,59,120,0,0,0,0,58,115,116,101,112,0,18,101,100,103,101,0,59,121,0,0,18,
+118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,115,116,101,112,0,1,0,0,11,101,100,103,101,0,0,1,0,0,11,118,0,
+0,0,1,8,58,118,101,99,51,0,58,115,116,101,112,0,18,101,100,103,101,0,59,120,0,0,18,118,0,59,120,0,
+0,0,0,58,115,116,101,112,0,18,101,100,103,101,0,59,121,0,0,18,118,0,59,121,0,0,0,0,58,115,116,101,
+112,0,18,101,100,103,101,0,59,122,0,0,18,118,0,59,122,0,0,0,0,0,0,0,1,0,12,0,115,116,101,112,0,1,0,
+0,12,101,100,103,101,0,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,58,115,116,101,112,0,18,101,100,
+103,101,0,59,120,0,0,18,118,0,59,120,0,0,0,0,58,115,116,101,112,0,18,101,100,103,101,0,59,121,0,0,
+18,118,0,59,121,0,0,0,0,58,115,116,101,112,0,18,101,100,103,101,0,59,122,0,0,18,118,0,59,122,0,0,0,
+0,58,115,116,101,112,0,18,101,100,103,101,0,59,119,0,0,18,118,0,59,119,0,0,0,0,0,0,0,1,0,10,0,115,
+116,101,112,0,1,0,0,9,101,100,103,101,0,0,1,0,0,10,118,0,0,0,1,8,58,115,116,101,112,0,58,118,101,
+99,50,0,18,101,100,103,101,0,0,0,0,18,118,0,0,0,0,0,1,0,11,0,115,116,101,112,0,1,0,0,9,101,100,103,
+101,0,0,1,0,0,11,118,0,0,0,1,8,58,115,116,101,112,0,58,118,101,99,51,0,18,101,100,103,101,0,0,0,0,
+18,118,0,0,0,0,0,1,0,12,0,115,116,101,112,0,1,0,0,9,101,100,103,101,0,0,1,0,0,12,118,0,0,0,1,8,58,
+115,116,101,112,0,58,118,101,99,52,0,18,101,100,103,101,0,0,0,0,18,118,0,0,0,0,0,1,0,9,0,115,109,
+111,111,116,104,115,116,101,112,0,1,0,0,9,101,100,103,101,48,0,0,1,0,0,9,101,100,103,101,49,0,0,1,
+0,0,9,120,0,0,0,1,3,2,0,9,1,116,0,2,58,99,108,97,109,112,0,18,120,0,18,101,100,103,101,48,0,47,18,
+101,100,103,101,49,0,18,101,100,103,101,48,0,47,49,0,17,48,0,48,0,0,0,17,49,0,48,0,0,0,0,0,0,8,18,
+116,0,18,116,0,48,17,51,0,48,0,0,17,50,0,48,0,0,18,116,0,48,47,48,0,0,1,0,10,0,115,109,111,111,116,
+104,115,116,101,112,0,1,0,0,10,101,100,103,101,48,0,0,1,0,0,10,101,100,103,101,49,0,0,1,0,0,10,118,
+0,0,0,1,8,58,118,101,99,50,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,
+59,120,0,0,18,101,100,103,101,49,0,59,120,0,0,18,118,0,59,120,0,0,0,0,58,115,109,111,111,116,104,
+115,116,101,112,0,18,101,100,103,101,48,0,59,121,0,0,18,101,100,103,101,49,0,59,121,0,0,18,118,0,
+59,121,0,0,0,0,0,0,0,1,0,11,0,115,109,111,111,116,104,115,116,101,112,0,1,0,0,11,101,100,103,101,
+48,0,0,1,0,0,11,101,100,103,101,49,0,0,1,0,0,11,118,0,0,0,1,8,58,118,101,99,51,0,58,115,109,111,
+111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,59,120,0,0,18,101,100,103,101,49,0,59,120,0,
+0,18,118,0,59,120,0,0,0,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,59,
+121,0,0,18,101,100,103,101,49,0,59,121,0,0,18,118,0,59,121,0,0,0,0,58,115,109,111,111,116,104,115,
+116,101,112,0,18,101,100,103,101,48,0,59,122,0,0,18,101,100,103,101,49,0,59,122,0,0,18,118,0,59,
+122,0,0,0,0,0,0,0,1,0,12,0,115,109,111,111,116,104,115,116,101,112,0,1,0,0,12,101,100,103,101,48,0,
+0,1,0,0,12,101,100,103,101,49,0,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,58,115,109,111,111,116,
+104,115,116,101,112,0,18,101,100,103,101,48,0,59,120,0,0,18,101,100,103,101,49,0,59,120,0,0,18,118,
+0,59,120,0,0,0,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,59,121,0,0,
+18,101,100,103,101,49,0,59,121,0,0,18,118,0,59,121,0,0,0,0,58,115,109,111,111,116,104,115,116,101,
+112,0,18,101,100,103,101,48,0,59,122,0,0,18,101,100,103,101,49,0,59,122,0,0,18,118,0,59,122,0,0,0,
+0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,59,119,0,0,18,101,100,103,
+101,49,0,59,119,0,0,18,118,0,59,119,0,0,0,0,0,0,0,1,0,10,0,115,109,111,111,116,104,115,116,101,112,
+0,1,0,0,9,101,100,103,101,48,0,0,1,0,0,9,101,100,103,101,49,0,0,1,0,0,10,118,0,0,0,1,8,58,118,101,
+99,50,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,0,18,101,100,103,101,
+49,0,0,18,118,0,59,120,0,0,0,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,
+0,0,18,101,100,103,101,49,0,0,18,118,0,59,121,0,0,0,0,0,0,0,1,0,11,0,115,109,111,111,116,104,115,
+116,101,112,0,1,0,0,9,101,100,103,101,48,0,0,1,0,0,9,101,100,103,101,49,0,0,1,0,0,11,118,0,0,0,1,8,
+58,118,101,99,51,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,0,18,101,
+100,103,101,49,0,0,18,118,0,59,120,0,0,0,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,
+103,101,48,0,0,18,101,100,103,101,49,0,0,18,118,0,59,121,0,0,0,0,58,115,109,111,111,116,104,115,
+116,101,112,0,18,101,100,103,101,48,0,0,18,101,100,103,101,49,0,0,18,118,0,59,122,0,0,0,0,0,0,0,1,
+0,12,0,115,109,111,111,116,104,115,116,101,112,0,1,0,0,9,101,100,103,101,48,0,0,1,0,0,9,101,100,
+103,101,49,0,0,1,0,0,12,118,0,0,0,1,8,58,118,101,99,52,0,58,115,109,111,111,116,104,115,116,101,
+112,0,18,101,100,103,101,48,0,0,18,101,100,103,101,49,0,0,18,118,0,59,120,0,0,0,0,58,115,109,111,
+111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,0,18,101,100,103,101,49,0,0,18,118,0,59,121,
+0,0,0,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,0,0,18,101,100,103,101,
+49,0,0,18,118,0,59,122,0,0,0,0,58,115,109,111,111,116,104,115,116,101,112,0,18,101,100,103,101,48,
+0,0,18,101,100,103,101,49,0,0,18,118,0,59,119,0,0,0,0,0,0,0,1,0,9,0,100,111,116,0,1,0,0,9,120,0,0,
+1,0,0,9,121,0,0,0,1,8,18,120,0,18,121,0,48,0,0,1,0,9,0,100,111,116,0,1,0,0,10,118,0,0,1,0,0,10,117,
+0,0,0,1,8,18,118,0,59,120,0,18,117,0,59,120,0,48,18,118,0,59,121,0,18,117,0,59,121,0,48,46,0,0,1,0,
+9,0,100,111,116,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,18,118,0,59,120,0,18,117,0,59,120,0,48,
+18,118,0,59,121,0,18,117,0,59,121,0,48,46,18,118,0,59,122,0,18,117,0,59,122,0,48,46,0,0,1,0,9,0,
+100,111,116,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,18,118,0,59,120,0,18,117,0,59,120,0,48,18,
+118,0,59,121,0,18,117,0,59,121,0,48,46,18,118,0,59,122,0,18,117,0,59,122,0,48,46,18,118,0,59,119,0,
+18,117,0,59,119,0,48,46,0,0,1,0,9,0,108,101,110,103,116,104,0,1,0,0,9,120,0,0,0,1,8,58,115,113,114,
+116,0,58,100,111,116,0,18,120,0,0,18,120,0,0,0,0,0,0,0,1,0,9,0,108,101,110,103,116,104,0,1,0,0,10,
+118,0,0,0,1,8,58,115,113,114,116,0,58,100,111,116,0,18,118,0,0,18,118,0,0,0,0,0,0,0,1,0,9,0,108,
+101,110,103,116,104,0,1,0,0,11,118,0,0,0,1,8,58,115,113,114,116,0,58,100,111,116,0,18,118,0,0,18,
+118,0,0,0,0,0,0,0,1,0,9,0,108,101,110,103,116,104,0,1,0,0,12,118,0,0,0,1,8,58,115,113,114,116,0,58,
+100,111,116,0,18,118,0,0,18,118,0,0,0,0,0,0,0,1,0,9,0,100,105,115,116,97,110,99,101,0,1,0,0,9,120,
+0,0,1,0,0,9,121,0,0,0,1,8,58,108,101,110,103,116,104,0,18,120,0,18,121,0,47,0,0,0,0,1,0,9,0,100,
+105,115,116,97,110,99,101,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,1,8,58,108,101,110,103,116,104,0,
+18,118,0,18,117,0,47,0,0,0,0,1,0,9,0,100,105,115,116,97,110,99,101,0,1,0,0,11,118,0,0,1,0,0,11,117,
+0,0,0,1,8,58,108,101,110,103,116,104,0,18,118,0,18,117,0,47,0,0,0,0,1,0,9,0,100,105,115,116,97,110,
+99,101,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,58,108,101,110,103,116,104,0,18,118,0,18,117,0,47,
+0,0,0,0,1,0,11,0,99,114,111,115,115,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,118,101,99,51,0,
+18,118,0,59,121,0,18,117,0,59,122,0,48,18,117,0,59,121,0,18,118,0,59,122,0,48,47,0,18,118,0,59,122,
+0,18,117,0,59,120,0,48,18,117,0,59,122,0,18,118,0,59,120,0,48,47,0,18,118,0,59,120,0,18,117,0,59,
+121,0,48,18,117,0,59,120,0,18,118,0,59,121,0,48,47,0,0,0,0,1,0,9,0,110,111,114,109,97,108,105,122,
+101,0,1,0,0,9,120,0,0,0,1,8,17,49,0,48,0,0,0,0,1,0,10,0,110,111,114,109,97,108,105,122,101,0,1,0,0,
+10,118,0,0,0,1,8,18,118,0,58,108,101,110,103,116,104,0,18,118,0,0,0,49,0,0,1,0,11,0,110,111,114,
+109,97,108,105,122,101,0,1,0,0,11,118,0,0,0,1,8,18,118,0,58,108,101,110,103,116,104,0,18,118,0,0,0,
+49,0,0,1,0,12,0,110,111,114,109,97,108,105,122,101,0,1,0,0,12,118,0,0,0,1,8,18,118,0,58,108,101,
+110,103,116,104,0,18,118,0,0,0,49,0,0,1,0,9,0,102,97,99,101,102,111,114,119,97,114,100,0,1,0,0,9,
+78,0,0,1,0,0,9,73,0,0,1,0,0,9,78,114,101,102,0,0,0,1,8,58,100,111,116,0,18,78,114,101,102,0,0,18,
+73,0,0,0,17,48,0,48,0,0,40,18,78,0,18,78,0,54,31,0,0,1,0,10,0,102,97,99,101,102,111,114,119,97,114,
+100,0,1,0,0,10,78,0,0,1,0,0,10,73,0,0,1,0,0,10,78,114,101,102,0,0,0,1,8,58,100,111,116,0,18,78,114,
+101,102,0,0,18,73,0,0,0,17,48,0,48,0,0,40,18,78,0,18,78,0,54,31,0,0,1,0,11,0,102,97,99,101,102,111,
+114,119,97,114,100,0,1,0,0,11,78,0,0,1,0,0,11,73,0,0,1,0,0,11,78,114,101,102,0,0,0,1,8,58,100,111,
+116,0,18,78,114,101,102,0,0,18,73,0,0,0,17,48,0,48,0,0,40,18,78,0,18,78,0,54,31,0,0,1,0,12,0,102,
+97,99,101,102,111,114,119,97,114,100,0,1,0,0,12,78,0,0,1,0,0,12,73,0,0,1,0,0,12,78,114,101,102,0,0,
+0,1,8,58,100,111,116,0,18,78,114,101,102,0,0,18,73,0,0,0,17,48,0,48,0,0,40,18,78,0,18,78,0,54,31,0,
+0,1,0,9,0,114,101,102,108,101,99,116,0,1,0,0,9,73,0,0,1,0,0,9,78,0,0,0,1,8,18,73,0,17,50,0,48,0,0,
+58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,18,78,0,48,47,0,0,1,0,10,0,114,101,102,108,101,99,116,0,
+1,0,0,10,73,0,0,1,0,0,10,78,0,0,0,1,8,18,73,0,17,50,0,48,0,0,58,100,111,116,0,18,78,0,0,18,73,0,0,
+0,48,18,78,0,48,47,0,0,1,0,11,0,114,101,102,108,101,99,116,0,1,0,0,11,73,0,0,1,0,0,11,78,0,0,0,1,8,
+18,73,0,17,50,0,48,0,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,18,78,0,48,47,0,0,1,0,12,0,114,
+101,102,108,101,99,116,0,1,0,0,12,73,0,0,1,0,0,12,78,0,0,0,1,8,18,73,0,17,50,0,48,0,0,58,100,111,
+116,0,18,78,0,0,18,73,0,0,0,48,18,78,0,48,47,0,0,1,0,9,0,114,101,102,114,97,99,116,0,1,0,0,9,73,0,
+0,1,0,0,9,78,0,0,1,0,0,9,101,116,97,0,0,0,1,3,2,0,9,1,107,0,2,17,49,0,48,0,0,18,101,116,97,0,18,
+101,116,97,0,48,17,49,0,48,0,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,58,100,111,116,0,18,78,0,0,
+18,73,0,0,0,48,47,48,47,0,0,10,18,107,0,17,48,0,48,0,0,40,0,8,17,48,0,48,0,0,0,9,14,0,8,18,101,116,
+97,0,18,73,0,48,18,101,116,97,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,58,115,113,114,116,0,18,
+107,0,0,0,46,18,78,0,48,47,0,0,1,0,10,0,114,101,102,114,97,99,116,0,1,0,0,10,73,0,0,1,0,0,10,78,0,
+0,1,0,0,9,101,116,97,0,0,0,1,3,2,0,9,1,107,0,2,17,49,0,48,0,0,18,101,116,97,0,18,101,116,97,0,48,
+17,49,0,48,0,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,47,
+48,47,0,0,10,18,107,0,17,48,0,48,0,0,40,0,8,17,48,0,48,0,0,0,9,14,0,8,18,101,116,97,0,18,73,0,48,
+18,101,116,97,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,58,115,113,114,116,0,18,107,0,0,0,46,18,
+78,0,48,47,0,0,1,0,11,0,114,101,102,114,97,99,116,0,1,0,0,11,73,0,0,1,0,0,11,78,0,0,1,0,0,9,101,
+116,97,0,0,0,1,3,2,0,9,1,107,0,2,17,49,0,48,0,0,18,101,116,97,0,18,101,116,97,0,48,17,49,0,48,0,0,
+58,100,111,116,0,18,78,0,0,18,73,0,0,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,47,48,47,0,0,10,
+18,107,0,17,48,0,48,0,0,40,0,8,17,48,0,48,0,0,0,9,14,0,8,18,101,116,97,0,18,73,0,48,18,101,116,97,
+0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,58,115,113,114,116,0,18,107,0,0,0,46,18,78,0,48,47,0,0,
+1,0,12,0,114,101,102,114,97,99,116,0,1,0,0,12,73,0,0,1,0,0,12,78,0,0,1,0,0,9,101,116,97,0,0,0,1,3,
+2,0,9,1,107,0,2,17,49,0,48,0,0,18,101,116,97,0,18,101,116,97,0,48,17,49,0,48,0,0,58,100,111,116,0,
+18,78,0,0,18,73,0,0,0,58,100,111,116,0,18,78,0,0,18,73,0,0,0,48,47,48,47,0,0,10,18,107,0,17,48,0,
+48,0,0,40,0,8,17,48,0,48,0,0,0,9,14,0,8,18,101,116,97,0,18,73,0,48,18,101,116,97,0,58,100,111,116,
+0,18,78,0,0,18,73,0,0,0,48,58,115,113,114,116,0,18,107,0,0,0,46,18,78,0,48,47,0,0,1,0,13,0,109,97,
+116,114,105,120,67,111,109,112,77,117,108,116,0,1,0,0,13,109,0,0,1,0,0,13,110,0,0,0,1,8,58,109,97,
+116,50,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,
+0,57,48,0,0,0,0,1,0,14,0,109,97,116,114,105,120,67,111,109,112,77,117,108,116,0,1,0,0,14,109,0,0,1,
+0,0,14,110,0,0,0,1,8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,48,0,18,109,0,
+16,10,49,0,57,18,110,0,16,10,49,0,57,48,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,48,0,0,0,0,
+1,0,15,0,109,97,116,114,105,120,67,111,109,112,77,117,108,116,0,1,0,0,15,109,0,0,1,0,0,15,110,0,0,
+0,1,8,58,109,97,116,52,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,
+18,110,0,16,10,49,0,57,48,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,48,0,18,109,0,16,10,51,0,
+57,18,110,0,16,10,51,0,57,48,0,0,0,0,1,0,2,0,108,101,115,115,84,104,97,110,0,1,0,0,10,118,0,0,1,0,
+0,10,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,40,0,18,118,0,59,121,
+0,18,117,0,59,121,0,40,0,0,0,0,1,0,3,0,108,101,115,115,84,104,97,110,0,1,0,0,11,118,0,0,1,0,0,11,
+117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,40,0,18,118,0,59,121,0,18,
+117,0,59,121,0,40,0,18,118,0,59,122,0,18,117,0,59,122,0,40,0,0,0,0,1,0,4,0,108,101,115,115,84,104,
+97,110,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,
+59,120,0,40,0,18,118,0,59,121,0,18,117,0,59,121,0,40,0,18,118,0,59,122,0,18,117,0,59,122,0,40,0,18,
+118,0,59,119,0,18,117,0,59,119,0,40,0,0,0,0,1,0,2,0,108,101,115,115,84,104,97,110,0,1,0,0,6,118,0,
+0,1,0,0,6,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,40,0,18,118,0,59,
+121,0,18,117,0,59,121,0,40,0,0,0,0,1,0,3,0,108,101,115,115,84,104,97,110,0,1,0,0,7,118,0,0,1,0,0,7,
+117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,40,0,18,118,0,59,121,0,18,
+117,0,59,121,0,40,0,18,118,0,59,122,0,18,117,0,59,122,0,40,0,0,0,0,1,0,4,0,108,101,115,115,84,104,
+97,110,0,1,0,0,8,118,0,0,1,0,0,8,117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,
+120,0,40,0,18,118,0,59,121,0,18,117,0,59,121,0,40,0,18,118,0,59,122,0,18,117,0,59,122,0,40,0,18,
+118,0,59,119,0,18,117,0,59,119,0,40,0,0,0,0,1,0,2,0,108,101,115,115,84,104,97,110,69,113,117,97,
+108,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,
+120,0,42,0,18,118,0,59,121,0,18,117,0,59,121,0,42,0,0,0,0,1,0,3,0,108,101,115,115,84,104,97,110,69,
+113,117,97,108,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,
+18,117,0,59,120,0,42,0,18,118,0,59,121,0,18,117,0,59,121,0,42,0,18,118,0,59,122,0,18,117,0,59,122,
+0,42,0,0,0,0,1,0,4,0,108,101,115,115,84,104,97,110,69,113,117,97,108,0,1,0,0,12,118,0,0,1,0,0,12,
+117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,42,0,18,118,0,59,121,0,18,
+117,0,59,121,0,42,0,18,118,0,59,122,0,18,117,0,59,122,0,42,0,18,118,0,59,119,0,18,117,0,59,119,0,
+42,0,0,0,0,1,0,2,0,108,101,115,115,84,104,97,110,69,113,117,97,108,0,1,0,0,6,118,0,0,1,0,0,6,117,0,
+0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,42,0,18,118,0,59,121,0,18,117,0,
+59,121,0,42,0,0,0,0,1,0,3,0,108,101,115,115,84,104,97,110,69,113,117,97,108,0,1,0,0,7,118,0,0,1,0,
+0,7,117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,42,0,18,118,0,59,121,0,
+18,117,0,59,121,0,42,0,18,118,0,59,122,0,18,117,0,59,122,0,42,0,0,0,0,1,0,4,0,108,101,115,115,84,
+104,97,110,69,113,117,97,108,0,1,0,0,8,118,0,0,1,0,0,8,117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,
+0,59,120,0,18,117,0,59,120,0,42,0,18,118,0,59,121,0,18,117,0,59,121,0,42,0,18,118,0,59,122,0,18,
+117,0,59,122,0,42,0,18,118,0,59,119,0,18,117,0,59,119,0,42,0,0,0,0,1,0,2,0,103,114,101,97,116,101,
+114,84,104,97,110,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,
+0,18,117,0,59,120,0,41,0,18,118,0,59,121,0,18,117,0,59,121,0,41,0,0,0,0,1,0,3,0,103,114,101,97,116,
+101,114,84,104,97,110,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,
+120,0,18,117,0,59,120,0,41,0,18,118,0,59,121,0,18,117,0,59,121,0,41,0,18,118,0,59,122,0,18,117,0,
+59,122,0,41,0,0,0,0,1,0,4,0,103,114,101,97,116,101,114,84,104,97,110,0,1,0,0,12,118,0,0,1,0,0,12,
+117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,41,0,18,118,0,59,121,0,18,
+117,0,59,121,0,41,0,18,118,0,59,122,0,18,117,0,59,122,0,41,0,18,118,0,59,119,0,18,117,0,59,119,0,
+41,0,0,0,0,1,0,2,0,103,114,101,97,116,101,114,84,104,97,110,0,1,0,0,6,118,0,0,1,0,0,6,117,0,0,0,1,
+8,58,98,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,41,0,18,118,0,59,121,0,18,117,0,59,121,
+0,41,0,0,0,0,1,0,3,0,103,114,101,97,116,101,114,84,104,97,110,0,1,0,0,7,118,0,0,1,0,0,7,117,0,0,0,
+1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,41,0,18,118,0,59,121,0,18,117,0,59,
+121,0,41,0,18,118,0,59,122,0,18,117,0,59,122,0,41,0,0,0,0,1,0,4,0,103,114,101,97,116,101,114,84,
+104,97,110,0,1,0,0,8,118,0,0,1,0,0,8,117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,
+0,59,120,0,41,0,18,118,0,59,121,0,18,117,0,59,121,0,41,0,18,118,0,59,122,0,18,117,0,59,122,0,41,0,
+18,118,0,59,119,0,18,117,0,59,119,0,41,0,0,0,0,1,0,2,0,103,114,101,97,116,101,114,84,104,97,110,69,
+113,117,97,108,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,
+18,117,0,59,120,0,43,0,18,118,0,59,121,0,18,117,0,59,121,0,43,0,0,0,0,1,0,3,0,103,114,101,97,116,
+101,114,84,104,97,110,69,113,117,97,108,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,98,118,101,99,
+51,0,18,118,0,59,120,0,18,117,0,59,120,0,43,0,18,118,0,59,121,0,18,117,0,59,121,0,43,0,18,118,0,59,
+122,0,18,117,0,59,122,0,43,0,0,0,0,1,0,4,0,103,114,101,97,116,101,114,84,104,97,110,69,113,117,97,
+108,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,
+120,0,43,0,18,118,0,59,121,0,18,117,0,59,121,0,43,0,18,118,0,59,122,0,18,117,0,59,122,0,43,0,18,
+118,0,59,119,0,18,117,0,59,119,0,43,0,0,0,0,1,0,2,0,103,114,101,97,116,101,114,84,104,97,110,69,
+113,117,97,108,0,1,0,0,6,118,0,0,1,0,0,6,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,18,
+117,0,59,120,0,43,0,18,118,0,59,121,0,18,117,0,59,121,0,43,0,0,0,0,1,0,3,0,103,114,101,97,116,101,
+114,84,104,97,110,69,113,117,97,108,0,1,0,0,7,118,0,0,1,0,0,7,117,0,0,0,1,8,58,98,118,101,99,51,0,
+18,118,0,59,120,0,18,117,0,59,120,0,43,0,18,118,0,59,121,0,18,117,0,59,121,0,43,0,18,118,0,59,122,
+0,18,117,0,59,122,0,43,0,0,0,0,1,0,4,0,103,114,101,97,116,101,114,84,104,97,110,69,113,117,97,108,
+0,1,0,0,8,118,0,0,1,0,0,8,117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,
+43,0,18,118,0,59,121,0,18,117,0,59,121,0,43,0,18,118,0,59,122,0,18,117,0,59,122,0,43,0,18,118,0,59,
+119,0,18,117,0,59,119,0,43,0,0,0,0,1,0,2,0,101,113,117,97,108,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,
+0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,38,0,18,118,0,59,121,0,18,117,0,59,
+121,0,38,0,0,0,0,1,0,3,0,101,113,117,97,108,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,98,118,
+101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,38,0,18,118,0,59,121,0,18,117,0,59,121,0,38,0,18,
+118,0,59,122,0,18,117,0,59,122,0,38,0,0,0,0,1,0,4,0,101,113,117,97,108,0,1,0,0,12,118,0,0,1,0,0,12,
+117,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,38,0,18,118,0,59,121,0,18,
+117,0,59,121,0,38,0,18,118,0,59,122,0,18,117,0,59,122,0,38,0,18,118,0,59,119,0,18,117,0,59,119,0,
+38,0,0,0,0,1,0,2,0,101,113,117,97,108,0,1,0,0,6,118,0,0,1,0,0,6,117,0,0,0,1,8,58,98,118,101,99,50,
+0,18,118,0,59,120,0,18,117,0,59,120,0,38,0,18,118,0,59,121,0,18,117,0,59,121,0,38,0,0,0,0,1,0,3,0,
+101,113,117,97,108,0,1,0,0,7,118,0,0,1,0,0,7,117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,
+18,117,0,59,120,0,38,0,18,118,0,59,121,0,18,117,0,59,121,0,38,0,18,118,0,59,122,0,18,117,0,59,122,
+0,38,0,0,0,0,1,0,4,0,101,113,117,97,108,0,1,0,0,8,118,0,0,1,0,0,8,117,0,0,0,1,8,58,98,118,101,99,
+52,0,18,118,0,59,120,0,18,117,0,59,120,0,38,0,18,118,0,59,121,0,18,117,0,59,121,0,38,0,18,118,0,59,
+122,0,18,117,0,59,122,0,38,0,18,118,0,59,119,0,18,117,0,59,119,0,38,0,0,0,0,1,0,2,0,110,111,116,69,
+113,117,97,108,0,1,0,0,10,118,0,0,1,0,0,10,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,0,59,120,0,
+18,117,0,59,120,0,39,0,18,118,0,59,121,0,18,117,0,59,121,0,39,0,0,0,0,1,0,3,0,110,111,116,69,113,
+117,97,108,0,1,0,0,11,118,0,0,1,0,0,11,117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,18,
+117,0,59,120,0,39,0,18,118,0,59,121,0,18,117,0,59,121,0,39,0,18,118,0,59,122,0,18,117,0,59,122,0,
+39,0,0,0,0,1,0,4,0,110,111,116,69,113,117,97,108,0,1,0,0,12,118,0,0,1,0,0,12,117,0,0,0,1,8,58,98,
+118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,39,0,18,118,0,59,121,0,18,117,0,59,121,0,39,0,
+18,118,0,59,122,0,18,117,0,59,122,0,39,0,18,118,0,59,119,0,18,117,0,59,119,0,39,0,0,0,0,1,0,2,0,
+110,111,116,69,113,117,97,108,0,1,0,0,6,118,0,0,1,0,0,6,117,0,0,0,1,8,58,98,118,101,99,50,0,18,118,
+0,59,120,0,18,117,0,59,120,0,39,0,18,118,0,59,121,0,18,117,0,59,121,0,39,0,0,0,0,1,0,3,0,110,111,
+116,69,113,117,97,108,0,1,0,0,7,118,0,0,1,0,0,7,117,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,
+120,0,18,117,0,59,120,0,39,0,18,118,0,59,121,0,18,117,0,59,121,0,39,0,18,118,0,59,122,0,18,117,0,
+59,122,0,39,0,0,0,0,1,0,4,0,110,111,116,69,113,117,97,108,0,1,0,0,8,118,0,0,1,0,0,8,117,0,0,0,1,8,
+58,98,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,39,0,18,118,0,59,121,0,18,117,0,59,121,0,
+39,0,18,118,0,59,122,0,18,117,0,59,122,0,39,0,18,118,0,59,119,0,18,117,0,59,119,0,39,0,0,0,0,1,0,1,
+0,97,110,121,0,1,0,0,2,118,0,0,0,1,8,18,118,0,59,120,0,18,118,0,59,121,0,32,0,0,1,0,1,0,97,110,121,
+0,1,0,0,3,118,0,0,0,1,8,18,118,0,59,120,0,18,118,0,59,121,0,32,18,118,0,59,122,0,32,0,0,1,0,1,0,97,
+110,121,0,1,0,0,4,118,0,0,0,1,8,18,118,0,59,120,0,18,118,0,59,121,0,32,18,118,0,59,122,0,32,18,118,
+0,59,119,0,32,0,0,1,0,1,0,97,108,108,0,1,0,0,2,118,0,0,0,1,8,18,118,0,59,120,0,18,118,0,59,121,0,
+34,0,0,1,0,1,0,97,108,108,0,1,0,0,3,118,0,0,0,1,8,18,118,0,59,120,0,18,118,0,59,121,0,34,18,118,0,
+59,122,0,34,0,0,1,0,1,0,97,108,108,0,1,0,0,4,118,0,0,0,1,8,18,118,0,59,120,0,18,118,0,59,121,0,34,
+18,118,0,59,122,0,34,18,118,0,59,119,0,34,0,0,1,0,2,0,110,111,116,0,1,0,0,2,118,0,0,0,1,8,58,98,
+118,101,99,50,0,18,118,0,59,120,0,56,0,18,118,0,59,121,0,56,0,0,0,0,1,0,3,0,110,111,116,0,1,0,0,3,
+118,0,0,0,1,8,58,98,118,101,99,51,0,18,118,0,59,120,0,56,0,18,118,0,59,121,0,56,0,18,118,0,59,122,
+0,56,0,0,0,0,1,0,4,0,110,111,116,0,1,0,0,4,118,0,0,0,1,8,58,98,118,101,99,52,0,18,118,0,59,120,0,
+56,0,18,118,0,59,121,0,56,0,18,118,0,59,122,0,56,0,18,118,0,59,119,0,56,0,0,0,0,1,0,12,0,116,101,
+120,116,117,114,101,49,68,0,1,0,0,16,115,97,109,112,108,101,114,0,0,1,0,0,9,99,111,111,114,100,0,0,
+0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,52,95,116,101,120,49,100,0,18,116,101,120,
+101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,17,48,0,48,0,0,0,0,8,18,
+116,101,120,101,108,0,0,0,1,0,12,0,116,101,120,116,117,114,101,49,68,80,114,111,106,0,1,0,0,16,115,
+97,109,112,108,101,114,0,0,1,0,0,10,99,111,111,114,100,0,0,0,1,8,58,116,101,120,116,117,114,101,49,
+68,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,
+116,0,49,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,49,68,80,114,111,106,0,1,0,0,16,115,97,109,
+112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,0,1,8,58,116,101,120,116,117,114,101,49,68,0,
+18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,113,
+0,49,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,50,68,0,1,0,0,17,115,97,109,112,108,101,114,0,0,
+1,0,0,10,99,111,111,114,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,52,95,116,
+101,120,50,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,
+100,0,0,17,48,0,48,0,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,116,101,120,116,117,114,101,50,
+68,80,114,111,106,0,1,0,0,17,115,97,109,112,108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,0,1,8,
+58,116,101,120,116,117,114,101,50,68,0,18,115,97,109,112,108,101,114,0,0,58,118,101,99,50,0,18,99,
+111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,112,0,49,0,18,99,111,111,114,100,0,59,116,0,
+18,99,111,111,114,100,0,59,112,0,49,0,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,50,68,80,114,
+111,106,0,1,0,0,17,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,0,1,8,58,116,101,
+120,116,117,114,101,50,68,0,18,115,97,109,112,108,101,114,0,0,58,118,101,99,50,0,18,99,111,111,114,
+100,0,59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,116,0,18,99,111,
+111,114,100,0,59,113,0,49,0,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,51,68,0,1,0,0,18,115,97,
+109,112,108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,
+118,101,99,52,95,116,101,120,51,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,
+18,99,111,111,114,100,0,0,17,48,0,48,0,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,116,101,120,
+116,117,114,101,51,68,80,114,111,106,0,1,0,0,18,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,
+114,100,0,0,0,1,8,58,116,101,120,116,117,114,101,51,68,0,18,115,97,109,112,108,101,114,0,0,58,118,
+101,99,51,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,
+114,100,0,59,116,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,112,0,18,99,
+111,111,114,100,0,59,113,0,49,0,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,67,117,98,101,0,1,0,
+0,19,115,97,109,112,108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,0,1,3,2,0,12,1,116,101,120,101,
+108,0,0,0,4,118,101,99,52,95,116,101,120,99,117,98,101,0,18,116,101,120,101,108,0,0,18,115,97,109,
+112,108,101,114,0,0,18,99,111,111,114,100,0,0,17,48,0,48,0,0,0,0,8,18,116,101,120,101,108,0,0,0,1,
+0,12,0,115,104,97,100,111,119,49,68,0,1,0,0,20,115,97,109,112,108,101,114,0,0,1,0,0,11,99,111,111,
+114,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,52,95,115,104,97,100,49,100,0,18,
+116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,17,48,0,48,0,0,
+0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,115,104,97,100,111,119,49,68,80,114,111,106,0,1,0,0,20,
+115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,0,1,8,58,115,104,97,100,111,119,49,
+68,0,18,115,97,109,112,108,101,114,0,0,58,118,101,99,51,0,18,99,111,111,114,100,0,59,115,0,18,99,
+111,111,114,100,0,59,113,0,49,0,17,48,0,48,0,0,0,18,99,111,111,114,100,0,59,112,0,18,99,111,111,
+114,100,0,59,113,0,49,0,0,0,0,0,0,1,0,12,0,115,104,97,100,111,119,50,68,0,1,0,0,21,115,97,109,112,
+108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,
+99,52,95,115,104,97,100,50,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,
+99,111,111,114,100,0,0,17,48,0,48,0,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,115,104,97,100,
+111,119,50,68,80,114,111,106,0,1,0,0,21,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,
+0,0,0,1,8,58,115,104,97,100,111,119,50,68,0,18,115,97,109,112,108,101,114,0,0,58,118,101,99,51,0,
+18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,
+116,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,112,0,18,99,111,111,114,100,
+0,59,113,0,49,0,0,0,0,0,0,1,0,9,0,110,111,105,115,101,49,0,1,0,0,9,120,0,0,0,1,3,2,0,9,1,97,0,0,0,
+4,102,108,111,97,116,95,110,111,105,115,101,49,0,18,97,0,0,18,120,0,0,0,8,18,97,0,0,0,1,0,9,0,110,
+111,105,115,101,49,0,1,0,0,10,120,0,0,0,1,3,2,0,9,1,97,0,0,0,4,102,108,111,97,116,95,110,111,105,
+115,101,50,0,18,97,0,0,18,120,0,0,0,8,18,97,0,0,0,1,0,9,0,110,111,105,115,101,49,0,1,0,0,11,120,0,
+0,0,1,3,2,0,9,1,97,0,0,0,4,102,108,111,97,116,95,110,111,105,115,101,51,0,18,97,0,0,18,120,0,0,0,8,
+18,97,0,0,0,1,0,9,0,110,111,105,115,101,49,0,1,0,0,12,120,0,0,0,1,3,2,0,9,1,97,0,0,0,4,102,108,111,
+97,116,95,110,111,105,115,101,52,0,18,97,0,0,18,120,0,0,0,8,18,97,0,0,0,1,0,10,0,110,111,105,115,
+101,50,0,1,0,0,9,120,0,0,0,1,8,58,118,101,99,50,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,
+110,111,105,115,101,49,0,18,120,0,17,49,57,0,51,52,0,0,46,0,0,0,0,0,0,1,0,10,0,110,111,105,115,101,
+50,0,1,0,0,10,120,0,0,0,1,8,58,118,101,99,50,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,110,
+111,105,115,101,49,0,18,120,0,58,118,101,99,50,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,0,46,0,
+0,0,0,0,0,1,0,10,0,110,111,105,115,101,50,0,1,0,0,11,120,0,0,0,1,8,58,118,101,99,50,0,58,110,111,
+105,115,101,49,0,18,120,0,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,51,0,17,49,57,0,
+51,52,0,0,0,17,55,0,54,54,0,0,0,17,51,0,50,51,0,0,0,0,46,0,0,0,0,0,0,1,0,10,0,110,111,105,115,101,
+50,0,1,0,0,12,120,0,0,0,1,8,58,118,101,99,50,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,110,
+111,105,115,101,49,0,18,120,0,58,118,101,99,52,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,17,51,
+0,50,51,0,0,0,17,50,0,55,55,0,0,0,0,46,0,0,0,0,0,0,1,0,11,0,110,111,105,115,101,51,0,1,0,0,9,120,0,
+0,0,1,8,58,118,101,99,51,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,110,111,105,115,101,49,0,
+18,120,0,17,49,57,0,51,52,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,17,53,0,52,55,0,0,46,0,
+0,0,0,0,0,1,0,11,0,110,111,105,115,101,51,0,1,0,0,10,120,0,0,0,1,8,58,118,101,99,51,0,58,110,111,
+105,115,101,49,0,18,120,0,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,50,0,17,49,57,0,
+51,52,0,0,0,17,55,0,54,54,0,0,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,50,0,
+17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,0,46,0,0,0,0,0,0,1,0,11,0,110,111,105,115,101,51,0,1,0,
+0,11,120,0,0,0,1,8,58,118,101,99,51,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,110,111,105,
+115,101,49,0,18,120,0,58,118,101,99,51,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,17,51,0,50,51,
+0,0,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,51,0,17,53,0,52,55,0,0,0,17,49,
+55,0,56,53,0,0,0,17,49,49,0,48,52,0,0,0,0,46,0,0,0,0,0,0,1,0,11,0,110,111,105,115,101,51,0,1,0,0,
+12,120,0,0,0,1,8,58,118,101,99,51,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,110,111,105,115,
+101,49,0,18,120,0,58,118,101,99,52,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,17,51,0,50,51,0,0,
+0,17,50,0,55,55,0,0,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,52,0,17,53,0,
+52,55,0,0,0,17,49,55,0,56,53,0,0,0,17,49,49,0,48,52,0,0,0,17,49,51,0,49,57,0,0,0,0,46,0,0,0,0,0,0,
+1,0,12,0,110,111,105,115,101,52,0,1,0,0,9,120,0,0,0,1,8,58,118,101,99,52,0,58,110,111,105,115,101,
+49,0,18,120,0,0,0,0,58,110,111,105,115,101,49,0,18,120,0,17,49,57,0,51,52,0,0,46,0,0,0,58,110,111,
+105,115,101,49,0,18,120,0,17,53,0,52,55,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,17,50,51,
+0,53,52,0,0,46,0,0,0,0,0,0,1,0,12,0,110,111,105,115,101,52,0,1,0,0,10,120,0,0,0,1,8,58,118,101,99,
+52,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,
+50,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,
+118,101,99,50,0,17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,0,46,0,0,0,58,110,111,105,115,101,49,0,
+18,120,0,58,118,101,99,50,0,17,50,51,0,53,52,0,0,0,17,50,57,0,49,49,0,0,0,0,46,0,0,0,0,0,0,1,0,12,
+0,110,111,105,115,101,52,0,1,0,0,11,120,0,0,0,1,8,58,118,101,99,52,0,58,110,111,105,115,101,49,0,
+18,120,0,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,51,0,17,49,57,0,51,52,0,0,0,17,
+55,0,54,54,0,0,0,17,51,0,50,51,0,0,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,
+51,0,17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,17,49,49,0,48,52,0,0,0,0,46,0,0,0,58,110,111,105,
+115,101,49,0,18,120,0,58,118,101,99,51,0,17,50,51,0,53,52,0,0,0,17,50,57,0,49,49,0,0,0,17,51,49,0,
+57,49,0,0,0,0,46,0,0,0,0,0,0,1,0,12,0,110,111,105,115,101,52,0,1,0,0,12,120,0,0,0,1,8,58,118,101,
+99,52,0,58,110,111,105,115,101,49,0,18,120,0,0,0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,
+99,52,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,17,51,0,50,51,0,0,0,17,50,0,55,55,0,0,0,0,46,0,
+0,0,58,110,111,105,115,101,49,0,18,120,0,58,118,101,99,52,0,17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,
+0,0,17,49,49,0,48,52,0,0,0,17,49,51,0,49,57,0,0,0,0,46,0,0,0,58,110,111,105,115,101,49,0,18,120,0,
+58,118,101,99,52,0,17,50,51,0,53,52,0,0,0,17,50,57,0,49,49,0,0,0,17,51,49,0,57,49,0,0,0,17,51,55,0,
+52,56,0,0,0,0,46,0,0,0,0,0,0,0
diff --git a/src/mesa/shader/slang/library/slang_core_gc.h b/src/mesa/shader/slang/library/slang_core_gc.h
new file mode 100644
index 00000000000..a7aaa317fa7
--- /dev/null
+++ b/src/mesa/shader/slang/library/slang_core_gc.h
@@ -0,0 +1,545 @@
+
+/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */
+/* slang_core.gc */
+
+3,1,0,5,1,1,1,0,9,102,0,0,0,1,3,2,0,5,1,105,0,0,0,4,102,108,111,97,116,95,116,111,95,105,110,116,0,
+18,105,0,0,18,102,0,0,0,8,18,105,0,0,0,1,0,1,1,1,1,0,5,105,0,0,0,1,8,18,105,0,16,8,48,0,39,0,0,1,0,
+1,1,1,1,0,9,102,0,0,0,1,8,18,102,0,17,48,0,48,0,0,39,0,0,1,0,5,1,1,1,0,1,98,0,0,0,1,8,18,98,0,16,
+10,49,0,16,8,48,0,31,0,0,1,0,9,1,1,1,0,1,98,0,0,0,1,8,18,98,0,17,49,0,48,0,0,17,48,0,48,0,0,31,0,0,
+1,0,9,1,1,1,0,5,105,0,0,0,1,3,2,0,9,1,102,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,116,0,
+18,102,0,0,18,105,0,0,0,8,18,102,0,0,0,1,0,1,1,1,1,0,1,98,0,0,0,1,8,18,98,0,0,0,1,0,5,1,1,1,0,5,
+105,0,0,0,1,8,18,105,0,0,0,1,0,9,1,1,1,0,9,102,0,0,0,1,8,18,102,0,0,0,1,0,10,1,1,1,0,9,102,0,0,0,1,
+8,58,118,101,99,50,0,18,102,0,0,18,102,0,0,0,0,0,1,0,10,1,1,1,0,5,105,0,0,0,1,3,2,0,9,1,120,0,0,0,
+4,105,110,116,95,116,111,95,102,108,111,97,116,0,18,120,0,0,18,105,0,0,0,8,58,118,101,99,50,0,18,
+120,0,0,0,0,0,1,0,10,1,1,1,0,1,98,0,0,0,1,8,58,118,101,99,50,0,18,98,0,17,49,0,48,0,0,17,48,0,48,0,
+0,31,0,0,0,0,1,0,11,1,1,1,0,9,102,0,0,0,1,8,58,118,101,99,51,0,18,102,0,0,18,102,0,0,18,102,0,0,0,
+0,0,1,0,11,1,1,1,0,5,105,0,0,0,1,3,2,0,9,1,120,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,
+116,0,18,120,0,0,18,105,0,0,0,8,58,118,101,99,51,0,18,120,0,0,0,0,0,1,0,11,1,1,1,0,1,98,0,0,0,1,8,
+58,118,101,99,51,0,18,98,0,17,49,0,48,0,0,17,48,0,48,0,0,31,0,0,0,0,1,0,12,1,1,1,0,9,102,0,0,0,1,8,
+58,118,101,99,52,0,18,102,0,0,18,102,0,0,18,102,0,0,18,102,0,0,0,0,0,1,0,12,1,1,1,0,5,105,0,0,0,1,
+3,2,0,9,1,120,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,116,0,18,120,0,0,18,105,0,0,0,8,58,
+118,101,99,52,0,18,120,0,0,0,0,0,1,0,12,1,1,1,0,1,98,0,0,0,1,8,58,118,101,99,52,0,18,98,0,17,49,0,
+48,0,0,17,48,0,48,0,0,31,0,0,0,0,1,0,6,1,1,1,0,5,105,0,0,0,1,8,58,105,118,101,99,50,0,18,105,0,0,
+18,105,0,0,0,0,0,1,0,6,1,1,1,0,9,102,0,0,0,1,8,58,105,118,101,99,50,0,58,105,110,116,0,18,102,0,0,
+0,0,0,0,0,1,0,6,1,1,1,0,1,98,0,0,0,1,8,58,105,118,101,99,50,0,58,105,110,116,0,18,98,0,0,0,0,0,0,0,
+1,0,7,1,1,1,0,5,105,0,0,0,1,8,58,105,118,101,99,51,0,18,105,0,0,18,105,0,0,18,105,0,0,0,0,0,1,0,7,
+1,1,1,0,9,102,0,0,0,1,8,58,105,118,101,99,51,0,58,105,110,116,0,18,102,0,0,0,0,0,0,0,1,0,7,1,1,1,0,
+1,98,0,0,0,1,8,58,105,118,101,99,51,0,58,105,110,116,0,18,98,0,0,0,0,0,0,0,1,0,8,1,1,1,0,5,105,0,0,
+0,1,8,58,105,118,101,99,52,0,18,105,0,0,18,105,0,0,18,105,0,0,18,105,0,0,0,0,0,1,0,8,1,1,1,0,9,102,
+0,0,0,1,8,58,105,118,101,99,52,0,58,105,110,116,0,18,102,0,0,0,0,0,0,0,1,0,8,1,1,1,0,1,98,0,0,0,1,
+8,58,105,118,101,99,52,0,58,105,110,116,0,18,98,0,0,0,0,0,0,0,1,0,2,1,1,1,0,1,98,0,0,0,1,8,58,98,
+118,101,99,50,0,18,98,0,0,18,98,0,0,0,0,0,1,0,2,1,1,1,0,9,102,0,0,0,1,8,58,98,118,101,99,50,0,58,
+98,111,111,108,0,18,102,0,0,0,0,0,0,0,1,0,2,1,1,1,0,5,105,0,0,0,1,8,58,98,118,101,99,50,0,58,98,
+111,111,108,0,18,105,0,0,0,0,0,0,0,1,0,3,1,1,1,0,1,98,0,0,0,1,8,58,98,118,101,99,51,0,18,98,0,0,18,
+98,0,0,18,98,0,0,0,0,0,1,0,3,1,1,1,0,9,102,0,0,0,1,8,58,98,118,101,99,51,0,58,98,111,111,108,0,18,
+102,0,0,0,0,0,0,0,1,0,3,1,1,1,0,5,105,0,0,0,1,8,58,98,118,101,99,51,0,58,98,111,111,108,0,18,105,0,
+0,0,0,0,0,0,1,0,4,1,1,1,0,1,98,0,0,0,1,8,58,98,118,101,99,52,0,18,98,0,0,18,98,0,0,18,98,0,0,18,98,
+0,0,0,0,0,1,0,4,1,1,1,0,9,102,0,0,0,1,8,58,98,118,101,99,52,0,58,98,111,111,108,0,18,102,0,0,0,0,0,
+0,0,1,0,4,1,1,1,0,5,105,0,0,0,1,8,58,98,118,101,99,52,0,58,98,111,111,108,0,18,105,0,0,0,0,0,0,0,1,
+0,13,1,1,1,0,9,102,0,0,0,1,8,58,109,97,116,50,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,
+102,0,0,0,0,0,1,0,13,1,1,1,0,5,105,0,0,0,1,3,2,0,9,1,120,0,0,0,4,105,110,116,95,116,111,95,102,108,
+111,97,116,0,18,120,0,0,18,105,0,0,0,8,58,109,97,116,50,0,18,120,0,0,0,0,0,1,0,13,1,1,1,0,1,98,0,0,
+0,1,8,58,109,97,116,50,0,18,98,0,17,49,0,48,0,0,17,48,0,48,0,0,31,0,0,0,0,1,0,14,1,1,1,0,9,102,0,0,
+0,1,8,58,109,97,116,51,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,
+17,48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,0,0,0,1,0,14,1,1,1,0,5,105,0,0,0,1,3,
+2,0,9,1,120,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,116,0,18,120,0,0,18,105,0,0,0,8,58,
+109,97,116,51,0,18,120,0,0,0,0,0,1,0,14,1,1,1,0,1,98,0,0,0,1,8,58,109,97,116,51,0,18,98,0,17,49,0,
+48,0,0,17,48,0,48,0,0,31,0,0,0,0,1,0,15,1,1,1,0,9,102,0,0,0,1,8,58,109,97,116,52,0,18,102,0,0,17,
+48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,
+0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,
+48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,0,0,0,1,0,15,1,1,1,0,5,105,0,0,0,1,3,2,0,9,1,120,0,0,0,4,105,
+110,116,95,116,111,95,102,108,111,97,116,0,18,120,0,0,18,105,0,0,0,8,58,109,97,116,52,0,18,120,0,0,
+0,0,0,1,0,15,1,1,1,0,1,98,0,0,0,1,8,58,109,97,116,52,0,18,98,0,17,49,0,48,0,0,17,48,0,48,0,0,31,0,
+0,0,0,1,0,0,2,1,1,0,2,9,97,0,0,1,1,0,9,98,0,0,0,1,4,102,108,111,97,116,95,97,100,100,0,18,97,0,0,
+18,97,0,0,18,98,0,0,0,0,1,0,9,2,27,1,1,0,9,97,0,0,0,1,3,2,0,9,1,98,0,0,0,4,102,108,111,97,116,95,
+110,101,103,97,116,101,0,18,98,0,0,18,97,0,0,0,8,18,98,0,0,0,1,0,0,2,2,1,0,2,9,97,0,0,1,1,0,9,98,0,
+0,0,1,3,2,0,9,1,99,0,0,0,4,102,108,111,97,116,95,110,101,103,97,116,101,0,18,99,0,0,18,98,0,0,0,4,
+102,108,111,97,116,95,97,100,100,0,18,97,0,0,18,97,0,0,18,99,0,0,0,0,1,0,0,2,3,1,0,2,9,97,0,0,1,1,
+0,9,98,0,0,0,1,4,102,108,111,97,116,95,109,117,108,116,105,112,108,121,0,18,97,0,0,18,97,0,0,18,98,
+0,0,0,0,1,0,0,2,4,1,0,2,9,97,0,0,1,1,0,9,98,0,0,0,1,4,102,108,111,97,116,95,100,105,118,105,100,
+101,0,18,97,0,0,18,97,0,0,18,98,0,0,0,0,1,0,9,2,26,1,1,0,9,97,0,0,1,1,0,9,98,0,0,0,1,3,2,0,9,1,99,
+0,0,0,4,102,108,111,97,116,95,97,100,100,0,18,99,0,0,18,97,0,0,18,98,0,0,0,8,18,99,0,0,0,1,0,0,2,1,
+1,0,2,5,97,0,0,1,1,0,5,98,0,0,0,1,9,18,97,0,58,105,110,116,0,58,102,108,111,97,116,0,18,97,0,0,0,
+58,102,108,111,97,116,0,18,98,0,0,0,46,0,0,20,0,0,1,0,5,2,27,1,1,0,5,97,0,0,0,1,3,2,0,9,1,120,0,0,
+0,3,2,0,5,1,98,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,116,0,18,120,0,0,18,97,0,0,0,4,102,
+108,111,97,116,95,110,101,103,97,116,101,0,18,120,0,0,18,120,0,0,0,4,102,108,111,97,116,95,116,111,
+95,105,110,116,0,18,98,0,0,18,120,0,0,0,8,18,98,0,0,0,1,0,0,2,2,1,0,2,5,97,0,0,1,1,0,5,98,0,0,0,1,
+9,18,97,0,18,98,0,54,21,0,0,1,0,9,2,21,1,1,0,9,97,0,0,1,1,0,9,98,0,0,0,1,3,2,0,9,1,99,0,0,0,4,102,
+108,111,97,116,95,109,117,108,116,105,112,108,121,0,18,99,0,0,18,97,0,0,18,98,0,0,0,8,18,99,0,0,0,
+1,0,0,2,3,1,0,2,5,97,0,0,1,1,0,5,98,0,0,0,1,9,18,97,0,58,105,110,116,0,58,102,108,111,97,116,0,18,
+97,0,0,0,58,102,108,111,97,116,0,18,98,0,0,0,48,0,0,20,0,0,1,0,9,2,22,1,1,0,9,97,0,0,1,1,0,9,98,0,
+0,0,1,3,2,0,9,1,99,0,0,0,4,102,108,111,97,116,95,100,105,118,105,100,101,0,18,99,0,0,18,97,0,0,18,
+98,0,0,0,8,18,99,0,0,0,1,0,0,2,4,1,0,2,5,97,0,0,1,1,0,5,98,0,0,0,1,9,18,97,0,58,105,110,116,0,58,
+102,108,111,97,116,0,18,97,0,0,0,58,102,108,111,97,116,0,18,98,0,0,0,49,0,0,20,0,0,1,0,0,2,1,1,0,2,
+10,118,0,0,1,1,0,10,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,21,0,9,18,118,0,59,121,0,18,
+117,0,59,121,0,21,0,0,1,0,0,2,2,1,0,2,10,118,0,0,1,1,0,10,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,
+59,120,0,22,0,9,18,118,0,59,121,0,18,117,0,59,121,0,22,0,0,1,0,0,2,3,1,0,2,10,118,0,0,1,1,0,10,117,
+0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,23,0,9,18,118,0,59,121,0,18,117,0,59,121,0,23,0,0,1,
+0,0,2,4,1,0,2,10,118,0,0,1,1,0,10,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,24,0,9,18,118,
+0,59,121,0,18,117,0,59,121,0,24,0,0,1,0,0,2,1,1,0,2,11,118,0,0,1,1,0,11,117,0,0,0,1,9,18,118,0,59,
+120,0,18,117,0,59,120,0,21,0,9,18,118,0,59,121,0,18,117,0,59,121,0,21,0,9,18,118,0,59,122,0,18,117,
+0,59,122,0,21,0,0,1,0,0,2,2,1,0,2,11,118,0,0,1,1,0,11,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,
+120,0,22,0,9,18,118,0,59,121,0,18,117,0,59,121,0,22,0,9,18,118,0,59,122,0,18,117,0,59,122,0,22,0,0,
+1,0,0,2,3,1,0,2,11,118,0,0,1,1,0,11,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,23,0,9,18,
+118,0,59,121,0,18,117,0,59,121,0,23,0,9,18,118,0,59,122,0,18,117,0,59,122,0,23,0,0,1,0,0,2,4,1,0,2,
+11,118,0,0,1,1,0,11,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,24,0,9,18,118,0,59,121,0,18,
+117,0,59,121,0,24,0,9,18,118,0,59,122,0,18,117,0,59,122,0,24,0,0,1,0,0,2,1,1,0,2,12,118,0,0,1,1,0,
+12,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,21,0,9,18,118,0,59,121,0,18,117,0,59,121,0,21,
+0,9,18,118,0,59,122,0,18,117,0,59,122,0,21,0,9,18,118,0,59,119,0,18,117,0,59,119,0,21,0,0,1,0,0,2,
+2,1,0,2,12,118,0,0,1,1,0,12,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,22,0,9,18,118,0,59,
+121,0,18,117,0,59,121,0,22,0,9,18,118,0,59,122,0,18,117,0,59,122,0,22,0,9,18,118,0,59,119,0,18,117,
+0,59,119,0,22,0,0,1,0,0,2,3,1,0,2,12,118,0,0,1,1,0,12,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,
+120,0,23,0,9,18,118,0,59,121,0,18,117,0,59,121,0,23,0,9,18,118,0,59,122,0,18,117,0,59,122,0,23,0,9,
+18,118,0,59,119,0,18,117,0,59,119,0,23,0,0,1,0,0,2,4,1,0,2,12,118,0,0,1,1,0,12,117,0,0,0,1,9,18,
+118,0,59,120,0,18,117,0,59,120,0,24,0,9,18,118,0,59,121,0,18,117,0,59,121,0,24,0,9,18,118,0,59,122,
+0,18,117,0,59,122,0,24,0,9,18,118,0,59,119,0,18,117,0,59,119,0,24,0,0,1,0,0,2,1,1,0,2,6,118,0,0,1,
+1,0,6,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,21,0,9,18,118,0,59,121,0,18,117,0,59,121,0,
+21,0,0,1,0,0,2,2,1,0,2,6,118,0,0,1,1,0,6,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,22,0,9,
+18,118,0,59,121,0,18,117,0,59,121,0,22,0,0,1,0,0,2,3,1,0,2,6,118,0,0,1,1,0,6,117,0,0,0,1,9,18,118,
+0,59,120,0,18,117,0,59,120,0,23,0,9,18,118,0,59,121,0,18,117,0,59,121,0,23,0,0,1,0,0,2,4,1,0,2,6,
+118,0,0,1,1,0,6,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,24,0,9,18,118,0,59,121,0,18,117,
+0,59,121,0,24,0,0,1,0,0,2,1,1,0,2,7,118,0,0,1,1,0,7,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,
+120,0,21,0,9,18,118,0,59,121,0,18,117,0,59,121,0,21,0,9,18,118,0,59,122,0,18,117,0,59,122,0,21,0,0,
+1,0,0,2,2,1,0,2,7,118,0,0,1,1,0,7,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,22,0,9,18,118,
+0,59,121,0,18,117,0,59,121,0,22,0,9,18,118,0,59,122,0,18,117,0,59,122,0,22,0,0,1,0,0,2,3,1,0,2,7,
+118,0,0,1,1,0,7,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,23,0,9,18,118,0,59,121,0,18,117,
+0,59,121,0,23,0,9,18,118,0,59,122,0,18,117,0,59,122,0,23,0,0,1,0,0,2,4,1,0,2,7,118,0,0,1,1,0,7,117,
+0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,24,0,9,18,118,0,59,121,0,18,117,0,59,121,0,24,0,9,18,
+118,0,59,122,0,18,117,0,59,122,0,24,0,0,1,0,0,2,1,1,0,2,8,118,0,0,1,1,0,8,117,0,0,0,1,9,18,118,0,
+59,120,0,18,117,0,59,120,0,21,0,9,18,118,0,59,121,0,18,117,0,59,121,0,21,0,9,18,118,0,59,122,0,18,
+117,0,59,122,0,21,0,9,18,118,0,59,119,0,18,117,0,59,119,0,21,0,0,1,0,0,2,2,1,0,2,8,118,0,0,1,1,0,8,
+117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,22,0,9,18,118,0,59,121,0,18,117,0,59,121,0,22,0,
+9,18,118,0,59,122,0,18,117,0,59,122,0,22,0,9,18,118,0,59,119,0,18,117,0,59,119,0,22,0,0,1,0,0,2,3,
+1,0,2,8,118,0,0,1,1,0,8,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,23,0,9,18,118,0,59,121,0,
+18,117,0,59,121,0,23,0,9,18,118,0,59,122,0,18,117,0,59,122,0,23,0,9,18,118,0,59,119,0,18,117,0,59,
+119,0,23,0,0,1,0,0,2,4,1,0,2,8,118,0,0,1,1,0,8,117,0,0,0,1,9,18,118,0,59,120,0,18,117,0,59,120,0,
+24,0,9,18,118,0,59,121,0,18,117,0,59,121,0,24,0,9,18,118,0,59,122,0,18,117,0,59,122,0,24,0,9,18,
+118,0,59,119,0,18,117,0,59,119,0,24,0,0,1,0,0,2,1,1,0,2,13,109,0,0,1,1,0,13,110,0,0,0,1,9,18,109,0,
+16,8,48,0,57,18,110,0,16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,21,0,0,1,0,
+0,2,2,1,0,2,13,109,0,0,1,1,0,13,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,22,0,9,
+18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,22,0,0,1,0,10,2,21,1,1,0,13,109,0,0,1,1,0,10,118,0,0,
+0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,120,0,48,18,118,0,59,121,0,18,
+109,0,16,10,49,0,57,59,120,0,48,46,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,121,0,48,18,118,0,
+59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,0,0,0,0,1,0,13,2,21,1,1,0,13,109,0,0,1,1,0,13,110,0,
+0,0,1,8,58,109,97,116,50,0,18,109,0,18,110,0,16,8,48,0,57,48,0,18,109,0,18,110,0,16,10,49,0,57,48,
+0,0,0,0,1,0,0,2,3,1,0,2,13,109,0,0,1,1,0,13,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0,0,1,0,
+0,2,4,1,0,2,13,109,0,0,1,1,0,13,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9,
+18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,24,0,0,1,0,0,2,1,1,0,2,14,109,0,0,1,1,0,14,110,0,0,0,
+1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,
+57,21,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,21,0,0,1,0,0,2,2,1,0,2,14,109,0,0,1,1,0,14,
+110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,22,0,9,18,109,0,16,10,49,0,57,18,110,0,
+16,10,49,0,57,22,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,22,0,0,1,0,11,2,21,1,1,0,14,109,
+0,0,1,1,0,11,118,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,120,0,48,
+18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,120,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,
+59,120,0,48,46,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,121,0,48,18,118,0,59,121,0,18,109,0,16,
+10,49,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,121,0,48,46,0,18,118,0,59,
+120,0,18,109,0,16,8,48,0,57,59,122,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,122,0,48,46,18,
+118,0,59,122,0,18,109,0,16,10,50,0,57,59,122,0,48,46,0,0,0,0,1,0,14,2,21,1,1,0,14,109,0,0,1,1,0,14,
+110,0,0,0,1,8,58,109,97,116,51,0,18,109,0,18,110,0,16,8,48,0,57,48,0,18,109,0,18,110,0,16,10,49,0,
+57,48,0,18,109,0,18,110,0,16,10,50,0,57,48,0,0,0,0,1,0,0,2,3,1,0,2,14,109,0,0,1,1,0,14,110,0,0,0,1,
+9,18,109,0,18,109,0,18,110,0,48,20,0,0,1,0,0,2,4,1,0,2,14,109,0,0,1,1,0,14,110,0,0,0,1,9,18,109,0,
+16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,24,0,9,18,
+109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,24,0,0,1,0,0,2,1,1,0,2,15,109,0,0,1,1,0,15,110,0,0,0,1,
+9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,
+21,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,21,0,9,18,109,0,16,10,51,0,57,18,110,0,16,10,
+51,0,57,21,0,0,1,0,0,2,2,1,0,2,15,109,0,0,1,1,0,15,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,
+8,48,0,57,22,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,22,0,9,18,109,0,16,10,50,0,57,18,
+110,0,16,10,50,0,57,22,0,9,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,22,0,0,1,0,12,2,21,1,1,0,
+15,109,0,0,1,1,0,12,118,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,
+120,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,120,0,48,46,18,118,0,59,122,0,18,109,0,16,10,
+50,0,57,59,120,0,48,46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,120,0,48,46,0,18,118,0,59,120,0,
+18,109,0,16,8,48,0,57,59,121,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,18,118,0,
+59,122,0,18,109,0,16,10,50,0,57,59,121,0,48,46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,121,0,
+48,46,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,122,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,
+57,59,122,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,122,0,48,46,18,118,0,59,119,0,18,109,
+0,16,10,51,0,57,59,122,0,48,46,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,119,0,48,18,118,0,59,
+121,0,18,109,0,16,10,49,0,57,59,119,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,119,0,48,
+46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,119,0,48,46,0,0,0,0,1,0,15,2,21,1,1,0,15,109,0,0,1,
+1,0,15,110,0,0,0,1,8,58,109,97,116,52,0,18,109,0,18,110,0,16,8,48,0,57,48,0,18,109,0,18,110,0,16,
+10,49,0,57,48,0,18,109,0,18,110,0,16,10,50,0,57,48,0,18,109,0,18,110,0,16,10,51,0,57,48,0,0,0,0,1,
+0,0,2,3,1,0,2,15,109,0,0,1,1,0,15,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0,0,1,0,0,2,4,1,0,
+2,15,109,0,0,1,1,0,15,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9,18,109,0,16,
+10,49,0,57,18,110,0,16,10,49,0,57,24,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,24,0,9,18,
+109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,24,0,0,1,0,0,2,1,1,0,2,10,118,0,0,1,1,0,9,97,0,0,0,1,9,
+18,118,0,59,120,0,18,97,0,21,0,9,18,118,0,59,121,0,18,97,0,21,0,0,1,0,0,2,2,1,0,2,10,118,0,0,1,1,0,
+9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,22,0,9,18,118,0,59,121,0,18,97,0,22,0,0,1,0,0,2,3,1,0,2,
+10,118,0,0,1,1,0,9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,23,0,9,18,118,0,59,121,0,18,97,0,23,0,0,
+1,0,0,2,4,1,0,2,10,118,0,0,1,1,0,9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,24,0,9,18,118,0,59,121,0,
+18,97,0,24,0,0,1,0,0,2,1,1,0,2,11,118,0,0,1,1,0,9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,21,0,9,18,
+118,0,59,121,0,18,97,0,21,0,9,18,118,0,59,122,0,18,97,0,21,0,0,1,0,0,2,2,1,0,2,11,118,0,0,1,1,0,9,
+97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,22,0,9,18,118,0,59,121,0,18,97,0,22,0,9,18,118,0,59,122,0,
+18,97,0,22,0,0,1,0,0,2,3,1,0,2,11,118,0,0,1,1,0,9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,23,0,9,18,
+118,0,59,121,0,18,97,0,23,0,9,18,118,0,59,122,0,18,97,0,23,0,0,1,0,0,2,4,1,0,2,11,118,0,0,1,1,0,9,
+97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,24,0,9,18,118,0,59,121,0,18,97,0,24,0,9,18,118,0,59,122,0,
+18,97,0,24,0,0,1,0,0,2,1,1,0,2,12,118,0,0,1,1,0,9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,21,0,9,18,
+118,0,59,121,0,18,97,0,21,0,9,18,118,0,59,122,0,18,97,0,21,0,9,18,118,0,59,119,0,18,97,0,21,0,0,1,
+0,0,2,2,1,0,2,12,118,0,0,1,1,0,9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,22,0,9,18,118,0,59,121,0,
+18,97,0,22,0,9,18,118,0,59,122,0,18,97,0,22,0,9,18,118,0,59,119,0,18,97,0,22,0,0,1,0,0,2,3,1,0,2,
+12,118,0,0,1,1,0,9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,23,0,9,18,118,0,59,121,0,18,97,0,23,0,9,
+18,118,0,59,122,0,18,97,0,23,0,9,18,118,0,59,119,0,18,97,0,23,0,0,1,0,0,2,4,1,0,2,12,118,0,0,1,1,0,
+9,97,0,0,0,1,9,18,118,0,59,120,0,18,97,0,24,0,9,18,118,0,59,121,0,18,97,0,24,0,9,18,118,0,59,122,0,
+18,97,0,24,0,9,18,118,0,59,119,0,18,97,0,24,0,0,1,0,0,2,1,1,0,2,13,109,0,0,1,1,0,9,97,0,0,0,1,9,18,
+109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,0,16,10,49,0,57,18,97,0,21,0,0,1,0,0,2,2,1,0,2,13,109,0,0,
+1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,22,0,9,18,109,0,16,10,49,0,57,18,97,0,22,0,0,1,
+0,0,2,3,1,0,2,13,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,23,0,9,18,109,0,16,10,
+49,0,57,18,97,0,23,0,0,1,0,0,2,4,1,0,2,13,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,
+0,24,0,9,18,109,0,16,10,49,0,57,18,97,0,24,0,0,1,0,0,2,1,1,0,2,14,109,0,0,1,1,0,9,97,0,0,0,1,9,18,
+109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,0,16,10,49,0,57,18,97,0,21,0,9,18,109,0,16,10,50,0,57,18,
+97,0,21,0,0,1,0,0,2,2,1,0,2,14,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,22,0,9,
+18,109,0,16,10,49,0,57,18,97,0,22,0,9,18,109,0,16,10,50,0,57,18,97,0,22,0,0,1,0,0,2,3,1,0,2,14,109,
+0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,23,0,9,18,109,0,16,10,49,0,57,18,97,0,23,0,
+9,18,109,0,16,10,50,0,57,18,97,0,23,0,0,1,0,0,2,4,1,0,2,14,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,
+16,8,48,0,57,18,97,0,24,0,9,18,109,0,16,10,49,0,57,18,97,0,24,0,9,18,109,0,16,10,50,0,57,18,97,0,
+24,0,0,1,0,0,2,1,1,0,2,15,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,
+0,16,10,49,0,57,18,97,0,21,0,9,18,109,0,16,10,50,0,57,18,97,0,21,0,9,18,109,0,16,10,51,0,57,18,97,
+0,21,0,0,1,0,0,2,2,1,0,2,15,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,22,0,9,18,
+109,0,16,10,49,0,57,18,97,0,22,0,9,18,109,0,16,10,50,0,57,18,97,0,22,0,9,18,109,0,16,10,51,0,57,18,
+97,0,22,0,0,1,0,0,2,3,1,0,2,15,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,23,0,9,
+18,109,0,16,10,49,0,57,18,97,0,23,0,9,18,109,0,16,10,50,0,57,18,97,0,23,0,9,18,109,0,16,10,51,0,57,
+18,97,0,23,0,0,1,0,0,2,4,1,0,2,15,109,0,0,1,1,0,9,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,24,0,
+9,18,109,0,16,10,49,0,57,18,97,0,24,0,9,18,109,0,16,10,50,0,57,18,97,0,24,0,9,18,109,0,16,10,51,0,
+57,18,97,0,24,0,0,1,0,10,2,21,1,1,0,10,118,0,0,1,1,0,13,109,0,0,0,1,8,58,118,101,99,50,0,18,118,0,
+59,120,0,18,109,0,16,8,48,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,8,48,0,57,59,121,0,48,46,
+0,18,118,0,59,120,0,18,109,0,16,10,49,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,
+121,0,48,46,0,0,0,0,1,0,0,2,3,1,0,2,10,118,0,0,1,1,0,13,109,0,0,0,1,9,18,118,0,18,118,0,18,109,0,
+48,20,0,0,1,0,11,2,21,1,1,0,11,118,0,0,1,1,0,14,109,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,
+18,109,0,16,8,48,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,8,48,0,57,59,121,0,48,46,18,118,0,
+59,122,0,18,109,0,16,8,48,0,57,59,122,0,48,46,0,18,118,0,59,120,0,18,109,0,16,10,49,0,57,59,120,0,
+48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10,49,0,
+57,59,122,0,48,46,0,18,118,0,59,120,0,18,109,0,16,10,50,0,57,59,120,0,48,18,118,0,59,121,0,18,109,
+0,16,10,50,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,122,0,48,46,0,0,0,0,1,0,
+0,2,3,1,0,2,11,118,0,0,1,1,0,14,109,0,0,0,1,9,18,118,0,18,118,0,18,109,0,48,20,0,0,1,0,12,2,21,1,1,
+0,12,118,0,0,1,1,0,15,109,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,
+120,0,48,18,118,0,59,121,0,18,109,0,16,8,48,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,8,48,
+0,57,59,122,0,48,46,18,118,0,59,119,0,18,109,0,16,8,48,0,57,59,119,0,48,46,0,18,118,0,59,120,0,18,
+109,0,16,10,49,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,18,118,0,
+59,122,0,18,109,0,16,10,49,0,57,59,122,0,48,46,18,118,0,59,119,0,18,109,0,16,10,49,0,57,59,119,0,
+48,46,0,18,118,0,59,120,0,18,109,0,16,10,50,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,10,50,0,
+57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,122,0,48,46,18,118,0,59,119,0,18,109,
+0,16,10,50,0,57,59,119,0,48,46,0,18,118,0,59,120,0,18,109,0,16,10,51,0,57,59,120,0,48,18,118,0,59,
+121,0,18,109,0,16,10,51,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10,51,0,57,59,122,0,48,
+46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,119,0,48,46,0,0,0,0,1,0,0,2,3,1,0,2,12,118,0,0,1,1,
+0,15,109,0,0,0,1,9,18,118,0,18,118,0,18,109,0,48,20,0,0,1,0,9,2,27,1,1,0,9,97,0,0,1,1,0,9,98,0,0,0,
+1,3,2,0,9,1,99,0,0,0,4,102,108,111,97,116,95,110,101,103,97,116,101,0,18,99,0,0,18,98,0,0,0,4,102,
+108,111,97,116,95,97,100,100,0,18,99,0,0,18,97,0,0,18,99,0,0,0,8,18,99,0,0,0,1,0,5,2,26,1,1,0,5,97,
+0,0,1,1,0,5,98,0,0,0,1,3,2,0,9,1,120,0,0,1,1,121,0,0,0,3,2,0,5,1,99,0,0,0,4,105,110,116,95,116,111,
+95,102,108,111,97,116,0,18,120,0,0,18,97,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,116,0,18,
+121,0,0,18,98,0,0,0,4,102,108,111,97,116,95,97,100,100,0,18,120,0,0,18,120,0,0,18,121,0,0,0,4,102,
+108,111,97,116,95,116,111,95,105,110,116,0,18,99,0,0,18,120,0,0,0,8,18,99,0,0,0,1,0,5,2,27,1,1,0,5,
+97,0,0,1,1,0,5,98,0,0,0,1,3,2,0,9,1,120,0,0,1,1,121,0,0,0,3,2,0,5,1,99,0,0,0,4,105,110,116,95,116,
+111,95,102,108,111,97,116,0,18,120,0,0,18,97,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,116,
+0,18,121,0,0,18,98,0,0,0,4,102,108,111,97,116,95,110,101,103,97,116,101,0,18,121,0,0,18,121,0,0,0,
+4,102,108,111,97,116,95,97,100,100,0,18,120,0,0,18,120,0,0,18,121,0,0,0,4,102,108,111,97,116,95,
+116,111,95,105,110,116,0,18,99,0,0,18,120,0,0,0,8,18,99,0,0,0,1,0,5,2,21,1,1,0,5,97,0,0,1,1,0,5,98,
+0,0,0,1,3,2,0,9,1,120,0,0,1,1,121,0,0,0,3,2,0,5,1,99,0,0,0,4,105,110,116,95,116,111,95,102,108,111,
+97,116,0,18,120,0,0,18,97,0,0,0,4,105,110,116,95,116,111,95,102,108,111,97,116,0,18,121,0,0,18,98,
+0,0,0,4,102,108,111,97,116,95,109,117,108,116,105,112,108,121,0,18,120,0,0,18,120,0,0,18,121,0,0,0,
+4,102,108,111,97,116,95,116,111,95,105,110,116,0,18,99,0,0,18,120,0,0,0,8,18,99,0,0,0,1,0,5,2,22,1,
+1,0,5,97,0,0,1,1,0,5,98,0,0,0,1,3,2,0,9,1,120,0,0,1,1,121,0,0,0,3,2,0,5,1,99,0,0,0,4,105,110,116,
+95,116,111,95,102,108,111,97,116,0,18,120,0,0,18,97,0,0,0,4,105,110,116,95,116,111,95,102,108,111,
+97,116,0,18,121,0,0,18,98,0,0,0,4,102,108,111,97,116,95,100,105,118,105,100,101,0,18,120,0,0,18,
+120,0,0,18,121,0,0,0,4,102,108,111,97,116,95,116,111,95,105,110,116,0,18,99,0,0,18,120,0,0,0,8,18,
+99,0,0,0,1,0,10,2,26,1,1,0,10,118,0,0,1,1,0,10,117,0,0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,
+18,117,0,59,120,0,46,0,18,118,0,59,121,0,18,117,0,59,121,0,46,0,0,0,0,1,0,10,2,27,1,1,0,10,118,0,0,
+1,1,0,10,117,0,0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,47,0,18,118,0,59,121,
+0,18,117,0,59,121,0,47,0,0,0,0,1,0,10,2,21,1,1,0,10,118,0,0,1,1,0,10,117,0,0,0,1,8,58,118,101,99,
+50,0,18,118,0,59,120,0,18,117,0,59,120,0,48,0,18,118,0,59,121,0,18,117,0,59,121,0,48,0,0,0,0,1,0,
+10,2,22,1,1,0,10,118,0,0,1,1,0,10,117,0,0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,
+120,0,49,0,18,118,0,59,121,0,18,117,0,59,121,0,49,0,0,0,0,1,0,11,2,26,1,1,0,11,118,0,0,1,1,0,11,
+117,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,46,0,18,118,0,59,121,0,18,117,
+0,59,121,0,46,0,18,118,0,59,122,0,18,117,0,59,122,0,46,0,0,0,0,1,0,11,2,27,1,1,0,11,118,0,0,1,1,0,
+11,117,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,47,0,18,118,0,59,121,0,18,
+117,0,59,121,0,47,0,18,118,0,59,122,0,18,117,0,59,122,0,47,0,0,0,0,1,0,11,2,21,1,1,0,11,118,0,0,1,
+1,0,11,117,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,48,0,18,118,0,59,121,0,
+18,117,0,59,121,0,48,0,18,118,0,59,122,0,18,117,0,59,122,0,48,0,0,0,0,1,0,11,2,22,1,1,0,11,118,0,0,
+1,1,0,11,117,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,49,0,18,118,0,59,121,
+0,18,117,0,59,121,0,49,0,18,118,0,59,122,0,18,117,0,59,122,0,49,0,0,0,0,1,0,12,2,26,1,1,0,12,118,0,
+0,1,1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,46,0,18,118,0,59,
+121,0,18,117,0,59,121,0,46,0,18,118,0,59,122,0,18,117,0,59,122,0,46,0,18,118,0,59,119,0,18,117,0,
+59,119,0,46,0,0,0,0,1,0,12,2,27,1,1,0,12,118,0,0,1,1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,118,
+0,59,120,0,18,117,0,59,120,0,47,0,18,118,0,59,121,0,18,117,0,59,121,0,47,0,18,118,0,59,122,0,18,
+117,0,59,122,0,47,0,18,118,0,59,119,0,18,117,0,59,119,0,47,0,0,0,0,1,0,12,2,21,1,1,0,12,118,0,0,1,
+1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,48,0,18,118,0,59,121,0,
+18,117,0,59,121,0,48,0,18,118,0,59,122,0,18,117,0,59,122,0,48,0,18,118,0,59,119,0,18,117,0,59,119,
+0,48,0,0,0,0,1,0,12,2,22,1,1,0,12,118,0,0,1,1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,
+120,0,18,117,0,59,120,0,49,0,18,118,0,59,121,0,18,117,0,59,121,0,49,0,18,118,0,59,122,0,18,117,0,
+59,122,0,49,0,18,118,0,59,119,0,18,117,0,59,119,0,49,0,0,0,0,1,0,6,2,26,1,1,0,6,118,0,0,1,1,0,6,
+117,0,0,0,1,8,58,105,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,46,0,18,118,0,59,121,0,18,
+117,0,59,121,0,46,0,0,0,0,1,0,6,2,27,1,1,0,6,118,0,0,1,1,0,6,117,0,0,0,1,8,58,105,118,101,99,50,0,
+18,118,0,59,120,0,18,117,0,59,120,0,47,0,18,118,0,59,121,0,18,117,0,59,121,0,47,0,0,0,0,1,0,6,2,21,
+1,1,0,6,118,0,0,1,1,0,6,117,0,0,0,1,8,58,105,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,
+48,0,18,118,0,59,121,0,18,117,0,59,121,0,48,0,0,0,0,1,0,6,2,22,1,1,0,6,118,0,0,1,1,0,6,117,0,0,0,1,
+8,58,105,118,101,99,50,0,18,118,0,59,120,0,18,117,0,59,120,0,49,0,18,118,0,59,121,0,18,117,0,59,
+121,0,49,0,0,0,0,1,0,7,2,26,1,1,0,7,118,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,99,51,0,18,118,0,
+59,120,0,18,117,0,59,120,0,46,0,18,118,0,59,121,0,18,117,0,59,121,0,46,0,18,118,0,59,122,0,18,117,
+0,59,122,0,46,0,0,0,0,1,0,7,2,27,1,1,0,7,118,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,99,51,0,18,
+118,0,59,120,0,18,117,0,59,120,0,47,0,18,118,0,59,121,0,18,117,0,59,121,0,47,0,18,118,0,59,122,0,
+18,117,0,59,122,0,47,0,0,0,0,1,0,7,2,21,1,1,0,7,118,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,99,51,
+0,18,118,0,59,120,0,18,117,0,59,120,0,48,0,18,118,0,59,121,0,18,117,0,59,121,0,48,0,18,118,0,59,
+122,0,18,117,0,59,122,0,48,0,0,0,0,1,0,7,2,22,1,1,0,7,118,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,
+99,51,0,18,118,0,59,120,0,18,117,0,59,120,0,49,0,18,118,0,59,121,0,18,117,0,59,121,0,49,0,18,118,0,
+59,122,0,18,117,0,59,122,0,49,0,0,0,0,1,0,8,2,26,1,1,0,8,118,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,
+101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,46,0,18,118,0,59,121,0,18,117,0,59,121,0,46,0,18,
+118,0,59,122,0,18,117,0,59,122,0,46,0,18,118,0,59,119,0,18,117,0,59,119,0,46,0,0,0,0,1,0,8,2,27,1,
+1,0,8,118,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,47,
+0,18,118,0,59,121,0,18,117,0,59,121,0,47,0,18,118,0,59,122,0,18,117,0,59,122,0,47,0,18,118,0,59,
+119,0,18,117,0,59,119,0,47,0,0,0,0,1,0,8,2,21,1,1,0,8,118,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,101,
+99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,48,0,18,118,0,59,121,0,18,117,0,59,121,0,48,0,18,118,0,
+59,122,0,18,117,0,59,122,0,48,0,18,118,0,59,119,0,18,117,0,59,119,0,48,0,0,0,0,1,0,8,2,22,1,1,0,8,
+118,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,101,99,52,0,18,118,0,59,120,0,18,117,0,59,120,0,49,0,18,
+118,0,59,121,0,18,117,0,59,121,0,49,0,18,118,0,59,122,0,18,117,0,59,122,0,49,0,18,118,0,59,119,0,
+18,117,0,59,119,0,49,0,0,0,0,1,0,13,2,26,1,1,0,13,109,0,0,1,1,0,13,110,0,0,0,1,8,58,109,97,116,50,
+0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,
+46,0,0,0,0,1,0,13,2,27,1,1,0,13,109,0,0,1,1,0,13,110,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,
+0,57,18,110,0,16,8,48,0,57,47,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,0,0,0,0,1,0,13,2,
+22,1,1,0,13,109,0,0,1,1,0,13,110,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,0,57,18,110,0,16,8,
+48,0,57,49,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,0,0,0,0,1,0,14,2,26,1,1,0,14,109,0,0,
+1,1,0,14,110,0,0,0,1,8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,0,18,109,
+0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,0,0,0,
+0,1,0,14,2,27,1,1,0,14,109,0,0,1,1,0,14,110,0,0,0,1,8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,18,
+110,0,16,8,48,0,57,47,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,0,18,109,0,16,10,50,0,57,
+18,110,0,16,10,50,0,57,47,0,0,0,0,1,0,14,2,22,1,1,0,14,109,0,0,1,1,0,14,110,0,0,0,1,8,58,109,97,
+116,51,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,
+0,57,49,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,0,0,0,0,1,0,15,2,26,1,1,0,15,109,0,0,1,
+1,0,15,110,0,0,0,1,8,58,109,97,116,52,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,0,18,109,0,
+16,10,49,0,57,18,110,0,16,10,49,0,57,46,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,0,18,
+109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,46,0,0,0,0,1,0,15,2,27,1,1,0,15,109,0,0,1,1,0,15,110,0,
+0,0,1,8,58,109,97,116,52,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,0,18,109,0,16,10,49,0,57,
+18,110,0,16,10,49,0,57,47,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,47,0,18,109,0,16,10,51,0,
+57,18,110,0,16,10,51,0,57,47,0,0,0,0,1,0,15,2,22,1,1,0,15,109,0,0,1,1,0,15,110,0,0,0,1,8,58,109,97,
+116,52,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,
+0,57,49,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,0,18,109,0,16,10,51,0,57,18,110,0,16,10,
+51,0,57,49,0,0,0,0,1,0,10,2,26,1,1,0,9,97,0,0,1,1,0,10,117,0,0,0,1,8,58,118,101,99,50,0,18,97,0,18,
+117,0,59,120,0,46,0,18,97,0,18,117,0,59,121,0,46,0,0,0,0,1,0,10,2,26,1,1,0,10,118,0,0,1,1,0,9,98,0,
+0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,18,98,0,46,0,18,118,0,59,121,0,18,98,0,46,0,0,0,0,1,0,
+10,2,27,1,1,0,9,97,0,0,1,1,0,10,117,0,0,0,1,8,58,118,101,99,50,0,18,97,0,18,117,0,59,120,0,47,0,18,
+97,0,18,117,0,59,121,0,47,0,0,0,0,1,0,10,2,27,1,1,0,10,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,
+50,0,18,118,0,59,120,0,18,98,0,47,0,18,118,0,59,121,0,18,98,0,47,0,0,0,0,1,0,10,2,21,1,1,0,9,97,0,
+0,1,1,0,10,117,0,0,0,1,8,58,118,101,99,50,0,18,97,0,18,117,0,59,120,0,48,0,18,97,0,18,117,0,59,121,
+0,48,0,0,0,0,1,0,10,2,21,1,1,0,10,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,
+0,18,98,0,48,0,18,118,0,59,121,0,18,98,0,48,0,0,0,0,1,0,10,2,22,1,1,0,9,97,0,0,1,1,0,10,117,0,0,0,
+1,8,58,118,101,99,50,0,18,97,0,18,117,0,59,120,0,49,0,18,97,0,18,117,0,59,121,0,49,0,0,0,0,1,0,10,
+2,22,1,1,0,10,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,18,98,0,49,0,18,
+118,0,59,121,0,18,98,0,49,0,0,0,0,1,0,11,2,26,1,1,0,9,97,0,0,1,1,0,11,117,0,0,0,1,8,58,118,101,99,
+51,0,18,97,0,18,117,0,59,120,0,46,0,18,97,0,18,117,0,59,121,0,46,0,18,97,0,18,117,0,59,122,0,46,0,
+0,0,0,1,0,11,2,26,1,1,0,11,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,18,98,
+0,46,0,18,118,0,59,121,0,18,98,0,46,0,18,118,0,59,122,0,18,98,0,46,0,0,0,0,1,0,11,2,27,1,1,0,9,97,
+0,0,1,1,0,11,117,0,0,0,1,8,58,118,101,99,51,0,18,97,0,18,117,0,59,120,0,47,0,18,97,0,18,117,0,59,
+121,0,47,0,18,97,0,18,117,0,59,122,0,47,0,0,0,0,1,0,11,2,27,1,1,0,11,118,0,0,1,1,0,9,98,0,0,0,1,8,
+58,118,101,99,51,0,18,118,0,59,120,0,18,98,0,47,0,18,118,0,59,121,0,18,98,0,47,0,18,118,0,59,122,0,
+18,98,0,47,0,0,0,0,1,0,11,2,21,1,1,0,9,97,0,0,1,1,0,11,117,0,0,0,1,8,58,118,101,99,51,0,18,97,0,18,
+117,0,59,120,0,48,0,18,97,0,18,117,0,59,121,0,48,0,18,97,0,18,117,0,59,122,0,48,0,0,0,0,1,0,11,2,
+21,1,1,0,11,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,18,98,0,48,0,18,118,
+0,59,121,0,18,98,0,48,0,18,118,0,59,122,0,18,98,0,48,0,0,0,0,1,0,11,2,22,1,1,0,9,97,0,0,1,1,0,11,
+117,0,0,0,1,8,58,118,101,99,51,0,18,97,0,18,117,0,59,120,0,49,0,18,97,0,18,117,0,59,121,0,49,0,18,
+97,0,18,117,0,59,122,0,49,0,0,0,0,1,0,11,2,22,1,1,0,11,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,
+51,0,18,118,0,59,120,0,18,98,0,49,0,18,118,0,59,121,0,18,98,0,49,0,18,118,0,59,122,0,18,98,0,49,0,
+0,0,0,1,0,12,2,26,1,1,0,9,97,0,0,1,1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,97,0,18,117,0,59,120,
+0,46,0,18,97,0,18,117,0,59,121,0,46,0,18,97,0,18,117,0,59,122,0,46,0,18,97,0,18,117,0,59,119,0,46,
+0,0,0,0,1,0,12,2,26,1,1,0,12,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,120,0,18,
+98,0,46,0,18,118,0,59,121,0,18,98,0,46,0,18,118,0,59,122,0,18,98,0,46,0,18,118,0,59,119,0,18,98,0,
+46,0,0,0,0,1,0,12,2,27,1,1,0,9,97,0,0,1,1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,97,0,18,117,0,
+59,120,0,47,0,18,97,0,18,117,0,59,121,0,47,0,18,97,0,18,117,0,59,122,0,47,0,18,97,0,18,117,0,59,
+119,0,47,0,0,0,0,1,0,12,2,27,1,1,0,12,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,
+120,0,18,98,0,47,0,18,118,0,59,121,0,18,98,0,47,0,18,118,0,59,122,0,18,98,0,47,0,18,118,0,59,119,0,
+18,98,0,47,0,0,0,0,1,0,12,2,21,1,1,0,9,97,0,0,1,1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,97,0,18,
+117,0,59,120,0,48,0,18,97,0,18,117,0,59,121,0,48,0,18,97,0,18,117,0,59,122,0,48,0,18,97,0,18,117,0,
+59,119,0,48,0,0,0,0,1,0,12,2,21,1,1,0,12,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,52,0,18,118,0,
+59,120,0,18,98,0,48,0,18,118,0,59,121,0,18,98,0,48,0,18,118,0,59,122,0,18,98,0,48,0,18,118,0,59,
+119,0,18,98,0,48,0,0,0,0,1,0,12,2,22,1,1,0,9,97,0,0,1,1,0,12,117,0,0,0,1,8,58,118,101,99,52,0,18,
+97,0,18,117,0,59,120,0,49,0,18,97,0,18,117,0,59,121,0,49,0,18,97,0,18,117,0,59,122,0,49,0,18,97,0,
+18,117,0,59,119,0,49,0,0,0,0,1,0,12,2,22,1,1,0,12,118,0,0,1,1,0,9,98,0,0,0,1,8,58,118,101,99,52,0,
+18,118,0,59,120,0,18,98,0,49,0,18,118,0,59,121,0,18,98,0,49,0,18,118,0,59,122,0,18,98,0,49,0,18,
+118,0,59,119,0,18,98,0,49,0,0,0,0,1,0,13,2,26,1,1,0,9,97,0,0,1,1,0,13,110,0,0,0,1,8,58,109,97,116,
+50,0,18,97,0,18,110,0,16,8,48,0,57,46,0,18,97,0,18,110,0,16,10,49,0,57,46,0,0,0,0,1,0,13,2,26,1,1,
+0,13,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,0,57,18,98,0,46,0,18,109,0,
+16,10,49,0,57,18,98,0,46,0,0,0,0,1,0,13,2,27,1,1,0,9,97,0,0,1,1,0,13,110,0,0,0,1,8,58,109,97,116,
+50,0,18,97,0,18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,47,0,0,0,0,1,0,13,2,27,1,1,
+0,13,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,0,57,18,98,0,47,0,18,109,0,
+16,10,49,0,57,18,98,0,47,0,0,0,0,1,0,13,2,21,1,1,0,9,97,0,0,1,1,0,13,110,0,0,0,1,8,58,109,97,116,
+50,0,18,97,0,18,110,0,16,8,48,0,57,48,0,18,97,0,18,110,0,16,10,49,0,57,48,0,0,0,0,1,0,13,2,21,1,1,
+0,13,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,0,57,18,98,0,48,0,18,109,0,
+16,10,49,0,57,18,98,0,48,0,0,0,0,1,0,13,2,22,1,1,0,9,97,0,0,1,1,0,13,110,0,0,0,1,8,58,109,97,116,
+50,0,18,97,0,18,110,0,16,8,48,0,57,49,0,18,97,0,18,110,0,16,10,49,0,57,49,0,0,0,0,1,0,13,2,22,1,1,
+0,13,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,0,57,18,98,0,49,0,18,109,0,
+16,10,49,0,57,18,98,0,49,0,0,0,0,1,0,14,2,26,1,1,0,9,97,0,0,1,1,0,14,110,0,0,0,1,8,58,109,97,116,
+51,0,18,97,0,18,110,0,16,8,48,0,57,46,0,18,97,0,18,110,0,16,10,49,0,57,46,0,18,97,0,18,110,0,16,10,
+50,0,57,46,0,0,0,0,1,0,14,2,26,1,1,0,14,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,51,0,18,109,0,
+16,8,48,0,57,18,98,0,46,0,18,109,0,16,10,49,0,57,18,98,0,46,0,18,109,0,16,10,50,0,57,18,98,0,46,0,
+0,0,0,1,0,14,2,27,1,1,0,9,97,0,0,1,1,0,14,110,0,0,0,1,8,58,109,97,116,51,0,18,97,0,18,110,0,16,8,
+48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,47,0,18,97,0,18,110,0,16,10,50,0,57,47,0,0,0,0,1,0,14,
+2,27,1,1,0,14,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,18,98,0,47,0,
+18,109,0,16,10,49,0,57,18,98,0,47,0,18,109,0,16,10,50,0,57,18,98,0,47,0,0,0,0,1,0,14,2,21,1,1,0,9,
+97,0,0,1,1,0,14,110,0,0,0,1,8,58,109,97,116,51,0,18,97,0,18,110,0,16,8,48,0,57,48,0,18,97,0,18,110,
+0,16,10,49,0,57,48,0,18,97,0,18,110,0,16,10,50,0,57,48,0,0,0,0,1,0,14,2,21,1,1,0,14,109,0,0,1,1,0,
+9,98,0,0,0,1,8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,18,98,0,48,0,18,109,0,16,10,49,0,57,18,98,
+0,48,0,18,109,0,16,10,50,0,57,18,98,0,48,0,0,0,0,1,0,14,2,22,1,1,0,9,97,0,0,1,1,0,14,110,0,0,0,1,8,
+58,109,97,116,51,0,18,97,0,18,110,0,16,8,48,0,57,49,0,18,97,0,18,110,0,16,10,49,0,57,49,0,18,97,0,
+18,110,0,16,10,50,0,57,49,0,0,0,0,1,0,14,2,22,1,1,0,14,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,
+51,0,18,109,0,16,8,48,0,57,18,98,0,49,0,18,109,0,16,10,49,0,57,18,98,0,49,0,18,109,0,16,10,50,0,57,
+18,98,0,49,0,0,0,0,1,0,15,2,26,1,1,0,9,97,0,0,1,1,0,15,110,0,0,0,1,8,58,109,97,116,52,0,18,97,0,18,
+110,0,16,8,48,0,57,46,0,18,97,0,18,110,0,16,10,49,0,57,46,0,18,97,0,18,110,0,16,10,50,0,57,46,0,18,
+97,0,18,110,0,16,10,51,0,57,46,0,0,0,0,1,0,15,2,26,1,1,0,15,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,
+116,52,0,18,109,0,16,8,48,0,57,18,98,0,46,0,18,109,0,16,10,49,0,57,18,98,0,46,0,18,109,0,16,10,50,
+0,57,18,98,0,46,0,18,109,0,16,10,51,0,57,18,98,0,46,0,0,0,0,1,0,15,2,27,1,1,0,9,97,0,0,1,1,0,15,
+110,0,0,0,1,8,58,109,97,116,52,0,18,97,0,18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,
+47,0,18,97,0,18,110,0,16,10,50,0,57,47,0,18,97,0,18,110,0,16,10,51,0,57,47,0,0,0,0,1,0,15,2,27,1,1,
+0,15,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,52,0,18,109,0,16,8,48,0,57,18,98,0,47,0,18,109,0,
+16,10,49,0,57,18,98,0,47,0,18,109,0,16,10,50,0,57,18,98,0,47,0,18,109,0,16,10,51,0,57,18,98,0,47,0,
+0,0,0,1,0,15,2,21,1,1,0,9,97,0,0,1,1,0,15,110,0,0,0,1,8,58,109,97,116,52,0,18,97,0,18,110,0,16,8,
+48,0,57,48,0,18,97,0,18,110,0,16,10,49,0,57,48,0,18,97,0,18,110,0,16,10,50,0,57,48,0,18,97,0,18,
+110,0,16,10,51,0,57,48,0,0,0,0,1,0,15,2,21,1,1,0,15,109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,52,
+0,18,109,0,16,8,48,0,57,18,98,0,48,0,18,109,0,16,10,49,0,57,18,98,0,48,0,18,109,0,16,10,50,0,57,18,
+98,0,48,0,18,109,0,16,10,51,0,57,18,98,0,48,0,0,0,0,1,0,15,2,22,1,1,0,9,97,0,0,1,1,0,15,110,0,0,0,
+1,8,58,109,97,116,52,0,18,97,0,18,110,0,16,8,48,0,57,49,0,18,97,0,18,110,0,16,10,49,0,57,49,0,18,
+97,0,18,110,0,16,10,50,0,57,49,0,18,97,0,18,110,0,16,10,51,0,57,49,0,0,0,0,1,0,15,2,22,1,1,0,15,
+109,0,0,1,1,0,9,98,0,0,0,1,8,58,109,97,116,52,0,18,109,0,16,8,48,0,57,18,98,0,49,0,18,109,0,16,10,
+49,0,57,18,98,0,49,0,18,109,0,16,10,50,0,57,18,98,0,49,0,18,109,0,16,10,51,0,57,18,98,0,49,0,0,0,0,
+1,0,6,2,26,1,1,0,5,97,0,0,1,1,0,6,117,0,0,0,1,8,58,105,118,101,99,50,0,18,97,0,0,0,18,117,0,46,0,0,
+1,0,6,2,26,1,1,0,6,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,50,0,18,98,0,0,0,46,0,0,
+1,0,6,2,27,1,1,0,5,97,0,0,1,1,0,6,117,0,0,0,1,8,58,105,118,101,99,50,0,18,97,0,0,0,18,117,0,47,0,0,
+1,0,6,2,27,1,1,0,6,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,50,0,18,98,0,0,0,47,0,0,
+1,0,6,2,21,1,1,0,5,97,0,0,1,1,0,6,117,0,0,0,1,8,58,105,118,101,99,50,0,18,97,0,0,0,18,117,0,48,0,0,
+1,0,6,2,21,1,1,0,6,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,50,0,18,98,0,0,0,48,0,0,
+1,0,6,2,22,1,1,0,5,97,0,0,1,1,0,6,117,0,0,0,1,8,58,105,118,101,99,50,0,18,97,0,0,0,18,117,0,49,0,0,
+1,0,6,2,22,1,1,0,6,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,50,0,18,98,0,0,0,49,0,0,
+1,0,7,2,26,1,1,0,5,97,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,99,51,0,18,97,0,0,0,18,117,0,46,0,0,
+1,0,7,2,26,1,1,0,7,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,51,0,18,98,0,0,0,46,0,0,
+1,0,7,2,27,1,1,0,5,97,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,99,51,0,18,97,0,0,0,18,117,0,47,0,0,
+1,0,7,2,27,1,1,0,7,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,51,0,18,98,0,0,0,47,0,0,
+1,0,7,2,21,1,1,0,5,97,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,99,51,0,18,97,0,0,0,18,117,0,48,0,0,
+1,0,7,2,21,1,1,0,7,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,51,0,18,98,0,0,0,48,0,0,
+1,0,7,2,22,1,1,0,5,97,0,0,1,1,0,7,117,0,0,0,1,8,58,105,118,101,99,51,0,18,97,0,0,0,18,117,0,49,0,0,
+1,0,7,2,22,1,1,0,7,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,51,0,18,98,0,0,0,49,0,0,
+1,0,8,2,26,1,1,0,5,97,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,101,99,52,0,18,97,0,0,0,18,117,0,46,0,0,
+1,0,8,2,26,1,1,0,8,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,52,0,18,98,0,0,0,46,0,0,
+1,0,8,2,27,1,1,0,5,97,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,101,99,52,0,18,97,0,0,0,18,117,0,47,0,0,
+1,0,8,2,27,1,1,0,8,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,52,0,18,98,0,0,0,47,0,0,
+1,0,8,2,21,1,1,0,5,97,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,101,99,52,0,18,97,0,0,0,18,117,0,48,0,0,
+1,0,8,2,21,1,1,0,8,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,52,0,18,98,0,0,0,48,0,0,
+1,0,8,2,22,1,1,0,5,97,0,0,1,1,0,8,117,0,0,0,1,8,58,105,118,101,99,52,0,18,97,0,0,0,18,117,0,49,0,0,
+1,0,8,2,22,1,1,0,8,118,0,0,1,1,0,5,98,0,0,0,1,8,18,118,0,58,105,118,101,99,52,0,18,98,0,0,0,49,0,0,
+1,0,10,2,27,1,1,0,10,118,0,0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,54,0,18,118,0,59,121,0,54,
+0,0,0,0,1,0,11,2,27,1,1,0,11,118,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,54,0,18,118,0,59,
+121,0,54,0,18,118,0,59,122,0,54,0,0,0,0,1,0,12,2,27,1,1,0,12,118,0,0,0,1,8,58,118,101,99,52,0,18,
+118,0,59,120,0,54,0,18,118,0,59,121,0,54,0,18,118,0,59,122,0,54,0,18,118,0,59,119,0,54,0,0,0,0,1,0,
+6,2,27,1,1,0,6,118,0,0,0,1,8,58,105,118,101,99,50,0,18,118,0,59,120,0,54,0,18,118,0,59,121,0,54,0,
+0,0,0,1,0,7,2,27,1,1,0,7,118,0,0,0,1,8,58,105,118,101,99,51,0,18,118,0,59,120,0,54,0,18,118,0,59,
+121,0,54,0,18,118,0,59,122,0,54,0,0,0,0,1,0,8,2,27,1,1,0,8,118,0,0,0,1,8,58,105,118,101,99,52,0,18,
+118,0,59,120,0,54,0,18,118,0,59,121,0,54,0,18,118,0,59,122,0,54,0,18,118,0,59,119,0,54,0,0,0,0,1,0,
+13,2,27,1,1,0,13,109,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,0,57,54,0,18,109,0,16,10,49,0,
+57,54,0,0,0,0,1,0,14,2,27,1,1,0,14,109,0,0,0,1,8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,54,0,18,
+109,0,16,10,49,0,57,54,0,18,109,0,16,10,50,0,57,54,0,0,0,0,1,0,15,2,27,1,1,0,15,109,0,0,0,1,8,58,
+109,97,116,52,0,18,109,0,16,8,48,0,57,54,0,18,109,0,16,10,49,0,57,54,0,18,109,0,16,10,50,0,57,54,0,
+18,109,0,16,10,51,0,57,54,0,0,0,0,1,0,0,2,25,1,0,2,9,97,0,0,0,1,9,18,97,0,17,49,0,48,0,0,22,0,0,1,
+0,0,2,25,1,0,2,5,97,0,0,0,1,9,18,97,0,16,10,49,0,22,0,0,1,0,0,2,25,1,0,2,10,118,0,0,0,1,9,18,118,0,
+59,120,0,52,0,9,18,118,0,59,121,0,52,0,0,1,0,0,2,25,1,0,2,11,118,0,0,0,1,9,18,118,0,59,120,0,52,0,
+9,18,118,0,59,121,0,52,0,9,18,118,0,59,122,0,52,0,0,1,0,0,2,25,1,0,2,12,118,0,0,0,1,9,18,118,0,59,
+120,0,52,0,9,18,118,0,59,121,0,52,0,9,18,118,0,59,122,0,52,0,9,18,118,0,59,119,0,52,0,0,1,0,0,2,25,
+1,0,2,6,118,0,0,0,1,9,18,118,0,59,120,0,52,0,9,18,118,0,59,121,0,52,0,0,1,0,0,2,25,1,0,2,7,118,0,0,
+0,1,9,18,118,0,59,120,0,52,0,9,18,118,0,59,121,0,52,0,9,18,118,0,59,122,0,52,0,0,1,0,0,2,25,1,0,2,
+8,118,0,0,0,1,9,18,118,0,59,120,0,52,0,9,18,118,0,59,121,0,52,0,9,18,118,0,59,122,0,52,0,9,18,118,
+0,59,119,0,52,0,0,1,0,0,2,25,1,0,2,13,109,0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,9,18,109,0,16,10,49,
+0,57,52,0,0,1,0,0,2,25,1,0,2,14,109,0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,9,18,109,0,16,10,49,0,57,
+52,0,9,18,109,0,16,10,50,0,57,52,0,0,1,0,0,2,25,1,0,2,15,109,0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,
+9,18,109,0,16,10,49,0,57,52,0,9,18,109,0,16,10,50,0,57,52,0,9,18,109,0,16,10,51,0,57,52,0,0,1,0,0,
+2,24,1,0,2,9,97,0,0,0,1,9,18,97,0,17,49,0,48,0,0,21,0,0,1,0,0,2,24,1,0,2,5,97,0,0,0,1,9,18,97,0,16,
+10,49,0,21,0,0,1,0,0,2,24,1,0,2,10,118,0,0,0,1,9,18,118,0,59,120,0,51,0,9,18,118,0,59,121,0,51,0,0,
+1,0,0,2,24,1,0,2,11,118,0,0,0,1,9,18,118,0,59,120,0,51,0,9,18,118,0,59,121,0,51,0,9,18,118,0,59,
+122,0,51,0,0,1,0,0,2,24,1,0,2,12,118,0,0,0,1,9,18,118,0,59,120,0,51,0,9,18,118,0,59,121,0,51,0,9,
+18,118,0,59,122,0,51,0,9,18,118,0,59,119,0,51,0,0,1,0,0,2,24,1,0,2,6,118,0,0,0,1,9,18,118,0,59,120,
+0,51,0,9,18,118,0,59,121,0,51,0,0,1,0,0,2,24,1,0,2,7,118,0,0,0,1,9,18,118,0,59,120,0,51,0,9,18,118,
+0,59,121,0,51,0,9,18,118,0,59,122,0,51,0,0,1,0,0,2,24,1,0,2,8,118,0,0,0,1,9,18,118,0,59,120,0,51,0,
+9,18,118,0,59,121,0,51,0,9,18,118,0,59,122,0,51,0,9,18,118,0,59,119,0,51,0,0,1,0,0,2,24,1,0,2,13,
+109,0,0,0,1,9,18,109,0,16,8,48,0,57,51,0,9,18,109,0,16,10,49,0,57,51,0,0,1,0,0,2,24,1,0,2,14,109,0,
+0,0,1,9,18,109,0,16,8,48,0,57,51,0,9,18,109,0,16,10,49,0,57,51,0,9,18,109,0,16,10,50,0,57,51,0,0,1,
+0,0,2,24,1,0,2,15,109,0,0,0,1,9,18,109,0,16,8,48,0,57,51,0,9,18,109,0,16,10,49,0,57,51,0,9,18,109,
+0,16,10,50,0,57,51,0,9,18,109,0,16,10,51,0,57,51,0,0,1,0,9,2,25,1,0,2,9,97,0,0,1,1,0,5,0,0,0,1,3,2,
+0,9,1,98,0,2,18,97,0,0,0,9,18,97,0,52,0,8,18,98,0,0,0,1,0,5,2,25,1,0,2,5,97,0,0,1,1,0,5,0,0,0,1,3,
+2,0,5,1,98,0,2,18,97,0,0,0,9,18,97,0,52,0,8,18,98,0,0,0,1,0,10,2,25,1,0,2,10,118,0,0,1,1,0,5,0,0,0,
+1,8,58,118,101,99,50,0,18,118,0,59,120,0,61,0,18,118,0,59,121,0,61,0,0,0,0,1,0,11,2,25,1,0,2,11,
+118,0,0,1,1,0,5,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,120,0,61,0,18,118,0,59,121,0,61,0,18,118,
+0,59,122,0,61,0,0,0,0,1,0,12,2,25,1,0,2,12,118,0,0,1,1,0,5,0,0,0,1,8,58,118,101,99,52,0,18,118,0,
+59,120,0,61,0,18,118,0,59,121,0,61,0,18,118,0,59,122,0,61,0,18,118,0,59,119,0,61,0,0,0,0,1,0,6,2,
+25,1,0,2,6,118,0,0,1,1,0,5,0,0,0,1,8,58,105,118,101,99,50,0,18,118,0,59,120,0,61,0,18,118,0,59,121,
+0,61,0,0,0,0,1,0,7,2,25,1,0,2,7,118,0,0,1,1,0,5,0,0,0,1,8,58,105,118,101,99,51,0,18,118,0,59,120,0,
+61,0,18,118,0,59,121,0,61,0,18,118,0,59,122,0,61,0,0,0,0,1,0,8,2,25,1,0,2,8,118,0,0,1,1,0,5,0,0,0,
+1,8,58,105,118,101,99,52,0,18,118,0,59,120,0,61,0,18,118,0,59,121,0,61,0,18,118,0,59,122,0,61,0,18,
+118,0,59,119,0,61,0,0,0,0,1,0,13,2,25,1,0,2,13,109,0,0,1,1,0,5,0,0,0,1,8,58,109,97,116,50,0,18,109,
+0,16,8,48,0,57,61,0,18,109,0,16,10,49,0,57,61,0,0,0,0,1,0,14,2,25,1,0,2,14,109,0,0,1,1,0,5,0,0,0,1,
+8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,61,0,18,109,0,16,10,49,0,57,61,0,18,109,0,16,10,50,0,57,
+61,0,0,0,0,1,0,15,2,25,1,0,2,15,109,0,0,1,1,0,5,0,0,0,1,8,58,109,97,116,52,0,18,109,0,16,8,48,0,57,
+61,0,18,109,0,16,10,49,0,57,61,0,18,109,0,16,10,50,0,57,61,0,18,109,0,16,10,51,0,57,61,0,0,0,0,1,0,
+9,2,24,1,0,2,9,97,0,0,1,1,0,5,0,0,0,1,3,2,0,9,1,98,0,2,18,97,0,0,0,9,18,97,0,51,0,8,18,98,0,0,0,1,
+0,5,2,24,1,0,2,5,97,0,0,1,1,0,5,0,0,0,1,3,2,0,5,1,98,0,2,18,97,0,0,0,9,18,97,0,51,0,8,18,98,0,0,0,
+1,0,10,2,24,1,0,2,10,118,0,0,1,1,0,5,0,0,0,1,8,58,118,101,99,50,0,18,118,0,59,120,0,60,0,18,118,0,
+59,121,0,60,0,0,0,0,1,0,11,2,24,1,0,2,11,118,0,0,1,1,0,5,0,0,0,1,8,58,118,101,99,51,0,18,118,0,59,
+120,0,60,0,18,118,0,59,121,0,60,0,18,118,0,59,122,0,60,0,0,0,0,1,0,12,2,24,1,0,2,12,118,0,0,1,1,0,
+5,0,0,0,1,8,58,118,101,99,52,0,18,118,0,59,120,0,60,0,18,118,0,59,121,0,60,0,18,118,0,59,122,0,60,
+0,18,118,0,59,119,0,60,0,0,0,0,1,0,6,2,24,1,0,2,6,118,0,0,1,1,0,5,0,0,0,1,8,58,105,118,101,99,50,0,
+18,118,0,59,120,0,60,0,18,118,0,59,121,0,60,0,0,0,0,1,0,7,2,24,1,0,2,7,118,0,0,1,1,0,5,0,0,0,1,8,
+58,105,118,101,99,51,0,18,118,0,59,120,0,60,0,18,118,0,59,121,0,60,0,18,118,0,59,122,0,60,0,0,0,0,
+1,0,8,2,24,1,0,2,8,118,0,0,1,1,0,5,0,0,0,1,8,58,105,118,101,99,52,0,18,118,0,59,120,0,60,0,18,118,
+0,59,121,0,60,0,18,118,0,59,122,0,60,0,18,118,0,59,119,0,60,0,0,0,0,1,0,13,2,24,1,0,2,13,109,0,0,1,
+1,0,5,0,0,0,1,8,58,109,97,116,50,0,18,109,0,16,8,48,0,57,60,0,18,109,0,16,10,49,0,57,60,0,0,0,0,1,
+0,14,2,24,1,0,2,14,109,0,0,1,1,0,5,0,0,0,1,8,58,109,97,116,51,0,18,109,0,16,8,48,0,57,60,0,18,109,
+0,16,10,49,0,57,60,0,18,109,0,16,10,50,0,57,60,0,0,0,0,1,0,15,2,24,1,0,2,15,109,0,0,1,1,0,5,0,0,0,
+1,8,58,109,97,116,52,0,18,109,0,16,8,48,0,57,60,0,18,109,0,16,10,49,0,57,60,0,18,109,0,16,10,50,0,
+57,60,0,18,109,0,16,10,51,0,57,60,0,0,0,0,1,0,1,2,15,1,1,0,9,97,0,0,1,1,0,9,98,0,0,0,1,3,2,0,1,1,
+99,0,0,0,4,102,108,111,97,116,95,108,101,115,115,0,18,99,0,0,18,97,0,0,18,98,0,0,0,8,18,99,0,0,0,1,
+0,1,2,15,1,1,0,5,97,0,0,1,1,0,5,98,0,0,0,1,8,58,102,108,111,97,116,0,18,97,0,0,0,58,102,108,111,97,
+116,0,18,98,0,0,0,40,0,0,1,0,1,2,16,1,1,0,9,97,0,0,1,1,0,9,98,0,0,0,1,3,2,0,1,1,99,0,0,0,4,102,108,
+111,97,116,95,108,101,115,115,0,18,99,0,0,18,98,0,0,18,97,0,0,0,8,18,99,0,0,0,1,0,1,2,16,1,1,0,5,
+97,0,0,1,1,0,5,98,0,0,0,1,8,58,102,108,111,97,116,0,18,97,0,0,0,58,102,108,111,97,116,0,18,98,0,0,
+0,41,0,0,1,0,1,2,18,1,1,0,9,97,0,0,1,1,0,9,98,0,0,0,1,3,2,0,1,1,103,0,0,1,1,101,0,0,0,4,102,108,
+111,97,116,95,108,101,115,115,0,18,103,0,0,18,98,0,0,18,97,0,0,0,4,102,108,111,97,116,95,101,113,
+117,97,108,0,18,101,0,0,18,97,0,0,18,98,0,0,0,8,18,103,0,18,101,0,32,0,0,1,0,1,2,18,1,1,0,5,97,0,0,
+1,1,0,5,98,0,0,0,1,8,58,102,108,111,97,116,0,18,97,0,0,0,58,102,108,111,97,116,0,18,98,0,0,0,43,0,
+0,1,0,1,2,17,1,1,0,9,97,0,0,1,1,0,9,98,0,0,0,1,3,2,0,1,1,103,0,0,1,1,101,0,0,0,4,102,108,111,97,
+116,95,108,101,115,115,0,18,103,0,0,18,97,0,0,18,98,0,0,0,4,102,108,111,97,116,95,101,113,117,97,
+108,0,18,101,0,0,18,97,0,0,18,98,0,0,0,8,18,103,0,18,101,0,32,0,0,1,0,1,2,17,1,1,0,5,97,0,0,1,1,0,
+5,98,0,0,0,1,8,58,102,108,111,97,116,0,18,97,0,0,0,58,102,108,111,97,116,0,18,98,0,0,0,42,0,0,1,0,
+1,2,11,1,1,0,1,97,0,0,1,1,0,1,98,0,0,0,1,8,18,97,0,18,98,0,39,0,0,1,0,1,2,29,1,1,0,1,97,0,0,0,1,8,
+18,97,0,15,2,48,0,38,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,9,102,0,0,0,1,4,102,108,
+111,97,116,95,112,114,105,110,116,0,18,102,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,
+5,105,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,105,0,0,0,0,1,0,0,0,112,114,105,110,116,77,
+69,83,65,0,1,1,0,1,98,0,0,0,1,4,98,111,111,108,95,112,114,105,110,116,0,18,98,0,0,0,0,1,0,0,0,112,
+114,105,110,116,77,69,83,65,0,1,1,0,10,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,
+59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,121,0,0,0,0,0,1,0,0,0,112,114,
+105,110,116,77,69,83,65,0,1,1,0,11,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,
+120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,121,0,0,0,0,9,58,112,114,105,110,
+116,77,69,83,65,0,18,118,0,59,122,0,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,12,118,
+0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,
+69,83,65,0,18,118,0,59,121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,122,0,0,0,0,
+9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,119,0,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,
+83,65,0,1,1,0,6,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,120,0,0,0,0,9,58,
+112,114,105,110,116,77,69,83,65,0,18,118,0,59,121,0,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,
+65,0,1,1,0,7,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,120,0,0,0,0,9,58,112,
+114,105,110,116,77,69,83,65,0,18,118,0,59,121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,
+118,0,59,122,0,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,8,118,0,0,0,1,9,58,112,114,
+105,110,116,77,69,83,65,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,
+59,121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,122,0,0,0,0,9,58,112,114,105,110,
+116,77,69,83,65,0,18,118,0,59,119,0,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,2,118,
+0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,
+69,83,65,0,18,118,0,59,121,0,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,3,118,0,0,0,1,
+9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,
+65,0,18,118,0,59,121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,122,0,0,0,0,0,1,0,
+0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,4,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,
+18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,118,0,59,121,0,0,0,0,9,58,112,
+114,105,110,116,77,69,83,65,0,18,118,0,59,122,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,
+118,0,59,119,0,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,13,109,0,0,0,1,9,58,112,114,
+105,110,116,77,69,83,65,0,18,109,0,16,8,48,0,57,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,
+109,0,16,10,49,0,57,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,14,109,0,0,0,1,9,58,
+112,114,105,110,116,77,69,83,65,0,18,109,0,16,8,48,0,57,0,0,0,9,58,112,114,105,110,116,77,69,83,65,
+0,18,109,0,16,10,49,0,57,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,109,0,16,10,50,0,57,0,0,0,
+0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,15,109,0,0,0,1,9,58,112,114,105,110,116,77,69,83,
+65,0,18,109,0,16,8,48,0,57,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,18,109,0,16,10,49,0,57,0,0,
+0,9,58,112,114,105,110,116,77,69,83,65,0,18,109,0,16,10,50,0,57,0,0,0,9,58,112,114,105,110,116,77,
+69,83,65,0,18,109,0,16,10,51,0,57,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,16,101,0,
+0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,
+65,0,1,1,0,17,101,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0,0,0,0,1,0,0,0,112,114,
+105,110,116,77,69,83,65,0,1,1,0,18,101,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0,0,0,
+0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,19,101,0,0,0,1,4,105,110,116,95,112,114,105,110,
+116,0,18,101,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,20,101,0,0,0,1,4,105,110,116,
+95,112,114,105,110,116,0,18,101,0,0,0,0,1,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,21,101,0,0,
+0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0,0,0,0,0
diff --git a/src/mesa/shader/slang/library/slang_fragment_builtin_gc.h b/src/mesa/shader/slang/library/slang_fragment_builtin_gc.h
new file mode 100644
index 00000000000..b7f1d3816c1
--- /dev/null
+++ b/src/mesa/shader/slang/library/slang_fragment_builtin_gc.h
@@ -0,0 +1,79 @@
+
+/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */
+/* slang_fragment_builtin.gc */
+
+3,2,2,6,12,1,103,108,95,70,114,97,103,67,111,111,114,100,0,0,0,2,2,6,1,1,103,108,95,70,114,111,110,
+116,70,97,99,105,110,103,0,0,0,2,2,5,12,1,103,108,95,70,114,97,103,67,111,108,111,114,0,0,0,2,2,5,
+12,1,103,108,95,70,114,97,103,68,97,116,97,0,3,18,103,108,95,77,97,120,68,114,97,119,66,117,102,
+102,101,114,115,0,0,0,2,2,5,9,1,103,108,95,70,114,97,103,68,101,112,116,104,0,0,0,2,2,3,12,1,103,
+108,95,67,111,108,111,114,0,0,0,2,2,3,12,1,103,108,95,83,101,99,111,110,100,97,114,121,67,111,108,
+111,114,0,0,0,2,2,3,12,1,103,108,95,84,101,120,67,111,111,114,100,0,3,18,103,108,95,77,97,120,84,
+101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,3,9,1,103,108,95,70,111,103,70,114,97,103,
+67,111,111,114,100,0,0,0,1,0,12,0,116,101,120,116,117,114,101,49,68,0,1,0,0,16,115,97,109,112,108,
+101,114,0,0,1,0,0,9,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,3,2,0,12,1,116,101,120,
+101,108,0,0,0,4,118,101,99,52,95,116,101,120,49,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,
+108,101,114,0,0,18,99,111,111,114,100,0,0,18,98,105,97,115,0,0,0,8,18,116,101,120,101,108,0,0,0,1,
+0,12,0,116,101,120,116,117,114,101,49,68,80,114,111,106,0,1,0,0,16,115,97,109,112,108,101,114,0,0,
+1,0,0,10,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,8,58,116,101,120,116,117,114,101,49,
+68,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,
+116,0,49,0,18,98,105,97,115,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,49,68,80,114,111,106,0,
+1,0,0,16,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,
+0,1,8,58,116,101,120,116,117,114,101,49,68,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,
+100,0,59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,98,105,97,115,0,0,0,0,0,1,0,12,0,116,101,
+120,116,117,114,101,50,68,0,1,0,0,17,115,97,109,112,108,101,114,0,0,1,0,0,10,99,111,111,114,100,0,
+0,1,0,0,9,98,105,97,115,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,52,95,116,101,
+120,50,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,
+0,18,98,105,97,115,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,116,101,120,116,117,114,101,50,68,
+80,114,111,106,0,1,0,0,17,115,97,109,112,108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,1,0,0,9,
+98,105,97,115,0,0,0,1,8,58,116,101,120,116,117,114,101,50,68,0,18,115,97,109,112,108,101,114,0,0,
+58,118,101,99,50,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,112,0,49,0,18,99,
+111,111,114,100,0,59,116,0,18,99,111,111,114,100,0,59,112,0,49,0,0,0,18,98,105,97,115,0,0,0,0,0,1,
+0,12,0,116,101,120,116,117,114,101,50,68,80,114,111,106,0,1,0,0,17,115,97,109,112,108,101,114,0,0,
+1,0,0,12,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,8,58,116,101,120,116,117,114,101,50,
+68,0,18,115,97,109,112,108,101,114,0,0,58,118,101,99,50,0,18,99,111,111,114,100,0,59,115,0,18,99,
+111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,116,0,18,99,111,111,114,100,0,59,113,0,
+49,0,0,0,18,98,105,97,115,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,51,68,0,1,0,0,18,115,97,
+109,112,108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,3,2,0,12,1,
+116,101,120,101,108,0,0,0,4,118,101,99,52,95,116,101,120,51,100,0,18,116,101,120,101,108,0,0,18,
+115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,18,98,105,97,115,0,0,0,8,18,116,101,120,
+101,108,0,0,0,1,0,12,0,116,101,120,116,117,114,101,51,68,80,114,111,106,0,1,0,0,18,115,97,109,112,
+108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,8,58,116,101,120,116,
+117,114,101,51,68,0,18,115,97,109,112,108,101,114,0,0,58,118,101,99,51,0,18,99,111,111,114,100,0,
+59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,116,0,18,99,111,111,114,
+100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,112,0,18,99,111,111,114,100,0,59,113,0,49,0,0,0,18,
+98,105,97,115,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,67,117,98,101,0,1,0,0,19,115,97,109,
+112,108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,3,2,0,12,1,116,
+101,120,101,108,0,0,0,4,118,101,99,52,95,116,101,120,99,117,98,101,0,18,116,101,120,101,108,0,0,18,
+115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,18,98,105,97,115,0,0,0,8,18,116,101,120,
+101,108,0,0,0,1,0,12,0,115,104,97,100,111,119,49,68,0,1,0,0,20,115,97,109,112,108,101,114,0,0,1,0,
+0,11,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,
+118,101,99,52,95,115,104,97,100,49,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,
+0,0,18,99,111,111,114,100,0,0,18,98,105,97,115,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,115,
+104,97,100,111,119,49,68,80,114,111,106,0,1,0,0,20,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,
+111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,8,58,115,104,97,100,111,119,49,68,0,18,115,97,109,
+112,108,101,114,0,0,58,118,101,99,51,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,
+113,0,49,0,17,48,0,48,0,0,0,18,99,111,111,114,100,0,59,112,0,18,99,111,111,114,100,0,59,113,0,49,0,
+0,0,18,98,105,97,115,0,0,0,0,0,1,0,12,0,115,104,97,100,111,119,50,68,0,1,0,0,21,115,97,109,112,108,
+101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,3,2,0,12,1,116,101,120,
+101,108,0,0,0,4,118,101,99,52,95,115,104,97,100,50,100,0,18,116,101,120,101,108,0,0,18,115,97,109,
+112,108,101,114,0,0,18,99,111,111,114,100,0,0,18,98,105,97,115,0,0,0,8,18,116,101,120,101,108,0,0,
+0,1,0,12,0,115,104,97,100,111,119,50,68,80,114,111,106,0,1,0,0,21,115,97,109,112,108,101,114,0,0,1,
+0,0,12,99,111,111,114,100,0,0,1,0,0,9,98,105,97,115,0,0,0,1,8,58,115,104,97,100,111,119,50,68,0,18,
+115,97,109,112,108,101,114,0,0,58,118,101,99,51,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,
+114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,116,0,18,99,111,111,114,100,0,59,113,0,49,0,18,
+99,111,111,114,100,0,59,112,0,18,99,111,111,114,100,0,59,113,0,49,0,0,0,18,98,105,97,115,0,0,0,0,0,
+1,0,9,0,100,70,100,120,0,1,0,0,9,112,0,0,0,1,8,17,48,0,48,48,49,0,0,0,0,1,0,10,0,100,70,100,120,0,
+1,0,0,10,112,0,0,0,1,8,58,118,101,99,50,0,17,48,0,48,48,49,0,0,0,0,0,0,1,0,11,0,100,70,100,120,0,1,
+0,0,11,112,0,0,0,1,8,58,118,101,99,51,0,17,48,0,48,48,49,0,0,0,0,0,0,1,0,12,0,100,70,100,120,0,1,0,
+0,12,112,0,0,0,1,8,58,118,101,99,52,0,17,48,0,48,48,49,0,0,0,0,0,0,1,0,9,0,100,70,100,121,0,1,0,0,
+9,112,0,0,0,1,8,17,48,0,48,48,49,0,0,0,0,1,0,10,0,100,70,100,121,0,1,0,0,10,112,0,0,0,1,8,58,118,
+101,99,50,0,17,48,0,48,48,49,0,0,0,0,0,0,1,0,11,0,100,70,100,121,0,1,0,0,11,112,0,0,0,1,8,58,118,
+101,99,51,0,17,48,0,48,48,49,0,0,0,0,0,0,1,0,12,0,100,70,100,121,0,1,0,0,12,112,0,0,0,1,8,58,118,
+101,99,52,0,17,48,0,48,48,49,0,0,0,0,0,0,1,0,9,0,102,119,105,100,116,104,0,1,0,0,9,112,0,0,0,1,8,
+58,97,98,115,0,58,100,70,100,120,0,18,112,0,0,0,0,0,58,97,98,115,0,58,100,70,100,121,0,18,112,0,0,
+0,0,0,46,0,0,1,0,10,0,102,119,105,100,116,104,0,1,0,0,10,112,0,0,0,1,8,58,97,98,115,0,58,100,70,
+100,120,0,18,112,0,0,0,0,0,58,97,98,115,0,58,100,70,100,121,0,18,112,0,0,0,0,0,46,0,0,1,0,11,0,102,
+119,105,100,116,104,0,1,0,0,11,112,0,0,0,1,8,58,97,98,115,0,58,100,70,100,120,0,18,112,0,0,0,0,0,
+58,97,98,115,0,58,100,70,100,121,0,18,112,0,0,0,0,0,46,0,0,1,0,12,0,102,119,105,100,116,104,0,1,0,
+0,12,112,0,0,0,1,8,58,97,98,115,0,58,100,70,100,120,0,18,112,0,0,0,0,0,58,97,98,115,0,58,100,70,
+100,121,0,18,112,0,0,0,0,0,46,0,0,0
diff --git a/src/mesa/shader/slang/library/slang_pp_version_syn.h b/src/mesa/shader/slang/library/slang_pp_version_syn.h
new file mode 100644
index 00000000000..a75cf7509f0
--- /dev/null
+++ b/src/mesa/shader/slang/library/slang_pp_version_syn.h
@@ -0,0 +1,69 @@
+
+/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE .syn FILE */
+
+".syntax version_directive;\n"
+"version_directive\n"
+" version_directive_1 .and .loop version_directive_2;\n"
+"version_directive_1\n"
+" prior_optional_spaces .and optional_version_directive .and .true .emit $;\n"
+"version_directive_2\n"
+" prior_optional_spaces .and version_directive_body .and .true .emit $;\n"
+"optional_version_directive\n"
+" version_directive_body .or .true .emit 10 .emit 1;\n"
+"version_directive_body\n"
+" '#' .and optional_space .and \"version\" .and space .and version_number .and optional_space .and\n"
+" new_line;\n"
+"version_number\n"
+" version_number_110 .or version_number_120;\n"
+"version_number_110\n"
+" leading_zeroes .and \"110\" .emit 10 .emit 1;\n"
+"version_number_120\n"
+" leading_zeroes .and \"120\" .emit 20 .emit 1;\n"
+"leading_zeroes\n"
+" .loop zero;\n"
+"zero\n"
+" '0';\n"
+"space\n"
+" single_space .and .loop single_space;\n"
+"optional_space\n"
+" .loop single_space;\n"
+"single_space\n"
+" ' ' .or '\\t';\n"
+"prior_optional_spaces\n"
+" .loop prior_space;\n"
+"prior_space\n"
+" c_style_comment_block .or cpp_style_comment_block .or space .or new_line;\n"
+"c_style_comment_block\n"
+" '/' .and '*' .and c_style_comment_rest;\n"
+"c_style_comment_rest\n"
+" .loop c_style_comment_char_no_star .and c_style_comment_rest_1;\n"
+"c_style_comment_rest_1\n"
+" c_style_comment_end .or c_style_comment_rest_2;\n"
+"c_style_comment_rest_2\n"
+" '*' .and c_style_comment_rest;\n"
+"c_style_comment_char_no_star\n"
+" '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n"
+"c_style_comment_end\n"
+" '*' .and '/';\n"
+"cpp_style_comment_block\n"
+" '/' .and '/' .and cpp_style_comment_block_1;\n"
+"cpp_style_comment_block_1\n"
+" cpp_style_comment_block_2 .or cpp_style_comment_block_3;\n"
+"cpp_style_comment_block_2\n"
+" .loop cpp_style_comment_char .and new_line;\n"
+"cpp_style_comment_block_3\n"
+" .loop cpp_style_comment_char;\n"
+"cpp_style_comment_char\n"
+" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n"
+"new_line\n"
+" cr_lf .or lf_cr .or '\\n' .or '\\r';\n"
+"cr_lf\n"
+" '\\r' .and '\\n';\n"
+"lf_cr\n"
+" '\\n' .and '\\r';\n"
+".string __string_filter;\n"
+"__string_filter\n"
+" .loop __identifier_char;\n"
+"__identifier_char\n"
+" 'a'-'z' .or 'A'-'Z' .or '_' .or '0'-'9';\n"
+""
diff --git a/src/mesa/shader/slang/library/slang_shader_syn.h b/src/mesa/shader/slang/library/slang_shader_syn.h
new file mode 100644
index 00000000000..f08c329303c
--- /dev/null
+++ b/src/mesa/shader/slang/library/slang_shader_syn.h
@@ -0,0 +1,758 @@
+".syntax translation_unit;\n"
+".emtcode REVISION 3\n"
+".emtcode EXTERNAL_NULL 0\n"
+".emtcode EXTERNAL_FUNCTION_DEFINITION 1\n"
+".emtcode EXTERNAL_DECLARATION 2\n"
+".emtcode DECLARATION_FUNCTION_PROTOTYPE 1\n"
+".emtcode DECLARATION_INIT_DECLARATOR_LIST 2\n"
+".emtcode FUNCTION_ORDINARY 0\n"
+".emtcode FUNCTION_CONSTRUCTOR 1\n"
+".emtcode FUNCTION_OPERATOR 2\n"
+".emtcode OPERATOR_ADDASSIGN 1\n"
+".emtcode OPERATOR_SUBASSIGN 2\n"
+".emtcode OPERATOR_MULASSIGN 3\n"
+".emtcode OPERATOR_DIVASSIGN 4\n"
+".emtcode OPERATOR_LOGICALXOR 11\n"
+".emtcode OPERATOR_LESS 15\n"
+".emtcode OPERATOR_GREATER 16\n"
+".emtcode OPERATOR_LESSEQUAL 17\n"
+".emtcode OPERATOR_GREATEREQUAL 18\n"
+".emtcode OPERATOR_MULTIPLY 21\n"
+".emtcode OPERATOR_DIVIDE 22\n"
+".emtcode OPERATOR_INCREMENT 24\n"
+".emtcode OPERATOR_DECREMENT 25\n"
+".emtcode OPERATOR_PLUS 26\n"
+".emtcode OPERATOR_MINUS 27\n"
+".emtcode OPERATOR_NOT 29\n"
+".emtcode DECLARATOR_NONE 0\n"
+".emtcode DECLARATOR_NEXT 1\n"
+".emtcode VARIABLE_NONE 0\n"
+".emtcode VARIABLE_IDENTIFIER 1\n"
+".emtcode VARIABLE_INITIALIZER 2\n"
+".emtcode VARIABLE_ARRAY_EXPLICIT 3\n"
+".emtcode VARIABLE_ARRAY_UNKNOWN 4\n"
+".emtcode TYPE_QUALIFIER_NONE 0\n"
+".emtcode TYPE_QUALIFIER_CONST 1\n"
+".emtcode TYPE_QUALIFIER_ATTRIBUTE 2\n"
+".emtcode TYPE_QUALIFIER_VARYING 3\n"
+".emtcode TYPE_QUALIFIER_UNIFORM 4\n"
+".emtcode TYPE_QUALIFIER_FIXEDOUTPUT 5\n"
+".emtcode TYPE_QUALIFIER_FIXEDINPUT 6\n"
+".emtcode TYPE_SPECIFIER_VOID 0\n"
+".emtcode TYPE_SPECIFIER_BOOL 1\n"
+".emtcode TYPE_SPECIFIER_BVEC2 2\n"
+".emtcode TYPE_SPECIFIER_BVEC3 3\n"
+".emtcode TYPE_SPECIFIER_BVEC4 4\n"
+".emtcode TYPE_SPECIFIER_INT 5\n"
+".emtcode TYPE_SPECIFIER_IVEC2 6\n"
+".emtcode TYPE_SPECIFIER_IVEC3 7\n"
+".emtcode TYPE_SPECIFIER_IVEC4 8\n"
+".emtcode TYPE_SPECIFIER_FLOAT 9\n"
+".emtcode TYPE_SPECIFIER_VEC2 10\n"
+".emtcode TYPE_SPECIFIER_VEC3 11\n"
+".emtcode TYPE_SPECIFIER_VEC4 12\n"
+".emtcode TYPE_SPECIFIER_MAT2 13\n"
+".emtcode TYPE_SPECIFIER_MAT3 14\n"
+".emtcode TYPE_SPECIFIER_MAT4 15\n"
+".emtcode TYPE_SPECIFIER_SAMPLER1D 16\n"
+".emtcode TYPE_SPECIFIER_SAMPLER2D 17\n"
+".emtcode TYPE_SPECIFIER_SAMPLER3D 18\n"
+".emtcode TYPE_SPECIFIER_SAMPLERCUBE 19\n"
+".emtcode TYPE_SPECIFIER_SAMPLER1DSHADOW 20\n"
+".emtcode TYPE_SPECIFIER_SAMPLER2DSHADOW 21\n"
+".emtcode TYPE_SPECIFIER_STRUCT 22\n"
+".emtcode TYPE_SPECIFIER_TYPENAME 23\n"
+".emtcode FIELD_NONE 0\n"
+".emtcode FIELD_NEXT 1\n"
+".emtcode FIELD_ARRAY 2\n"
+".emtcode OP_END 0\n"
+".emtcode OP_BLOCK_BEGIN_NO_NEW_SCOPE 1\n"
+".emtcode OP_BLOCK_BEGIN_NEW_SCOPE 2\n"
+".emtcode OP_DECLARE 3\n"
+".emtcode OP_ASM 4\n"
+".emtcode OP_BREAK 5\n"
+".emtcode OP_CONTINUE 6\n"
+".emtcode OP_DISCARD 7\n"
+".emtcode OP_RETURN 8\n"
+".emtcode OP_EXPRESSION 9\n"
+".emtcode OP_IF 10\n"
+".emtcode OP_WHILE 11\n"
+".emtcode OP_DO 12\n"
+".emtcode OP_FOR 13\n"
+".emtcode OP_PUSH_VOID 14\n"
+".emtcode OP_PUSH_BOOL 15\n"
+".emtcode OP_PUSH_INT 16\n"
+".emtcode OP_PUSH_FLOAT 17\n"
+".emtcode OP_PUSH_IDENTIFIER 18\n"
+".emtcode OP_SEQUENCE 19\n"
+".emtcode OP_ASSIGN 20\n"
+".emtcode OP_ADDASSIGN 21\n"
+".emtcode OP_SUBASSIGN 22\n"
+".emtcode OP_MULASSIGN 23\n"
+".emtcode OP_DIVASSIGN 24\n"
+".emtcode OP_SELECT 31\n"
+".emtcode OP_LOGICALOR 32\n"
+".emtcode OP_LOGICALXOR 33\n"
+".emtcode OP_LOGICALAND 34\n"
+".emtcode OP_EQUAL 38\n"
+".emtcode OP_NOTEQUAL 39\n"
+".emtcode OP_LESS 40\n"
+".emtcode OP_GREATER 41\n"
+".emtcode OP_LESSEQUAL 42\n"
+".emtcode OP_GREATEREQUAL 43\n"
+".emtcode OP_ADD 46\n"
+".emtcode OP_SUBTRACT 47\n"
+".emtcode OP_MULTIPLY 48\n"
+".emtcode OP_DIVIDE 49\n"
+".emtcode OP_PREINCREMENT 51\n"
+".emtcode OP_PREDECREMENT 52\n"
+".emtcode OP_PLUS 53\n"
+".emtcode OP_MINUS 54\n"
+".emtcode OP_NOT 56\n"
+".emtcode OP_SUBSCRIPT 57\n"
+".emtcode OP_CALL 58\n"
+".emtcode OP_FIELD 59\n"
+".emtcode OP_POSTINCREMENT 60\n"
+".emtcode OP_POSTDECREMENT 61\n"
+".emtcode PARAM_QUALIFIER_IN 0\n"
+".emtcode PARAM_QUALIFIER_OUT 1\n"
+".emtcode PARAM_QUALIFIER_INOUT 2\n"
+".emtcode PARAMETER_NONE 0\n"
+".emtcode PARAMETER_NEXT 1\n"
+".emtcode PARAMETER_ARRAY_NOT_PRESENT 0\n"
+".emtcode PARAMETER_ARRAY_PRESENT 1\n"
+".errtext INVALID_EXTERNAL_DECLARATION \"2001: Invalid external declaration.\"\n"
+".errtext INVALID_OPERATOR_OVERRIDE \"2002: Invalid operator override.\"\n"
+".errtext LBRACE_EXPECTED \"2003: '{' expected but '$err_token$' found.\"\n"
+".errtext LPAREN_EXPECTED \"2004: '(' expected but '$err_token$' found.\"\n"
+".errtext RPAREN_EXPECTED \"2005: ')' expected but '$err_token$' found.\"\n"
+".regbyte parsing_builtin 0\n"
+".regbyte shader_type 0\n"
+"variable_identifier\n"
+" identifier .emit OP_PUSH_IDENTIFIER;\n"
+"primary_expression\n"
+" floatconstant .or boolconstant .or intconstant .or variable_identifier .or primary_expression_1;\n"
+"primary_expression_1\n"
+" lparen .and expression .and rparen;\n"
+"postfix_expression\n"
+" postfix_expression_1 .and .loop postfix_expression_2;\n"
+"postfix_expression_1\n"
+" function_call .or primary_expression;\n"
+"postfix_expression_2\n"
+" postfix_expression_3 .or postfix_expression_4 .or\n"
+" plusplus .emit OP_POSTINCREMENT .or\n"
+" minusminus .emit OP_POSTDECREMENT;\n"
+"postfix_expression_3\n"
+" lbracket .and integer_expression .and rbracket .emit OP_SUBSCRIPT;\n"
+"postfix_expression_4\n"
+" dot .and field_selection .emit OP_FIELD;\n"
+"integer_expression\n"
+" expression;\n"
+"function_call\n"
+" function_call_generic .emit OP_CALL .and .true .emit OP_END;\n"
+"function_call_generic\n"
+" function_call_generic_1 .or function_call_generic_2;\n"
+"function_call_generic_1\n"
+" function_call_header_with_parameters .and rparen .error RPAREN_EXPECTED;\n"
+"function_call_generic_2\n"
+" function_call_header_no_parameters .and rparen .error RPAREN_EXPECTED;\n"
+"function_call_header_no_parameters\n"
+" function_call_header .and function_call_header_no_parameters_1;\n"
+"function_call_header_no_parameters_1\n"
+" \"void\" .or .true;\n"
+"function_call_header_with_parameters\n"
+" function_call_header .and assignment_expression .and .true .emit OP_END .and\n"
+" .loop function_call_header_with_parameters_1;\n"
+"function_call_header_with_parameters_1\n"
+" comma .and assignment_expression .and .true .emit OP_END;\n"
+"function_call_header\n"
+" function_identifier .and lparen;\n"
+"function_identifier\n"
+" identifier;\n"
+"unary_expression\n"
+" postfix_expression .or unary_expression_1 .or unary_expression_2 .or unary_expression_3 .or\n"
+" unary_expression_4 .or unary_expression_5;\n"
+"unary_expression_1\n"
+" plusplus .and unary_expression .and .true .emit OP_PREINCREMENT;\n"
+"unary_expression_2\n"
+" minusminus .and unary_expression .and .true .emit OP_PREDECREMENT;\n"
+"unary_expression_3\n"
+" plus .and unary_expression .and .true .emit OP_PLUS;\n"
+"unary_expression_4\n"
+" minus .and unary_expression .and .true .emit OP_MINUS;\n"
+"unary_expression_5\n"
+" bang .and unary_expression .and .true .emit OP_NOT;\n"
+"multiplicative_expression\n"
+" unary_expression .and .loop multiplicative_expression_1;\n"
+"multiplicative_expression_1\n"
+" multiplicative_expression_2 .or multiplicative_expression_3;\n"
+"multiplicative_expression_2\n"
+" star .and unary_expression .and .true .emit OP_MULTIPLY;\n"
+"multiplicative_expression_3\n"
+" slash .and unary_expression .and .true .emit OP_DIVIDE;\n"
+"additive_expression\n"
+" multiplicative_expression .and .loop additive_expression_1;\n"
+"additive_expression_1\n"
+" additive_expression_2 .or additive_expression_3;\n"
+"additive_expression_2\n"
+" plus .and multiplicative_expression .and .true .emit OP_ADD;\n"
+"additive_expression_3\n"
+" minus .and multiplicative_expression .and .true .emit OP_SUBTRACT;\n"
+"shift_expression\n"
+" additive_expression;\n"
+"relational_expression\n"
+" shift_expression .and .loop relational_expression_1;\n"
+"relational_expression_1\n"
+" relational_expression_2 .or relational_expression_3 .or relational_expression_4 .or\n"
+" relational_expression_5;\n"
+"relational_expression_2\n"
+" lessequals .and shift_expression .and .true .emit OP_LESSEQUAL;\n"
+"relational_expression_3\n"
+" greaterequals .and shift_expression .and .true .emit OP_GREATEREQUAL;\n"
+"relational_expression_4\n"
+" less .and shift_expression .and .true .emit OP_LESS;\n"
+"relational_expression_5\n"
+" greater .and shift_expression .and .true .emit OP_GREATER;\n"
+"equality_expression\n"
+" relational_expression .and .loop equality_expression_1;\n"
+"equality_expression_1\n"
+" equality_expression_2 .or equality_expression_3;\n"
+"equality_expression_2\n"
+" equalsequals .and relational_expression .and .true .emit OP_EQUAL;\n"
+"equality_expression_3\n"
+" bangequals .and relational_expression .and .true .emit OP_NOTEQUAL;\n"
+"and_expression\n"
+" equality_expression;\n"
+"exclusive_or_expression\n"
+" and_expression;\n"
+"inclusive_or_expression\n"
+" exclusive_or_expression;\n"
+"logical_and_expression\n"
+" inclusive_or_expression .and .loop logical_and_expression_1;\n"
+"logical_and_expression_1\n"
+" ampersandampersand .and inclusive_or_expression .and .true .emit OP_LOGICALAND;\n"
+"logical_xor_expression\n"
+" logical_and_expression .and .loop logical_xor_expression_1;\n"
+"logical_xor_expression_1\n"
+" caretcaret .and logical_and_expression .and .true .emit OP_LOGICALXOR;\n"
+"logical_or_expression\n"
+" logical_xor_expression .and .loop logical_or_expression_1;\n"
+"logical_or_expression_1\n"
+" barbar .and logical_xor_expression .and .true .emit OP_LOGICALOR;\n"
+"conditional_expression\n"
+" logical_or_expression .and .loop conditional_expression_1;\n"
+"conditional_expression_1\n"
+" question .and expression .and colon .and conditional_expression .and .true .emit OP_SELECT;\n"
+"assignment_expression\n"
+" assignment_expression_1 .or assignment_expression_2 .or assignment_expression_3 .or\n"
+" assignment_expression_4 .or assignment_expression_5 .or conditional_expression;\n"
+"assignment_expression_1\n"
+" unary_expression .and equals .and assignment_expression .and .true .emit OP_ASSIGN;\n"
+"assignment_expression_2\n"
+" unary_expression .and starequals .and assignment_expression .and .true .emit OP_MULASSIGN;\n"
+"assignment_expression_3\n"
+" unary_expression .and slashequals .and assignment_expression .and .true .emit OP_DIVASSIGN;\n"
+"assignment_expression_4\n"
+" unary_expression .and plusequals .and assignment_expression .and .true .emit OP_ADDASSIGN;\n"
+"assignment_expression_5\n"
+" unary_expression .and minusequals .and assignment_expression .and .true .emit OP_SUBASSIGN;\n"
+"expression\n"
+" assignment_expression .and .loop expression_1;\n"
+"expression_1\n"
+" comma .and assignment_expression .and .true .emit OP_SEQUENCE;\n"
+"constant_expression\n"
+" conditional_expression .and .true .emit OP_END;\n"
+"declaration\n"
+" declaration_1 .or declaration_2;\n"
+"declaration_1\n"
+" function_prototype .emit DECLARATION_FUNCTION_PROTOTYPE .and semicolon;\n"
+"declaration_2\n"
+" init_declarator_list .emit DECLARATION_INIT_DECLARATOR_LIST .and semicolon;\n"
+"function_prototype\n"
+" function_prototype_1 .or function_prototype_2;\n"
+"function_prototype_1\n"
+" function_header .and \"void\" .and rparen .error RPAREN_EXPECTED .emit PARAMETER_NONE;\n"
+"function_prototype_2\n"
+" function_declarator .and rparen .error RPAREN_EXPECTED .emit PARAMETER_NONE;\n"
+"function_declarator\n"
+" function_header_with_parameters .or function_header;\n"
+"function_header_with_parameters\n"
+" function_header .and parameter_declaration .and .loop function_header_with_parameters_1;\n"
+"function_header_with_parameters_1\n"
+" comma .and parameter_declaration;\n"
+"function_header\n"
+" function_header_nospace .or function_header_space;\n"
+"function_header_space\n"
+" fully_specified_type_space .and space .and function_decl_identifier .and lparen;\n"
+"function_header_nospace\n"
+" fully_specified_type_nospace .and function_decl_identifier .and lparen;\n"
+"function_decl_identifier\n"
+" .if (parsing_builtin != 0) __operator .emit FUNCTION_OPERATOR .or\n"
+" .if (parsing_builtin != 0) \"__constructor\" .emit FUNCTION_CONSTRUCTOR .or\n"
+" identifier .emit FUNCTION_ORDINARY;\n"
+"__operator\n"
+" \"__operator\" .and overriden_operator .error INVALID_OPERATOR_OVERRIDE;\n"
+"overriden_operator\n"
+" plusplus .emit OPERATOR_INCREMENT .or\n"
+" plusequals .emit OPERATOR_ADDASSIGN .or\n"
+" plus .emit OPERATOR_PLUS .or\n"
+" minusminus .emit OPERATOR_DECREMENT .or\n"
+" minusequals .emit OPERATOR_SUBASSIGN .or\n"
+" minus .emit OPERATOR_MINUS .or\n"
+" bang .emit OPERATOR_NOT .or\n"
+" starequals .emit OPERATOR_MULASSIGN .or\n"
+" star .emit OPERATOR_MULTIPLY .or\n"
+" slashequals .emit OPERATOR_DIVASSIGN .or\n"
+" slash .emit OPERATOR_DIVIDE .or\n"
+" lessequals .emit OPERATOR_LESSEQUAL .or\n"
+" \n"
+" \n"
+" less .emit OPERATOR_LESS .or\n"
+" greaterequals .emit OPERATOR_GREATEREQUAL .or\n"
+" \n"
+" \n"
+" greater .emit OPERATOR_GREATER .or\n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+" caretcaret .emit OPERATOR_LOGICALXOR ;\n"
+"parameter_declarator\n"
+" parameter_declarator_nospace .or parameter_declarator_space;\n"
+"parameter_declarator_nospace\n"
+" type_specifier_nospace .and identifier .and parameter_declarator_1;\n"
+"parameter_declarator_space\n"
+" type_specifier_space .and space .and identifier .and parameter_declarator_1;\n"
+"parameter_declarator_1\n"
+" parameter_declarator_2 .emit PARAMETER_ARRAY_PRESENT .or\n"
+" .true .emit PARAMETER_ARRAY_NOT_PRESENT;\n"
+"parameter_declarator_2\n"
+" lbracket .and constant_expression .and rbracket;\n"
+"parameter_declaration\n"
+" parameter_declaration_1 .emit PARAMETER_NEXT;\n"
+"parameter_declaration_1\n"
+" parameter_declaration_2 .or parameter_declaration_3;\n"
+"parameter_declaration_2\n"
+" type_qualifier .and space .and parameter_qualifier .and parameter_declaration_4;\n"
+"parameter_declaration_3\n"
+" parameter_qualifier .emit TYPE_QUALIFIER_NONE .and parameter_declaration_4;\n"
+"parameter_declaration_4\n"
+" parameter_declarator .or parameter_type_specifier;\n"
+"parameter_qualifier\n"
+" parameter_qualifier_1 .or .true .emit PARAM_QUALIFIER_IN;\n"
+"parameter_qualifier_1\n"
+" parameter_qualifier_2 .and space;\n"
+"parameter_qualifier_2\n"
+" \"in\" .emit PARAM_QUALIFIER_IN .or\n"
+" \"out\" .emit PARAM_QUALIFIER_OUT .or\n"
+" \"inout\" .emit PARAM_QUALIFIER_INOUT;\n"
+"parameter_type_specifier\n"
+" parameter_type_specifier_1 .and .true .emit '\\0' .and parameter_type_specifier_2;\n"
+"parameter_type_specifier_1\n"
+" type_specifier_nospace .or type_specifier_space;\n"
+"parameter_type_specifier_2\n"
+" parameter_type_specifier_3 .emit PARAMETER_ARRAY_PRESENT .or\n"
+" .true .emit PARAMETER_ARRAY_NOT_PRESENT;\n"
+"parameter_type_specifier_3\n"
+" lbracket .and constant_expression .and rbracket;\n"
+"init_declarator_list\n"
+" single_declaration .and .loop init_declarator_list_1 .emit DECLARATOR_NEXT .and\n"
+" .true .emit DECLARATOR_NONE;\n"
+"init_declarator_list_1\n"
+" comma .and identifier .emit VARIABLE_IDENTIFIER .and init_declarator_list_2;\n"
+"init_declarator_list_2\n"
+" init_declarator_list_3 .or init_declarator_list_4 .or .true .emit VARIABLE_NONE;\n"
+"init_declarator_list_3\n"
+" equals .and initializer .emit VARIABLE_INITIALIZER;\n"
+"init_declarator_list_4\n"
+" lbracket .and init_declarator_list_5 .and rbracket;\n"
+"init_declarator_list_5\n"
+" constant_expression .emit VARIABLE_ARRAY_EXPLICIT .or .true .emit VARIABLE_ARRAY_UNKNOWN;\n"
+"single_declaration\n"
+" single_declaration_nospace .or single_declaration_space;\n"
+"single_declaration_space\n"
+" fully_specified_type_space .and single_declaration_space_1;\n"
+"single_declaration_nospace\n"
+" fully_specified_type_nospace .and single_declaration_nospace_1;\n"
+"single_declaration_space_1\n"
+" single_declaration_space_2 .emit VARIABLE_IDENTIFIER .or .true .emit VARIABLE_NONE;\n"
+"single_declaration_nospace_1\n"
+" single_declaration_nospace_2 .emit VARIABLE_IDENTIFIER .or .true .emit VARIABLE_NONE;\n"
+"single_declaration_space_2\n"
+" space .and identifier .and single_declaration_3;\n"
+"single_declaration_nospace_2\n"
+" identifier .and single_declaration_3;\n"
+"single_declaration_3\n"
+" single_declaration_4 .or single_declaration_5 .or .true .emit VARIABLE_NONE;\n"
+"single_declaration_4\n"
+" equals .and initializer .emit VARIABLE_INITIALIZER;\n"
+"single_declaration_5\n"
+" lbracket .and single_declaration_6 .and rbracket;\n"
+"single_declaration_6\n"
+" constant_expression .emit VARIABLE_ARRAY_EXPLICIT .or .true .emit VARIABLE_ARRAY_UNKNOWN;\n"
+"fully_specified_type_space\n"
+" fully_specified_type_1 .and type_specifier_space;\n"
+"fully_specified_type_nospace\n"
+" fully_specified_type_1 .and type_specifier_nospace;\n"
+"fully_specified_type_1\n"
+" fully_specified_type_2 .or .true .emit TYPE_QUALIFIER_NONE;\n"
+"fully_specified_type_2\n"
+" type_qualifier .and space;\n"
+"type_qualifier\n"
+" \"const\" .emit TYPE_QUALIFIER_CONST .or\n"
+" .if (shader_type == 2) \"attribute\" .emit TYPE_QUALIFIER_ATTRIBUTE .or\n"
+" \"varying\" .emit TYPE_QUALIFIER_VARYING .or\n"
+" \"uniform\" .emit TYPE_QUALIFIER_UNIFORM .or\n"
+" .if (parsing_builtin != 0) \"__fixed_output\" .emit TYPE_QUALIFIER_FIXEDOUTPUT .or\n"
+" .if (parsing_builtin != 0) \"__fixed_input\" .emit TYPE_QUALIFIER_FIXEDINPUT;\n"
+"type_specifier_space\n"
+" \"void\" .emit TYPE_SPECIFIER_VOID .or\n"
+" \"float\" .emit TYPE_SPECIFIER_FLOAT .or\n"
+" \"int\" .emit TYPE_SPECIFIER_INT .or\n"
+" \"bool\" .emit TYPE_SPECIFIER_BOOL .or\n"
+" \"vec2\" .emit TYPE_SPECIFIER_VEC2 .or\n"
+" \"vec3\" .emit TYPE_SPECIFIER_VEC3 .or\n"
+" \"vec4\" .emit TYPE_SPECIFIER_VEC4 .or\n"
+" \"bvec2\" .emit TYPE_SPECIFIER_BVEC2 .or\n"
+" \"bvec3\" .emit TYPE_SPECIFIER_BVEC3 .or\n"
+" \"bvec4\" .emit TYPE_SPECIFIER_BVEC4 .or\n"
+" \"ivec2\" .emit TYPE_SPECIFIER_IVEC2 .or\n"
+" \"ivec3\" .emit TYPE_SPECIFIER_IVEC3 .or\n"
+" \"ivec4\" .emit TYPE_SPECIFIER_IVEC4 .or\n"
+" \"mat2\" .emit TYPE_SPECIFIER_MAT2 .or\n"
+" \"mat3\" .emit TYPE_SPECIFIER_MAT3 .or\n"
+" \"mat4\" .emit TYPE_SPECIFIER_MAT4 .or\n"
+" \"sampler1D\" .emit TYPE_SPECIFIER_SAMPLER1D .or\n"
+" \"sampler2D\" .emit TYPE_SPECIFIER_SAMPLER2D .or\n"
+" \"sampler3D\" .emit TYPE_SPECIFIER_SAMPLER3D .or\n"
+" \"samplerCube\" .emit TYPE_SPECIFIER_SAMPLERCUBE .or\n"
+" \"sampler1DShadow\" .emit TYPE_SPECIFIER_SAMPLER1DSHADOW .or\n"
+" \"sampler2DShadow\" .emit TYPE_SPECIFIER_SAMPLER2DSHADOW .or\n"
+" type_name .emit TYPE_SPECIFIER_TYPENAME;\n"
+"type_specifier_nospace\n"
+" struct_specifier .emit TYPE_SPECIFIER_STRUCT;\n"
+"struct_specifier\n"
+" \"struct\" .and struct_specifier_1 .and optional_space .and lbrace .error LBRACE_EXPECTED .and\n"
+" struct_declaration_list .and rbrace .emit FIELD_NONE;\n"
+"struct_specifier_1\n"
+" struct_specifier_2 .or .true .emit '\\0';\n"
+"struct_specifier_2\n"
+" space .and identifier;\n"
+"struct_declaration_list\n"
+" struct_declaration .and .loop struct_declaration .emit FIELD_NEXT;\n"
+"struct_declaration\n"
+" struct_declaration_nospace .or struct_declaration_space;\n"
+"struct_declaration_space\n"
+" type_specifier_space .and space .and struct_declarator_list .and semicolon .emit FIELD_NONE;\n"
+"struct_declaration_nospace\n"
+" type_specifier_nospace .and struct_declarator_list .and semicolon .emit FIELD_NONE;\n"
+"struct_declarator_list\n"
+" struct_declarator .and .loop struct_declarator_list_1 .emit FIELD_NEXT;\n"
+"struct_declarator_list_1\n"
+" comma .and struct_declarator;\n"
+"struct_declarator\n"
+" identifier .and struct_declarator_1;\n"
+"struct_declarator_1\n"
+" struct_declarator_2 .emit FIELD_ARRAY .or .true .emit FIELD_NONE;\n"
+"struct_declarator_2\n"
+" lbracket .and constant_expression .and rbracket;\n"
+"initializer\n"
+" assignment_expression .and .true .emit OP_END;\n"
+"declaration_statement\n"
+" declaration;\n"
+"statement\n"
+" compound_statement .or simple_statement;\n"
+"statement_space\n"
+" compound_statement .or statement_space_1;\n"
+"statement_space_1\n"
+" space .and simple_statement;\n"
+"simple_statement\n"
+" .if (parsing_builtin != 0) __asm_statement .emit OP_ASM .or\n"
+" selection_statement .or\n"
+" iteration_statement .or\n"
+" jump_statement .or\n"
+" expression_statement .emit OP_EXPRESSION .or\n"
+" declaration_statement .emit OP_DECLARE;\n"
+"compound_statement\n"
+" compound_statement_1 .emit OP_BLOCK_BEGIN_NEW_SCOPE .and .true .emit OP_END;\n"
+"compound_statement_1\n"
+" compound_statement_2 .or compound_statement_3;\n"
+"compound_statement_2\n"
+" lbrace .and rbrace;\n"
+"compound_statement_3\n"
+" lbrace .and statement_list .and rbrace;\n"
+"statement_no_new_scope\n"
+" compound_statement_no_new_scope .or simple_statement;\n"
+"compound_statement_no_new_scope\n"
+" compound_statement_no_new_scope_1 .emit OP_BLOCK_BEGIN_NO_NEW_SCOPE .and .true .emit OP_END;\n"
+"compound_statement_no_new_scope_1\n"
+" compound_statement_no_new_scope_2 .or compound_statement_no_new_scope_3;\n"
+"compound_statement_no_new_scope_2\n"
+" lbrace .and rbrace;\n"
+"compound_statement_no_new_scope_3\n"
+" lbrace .and statement_list .and rbrace;\n"
+"statement_list\n"
+" statement .and .loop statement;\n"
+"expression_statement\n"
+" expression_statement_1 .or expression_statement_2;\n"
+"expression_statement_1\n"
+" semicolon .emit OP_PUSH_VOID .emit OP_END;\n"
+"expression_statement_2\n"
+" expression .and semicolon .emit OP_END;\n"
+"selection_statement\n"
+" \"if\" .emit OP_IF .and lparen .error LPAREN_EXPECTED .and expression .and\n"
+" rparen .error RPAREN_EXPECTED .emit OP_END .and selection_rest_statement;\n"
+"selection_rest_statement\n"
+" statement .and selection_rest_statement_1;\n"
+"selection_rest_statement_1\n"
+" selection_rest_statement_2 .or .true .emit OP_EXPRESSION .emit OP_PUSH_VOID .emit OP_END;\n"
+"selection_rest_statement_2\n"
+" \"else\" .and optional_space .and statement;\n"
+"condition\n"
+" condition_1 .emit OP_DECLARE .emit DECLARATION_INIT_DECLARATOR_LIST .or\n"
+" condition_3 .emit OP_EXPRESSION;\n"
+"condition_1\n"
+" condition_1_nospace .or condition_1_space;\n"
+"condition_1_nospace\n"
+" fully_specified_type_nospace .and condition_2;\n"
+"condition_1_space\n"
+" fully_specified_type_space .and space .and condition_2;\n"
+"condition_2\n"
+" identifier .emit VARIABLE_IDENTIFIER .and equals .emit VARIABLE_INITIALIZER .and\n"
+" initializer .and .true .emit DECLARATOR_NONE;\n"
+"condition_3\n"
+" expression .and .true .emit OP_END;\n"
+"iteration_statement\n"
+" iteration_statement_1 .or iteration_statement_2 .or iteration_statement_3;\n"
+"iteration_statement_1\n"
+" \"while\" .emit OP_WHILE .and lparen .error LPAREN_EXPECTED .and condition .and\n"
+" rparen .error RPAREN_EXPECTED .and statement_no_new_scope;\n"
+"iteration_statement_2\n"
+" \"do\" .emit OP_DO .and statement_space .and \"while\" .and lparen .error LPAREN_EXPECTED .and\n"
+" expression .and rparen .error RPAREN_EXPECTED .emit OP_END .and semicolon;\n"
+"iteration_statement_3\n"
+" \"for\" .emit OP_FOR .and lparen .error LPAREN_EXPECTED .and for_init_statement .and\n"
+" for_rest_statement .and rparen .error RPAREN_EXPECTED .and statement_no_new_scope;\n"
+"for_init_statement\n"
+" expression_statement .emit OP_EXPRESSION .or declaration_statement .emit OP_DECLARE;\n"
+"conditionopt\n"
+" condition .or\n"
+" .true .emit OP_EXPRESSION .emit OP_PUSH_BOOL .emit 2 .emit '1' .emit '\\0' .emit OP_END;\n"
+"for_rest_statement\n"
+" conditionopt .and semicolon .and for_rest_statement_1;\n"
+"for_rest_statement_1\n"
+" for_rest_statement_2 .or .true .emit OP_PUSH_VOID .emit OP_END;\n"
+"for_rest_statement_2\n"
+" expression .and .true .emit OP_END;\n"
+"jump_statement\n"
+" jump_statement_1 .or jump_statement_2 .or jump_statement_3 .or jump_statement_4 .or\n"
+" .if (shader_type == 1) jump_statement_5;\n"
+"jump_statement_1\n"
+" \"continue\" .and semicolon .emit OP_CONTINUE;\n"
+"jump_statement_2\n"
+" \"break\" .and semicolon .emit OP_BREAK;\n"
+"jump_statement_3\n"
+" \"return\" .emit OP_RETURN .and optional_space .and expression .and semicolon .emit OP_END;\n"
+"jump_statement_4\n"
+" \"return\" .emit OP_RETURN .and semicolon .emit OP_PUSH_VOID .emit OP_END;\n"
+"jump_statement_5\n"
+" \"discard\" .and semicolon .emit OP_DISCARD;\n"
+"__asm_statement\n"
+" \"__asm\" .and space .and identifier .and space .and asm_arguments .and semicolon .emit OP_END;\n"
+"asm_arguments\n"
+" asm_argument .and .true .emit OP_END .and .loop asm_arguments_1;\n"
+"asm_arguments_1\n"
+" comma .and asm_argument .and .true .emit OP_END;\n"
+"asm_argument\n"
+" variable_identifier .or floatconstant;\n"
+"translation_unit\n"
+" optional_space .emit REVISION .and external_declaration .error INVALID_EXTERNAL_DECLARATION .and\n"
+" .loop external_declaration .and optional_space .and\n"
+" '\\0' .error INVALID_EXTERNAL_DECLARATION .emit EXTERNAL_NULL;\n"
+"external_declaration\n"
+" function_definition .emit EXTERNAL_FUNCTION_DEFINITION .or\n"
+" declaration .emit EXTERNAL_DECLARATION;\n"
+"function_definition\n"
+" function_prototype .and compound_statement_no_new_scope;\n"
+"digit_oct\n"
+" '0'-'7';\n"
+"digit_dec\n"
+" '0'-'9';\n"
+"digit_hex\n"
+" '0'-'9' .or 'A'-'F' .or 'a'-'f';\n"
+"id_character_first\n"
+" 'a'-'z' .or 'A'-'Z' .or '_';\n"
+"id_character_next\n"
+" id_character_first .or digit_dec;\n"
+"identifier\n"
+" id_character_first .emit * .and .loop id_character_next .emit * .and .true .emit '\\0';\n"
+"float\n"
+" float_1 .or float_2;\n"
+"float_1\n"
+" float_fractional_constant .and float_optional_exponent_part;\n"
+"float_2\n"
+" float_digit_sequence .and .true .emit '\\0' .and float_exponent_part;\n"
+"float_fractional_constant\n"
+" float_fractional_constant_1 .or float_fractional_constant_2 .or float_fractional_constant_3;\n"
+"float_fractional_constant_1\n"
+" float_digit_sequence .and '.' .and float_digit_sequence;\n"
+"float_fractional_constant_2\n"
+" float_digit_sequence .and '.' .and .true .emit '\\0';\n"
+"float_fractional_constant_3\n"
+" '.' .emit '\\0' .and float_digit_sequence;\n"
+"float_optional_exponent_part\n"
+" float_exponent_part .or .true .emit '\\0';\n"
+"float_digit_sequence\n"
+" digit_dec .emit * .and .loop digit_dec .emit * .and .true .emit '\\0';\n"
+"float_exponent_part\n"
+" float_exponent_part_1 .or float_exponent_part_2;\n"
+"float_exponent_part_1\n"
+" 'e' .and float_optional_sign .and float_digit_sequence;\n"
+"float_exponent_part_2\n"
+" 'E' .and float_optional_sign .and float_digit_sequence;\n"
+"float_optional_sign\n"
+" float_sign .or .true;\n"
+"float_sign\n"
+" '+' .or '-' .emit '-';\n"
+"integer\n"
+" integer_hex .or integer_oct .or integer_dec;\n"
+"integer_hex\n"
+" '0' .and integer_hex_1 .emit 0x10 .and digit_hex .emit * .and .loop digit_hex .emit * .and\n"
+" .true .emit '\\0';\n"
+"integer_hex_1\n"
+" 'x' .or 'X';\n"
+"integer_oct\n"
+" '0' .emit 8 .emit * .and .loop digit_oct .emit * .and .true .emit '\\0';\n"
+"integer_dec\n"
+" digit_dec .emit 10 .emit * .and .loop digit_dec .emit * .and .true .emit '\\0';\n"
+"boolean\n"
+" \"true\" .emit 2 .emit '1' .emit '\\0' .or\n"
+" \"false\" .emit 2 .emit '0' .emit '\\0';\n"
+"type_name\n"
+" identifier;\n"
+"field_selection\n"
+" identifier;\n"
+"floatconstant\n"
+" float .emit OP_PUSH_FLOAT;\n"
+"intconstant\n"
+" integer .emit OP_PUSH_INT;\n"
+"boolconstant\n"
+" boolean .emit OP_PUSH_BOOL;\n"
+"optional_space\n"
+" .loop single_space;\n"
+"space\n"
+" single_space .and .loop single_space;\n"
+"single_space\n"
+" white_char .or c_style_comment_block .or cpp_style_comment_block;\n"
+"white_char\n"
+" ' ' .or '\\t' .or new_line .or '\\v' .or '\\f';\n"
+"new_line\n"
+" cr_lf .or lf_cr .or '\\n' .or '\\r';\n"
+"cr_lf\n"
+" '\\r' .and '\\n';\n"
+"lf_cr\n"
+" '\\n' .and '\\r';\n"
+"c_style_comment_block\n"
+" '/' .and '*' .and c_style_comment_rest;\n"
+"c_style_comment_rest\n"
+" .loop c_style_comment_char_no_star .and c_style_comment_rest_1;\n"
+"c_style_comment_rest_1\n"
+" c_style_comment_end .or c_style_comment_rest_2;\n"
+"c_style_comment_rest_2\n"
+" '*' .and c_style_comment_rest;\n"
+"c_style_comment_char_no_star\n"
+" '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n"
+"c_style_comment_end\n"
+" '*' .and '/';\n"
+"cpp_style_comment_block\n"
+" '/' .and '/' .and cpp_style_comment_block_1;\n"
+"cpp_style_comment_block_1\n"
+" cpp_style_comment_block_2 .or cpp_style_comment_block_3;\n"
+"cpp_style_comment_block_2\n"
+" .loop cpp_style_comment_char .and new_line;\n"
+"cpp_style_comment_block_3\n"
+" .loop cpp_style_comment_char;\n"
+"cpp_style_comment_char\n"
+" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n"
+"ampersandampersand\n"
+" optional_space .and '&' .and '&' .and optional_space;\n"
+"barbar\n"
+" optional_space .and '|' .and '|' .and optional_space;\n"
+"bang\n"
+" optional_space .and '!' .and optional_space;\n"
+"bangequals\n"
+" optional_space .and '!' .and '=' .and optional_space;\n"
+"caretcaret\n"
+" optional_space .and '^' .and '^' .and optional_space;\n"
+"colon\n"
+" optional_space .and ':' .and optional_space;\n"
+"comma\n"
+" optional_space .and ',' .and optional_space;\n"
+"dot\n"
+" optional_space .and '.' .and optional_space;\n"
+"equals\n"
+" optional_space .and '=' .and optional_space;\n"
+"equalsequals\n"
+" optional_space .and '=' .and '=' .and optional_space;\n"
+"greater\n"
+" optional_space .and '>' .and optional_space;\n"
+"greaterequals\n"
+" optional_space .and '>' .and '=' .and optional_space;\n"
+"lbrace\n"
+" optional_space .and '{' .and optional_space;\n"
+"lbracket\n"
+" optional_space .and '[' .and optional_space;\n"
+"less\n"
+" optional_space .and '<' .and optional_space;\n"
+"lessequals\n"
+" optional_space .and '<' .and '=' .and optional_space;\n"
+"lparen\n"
+" optional_space .and '(' .and optional_space;\n"
+"minus\n"
+" optional_space .and '-' .and optional_space;\n"
+"minusequals\n"
+" optional_space .and '-' .and '=' .and optional_space;\n"
+"minusminus\n"
+" optional_space .and '-' .and '-' .and optional_space;\n"
+"plus\n"
+" optional_space .and '+' .and optional_space;\n"
+"plusequals\n"
+" optional_space .and '+' .and '=' .and optional_space;\n"
+"plusplus\n"
+" optional_space .and '+' .and '+' .and optional_space;\n"
+"question\n"
+" optional_space .and '?' .and optional_space;\n"
+"rbrace\n"
+" optional_space .and '}' .and optional_space;\n"
+"rbracket\n"
+" optional_space .and ']' .and optional_space;\n"
+"rparen\n"
+" optional_space .and ')' .and optional_space;\n"
+"semicolon\n"
+" optional_space .and ';' .and optional_space;\n"
+"slash\n"
+" optional_space .and '/' .and optional_space;\n"
+"slashequals\n"
+" optional_space .and '/' .and '=' .and optional_space;\n"
+"star\n"
+" optional_space .and '*' .and optional_space;\n"
+"starequals\n"
+" optional_space .and '*' .and '=' .and optional_space;\n"
+".string string_lexer;\n"
+"string_lexer\n"
+" lex_first_identifier_character .and .loop lex_next_identifier_character;\n"
+"lex_first_identifier_character\n"
+" 'a'-'z' .or 'A'-'Z' .or '_';\n"
+"lex_next_identifier_character\n"
+" 'a'-'z' .or 'A'-'Z' .or '0'-'9' .or '_';\n"
+"err_token\n"
+" '~' .or '`' .or '!' .or '@' .or '#' .or '$' .or '%' .or '^' .or '&' .or '*' .or '(' .or ')' .or\n"
+" '-' .or '+' .or '=' .or '|' .or '\\\\' .or '[' .or ']' .or '{' .or '}' .or ':' .or ';' .or '\"' .or\n"
+" '\\'' .or '<' .or ',' .or '>' .or '.' .or '/' .or '?' .or err_identifier;\n"
+"err_identifier\n"
+" id_character_first .and .loop id_character_next;\n"
+""
diff --git a/src/mesa/shader/slang/library/slang_vertex_builtin_gc.h b/src/mesa/shader/slang/library/slang_vertex_builtin_gc.h
new file mode 100644
index 00000000000..b47c2717c56
--- /dev/null
+++ b/src/mesa/shader/slang/library/slang_vertex_builtin_gc.h
@@ -0,0 +1,78 @@
+
+/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */
+/* slang_vertex_builtin.gc */
+
+3,2,2,5,12,1,103,108,95,80,111,115,105,116,105,111,110,0,0,0,2,2,5,9,1,103,108,95,80,111,105,110,
+116,83,105,122,101,0,0,0,2,2,5,12,1,103,108,95,67,108,105,112,86,101,114,116,101,120,0,0,0,2,2,2,
+12,1,103,108,95,67,111,108,111,114,0,0,0,2,2,2,12,1,103,108,95,83,101,99,111,110,100,97,114,121,67,
+111,108,111,114,0,0,0,2,2,2,11,1,103,108,95,78,111,114,109,97,108,0,0,0,2,2,2,12,1,103,108,95,86,
+101,114,116,101,120,0,0,0,2,2,2,12,1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,
+48,0,0,0,2,2,2,12,1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,49,0,0,0,2,2,2,12,
+1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,50,0,0,0,2,2,2,12,1,103,108,95,77,
+117,108,116,105,84,101,120,67,111,111,114,100,51,0,0,0,2,2,2,12,1,103,108,95,77,117,108,116,105,84,
+101,120,67,111,111,114,100,52,0,0,0,2,2,2,12,1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,
+114,100,53,0,0,0,2,2,2,12,1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,54,0,0,0,2,
+2,2,12,1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,55,0,0,0,2,2,2,9,1,103,108,95,
+70,111,103,67,111,111,114,100,0,0,0,2,2,3,12,1,103,108,95,70,114,111,110,116,67,111,108,111,114,0,
+0,0,2,2,3,12,1,103,108,95,66,97,99,107,67,111,108,111,114,0,0,0,2,2,3,12,1,103,108,95,70,114,111,
+110,116,83,101,99,111,110,100,97,114,121,67,111,108,111,114,0,0,0,2,2,3,12,1,103,108,95,66,97,99,
+107,83,101,99,111,110,100,97,114,121,67,111,108,111,114,0,0,0,2,2,3,12,1,103,108,95,84,101,120,67,
+111,111,114,100,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,
+0,2,2,3,9,1,103,108,95,70,111,103,70,114,97,103,67,111,111,114,100,0,0,0,1,0,12,0,102,116,114,97,
+110,115,102,111,114,109,0,0,1,8,18,103,108,95,77,111,100,101,108,86,105,101,119,80,114,111,106,101,
+99,116,105,111,110,77,97,116,114,105,120,0,18,103,108,95,86,101,114,116,101,120,0,48,0,0,1,0,12,0,
+116,101,120,116,117,114,101,49,68,76,111,100,0,1,0,0,16,115,97,109,112,108,101,114,0,0,1,0,0,9,99,
+111,111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,
+52,95,116,101,120,49,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,
+111,114,100,0,0,18,108,111,100,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,116,101,120,116,117,
+114,101,49,68,80,114,111,106,76,111,100,0,1,0,0,16,115,97,109,112,108,101,114,0,0,1,0,0,10,99,111,
+111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,8,58,116,101,120,116,117,114,101,49,68,76,111,100,0,18,
+115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,116,0,
+49,0,18,108,111,100,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,49,68,80,114,111,106,76,111,100,
+0,1,0,0,16,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,1,0,0,9,108,111,100,0,0,
+0,1,8,58,116,101,120,116,117,114,101,49,68,76,111,100,0,18,115,97,109,112,108,101,114,0,0,18,99,
+111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,108,111,100,0,0,0,0,0,1,0,12,0,
+116,101,120,116,117,114,101,50,68,76,111,100,0,1,0,0,17,115,97,109,112,108,101,114,0,0,1,0,0,10,99,
+111,111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,
+52,95,116,101,120,50,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,
+111,114,100,0,0,18,108,111,100,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,116,101,120,116,117,
+114,101,50,68,80,114,111,106,76,111,100,0,1,0,0,17,115,97,109,112,108,101,114,0,0,1,0,0,11,99,111,
+111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,8,58,116,101,120,116,117,114,101,50,68,76,111,100,0,18,
+115,97,109,112,108,101,114,0,0,58,118,101,99,50,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,
+114,100,0,59,112,0,49,0,18,99,111,111,114,100,0,59,116,0,18,99,111,111,114,100,0,59,112,0,49,0,0,0,
+18,108,111,100,0,0,0,0,0,1,0,12,0,116,101,120,116,117,114,101,50,68,80,114,111,106,76,111,100,0,1,
+0,0,17,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,
+8,58,116,101,120,116,117,114,101,50,68,76,111,100,0,18,115,97,109,112,108,101,114,0,0,58,118,101,
+99,50,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,
+100,0,59,116,0,18,99,111,111,114,100,0,59,113,0,49,0,0,0,18,108,111,100,0,0,0,0,0,1,0,12,0,116,101,
+120,116,117,114,101,51,68,76,111,100,0,1,0,0,18,115,97,109,112,108,101,114,0,0,1,0,0,11,99,111,111,
+114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,52,95,
+116,101,120,51,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,
+114,100,0,0,18,108,111,100,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,116,101,120,116,117,114,
+101,51,68,80,114,111,106,76,111,100,0,1,0,0,18,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,
+114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,8,58,116,101,120,116,117,114,101,51,68,76,111,100,0,18,115,
+97,109,112,108,101,114,0,0,58,118,101,99,51,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,
+100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,116,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,
+111,111,114,100,0,59,112,0,18,99,111,111,114,100,0,59,113,0,49,0,0,0,18,108,111,100,0,0,0,0,0,1,0,
+12,0,116,101,120,116,117,114,101,67,117,98,101,76,111,100,0,1,0,0,19,115,97,109,112,108,101,114,0,
+0,1,0,0,11,99,111,111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,
+4,118,101,99,52,95,116,101,120,99,117,98,101,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,
+101,114,0,0,18,99,111,111,114,100,0,0,18,108,111,100,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,
+115,104,97,100,111,119,49,68,76,111,100,0,1,0,0,20,115,97,109,112,108,101,114,0,0,1,0,0,11,99,111,
+111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,3,2,0,12,1,116,101,120,101,108,0,0,0,4,118,101,99,52,
+95,115,104,97,100,49,100,0,18,116,101,120,101,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,
+111,114,100,0,0,18,108,111,100,0,0,0,8,18,116,101,120,101,108,0,0,0,1,0,12,0,115,104,97,100,111,
+119,49,68,80,114,111,106,76,111,100,0,1,0,0,20,115,97,109,112,108,101,114,0,0,1,0,0,12,99,111,111,
+114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,8,58,115,104,97,100,111,119,49,68,76,111,100,0,18,115,97,
+109,112,108,101,114,0,0,58,118,101,99,51,0,18,99,111,111,114,100,0,59,115,0,18,99,111,111,114,100,
+0,59,113,0,49,0,17,48,0,48,0,0,0,18,99,111,111,114,100,0,59,112,0,18,99,111,111,114,100,0,59,113,0,
+49,0,0,0,18,108,111,100,0,0,0,0,0,1,0,12,0,115,104,97,100,111,119,50,68,76,111,100,0,1,0,0,21,115,
+97,109,112,108,101,114,0,0,1,0,0,11,99,111,111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,3,2,0,12,1,
+116,101,120,101,108,0,0,0,4,118,101,99,52,95,115,104,97,100,50,100,0,18,116,101,120,101,108,0,0,18,
+115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,18,108,111,100,0,0,0,8,18,116,101,120,101,
+108,0,0,0,1,0,12,0,115,104,97,100,111,119,50,68,80,114,111,106,76,111,100,0,1,0,0,21,115,97,109,
+112,108,101,114,0,0,1,0,0,12,99,111,111,114,100,0,0,1,0,0,9,108,111,100,0,0,0,1,8,58,115,104,97,
+100,111,119,50,68,76,111,100,0,18,115,97,109,112,108,101,114,0,0,58,118,101,99,51,0,18,99,111,111,
+114,100,0,59,115,0,18,99,111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,116,0,18,99,
+111,111,114,100,0,59,113,0,49,0,18,99,111,111,114,100,0,59,112,0,18,99,111,111,114,100,0,59,113,0,
+49,0,0,0,18,108,111,100,0,0,0,0,0,0
diff --git a/src/mesa/shader/slang/library/syn_to_c.c b/src/mesa/shader/slang/library/syn_to_c.c
new file mode 100644
index 00000000000..f997edfd8b5
--- /dev/null
+++ b/src/mesa/shader/slang/library/syn_to_c.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+
+static int was_space = 0;
+static int first_char = 1;
+
+static void put_char (int c)
+{
+ if (c == '\n') {
+ if (!first_char) {
+ fputs ("\\n\"\n\"", stdout);
+ first_char = 1;
+ }
+ }
+ else {
+ first_char = 0;
+ if (c == '\\')
+ fputs ("\\\\", stdout);
+ else if (c == '\"')
+ fputs ("\\\"", stdout);
+ else if (!was_space || !(c == ' ' || c == '\t'))
+ fputc (c, stdout);
+ was_space = (c == ' ' || c == '\t');
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ int c;
+ FILE *f;
+
+ if (argc == 1)
+ return 1;
+ f = fopen (argv[1], "r");
+ if (f == NULL)
+ return 1;
+
+ fputs ("\n", stdout);
+ fputs ("/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE .syn FILE */\n", stdout);
+ fputs ("\n", stdout);
+ fputs ("\"", stdout);
+ c = getc (f);
+ while (c != EOF) {
+ if (c == '/') {
+ int c2 = getc (f);
+ if (c2 == '*') {
+ was_space = 0;
+ c = getc (f);
+ for (;;) {
+ if (c == '*') {
+ c2 = getc (f);
+ if (c2 == '/')
+ break;
+ }
+ c = getc (f);
+ }
+ }
+ else {
+ put_char (c);
+ put_char (c2);
+ }
+ }
+ else {
+ put_char (c);
+ }
+ c = getc (f);
+ }
+ fputs ("\"\n", stdout);
+
+ fclose (f);
+ return 0;
+}
+
diff --git a/src/mesa/shader/slang/slang_analyse.c b/src/mesa/shader/slang/slang_analyse.c
new file mode 100644
index 00000000000..7a38dbbcbb5
--- /dev/null
+++ b/src/mesa/shader/slang/slang_analyse.c
@@ -0,0 +1,100 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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 slang_analyse.c
+ * slang assembly code analysis
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_analyse.h"
+#include "slang_utility.h"
+
+GLboolean _slang_analyse_texture_usage (slang_program *prog)
+{
+ GLuint i, count = 0;
+
+ slang_texture_usages_dtr (&prog->texture_usage);
+ slang_texture_usages_ctr (&prog->texture_usage);
+
+ /*
+ * We could do a full code analysis to find out which uniforms are actually used.
+ * For now, we are very conservative and extract them from uniform binding table, which
+ * in turn also do not come from code analysis.
+ */
+
+ for (i = 0; i < prog->uniforms.count; i++)
+ {
+ slang_uniform_binding *b = &prog->uniforms.table[i];
+
+ if (b->address[SLANG_SHADER_FRAGMENT] != ~0 && !slang_export_data_quant_struct (b->quant))
+ {
+ switch (slang_export_data_quant_type (b->quant))
+ {
+ case GL_SAMPLER_1D_ARB:
+ case GL_SAMPLER_2D_ARB:
+ case GL_SAMPLER_3D_ARB:
+ case GL_SAMPLER_CUBE_ARB:
+ case GL_SAMPLER_1D_SHADOW_ARB:
+ case GL_SAMPLER_2D_SHADOW_ARB:
+ count++;
+ break;
+ }
+ }
+ }
+
+ if (count == 0)
+ return GL_TRUE;
+ prog->texture_usage.table = (slang_texture_usage *) slang_alloc_malloc (
+ count * sizeof (slang_texture_usage));
+ if (prog->texture_usage.table == NULL)
+ return GL_FALSE;
+ prog->texture_usage.count = count;
+
+ for (count = i = 0; i < prog->uniforms.count; i++)
+ {
+ slang_uniform_binding *b = &prog->uniforms.table[i];
+
+ if (b->address[SLANG_SHADER_FRAGMENT] != ~0 && !slang_export_data_quant_struct (b->quant))
+ {
+ switch (slang_export_data_quant_type (b->quant))
+ {
+ case GL_SAMPLER_1D_ARB:
+ case GL_SAMPLER_2D_ARB:
+ case GL_SAMPLER_3D_ARB:
+ case GL_SAMPLER_CUBE_ARB:
+ case GL_SAMPLER_1D_SHADOW_ARB:
+ case GL_SAMPLER_2D_SHADOW_ARB:
+ prog->texture_usage.table[count].quant = b->quant;
+ prog->texture_usage.table[count].frag_address = b->address[SLANG_SHADER_FRAGMENT];
+ count++;
+ break;
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_analyse.h b/src/mesa/shader/slang/slang_analyse.h
new file mode 100644
index 00000000000..d7e39ae7ce7
--- /dev/null
+++ b/src/mesa/shader/slang/slang_analyse.h
@@ -0,0 +1,50 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#if !defined SLANG_ANALYSE_H
+#define SLANG_ANALYSE_H
+
+#include "slang_link.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Texture usage analysis is a bit more difficult than for fragment programs. While fragment
+ * programs statically link to texture targets and texture units, shaders statically link
+ * only to texture targets. The texture unit linkage is determined just before the execution
+ * of a given primitive by reading active uniform samplers.
+ *
+ * This procedure retrieves a list of uniforms that reach texture sample instructions.
+ */
+
+GLboolean _slang_analyse_texture_usage (slang_program *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_assemble.c b/src/mesa/shader/slang/slang_assemble.c
new file mode 100644
index 00000000000..36fb2305f68
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble.c
@@ -0,0 +1,1503 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_assemble.c
+ * slang intermediate code assembler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_assemble.h"
+#include "slang_compile.h"
+#include "slang_storage.h"
+
+/* slang_assembly */
+
+static GLboolean slang_assembly_construct (slang_assembly *assem)
+{
+ assem->type = slang_asm_none;
+ return GL_TRUE;
+}
+
+static GLvoid slang_assembly_destruct (slang_assembly *assem)
+{
+}
+
+/*
+ * slang_assembly_file
+ */
+
+GLvoid
+_slang_assembly_file_ctr (slang_assembly_file *self)
+{
+ self->code = NULL;
+ self->count = 0;
+ self->capacity = 0;
+}
+
+GLvoid slang_assembly_file_destruct (slang_assembly_file *file)
+{
+ GLuint i;
+
+ for (i = 0; i < file->count; i++)
+ slang_assembly_destruct (&file->code[i]);
+ slang_alloc_free (file->code);
+}
+
+static GLboolean push_new (slang_assembly_file *file)
+{
+ if (file->count == file->capacity)
+ {
+ GLuint n;
+
+ if (file->capacity == 0)
+ n = 256;
+ else
+ n = file->capacity * 2;
+ file->code = (slang_assembly *) slang_alloc_realloc (file->code,
+ file->capacity * sizeof (slang_assembly), n * sizeof (slang_assembly));
+ if (file->code == NULL)
+ return GL_FALSE;
+ file->capacity = n;
+ }
+ if (!slang_assembly_construct (&file->code[file->count]))
+ return GL_FALSE;
+ file->count++;
+ return GL_TRUE;
+}
+
+static GLboolean push_gen (slang_assembly_file *file, slang_assembly_type type, GLfloat literal,
+ GLuint label, GLuint size)
+{
+ slang_assembly *assem;
+
+ if (!push_new (file))
+ return GL_FALSE;
+ assem = &file->code[file->count - 1];
+ assem->type = type;
+ assem->literal = literal;
+ assem->param[0] = label;
+ assem->param[1] = size;
+ return GL_TRUE;
+}
+
+GLboolean slang_assembly_file_push (slang_assembly_file *file, slang_assembly_type type)
+{
+ return push_gen (file, type, (GLfloat) 0, 0, 0);
+}
+
+GLboolean slang_assembly_file_push_label (slang_assembly_file *file, slang_assembly_type type,
+ GLuint label)
+{
+ return push_gen (file, type, (GLfloat) 0, label, 0);
+}
+
+GLboolean slang_assembly_file_push_label2 (slang_assembly_file *file, slang_assembly_type type,
+ GLuint label1, GLuint label2)
+{
+ return push_gen (file, type, (GLfloat) 0, label1, label2);
+}
+
+GLboolean slang_assembly_file_push_literal (slang_assembly_file *file, slang_assembly_type type,
+ GLfloat literal)
+{
+ return push_gen (file, type, literal, 0, 0);
+}
+
+#define PUSH slang_assembly_file_push
+#define PLAB slang_assembly_file_push_label
+#define PLAB2 slang_assembly_file_push_label2
+#define PLIT slang_assembly_file_push_literal
+
+/* slang_assembly_file_restore_point */
+
+GLboolean slang_assembly_file_restore_point_save (slang_assembly_file *file,
+ slang_assembly_file_restore_point *point)
+{
+ point->count = file->count;
+ return GL_TRUE;
+}
+
+GLboolean slang_assembly_file_restore_point_load (slang_assembly_file *file,
+ slang_assembly_file_restore_point *point)
+{
+ GLuint i;
+
+ for (i = point->count; i < file->count; i++)
+ slang_assembly_destruct (&file->code[i]);
+ file->count = point->count;
+ return GL_TRUE;
+}
+
+/* utility functions */
+
+static GLboolean sizeof_variable (slang_assemble_ctx *A, slang_type_specifier *spec,
+ slang_type_qualifier qual, GLuint array_len, GLuint *size)
+{
+ slang_storage_aggregate agg;
+
+ /* calculate the size of the variable's aggregate */
+ if (!slang_storage_aggregate_construct (&agg))
+ return GL_FALSE;
+ if (!_slang_aggregate_variable (&agg, spec, array_len, A->space.funcs, A->space.structs,
+ A->space.vars, A->mach, A->file, A->atoms))
+ {
+ slang_storage_aggregate_destruct (&agg);
+ return GL_FALSE;
+ }
+ *size += _slang_sizeof_aggregate (&agg);
+ slang_storage_aggregate_destruct (&agg);
+
+ /* for reference variables consider the additional address overhead */
+ if (qual == slang_qual_out || qual == slang_qual_inout)
+ *size += 4;
+
+ return GL_TRUE;
+}
+
+static GLboolean sizeof_variable2 (slang_assemble_ctx *A, slang_variable *var, GLuint *size)
+{
+ var->address = *size;
+ if (var->type.qualifier == slang_qual_out || var->type.qualifier == slang_qual_inout)
+ var->address += 4;
+ return sizeof_variable (A, &var->type.specifier, var->type.qualifier, var->array_len, size);
+}
+
+static GLboolean sizeof_variables (slang_assemble_ctx *A, slang_variable_scope *vars, GLuint start,
+ GLuint stop, GLuint *size)
+{
+ GLuint i;
+
+ for (i = start; i < stop; i++)
+ if (!sizeof_variable2 (A, &vars->variables[i], size))
+ return GL_FALSE;
+ return GL_TRUE;
+}
+
+static GLboolean collect_locals (slang_assemble_ctx *A, slang_operation *op, GLuint *size)
+{
+ GLuint i;
+
+ if (!sizeof_variables (A, op->locals, 0, op->locals->num_variables, size))
+ return GL_FALSE;
+ for (i = 0; i < op->num_children; i++)
+ if (!collect_locals (A, &op->children[i], size))
+ return GL_FALSE;
+ return GL_TRUE;
+}
+
+/* _slang_locate_function() */
+
+slang_function *_slang_locate_function (slang_function_scope *funcs, slang_atom a_name,
+ slang_operation *params, GLuint num_params, slang_assembly_name_space *space,
+ slang_atom_pool *atoms)
+{
+ GLuint i;
+
+ for (i = 0; i < funcs->num_functions; i++)
+ {
+ GLuint j;
+ slang_function *f = &funcs->functions[i];
+
+ if (a_name != f->header.a_name)
+ continue;
+ if (f->param_count != num_params)
+ continue;
+ for (j = 0; j < num_params; j++)
+ {
+ slang_assembly_typeinfo ti;
+
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return NULL;
+ if (!_slang_typeof_operation_ (&params[j], space, &ti, atoms))
+ {
+ slang_assembly_typeinfo_destruct (&ti);
+ return NULL;
+ }
+ if (!slang_type_specifier_equal (&ti.spec, &f->parameters->variables[j].type.specifier))
+ {
+ slang_assembly_typeinfo_destruct (&ti);
+ break;
+ }
+ slang_assembly_typeinfo_destruct (&ti);
+
+ /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
+ if (!ti.can_be_referenced &&
+ (f->parameters->variables[j].type.qualifier == slang_qual_out ||
+ f->parameters->variables[j].type.qualifier == slang_qual_inout))
+ break;
+ }
+ if (j == num_params)
+ return f;
+ }
+ if (funcs->outer_scope != NULL)
+ return _slang_locate_function (funcs->outer_scope, a_name, params, num_params, space, atoms);
+ return NULL;
+}
+
+/* _slang_assemble_function() */
+
+GLboolean _slang_assemble_function (slang_assemble_ctx *A, slang_function *fun)
+{
+ GLuint param_size, local_size;
+ GLuint skip, cleanup;
+
+ fun->address = A->file->count;
+
+ if (fun->body == NULL)
+ {
+ /* jump to the actual function body - we do not know it, so add the instruction
+ * to fixup table */
+ fun->fixups.table = (GLuint *) slang_alloc_realloc (fun->fixups.table,
+ fun->fixups.count * sizeof (GLuint), (fun->fixups.count + 1) * sizeof (GLuint));
+ if (fun->fixups.table == NULL)
+ return GL_FALSE;
+ fun->fixups.table[fun->fixups.count] = fun->address;
+ fun->fixups.count++;
+ if (!PUSH (A->file, slang_asm_jump))
+ return GL_FALSE;
+ return GL_TRUE;
+ }
+ else
+ {
+ GLuint i;
+
+ /* resolve all fixup table entries and delete it */
+ for (i = 0; i < fun->fixups.count; i++)
+ A->file->code[fun->fixups.table[i]].param[0] = fun->address;
+ slang_fixup_table_free (&fun->fixups);
+ }
+
+ /* At this point traverse function formal parameters and code to calculate
+ * total memory size to be allocated on the stack.
+ * During this process the variables will be assigned local addresses to
+ * reference them in the code.
+ * No storage optimizations are performed so exclusive scopes are not detected and shared. */
+
+ /* calculate return value size */
+ param_size = 0;
+ if (fun->header.type.specifier.type != slang_spec_void)
+ if (!sizeof_variable (A, &fun->header.type.specifier, slang_qual_none, 0, &param_size))
+ return GL_FALSE;
+ A->local.ret_size = param_size;
+
+ /* calculate formal parameter list size */
+ if (!sizeof_variables (A, fun->parameters, 0, fun->param_count, &param_size))
+ return GL_FALSE;
+
+ /* calculate local variables size - take into account the four-byte return address and
+ * temporaries for various tasks (4 for addr and 16 for swizzle temporaries).
+ * these include variables from the formal parameter scope and from the code */
+ A->local.addr_tmp = param_size + 4;
+ A->local.swizzle_tmp = param_size + 4 + 4;
+ local_size = param_size + 4 + 4 + 16;
+ if (!sizeof_variables (A, fun->parameters, fun->param_count, fun->parameters->num_variables,
+ &local_size))
+ return GL_FALSE;
+ if (!collect_locals (A, fun->body, &local_size))
+ return GL_FALSE;
+
+ /* allocate local variable storage */
+ if (!PLAB (A->file, slang_asm_local_alloc, local_size - param_size - 4))
+ return GL_FALSE;
+
+ /* mark a new frame for function variable storage */
+ if (!PLAB (A->file, slang_asm_enter, local_size))
+ return GL_FALSE;
+
+ /* jump directly to the actual code */
+ skip = A->file->count;
+ if (!push_new (A->file))
+ return GL_FALSE;
+ A->file->code[skip].type = slang_asm_jump;
+
+ /* all "return" statements will be directed here */
+ A->flow.function_end = A->file->count;
+ cleanup = A->file->count;
+ if (!push_new (A->file))
+ return GL_FALSE;
+ A->file->code[cleanup].type = slang_asm_jump;
+
+ /* execute the function body */
+ A->file->code[skip].param[0] = A->file->count;
+ if (!_slang_assemble_operation (A, fun->body, /*slang_ref_freelance*/slang_ref_forbid))
+ return GL_FALSE;
+
+ /* this is the end of the function - restore the old function frame */
+ A->file->code[cleanup].param[0] = A->file->count;
+ if (!PUSH (A->file, slang_asm_leave))
+ return GL_FALSE;
+
+ /* free local variable storage */
+ if (!PLAB (A->file, slang_asm_local_free, local_size - param_size - 4))
+ return GL_FALSE;
+
+ /* return from the function */
+ if (!PUSH (A->file, slang_asm_return))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+GLboolean _slang_cleanup_stack (slang_assemble_ctx *A, slang_operation *op)
+{
+ slang_assembly_typeinfo ti;
+ GLuint size = 0;
+
+ /* get type info of the operation and calculate its size */
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation (A, op, &ti))
+ {
+ slang_assembly_typeinfo_destruct (&ti);
+ return GL_FALSE;
+ }
+ if (ti.spec.type != slang_spec_void) {
+ if (A->ref == slang_ref_force) {
+ size = 4;
+ }
+ else if (!sizeof_variable (A, &ti.spec, slang_qual_none, 0, &size))
+ {
+ slang_assembly_typeinfo_destruct (&ti);
+ return GL_FALSE;
+ }
+ }
+ slang_assembly_typeinfo_destruct (&ti);
+
+ /* if nonzero, free it from the stack */
+ if (size != 0)
+ {
+ if (!PLAB (A->file, slang_asm_local_free, size))
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+/* _slang_assemble_operation() */
+
+static GLboolean
+dereference_basic (slang_assemble_ctx *A, slang_storage_type type, GLuint *size, slang_swizzle *swz,
+ GLboolean is_swizzled)
+{
+ GLuint src_offset;
+ slang_assembly_type ty;
+
+ *size -= _slang_sizeof_type (type);
+
+ /* If swizzling is taking place, we are forced to use scalar operations, even if we have
+ * vec4 instructions enabled (this should be actually done with special vec4 shuffle
+ * instructions).
+ * Adjust the size and calculate the offset within source variable to read.
+ */
+ if (is_swizzled)
+ src_offset = swz->swizzle[*size / 4] * 4;
+ else
+ src_offset = *size;
+
+ /* dereference data slot of a basic type */
+ if (!PLAB2 (A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_deref))
+ return GL_FALSE;
+ if (src_offset != 0) {
+ if (!PLAB (A->file, slang_asm_addr_push, src_offset))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_add))
+ return GL_FALSE;
+ }
+
+ switch (type) {
+ case slang_stor_bool:
+ ty = slang_asm_bool_deref;
+ break;
+ case slang_stor_int:
+ ty = slang_asm_int_deref;
+ break;
+ case slang_stor_float:
+ ty = slang_asm_float_deref;
+ break;
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ case slang_stor_vec4:
+ ty = slang_asm_vec4_deref;
+ break;
+#endif
+ default:
+ _mesa_problem(NULL, "Unexpected arr->type in dereference_basic");
+ ty = slang_asm_none;
+ }
+
+ return PUSH (A->file, ty);
+}
+
+static GLboolean
+dereference_aggregate (slang_assemble_ctx *A, const slang_storage_aggregate *agg, GLuint *size,
+ slang_swizzle *swz, GLboolean is_swizzled)
+{
+ GLuint i;
+
+ for (i = agg->count; i > 0; i--) {
+ const slang_storage_array *arr = &agg->arrays[i - 1];
+ GLuint j;
+
+ for (j = arr->length; j > 0; j--) {
+ if (arr->type == slang_stor_aggregate) {
+ if (!dereference_aggregate (A, arr->aggregate, size, swz, is_swizzled))
+ return GL_FALSE;
+ }
+ else {
+ if (is_swizzled && arr->type == slang_stor_vec4) {
+ if (!dereference_basic (A, slang_stor_float, size, swz, is_swizzled))
+ return GL_FALSE;
+ if (!dereference_basic (A, slang_stor_float, size, swz, is_swizzled))
+ return GL_FALSE;
+ if (!dereference_basic (A, slang_stor_float, size, swz, is_swizzled))
+ return GL_FALSE;
+ if (!dereference_basic (A, slang_stor_float, size, swz, is_swizzled))
+ return GL_FALSE;
+ }
+ else {
+ if (!dereference_basic (A, arr->type, size, swz, is_swizzled))
+ return GL_FALSE;
+ }
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean _slang_dereference (slang_assemble_ctx *A, slang_operation *op)
+{
+ slang_assembly_typeinfo ti;
+ GLboolean result = GL_FALSE;
+ slang_storage_aggregate agg;
+ GLuint size;
+
+ /* get type information of the given operation */
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation (A, op, &ti))
+ goto end1;
+
+ /* construct aggregate from the type info */
+ if (!slang_storage_aggregate_construct (&agg))
+ goto end1;
+ if (!_slang_aggregate_variable (&agg, &ti.spec, ti.array_len, A->space.funcs, A->space.structs,
+ A->space.vars, A->mach, A->file, A->atoms))
+ goto end;
+
+ /* dereference the resulting aggregate */
+ size = _slang_sizeof_aggregate (&agg);
+ result = dereference_aggregate (A, &agg, &size, &ti.swz, ti.is_swizzled);
+
+end:
+ slang_storage_aggregate_destruct (&agg);
+end1:
+ slang_assembly_typeinfo_destruct (&ti);
+ return result;
+}
+
+GLboolean _slang_assemble_function_call (slang_assemble_ctx *A, slang_function *fun,
+ slang_operation *params, GLuint param_count, GLboolean assignment)
+{
+ GLuint i;
+ slang_swizzle p_swz[64];
+ slang_ref_type p_ref[64];
+
+ /* TODO: fix this, allocate dynamically */
+ if (param_count > 64)
+ return GL_FALSE;
+
+ /* make room for the return value, if any */
+ if (fun->header.type.specifier.type != slang_spec_void)
+ {
+ GLuint ret_size = 0;
+
+ if (!sizeof_variable (A, &fun->header.type.specifier, slang_qual_none, 0, &ret_size))
+ return GL_FALSE;
+ if (!PLAB (A->file, slang_asm_local_alloc, ret_size))
+ return GL_FALSE;
+ }
+
+ /* push the actual parameters on the stack */
+ for (i = 0; i < param_count; i++)
+ {
+ if (fun->parameters->variables[i].type.qualifier == slang_qual_inout ||
+ fun->parameters->variables[i].type.qualifier == slang_qual_out)
+ {
+ if (!PLAB2 (A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
+ return GL_FALSE;
+ /* TODO: optimize the "out" parameter case */
+ if (!_slang_assemble_operation (A, &params[i], slang_ref_force))
+ return GL_FALSE;
+ p_swz[i] = A->swz;
+ p_ref[i] = A->ref;
+ if (!PUSH (A->file, slang_asm_addr_copy))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_deref))
+ return GL_FALSE;
+ if (i == 0 && assignment)
+ {
+ /* duplicate the resulting address */
+ if (!PLAB2 (A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_deref))
+ return GL_FALSE;
+ }
+ if (!_slang_dereference (A, &params[i]))
+ return GL_FALSE;
+ }
+ else
+ {
+ if (!_slang_assemble_operation (A, &params[i], slang_ref_forbid))
+ return GL_FALSE;
+ p_swz[i] = A->swz;
+ p_ref[i] = A->ref;
+ }
+ }
+
+ /* call the function */
+ if (!PLAB (A->file, slang_asm_call, fun->address))
+ return GL_FALSE;
+
+ /* pop the parameters from the stack */
+ for (i = param_count; i > 0; i--)
+ {
+ GLuint j = i - 1;
+
+ A->swz = p_swz[j];
+ A->ref = p_ref[j];
+ if (fun->parameters->variables[j].type.qualifier == slang_qual_inout ||
+ fun->parameters->variables[j].type.qualifier == slang_qual_out)
+ {
+ /* for output parameter copy the contents of the formal parameter
+ * back to the original actual parameter */
+ if (!_slang_assemble_assignment (A, &params[j]))
+ return GL_FALSE;
+ /* pop the actual parameter's address */
+ if (!PLAB (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+ }
+ else
+ {
+ /* pop the value of the parameter */
+ if (!_slang_cleanup_stack (A, &params[j]))
+ return GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean _slang_assemble_function_call_name (slang_assemble_ctx *A, const char *name,
+ slang_operation *params, GLuint param_count, GLboolean assignment)
+{
+ slang_atom atom;
+ slang_function *fun;
+
+ atom = slang_atom_pool_atom (A->atoms, name);
+ if (atom == SLANG_ATOM_NULL)
+ return GL_FALSE;
+ fun = _slang_locate_function (A->space.funcs, atom, params, param_count, &A->space, A->atoms);
+ if (fun == NULL)
+ return GL_FALSE;
+ return _slang_assemble_function_call (A, fun, params, param_count, assignment);
+}
+
+static GLboolean assemble_function_call_name_dummyint (slang_assemble_ctx *A, const char *name,
+ slang_operation *params)
+{
+ slang_operation p[2];
+ GLboolean result;
+
+ p[0] = params[0];
+ if (!slang_operation_construct (&p[1]))
+ return GL_FALSE;
+ p[1].type = slang_oper_literal_int;
+ result = _slang_assemble_function_call_name (A, name, p, 2, GL_FALSE);
+ slang_operation_destruct (&p[1]);
+ return result;
+}
+
+static const struct
+{
+ const char *name;
+ slang_assembly_type code1, code2;
+} inst[] = {
+ /* core */
+ { "float_add", slang_asm_float_add, slang_asm_float_copy },
+ { "float_multiply", slang_asm_float_multiply, slang_asm_float_copy },
+ { "float_divide", slang_asm_float_divide, slang_asm_float_copy },
+ { "float_negate", slang_asm_float_negate, slang_asm_float_copy },
+ { "float_less", slang_asm_float_less, slang_asm_bool_copy },
+ { "float_equal", slang_asm_float_equal_exp,slang_asm_bool_copy },
+ { "float_to_int", slang_asm_float_to_int, slang_asm_int_copy },
+ { "float_sine", slang_asm_float_sine, slang_asm_float_copy },
+ { "float_arcsine", slang_asm_float_arcsine, slang_asm_float_copy },
+ { "float_arctan", slang_asm_float_arctan, slang_asm_float_copy },
+ { "float_power", slang_asm_float_power, slang_asm_float_copy },
+ { "float_log2", slang_asm_float_log2, slang_asm_float_copy },
+ { "float_floor", slang_asm_float_floor, slang_asm_float_copy },
+ { "float_ceil", slang_asm_float_ceil, slang_asm_float_copy },
+ { "float_noise1", slang_asm_float_noise1, slang_asm_float_copy },
+ { "float_noise2", slang_asm_float_noise2, slang_asm_float_copy },
+ { "float_noise3", slang_asm_float_noise3, slang_asm_float_copy },
+ { "float_noise4", slang_asm_float_noise4, slang_asm_float_copy },
+ { "int_to_float", slang_asm_int_to_float, slang_asm_float_copy },
+ { "vec4_tex1d", slang_asm_vec4_tex1d, slang_asm_none },
+ { "vec4_tex2d", slang_asm_vec4_tex2d, slang_asm_none },
+ { "vec4_tex3d", slang_asm_vec4_tex3d, slang_asm_none },
+ { "vec4_texcube", slang_asm_vec4_texcube, slang_asm_none },
+ { "vec4_shad1d", slang_asm_vec4_shad1d, slang_asm_none },
+ { "vec4_shad2d", slang_asm_vec4_shad2d, slang_asm_none },
+ /* GL_MESA_shader_debug */
+ { "float_print", slang_asm_float_deref, slang_asm_float_print },
+ { "int_print", slang_asm_int_deref, slang_asm_int_print },
+ { "bool_print", slang_asm_bool_deref, slang_asm_bool_print },
+ /* vec4 */
+ { "float_to_vec4", slang_asm_float_to_vec4, slang_asm_none },
+ { "vec4_add", slang_asm_vec4_add, slang_asm_none },
+ { "vec4_subtract", slang_asm_vec4_subtract, slang_asm_none },
+ { "vec4_multiply", slang_asm_vec4_multiply, slang_asm_none },
+ { "vec4_divide", slang_asm_vec4_divide, slang_asm_none },
+ { "vec4_negate", slang_asm_vec4_negate, slang_asm_none },
+ { "vec4_dot", slang_asm_vec4_dot, slang_asm_none },
+
+ { NULL, slang_asm_none, slang_asm_none }
+};
+
+static GLboolean call_asm_instruction (slang_assemble_ctx *A, slang_atom a_name)
+{
+ const char *id;
+ GLuint i;
+
+ id = slang_atom_pool_id (A->atoms, a_name);
+
+ for (i = 0; inst[i].name != NULL; i++)
+ if (slang_string_compare (id, inst[i].name) == 0)
+ break;
+ if (inst[i].name == NULL)
+ return GL_FALSE;
+
+ if (!PLAB2 (A->file, inst[i].code1, 4, 0))
+ return GL_FALSE;
+ if (inst[i].code2 != slang_asm_none)
+ if (!PLAB2 (A->file, inst[i].code2, 4, 0))
+ return GL_FALSE;
+
+ /* clean-up the stack from the remaining dst address */
+ if (!PLAB (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+static GLboolean
+equality_aggregate (slang_assemble_ctx *A, const slang_storage_aggregate *agg, GLuint *index,
+ GLuint size, GLuint z_label)
+{
+ GLuint i;
+
+ for (i = 0; i < agg->count; i++) {
+ const slang_storage_array *arr = &agg->arrays[i];
+ GLuint j;
+
+ for (j = 0; j < arr->length; j++) {
+ if (arr->type == slang_stor_aggregate) {
+ if (!equality_aggregate (A, arr->aggregate, index, size, z_label))
+ return GL_FALSE;
+ }
+ else {
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ if (arr->type == slang_stor_vec4) {
+ if (!PLAB2 (A->file, slang_asm_vec4_equal_int, size + *index, *index))
+ return GL_FALSE;
+ }
+ else
+#endif
+ if (!PLAB2 (A->file, slang_asm_float_equal_int, size + *index, *index))
+ return GL_FALSE;
+
+ *index += _slang_sizeof_type (arr->type);
+ if (!PLAB (A->file, slang_asm_jump_if_zero, z_label))
+ return GL_FALSE;
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean equality (slang_assemble_ctx *A, slang_operation *op, GLboolean equal)
+{
+ slang_assembly_typeinfo ti;
+ GLboolean result = GL_FALSE;
+ slang_storage_aggregate agg;
+ GLuint index, size;
+ GLuint skip_jump, true_label, true_jump, false_label, false_jump;
+
+ /* get type of operation */
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation (A, op, &ti))
+ goto end1;
+
+ /* convert it to an aggregate */
+ if (!slang_storage_aggregate_construct (&agg))
+ goto end1;
+ if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
+ A->space.vars, A->mach, A->file, A->atoms))
+ goto end;
+
+ /* compute the size of the agregate - there are two such aggregates on the stack */
+ size = _slang_sizeof_aggregate (&agg);
+
+ /* jump to the actual data-comparison code */
+ skip_jump = A->file->count;
+ if (!PUSH (A->file, slang_asm_jump))
+ goto end;
+
+ /* pop off the stack the compared data and push 1 */
+ true_label = A->file->count;
+ if (!PLAB (A->file, slang_asm_local_free, size * 2))
+ goto end;
+ if (!PLIT (A->file, slang_asm_bool_push, (GLfloat) 1))
+ goto end;
+ true_jump = A->file->count;
+ if (!PUSH (A->file, slang_asm_jump))
+ goto end;
+
+ false_label = A->file->count;
+ if (!PLAB (A->file, slang_asm_local_free, size * 2))
+ goto end;
+ if (!PLIT (A->file, slang_asm_bool_push, (GLfloat) 0))
+ goto end;
+ false_jump = A->file->count;
+ if (!PUSH (A->file, slang_asm_jump))
+ goto end;
+
+ A->file->code[skip_jump].param[0] = A->file->count;
+
+ /* compare the data on stack, it will eventually jump either to true or false label */
+ index = 0;
+ if (!equality_aggregate (A, &agg, &index, size, equal ? false_label : true_label))
+ goto end;
+ if (!PLAB (A->file, slang_asm_jump, equal ? true_label : false_label))
+ goto end;
+
+ A->file->code[true_jump].param[0] = A->file->count;
+ A->file->code[false_jump].param[0] = A->file->count;
+
+ result = GL_TRUE;
+end:
+ slang_storage_aggregate_destruct (&agg);
+end1:
+ slang_assembly_typeinfo_destruct (&ti);
+ return result;
+}
+
+static GLboolean handle_subscript (slang_assemble_ctx *A, slang_assembly_typeinfo *tie,
+ slang_assembly_typeinfo *tia, slang_operation *op, slang_ref_type ref)
+{
+ GLuint asize = 0, esize = 0;
+
+ /* get type info of the master expression (matrix, vector or an array */
+ if (!_slang_typeof_operation (A, &op->children[0], tia))
+ return GL_FALSE;
+ if (!sizeof_variable (A, &tia->spec, slang_qual_none, tia->array_len, &asize))
+ return GL_FALSE;
+
+ /* get type info of the result (matrix column, vector row or array element) */
+ if (!_slang_typeof_operation (A, op, tie))
+ return GL_FALSE;
+ if (!sizeof_variable (A, &tie->spec, slang_qual_none, 0, &esize))
+ return GL_FALSE;
+
+ /* assemble the master expression */
+ if (!_slang_assemble_operation (A, &op->children[0], ref))
+ return GL_FALSE;
+
+ /* when indexing an l-value swizzle, push the swizzle_tmp */
+ if (ref == slang_ref_force && tia->is_swizzled)
+ if (!PLAB2 (A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
+ return GL_FALSE;
+
+ /* assemble the subscript expression */
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+
+ if (ref == slang_ref_force && tia->is_swizzled)
+ {
+ GLuint i;
+
+ /* copy the swizzle indexes to the swizzle_tmp */
+ for (i = 0; i < tia->swz.num_components; i++)
+ {
+ if (!PLAB2 (A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
+ return GL_FALSE;
+ if (!PLAB (A->file, slang_asm_addr_push, i * 4))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_add))
+ return GL_FALSE;
+ if (!PLAB (A->file, slang_asm_addr_push, tia->swz.swizzle[i]))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_copy))
+ return GL_FALSE;
+ if (!PLAB (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+ }
+
+ /* offset the pushed swizzle_tmp address and dereference it */
+ if (!PUSH (A->file, slang_asm_int_to_addr))
+ return GL_FALSE;
+ if (!PLAB (A->file, slang_asm_addr_push, 4))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_multiply))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_add))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_deref))
+ return GL_FALSE;
+ }
+ else
+ {
+ /* convert the integer subscript to a relative address */
+ if (!PUSH (A->file, slang_asm_int_to_addr))
+ return GL_FALSE;
+ }
+
+ if (!PLAB (A->file, slang_asm_addr_push, esize))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_multiply))
+ return GL_FALSE;
+
+ if (ref == slang_ref_force)
+ {
+ /* offset the base address with the relative address */
+ if (!PUSH (A->file, slang_asm_addr_add))
+ return GL_FALSE;
+ }
+ else
+ {
+ GLuint i;
+
+ /* move the selected element to the beginning of the master expression */
+ for (i = 0; i < esize; i += 4)
+ if (!PLAB2 (A->file, slang_asm_float_move, asize - esize + i + 4, i + 4))
+ return GL_FALSE;
+ if (!PLAB (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+
+ /* free the rest of the master expression */
+ if (!PLAB (A->file, slang_asm_local_free, asize - esize))
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean handle_field (slang_assemble_ctx *A, slang_assembly_typeinfo *tia,
+ slang_assembly_typeinfo *tib, slang_operation *op, slang_ref_type ref)
+{
+ /* get type info of the result (field or swizzle) */
+ if (!_slang_typeof_operation (A, op, tia))
+ return GL_FALSE;
+
+ /* get type info of the master expression being accessed (struct or vector) */
+ if (!_slang_typeof_operation (A, &op->children[0], tib))
+ return GL_FALSE;
+
+ /* if swizzling a vector in-place, the swizzle temporary is needed */
+ if (ref == slang_ref_forbid && tia->is_swizzled)
+ if (!PLAB2 (A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
+ return GL_FALSE;
+
+ /* assemble the master expression */
+ if (!_slang_assemble_operation (A, &op->children[0], ref))
+ return GL_FALSE;
+
+ /* assemble the field expression */
+ if (tia->is_swizzled)
+ {
+ if (ref == slang_ref_force)
+ {
+#if 0
+ if (tia->swz.num_components == 1)
+ {
+ /* simple case - adjust the vector's address to point to the selected component */
+ if (!PLAB (file, slang_asm_addr_push, tia->swz.swizzle[0] * 4))
+ return 0;
+ if (!PUSH (file, slang_asm_addr_add))
+ return 0;
+ }
+ else
+#endif
+ {
+ /* two or more vector components are being referenced - the so-called write mask
+ * must be passed to the upper operations and applied when assigning value
+ * to this swizzle */
+ A->swz = tia->swz;
+ }
+ }
+ else
+ {
+ /* swizzle the vector in-place using the swizzle temporary */
+ if (!_slang_assemble_constructor_from_swizzle (A, &tia->swz, &tia->spec, &tib->spec))
+ return GL_FALSE;
+ }
+ }
+ else
+ {
+ GLuint i, struct_size = 0, field_offset = 0, field_size = 0;
+
+ /*
+ * Calculate struct size, field offset and field size.
+ */
+ for (i = 0; i < tib->spec._struct->fields->num_variables; i++)
+ {
+ slang_variable *field;
+ slang_storage_aggregate agg;
+ GLuint size;
+
+ field = &tib->spec._struct->fields->variables[i];
+ if (!slang_storage_aggregate_construct (&agg))
+ return GL_FALSE;
+ if (!_slang_aggregate_variable (&agg, &field->type.specifier, field->array_len,
+ A->space.funcs, A->space.structs, A->space.vars, A->mach, A->file, A->atoms))
+ {
+ slang_storage_aggregate_destruct (&agg);
+ return GL_FALSE;
+ }
+ size = _slang_sizeof_aggregate (&agg);
+ slang_storage_aggregate_destruct (&agg);
+
+ if (op->a_id == field->a_name) {
+ field_size = size;
+ field_offset = struct_size;
+ }
+ struct_size += size;
+ }
+
+ if (ref == slang_ref_force)
+ {
+ GLboolean shift;
+
+ /*
+ * OPTIMIZATION: If selecting first field, no address shifting is needed.
+ */
+ shift = (field_offset != 0);
+
+ if (shift) {
+ if (!PLAB (A->file, slang_asm_addr_push, field_offset))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_addr_add))
+ return GL_FALSE;
+ }
+ }
+ else
+ {
+ GLboolean relocate, shrink;
+ GLuint free_b = 0;
+
+ /*
+ * OPTIMIZATION: If selecting last field, no relocation is needed.
+ */
+ relocate = (field_offset != (struct_size - field_size));
+
+ /*
+ * OPTIMIZATION: If field and struct sizes are equal, no partial free is needed.
+ */
+ shrink = (field_size != struct_size);
+
+ if (relocate)
+ {
+ GLuint i;
+
+ /*
+ * Move the selected element to the end of the master expression.
+ * Do it in reverse order to avoid overwriting itself.
+ */
+ if (!PLAB (A->file, slang_asm_addr_push, field_offset))
+ return GL_FALSE;
+ for (i = field_size; i > 0; i -= 4)
+ if (!PLAB2 (A->file, slang_asm_float_move, struct_size - field_size + i, i))
+ return GL_FALSE;
+ free_b += 4;
+ }
+
+ if (shrink)
+ {
+ /* free the rest of the master expression */
+ free_b += struct_size - field_size;
+ }
+
+ if (free_b)
+ {
+ if (!PLAB (A->file, slang_asm_local_free, free_b))
+ return GL_FALSE;
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean _slang_assemble_operation (slang_assemble_ctx *A, slang_operation *op, slang_ref_type ref)
+{
+ /* set default results */
+ A->ref = /*(ref == slang_ref_freelance) ? slang_ref_force : */ref;
+ A->swz.num_components = 0;
+
+ switch (op->type)
+ {
+ case slang_oper_block_no_new_scope:
+ case slang_oper_block_new_scope:
+ {
+ GLuint i;
+
+ for (i = 0; i < op->num_children; i++)
+ {
+ if (!_slang_assemble_operation (A, &op->children[i], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[i]))
+ return GL_FALSE;
+ }
+ }
+ break;
+ case slang_oper_variable_decl:
+ {
+ GLuint i;
+ slang_operation assign;
+ GLboolean result;
+
+ /* Construct assignment expression placeholder. */
+ if (!slang_operation_construct (&assign))
+ return GL_FALSE;
+ assign.type = slang_oper_assign;
+ assign.children = (slang_operation *) slang_alloc_malloc (2 * sizeof (slang_operation));
+ if (assign.children == NULL)
+ {
+ slang_operation_destruct (&assign);
+ return GL_FALSE;
+ }
+ for (assign.num_children = 0; assign.num_children < 2; assign.num_children++)
+ if (!slang_operation_construct (&assign.children[assign.num_children]))
+ {
+ slang_operation_destruct (&assign);
+ return GL_FALSE;
+ }
+
+ result = GL_TRUE;
+ for (i = 0; i < op->num_children; i++)
+ {
+ slang_variable *var;
+
+ var = _slang_locate_variable (op->children[i].locals, op->children[i].a_id, GL_TRUE);
+ if (var == NULL)
+ {
+ result = GL_FALSE;
+ break;
+ }
+ if (var->initializer == NULL)
+ continue;
+
+ if (!slang_operation_copy (&assign.children[0], &op->children[i]) ||
+ !slang_operation_copy (&assign.children[1], var->initializer) ||
+ !_slang_assemble_assign (A, &assign, "=", slang_ref_forbid) ||
+ !_slang_cleanup_stack (A, &assign))
+ {
+ result = GL_FALSE;
+ break;
+ }
+ }
+ slang_operation_destruct (&assign);
+ if (!result)
+ return GL_FALSE;
+ }
+ break;
+ case slang_oper_asm:
+ {
+ GLuint i;
+
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_force))
+ return GL_FALSE;
+ for (i = 1; i < op->num_children; i++)
+ if (!_slang_assemble_operation (A, &op->children[i], slang_ref_forbid))
+ return GL_FALSE;
+ if (!call_asm_instruction (A, op->a_id))
+ return GL_FALSE;
+ }
+ break;
+ case slang_oper_break:
+ if (!PLAB (A->file, slang_asm_jump, A->flow.loop_end))
+ return GL_FALSE;
+ break;
+ case slang_oper_continue:
+ if (!PLAB (A->file, slang_asm_jump, A->flow.loop_start))
+ return GL_FALSE;
+ break;
+ case slang_oper_discard:
+ if (!PUSH (A->file, slang_asm_discard))
+ return GL_FALSE;
+ if (!PUSH (A->file, slang_asm_exit))
+ return GL_FALSE;
+ break;
+ case slang_oper_return:
+ if (A->local.ret_size != 0)
+ {
+ /* push the result's address */
+ if (!PLAB2 (A->file, slang_asm_local_addr, 0, A->local.ret_size))
+ return GL_FALSE;
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+
+ A->swz.num_components = 0;
+ /* assign the operation to the function result (it was reserved on the stack) */
+ if (!_slang_assemble_assignment (A, op->children))
+ return GL_FALSE;
+
+ if (!PLAB (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+ }
+ if (!PLAB (A->file, slang_asm_jump, A->flow.function_end))
+ return GL_FALSE;
+ break;
+ case slang_oper_expression:
+ if (ref == slang_ref_force)
+ return GL_FALSE;
+ if (!_slang_assemble_operation (A, &op->children[0], ref))
+ return GL_FALSE;
+ break;
+ case slang_oper_if:
+ if (!_slang_assemble_if (A, op))
+ return GL_FALSE;
+ break;
+ case slang_oper_while:
+ if (!_slang_assemble_while (A, op))
+ return GL_FALSE;
+ break;
+ case slang_oper_do:
+ if (!_slang_assemble_do (A, op))
+ return GL_FALSE;
+ break;
+ case slang_oper_for:
+ if (!_slang_assemble_for (A, op))
+ return GL_FALSE;
+ break;
+ case slang_oper_void:
+ break;
+ case slang_oper_literal_bool:
+ if (ref == slang_ref_force)
+ return GL_FALSE;
+ if (!PLIT (A->file, slang_asm_bool_push, op->literal))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_literal_int:
+ if (ref == slang_ref_force)
+ return GL_FALSE;
+ if (!PLIT (A->file, slang_asm_int_push, op->literal))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_literal_float:
+ if (ref == slang_ref_force)
+ return GL_FALSE;
+ if (!PLIT (A->file, slang_asm_float_push, op->literal))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_identifier:
+ {
+ slang_variable *var;
+ GLuint size;
+
+ /* find the variable and calculate its size */
+ var = _slang_locate_variable (op->locals, op->a_id, GL_TRUE);
+ if (var == NULL)
+ return GL_FALSE;
+ size = 0;
+ if (!sizeof_variable (A, &var->type.specifier, slang_qual_none, var->array_len, &size))
+ return GL_FALSE;
+
+ /* prepare stack for dereferencing */
+ if (ref == slang_ref_forbid)
+ if (!PLAB2 (A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
+ return GL_FALSE;
+
+ /* push the variable's address */
+ if (var->global)
+ {
+ if (!PLAB (A->file, slang_asm_global_addr, var->address))
+ return GL_FALSE;
+ }
+ else
+ {
+ if (!PLAB2 (A->file, slang_asm_local_addr, var->address, size))
+ return GL_FALSE;
+ }
+
+ /* perform the dereference */
+ if (ref == slang_ref_forbid)
+ {
+ if (!PUSH (A->file, slang_asm_addr_copy))
+ return GL_FALSE;
+ if (!PLAB (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+ if (!_slang_dereference (A, op))
+ return GL_FALSE;
+ }
+ }
+ break;
+ case slang_oper_sequence:
+ if (ref == slang_ref_force)
+ return GL_FALSE;
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[0]))
+ return GL_FALSE;
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_assign:
+ if (!_slang_assemble_assign (A, op, "=", ref))
+ return GL_FALSE;
+ break;
+ case slang_oper_addassign:
+ if (!_slang_assemble_assign (A, op, "+=", ref))
+ return GL_FALSE;
+ A->ref = ref;
+ break;
+ case slang_oper_subassign:
+ if (!_slang_assemble_assign (A, op, "-=", ref))
+ return GL_FALSE;
+ A->ref = ref;
+ break;
+ case slang_oper_mulassign:
+ if (!_slang_assemble_assign (A, op, "*=", ref))
+ return GL_FALSE;
+ A->ref = ref;
+ break;
+ /*case slang_oper_modassign:*/
+ /*case slang_oper_lshassign:*/
+ /*case slang_oper_rshassign:*/
+ /*case slang_oper_orassign:*/
+ /*case slang_oper_xorassign:*/
+ /*case slang_oper_andassign:*/
+ case slang_oper_divassign:
+ if (!_slang_assemble_assign (A, op, "/=", ref))
+ return GL_FALSE;
+ A->ref = ref;
+ break;
+ case slang_oper_select:
+ if (!_slang_assemble_select (A, op))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_logicalor:
+ if (!_slang_assemble_logicalor (A, op))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_logicaland:
+ if (!_slang_assemble_logicaland (A, op))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_logicalxor:
+ if (!_slang_assemble_function_call_name (A, "^^", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ /*case slang_oper_bitor:*/
+ /*case slang_oper_bitxor:*/
+ /*case slang_oper_bitand:*/
+ case slang_oper_less:
+ if (!_slang_assemble_function_call_name (A, "<", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_greater:
+ if (!_slang_assemble_function_call_name (A, ">", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_lessequal:
+ if (!_slang_assemble_function_call_name (A, "<=", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_greaterequal:
+ if (!_slang_assemble_function_call_name (A, ">=", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ /*case slang_oper_lshift:*/
+ /*case slang_oper_rshift:*/
+ case slang_oper_add:
+ if (!_slang_assemble_function_call_name (A, "+", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_subtract:
+ if (!_slang_assemble_function_call_name (A, "-", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_multiply:
+ if (!_slang_assemble_function_call_name (A, "*", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ /*case slang_oper_modulus:*/
+ case slang_oper_divide:
+ if (!_slang_assemble_function_call_name (A, "/", op->children, 2, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_equal:
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+ if (!equality (A, op->children, GL_TRUE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_notequal:
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+ if (!equality (A, op->children, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_preincrement:
+ if (!_slang_assemble_assign (A, op, "++", ref))
+ return GL_FALSE;
+ A->ref = ref;
+ break;
+ case slang_oper_predecrement:
+ if (!_slang_assemble_assign (A, op, "--", ref))
+ return GL_FALSE;
+ A->ref = ref;
+ break;
+ case slang_oper_plus:
+ if (!_slang_dereference (A, op))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_minus:
+ if (!_slang_assemble_function_call_name (A, "-", op->children, 1, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ /*case slang_oper_complement:*/
+ case slang_oper_not:
+ if (!_slang_assemble_function_call_name (A, "!", op->children, 1, GL_FALSE))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_subscript:
+ {
+ slang_assembly_typeinfo ti_arr, ti_elem;
+
+ if (!slang_assembly_typeinfo_construct (&ti_arr))
+ return GL_FALSE;
+ if (!slang_assembly_typeinfo_construct (&ti_elem))
+ {
+ slang_assembly_typeinfo_destruct (&ti_arr);
+ return GL_FALSE;
+ }
+ if (!handle_subscript (A, &ti_elem, &ti_arr, op, ref))
+ {
+ slang_assembly_typeinfo_destruct (&ti_arr);
+ slang_assembly_typeinfo_destruct (&ti_elem);
+ return GL_FALSE;
+ }
+ slang_assembly_typeinfo_destruct (&ti_arr);
+ slang_assembly_typeinfo_destruct (&ti_elem);
+ }
+ break;
+ case slang_oper_call:
+ {
+ slang_function *fun;
+
+ fun = _slang_locate_function (A->space.funcs, op->a_id, op->children, op->num_children,
+ &A->space, A->atoms);
+ if (fun == NULL)
+ {
+ if (!_slang_assemble_constructor (A, op))
+ return GL_FALSE;
+ }
+ else
+ {
+ if (!_slang_assemble_function_call (A, fun, op->children, op->num_children, GL_FALSE))
+ return GL_FALSE;
+ }
+ A->ref = slang_ref_forbid;
+ }
+ break;
+ case slang_oper_field:
+ {
+ slang_assembly_typeinfo ti_after, ti_before;
+
+ if (!slang_assembly_typeinfo_construct (&ti_after))
+ return GL_FALSE;
+ if (!slang_assembly_typeinfo_construct (&ti_before))
+ {
+ slang_assembly_typeinfo_destruct (&ti_after);
+ return GL_FALSE;
+ }
+ if (!handle_field (A, &ti_after, &ti_before, op, ref))
+ {
+ slang_assembly_typeinfo_destruct (&ti_after);
+ slang_assembly_typeinfo_destruct (&ti_before);
+ return GL_FALSE;
+ }
+ slang_assembly_typeinfo_destruct (&ti_after);
+ slang_assembly_typeinfo_destruct (&ti_before);
+ }
+ break;
+ case slang_oper_postincrement:
+ if (!assemble_function_call_name_dummyint (A, "++", op->children))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ case slang_oper_postdecrement:
+ if (!assemble_function_call_name_dummyint (A, "--", op->children))
+ return GL_FALSE;
+ A->ref = slang_ref_forbid;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_assemble.h b/src/mesa/shader/slang/slang_assemble.h
new file mode 100644
index 00000000000..95e4fa263a3
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble.h
@@ -0,0 +1,228 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_ASSEMBLE_H
+#define SLANG_ASSEMBLE_H
+
+#include "slang_utility.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+struct slang_operation_;
+
+typedef enum slang_assembly_type_
+{
+ /* core */
+ slang_asm_none,
+ slang_asm_float_copy,
+ slang_asm_float_move,
+ slang_asm_float_push,
+ slang_asm_float_deref,
+ slang_asm_float_add,
+ slang_asm_float_multiply,
+ slang_asm_float_divide,
+ slang_asm_float_negate,
+ slang_asm_float_less,
+ slang_asm_float_equal_exp,
+ slang_asm_float_equal_int,
+ slang_asm_float_to_int,
+ slang_asm_float_sine,
+ slang_asm_float_arcsine,
+ slang_asm_float_arctan,
+ slang_asm_float_power,
+ slang_asm_float_log2,
+ slang_asm_float_floor,
+ slang_asm_float_ceil,
+ slang_asm_float_noise1,
+ slang_asm_float_noise2,
+ slang_asm_float_noise3,
+ slang_asm_float_noise4,
+ slang_asm_int_copy,
+ slang_asm_int_move,
+ slang_asm_int_push,
+ slang_asm_int_deref,
+ slang_asm_int_to_float,
+ slang_asm_int_to_addr,
+ slang_asm_bool_copy,
+ slang_asm_bool_move,
+ slang_asm_bool_push,
+ slang_asm_bool_deref,
+ slang_asm_addr_copy,
+ slang_asm_addr_push,
+ slang_asm_addr_deref,
+ slang_asm_addr_add,
+ slang_asm_addr_multiply,
+ slang_asm_vec4_tex1d,
+ slang_asm_vec4_tex2d,
+ slang_asm_vec4_tex3d,
+ slang_asm_vec4_texcube,
+ slang_asm_vec4_shad1d,
+ slang_asm_vec4_shad2d,
+ slang_asm_jump,
+ slang_asm_jump_if_zero,
+ slang_asm_enter,
+ slang_asm_leave,
+ slang_asm_local_alloc,
+ slang_asm_local_free,
+ slang_asm_local_addr,
+ slang_asm_global_addr,
+ slang_asm_call,
+ slang_asm_return,
+ slang_asm_discard,
+ slang_asm_exit,
+ /* GL_MESA_shader_debug */
+ slang_asm_float_print,
+ slang_asm_int_print,
+ slang_asm_bool_print,
+ /* vec4 */
+ slang_asm_float_to_vec4,
+ slang_asm_vec4_add,
+ slang_asm_vec4_subtract,
+ slang_asm_vec4_multiply,
+ slang_asm_vec4_divide,
+ slang_asm_vec4_negate,
+ slang_asm_vec4_dot,
+ slang_asm_vec4_copy,
+ slang_asm_vec4_deref,
+ slang_asm_vec4_equal_int,
+ /* not a real assembly instruction */
+ slang_asm__last
+} slang_assembly_type;
+
+typedef struct slang_assembly_
+{
+ slang_assembly_type type;
+ GLfloat literal;
+ GLuint param[2];
+} slang_assembly;
+
+typedef struct slang_assembly_file_
+{
+ slang_assembly *code;
+ GLuint count;
+ GLuint capacity;
+} slang_assembly_file;
+
+extern GLvoid
+_slang_assembly_file_ctr (slang_assembly_file *);
+
+GLvoid slang_assembly_file_destruct (slang_assembly_file *);
+GLboolean slang_assembly_file_push (slang_assembly_file *, slang_assembly_type);
+GLboolean slang_assembly_file_push_label (slang_assembly_file *, slang_assembly_type, GLuint);
+GLboolean slang_assembly_file_push_label2 (slang_assembly_file *, slang_assembly_type, GLuint, GLuint);
+GLboolean slang_assembly_file_push_literal (slang_assembly_file *, slang_assembly_type, GLfloat);
+
+typedef struct slang_assembly_file_restore_point_
+{
+ GLuint count;
+} slang_assembly_file_restore_point;
+
+GLboolean slang_assembly_file_restore_point_save (slang_assembly_file *,
+ slang_assembly_file_restore_point *);
+GLboolean slang_assembly_file_restore_point_load (slang_assembly_file *,
+ slang_assembly_file_restore_point *);
+
+typedef struct slang_assembly_flow_control_
+{
+ GLuint loop_start; /* for "continue" statement */
+ GLuint loop_end; /* for "break" statement */
+ GLuint function_end; /* for "return" statement */
+} slang_assembly_flow_control;
+
+typedef struct slang_assembly_local_info_
+{
+ GLuint ret_size;
+ GLuint addr_tmp;
+ GLuint swizzle_tmp;
+} slang_assembly_local_info;
+
+typedef enum
+{
+ slang_ref_force,
+ slang_ref_forbid/*,
+ slang_ref_freelance*/
+} slang_ref_type;
+
+/*
+ * Holds a complete information about vector swizzle - the <swizzle> array contains
+ * vector component source indices, where 0 is "x", 1 is "y", 2 is "z" and 3 is "w".
+ * Example: "xwz" --> { 3, { 0, 3, 2, not used } }.
+ */
+typedef struct slang_swizzle_
+{
+ GLuint num_components;
+ GLuint swizzle[4];
+} slang_swizzle;
+
+typedef struct slang_assembly_name_space_
+{
+ struct slang_function_scope_ *funcs;
+ struct slang_struct_scope_ *structs;
+ struct slang_variable_scope_ *vars;
+} slang_assembly_name_space;
+
+typedef struct slang_assemble_ctx_
+{
+ slang_assembly_file *file;
+ struct slang_machine_ *mach;
+ slang_atom_pool *atoms;
+ slang_assembly_name_space space;
+ slang_assembly_flow_control flow;
+ slang_assembly_local_info local;
+ slang_ref_type ref;
+ slang_swizzle swz;
+} slang_assemble_ctx;
+
+struct slang_function_ *_slang_locate_function (struct slang_function_scope_ *funcs, slang_atom name,
+ struct slang_operation_ *params, GLuint num_params, slang_assembly_name_space *space,
+ slang_atom_pool *);
+
+GLboolean _slang_assemble_function (slang_assemble_ctx *, struct slang_function_ *);
+
+GLboolean _slang_cleanup_stack (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_dereference (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_function_call (slang_assemble_ctx *, struct slang_function_ *,
+ struct slang_operation_ *, GLuint, GLboolean);
+
+GLboolean _slang_assemble_function_call_name (slang_assemble_ctx *, const char *,
+ struct slang_operation_ *, GLuint, GLboolean);
+
+GLboolean _slang_assemble_operation (slang_assemble_ctx *, struct slang_operation_ *,
+ slang_ref_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "slang_assemble_assignment.h"
+#include "slang_assemble_typeinfo.h"
+#include "slang_assemble_constructor.h"
+#include "slang_assemble_conditional.h"
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_assemble_assignment.c b/src/mesa/shader/slang/slang_assemble_assignment.c
new file mode 100644
index 00000000000..d894a8db18c
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_assignment.c
@@ -0,0 +1,217 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_assemble_assignment.c
+ * slang assignment expressions assembler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_assemble.h"
+#include "slang_storage.h"
+
+/*
+ * _slang_assemble_assignment()
+ *
+ * Copies values on the stack (<component 0> to <component N-1>) to a memory
+ * location pointed by <addr of variable>.
+ *
+ * in:
+ * +------------------+
+ * | addr of variable |
+ * +------------------+
+ * | component N-1 |
+ * | ... |
+ * | component 0 |
+ * +------------------+
+ *
+ * out:
+ * +------------------+
+ * | addr of variable |
+ * +------------------+
+ */
+
+static GLboolean
+assign_basic (slang_assemble_ctx *A, slang_storage_type type, GLuint *index, GLuint size)
+{
+ GLuint dst_offset, dst_addr_loc;
+ slang_assembly_type ty;
+
+ /* Calculate the offset within destination variable to write. */
+ if (A->swz.num_components != 0)
+ dst_offset = A->swz.swizzle[*index / 4] * 4;
+ else
+ dst_offset = *index;
+
+ switch (type) {
+ case slang_stor_bool:
+ ty = slang_asm_bool_copy;
+ break;
+ case slang_stor_int:
+ ty = slang_asm_int_copy;
+ break;
+ case slang_stor_float:
+ ty = slang_asm_float_copy;
+ break;
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ case slang_stor_vec4:
+ ty = slang_asm_vec4_copy;
+ break;
+#endif
+ default:
+ _mesa_problem(NULL, "Unexpected arr->type in assign_basic");
+ ty = slang_asm_none;
+ }
+
+ /* Calculate the distance from top of the stack to the destination address. As the
+ * copy operation progresses, components of the source are being successively popped
+ * off the stack by the amount of *index increase step.
+ */
+ dst_addr_loc = size - *index;
+
+ if (!slang_assembly_file_push_label2 (A->file, ty, dst_addr_loc, dst_offset))
+ return GL_FALSE;
+ *index += _slang_sizeof_type (type);
+
+ return GL_TRUE;
+}
+
+static GLboolean
+assign_aggregate (slang_assemble_ctx *A, const slang_storage_aggregate *agg, GLuint *index,
+ GLuint size)
+{
+ GLuint i;
+
+ for (i = 0; i < agg->count; i++) {
+ const slang_storage_array *arr = &agg->arrays[i];
+ GLuint j;
+
+ for (j = 0; j < arr->length; j++) {
+ if (arr->type == slang_stor_aggregate) {
+ if (!assign_aggregate (A, arr->aggregate, index, size))
+ return GL_FALSE;
+ }
+ else {
+ /* When the destination is swizzled, we are forced to do float_copy, even if
+ * vec4 extension is enabled with vec4_copy operation.
+ */
+ if (A->swz.num_components != 0 && arr->type == slang_stor_vec4) {
+ if (!assign_basic (A, slang_stor_float, index, size))
+ return GL_FALSE;
+ if (!assign_basic (A, slang_stor_float, index, size))
+ return GL_FALSE;
+ if (!assign_basic (A, slang_stor_float, index, size))
+ return GL_FALSE;
+ if (!assign_basic (A, slang_stor_float, index, size))
+ return GL_FALSE;
+ }
+ else {
+ if (!assign_basic (A, arr->type, index, size))
+ return GL_FALSE;
+ }
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean _slang_assemble_assignment (slang_assemble_ctx *A, slang_operation *op)
+{
+ slang_assembly_typeinfo ti;
+ GLboolean result = GL_FALSE;
+ slang_storage_aggregate agg;
+ GLuint index, size;
+
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation (A, op, &ti))
+ goto end1;
+
+ if (!slang_storage_aggregate_construct (&agg))
+ goto end1;
+ if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
+ A->space.vars, A->mach, A->file, A->atoms))
+ goto end;
+
+ index = 0;
+ size = _slang_sizeof_aggregate (&agg);
+ result = assign_aggregate (A, &agg, &index, size);
+
+end1:
+ slang_storage_aggregate_destruct (&agg);
+end:
+ slang_assembly_typeinfo_destruct (&ti);
+ return result;
+}
+
+/*
+ * _slang_assemble_assign()
+ *
+ * Performs unary (pre ++ and --) or binary (=, +=, -=, *=, /=) assignment on the operation's
+ * children.
+ */
+
+GLboolean _slang_assemble_assign (slang_assemble_ctx *A, slang_operation *op, const char *oper,
+ slang_ref_type ref)
+{
+ slang_swizzle swz;
+
+ if (ref == slang_ref_forbid)
+ {
+ if (!slang_assembly_file_push_label2 (A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
+ return GL_FALSE;
+ }
+
+ if (slang_string_compare ("=", oper) == 0)
+ {
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_force))
+ return GL_FALSE;
+ swz = A->swz;
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+ A->swz = swz;
+ if (!_slang_assemble_assignment (A, op->children))
+ return GL_FALSE;
+ }
+ else
+ {
+ if (!_slang_assemble_function_call_name (A, oper, op->children, op->num_children, GL_TRUE))
+ return GL_FALSE;
+ }
+
+ if (ref == slang_ref_forbid)
+ {
+ if (!slang_assembly_file_push (A->file, slang_asm_addr_copy))
+ return GL_FALSE;
+ if (!slang_assembly_file_push_label (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+ if (!_slang_dereference (A, op->children))
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_assemble_assignment.h b/src/mesa/shader/slang/slang_assemble_assignment.h
new file mode 100644
index 00000000000..7b993b543b1
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_assignment.h
@@ -0,0 +1,42 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_ASSEMBLE_ASSIGNMENT_H
+#define SLANG_ASSEMBLE_ASSIGNMENT_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+GLboolean _slang_assemble_assignment (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_assign (slang_assemble_ctx *, struct slang_operation_ *, const char *,
+ slang_ref_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_assemble_conditional.c b/src/mesa/shader/slang/slang_assemble_conditional.c
new file mode 100644
index 00000000000..f3400e8753a
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_conditional.c
@@ -0,0 +1,448 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_assemble_conditional.c
+ * slang condtional expressions assembler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_assemble.h"
+#include "slang_compile.h"
+
+/*
+ * _slang_assemble_logicaland()
+ *
+ * and:
+ * <left-expression>
+ * jumpz zero
+ * <right-expression>
+ * jump end
+ * zero:
+ * push 0
+ * end:
+ */
+
+GLboolean _slang_assemble_logicaland (slang_assemble_ctx *A, slang_operation *op)
+{
+ GLuint zero_jump, end_jump;
+
+ /* evaluate left expression */
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to pushing 0 if not true */
+ zero_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump_if_zero))
+ return GL_FALSE;
+
+ /* evaluate right expression */
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to the end of the expression */
+ end_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* push 0 on stack */
+ A->file->code[zero_jump].param[0] = A->file->count;
+ if (!slang_assembly_file_push_literal (A->file, slang_asm_bool_push, (GLfloat) 0))
+ return GL_FALSE;
+
+ /* the end of the expression */
+ A->file->code[end_jump].param[0] = A->file->count;
+
+ return GL_TRUE;
+}
+
+/*
+ * _slang_assemble_logicalor()
+ *
+ * or:
+ * <left-expression>
+ * jumpz right
+ * push 1
+ * jump end
+ * right:
+ * <right-expression>
+ * end:
+ */
+
+GLboolean _slang_assemble_logicalor (slang_assemble_ctx *A, slang_operation *op)
+{
+ GLuint right_jump, end_jump;
+
+ /* evaluate left expression */
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to evaluation of right expression if not true */
+ right_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump_if_zero))
+ return GL_FALSE;
+
+ /* push 1 on stack */
+ if (!slang_assembly_file_push_literal (A->file, slang_asm_bool_push, (GLfloat) 1))
+ return GL_FALSE;
+
+ /* jump to the end of the expression */
+ end_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* evaluate right expression */
+ A->file->code[right_jump].param[0] = A->file->count;
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* the end of the expression */
+ A->file->code[end_jump].param[0] = A->file->count;
+
+ return GL_TRUE;
+}
+
+/*
+ * _slang_assemble_select()
+ *
+ * select:
+ * <condition-expression>
+ * jumpz false
+ * <true-expression>
+ * jump end
+ * false:
+ * <false-expression>
+ * end:
+ */
+
+GLboolean _slang_assemble_select (slang_assemble_ctx *A, slang_operation *op)
+{
+ GLuint cond_jump, end_jump;
+
+ /* execute condition expression */
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to false expression if not true */
+ cond_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump_if_zero))
+ return GL_FALSE;
+
+ /* execute true expression */
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to the end of the expression */
+ end_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* resolve false point */
+ A->file->code[cond_jump].param[0] = A->file->count;
+
+ /* execute false expression */
+ if (!_slang_assemble_operation (A, &op->children[2], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* resolve the end of the expression */
+ A->file->code[end_jump].param[0] = A->file->count;
+
+ return GL_TRUE;
+}
+
+/*
+ * _slang_assemble_for()
+ *
+ * for:
+ * <init-statement>
+ * jump start
+ * break:
+ * jump end
+ * continue:
+ * <loop-increment>
+ * start:
+ * <condition-statement>
+ * jumpz end
+ * <loop-body>
+ * jump continue
+ * end:
+ */
+
+GLboolean _slang_assemble_for (slang_assemble_ctx *A, slang_operation *op)
+{
+ GLuint start_jump, end_jump, cond_jump;
+ GLuint break_label, cont_label;
+ slang_assembly_flow_control save_flow = A->flow;
+
+ /* execute initialization statement */
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[0]))
+ return GL_FALSE;
+
+ /* skip the "go to the end of the loop" and loop-increment statements */
+ start_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* go to the end of the loop - break statements are directed here */
+ break_label = A->file->count;
+ end_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* resolve the beginning of the loop - continue statements are directed here */
+ cont_label = A->file->count;
+
+ /* execute loop-increment statement */
+ if (!_slang_assemble_operation (A, &op->children[2], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[2]))
+ return GL_FALSE;
+
+ /* resolve the condition point */
+ A->file->code[start_jump].param[0] = A->file->count;
+
+ /* execute condition statement */
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to the end of the loop if not true */
+ cond_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump_if_zero))
+ return GL_FALSE;
+
+ /* execute loop body */
+ A->flow.loop_start = cont_label;
+ A->flow.loop_end = break_label;
+ if (!_slang_assemble_operation (A, &op->children[3], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[3]))
+ return GL_FALSE;
+ A->flow = save_flow;
+
+ /* go to the beginning of the loop */
+ if (!slang_assembly_file_push_label (A->file, slang_asm_jump, cont_label))
+ return GL_FALSE;
+
+ /* resolve the end of the loop */
+ A->file->code[end_jump].param[0] = A->file->count;
+ A->file->code[cond_jump].param[0] = A->file->count;
+
+ return GL_TRUE;
+}
+
+/*
+ * _slang_assemble_do()
+ *
+ * do:
+ * jump start
+ * break:
+ * jump end
+ * continue:
+ * jump condition
+ * start:
+ * <loop-body>
+ * condition:
+ * <condition-statement>
+ * jumpz end
+ * jump start
+ * end:
+ */
+
+GLboolean _slang_assemble_do (slang_assemble_ctx *A, slang_operation *op)
+{
+ GLuint skip_jump, end_jump, cont_jump, cond_jump;
+ GLuint break_label, cont_label;
+ slang_assembly_flow_control save_flow = A->flow;
+
+ /* skip the "go to the end of the loop" and "go to condition" statements */
+ skip_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* go to the end of the loop - break statements are directed here */
+ break_label = A->file->count;
+ end_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* go to condition - continue statements are directed here */
+ cont_label = A->file->count;
+ cont_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* resolve the beginning of the loop */
+ A->file->code[skip_jump].param[0] = A->file->count;
+
+ /* execute loop body */
+ A->flow.loop_start = cont_label;
+ A->flow.loop_end = break_label;
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[0]))
+ return GL_FALSE;
+ A->flow = save_flow;
+
+ /* resolve condition point */
+ A->file->code[cont_jump].param[0] = A->file->count;
+
+ /* execute condition statement */
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to the end of the loop if not true */
+ cond_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump_if_zero))
+ return GL_FALSE;
+
+ /* jump to the beginning of the loop */
+ if (!slang_assembly_file_push_label (A->file, slang_asm_jump, A->file->code[skip_jump].param[0]))
+ return GL_FALSE;
+
+ /* resolve the end of the loop */
+ A->file->code[end_jump].param[0] = A->file->count;
+ A->file->code[cond_jump].param[0] = A->file->count;
+
+ return GL_TRUE;
+}
+
+/*
+ * _slang_assemble_while()
+ *
+ * while:
+ * jump continue
+ * break:
+ * jump end
+ * continue:
+ * <condition-statement>
+ * jumpz end
+ * <loop-body>
+ * jump continue
+ * end:
+ */
+
+GLboolean _slang_assemble_while (slang_assemble_ctx *A, slang_operation *op)
+{
+ GLuint skip_jump, end_jump, cond_jump;
+ GLuint break_label;
+ slang_assembly_flow_control save_flow = A->flow;
+
+ /* skip the "go to the end of the loop" statement */
+ skip_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* go to the end of the loop - break statements are directed here */
+ break_label = A->file->count;
+ end_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* resolve the beginning of the loop - continue statements are directed here */
+ A->file->code[skip_jump].param[0] = A->file->count;
+
+ /* execute condition statement */
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to the end of the loop if not true */
+ cond_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump_if_zero))
+ return GL_FALSE;
+
+ /* execute loop body */
+ A->flow.loop_start = A->file->code[skip_jump].param[0];
+ A->flow.loop_end = break_label;
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[1]))
+ return GL_FALSE;
+ A->flow = save_flow;
+
+ /* jump to the beginning of the loop */
+ if (!slang_assembly_file_push_label (A->file, slang_asm_jump, A->file->code[skip_jump].param[0]))
+ return GL_FALSE;
+
+ /* resolve the end of the loop */
+ A->file->code[end_jump].param[0] = A->file->count;
+ A->file->code[cond_jump].param[0] = A->file->count;
+
+ return GL_TRUE;
+}
+
+/*
+ * _slang_assemble_if()
+ *
+ * if:
+ * <condition-statement>
+ * jumpz else
+ * <true-statement>
+ * jump end
+ * else:
+ * <false-statement>
+ * end:
+ */
+
+GLboolean _slang_assemble_if (slang_assemble_ctx *A, slang_operation *op)
+{
+ GLuint cond_jump, else_jump;
+
+ /* execute condition statement */
+ if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid))
+ return GL_FALSE;
+
+ /* jump to false-statement if not true */
+ cond_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump_if_zero))
+ return GL_FALSE;
+
+ /* execute true-statement */
+ if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[1]))
+ return GL_FALSE;
+
+ /* skip if-false statement */
+ else_jump = A->file->count;
+ if (!slang_assembly_file_push (A->file, slang_asm_jump))
+ return GL_FALSE;
+
+ /* resolve start of false-statement */
+ A->file->code[cond_jump].param[0] = A->file->count;
+
+ /* execute false-statement */
+ if (!_slang_assemble_operation (A, &op->children[2], slang_ref_forbid/*slang_ref_freelance*/))
+ return GL_FALSE;
+ if (!_slang_cleanup_stack (A, &op->children[2]))
+ return GL_FALSE;
+
+ /* resolve end of if-false statement */
+ A->file->code[else_jump].param[0] = A->file->count;
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_assemble_conditional.h b/src/mesa/shader/slang/slang_assemble_conditional.h
new file mode 100644
index 00000000000..ce9e4de6c9d
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_conditional.h
@@ -0,0 +1,51 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_ASSEMBLE_CONDITIONAL_H
+#define SLANG_ASSEMBLE_CONDITIONAL_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+GLboolean _slang_assemble_logicaland (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_logicalor (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_select (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_for (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_do (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_while (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_if (slang_assemble_ctx *, struct slang_operation_ *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_assemble_constructor.c b/src/mesa/shader/slang/slang_assemble_constructor.c
new file mode 100644
index 00000000000..9d1aa707182
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_constructor.c
@@ -0,0 +1,379 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_assemble_constructor.c
+ * slang constructor and vector swizzle assembler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_assemble.h"
+#include "slang_storage.h"
+
+/* _slang_is_swizzle() */
+
+GLboolean _slang_is_swizzle (const char *field, GLuint rows, slang_swizzle *swz)
+{
+ GLuint i;
+ GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE;
+
+ /* the swizzle can be at most 4-component long */
+ swz->num_components = slang_string_length (field);
+ if (swz->num_components > 4)
+ return GL_FALSE;
+
+ for (i = 0; i < swz->num_components; i++)
+ {
+ /* mark which swizzle group is used */
+ switch (field[i])
+ {
+ case 'x':
+ case 'y':
+ case 'z':
+ case 'w':
+ xyzw = GL_TRUE;
+ break;
+ case 'r':
+ case 'g':
+ case 'b':
+ case 'a':
+ rgba = GL_TRUE;
+ break;
+ case 's':
+ case 't':
+ case 'p':
+ case 'q':
+ stpq = GL_TRUE;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ /* collect swizzle component */
+ switch (field[i])
+ {
+ case 'x':
+ case 'r':
+ case 's':
+ swz->swizzle[i] = 0;
+ break;
+ case 'y':
+ case 'g':
+ case 't':
+ swz->swizzle[i] = 1;
+ break;
+ case 'z':
+ case 'b':
+ case 'p':
+ swz->swizzle[i] = 2;
+ break;
+ case 'w':
+ case 'a':
+ case 'q':
+ swz->swizzle[i] = 3;
+ break;
+ }
+
+ /* check if the component is valid for given vector's row count */
+ if (rows <= swz->swizzle[i])
+ return GL_FALSE;
+ }
+
+ /* only one swizzle group can be used */
+ if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+/* _slang_is_swizzle_mask() */
+
+GLboolean _slang_is_swizzle_mask (const slang_swizzle *swz, GLuint rows)
+{
+ GLuint i, c = 0;
+
+ /* the swizzle may not be longer than the vector dim */
+ if (swz->num_components > rows)
+ return GL_FALSE;
+
+ /* the swizzle components cannot be duplicated */
+ for (i = 0; i < swz->num_components; i++)
+ {
+ if ((c & (1 << swz->swizzle[i])) != 0)
+ return GL_FALSE;
+ c |= 1 << swz->swizzle[i];
+ }
+
+ return GL_TRUE;
+}
+
+/* _slang_multiply_swizzles() */
+
+GLvoid _slang_multiply_swizzles (slang_swizzle *dst, const slang_swizzle *left,
+ const slang_swizzle *right)
+{
+ GLuint i;
+
+ dst->num_components = right->num_components;
+ for (i = 0; i < right->num_components; i++)
+ dst->swizzle[i] = left->swizzle[right->swizzle[i]];
+}
+
+/* _slang_assemble_constructor() */
+
+static GLboolean
+sizeof_argument (slang_assemble_ctx *A, GLuint *size, slang_operation *op)
+{
+ slang_assembly_typeinfo ti;
+ GLboolean result = GL_FALSE;
+ slang_storage_aggregate agg;
+
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation (A, op, &ti))
+ goto end1;
+
+ if (!slang_storage_aggregate_construct (&agg))
+ goto end1;
+ if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
+ A->space.vars, A->mach, A->file, A->atoms))
+ goto end;
+
+ *size = _slang_sizeof_aggregate (&agg);
+ result = GL_TRUE;
+
+end:
+ slang_storage_aggregate_destruct (&agg);
+end1:
+ slang_assembly_typeinfo_destruct (&ti);
+ return result;
+}
+
+static GLboolean constructor_aggregate (slang_assemble_ctx *A, const slang_storage_aggregate *flat,
+ slang_operation *op, GLuint garbage_size)
+{
+ slang_assembly_typeinfo ti;
+ GLboolean result = GL_FALSE;
+ slang_storage_aggregate agg, flat_agg;
+
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation (A, op, &ti))
+ goto end1;
+
+ if (!slang_storage_aggregate_construct (&agg))
+ goto end1;
+ if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
+ A->space.vars, A->mach, A->file, A->atoms))
+ goto end2;
+
+ if (!slang_storage_aggregate_construct (&flat_agg))
+ goto end2;
+ if (!_slang_flatten_aggregate (&flat_agg, &agg))
+ goto end;
+
+ if (!_slang_assemble_operation (A, op, slang_ref_forbid))
+ goto end;
+
+ /* TODO: convert (generic) elements */
+
+ /* free the garbage */
+ if (garbage_size != 0)
+ {
+ GLuint i;
+
+ /* move the non-garbage part to the end of the argument */
+ if (!slang_assembly_file_push_label (A->file, slang_asm_addr_push, 0))
+ goto end;
+ for (i = flat_agg.count * 4 - garbage_size; i > 0; i -= 4)
+ {
+ if (!slang_assembly_file_push_label2 (A->file, slang_asm_float_move,
+ garbage_size + i, i))
+ {
+ goto end;
+ }
+ }
+ if (!slang_assembly_file_push_label (A->file, slang_asm_local_free, garbage_size + 4))
+ goto end;
+ }
+
+ result = GL_TRUE;
+end:
+ slang_storage_aggregate_destruct (&flat_agg);
+end2:
+ slang_storage_aggregate_destruct (&agg);
+end1:
+ slang_assembly_typeinfo_destruct (&ti);
+ return result;
+}
+
+GLboolean _slang_assemble_constructor (slang_assemble_ctx *A, slang_operation *op)
+{
+ slang_assembly_typeinfo ti;
+ GLboolean result = GL_FALSE;
+ slang_storage_aggregate agg, flat;
+ GLuint size, i;
+ GLuint arg_sums[2];
+
+ /* get typeinfo of the constructor (the result of constructor expression) */
+ if (!slang_assembly_typeinfo_construct (&ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation (A, op, &ti))
+ goto end1;
+
+ /* create an aggregate of the constructor */
+ if (!slang_storage_aggregate_construct (&agg))
+ goto end1;
+ if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
+ A->space.vars, A->mach, A->file, A->atoms))
+ goto end2;
+
+ /* calculate size of the constructor */
+ size = _slang_sizeof_aggregate (&agg);
+
+ /* flatten the constructor */
+ if (!slang_storage_aggregate_construct (&flat))
+ goto end2;
+ if (!_slang_flatten_aggregate (&flat, &agg))
+ goto end;
+
+ /* collect the last two constructor's argument size sums */
+ arg_sums[0] = 0; /* will hold all but the last argument's size sum */
+ arg_sums[1] = 0; /* will hold all argument's size sum */
+ for (i = 0; i < op->num_children; i++)
+ {
+ GLuint arg_size = 0;
+
+ if (!sizeof_argument (A, &arg_size, &op->children[i]))
+ goto end;
+ if (i > 0)
+ arg_sums[0] = arg_sums[1];
+ arg_sums[1] += arg_size;
+ }
+
+ /* check if there are too many arguments */
+ if (arg_sums[0] >= size)
+ {
+ /* TODO: info log: too many arguments in constructor list */
+ goto end;
+ }
+
+ /* check if there are too few arguments */
+ if (arg_sums[1] < size)
+ {
+ /* TODO: info log: too few arguments in constructor list */
+ goto end;
+ }
+
+ /* traverse the children that form the constructor expression */
+ for (i = op->num_children; i > 0; i--)
+ {
+ GLuint garbage_size;
+
+ /* the last argument may be too big - calculate the unnecessary data size */
+ if (i == op->num_children)
+ garbage_size = arg_sums[1] - size;
+ else
+ garbage_size = 0;
+
+ if (!constructor_aggregate (A, &flat, &op->children[i - 1], garbage_size))
+ goto end;
+ }
+
+ result = GL_TRUE;
+end:
+ slang_storage_aggregate_destruct (&flat);
+end2:
+ slang_storage_aggregate_destruct (&agg);
+end1:
+ slang_assembly_typeinfo_destruct (&ti);
+ return result;
+}
+
+/* _slang_assemble_constructor_from_swizzle() */
+
+GLboolean _slang_assemble_constructor_from_swizzle (slang_assemble_ctx *A, const slang_swizzle *swz,
+ slang_type_specifier *spec, slang_type_specifier *master_spec)
+{
+ GLuint master_rows, i;
+
+ master_rows = _slang_type_dim (master_spec->type);
+ for (i = 0; i < master_rows; i++)
+ {
+ switch (_slang_type_base (master_spec->type))
+ {
+ case slang_spec_bool:
+ if (!slang_assembly_file_push_label2 (A->file, slang_asm_bool_copy,
+ (master_rows - i) * 4, i * 4))
+ return GL_FALSE;
+ break;
+ case slang_spec_int:
+ if (!slang_assembly_file_push_label2 (A->file, slang_asm_int_copy,
+ (master_rows - i) * 4, i * 4))
+ return GL_FALSE;
+ break;
+ case slang_spec_float:
+ if (!slang_assembly_file_push_label2 (A->file, slang_asm_float_copy,
+ (master_rows - i) * 4, i * 4))
+ return GL_FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!slang_assembly_file_push_label (A->file, slang_asm_local_free, 4))
+ return GL_FALSE;
+ for (i = swz->num_components; i > 0; i--)
+ {
+ GLuint n = i - 1;
+
+ if (!slang_assembly_file_push_label2 (A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
+ return GL_FALSE;
+ if (!slang_assembly_file_push_label (A->file, slang_asm_addr_push, swz->swizzle[n] * 4))
+ return GL_FALSE;
+ if (!slang_assembly_file_push (A->file, slang_asm_addr_add))
+ return GL_FALSE;
+ switch (_slang_type_base (master_spec->type))
+ {
+ case slang_spec_bool:
+ if (!slang_assembly_file_push (A->file, slang_asm_bool_deref))
+ return GL_FALSE;
+ break;
+ case slang_spec_int:
+ if (!slang_assembly_file_push (A->file, slang_asm_int_deref))
+ return GL_FALSE;
+ break;
+ case slang_spec_float:
+ if (!slang_assembly_file_push (A->file, slang_asm_float_deref))
+ return GL_FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_assemble_constructor.h b/src/mesa/shader/slang/slang_assemble_constructor.h
new file mode 100644
index 00000000000..41a03943cf5
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_constructor.h
@@ -0,0 +1,64 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_ASSEMBLE_CONSTRUCTOR_H
+#define SLANG_ASSEMBLE_CONSTRUCTOR_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Checks if a field selector is a general swizzle (an r-value swizzle with replicated
+ * components or an l-value swizzle mask) for a vector.
+ * Returns GL_TRUE if this is the case, <swz> is filled with swizzle information.
+ * Returns GL_FALSE otherwise.
+ */
+GLboolean _slang_is_swizzle (const char *field, GLuint rows, slang_swizzle *swz);
+
+/*
+ * Checks if a general swizzle is an l-value swizzle - these swizzles do not have
+ * duplicated fields.
+ * Returns GL_TRUE if this is a swizzle mask.
+ * Returns GL_FALSE otherwise
+ */
+GLboolean _slang_is_swizzle_mask (const slang_swizzle *swz, GLuint rows);
+
+/*
+ * Combines (multiplies) two swizzles to form single swizzle.
+ * Example: "vec.wzyx.yx" --> "vec.zw".
+ */
+GLvoid _slang_multiply_swizzles (slang_swizzle *, const slang_swizzle *, const slang_swizzle *);
+
+GLboolean _slang_assemble_constructor (slang_assemble_ctx *, struct slang_operation_ *);
+
+GLboolean _slang_assemble_constructor_from_swizzle (slang_assemble_ctx *, const slang_swizzle *,
+ slang_type_specifier *, slang_type_specifier *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_assemble_typeinfo.c b/src/mesa/shader/slang/slang_assemble_typeinfo.c
new file mode 100644
index 00000000000..58f4e24f256
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_typeinfo.c
@@ -0,0 +1,587 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_assemble_typeinfo.c
+ * slang type info
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_assemble.h"
+#include "slang_compile.h"
+
+/*
+ * slang_type_specifier
+ */
+
+GLvoid slang_type_specifier_ctr (slang_type_specifier *self)
+{
+ self->type = slang_spec_void;
+ self->_struct = NULL;
+ self->_array = NULL;
+}
+
+GLvoid slang_type_specifier_dtr (slang_type_specifier *self)
+{
+ if (self->_struct != NULL)
+ {
+ slang_struct_destruct (self->_struct);
+ slang_alloc_free (self->_struct);
+ }
+ if (self->_array != NULL)
+ {
+ slang_type_specifier_dtr (self->_array);
+ slang_alloc_free (self->_array);
+ }
+}
+
+GLboolean slang_type_specifier_copy (slang_type_specifier *x, const slang_type_specifier *y)
+{
+ slang_type_specifier z;
+
+ slang_type_specifier_ctr (&z);
+ z.type = y->type;
+ if (z.type == slang_spec_struct)
+ {
+ z._struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));
+ if (z._struct == NULL)
+ {
+ slang_type_specifier_dtr (&z);
+ return GL_FALSE;
+ }
+ if (!slang_struct_construct (z._struct))
+ {
+ slang_alloc_free (z._struct);
+ slang_type_specifier_dtr (&z);
+ return GL_FALSE;
+ }
+ if (!slang_struct_copy (z._struct, y->_struct))
+ {
+ slang_type_specifier_dtr (&z);
+ return GL_FALSE;
+ }
+ }
+ else if (z.type == slang_spec_array)
+ {
+ z._array = (slang_type_specifier *) slang_alloc_malloc (sizeof (slang_type_specifier));
+ if (z._array == NULL)
+ {
+ slang_type_specifier_dtr (&z);
+ return GL_FALSE;
+ }
+ slang_type_specifier_ctr (z._array);
+ if (!slang_type_specifier_copy (z._array, y->_array))
+ {
+ slang_type_specifier_dtr (&z);
+ return GL_FALSE;
+ }
+ }
+ slang_type_specifier_dtr (x);
+ *x = z;
+ return GL_TRUE;
+}
+
+GLboolean slang_type_specifier_equal (const slang_type_specifier *x, const slang_type_specifier *y)
+{
+ if (x->type != y->type)
+ return 0;
+ if (x->type == slang_spec_struct)
+ return slang_struct_equal (x->_struct, y->_struct);
+ if (x->type == slang_spec_array)
+ return slang_type_specifier_equal (x->_array, y->_array);
+ return 1;
+}
+
+/* slang_assembly_typeinfo */
+
+GLboolean slang_assembly_typeinfo_construct (slang_assembly_typeinfo *ti)
+{
+ slang_type_specifier_ctr (&ti->spec);
+ ti->array_len = 0;
+ return GL_TRUE;
+}
+
+GLvoid slang_assembly_typeinfo_destruct (slang_assembly_typeinfo *ti)
+{
+ slang_type_specifier_dtr (&ti->spec);
+}
+
+/* _slang_typeof_operation() */
+
+static GLboolean typeof_existing_function (const char *name, slang_operation *params,
+ GLuint num_params, slang_assembly_name_space *space, slang_type_specifier *spec,
+ slang_atom_pool *atoms)
+{
+ slang_atom atom;
+ GLboolean exists;
+
+ atom = slang_atom_pool_atom (atoms, name);
+ if (!_slang_typeof_function (atom, params, num_params, space, spec, &exists, atoms))
+ return GL_FALSE;
+ return exists;
+}
+
+GLboolean _slang_typeof_operation (slang_assemble_ctx *A, slang_operation *op,
+ slang_assembly_typeinfo *ti)
+{
+ return _slang_typeof_operation_ (op, &A->space, ti, A->atoms);
+}
+
+GLboolean _slang_typeof_operation_ (slang_operation *op, slang_assembly_name_space *space,
+ slang_assembly_typeinfo *ti, slang_atom_pool *atoms)
+{
+ ti->can_be_referenced = GL_FALSE;
+ ti->is_swizzled = GL_FALSE;
+
+ switch (op->type)
+ {
+ case slang_oper_block_no_new_scope:
+ case slang_oper_block_new_scope:
+ case slang_oper_variable_decl:
+ case slang_oper_asm:
+ case slang_oper_break:
+ case slang_oper_continue:
+ case slang_oper_discard:
+ case slang_oper_return:
+ case slang_oper_if:
+ case slang_oper_while:
+ case slang_oper_do:
+ case slang_oper_for:
+ case slang_oper_void:
+ ti->spec.type = slang_spec_void;
+ break;
+ case slang_oper_expression:
+ case slang_oper_assign:
+ case slang_oper_addassign:
+ case slang_oper_subassign:
+ case slang_oper_mulassign:
+ case slang_oper_divassign:
+ case slang_oper_preincrement:
+ case slang_oper_predecrement:
+ if (!_slang_typeof_operation_ (op->children, space, ti, atoms))
+ return 0;
+ break;
+ case slang_oper_literal_bool:
+ case slang_oper_logicalor:
+ case slang_oper_logicalxor:
+ case slang_oper_logicaland:
+ case slang_oper_equal:
+ case slang_oper_notequal:
+ case slang_oper_less:
+ case slang_oper_greater:
+ case slang_oper_lessequal:
+ case slang_oper_greaterequal:
+ case slang_oper_not:
+ ti->spec.type = slang_spec_bool;
+ break;
+ case slang_oper_literal_int:
+ ti->spec.type = slang_spec_int;
+ break;
+ case slang_oper_literal_float:
+ ti->spec.type = slang_spec_float;
+ break;
+ case slang_oper_identifier:
+ {
+ slang_variable *var;
+
+ var = _slang_locate_variable (op->locals, op->a_id, GL_TRUE);
+ if (var == NULL)
+ return GL_FALSE;
+ if (!slang_type_specifier_copy (&ti->spec, &var->type.specifier))
+ return GL_FALSE;
+ ti->can_be_referenced = GL_TRUE;
+ ti->array_len = var->array_len;
+ }
+ break;
+ case slang_oper_sequence:
+ /* TODO: check [0] and [1] if they match */
+ if (!_slang_typeof_operation_ (&op->children[1], space, ti, atoms))
+ return GL_FALSE;
+ ti->can_be_referenced = GL_FALSE;
+ ti->is_swizzled = GL_FALSE;
+ break;
+ /*case slang_oper_modassign:*/
+ /*case slang_oper_lshassign:*/
+ /*case slang_oper_rshassign:*/
+ /*case slang_oper_orassign:*/
+ /*case slang_oper_xorassign:*/
+ /*case slang_oper_andassign:*/
+ case slang_oper_select:
+ /* TODO: check [1] and [2] if they match */
+ if (!_slang_typeof_operation_ (&op->children[1], space, ti, atoms))
+ return GL_FALSE;
+ ti->can_be_referenced = GL_FALSE;
+ ti->is_swizzled = GL_FALSE;
+ break;
+ /*case slang_oper_bitor:*/
+ /*case slang_oper_bitxor:*/
+ /*case slang_oper_bitand:*/
+ /*case slang_oper_lshift:*/
+ /*case slang_oper_rshift:*/
+ case slang_oper_add:
+ if (!typeof_existing_function ("+", op->children, 2, space, &ti->spec, atoms))
+ return GL_FALSE;
+ break;
+ case slang_oper_subtract:
+ if (!typeof_existing_function ("-", op->children, 2, space, &ti->spec, atoms))
+ return GL_FALSE;
+ break;
+ case slang_oper_multiply:
+ if (!typeof_existing_function ("*", op->children, 2, space, &ti->spec, atoms))
+ return GL_FALSE;
+ break;
+ case slang_oper_divide:
+ if (!typeof_existing_function ("/", op->children, 2, space, &ti->spec, atoms))
+ return GL_FALSE;
+ break;
+ /*case slang_oper_modulus:*/
+ case slang_oper_plus:
+ if (!_slang_typeof_operation_ (op->children, space, ti, atoms))
+ return GL_FALSE;
+ ti->can_be_referenced = GL_FALSE;
+ ti->is_swizzled = GL_FALSE;
+ break;
+ case slang_oper_minus:
+ if (!typeof_existing_function ("-", op->children, 1, space, &ti->spec, atoms))
+ return GL_FALSE;
+ break;
+ /*case slang_oper_complement:*/
+ case slang_oper_subscript:
+ {
+ slang_assembly_typeinfo _ti;
+
+ if (!slang_assembly_typeinfo_construct (&_ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation_ (op->children, space, &_ti, atoms))
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ ti->can_be_referenced = _ti.can_be_referenced;
+ if (_ti.spec.type == slang_spec_array)
+ {
+ if (!slang_type_specifier_copy (&ti->spec, _ti.spec._array))
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ }
+ else
+ {
+ if (!_slang_type_is_vector (_ti.spec.type) && !_slang_type_is_matrix (_ti.spec.type))
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ ti->spec.type = _slang_type_base (_ti.spec.type);
+ }
+ slang_assembly_typeinfo_destruct (&_ti);
+ }
+ break;
+ case slang_oper_call:
+ {
+ GLboolean exists;
+
+ if (!_slang_typeof_function (op->a_id, op->children, op->num_children, space, &ti->spec,
+ &exists, atoms))
+ return GL_FALSE;
+ if (!exists)
+ {
+ slang_struct *s = slang_struct_scope_find (space->structs, op->a_id, GL_TRUE);
+ if (s != NULL)
+ {
+ ti->spec.type = slang_spec_struct;
+ ti->spec._struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));
+ if (ti->spec._struct == NULL)
+ return GL_FALSE;
+ if (!slang_struct_construct (ti->spec._struct))
+ {
+ slang_alloc_free (ti->spec._struct);
+ ti->spec._struct = NULL;
+ return GL_FALSE;
+ }
+ if (!slang_struct_copy (ti->spec._struct, s))
+ return GL_FALSE;
+ }
+ else
+ {
+ const char *name;
+ slang_type_specifier_type type;
+
+ name = slang_atom_pool_id (atoms, op->a_id);
+ type = slang_type_specifier_type_from_string (name);
+ if (type == slang_spec_void)
+ return GL_FALSE;
+ ti->spec.type = type;
+ }
+ }
+ }
+ break;
+ case slang_oper_field:
+ {
+ slang_assembly_typeinfo _ti;
+
+ if (!slang_assembly_typeinfo_construct (&_ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation_ (op->children, space, &_ti, atoms))
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ if (_ti.spec.type == slang_spec_struct)
+ {
+ slang_variable *field;
+
+ field = _slang_locate_variable (_ti.spec._struct->fields, op->a_id, GL_FALSE);
+ if (field == NULL)
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ if (!slang_type_specifier_copy (&ti->spec, &field->type.specifier))
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ ti->can_be_referenced = _ti.can_be_referenced;
+ }
+ else
+ {
+ GLuint rows;
+ const char *swizzle;
+ slang_type_specifier_type base;
+
+ /* determine the swizzle of the field expression */
+ if (!_slang_type_is_vector (_ti.spec.type))
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ rows = _slang_type_dim (_ti.spec.type);
+ swizzle = slang_atom_pool_id (atoms, op->a_id);
+ if (!_slang_is_swizzle (swizzle, rows, &ti->swz))
+ {
+ slang_assembly_typeinfo_destruct (&_ti);
+ return GL_FALSE;
+ }
+ ti->is_swizzled = GL_TRUE;
+ ti->can_be_referenced = _ti.can_be_referenced && _slang_is_swizzle_mask (&ti->swz,
+ rows);
+ if (_ti.is_swizzled)
+ {
+ slang_swizzle swz;
+
+ /* swizzle the swizzle */
+ _slang_multiply_swizzles (&swz, &_ti.swz, &ti->swz);
+ ti->swz = swz;
+ }
+ base = _slang_type_base (_ti.spec.type);
+ switch (ti->swz.num_components)
+ {
+ case 1:
+ ti->spec.type = base;
+ break;
+ case 2:
+ switch (base)
+ {
+ case slang_spec_float:
+ ti->spec.type = slang_spec_vec2;
+ break;
+ case slang_spec_int:
+ ti->spec.type = slang_spec_ivec2;
+ break;
+ case slang_spec_bool:
+ ti->spec.type = slang_spec_bvec2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (base)
+ {
+ case slang_spec_float:
+ ti->spec.type = slang_spec_vec3;
+ break;
+ case slang_spec_int:
+ ti->spec.type = slang_spec_ivec3;
+ break;
+ case slang_spec_bool:
+ ti->spec.type = slang_spec_bvec3;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ switch (base)
+ {
+ case slang_spec_float:
+ ti->spec.type = slang_spec_vec4;
+ break;
+ case slang_spec_int:
+ ti->spec.type = slang_spec_ivec4;
+ break;
+ case slang_spec_bool:
+ ti->spec.type = slang_spec_bvec4;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ slang_assembly_typeinfo_destruct (&_ti);
+ }
+ break;
+ case slang_oper_postincrement:
+ case slang_oper_postdecrement:
+ if (!_slang_typeof_operation_ (op->children, space, ti, atoms))
+ return GL_FALSE;
+ ti->can_be_referenced = GL_FALSE;
+ ti->is_swizzled = GL_FALSE;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+/* _slang_typeof_function() */
+
+GLboolean _slang_typeof_function (slang_atom a_name, slang_operation *params, GLuint num_params,
+ slang_assembly_name_space *space, slang_type_specifier *spec, GLboolean *exists,
+ slang_atom_pool *atoms)
+{
+ slang_function *fun;
+
+ fun = _slang_locate_function (space->funcs, a_name, params, num_params, space, atoms);
+ *exists = fun != NULL;
+ if (fun == NULL)
+ return GL_TRUE;
+ return slang_type_specifier_copy (spec, &fun->header.type.specifier);
+}
+
+/* _slang_type_is_matrix() */
+
+GLboolean _slang_type_is_matrix (slang_type_specifier_type ty)
+{
+ switch (ty)
+ {
+ case slang_spec_mat2:
+ case slang_spec_mat3:
+ case slang_spec_mat4:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+/* _slang_type_is_vector() */
+
+GLboolean _slang_type_is_vector (slang_type_specifier_type ty)
+{
+ switch (ty)
+ {
+ case slang_spec_vec2:
+ case slang_spec_vec3:
+ case slang_spec_vec4:
+ case slang_spec_ivec2:
+ case slang_spec_ivec3:
+ case slang_spec_ivec4:
+ case slang_spec_bvec2:
+ case slang_spec_bvec3:
+ case slang_spec_bvec4:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+/* _slang_type_base_of_vector() */
+
+slang_type_specifier_type _slang_type_base (slang_type_specifier_type ty)
+{
+ switch (ty)
+ {
+ case slang_spec_float:
+ case slang_spec_vec2:
+ case slang_spec_vec3:
+ case slang_spec_vec4:
+ return slang_spec_float;
+ case slang_spec_int:
+ case slang_spec_ivec2:
+ case slang_spec_ivec3:
+ case slang_spec_ivec4:
+ return slang_spec_int;
+ case slang_spec_bool:
+ case slang_spec_bvec2:
+ case slang_spec_bvec3:
+ case slang_spec_bvec4:
+ return slang_spec_bool;
+ case slang_spec_mat2:
+ return slang_spec_vec2;
+ case slang_spec_mat3:
+ return slang_spec_vec3;
+ case slang_spec_mat4:
+ return slang_spec_vec4;
+ default:
+ return slang_spec_void;
+ }
+}
+
+/* _slang_type_dim */
+
+GLuint _slang_type_dim (slang_type_specifier_type ty)
+{
+ switch (ty)
+ {
+ case slang_spec_float:
+ case slang_spec_int:
+ case slang_spec_bool:
+ return 1;
+ case slang_spec_vec2:
+ case slang_spec_ivec2:
+ case slang_spec_bvec2:
+ case slang_spec_mat2:
+ return 2;
+ case slang_spec_vec3:
+ case slang_spec_ivec3:
+ case slang_spec_bvec3:
+ case slang_spec_mat3:
+ return 3;
+ case slang_spec_vec4:
+ case slang_spec_ivec4:
+ case slang_spec_bvec4:
+ case slang_spec_mat4:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
diff --git a/src/mesa/shader/slang/slang_assemble_typeinfo.h b/src/mesa/shader/slang/slang_assemble_typeinfo.h
new file mode 100644
index 00000000000..7e8af96915b
--- /dev/null
+++ b/src/mesa/shader/slang/slang_assemble_typeinfo.h
@@ -0,0 +1,116 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_ASSEMBLE_TYPEINFO_H
+#define SLANG_ASSEMBLE_TYPEINFO_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef enum slang_type_specifier_type_
+{
+ slang_spec_void,
+ slang_spec_bool,
+ slang_spec_bvec2,
+ slang_spec_bvec3,
+ slang_spec_bvec4,
+ slang_spec_int,
+ slang_spec_ivec2,
+ slang_spec_ivec3,
+ slang_spec_ivec4,
+ slang_spec_float,
+ slang_spec_vec2,
+ slang_spec_vec3,
+ slang_spec_vec4,
+ slang_spec_mat2,
+ slang_spec_mat3,
+ slang_spec_mat4,
+ slang_spec_sampler1D,
+ slang_spec_sampler2D,
+ slang_spec_sampler3D,
+ slang_spec_samplerCube,
+ slang_spec_sampler1DShadow,
+ slang_spec_sampler2DShadow,
+ slang_spec_struct,
+ slang_spec_array
+} slang_type_specifier_type;
+
+typedef struct slang_type_specifier_
+{
+ slang_type_specifier_type type;
+ struct slang_struct_ *_struct; /* type: spec_struct */
+ struct slang_type_specifier_ *_array; /* type: spec_array */
+} slang_type_specifier;
+
+GLvoid slang_type_specifier_ctr (slang_type_specifier *);
+GLvoid slang_type_specifier_dtr (slang_type_specifier *);
+GLboolean slang_type_specifier_copy (slang_type_specifier *, const slang_type_specifier *);
+GLboolean slang_type_specifier_equal (const slang_type_specifier *, const slang_type_specifier *);
+
+typedef struct slang_assembly_typeinfo_
+{
+ GLboolean can_be_referenced;
+ GLboolean is_swizzled;
+ slang_swizzle swz;
+ slang_type_specifier spec;
+ GLuint array_len;
+} slang_assembly_typeinfo;
+
+GLboolean slang_assembly_typeinfo_construct (slang_assembly_typeinfo *);
+GLvoid slang_assembly_typeinfo_destruct (slang_assembly_typeinfo *);
+
+/*
+ * Retrieves type information about an operation.
+ * Returns GL_TRUE on success.
+ * Returns GL_FALSE otherwise.
+ */
+GLboolean _slang_typeof_operation (slang_assemble_ctx *, struct slang_operation_ *,
+ slang_assembly_typeinfo *);
+GLboolean _slang_typeof_operation_ (struct slang_operation_ *, slang_assembly_name_space *,
+ slang_assembly_typeinfo *, slang_atom_pool *);
+
+/*
+ * Retrieves type of a function prototype, if one exists.
+ * Returns GL_TRUE on success, even if the function was not found.
+ * Returns GL_FALSE otherwise.
+ */
+GLboolean _slang_typeof_function (slang_atom a_name, struct slang_operation_ *params,
+ GLuint num_params, slang_assembly_name_space *, slang_type_specifier *spec, GLboolean *exists,
+ slang_atom_pool *);
+
+GLboolean _slang_type_is_matrix (slang_type_specifier_type);
+
+GLboolean _slang_type_is_vector (slang_type_specifier_type);
+
+slang_type_specifier_type _slang_type_base (slang_type_specifier_type);
+
+GLuint _slang_type_dim (slang_type_specifier_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c
new file mode 100644
index 00000000000..46bdf830f92
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile.c
@@ -0,0 +1,2082 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_compile.c
+ * slang front-end compiler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "grammar_mesa.h"
+#include "slang_compile.h"
+#include "slang_preprocess.h"
+#include "slang_storage.h"
+
+/*
+ * This is a straightforward implementation of the slang front-end compiler.
+ * Lots of error-checking functionality is missing but every well-formed shader source should
+ * compile successfully and execute as expected. However, some semantically ill-formed shaders
+ * may be accepted resulting in undefined behaviour.
+ */
+
+/* slang_var_pool */
+
+static GLuint slang_var_pool_alloc (slang_var_pool *pool, unsigned int size)
+{
+ GLuint addr;
+
+ addr = pool->next_addr;
+ pool->next_addr += size;
+ return addr;
+}
+
+/*
+ * slang_code_unit
+ */
+
+GLvoid
+_slang_code_unit_ctr (slang_code_unit *self, struct slang_code_object_ *object)
+{
+ _slang_variable_scope_ctr (&self->vars);
+ _slang_function_scope_ctr (&self->funs);
+ _slang_struct_scope_ctr (&self->structs);
+ self->object = object;
+}
+
+GLvoid
+_slang_code_unit_dtr (slang_code_unit *self)
+{
+ slang_variable_scope_destruct (&self->vars);
+ slang_function_scope_destruct (&self->funs);
+ slang_struct_scope_destruct (&self->structs);
+}
+
+/*
+ * slang_code_object
+ */
+
+GLvoid
+_slang_code_object_ctr (slang_code_object *self)
+{
+ GLuint i;
+
+ for (i = 0; i < SLANG_BUILTIN_TOTAL; i++)
+ _slang_code_unit_ctr (&self->builtin[i], self);
+ _slang_code_unit_ctr (&self->unit, self);
+ _slang_assembly_file_ctr (&self->assembly);
+ slang_machine_ctr (&self->machine);
+ self->varpool.next_addr = 0;
+ slang_atom_pool_construct (&self->atompool);
+ slang_export_data_table_ctr (&self->expdata);
+ self->expdata.atoms = &self->atompool;
+ slang_export_code_table_ctr (&self->expcode);
+ self->expcode.atoms = &self->atompool;
+}
+
+GLvoid
+_slang_code_object_dtr (slang_code_object *self)
+{
+ GLuint i;
+
+ for (i = 0; i < SLANG_BUILTIN_TOTAL; i++)
+ _slang_code_unit_dtr (&self->builtin[i]);
+ _slang_code_unit_dtr (&self->unit);
+ slang_assembly_file_destruct (&self->assembly);
+ slang_machine_dtr (&self->machine);
+ slang_atom_pool_destruct (&self->atompool);
+ slang_export_data_table_dtr (&self->expdata);
+ slang_export_code_table_ctr (&self->expcode);
+}
+
+/* slang_info_log */
+
+static char *out_of_memory = "Error: Out of memory.\n";
+
+void slang_info_log_construct (slang_info_log *log)
+{
+ log->text = NULL;
+ log->dont_free_text = 0;
+}
+
+void slang_info_log_destruct (slang_info_log *log)
+{
+ if (!log->dont_free_text)
+ slang_alloc_free (log->text);
+}
+
+static int slang_info_log_message (slang_info_log *log, const char *prefix, const char *msg)
+{
+ GLuint size;
+
+ if (log->dont_free_text)
+ return 0;
+ size = slang_string_length (msg) + 2;
+ if (prefix != NULL)
+ size += slang_string_length (prefix) + 2;
+ if (log->text != NULL) {
+ GLuint old_len = slang_string_length (log->text);
+ log->text = (char *) (slang_alloc_realloc (log->text, old_len + 1, old_len + size));
+ }
+ else {
+ log->text = (char *) (slang_alloc_malloc (size));
+ if (log->text != NULL)
+ log->text[0] = '\0';
+ }
+ if (log->text == NULL)
+ return 0;
+ if (prefix != NULL) {
+ slang_string_concat (log->text, prefix);
+ slang_string_concat (log->text, ": ");
+ }
+ slang_string_concat (log->text, msg);
+ slang_string_concat (log->text, "\n");
+ return 1;
+}
+
+int slang_info_log_print (slang_info_log *log, const char *msg, ...)
+{
+ va_list va;
+ char buf[1024];
+
+ va_start (va, msg);
+ _mesa_vsprintf (buf, msg, va);
+ va_end (va);
+ return slang_info_log_message (log, NULL, buf);
+}
+
+int slang_info_log_error (slang_info_log *log, const char *msg, ...)
+{
+ va_list va;
+ char buf[1024];
+
+ va_start (va, msg);
+ _mesa_vsprintf (buf, msg, va);
+ va_end (va);
+ if (slang_info_log_message (log, "Error", buf))
+ return 1;
+ slang_info_log_memory (log);
+ return 0;
+}
+
+int slang_info_log_warning (slang_info_log *log, const char *msg, ...)
+{
+ va_list va;
+ char buf[1024];
+
+ va_start (va, msg);
+ _mesa_vsprintf (buf, msg, va);
+ va_end (va);
+ if (slang_info_log_message (log, "Warning", buf))
+ return 1;
+ slang_info_log_memory (log);
+ return 0;
+}
+
+void slang_info_log_memory (slang_info_log *log)
+{
+ if (!slang_info_log_message (log, "Error", "Out of memory."))
+ {
+ log->dont_free_text = 1;
+ log->text = out_of_memory;
+ }
+}
+
+/* slang_parse_ctx */
+
+typedef struct slang_parse_ctx_
+{
+ const byte *I;
+ slang_info_log *L;
+ int parsing_builtin;
+ int global_scope;
+ slang_atom_pool *atoms;
+} slang_parse_ctx;
+
+/* slang_output_ctx */
+
+typedef struct slang_output_ctx_
+{
+ slang_variable_scope *vars;
+ slang_function_scope *funs;
+ slang_struct_scope *structs;
+ slang_assembly_file *assembly;
+ slang_var_pool *global_pool;
+ slang_machine *machine;
+} slang_output_ctx;
+
+/* _slang_compile() */
+
+static void parse_identifier_str (slang_parse_ctx *C, char **id)
+{
+ *id = (char *) C->I;
+ C->I += _mesa_strlen (*id) + 1;
+}
+
+static slang_atom parse_identifier (slang_parse_ctx *C)
+{
+ const char *id;
+
+ id = (const char *) C->I;
+ C->I += _mesa_strlen (id) + 1;
+ return slang_atom_pool_atom (C->atoms, id);
+}
+
+static int parse_number (slang_parse_ctx *C, int *number)
+{
+ const int radix = (int) (*C->I++);
+ *number = 0;
+ while (*C->I != '\0')
+ {
+ int digit;
+ if (*C->I >= '0' && *C->I <= '9')
+ digit = (int) (*C->I - '0');
+ else if (*C->I >= 'A' && *C->I <= 'Z')
+ digit = (int) (*C->I - 'A') + 10;
+ else
+ digit = (int) (*C->I - 'a') + 10;
+ *number = *number * radix + digit;
+ C->I++;
+ }
+ C->I++;
+ if (*number > 65535)
+ slang_info_log_warning (C->L, "%d: literal integer overflow.", *number);
+ return 1;
+}
+
+static int parse_float (slang_parse_ctx *C, float *number)
+{
+ char *integral = NULL;
+ char *fractional = NULL;
+ char *exponent = NULL;
+ char *whole = NULL;
+
+ parse_identifier_str (C, &integral);
+ parse_identifier_str (C, &fractional);
+ parse_identifier_str (C, &exponent);
+
+ whole = (char *) (slang_alloc_malloc ((_mesa_strlen (integral) + _mesa_strlen (fractional) +
+ _mesa_strlen (exponent) + 3) * sizeof (char)));
+ if (whole == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+
+ slang_string_copy (whole, integral);
+ slang_string_concat (whole, ".");
+ slang_string_concat (whole, fractional);
+ slang_string_concat (whole, "E");
+ slang_string_concat (whole, exponent);
+
+ *number = (float) (_mesa_strtod(whole, (char **)NULL));
+
+ slang_alloc_free (whole);
+ return 1;
+}
+
+/* revision number - increment after each change affecting emitted output */
+#define REVISION 3
+
+static int check_revision (slang_parse_ctx *C)
+{
+ if (*C->I != REVISION)
+ {
+ slang_info_log_error (C->L, "Internal compiler error.");
+ return 0;
+ }
+ C->I++;
+ return 1;
+}
+
+static int parse_statement (slang_parse_ctx *, slang_output_ctx *, slang_operation *);
+static int parse_expression (slang_parse_ctx *, slang_output_ctx *, slang_operation *);
+static int parse_type_specifier (slang_parse_ctx *, slang_output_ctx *, slang_type_specifier *);
+
+static GLboolean parse_array_len (slang_parse_ctx *C, slang_output_ctx *O, GLuint *len)
+{
+ slang_operation array_size;
+ slang_assembly_name_space space;
+ GLboolean result;
+
+ if (!slang_operation_construct (&array_size))
+ return GL_FALSE;
+ if (!parse_expression (C, O, &array_size))
+ {
+ slang_operation_destruct (&array_size);
+ return GL_FALSE;
+ }
+
+ space.funcs = O->funs;
+ space.structs = O->structs;
+ space.vars = O->vars;
+ result = _slang_evaluate_int (O->assembly, O->machine, &space, &array_size, len, C->atoms);
+ slang_operation_destruct (&array_size);
+ return result;
+}
+
+static GLboolean calculate_var_size (slang_parse_ctx *C, slang_output_ctx *O, slang_variable *var)
+{
+ slang_storage_aggregate agg;
+
+ if (!slang_storage_aggregate_construct (&agg))
+ return GL_FALSE;
+ if (!_slang_aggregate_variable (&agg, &var->type.specifier, var->array_len, O->funs, O->structs,
+ O->vars, O->machine, O->assembly, C->atoms))
+ {
+ slang_storage_aggregate_destruct (&agg);
+ return GL_FALSE;
+ }
+ var->size = _slang_sizeof_aggregate (&agg);
+ slang_storage_aggregate_destruct (&agg);
+ return GL_TRUE;
+}
+
+static GLboolean convert_to_array (slang_parse_ctx *C, slang_variable *var,
+ const slang_type_specifier *sp)
+{
+ /* sized array - mark it as array, copy the specifier to the array element and
+ * parse the expression */
+ var->type.specifier.type = slang_spec_array;
+ var->type.specifier._array = (slang_type_specifier *) slang_alloc_malloc (sizeof (
+ slang_type_specifier));
+ if (var->type.specifier._array == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return GL_FALSE;
+ }
+ slang_type_specifier_ctr (var->type.specifier._array);
+ return slang_type_specifier_copy (var->type.specifier._array, sp);
+}
+
+/* structure field */
+#define FIELD_NONE 0
+#define FIELD_NEXT 1
+#define FIELD_ARRAY 2
+
+static GLboolean parse_struct_field_var (slang_parse_ctx *C, slang_output_ctx *O, slang_variable *var,
+ const slang_type_specifier *sp)
+{
+ var->a_name = parse_identifier (C);
+ if (var->a_name == SLANG_ATOM_NULL)
+ return GL_FALSE;
+
+ switch (*C->I++)
+ {
+ case FIELD_NONE:
+ if (!slang_type_specifier_copy (&var->type.specifier, sp))
+ return GL_FALSE;
+ break;
+ case FIELD_ARRAY:
+ if (!convert_to_array (C, var, sp))
+ return GL_FALSE;
+ if (!parse_array_len (C, O, &var->array_len))
+ return GL_FALSE;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ return calculate_var_size (C, O, var);
+}
+
+static int parse_struct_field (slang_parse_ctx *C, slang_output_ctx *O, slang_struct *st,
+ slang_type_specifier *sp)
+{
+ slang_output_ctx o = *O;
+
+ o.structs = st->structs;
+ if (!parse_type_specifier (C, &o, sp))
+ return 0;
+ do
+ {
+ slang_variable *var;
+
+ st->fields->variables = (slang_variable *) slang_alloc_realloc (st->fields->variables,
+ st->fields->num_variables * sizeof (slang_variable),
+ (st->fields->num_variables + 1) * sizeof (slang_variable));
+ if (st->fields->variables == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ var = &st->fields->variables[st->fields->num_variables];
+ if (!slang_variable_construct (var))
+ return 0;
+ st->fields->num_variables++;
+ if (!parse_struct_field_var (C, &o, var, sp))
+ return 0;
+ }
+ while (*C->I++ != FIELD_NONE);
+
+ return 1;
+}
+
+static int parse_struct (slang_parse_ctx *C, slang_output_ctx *O, slang_struct **st)
+{
+ slang_atom a_name;
+ const char *name;
+
+ /* parse struct name (if any) and make sure it is unique in current scope */
+ a_name = parse_identifier (C);
+ if (a_name == SLANG_ATOM_NULL)
+ return 0;
+ name = slang_atom_pool_id (C->atoms, a_name);
+ if (name[0] != '\0' && slang_struct_scope_find (O->structs, a_name, 0) != NULL)
+ {
+ slang_info_log_error (C->L, "%s: duplicate type name.", name);
+ return 0;
+ }
+
+ /* set-up a new struct */
+ *st = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));
+ if (*st == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ if (!slang_struct_construct (*st))
+ {
+ slang_alloc_free (*st);
+ *st = NULL;
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ (**st).a_name = a_name;
+ (**st).structs->outer_scope = O->structs;
+
+ /* parse individual struct fields */
+ do
+ {
+ slang_type_specifier sp;
+
+ slang_type_specifier_ctr (&sp);
+ if (!parse_struct_field (C, O, *st, &sp))
+ {
+ slang_type_specifier_dtr (&sp);
+ return 0;
+ }
+ slang_type_specifier_dtr (&sp);
+ }
+ while (*C->I++ != FIELD_NONE);
+
+ /* if named struct, copy it to current scope */
+ if (name[0] != '\0')
+ {
+ slang_struct *s;
+
+ O->structs->structs = (slang_struct *) slang_alloc_realloc (O->structs->structs,
+ O->structs->num_structs * sizeof (slang_struct),
+ (O->structs->num_structs + 1) * sizeof (slang_struct));
+ if (O->structs->structs == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ s = &O->structs->structs[O->structs->num_structs];
+ if (!slang_struct_construct (s))
+ return 0;
+ O->structs->num_structs++;
+ if (!slang_struct_copy (s, *st))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* type qualifier */
+#define TYPE_QUALIFIER_NONE 0
+#define TYPE_QUALIFIER_CONST 1
+#define TYPE_QUALIFIER_ATTRIBUTE 2
+#define TYPE_QUALIFIER_VARYING 3
+#define TYPE_QUALIFIER_UNIFORM 4
+#define TYPE_QUALIFIER_FIXEDOUTPUT 5
+#define TYPE_QUALIFIER_FIXEDINPUT 6
+
+static int parse_type_qualifier (slang_parse_ctx *C, slang_type_qualifier *qual)
+{
+ switch (*C->I++)
+ {
+ case TYPE_QUALIFIER_NONE:
+ *qual = slang_qual_none;
+ break;
+ case TYPE_QUALIFIER_CONST:
+ *qual = slang_qual_const;
+ break;
+ case TYPE_QUALIFIER_ATTRIBUTE:
+ *qual = slang_qual_attribute;
+ break;
+ case TYPE_QUALIFIER_VARYING:
+ *qual = slang_qual_varying;
+ break;
+ case TYPE_QUALIFIER_UNIFORM:
+ *qual = slang_qual_uniform;
+ break;
+ case TYPE_QUALIFIER_FIXEDOUTPUT:
+ *qual = slang_qual_fixedoutput;
+ break;
+ case TYPE_QUALIFIER_FIXEDINPUT:
+ *qual = slang_qual_fixedinput;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/* type specifier */
+#define TYPE_SPECIFIER_VOID 0
+#define TYPE_SPECIFIER_BOOL 1
+#define TYPE_SPECIFIER_BVEC2 2
+#define TYPE_SPECIFIER_BVEC3 3
+#define TYPE_SPECIFIER_BVEC4 4
+#define TYPE_SPECIFIER_INT 5
+#define TYPE_SPECIFIER_IVEC2 6
+#define TYPE_SPECIFIER_IVEC3 7
+#define TYPE_SPECIFIER_IVEC4 8
+#define TYPE_SPECIFIER_FLOAT 9
+#define TYPE_SPECIFIER_VEC2 10
+#define TYPE_SPECIFIER_VEC3 11
+#define TYPE_SPECIFIER_VEC4 12
+#define TYPE_SPECIFIER_MAT2 13
+#define TYPE_SPECIFIER_MAT3 14
+#define TYPE_SPECIFIER_MAT4 15
+#define TYPE_SPECIFIER_SAMPLER1D 16
+#define TYPE_SPECIFIER_SAMPLER2D 17
+#define TYPE_SPECIFIER_SAMPLER3D 18
+#define TYPE_SPECIFIER_SAMPLERCUBE 19
+#define TYPE_SPECIFIER_SAMPLER1DSHADOW 20
+#define TYPE_SPECIFIER_SAMPLER2DSHADOW 21
+#define TYPE_SPECIFIER_STRUCT 22
+#define TYPE_SPECIFIER_TYPENAME 23
+
+static int parse_type_specifier (slang_parse_ctx *C, slang_output_ctx *O, slang_type_specifier *spec)
+{
+ switch (*C->I++)
+ {
+ case TYPE_SPECIFIER_VOID:
+ spec->type = slang_spec_void;
+ break;
+ case TYPE_SPECIFIER_BOOL:
+ spec->type = slang_spec_bool;
+ break;
+ case TYPE_SPECIFIER_BVEC2:
+ spec->type = slang_spec_bvec2;
+ break;
+ case TYPE_SPECIFIER_BVEC3:
+ spec->type = slang_spec_bvec3;
+ break;
+ case TYPE_SPECIFIER_BVEC4:
+ spec->type = slang_spec_bvec4;
+ break;
+ case TYPE_SPECIFIER_INT:
+ spec->type = slang_spec_int;
+ break;
+ case TYPE_SPECIFIER_IVEC2:
+ spec->type = slang_spec_ivec2;
+ break;
+ case TYPE_SPECIFIER_IVEC3:
+ spec->type = slang_spec_ivec3;
+ break;
+ case TYPE_SPECIFIER_IVEC4:
+ spec->type = slang_spec_ivec4;
+ break;
+ case TYPE_SPECIFIER_FLOAT:
+ spec->type = slang_spec_float;
+ break;
+ case TYPE_SPECIFIER_VEC2:
+ spec->type = slang_spec_vec2;
+ break;
+ case TYPE_SPECIFIER_VEC3:
+ spec->type = slang_spec_vec3;
+ break;
+ case TYPE_SPECIFIER_VEC4:
+ spec->type = slang_spec_vec4;
+ break;
+ case TYPE_SPECIFIER_MAT2:
+ spec->type = slang_spec_mat2;
+ break;
+ case TYPE_SPECIFIER_MAT3:
+ spec->type = slang_spec_mat3;
+ break;
+ case TYPE_SPECIFIER_MAT4:
+ spec->type = slang_spec_mat4;
+ break;
+ case TYPE_SPECIFIER_SAMPLER1D:
+ spec->type = slang_spec_sampler1D;
+ break;
+ case TYPE_SPECIFIER_SAMPLER2D:
+ spec->type = slang_spec_sampler2D;
+ break;
+ case TYPE_SPECIFIER_SAMPLER3D:
+ spec->type = slang_spec_sampler3D;
+ break;
+ case TYPE_SPECIFIER_SAMPLERCUBE:
+ spec->type = slang_spec_samplerCube;
+ break;
+ case TYPE_SPECIFIER_SAMPLER1DSHADOW:
+ spec->type = slang_spec_sampler1DShadow;
+ break;
+ case TYPE_SPECIFIER_SAMPLER2DSHADOW:
+ spec->type = slang_spec_sampler2DShadow;
+ break;
+ case TYPE_SPECIFIER_STRUCT:
+ spec->type = slang_spec_struct;
+ if (!parse_struct (C, O, &spec->_struct))
+ return 0;
+ break;
+ case TYPE_SPECIFIER_TYPENAME:
+ spec->type = slang_spec_struct;
+ {
+ slang_atom a_name;
+ slang_struct *stru;
+
+ a_name = parse_identifier (C);
+ if (a_name == NULL)
+ return 0;
+
+ stru = slang_struct_scope_find (O->structs, a_name, 1);
+ if (stru == NULL)
+ {
+ slang_info_log_error (C->L, "%s: undeclared type name.",
+ slang_atom_pool_id (C->atoms, a_name));
+ return 0;
+ }
+
+ spec->_struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));
+ if (spec->_struct == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ if (!slang_struct_construct (spec->_struct))
+ {
+ slang_alloc_free (spec->_struct);
+ spec->_struct = NULL;
+ return 0;
+ }
+ if (!slang_struct_copy (spec->_struct, stru))
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int parse_fully_specified_type (slang_parse_ctx *C, slang_output_ctx *O,
+ slang_fully_specified_type *type)
+{
+ if (!parse_type_qualifier (C, &type->qualifier))
+ return 0;
+ return parse_type_specifier (C, O, &type->specifier);
+}
+
+/* operation */
+#define OP_END 0
+#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1
+#define OP_BLOCK_BEGIN_NEW_SCOPE 2
+#define OP_DECLARE 3
+#define OP_ASM 4
+#define OP_BREAK 5
+#define OP_CONTINUE 6
+#define OP_DISCARD 7
+#define OP_RETURN 8
+#define OP_EXPRESSION 9
+#define OP_IF 10
+#define OP_WHILE 11
+#define OP_DO 12
+#define OP_FOR 13
+#define OP_PUSH_VOID 14
+#define OP_PUSH_BOOL 15
+#define OP_PUSH_INT 16
+#define OP_PUSH_FLOAT 17
+#define OP_PUSH_IDENTIFIER 18
+#define OP_SEQUENCE 19
+#define OP_ASSIGN 20
+#define OP_ADDASSIGN 21
+#define OP_SUBASSIGN 22
+#define OP_MULASSIGN 23
+#define OP_DIVASSIGN 24
+/*#define OP_MODASSIGN 25*/
+/*#define OP_LSHASSIGN 26*/
+/*#define OP_RSHASSIGN 27*/
+/*#define OP_ORASSIGN 28*/
+/*#define OP_XORASSIGN 29*/
+/*#define OP_ANDASSIGN 30*/
+#define OP_SELECT 31
+#define OP_LOGICALOR 32
+#define OP_LOGICALXOR 33
+#define OP_LOGICALAND 34
+/*#define OP_BITOR 35*/
+/*#define OP_BITXOR 36*/
+/*#define OP_BITAND 37*/
+#define OP_EQUAL 38
+#define OP_NOTEQUAL 39
+#define OP_LESS 40
+#define OP_GREATER 41
+#define OP_LESSEQUAL 42
+#define OP_GREATEREQUAL 43
+/*#define OP_LSHIFT 44*/
+/*#define OP_RSHIFT 45*/
+#define OP_ADD 46
+#define OP_SUBTRACT 47
+#define OP_MULTIPLY 48
+#define OP_DIVIDE 49
+/*#define OP_MODULUS 50*/
+#define OP_PREINCREMENT 51
+#define OP_PREDECREMENT 52
+#define OP_PLUS 53
+#define OP_MINUS 54
+/*#define OP_COMPLEMENT 55*/
+#define OP_NOT 56
+#define OP_SUBSCRIPT 57
+#define OP_CALL 58
+#define OP_FIELD 59
+#define OP_POSTINCREMENT 60
+#define OP_POSTDECREMENT 61
+
+static int parse_child_operation (slang_parse_ctx *C, slang_output_ctx *O, slang_operation *oper,
+ int statement)
+{
+ slang_operation *ch;
+
+ oper->children = (slang_operation *) slang_alloc_realloc (oper->children,
+ oper->num_children * sizeof (slang_operation),
+ (oper->num_children + 1) * sizeof (slang_operation));
+ if (oper->children == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ ch = &oper->children[oper->num_children];
+ if (!slang_operation_construct (ch))
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ oper->num_children++;
+ if (statement)
+ return parse_statement (C, O, ch);
+ return parse_expression (C, O, ch);
+}
+
+static int parse_declaration (slang_parse_ctx *C, slang_output_ctx *O);
+
+static int parse_statement (slang_parse_ctx *C, slang_output_ctx *O, slang_operation *oper)
+{
+ oper->locals->outer_scope = O->vars;
+ switch (*C->I++)
+ {
+ case OP_BLOCK_BEGIN_NO_NEW_SCOPE:
+ /* parse child statements, do not create new variable scope */
+ oper->type = slang_oper_block_no_new_scope;
+ while (*C->I != OP_END)
+ if (!parse_child_operation (C, O, oper, 1))
+ return 0;
+ C->I++;
+ break;
+ case OP_BLOCK_BEGIN_NEW_SCOPE:
+ /* parse child statements, create new variable scope */
+ {
+ slang_output_ctx o = *O;
+
+ oper->type = slang_oper_block_new_scope;
+ o.vars = oper->locals;
+ while (*C->I != OP_END)
+ if (!parse_child_operation (C, &o, oper, 1))
+ return 0;
+ C->I++;
+ }
+ break;
+ case OP_DECLARE:
+ /* local variable declaration, individual declarators are stored as children identifiers */
+ oper->type = slang_oper_variable_decl;
+ {
+ const unsigned int first_var = O->vars->num_variables;
+
+ /* parse the declaration, note that there can be zero or more than one declarators */
+ if (!parse_declaration (C, O))
+ return 0;
+ if (first_var < O->vars->num_variables)
+ {
+ const unsigned int num_vars = O->vars->num_variables - first_var;
+ unsigned int i;
+
+ oper->children = (slang_operation *) slang_alloc_malloc (num_vars * sizeof (
+ slang_operation));
+ if (oper->children == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ for (oper->num_children = 0; oper->num_children < num_vars; oper->num_children++)
+ if (!slang_operation_construct (&oper->children[oper->num_children]))
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ for (i = first_var; i < O->vars->num_variables; i++)
+ {
+ slang_operation *o = &oper->children[i - first_var];
+
+ o->type = slang_oper_identifier;
+ o->locals->outer_scope = O->vars;
+ o->a_id = O->vars->variables[i].a_name;
+ }
+ }
+ }
+ break;
+ case OP_ASM:
+ /* the __asm statement, parse the mnemonic and all its arguments as expressions */
+ oper->type = slang_oper_asm;
+ oper->a_id = parse_identifier (C);
+ if (oper->a_id == SLANG_ATOM_NULL)
+ return 0;
+ while (*C->I != OP_END)
+ if (!parse_child_operation (C, O, oper, 0))
+ return 0;
+ C->I++;
+ break;
+ case OP_BREAK:
+ oper->type = slang_oper_break;
+ break;
+ case OP_CONTINUE:
+ oper->type = slang_oper_continue;
+ break;
+ case OP_DISCARD:
+ oper->type = slang_oper_discard;
+ break;
+ case OP_RETURN:
+ oper->type = slang_oper_return;
+ if (!parse_child_operation (C, O, oper, 0))
+ return 0;
+ break;
+ case OP_EXPRESSION:
+ oper->type = slang_oper_expression;
+ if (!parse_child_operation (C, O, oper, 0))
+ return 0;
+ break;
+ case OP_IF:
+ oper->type = slang_oper_if;
+ if (!parse_child_operation (C, O, oper, 0))
+ return 0;
+ if (!parse_child_operation (C, O, oper, 1))
+ return 0;
+ if (!parse_child_operation (C, O, oper, 1))
+ return 0;
+ break;
+ case OP_WHILE:
+ {
+ slang_output_ctx o = *O;
+
+ oper->type = slang_oper_while;
+ o.vars = oper->locals;
+ if (!parse_child_operation (C, &o, oper, 1))
+ return 0;
+ if (!parse_child_operation (C, &o, oper, 1))
+ return 0;
+ }
+ break;
+ case OP_DO:
+ oper->type = slang_oper_do;
+ if (!parse_child_operation (C, O, oper, 1))
+ return 0;
+ if (!parse_child_operation (C, O, oper, 0))
+ return 0;
+ break;
+ case OP_FOR:
+ {
+ slang_output_ctx o = *O;
+
+ oper->type = slang_oper_for;
+ o.vars = oper->locals;
+ if (!parse_child_operation (C, &o, oper, 1))
+ return 0;
+ if (!parse_child_operation (C, &o, oper, 1))
+ return 0;
+ if (!parse_child_operation (C, &o, oper, 0))
+ return 0;
+ if (!parse_child_operation (C, &o, oper, 1))
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int handle_nary_expression (slang_parse_ctx *C, slang_operation *op, slang_operation **ops,
+ unsigned int *total_ops, unsigned int n)
+{
+ unsigned int i;
+
+ op->children = (slang_operation *) slang_alloc_malloc (n * sizeof (slang_operation));
+ if (op->children == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ op->num_children = n;
+
+ for (i = 0; i < n; i++)
+ op->children[i] = (*ops)[*total_ops - (n + 1 - i)];
+ (*ops)[*total_ops - (n + 1)] = (*ops)[*total_ops - 1];
+ *total_ops -= n;
+
+ *ops = (slang_operation *) slang_alloc_realloc (*ops, (*total_ops + n) * sizeof (slang_operation),
+ *total_ops * sizeof (slang_operation));
+ if (*ops == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ return 1;
+}
+
+static int is_constructor_name (const char *name, slang_atom a_name, slang_struct_scope *structs)
+{
+ if (slang_type_specifier_type_from_string (name) != slang_spec_void)
+ return 1;
+ return slang_struct_scope_find (structs, a_name, 1) != NULL;
+}
+
+static int parse_expression (slang_parse_ctx *C, slang_output_ctx *O, slang_operation *oper)
+{
+ slang_operation *ops = NULL;
+ unsigned int num_ops = 0;
+ int number;
+
+ while (*C->I != OP_END)
+ {
+ slang_operation *op;
+ const unsigned int op_code = *C->I++;
+
+ /* allocate default operation, becomes a no-op if not used */
+ ops = (slang_operation *) slang_alloc_realloc (ops,
+ num_ops * sizeof (slang_operation), (num_ops + 1) * sizeof (slang_operation));
+ if (ops == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ op = &ops[num_ops];
+ if (!slang_operation_construct (op))
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ num_ops++;
+ op->locals->outer_scope = O->vars;
+
+ switch (op_code)
+ {
+ case OP_PUSH_VOID:
+ op->type = slang_oper_void;
+ break;
+ case OP_PUSH_BOOL:
+ op->type = slang_oper_literal_bool;
+ if (!parse_number (C, &number))
+ return 0;
+ op->literal = (GLfloat) number;
+ break;
+ case OP_PUSH_INT:
+ op->type = slang_oper_literal_int;
+ if (!parse_number (C, &number))
+ return 0;
+ op->literal = (GLfloat) number;
+ break;
+ case OP_PUSH_FLOAT:
+ op->type = slang_oper_literal_float;
+ if (!parse_float (C, &op->literal))
+ return 0;
+ break;
+ case OP_PUSH_IDENTIFIER:
+ op->type = slang_oper_identifier;
+ op->a_id = parse_identifier (C);
+ if (op->a_id == SLANG_ATOM_NULL)
+ return 0;
+ break;
+ case OP_SEQUENCE:
+ op->type = slang_oper_sequence;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_ASSIGN:
+ op->type = slang_oper_assign;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_ADDASSIGN:
+ op->type = slang_oper_addassign;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_SUBASSIGN:
+ op->type = slang_oper_subassign;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_MULASSIGN:
+ op->type = slang_oper_mulassign;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_DIVASSIGN:
+ op->type = slang_oper_divassign;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ /*case OP_MODASSIGN:*/
+ /*case OP_LSHASSIGN:*/
+ /*case OP_RSHASSIGN:*/
+ /*case OP_ORASSIGN:*/
+ /*case OP_XORASSIGN:*/
+ /*case OP_ANDASSIGN:*/
+ case OP_SELECT:
+ op->type = slang_oper_select;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 3))
+ return 0;
+ break;
+ case OP_LOGICALOR:
+ op->type = slang_oper_logicalor;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_LOGICALXOR:
+ op->type = slang_oper_logicalxor;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_LOGICALAND:
+ op->type = slang_oper_logicaland;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ /*case OP_BITOR:*/
+ /*case OP_BITXOR:*/
+ /*case OP_BITAND:*/
+ case OP_EQUAL:
+ op->type = slang_oper_equal;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_NOTEQUAL:
+ op->type = slang_oper_notequal;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_LESS:
+ op->type = slang_oper_less;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_GREATER:
+ op->type = slang_oper_greater;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_LESSEQUAL:
+ op->type = slang_oper_lessequal;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_GREATEREQUAL:
+ op->type = slang_oper_greaterequal;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ /*case OP_LSHIFT:*/
+ /*case OP_RSHIFT:*/
+ case OP_ADD:
+ op->type = slang_oper_add;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_SUBTRACT:
+ op->type = slang_oper_subtract;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_MULTIPLY:
+ op->type = slang_oper_multiply;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_DIVIDE:
+ op->type = slang_oper_divide;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ /*case OP_MODULUS:*/
+ case OP_PREINCREMENT:
+ op->type = slang_oper_preincrement;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ case OP_PREDECREMENT:
+ op->type = slang_oper_predecrement;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ case OP_PLUS:
+ op->type = slang_oper_plus;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ case OP_MINUS:
+ op->type = slang_oper_minus;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ case OP_NOT:
+ op->type = slang_oper_not;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ /*case OP_COMPLEMENT:*/
+ case OP_SUBSCRIPT:
+ op->type = slang_oper_subscript;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 2))
+ return 0;
+ break;
+ case OP_CALL:
+ op->type = slang_oper_call;
+ op->a_id = parse_identifier (C);
+ if (op->a_id == SLANG_ATOM_NULL)
+ return 0;
+ while (*C->I != OP_END)
+ if (!parse_child_operation (C, O, op, 0))
+ return 0;
+ C->I++;
+ if (!C->parsing_builtin && !slang_function_scope_find_by_name (O->funs, op->a_id, 1))
+ {
+ const char *id;
+
+ id = slang_atom_pool_id (C->atoms, op->a_id);
+ if (!is_constructor_name (id, op->a_id, O->structs))
+ {
+ slang_info_log_error (C->L, "%s: undeclared function name.", id);
+ return 0;
+ }
+ }
+ break;
+ case OP_FIELD:
+ op->type = slang_oper_field;
+ op->a_id = parse_identifier (C);
+ if (op->a_id == SLANG_ATOM_NULL)
+ return 0;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ case OP_POSTINCREMENT:
+ op->type = slang_oper_postincrement;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ case OP_POSTDECREMENT:
+ op->type = slang_oper_postdecrement;
+ if (!handle_nary_expression (C, op, &ops, &num_ops, 1))
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ }
+ C->I++;
+
+ *oper = *ops;
+ slang_alloc_free (ops);
+ return 1;
+}
+
+/* parameter qualifier */
+#define PARAM_QUALIFIER_IN 0
+#define PARAM_QUALIFIER_OUT 1
+#define PARAM_QUALIFIER_INOUT 2
+
+/* function parameter array presence */
+#define PARAMETER_ARRAY_NOT_PRESENT 0
+#define PARAMETER_ARRAY_PRESENT 1
+
+static int parse_parameter_declaration (slang_parse_ctx *C, slang_output_ctx *O,
+ slang_variable *param)
+{
+ /* parse and validate the parameter's type qualifiers (there can be two at most) because
+ * not all combinations are valid */
+ if (!parse_type_qualifier (C, &param->type.qualifier))
+ return 0;
+ switch (*C->I++)
+ {
+ case PARAM_QUALIFIER_IN:
+ if (param->type.qualifier != slang_qual_const && param->type.qualifier != slang_qual_none)
+ {
+ slang_info_log_error (C->L, "Invalid type qualifier.");
+ return 0;
+ }
+ break;
+ case PARAM_QUALIFIER_OUT:
+ if (param->type.qualifier == slang_qual_none)
+ param->type.qualifier = slang_qual_out;
+ else
+ {
+ slang_info_log_error (C->L, "Invalid type qualifier.");
+ return 0;
+ }
+ break;
+ case PARAM_QUALIFIER_INOUT:
+ if (param->type.qualifier == slang_qual_none)
+ param->type.qualifier = slang_qual_inout;
+ else
+ {
+ slang_info_log_error (C->L, "Invalid type qualifier.");
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ /* parse parameter's type specifier and name */
+ if (!parse_type_specifier (C, O, &param->type.specifier))
+ return 0;
+ param->a_name = parse_identifier (C);
+ if (param->a_name == SLANG_ATOM_NULL)
+ return 0;
+
+ /* if the parameter is an array, parse its size (the size must be explicitly defined */
+ if (*C->I++ == PARAMETER_ARRAY_PRESENT)
+ {
+ slang_type_specifier p;
+
+ slang_type_specifier_ctr (&p);
+ if (!slang_type_specifier_copy (&p, &param->type.specifier))
+ {
+ slang_type_specifier_dtr (&p);
+ return GL_FALSE;
+ }
+ if (!convert_to_array (C, param, &p))
+ {
+ slang_type_specifier_dtr (&p);
+ return GL_FALSE;
+ }
+ slang_type_specifier_dtr (&p);
+ if (!parse_array_len (C, O, &param->array_len))
+ return GL_FALSE;
+ }
+
+ /* calculate the parameter size */
+ if (!calculate_var_size (C, O, param))
+ return GL_FALSE;
+
+ /* TODO: allocate the local address here? */
+ return 1;
+}
+
+/* function type */
+#define FUNCTION_ORDINARY 0
+#define FUNCTION_CONSTRUCTOR 1
+#define FUNCTION_OPERATOR 2
+
+/* function parameter */
+#define PARAMETER_NONE 0
+#define PARAMETER_NEXT 1
+
+/* operator type */
+#define OPERATOR_ADDASSIGN 1
+#define OPERATOR_SUBASSIGN 2
+#define OPERATOR_MULASSIGN 3
+#define OPERATOR_DIVASSIGN 4
+/*#define OPERATOR_MODASSIGN 5*/
+/*#define OPERATOR_LSHASSIGN 6*/
+/*#define OPERATOR_RSHASSIGN 7*/
+/*#define OPERATOR_ANDASSIGN 8*/
+/*#define OPERATOR_XORASSIGN 9*/
+/*#define OPERATOR_ORASSIGN 10*/
+#define OPERATOR_LOGICALXOR 11
+/*#define OPERATOR_BITOR 12*/
+/*#define OPERATOR_BITXOR 13*/
+/*#define OPERATOR_BITAND 14*/
+#define OPERATOR_LESS 15
+#define OPERATOR_GREATER 16
+#define OPERATOR_LESSEQUAL 17
+#define OPERATOR_GREATEREQUAL 18
+/*#define OPERATOR_LSHIFT 19*/
+/*#define OPERATOR_RSHIFT 20*/
+#define OPERATOR_MULTIPLY 21
+#define OPERATOR_DIVIDE 22
+/*#define OPERATOR_MODULUS 23*/
+#define OPERATOR_INCREMENT 24
+#define OPERATOR_DECREMENT 25
+#define OPERATOR_PLUS 26
+#define OPERATOR_MINUS 27
+/*#define OPERATOR_COMPLEMENT 28*/
+#define OPERATOR_NOT 29
+
+static const struct {
+ unsigned int o_code;
+ const char *o_name;
+} operator_names[] = {
+ { OPERATOR_INCREMENT, "++" },
+ { OPERATOR_ADDASSIGN, "+=" },
+ { OPERATOR_PLUS, "+" },
+ { OPERATOR_DECREMENT, "--" },
+ { OPERATOR_SUBASSIGN, "-=" },
+ { OPERATOR_MINUS, "-" },
+ { OPERATOR_NOT, "!" },
+ { OPERATOR_MULASSIGN, "*=" },
+ { OPERATOR_MULTIPLY, "*" },
+ { OPERATOR_DIVASSIGN, "/=" },
+ { OPERATOR_DIVIDE, "/" },
+ { OPERATOR_LESSEQUAL, "<=" },
+ /*{ OPERATOR_LSHASSIGN, "<<=" },*/
+ /*{ OPERATOR_LSHIFT, "<<" },*/
+ { OPERATOR_LESS, "<" },
+ { OPERATOR_GREATEREQUAL, ">=" },
+ /*{ OPERATOR_RSHASSIGN, ">>=" },*/
+ /*{ OPERATOR_RSHIFT, ">>" },*/
+ { OPERATOR_GREATER, ">" },
+ /*{ OPERATOR_MODASSIGN, "%=" },*/
+ /*{ OPERATOR_MODULUS, "%" },*/
+ /*{ OPERATOR_ANDASSIGN, "&=" },*/
+ /*{ OPERATOR_BITAND, "&" },*/
+ /*{ OPERATOR_ORASSIGN, "|=" },*/
+ /*{ OPERATOR_BITOR, "|" },*/
+ /*{ OPERATOR_COMPLEMENT, "~" },*/
+ /*{ OPERATOR_XORASSIGN, "^=" },*/
+ { OPERATOR_LOGICALXOR, "^^" },
+ /*{ OPERATOR_BITXOR, "^" }*/
+};
+
+static slang_atom parse_operator_name (slang_parse_ctx *C)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (operator_names) / sizeof (*operator_names); i++)
+ {
+ if (operator_names[i].o_code == (unsigned int) (*C->I))
+ {
+ slang_atom atom = slang_atom_pool_atom (C->atoms, operator_names[i].o_name);
+ if (atom == SLANG_ATOM_NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ C->I++;
+ return atom;
+ }
+ }
+ return 0;
+}
+
+static int parse_function_prototype (slang_parse_ctx *C, slang_output_ctx *O, slang_function *func)
+{
+ /* parse function type and name */
+ if (!parse_fully_specified_type (C, O, &func->header.type))
+ return 0;
+ switch (*C->I++)
+ {
+ case FUNCTION_ORDINARY:
+ func->kind = slang_func_ordinary;
+ func->header.a_name = parse_identifier (C);
+ if (func->header.a_name == SLANG_ATOM_NULL)
+ return 0;
+ break;
+ case FUNCTION_CONSTRUCTOR:
+ func->kind = slang_func_constructor;
+ if (func->header.type.specifier.type == slang_spec_struct)
+ return 0;
+ func->header.a_name = slang_atom_pool_atom (C->atoms,
+ slang_type_specifier_type_to_string (func->header.type.specifier.type));
+ if (func->header.a_name == SLANG_ATOM_NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ break;
+ case FUNCTION_OPERATOR:
+ func->kind = slang_func_operator;
+ func->header.a_name = parse_operator_name (C);
+ if (func->header.a_name == SLANG_ATOM_NULL)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ /* parse function parameters */
+ while (*C->I++ == PARAMETER_NEXT)
+ {
+ slang_variable *p;
+
+ func->parameters->variables = (slang_variable *) slang_alloc_realloc (
+ func->parameters->variables,
+ func->parameters->num_variables * sizeof (slang_variable),
+ (func->parameters->num_variables + 1) * sizeof (slang_variable));
+ if (func->parameters->variables == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ p = &func->parameters->variables[func->parameters->num_variables];
+ if (!slang_variable_construct (p))
+ return 0;
+ func->parameters->num_variables++;
+ if (!parse_parameter_declaration (C, O, p))
+ return 0;
+ }
+
+ /* function formal parameters and local variables share the same scope, so save
+ * the information about param count in a seperate place
+ * also link the scope to the global variable scope so when a given identifier is not
+ * found here, the search process continues in the global space */
+ func->param_count = func->parameters->num_variables;
+ func->parameters->outer_scope = O->vars;
+ return 1;
+}
+
+static int parse_function_definition (slang_parse_ctx *C, slang_output_ctx *O, slang_function *func)
+{
+ slang_output_ctx o = *O;
+
+ if (!parse_function_prototype (C, O, func))
+ return 0;
+
+ /* create function's body operation */
+ func->body = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
+ if (func->body == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ if (!slang_operation_construct (func->body))
+ {
+ slang_alloc_free (func->body);
+ func->body = NULL;
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+
+ /* to parse the body the parse context is modified in order to capture parsed variables
+ * into function's local variable scope */
+ C->global_scope = 0;
+ o.vars = func->parameters;
+ if (!parse_statement (C, &o, func->body))
+ return 0;
+ C->global_scope = 1;
+ return 1;
+}
+
+static GLboolean initialize_global (slang_assemble_ctx *A, slang_variable *var)
+{
+ slang_assembly_file_restore_point point;
+ slang_machine mach;
+ slang_assembly_local_info save_local = A->local;
+ slang_operation op_id, op_assign;
+ GLboolean result;
+
+ /* save the current assembly */
+ if (!slang_assembly_file_restore_point_save (A->file, &point))
+ return GL_FALSE;
+
+ /* setup the machine */
+ mach = *A->mach;
+ mach.ip = A->file->count;
+
+ /* allocate local storage for expression */
+ A->local.ret_size = 0;
+ A->local.addr_tmp = 0;
+ A->local.swizzle_tmp = 4;
+ if (!slang_assembly_file_push_label (A->file, slang_asm_local_alloc, 20))
+ return GL_FALSE;
+ if (!slang_assembly_file_push_label (A->file, slang_asm_enter, 20))
+ return GL_FALSE;
+
+ /* construct the left side of assignment */
+ if (!slang_operation_construct (&op_id))
+ return GL_FALSE;
+ op_id.type = slang_oper_identifier;
+ op_id.a_id = var->a_name;
+
+ /* put the variable into operation's scope */
+ op_id.locals->variables = (slang_variable *) slang_alloc_malloc (sizeof (slang_variable));
+ if (op_id.locals->variables == NULL)
+ {
+ slang_operation_destruct (&op_id);
+ return GL_FALSE;
+ }
+ op_id.locals->num_variables = 1;
+ op_id.locals->variables[0] = *var;
+
+ /* construct the assignment expression */
+ if (!slang_operation_construct (&op_assign))
+ {
+ op_id.locals->num_variables = 0;
+ slang_operation_destruct (&op_id);
+ return GL_FALSE;
+ }
+ op_assign.type = slang_oper_assign;
+ op_assign.children = (slang_operation *) slang_alloc_malloc (2 * sizeof (slang_operation));
+ if (op_assign.children == NULL)
+ {
+ slang_operation_destruct (&op_assign);
+ op_id.locals->num_variables = 0;
+ slang_operation_destruct (&op_id);
+ return GL_FALSE;
+ }
+ op_assign.num_children = 2;
+ op_assign.children[0] = op_id;
+ op_assign.children[1] = *var->initializer;
+
+ /* insert the actual expression */
+ result = _slang_assemble_operation (A, &op_assign, slang_ref_forbid);
+
+ /* carefully destroy the operations */
+ op_assign.num_children = 0;
+ slang_alloc_free (op_assign.children);
+ op_assign.children = NULL;
+ slang_operation_destruct (&op_assign);
+ op_id.locals->num_variables = 0;
+ slang_operation_destruct (&op_id);
+
+ if (!result)
+ return GL_FALSE;
+ if (!slang_assembly_file_push (A->file, slang_asm_exit))
+ return GL_FALSE;
+
+ /* execute the expression */
+ if (!_slang_execute2 (A->file, &mach))
+ return GL_FALSE;
+
+ /* restore the old assembly */
+ if (!slang_assembly_file_restore_point_load (A->file, &point))
+ return GL_FALSE;
+ A->local = save_local;
+
+ /* now we copy the contents of the initialized variable back to the original machine */
+ _mesa_memcpy ((GLubyte *) A->mach->mem + var->address, (GLubyte *) mach.mem + var->address,
+ var->size);
+
+ return GL_TRUE;
+}
+
+/* init declarator list */
+#define DECLARATOR_NONE 0
+#define DECLARATOR_NEXT 1
+
+/* variable declaration */
+#define VARIABLE_NONE 0
+#define VARIABLE_IDENTIFIER 1
+#define VARIABLE_INITIALIZER 2
+#define VARIABLE_ARRAY_EXPLICIT 3
+#define VARIABLE_ARRAY_UNKNOWN 4
+
+static int parse_init_declarator (slang_parse_ctx *C, slang_output_ctx *O,
+ const slang_fully_specified_type *type)
+{
+ slang_variable *var;
+
+ /* empty init declatator (without name, e.g. "float ;") */
+ if (*C->I++ == VARIABLE_NONE)
+ return 1;
+
+ /* make room for the new variable and initialize it */
+ O->vars->variables = (slang_variable *) slang_alloc_realloc (O->vars->variables,
+ O->vars->num_variables * sizeof (slang_variable),
+ (O->vars->num_variables + 1) * sizeof (slang_variable));
+ if (O->vars->variables == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ var = &O->vars->variables[O->vars->num_variables];
+ if (!slang_variable_construct (var))
+ return 0;
+ O->vars->num_variables++;
+
+ /* copy the declarator qualifier type, parse the identifier */
+ var->global = C->global_scope;
+ var->type.qualifier = type->qualifier;
+ var->a_name = parse_identifier (C);
+ if (var->a_name == SLANG_ATOM_NULL)
+ return 0;
+
+ switch (*C->I++)
+ {
+ case VARIABLE_NONE:
+ /* simple variable declarator - just copy the specifier */
+ if (!slang_type_specifier_copy (&var->type.specifier, &type->specifier))
+ return 0;
+ break;
+ case VARIABLE_INITIALIZER:
+ /* initialized variable - copy the specifier and parse the expression */
+ if (!slang_type_specifier_copy (&var->type.specifier, &type->specifier))
+ return 0;
+ var->initializer = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
+ if (var->initializer == NULL)
+ {
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ if (!slang_operation_construct (var->initializer))
+ {
+ slang_alloc_free (var->initializer);
+ var->initializer = NULL;
+ slang_info_log_memory (C->L);
+ return 0;
+ }
+ if (!parse_expression (C, O, var->initializer))
+ return 0;
+ break;
+#if 0
+ case VARIABLE_ARRAY_UNKNOWN:
+ /* unsized array - mark it as array and copy the specifier to the array element */
+ if (!convert_to_array (C, var, &type->specifier))
+ return GL_FALSE;
+ break;
+#endif
+ case VARIABLE_ARRAY_EXPLICIT:
+ if (!convert_to_array (C, var, &type->specifier))
+ return GL_FALSE;
+ if (!parse_array_len (C, O, &var->array_len))
+ return GL_FALSE;
+ break;
+ default:
+ return 0;
+ }
+
+ /* allocate global address space for a variable with a known size */
+ if (C->global_scope && !(var->type.specifier.type == slang_spec_array && var->array_len == 0))
+ {
+ if (!calculate_var_size (C, O, var))
+ return GL_FALSE;
+ var->address = slang_var_pool_alloc (O->global_pool, var->size);
+ }
+
+ /* initialize global variable */
+ if (C->global_scope) {
+ if (var->initializer != NULL) {
+ slang_assemble_ctx A;
+
+ A.file = O->assembly;
+ A.mach = O->machine;
+ A.atoms = C->atoms;
+ A.space.funcs = O->funs;
+ A.space.structs = O->structs;
+ A.space.vars = O->vars;
+ if (!initialize_global (&A, var))
+ return 0;
+ }
+ else {
+ _mesa_memset ((GLubyte *) (O->machine->mem) + var->address, 0, var->size);
+ }
+ }
+ return 1;
+}
+
+static int parse_init_declarator_list (slang_parse_ctx *C, slang_output_ctx *O)
+{
+ slang_fully_specified_type type;
+
+ /* parse the fully specified type, common to all declarators */
+ if (!slang_fully_specified_type_construct (&type))
+ return 0;
+ if (!parse_fully_specified_type (C, O, &type))
+ {
+ slang_fully_specified_type_destruct (&type);
+ return 0;
+ }
+
+ /* parse declarators, pass-in the parsed type */
+ do
+ {
+ if (!parse_init_declarator (C, O, &type))
+ {
+ slang_fully_specified_type_destruct (&type);
+ return 0;
+ }
+ }
+ while (*C->I++ == DECLARATOR_NEXT);
+
+ slang_fully_specified_type_destruct (&type);
+ return 1;
+}
+
+static int parse_function (slang_parse_ctx *C, slang_output_ctx *O, int definition,
+ slang_function **parsed_func_ret)
+{
+ slang_function parsed_func, *found_func;
+
+ /* parse function definition/declaration */
+ if (!slang_function_construct (&parsed_func))
+ return 0;
+ if (definition)
+ {
+ if (!parse_function_definition (C, O, &parsed_func))
+ {
+ slang_function_destruct (&parsed_func);
+ return 0;
+ }
+ }
+ else
+ {
+ if (!parse_function_prototype (C, O, &parsed_func))
+ {
+ slang_function_destruct (&parsed_func);
+ return 0;
+ }
+ }
+
+ /* find a function with a prototype matching the parsed one - only the current scope
+ * is being searched to allow built-in function overriding */
+ found_func = slang_function_scope_find (O->funs, &parsed_func, 0);
+ if (found_func == NULL)
+ {
+ /* add the parsed function to the function list */
+ O->funs->functions = (slang_function *) slang_alloc_realloc (O->funs->functions,
+ O->funs->num_functions * sizeof (slang_function),
+ (O->funs->num_functions + 1) * sizeof (slang_function));
+ if (O->funs->functions == NULL)
+ {
+ slang_info_log_memory (C->L);
+ slang_function_destruct (&parsed_func);
+ return 0;
+ }
+ O->funs->functions[O->funs->num_functions] = parsed_func;
+ O->funs->num_functions++;
+
+ /* return the newly parsed function */
+ *parsed_func_ret = &O->funs->functions[O->funs->num_functions - 1];
+ }
+ else
+ {
+ /* TODO: check function return type qualifiers and specifiers */
+ if (definition)
+ {
+ if (found_func->body != NULL)
+ {
+ slang_info_log_error (C->L, "%s: function already has a body.",
+ slang_atom_pool_id (C->atoms, parsed_func.header.a_name));
+ slang_function_destruct (&parsed_func);
+ return 0;
+ }
+
+ /* destroy the existing function declaration and replace it with the new one,
+ * remember to save the fixup table */
+ parsed_func.fixups = found_func->fixups;
+ slang_fixup_table_init (&found_func->fixups);
+ slang_function_destruct (found_func);
+ *found_func = parsed_func;
+ }
+ else
+ {
+ /* another declaration of the same function prototype - ignore it */
+ slang_function_destruct (&parsed_func);
+ }
+
+ /* return the found function */
+ *parsed_func_ret = found_func;
+ }
+
+ /* assemble the parsed function */
+ {
+ slang_assemble_ctx A;
+
+ A.file = O->assembly;
+ A.mach = O->machine;
+ A.atoms = C->atoms;
+ A.space.funcs = O->funs;
+ A.space.structs = O->structs;
+ A.space.vars = O->vars;
+ if (!_slang_assemble_function (&A, *parsed_func_ret))
+ return 0;
+ }
+ return 1;
+}
+
+/* declaration */
+#define DECLARATION_FUNCTION_PROTOTYPE 1
+#define DECLARATION_INIT_DECLARATOR_LIST 2
+
+static int parse_declaration (slang_parse_ctx *C, slang_output_ctx *O)
+{
+ switch (*C->I++)
+ {
+ case DECLARATION_INIT_DECLARATOR_LIST:
+ if (!parse_init_declarator_list (C, O))
+ return 0;
+ break;
+ case DECLARATION_FUNCTION_PROTOTYPE:
+ {
+ slang_function *dummy_func;
+
+ if (!parse_function (C, O, 0, &dummy_func))
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/* external declaration */
+#define EXTERNAL_NULL 0
+#define EXTERNAL_FUNCTION_DEFINITION 1
+#define EXTERNAL_DECLARATION 2
+
+static GLboolean
+parse_code_unit (slang_parse_ctx *C, slang_code_unit *unit)
+{
+ slang_output_ctx o;
+
+ /* setup output context */
+ o.funs = &unit->funs;
+ o.structs = &unit->structs;
+ o.vars = &unit->vars;
+ o.assembly = &unit->object->assembly;
+ o.global_pool = &unit->object->varpool;
+ o.machine = &unit->object->machine;
+
+ /* parse individual functions and declarations */
+ while (*C->I != EXTERNAL_NULL)
+ {
+ switch (*C->I++)
+ {
+ case EXTERNAL_FUNCTION_DEFINITION:
+ {
+ slang_function *func;
+
+ if (!parse_function (C, &o, 1, &func))
+ return 0;
+ }
+ break;
+ case EXTERNAL_DECLARATION:
+ if (!parse_declaration (C, &o))
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ }
+ C->I++;
+ return 1;
+}
+
+static GLboolean
+compile_binary (const byte *prod, slang_code_unit *unit, slang_unit_type type,
+ slang_info_log *infolog, slang_code_unit *builtin, slang_code_unit *downlink)
+{
+ slang_parse_ctx C;
+
+ unit->type = type;
+
+ /* setup parse context */
+ C.I = prod;
+ C.L = infolog;
+ C.parsing_builtin = (builtin == NULL);
+ C.global_scope = GL_TRUE;
+ C.atoms = &unit->object->atompool;
+
+ if (!check_revision (&C))
+ return GL_FALSE;
+
+ if (downlink != NULL) {
+ unit->vars.outer_scope = &downlink->vars;
+ unit->funs.outer_scope = &downlink->funs;
+ unit->structs.outer_scope = &downlink->structs;
+ }
+
+ /* parse translation unit */
+ return parse_code_unit (&C, unit);
+}
+
+static GLboolean
+compile_with_grammar (grammar id, const char *source, slang_code_unit *unit, slang_unit_type type,
+ slang_info_log *infolog, slang_code_unit *builtin)
+{
+ byte *prod;
+ GLuint size, start, version;
+
+ /* retrieve version */
+ if (!_slang_preprocess_version (source, &version, &start, infolog))
+ return GL_FALSE;
+
+ if (version > 110) {
+ slang_info_log_error (infolog, "language version specified is not supported.");
+ return GL_FALSE;
+ }
+
+ /* check the syntax and generate its binary representation */
+ if (!grammar_fast_check (id, (const byte *) source + start, &prod, &size, 65536))
+ {
+ char buf[1024];
+ unsigned int pos;
+ grammar_get_last_error ( (unsigned char*) buf, 1024, (int*) &pos);
+ slang_info_log_error (infolog, buf);
+ return GL_FALSE;
+ }
+
+ /* syntax is okay - translate it to internal representation */
+ if (!compile_binary (prod, unit, type, infolog, builtin, &builtin[SLANG_BUILTIN_TOTAL - 1])) {
+ grammar_alloc_free (prod);
+ return GL_FALSE;
+ }
+
+ grammar_alloc_free (prod);
+ return GL_TRUE;
+}
+
+static const char *slang_shader_syn =
+#include "library/slang_shader_syn.h"
+;
+
+static const byte slang_core_gc[] = {
+#include "library/slang_core_gc.h"
+};
+
+static const byte slang_common_builtin_gc[] = {
+#include "library/slang_common_builtin_gc.h"
+};
+
+static const byte slang_fragment_builtin_gc[] = {
+#include "library/slang_fragment_builtin_gc.h"
+};
+
+static const byte slang_vertex_builtin_gc[] = {
+#include "library/slang_vertex_builtin_gc.h"
+};
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+static const byte slang_builtin_vec4_gc[] = {
+#include "library/slang_builtin_vec4_gc.h"
+};
+#endif
+
+static GLboolean
+compile_object (grammar *id, const char *source, slang_code_object *object, slang_unit_type type,
+ slang_info_log *infolog)
+{
+ slang_code_unit *builtins = NULL;
+
+ /* load GLSL grammar */
+ *id = grammar_load_from_text ((const byte *) (slang_shader_syn));
+ if (*id == 0)
+ {
+ byte buf[1024];
+ int pos;
+
+ grammar_get_last_error (buf, 1024, &pos);
+ slang_info_log_error (infolog, (const char *) (buf));
+ return GL_FALSE;
+ }
+
+ /* set shader type - the syntax is slightly different for different shaders */
+ if (type == slang_unit_fragment_shader || type == slang_unit_fragment_builtin)
+ grammar_set_reg8 (*id, (const byte *) "shader_type", 1);
+ else
+ grammar_set_reg8 (*id, (const byte *) "shader_type", 2);
+
+ /* enable language extensions */
+ grammar_set_reg8 (*id, (const byte *) "parsing_builtin", 1);
+
+ /* if parsing user-specified shader, load built-in library */
+ if (type == slang_unit_fragment_shader || type == slang_unit_vertex_shader)
+ {
+ /* compile core functionality first */
+ if (!compile_binary (slang_core_gc, &object->builtin[SLANG_BUILTIN_CORE],
+ slang_unit_fragment_builtin, infolog, NULL, NULL))
+ return GL_FALSE;
+
+ /* compile common functions and variables, link to core */
+ if (!compile_binary (slang_common_builtin_gc, &object->builtin[SLANG_BUILTIN_COMMON],
+ slang_unit_fragment_builtin, infolog, NULL,
+ &object->builtin[SLANG_BUILTIN_CORE]))
+ return GL_FALSE;
+
+ /* compile target-specific functions and variables, link to common */
+ if (type == slang_unit_fragment_shader)
+ {
+ if (!compile_binary (slang_fragment_builtin_gc, &object->builtin[SLANG_BUILTIN_TARGET],
+ slang_unit_fragment_builtin, infolog, NULL,
+ &object->builtin[SLANG_BUILTIN_COMMON]))
+ return GL_FALSE;
+ }
+ else if (type == slang_unit_vertex_shader)
+ {
+ if (!compile_binary (slang_vertex_builtin_gc, &object->builtin[SLANG_BUILTIN_TARGET],
+ slang_unit_vertex_builtin, infolog, NULL,
+ &object->builtin[SLANG_BUILTIN_COMMON]))
+ return GL_FALSE;
+ }
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ /* compile x86 4-component vector overrides, link to target */
+ if (!compile_binary (slang_builtin_vec4_gc, &object->builtin[SLANG_BUILTIN_VEC4],
+ slang_unit_fragment_builtin, infolog, NULL,
+ &object->builtin[SLANG_BUILTIN_TARGET]))
+ return GL_FALSE;
+#endif
+
+ /* disable language extensions */
+ grammar_set_reg8 (*id, (const byte *) "parsing_builtin", 0);
+ builtins = object->builtin;
+ }
+
+ /* compile the actual shader - pass-in built-in library for external shader */
+ return compile_with_grammar (*id, source, &object->unit, type, infolog, builtins);
+}
+
+GLboolean
+_slang_compile (const char *source, slang_code_object *object, slang_unit_type type,
+ slang_info_log *infolog)
+{
+ GLboolean success;
+ grammar id = 0;
+
+ _slang_code_object_dtr (object);
+ _slang_code_object_ctr (object);
+
+ success = compile_object (&id, source, object, type, infolog);
+ if (id != 0)
+ grammar_destroy (id);
+ if (!success)
+ return GL_FALSE;
+
+ if (!_slang_build_export_data_table (&object->expdata, &object->unit.vars))
+ return GL_FALSE;
+ if (!_slang_build_export_code_table (&object->expcode, &object->unit.funs, &object->unit))
+ return GL_FALSE;
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ /* XXX: lookup the @main label */
+ if (!_slang_x86_codegen (&object->machine, &object->assembly, object->expcode.entries[0].address))
+ return GL_FALSE;
+#endif
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_compile.h b/src/mesa/shader/slang/slang_compile.h
new file mode 100644
index 00000000000..02987f4e1bc
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile.h
@@ -0,0 +1,117 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_COMPILE_H
+#define SLANG_COMPILE_H
+
+#include "slang_export.h"
+#include "slang_execute.h"
+#include "slang_compile_variable.h"
+#include "slang_compile_struct.h"
+#include "slang_compile_operation.h"
+#include "slang_compile_function.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef enum slang_unit_type_
+{
+ slang_unit_fragment_shader,
+ slang_unit_vertex_shader,
+ slang_unit_fragment_builtin,
+ slang_unit_vertex_builtin
+} slang_unit_type;
+
+typedef struct slang_var_pool_
+{
+ GLuint next_addr;
+} slang_var_pool;
+
+typedef struct slang_code_unit_
+{
+ slang_variable_scope vars;
+ slang_function_scope funs;
+ slang_struct_scope structs;
+ slang_unit_type type;
+ struct slang_code_object_ *object;
+} slang_code_unit;
+
+extern GLvoid
+_slang_code_unit_ctr (slang_code_unit *, struct slang_code_object_ *);
+
+extern GLvoid
+_slang_code_unit_dtr (slang_code_unit *);
+
+#define SLANG_BUILTIN_CORE 0
+#define SLANG_BUILTIN_COMMON 1
+#define SLANG_BUILTIN_TARGET 2
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+#define SLANG_BUILTIN_VEC4 3
+#define SLANG_BUILTIN_TOTAL 4
+#else
+#define SLANG_BUILTIN_TOTAL 3
+#endif
+
+typedef struct slang_code_object_
+{
+ slang_code_unit builtin[SLANG_BUILTIN_TOTAL];
+ slang_code_unit unit;
+ slang_assembly_file assembly;
+ slang_machine machine;
+ slang_var_pool varpool;
+ slang_atom_pool atompool;
+ slang_export_data_table expdata;
+ slang_export_code_table expcode;
+} slang_code_object;
+
+extern GLvoid
+_slang_code_object_ctr (slang_code_object *);
+
+extern GLvoid
+_slang_code_object_dtr (slang_code_object *);
+
+typedef struct slang_info_log_
+{
+ char *text;
+ int dont_free_text;
+} slang_info_log;
+
+void slang_info_log_construct (slang_info_log *);
+void slang_info_log_destruct (slang_info_log *);
+int slang_info_log_print (slang_info_log *, const char *, ...);
+int slang_info_log_error (slang_info_log *, const char *, ...);
+int slang_info_log_warning (slang_info_log *, const char *, ...);
+void slang_info_log_memory (slang_info_log *);
+
+extern GLboolean
+_slang_compile (const char *, slang_code_object *, slang_unit_type, slang_info_log *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_compile_function.c b/src/mesa/shader/slang/slang_compile_function.c
new file mode 100644
index 00000000000..eb8fd1bd40f
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_function.c
@@ -0,0 +1,188 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_compile_function.c
+ * slang front-end compiler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_compile.h"
+
+/* slang_fixup_table */
+
+void slang_fixup_table_init (slang_fixup_table *fix)
+{
+ fix->table = NULL;
+ fix->count = 0;
+}
+
+void slang_fixup_table_free (slang_fixup_table *fix)
+{
+ slang_alloc_free (fix->table);
+ slang_fixup_table_init (fix);
+}
+
+/* slang_function */
+
+int slang_function_construct (slang_function *func)
+{
+ func->kind = slang_func_ordinary;
+ if (!slang_variable_construct (&func->header))
+ return 0;
+ func->parameters = (slang_variable_scope *) slang_alloc_malloc (sizeof (slang_variable_scope));
+ if (func->parameters == NULL)
+ {
+ slang_variable_destruct (&func->header);
+ return 0;
+ }
+ _slang_variable_scope_ctr (func->parameters);
+ func->param_count = 0;
+ func->body = NULL;
+ func->address = ~0;
+ slang_fixup_table_init (&func->fixups);
+ return 1;
+}
+
+void slang_function_destruct (slang_function *func)
+{
+ slang_variable_destruct (&func->header);
+ slang_variable_scope_destruct (func->parameters);
+ slang_alloc_free (func->parameters);
+ if (func->body != NULL)
+ {
+ slang_operation_destruct (func->body);
+ slang_alloc_free (func->body);
+ }
+ slang_fixup_table_free (&func->fixups);
+}
+
+/*
+ * slang_function_scope
+ */
+
+GLvoid
+_slang_function_scope_ctr (slang_function_scope *self)
+{
+ self->functions = NULL;
+ self->num_functions = 0;
+ self->outer_scope = NULL;
+}
+
+void slang_function_scope_destruct (slang_function_scope *scope)
+{
+ unsigned int i;
+
+ for (i = 0; i < scope->num_functions; i++)
+ slang_function_destruct (scope->functions + i);
+ slang_alloc_free (scope->functions);
+}
+
+int slang_function_scope_find_by_name (slang_function_scope *funcs, slang_atom a_name, int all_scopes)
+{
+ unsigned int i;
+
+ for (i = 0; i < funcs->num_functions; i++)
+ if (a_name == funcs->functions[i].header.a_name)
+ return 1;
+ if (all_scopes && funcs->outer_scope != NULL)
+ return slang_function_scope_find_by_name (funcs->outer_scope, a_name, 1);
+ return 0;
+}
+
+slang_function *slang_function_scope_find (slang_function_scope *funcs, slang_function *fun,
+ int all_scopes)
+{
+ unsigned int i;
+
+ for (i = 0; i < funcs->num_functions; i++)
+ {
+ slang_function *f = &funcs->functions[i];
+ unsigned int j;
+
+ if (fun->header.a_name != f->header.a_name)
+ continue;
+ if (fun->param_count != f->param_count)
+ continue;
+ for (j = 0; j < fun->param_count; j++)
+ {
+ if (!slang_type_specifier_equal (&fun->parameters->variables[j].type.specifier,
+ &f->parameters->variables[j].type.specifier))
+ break;
+ }
+ if (j == fun->param_count)
+ return f;
+ }
+ if (all_scopes && funcs->outer_scope != NULL)
+ return slang_function_scope_find (funcs->outer_scope, fun, 1);
+ return NULL;
+}
+
+/*
+ * _slang_build_export_code_table()
+ */
+
+GLboolean
+_slang_build_export_code_table (slang_export_code_table *tbl, slang_function_scope *funs,
+ slang_code_unit *unit)
+{
+ slang_atom mainAtom;
+ GLuint i;
+
+ mainAtom = slang_atom_pool_atom (tbl->atoms, "main");
+ if (mainAtom == SLANG_ATOM_NULL)
+ return GL_FALSE;
+
+ for (i = 0; i < funs->num_functions; i++)
+ {
+ if (funs->functions[i].header.a_name == mainAtom)
+ {
+ slang_function *fun = &funs->functions[i];
+ slang_export_code_entry *e;
+ slang_assemble_ctx A;
+
+ e = slang_export_code_table_add (tbl);
+ if (e == NULL)
+ return GL_FALSE;
+ e->address = unit->object->assembly.count;
+ e->name = slang_atom_pool_atom (tbl->atoms, "@main");
+ if (e->name == SLANG_ATOM_NULL)
+ return GL_FALSE;
+
+ A.file = &unit->object->assembly;
+ A.mach = &unit->object->machine;
+ A.atoms = &unit->object->atompool;
+ A.space.funcs = &unit->funs;
+ A.space.structs = &unit->structs;
+ A.space.vars = &unit->vars;
+ slang_assembly_file_push_label (&unit->object->assembly, slang_asm_local_alloc, 20);
+ slang_assembly_file_push_label (&unit->object->assembly, slang_asm_enter, 20);
+ _slang_assemble_function_call (&A, fun, NULL, 0, GL_FALSE);
+ slang_assembly_file_push (&unit->object->assembly, slang_asm_exit);
+ }
+ }
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_compile_function.h b/src/mesa/shader/slang/slang_compile_function.h
new file mode 100644
index 00000000000..24bc0d6ffd1
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_function.h
@@ -0,0 +1,87 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_COMPILE_FUNCTION_H
+#define SLANG_COMPILE_FUNCTION_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+struct slang_code_unit_;
+
+typedef enum slang_function_kind_
+{
+ slang_func_ordinary,
+ slang_func_constructor,
+ slang_func_operator
+} slang_function_kind;
+
+typedef struct slang_fixup_table_
+{
+ GLuint *table;
+ GLuint count;
+} slang_fixup_table;
+
+void slang_fixup_table_init (slang_fixup_table *);
+void slang_fixup_table_free (slang_fixup_table *);
+
+typedef struct slang_function_
+{
+ slang_function_kind kind;
+ slang_variable header;
+ slang_variable_scope *parameters;
+ unsigned int param_count;
+ slang_operation *body;
+ unsigned int address;
+ slang_fixup_table fixups;
+} slang_function;
+
+int slang_function_construct (slang_function *);
+void slang_function_destruct (slang_function *);
+
+typedef struct slang_function_scope_
+{
+ slang_function *functions;
+ GLuint num_functions;
+ struct slang_function_scope_ *outer_scope;
+} slang_function_scope;
+
+extern GLvoid
+_slang_function_scope_ctr (slang_function_scope *);
+
+void slang_function_scope_destruct (slang_function_scope *);
+int slang_function_scope_find_by_name (slang_function_scope *, slang_atom, int);
+slang_function *slang_function_scope_find (slang_function_scope *, slang_function *, int);
+
+extern GLboolean
+_slang_build_export_code_table (slang_export_code_table *, slang_function_scope *,
+ struct slang_code_unit_ *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c
new file mode 100644
index 00000000000..7e920135597
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_operation.c
@@ -0,0 +1,98 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_compile_operation.c
+ * slang front-end compiler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_compile.h"
+
+/* slang_operation */
+
+int slang_operation_construct (slang_operation *oper)
+{
+ oper->type = slang_oper_none;
+ oper->children = NULL;
+ oper->num_children = 0;
+ oper->literal = (float) 0;
+ oper->a_id = SLANG_ATOM_NULL;
+ oper->locals = (slang_variable_scope *) slang_alloc_malloc (sizeof (slang_variable_scope));
+ if (oper->locals == NULL)
+ return 0;
+ _slang_variable_scope_ctr (oper->locals);
+ return 1;
+}
+
+void slang_operation_destruct (slang_operation *oper)
+{
+ unsigned int i;
+
+ for (i = 0; i < oper->num_children; i++)
+ slang_operation_destruct (oper->children + i);
+ slang_alloc_free (oper->children);
+ slang_variable_scope_destruct (oper->locals);
+ slang_alloc_free (oper->locals);
+}
+
+int slang_operation_copy (slang_operation *x, const slang_operation *y)
+{
+ slang_operation z;
+ unsigned int i;
+
+ if (!slang_operation_construct (&z))
+ return 0;
+ z.type = y->type;
+ z.children = (slang_operation *) slang_alloc_malloc (y->num_children * sizeof (slang_operation));
+ if (z.children == NULL)
+ {
+ slang_operation_destruct (&z);
+ return 0;
+ }
+ for (z.num_children = 0; z.num_children < y->num_children; z.num_children++)
+ if (!slang_operation_construct (&z.children[z.num_children]))
+ {
+ slang_operation_destruct (&z);
+ return 0;
+ }
+ for (i = 0; i < z.num_children; i++)
+ if (!slang_operation_copy (&z.children[i], &y->children[i]))
+ {
+ slang_operation_destruct (&z);
+ return 0;
+ }
+ z.literal = y->literal;
+ z.a_id = y->a_id;
+ if (!slang_variable_scope_copy (z.locals, y->locals))
+ {
+ slang_operation_destruct (&z);
+ return 0;
+ }
+ slang_operation_destruct (x);
+ *x = z;
+ return 1;
+}
+
diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h
new file mode 100644
index 00000000000..d9bce36b9bd
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_operation.h
@@ -0,0 +1,117 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_COMPILE_OPERATION_H
+#define SLANG_COMPILE_OPERATION_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef enum slang_operation_type_
+{
+ slang_oper_none,
+ slang_oper_block_no_new_scope,
+ slang_oper_block_new_scope,
+ slang_oper_variable_decl,
+ slang_oper_asm,
+ slang_oper_break,
+ slang_oper_continue,
+ slang_oper_discard,
+ slang_oper_return,
+ slang_oper_expression,
+ slang_oper_if,
+ slang_oper_while,
+ slang_oper_do,
+ slang_oper_for,
+ slang_oper_void,
+ slang_oper_literal_bool,
+ slang_oper_literal_int,
+ slang_oper_literal_float,
+ slang_oper_identifier,
+ slang_oper_sequence,
+ slang_oper_assign,
+ slang_oper_addassign,
+ slang_oper_subassign,
+ slang_oper_mulassign,
+ slang_oper_divassign,
+ /*slang_oper_modassign,*/
+ /*slang_oper_lshassign,*/
+ /*slang_oper_rshassign,*/
+ /*slang_oper_orassign,*/
+ /*slang_oper_xorassign,*/
+ /*slang_oper_andassign,*/
+ slang_oper_select,
+ slang_oper_logicalor,
+ slang_oper_logicalxor,
+ slang_oper_logicaland,
+ /*slang_oper_bitor,*/
+ /*slang_oper_bitxor,*/
+ /*slang_oper_bitand,*/
+ slang_oper_equal,
+ slang_oper_notequal,
+ slang_oper_less,
+ slang_oper_greater,
+ slang_oper_lessequal,
+ slang_oper_greaterequal,
+ /*slang_oper_lshift,*/
+ /*slang_oper_rshift,*/
+ slang_oper_add,
+ slang_oper_subtract,
+ slang_oper_multiply,
+ slang_oper_divide,
+ /*slang_oper_modulus,*/
+ slang_oper_preincrement,
+ slang_oper_predecrement,
+ slang_oper_plus,
+ slang_oper_minus,
+ /*slang_oper_complement,*/
+ slang_oper_not,
+ slang_oper_subscript,
+ slang_oper_call,
+ slang_oper_field,
+ slang_oper_postincrement,
+ slang_oper_postdecrement
+} slang_operation_type;
+
+typedef struct slang_operation_
+{
+ slang_operation_type type;
+ struct slang_operation_ *children;
+ unsigned int num_children;
+ float literal; /* type: bool, literal_int, literal_float */
+ slang_atom a_id; /* type: asm, identifier, call, field */
+ slang_variable_scope *locals;
+} slang_operation;
+
+int slang_operation_construct (slang_operation *);
+void slang_operation_destruct (slang_operation *);
+int slang_operation_copy (slang_operation *, const slang_operation *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_compile_struct.c b/src/mesa/shader/slang/slang_compile_struct.c
new file mode 100644
index 00000000000..15585a62afe
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_struct.c
@@ -0,0 +1,169 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_compile_struct.c
+ * slang front-end compiler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_compile.h"
+
+/*
+ * slang_struct_scope
+ */
+
+GLvoid
+_slang_struct_scope_ctr (slang_struct_scope *self)
+{
+ self->structs = NULL;
+ self->num_structs = 0;
+ self->outer_scope = NULL;
+}
+
+void slang_struct_scope_destruct (slang_struct_scope *scope)
+{
+ unsigned int i;
+
+ for (i = 0; i < scope->num_structs; i++)
+ slang_struct_destruct (scope->structs + i);
+ slang_alloc_free (scope->structs);
+ /* do not free scope->outer_scope */
+}
+
+int slang_struct_scope_copy (slang_struct_scope *x, const slang_struct_scope *y)
+{
+ slang_struct_scope z;
+ unsigned int i;
+
+ _slang_struct_scope_ctr (&z);
+ z.structs = (slang_struct *) slang_alloc_malloc (y->num_structs * sizeof (slang_struct));
+ if (z.structs == NULL)
+ {
+ slang_struct_scope_destruct (&z);
+ return 0;
+ }
+ for (z.num_structs = 0; z.num_structs < y->num_structs; z.num_structs++)
+ if (!slang_struct_construct (&z.structs[z.num_structs]))
+ {
+ slang_struct_scope_destruct (&z);
+ return 0;
+ }
+ for (i = 0; i < z.num_structs; i++)
+ if (!slang_struct_copy (&z.structs[i], &y->structs[i]))
+ {
+ slang_struct_scope_destruct (&z);
+ return 0;
+ }
+ z.outer_scope = y->outer_scope;
+ slang_struct_scope_destruct (x);
+ *x = z;
+ return 1;
+}
+
+slang_struct *slang_struct_scope_find (slang_struct_scope *stru, slang_atom a_name, int all_scopes)
+{
+ unsigned int i;
+
+ for (i = 0; i < stru->num_structs; i++)
+ if (a_name == stru->structs[i].a_name)
+ return &stru->structs[i];
+ if (all_scopes && stru->outer_scope != NULL)
+ return slang_struct_scope_find (stru->outer_scope, a_name, 1);
+ return NULL;
+}
+
+/* slang_struct */
+
+int slang_struct_construct (slang_struct *stru)
+{
+ stru->a_name = SLANG_ATOM_NULL;
+ stru->fields = (slang_variable_scope *) slang_alloc_malloc (sizeof (slang_variable_scope));
+ if (stru->fields == NULL)
+ return 0;
+ _slang_variable_scope_ctr (stru->fields);
+ stru->structs = (slang_struct_scope *) slang_alloc_malloc (sizeof (slang_struct_scope));
+ if (stru->structs == NULL)
+ {
+ slang_variable_scope_destruct (stru->fields);
+ slang_alloc_free (stru->fields);
+ return 0;
+ }
+ _slang_struct_scope_ctr (stru->structs);
+ return 1;
+}
+
+void slang_struct_destruct (slang_struct *stru)
+{
+ slang_variable_scope_destruct (stru->fields);
+ slang_alloc_free (stru->fields);
+ slang_struct_scope_destruct (stru->structs);
+ slang_alloc_free (stru->structs);
+}
+
+int slang_struct_copy (slang_struct *x, const slang_struct *y)
+{
+ slang_struct z;
+
+ if (!slang_struct_construct (&z))
+ return 0;
+ z.a_name = y->a_name;
+ if (!slang_variable_scope_copy (z.fields, y->fields))
+ {
+ slang_struct_destruct (&z);
+ return 0;
+ }
+ if (!slang_struct_scope_copy (z.structs, y->structs))
+ {
+ slang_struct_destruct (&z);
+ return 0;
+ }
+ slang_struct_destruct (x);
+ *x = z;
+ return 1;
+}
+
+int slang_struct_equal (const slang_struct *x, const slang_struct *y)
+{
+ unsigned int i;
+
+ if (x->fields->num_variables != y->fields->num_variables)
+ return 0;
+ for (i = 0; i < x->fields->num_variables; i++)
+ {
+ slang_variable *varx = &x->fields->variables[i];
+ slang_variable *vary = &y->fields->variables[i];
+
+ if (varx->a_name != vary->a_name)
+ return 0;
+ if (!slang_type_specifier_equal (&varx->type.specifier, &vary->type.specifier))
+ return 0;
+ if (varx->type.specifier.type == slang_spec_array)
+ if (varx->array_len != vary->array_len)
+ return GL_FALSE;
+ }
+ return 1;
+}
+
diff --git a/src/mesa/shader/slang/slang_compile_struct.h b/src/mesa/shader/slang/slang_compile_struct.h
new file mode 100644
index 00000000000..79e63066168
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_struct.h
@@ -0,0 +1,63 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_COMPILE_STRUCT_H
+#define SLANG_COMPILE_STRUCT_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef struct slang_struct_scope_
+{
+ struct slang_struct_ *structs;
+ GLuint num_structs;
+ struct slang_struct_scope_ *outer_scope;
+} slang_struct_scope;
+
+extern GLvoid
+_slang_struct_scope_ctr (slang_struct_scope *);
+
+void slang_struct_scope_destruct (slang_struct_scope *);
+int slang_struct_scope_copy (slang_struct_scope *, const slang_struct_scope *);
+struct slang_struct_ *slang_struct_scope_find (slang_struct_scope *, slang_atom, int);
+
+typedef struct slang_struct_
+{
+ slang_atom a_name;
+ struct slang_variable_scope_ *fields;
+ slang_struct_scope *structs;
+} slang_struct;
+
+int slang_struct_construct (slang_struct *);
+void slang_struct_destruct (slang_struct *);
+int slang_struct_copy (slang_struct *, const slang_struct *);
+int slang_struct_equal (const slang_struct *, const slang_struct *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_compile_variable.c b/src/mesa/shader/slang/slang_compile_variable.c
new file mode 100644
index 00000000000..b62743addb0
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_variable.c
@@ -0,0 +1,370 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_compile_variable.c
+ * slang front-end compiler
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_compile.h"
+
+/* slang_type_specifier_type */
+
+typedef struct
+{
+ const char *name;
+ slang_type_specifier_type type;
+} type_specifier_type_name;
+
+static type_specifier_type_name type_specifier_type_names[] = {
+ { "void", slang_spec_void },
+ { "bool", slang_spec_bool },
+ { "bvec2", slang_spec_bvec2 },
+ { "bvec3", slang_spec_bvec3 },
+ { "bvec4", slang_spec_bvec4 },
+ { "int", slang_spec_int },
+ { "ivec2", slang_spec_ivec2 },
+ { "ivec3", slang_spec_ivec3 },
+ { "ivec4", slang_spec_ivec4 },
+ { "float", slang_spec_float },
+ { "vec2", slang_spec_vec2 },
+ { "vec3", slang_spec_vec3 },
+ { "vec4", slang_spec_vec4 },
+ { "mat2", slang_spec_mat2 },
+ { "mat3", slang_spec_mat3 },
+ { "mat4", slang_spec_mat4 },
+ { "sampler1D", slang_spec_sampler1D },
+ { "sampler2D", slang_spec_sampler2D },
+ { "sampler3D", slang_spec_sampler3D },
+ { "samplerCube", slang_spec_samplerCube },
+ { "sampler1DShadow", slang_spec_sampler1DShadow },
+ { "sampler2DShadow", slang_spec_sampler2DShadow },
+ { NULL, slang_spec_void }
+};
+
+slang_type_specifier_type slang_type_specifier_type_from_string (const char *name)
+{
+ type_specifier_type_name *p = type_specifier_type_names;
+ while (p->name != NULL)
+ {
+ if (slang_string_compare (p->name, name) == 0)
+ break;
+ p++;
+ }
+ return p->type;
+}
+
+const char *slang_type_specifier_type_to_string (slang_type_specifier_type type)
+{
+ type_specifier_type_name *p = type_specifier_type_names;
+ while (p->name != NULL)
+ {
+ if (p->type == type)
+ break;
+ p++;
+ }
+ return p->name;
+}
+
+/* slang_fully_specified_type */
+
+int slang_fully_specified_type_construct (slang_fully_specified_type *type)
+{
+ type->qualifier = slang_qual_none;
+ slang_type_specifier_ctr (&type->specifier);
+ return 1;
+}
+
+void slang_fully_specified_type_destruct (slang_fully_specified_type *type)
+{
+ slang_type_specifier_dtr (&type->specifier);
+}
+
+int slang_fully_specified_type_copy (slang_fully_specified_type *x, const slang_fully_specified_type *y)
+{
+ slang_fully_specified_type z;
+
+ if (!slang_fully_specified_type_construct (&z))
+ return 0;
+ z.qualifier = y->qualifier;
+ if (!slang_type_specifier_copy (&z.specifier, &y->specifier))
+ {
+ slang_fully_specified_type_destruct (&z);
+ return 0;
+ }
+ slang_fully_specified_type_destruct (x);
+ *x = z;
+ return 1;
+}
+
+/*
+ * slang_variable_scope
+ */
+
+GLvoid
+_slang_variable_scope_ctr (slang_variable_scope *self)
+{
+ self->variables = NULL;
+ self->num_variables = 0;
+ self->outer_scope = NULL;
+}
+
+void slang_variable_scope_destruct (slang_variable_scope *scope)
+{
+ unsigned int i;
+
+ for (i = 0; i < scope->num_variables; i++)
+ slang_variable_destruct (scope->variables + i);
+ slang_alloc_free (scope->variables);
+ /* do not free scope->outer_scope */
+}
+
+int slang_variable_scope_copy (slang_variable_scope *x, const slang_variable_scope *y)
+{
+ slang_variable_scope z;
+ unsigned int i;
+
+ _slang_variable_scope_ctr (&z);
+ z.variables = (slang_variable *) slang_alloc_malloc (y->num_variables * sizeof (slang_variable));
+ if (z.variables == NULL)
+ {
+ slang_variable_scope_destruct (&z);
+ return 0;
+ }
+ for (z.num_variables = 0; z.num_variables < y->num_variables; z.num_variables++)
+ if (!slang_variable_construct (&z.variables[z.num_variables]))
+ {
+ slang_variable_scope_destruct (&z);
+ return 0;
+ }
+ for (i = 0; i < z.num_variables; i++)
+ if (!slang_variable_copy (&z.variables[i], &y->variables[i]))
+ {
+ slang_variable_scope_destruct (&z);
+ return 0;
+ }
+ z.outer_scope = y->outer_scope;
+ slang_variable_scope_destruct (x);
+ *x = z;
+ return 1;
+}
+
+/* slang_variable */
+
+int slang_variable_construct (slang_variable *var)
+{
+ if (!slang_fully_specified_type_construct (&var->type))
+ return 0;
+ var->a_name = SLANG_ATOM_NULL;
+ var->array_len = 0;
+ var->initializer = NULL;
+ var->address = ~0;
+ var->size = 0;
+ var->global = 0;
+ return 1;
+}
+
+void slang_variable_destruct (slang_variable *var)
+{
+ slang_fully_specified_type_destruct (&var->type);
+ if (var->initializer != NULL)
+ {
+ slang_operation_destruct (var->initializer);
+ slang_alloc_free (var->initializer);
+ }
+}
+
+int slang_variable_copy (slang_variable *x, const slang_variable *y)
+{
+ slang_variable z;
+
+ if (!slang_variable_construct (&z))
+ return 0;
+ if (!slang_fully_specified_type_copy (&z.type, &y->type))
+ {
+ slang_variable_destruct (&z);
+ return 0;
+ }
+ z.a_name = y->a_name;
+ z.array_len = y->array_len;
+ if (y->initializer != NULL)
+ {
+ z.initializer = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
+ if (z.initializer == NULL)
+ {
+ slang_variable_destruct (&z);
+ return 0;
+ }
+ if (!slang_operation_construct (z.initializer))
+ {
+ slang_alloc_free (z.initializer);
+ slang_variable_destruct (&z);
+ return 0;
+ }
+ if (!slang_operation_copy (z.initializer, y->initializer))
+ {
+ slang_variable_destruct (&z);
+ return 0;
+ }
+ }
+ z.address = y->address;
+ z.size = y->size;
+ z.global = y->global;
+ slang_variable_destruct (x);
+ *x = z;
+ return 1;
+}
+
+slang_variable *_slang_locate_variable (slang_variable_scope *scope, slang_atom a_name, GLboolean all)
+{
+ GLuint i;
+
+ for (i = 0; i < scope->num_variables; i++)
+ if (a_name == scope->variables[i].a_name)
+ return &scope->variables[i];
+ if (all && scope->outer_scope != NULL)
+ return _slang_locate_variable (scope->outer_scope, a_name, 1);
+ return NULL;
+}
+
+/*
+ * _slang_build_export_data_table()
+ */
+
+static GLenum gl_type_from_specifier (const slang_type_specifier *type)
+{
+ switch (type->type)
+ {
+ case slang_spec_bool:
+ return GL_BOOL_ARB;
+ case slang_spec_bvec2:
+ return GL_BOOL_VEC2_ARB;
+ case slang_spec_bvec3:
+ return GL_BOOL_VEC3_ARB;
+ case slang_spec_bvec4:
+ return GL_BOOL_VEC4_ARB;
+ case slang_spec_int:
+ return GL_INT;
+ case slang_spec_ivec2:
+ return GL_INT_VEC2_ARB;
+ case slang_spec_ivec3:
+ return GL_INT_VEC3_ARB;
+ case slang_spec_ivec4:
+ return GL_INT_VEC4_ARB;
+ case slang_spec_float:
+ return GL_FLOAT;
+ case slang_spec_vec2:
+ return GL_FLOAT_VEC2_ARB;
+ case slang_spec_vec3:
+ return GL_FLOAT_VEC3_ARB;
+ case slang_spec_vec4:
+ return GL_FLOAT_VEC4_ARB;
+ case slang_spec_mat2:
+ return GL_FLOAT_MAT2_ARB;
+ case slang_spec_mat3:
+ return GL_FLOAT_MAT3_ARB;
+ case slang_spec_mat4:
+ return GL_FLOAT_MAT4_ARB;
+ case slang_spec_sampler1D:
+ return GL_SAMPLER_1D_ARB;
+ case slang_spec_sampler2D:
+ return GL_SAMPLER_2D_ARB;
+ case slang_spec_sampler3D:
+ return GL_SAMPLER_3D_ARB;
+ case slang_spec_samplerCube:
+ return GL_SAMPLER_CUBE_ARB;
+ case slang_spec_sampler1DShadow:
+ return GL_SAMPLER_1D_SHADOW_ARB;
+ case slang_spec_sampler2DShadow:
+ return GL_SAMPLER_2D_SHADOW_ARB;
+ case slang_spec_array:
+ return gl_type_from_specifier (type->_array);
+ default:
+ return GL_FLOAT;
+ }
+}
+
+static GLboolean build_quant (slang_export_data_quant *q, slang_variable *var)
+{
+ slang_type_specifier *spec = &var->type.specifier;
+
+ q->name = var->a_name;
+ q->size = var->size;
+ if (spec->type == slang_spec_array)
+ {
+ q->array_len = var->array_len;
+ q->size /= var->array_len;
+ spec = spec->_array;
+ }
+ if (spec->type == slang_spec_struct)
+ {
+ GLuint i;
+
+ q->u.field_count = spec->_struct->fields->num_variables;
+ q->structure = (slang_export_data_quant *) slang_alloc_malloc (
+ q->u.field_count * sizeof (slang_export_data_quant));
+ if (q->structure == NULL)
+ return GL_FALSE;
+
+ for (i = 0; i < q->u.field_count; i++)
+ slang_export_data_quant_ctr (&q->structure[i]);
+ for (i = 0; i < q->u.field_count; i++)
+ if (!build_quant (&q->structure[i], &spec->_struct->fields->variables[i]))
+ return GL_FALSE;
+ }
+ else
+ q->u.basic_type = gl_type_from_specifier (spec);
+ return GL_TRUE;
+}
+
+GLboolean _slang_build_export_data_table (slang_export_data_table *tbl, slang_variable_scope *vars)
+{
+ GLuint i;
+
+ for (i = 0; i < vars->num_variables; i++)
+ {
+ slang_variable *var = &vars->variables[i];
+ slang_export_data_entry *e;
+
+ e = slang_export_data_table_add (tbl);
+ if (e == NULL)
+ return GL_FALSE;
+ if (!build_quant (&e->quant, var))
+ return GL_FALSE;
+ if (var->type.qualifier == slang_qual_uniform)
+ e->access = slang_exp_uniform;
+ else if (var->type.qualifier == slang_qual_attribute)
+ e->access = slang_exp_attribute;
+ else
+ e->access = slang_exp_varying;
+ e->address = var->address;
+ }
+
+ if (vars->outer_scope != NULL)
+ return _slang_build_export_data_table (tbl, vars->outer_scope);
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_compile_variable.h b/src/mesa/shader/slang/slang_compile_variable.h
new file mode 100644
index 00000000000..6b9679a3b75
--- /dev/null
+++ b/src/mesa/shader/slang/slang_compile_variable.h
@@ -0,0 +1,95 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_COMPILE_VARIABLE_H
+#define SLANG_COMPILE_VARIABLE_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef enum slang_type_qualifier_
+{
+ slang_qual_none,
+ slang_qual_const,
+ slang_qual_attribute,
+ slang_qual_varying,
+ slang_qual_uniform,
+ slang_qual_out,
+ slang_qual_inout,
+ slang_qual_fixedoutput, /* internal */
+ slang_qual_fixedinput /* internal */
+} slang_type_qualifier;
+
+slang_type_specifier_type slang_type_specifier_type_from_string (const char *);
+const char *slang_type_specifier_type_to_string (slang_type_specifier_type);
+
+typedef struct slang_fully_specified_type_
+{
+ slang_type_qualifier qualifier;
+ slang_type_specifier specifier;
+} slang_fully_specified_type;
+
+int slang_fully_specified_type_construct (slang_fully_specified_type *);
+void slang_fully_specified_type_destruct (slang_fully_specified_type *);
+int slang_fully_specified_type_copy (slang_fully_specified_type *, const slang_fully_specified_type *);
+
+typedef struct slang_variable_scope_
+{
+ struct slang_variable_ *variables;
+ GLuint num_variables;
+ struct slang_variable_scope_ *outer_scope;
+} slang_variable_scope;
+
+extern GLvoid
+_slang_variable_scope_ctr (slang_variable_scope *);
+
+void slang_variable_scope_destruct (slang_variable_scope *);
+int slang_variable_scope_copy (slang_variable_scope *, const slang_variable_scope *);
+
+typedef struct slang_variable_
+{
+ slang_fully_specified_type type;
+ slang_atom a_name;
+ GLuint array_len; /* type: spec_array */
+ struct slang_operation_ *initializer;
+ unsigned int address;
+ unsigned int size;
+ int global;
+} slang_variable;
+
+int slang_variable_construct (slang_variable *);
+void slang_variable_destruct (slang_variable *);
+int slang_variable_copy (slang_variable *, const slang_variable *);
+
+slang_variable *_slang_locate_variable (slang_variable_scope *, slang_atom a_name, GLboolean all);
+
+GLboolean _slang_build_export_data_table (slang_export_data_table *, slang_variable_scope *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_execute.c b/src/mesa/shader/slang/slang_execute.c
new file mode 100644
index 00000000000..98bfd896c4e
--- /dev/null
+++ b/src/mesa/shader/slang/slang_execute.c
@@ -0,0 +1,729 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_execute.c
+ * intermediate code interpreter
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_compile.h"
+#include "slang_execute.h"
+#include "slang_library_noise.h"
+#include "slang_library_texsample.h"
+
+#define DEBUG_SLANG 0
+
+GLvoid slang_machine_ctr (slang_machine *self)
+{
+ slang_machine_init (self);
+ self->infolog = NULL;
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ self->x86.compiled_func = NULL;
+#endif
+}
+
+GLvoid slang_machine_dtr (slang_machine *self)
+{
+ if (self->infolog != NULL) {
+ slang_info_log_destruct (self->infolog);
+ slang_alloc_free (self->infolog);
+ }
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ if (self->x86.compiled_func != NULL)
+ _mesa_exec_free (self->x86.compiled_func);
+#endif
+}
+
+void slang_machine_init (slang_machine *mach)
+{
+ mach->ip = 0;
+ mach->sp = SLANG_MACHINE_STACK_SIZE;
+ mach->bp = 0;
+ mach->kill = 0;
+ mach->exit = 0;
+}
+
+#if DEBUG_SLANG
+
+static void dump_instruction (FILE *f, slang_assembly *a, unsigned int i)
+{
+ fprintf (f, "%.5u:\t", i);
+
+ switch (a->type)
+ {
+ /* core */
+ case slang_asm_none:
+ fprintf (f, "none");
+ break;
+ case slang_asm_float_copy:
+ fprintf (f, "float_copy\t%d, %d", a->param[0], a->param[1]);
+ break;
+ case slang_asm_float_move:
+ fprintf (f, "float_move\t%d, %d", a->param[0], a->param[1]);
+ break;
+ case slang_asm_float_push:
+ fprintf (f, "float_push\t%f", a->literal);
+ break;
+ case slang_asm_float_deref:
+ fprintf (f, "float_deref");
+ break;
+ case slang_asm_float_add:
+ fprintf (f, "float_add");
+ break;
+ case slang_asm_float_multiply:
+ fprintf (f, "float_multiply");
+ break;
+ case slang_asm_float_divide:
+ fprintf (f, "float_divide");
+ break;
+ case slang_asm_float_negate:
+ fprintf (f, "float_negate");
+ break;
+ case slang_asm_float_less:
+ fprintf (f, "float_less");
+ break;
+ case slang_asm_float_equal_exp:
+ fprintf (f, "float_equal");
+ break;
+ case slang_asm_float_equal_int:
+ fprintf (f, "float_equal\t%d, %d", a->param[0], a->param[1]);
+ break;
+ case slang_asm_float_to_int:
+ fprintf (f, "float_to_int");
+ break;
+ case slang_asm_float_sine:
+ fprintf (f, "float_sine");
+ break;
+ case slang_asm_float_arcsine:
+ fprintf (f, "float_arcsine");
+ break;
+ case slang_asm_float_arctan:
+ fprintf (f, "float_arctan");
+ break;
+ case slang_asm_float_power:
+ fprintf (f, "float_power");
+ break;
+ case slang_asm_float_log2:
+ fprintf (f, "float_log2");
+ break;
+ case slang_asm_float_floor:
+ fprintf (f, "float_floor");
+ break;
+ case slang_asm_float_ceil:
+ fprintf (f, "float_ceil");
+ break;
+ case slang_asm_float_noise1:
+ fprintf (f, "float_noise1");
+ break;
+ case slang_asm_float_noise2:
+ fprintf (f, "float_noise2");
+ break;
+ case slang_asm_float_noise3:
+ fprintf (f, "float_noise3");
+ break;
+ case slang_asm_float_noise4:
+ fprintf (f, "float_noise4");
+ break;
+ case slang_asm_int_copy:
+ fprintf (f, "int_copy\t%d, %d", a->param[0], a->param[1]);
+ break;
+ case slang_asm_int_move:
+ fprintf (f, "int_move\t%d, %d", a->param[0], a->param[1]);
+ break;
+ case slang_asm_int_push:
+ fprintf (f, "int_push\t%d", (GLint) a->literal);
+ break;
+ case slang_asm_int_deref:
+ fprintf (f, "int_deref");
+ break;
+ case slang_asm_int_to_float:
+ fprintf (f, "int_to_float");
+ break;
+ case slang_asm_int_to_addr:
+ fprintf (f, "int_to_addr");
+ break;
+ case slang_asm_bool_copy:
+ fprintf (f, "bool_copy\t%d, %d", a->param[0], a->param[1]);
+ break;
+ case slang_asm_bool_move:
+ fprintf (f, "bool_move\t%d, %d", a->param[0], a->param[1]);
+ break;
+ case slang_asm_bool_push:
+ fprintf (f, "bool_push\t%d", a->literal != 0.0f);
+ break;
+ case slang_asm_bool_deref:
+ fprintf (f, "bool_deref");
+ break;
+ case slang_asm_addr_copy:
+ fprintf (f, "addr_copy");
+ break;
+ case slang_asm_addr_push:
+ fprintf (f, "addr_push\t%u", a->param[0]);
+ break;
+ case slang_asm_addr_deref:
+ fprintf (f, "addr_deref");
+ break;
+ case slang_asm_addr_add:
+ fprintf (f, "addr_add");
+ break;
+ case slang_asm_addr_multiply:
+ fprintf (f, "addr_multiply");
+ break;
+ case slang_asm_vec4_tex1d:
+ fprintf (f, "vec4_tex1d");
+ break;
+ case slang_asm_vec4_tex2d:
+ fprintf (f, "vec4_tex2d");
+ break;
+ case slang_asm_vec4_tex3d:
+ fprintf (f, "vec4_tex3d");
+ break;
+ case slang_asm_vec4_texcube:
+ fprintf (f, "vec4_texcube");
+ break;
+ case slang_asm_vec4_shad1d:
+ fprintf (f, "vec4_shad1d");
+ break;
+ case slang_asm_vec4_shad2d:
+ fprintf (f, "vec4_shad2d");
+ break;
+ case slang_asm_jump:
+ fprintf (f, "jump\t%u", a->param[0]);
+ break;
+ case slang_asm_jump_if_zero:
+ fprintf (f, "jump_if_zero\t%u", a->param[0]);
+ break;
+ case slang_asm_enter:
+ fprintf (f, "enter\t%u", a->param[0]);
+ break;
+ case slang_asm_leave:
+ fprintf (f, "leave");
+ break;
+ case slang_asm_local_alloc:
+ fprintf (f, "local_alloc\t%u", a->param[0]);
+ break;
+ case slang_asm_local_free:
+ fprintf (f, "local_free\t%u", a->param[0]);
+ break;
+ case slang_asm_local_addr:
+ fprintf (f, "local_addr\t%u, %u", a->param[0], a->param[1]);
+ break;
+ case slang_asm_global_addr:
+ fprintf (f, "global_addr\t%u", a->param[0]);
+ break;
+ case slang_asm_call:
+ fprintf (f, "call\t%u", a->param[0]);
+ break;
+ case slang_asm_return:
+ fprintf (f, "return");
+ break;
+ case slang_asm_discard:
+ fprintf (f, "discard");
+ break;
+ case slang_asm_exit:
+ fprintf (f, "exit");
+ break;
+ /* GL_MESA_shader_debug */
+ case slang_asm_float_print:
+ fprintf (f, "float_print");
+ break;
+ case slang_asm_int_print:
+ fprintf (f, "int_print");
+ break;
+ case slang_asm_bool_print:
+ fprintf (f, "bool_print");
+ break;
+ /* vec4 */
+ case slang_asm_float_to_vec4:
+ fprintf (f, "float_to_vec4");
+ break;
+ case slang_asm_vec4_add:
+ fprintf (f, "vec4_add");
+ break;
+ case slang_asm_vec4_subtract:
+ fprintf (f, "vec4_subtract");
+ break;
+ case slang_asm_vec4_multiply:
+ fprintf (f, "vec4_multiply");
+ break;
+ case slang_asm_vec4_divide:
+ fprintf (f, "vec4_divide");
+ break;
+ case slang_asm_vec4_negate:
+ fprintf (f, "vec4_negate");
+ break;
+ case slang_asm_vec4_dot:
+ fprintf (f, "vec4_dot");
+ break;
+ case slang_asm_vec4_copy:
+ fprintf (f, "vec4_copy");
+ break;
+ case slang_asm_vec4_deref:
+ fprintf (f, "vec4_deref");
+ break;
+ case slang_asm_vec4_equal_int:
+ fprintf (f, "vec4_equal");
+ break;
+ default:
+ break;
+ }
+
+ fprintf (f, "\n");
+}
+
+static void dump (const slang_assembly_file *file)
+{
+ unsigned int i;
+ static unsigned int counter = 0;
+ FILE *f;
+ char filename[256];
+
+ counter++;
+ _mesa_sprintf (filename, "~mesa-slang-assembly-dump-(%u).txt", counter);
+ f = fopen (filename, "w");
+ if (f == NULL)
+ return;
+
+ for (i = 0; i < file->count; i++)
+ dump_instruction (f, file->code + i, i);
+
+ fclose (f);
+}
+
+#endif
+
+static GLvoid
+ensure_infolog_created (slang_info_log **infolog)
+{
+ if (*infolog == NULL) {
+ *infolog = slang_alloc_malloc (sizeof (slang_info_log));
+ if (*infolog == NULL)
+ return;
+ slang_info_log_construct (*infolog);
+ }
+}
+
+GLboolean
+_slang_execute2 (const slang_assembly_file *file, slang_machine *mach)
+{
+ slang_machine_slot *stack;
+
+#if DEBUG_SLANG
+ static unsigned int counter = 0;
+ char filename[256];
+ FILE *f;
+#endif
+
+ /* assume 32-bit floats and uints; should work fine also on 64-bit platforms */
+ static_assert(sizeof (GLfloat) == 4);
+ static_assert(sizeof (GLuint) == 4);
+
+#if DEBUG_SLANG
+ dump (file);
+ counter++;
+ _mesa_sprintf (filename, "~mesa-slang-assembly-exec-(%u).txt", counter);
+ f = fopen (filename, "w");
+#endif
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ if (mach->x86.compiled_func != NULL)
+ {
+ mach->x86.compiled_func (mach);
+ return GL_TRUE;
+ }
+#endif
+
+ stack = mach->mem + SLANG_MACHINE_GLOBAL_SIZE;
+
+ while (!mach->exit)
+ {
+ slang_assembly *a = &file->code[mach->ip];
+
+#if DEBUG_SLANG
+ if (f != NULL && a->type != slang_asm_none)
+ {
+ unsigned int i;
+
+ dump_instruction (f, file->code + mach->ip, mach->ip);
+ fprintf (f, "\t\tsp=%u bp=%u\n", mach->sp, mach->bp);
+ for (i = mach->sp; i < SLANG_MACHINE_STACK_SIZE; i++)
+ fprintf (f, "\t%.5u\t%6f\t%u\n", i, stack[i]._float, stack[i]._addr);
+ fflush (f);
+ }
+#endif
+
+ mach->ip++;
+
+ switch (a->type)
+ {
+ /* core */
+ case slang_asm_none:
+ break;
+ case slang_asm_float_copy:
+ case slang_asm_int_copy:
+ case slang_asm_bool_copy:
+ mach->mem[(stack[mach->sp + a->param[0] / 4]._addr + a->param[1]) / 4]._float =
+ stack[mach->sp]._float;
+ mach->sp++;
+ break;
+ case slang_asm_float_move:
+ case slang_asm_int_move:
+ case slang_asm_bool_move:
+ stack[mach->sp + a->param[0] / 4]._float =
+ stack[mach->sp + (stack[mach->sp]._addr + a->param[1]) / 4]._float;
+ break;
+ case slang_asm_float_push:
+ case slang_asm_int_push:
+ case slang_asm_bool_push:
+ mach->sp--;
+ stack[mach->sp]._float = a->literal;
+ break;
+ case slang_asm_float_deref:
+ case slang_asm_int_deref:
+ case slang_asm_bool_deref:
+ stack[mach->sp]._float = mach->mem[stack[mach->sp]._addr / 4]._float;
+ break;
+ case slang_asm_float_add:
+ stack[mach->sp + 1]._float += stack[mach->sp]._float;
+ mach->sp++;
+ break;
+ case slang_asm_float_multiply:
+ stack[mach->sp + 1]._float *= stack[mach->sp]._float;
+ mach->sp++;
+ break;
+ case slang_asm_float_divide:
+ stack[mach->sp + 1]._float /= stack[mach->sp]._float;
+ mach->sp++;
+ break;
+ case slang_asm_float_negate:
+ stack[mach->sp]._float = -stack[mach->sp]._float;
+ break;
+ case slang_asm_float_less:
+ stack[mach->sp + 1]._float =
+ stack[mach->sp + 1]._float < stack[mach->sp]._float ? (GLfloat) 1 : (GLfloat) 0;
+ mach->sp++;
+ break;
+ case slang_asm_float_equal_exp:
+ stack[mach->sp + 1]._float =
+ stack[mach->sp + 1]._float == stack[mach->sp]._float ? (GLfloat) 1 : (GLfloat) 0;
+ mach->sp++;
+ break;
+ case slang_asm_float_equal_int:
+ mach->sp--;
+ stack[mach->sp]._float = stack[mach->sp + 1 + a->param[0] / 4]._float ==
+ stack[mach->sp + 1 + a->param[1] / 4]._float ? (GLfloat) 1 : (GLfloat) 0;
+ break;
+ case slang_asm_float_to_int:
+ stack[mach->sp]._float = (GLfloat) (GLint) stack[mach->sp]._float;
+ break;
+ case slang_asm_float_sine:
+ stack[mach->sp]._float = (GLfloat) _mesa_sin (stack[mach->sp]._float);
+ break;
+ case slang_asm_float_arcsine:
+ stack[mach->sp]._float = _mesa_asinf (stack[mach->sp]._float);
+ break;
+ case slang_asm_float_arctan:
+ stack[mach->sp]._float = _mesa_atanf (stack[mach->sp]._float);
+ break;
+ case slang_asm_float_power:
+ stack[mach->sp + 1]._float =
+ (GLfloat) _mesa_pow (stack[mach->sp + 1]._float, stack[mach->sp]._float);
+ mach->sp++;
+ break;
+ case slang_asm_float_log2:
+ stack[mach->sp]._float = LOG2 (stack[mach->sp]._float);
+ break;
+ case slang_asm_float_floor:
+ stack[mach->sp]._float = FLOORF (stack[mach->sp]._float);
+ break;
+ case slang_asm_float_ceil:
+ stack[mach->sp]._float = CEILF (stack[mach->sp]._float);
+ break;
+ case slang_asm_float_noise1:
+ stack[mach->sp]._float = _slang_library_noise1 (stack[mach->sp]._float);
+ break;
+ case slang_asm_float_noise2:
+ stack[mach->sp + 1]._float = _slang_library_noise2 (stack[mach->sp]._float,
+ stack[mach->sp + 1]._float);
+ mach->sp++;
+ break;
+ case slang_asm_float_noise3:
+ stack[mach->sp + 2]._float = _slang_library_noise3 (stack[mach->sp]._float,
+ stack[mach->sp + 1]._float, stack[mach->sp + 2]._float);
+ mach->sp += 2;
+ break;
+ case slang_asm_float_noise4:
+ stack[mach->sp + 3]._float = _slang_library_noise4 (stack[mach->sp]._float,
+ stack[mach->sp + 1]._float, stack[mach->sp + 2]._float, stack[mach->sp + 3]._float);
+ mach->sp += 3;
+ break;
+ case slang_asm_int_to_float:
+ break;
+ case slang_asm_int_to_addr:
+ stack[mach->sp]._addr = (GLuint) (GLint) stack[mach->sp]._float;
+ break;
+ case slang_asm_addr_copy:
+ mach->mem[stack[mach->sp + 1]._addr / 4]._addr = stack[mach->sp]._addr;
+ mach->sp++;
+ break;
+ case slang_asm_addr_push:
+ case slang_asm_global_addr:
+ mach->sp--;
+ stack[mach->sp]._addr = a->param[0];
+ break;
+ case slang_asm_addr_deref:
+ stack[mach->sp]._addr = mach->mem[stack[mach->sp]._addr / 4]._addr;
+ break;
+ case slang_asm_addr_add:
+ stack[mach->sp + 1]._addr += stack[mach->sp]._addr;
+ mach->sp++;
+ break;
+ case slang_asm_addr_multiply:
+ stack[mach->sp + 1]._addr *= stack[mach->sp]._addr;
+ mach->sp++;
+ break;
+ case slang_asm_vec4_tex1d:
+ _slang_library_tex1d (stack[mach->sp]._float, stack[mach->sp + 1]._float,
+ stack[mach->sp + 2]._float, &mach->mem[stack[mach->sp + 3]._addr / 4]._float);
+ mach->sp += 3;
+ break;
+ case slang_asm_vec4_tex2d:
+ _slang_library_tex2d (stack[mach->sp]._float, stack[mach->sp + 1]._float,
+ stack[mach->sp + 2]._float, stack[mach->sp + 3]._float,
+ &mach->mem[stack[mach->sp + 4]._addr / 4]._float);
+ mach->sp += 4;
+ break;
+ case slang_asm_vec4_tex3d:
+ _slang_library_tex3d (stack[mach->sp]._float, stack[mach->sp + 1]._float,
+ stack[mach->sp + 2]._float, stack[mach->sp + 3]._float, stack[mach->sp + 4]._float,
+ &mach->mem[stack[mach->sp + 5]._addr / 4]._float);
+ mach->sp += 5;
+ break;
+ case slang_asm_vec4_texcube:
+ _slang_library_texcube (stack[mach->sp]._float, stack[mach->sp + 1]._float,
+ stack[mach->sp + 2]._float, stack[mach->sp + 3]._float, stack[mach->sp + 4]._float,
+ &mach->mem[stack[mach->sp + 5]._addr / 4]._float);
+ mach->sp += 5;
+ break;
+ case slang_asm_vec4_shad1d:
+ _slang_library_shad1d (stack[mach->sp]._float, stack[mach->sp + 1]._float,
+ stack[mach->sp + 2]._float, stack[mach->sp + 3]._float, stack[mach->sp + 4]._float,
+ &mach->mem[stack[mach->sp + 5]._addr / 4]._float);
+ mach->sp += 5;
+ break;
+ case slang_asm_vec4_shad2d:
+ _slang_library_shad2d (stack[mach->sp]._float, stack[mach->sp + 1]._float,
+ stack[mach->sp + 2]._float, stack[mach->sp + 3]._float, stack[mach->sp + 4]._float,
+ &mach->mem[stack[mach->sp + 5]._addr / 4]._float);
+ mach->sp += 5;
+ break;
+ case slang_asm_jump:
+ mach->ip = a->param[0];
+ break;
+ case slang_asm_jump_if_zero:
+ if (stack[mach->sp]._float == 0.0f)
+ mach->ip = a->param[0];
+ mach->sp++;
+ break;
+ case slang_asm_enter:
+ mach->sp--;
+ stack[mach->sp]._addr = mach->bp;
+ mach->bp = mach->sp + a->param[0] / 4;
+ break;
+ case slang_asm_leave:
+ mach->bp = stack[mach->sp]._addr;
+ mach->sp++;
+ break;
+ case slang_asm_local_alloc:
+ mach->sp -= a->param[0] / 4;
+ break;
+ case slang_asm_local_free:
+ mach->sp += a->param[0] / 4;
+ break;
+ case slang_asm_local_addr:
+ mach->sp--;
+ stack[mach->sp]._addr = SLANG_MACHINE_GLOBAL_SIZE * 4 + mach->bp * 4 -
+ (a->param[0] + a->param[1]) + 4;
+ break;
+ case slang_asm_call:
+ mach->sp--;
+ stack[mach->sp]._addr = mach->ip;
+ mach->ip = a->param[0];
+ break;
+ case slang_asm_return:
+ mach->ip = stack[mach->sp]._addr;
+ mach->sp++;
+ break;
+ case slang_asm_discard:
+ mach->kill = 1;
+ break;
+ case slang_asm_exit:
+ mach->exit = 1;
+ break;
+ /* GL_MESA_shader_debug */
+ case slang_asm_float_print:
+ _mesa_printf ("slang print: %f\n", stack[mach->sp]._float);
+ ensure_infolog_created (&mach->infolog);
+ slang_info_log_print (mach->infolog, "%f", stack[mach->sp]._float);
+ break;
+ case slang_asm_int_print:
+ _mesa_printf ("slang print: %d\n", (GLint) stack[mach->sp]._float);
+ ensure_infolog_created (&mach->infolog);
+ slang_info_log_print (mach->infolog, "%d", (GLint) (stack[mach->sp]._float));
+ break;
+ case slang_asm_bool_print:
+ _mesa_printf ("slang print: %s\n", (GLint) stack[mach->sp]._float ? "true" : "false");
+ ensure_infolog_created (&mach->infolog);
+ slang_info_log_print (mach->infolog, "%s",
+ (GLint) (stack[mach->sp]._float) ? "true" : "false");
+ break;
+ /* vec4 */
+ case slang_asm_float_to_vec4:
+ /* [vec4] | float > [vec4] */
+ {
+ GLuint da = stack[mach->sp + 1]._addr;
+ mach->mem[da / 4]._float = stack[mach->sp]._float;
+ mach->sp++;
+ }
+ break;
+ case slang_asm_vec4_add:
+ /* [vec4] | vec4 > [vec4] */
+ {
+ GLuint da = stack[mach->sp + 4]._addr;
+ mach->mem[da / 4]._float += stack[mach->sp]._float;
+ mach->mem[(da + 4) / 4]._float += stack[mach->sp + 1]._float;
+ mach->mem[(da + 8) / 4]._float += stack[mach->sp + 2]._float;
+ mach->mem[(da + 12) / 4]._float += stack[mach->sp + 3]._float;
+ mach->sp += 4;
+ }
+ break;
+ case slang_asm_vec4_subtract:
+ /* [vec4] | vec4 > [vec4] */
+ {
+ GLuint da = stack[mach->sp + 4]._addr;
+ mach->mem[da / 4]._float -= stack[mach->sp]._float;
+ mach->mem[(da + 4) / 4]._float -= stack[mach->sp + 1]._float;
+ mach->mem[(da + 8) / 4]._float -= stack[mach->sp + 2]._float;
+ mach->mem[(da + 12) / 4]._float -= stack[mach->sp + 3]._float;
+ mach->sp += 4;
+ }
+ break;
+ case slang_asm_vec4_multiply:
+ /* [vec4] | vec4 > [vec4] */
+ {
+ GLuint da = stack[mach->sp + 4]._addr;
+ mach->mem[da / 4]._float *= stack[mach->sp]._float;
+ mach->mem[(da + 4) / 4]._float *= stack[mach->sp + 1]._float;
+ mach->mem[(da + 8) / 4]._float *= stack[mach->sp + 2]._float;
+ mach->mem[(da + 12) / 4]._float *= stack[mach->sp + 3]._float;
+ mach->sp += 4;
+ }
+ break;
+ case slang_asm_vec4_divide:
+ /* [vec4] | vec4 > [vec4] */
+ {
+ GLuint da = stack[mach->sp + 4]._addr;
+ mach->mem[da / 4]._float /= stack[mach->sp]._float;
+ mach->mem[(da + 4) / 4]._float /= stack[mach->sp + 1]._float;
+ mach->mem[(da + 8) / 4]._float /= stack[mach->sp + 2]._float;
+ mach->mem[(da + 12) / 4]._float /= stack[mach->sp + 3]._float;
+ mach->sp += 4;
+ }
+ break;
+ case slang_asm_vec4_negate:
+ /* [vec4] > [vec4] */
+ {
+ GLuint da = stack[mach->sp]._addr;
+ mach->mem[da / 4]._float = -mach->mem[da / 4]._float;
+ mach->mem[(da + 4) / 4]._float = -mach->mem[(da + 4) / 4]._float;
+ mach->mem[(da + 8) / 4]._float = -mach->mem[(da + 8) / 4]._float;
+ mach->mem[(da + 12) / 4]._float = -mach->mem[(da + 12) / 4]._float;
+ }
+ break;
+ case slang_asm_vec4_dot:
+ /* [vec4] | vec4 > [float] */
+ {
+ GLuint da = stack[mach->sp + 4]._addr;
+ mach->mem[da / 4]._float =
+ mach->mem[da / 4]._float * stack[mach->sp]._float +
+ mach->mem[(da + 4) / 4]._float * stack[mach->sp + 1]._float +
+ mach->mem[(da + 8) / 4]._float * stack[mach->sp + 2]._float +
+ mach->mem[(da + 12) / 4]._float * stack[mach->sp + 3]._float;
+ mach->sp += 4;
+ }
+ break;
+ case slang_asm_vec4_copy:
+ /* [vec4] | vec4 > [vec4] */
+ {
+ GLuint da = stack[mach->sp + a->param[0] / 4]._addr + a->param[1];
+ mach->mem[da / 4]._float = stack[mach->sp]._float;
+ mach->mem[(da + 4) / 4]._float = stack[mach->sp + 1]._float;
+ mach->mem[(da + 8) / 4]._float = stack[mach->sp + 2]._float;
+ mach->mem[(da + 12) / 4]._float = stack[mach->sp + 3]._float;
+ mach->sp += 4;
+ }
+ break;
+ case slang_asm_vec4_deref:
+ /* [vec4] > vec4 */
+ {
+ GLuint sa = stack[mach->sp]._addr;
+ mach->sp -= 3;
+ stack[mach->sp]._float = mach->mem[sa / 4]._float;
+ stack[mach->sp + 1]._float = mach->mem[(sa + 4) / 4]._float;
+ stack[mach->sp + 2]._float = mach->mem[(sa + 8) / 4]._float;
+ stack[mach->sp + 3]._float = mach->mem[(sa + 12) / 4]._float;
+ }
+ break;
+ case slang_asm_vec4_equal_int:
+ {
+ GLuint sp0 = mach->sp + a->param[0] / 4;
+ GLuint sp1 = mach->sp + a->param[1] / 4;
+ mach->sp--;
+ if (stack[sp0]._float == stack[sp1]._float &&
+ stack[sp0 + 1]._float == stack[sp1 + 1]._float &&
+ stack[sp0 + 2]._float == stack[sp1 + 2]._float &&
+ stack[sp0 + 3]._float == stack[sp1 + 3]._float) {
+ stack[mach->sp]._float = 1.0f;
+ }
+ else {
+ stack[mach->sp]._float = 0.0f;
+ }
+ }
+ break;
+ default:
+ _mesa_problem(NULL, "bad slang opcode 0x%x", a->type);
+ return GL_FALSE;
+ }
+ }
+
+#if DEBUG_SLANG
+ if (f != NULL)
+ fclose (f);
+#endif
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_execute.h b/src/mesa/shader/slang/slang_execute.h
new file mode 100644
index 00000000000..cb152c71420
--- /dev/null
+++ b/src/mesa/shader/slang/slang_execute.h
@@ -0,0 +1,85 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_EXECUTE_H
+#define SLANG_EXECUTE_H
+
+#include "slang_assemble.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef union slang_machine_slot_
+{
+ GLfloat _float;
+ GLuint _addr;
+} slang_machine_slot;
+
+#define SLANG_MACHINE_GLOBAL_SIZE 3072
+#define SLANG_MACHINE_STACK_SIZE 1024
+#define SLANG_MACHINE_MEMORY_SIZE (SLANG_MACHINE_GLOBAL_SIZE + SLANG_MACHINE_STACK_SIZE)
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+typedef struct
+{
+ GLvoid (* compiled_func) (struct slang_machine_ *);
+ GLuint esp_restore;
+ GLshort fpucntl_rnd_neg;
+ GLshort fpucntl_restore;
+} slang_machine_x86;
+#endif
+
+typedef struct slang_machine_
+{
+ GLuint ip; /* instruction pointer, for flow control */
+ GLuint sp; /* stack pointer, for stack access */
+ GLuint bp; /* base pointer, for local variable access */
+ GLuint kill; /* discard the fragment */
+ GLuint exit; /* terminate the shader */
+ slang_machine_slot mem[SLANG_MACHINE_MEMORY_SIZE];
+ struct slang_info_log_ *infolog; /* printMESA() support */
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ slang_machine_x86 x86;
+#endif
+} slang_machine;
+
+GLvoid slang_machine_ctr (slang_machine *);
+GLvoid slang_machine_dtr (slang_machine *);
+
+void slang_machine_init (slang_machine *);
+
+GLboolean
+_slang_execute2 (const slang_assembly_file *, slang_machine *);
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+GLboolean _slang_x86_codegen (slang_machine *, slang_assembly_file *, GLuint);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_execute_x86.c b/src/mesa/shader/slang/slang_execute_x86.c
new file mode 100644
index 00000000000..3e21edff6a3
--- /dev/null
+++ b/src/mesa/shader/slang/slang_execute_x86.c
@@ -0,0 +1,748 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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 slang_execute_x86.c
+ * x86 back end compiler
+ * \author Michal Krol, Keith Whitwell
+ */
+
+#include "imports.h"
+#include "slang_compile.h"
+#include "slang_execute.h"
+#include "slang_library_noise.h"
+#include "slang_library_texsample.h"
+
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+
+#include "x86/rtasm/x86sse.h"
+
+typedef struct
+{
+ GLuint index;
+ GLubyte *csr;
+} fixup;
+
+typedef struct
+{
+ struct x86_function f;
+ struct x86_reg r_eax;
+ struct x86_reg r_ecx;
+ struct x86_reg r_edx;
+ struct x86_reg r_ebx;
+ struct x86_reg r_esp;
+ struct x86_reg r_ebp;
+ struct x86_reg r_st0;
+ struct x86_reg r_st1;
+ struct x86_reg r_st2;
+ struct x86_reg r_st3;
+ struct x86_reg r_st4;
+ fixup *fixups;
+ GLuint fixup_count;
+ GLubyte **labels;
+ slang_machine *mach;
+ GLubyte *l_discard;
+ GLubyte *l_exit;
+ GLshort fpucntl;
+} codegen_ctx;
+
+static GLvoid add_fixup (codegen_ctx *G, GLuint index, GLubyte *csr)
+{
+ G->fixups = (fixup *) slang_alloc_realloc (G->fixups, G->fixup_count * sizeof (fixup),
+ (G->fixup_count + 1) * sizeof (fixup));
+ G->fixups[G->fixup_count].index = index;
+ G->fixups[G->fixup_count].csr = csr;
+ G->fixup_count++;
+}
+
+#ifdef NO_FAST_MATH
+#define RESTORE_FPU (DEFAULT_X86_FPU)
+#define RND_NEG_FPU (DEFAULT_X86_FPU | 0x400)
+#else
+#define RESTORE_FPU (FAST_X86_FPU)
+#define RND_NEG_FPU (FAST_X86_FPU | 0x400)
+#endif
+
+#if 0
+
+/*
+ * XXX
+ * These should produce a valid code that computes powers. Unfortunately, it does not.
+ */
+static void set_fpu_round_neg_inf (codegen_ctx *G)
+{
+ if (G->fpucntl != RND_NEG_FPU)
+ {
+ G->fpucntl = RND_NEG_FPU;
+ x87_fnclex (&G->f);
+ x86_mov_reg_imm (&G->f, G->r_eax, (GLint) &G->mach->x86.fpucntl_rnd_neg);
+ x87_fldcw (&G->f, x86_deref (G->r_eax));
+ }
+}
+
+static void emit_x87_ex2 (codegen_ctx *G)
+{
+ set_fpu_round_neg_inf (G);
+
+ x87_fld (&G->f, G->r_st0); /* a a */
+ x87_fprndint (&G->f); /* int(a) a */
+ x87_fld (&G->f, G->r_st0); /* int(a) int(a) a */
+ x87_fstp (&G->f, G->r_st3); /* int(a) a int(a)*/
+ x87_fsubp (&G->f, G->r_st1);/* frac(a) int(a) */
+ x87_f2xm1 (&G->f); /* (2^frac(a))-1 int(a)*/
+ x87_fld1 (&G->f); /* 1 (2^frac(a))-1 int(a)*/
+ x87_faddp (&G->f, G->r_st1);/* 2^frac(a) int(a) */
+ x87_fscale (&G->f); /* 2^a */
+}
+
+static void emit_pow (codegen_ctx *G)
+{
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x87_fld (&G->f, x86_make_disp (G->r_esp, 4));
+ x87_fyl2x (&G->f);
+ emit_x87_ex2 (G);
+}
+
+#endif
+
+static GLfloat do_ceilf (GLfloat x)
+{
+ return CEILF (x);
+}
+
+static GLfloat do_floorf (GLfloat x)
+{
+ return FLOORF (x);
+}
+
+static GLfloat
+do_ftoi (GLfloat x)
+{
+ return (GLfloat) ((GLint) (x));
+}
+
+static GLfloat do_powf (GLfloat y, GLfloat x)
+{
+ return (GLfloat) _mesa_pow ((GLdouble) x, (GLdouble) y);
+}
+
+static GLvoid
+ensure_infolog_created (slang_info_log **infolog)
+{
+ if (*infolog == NULL) {
+ *infolog = slang_alloc_malloc (sizeof (slang_info_log));
+ if (*infolog == NULL)
+ return;
+ slang_info_log_construct (*infolog);
+ }
+}
+
+static GLvoid do_print_float (slang_info_log **infolog, GLfloat x)
+{
+ _mesa_printf ("slang print: %f\n", x);
+ ensure_infolog_created (infolog);
+ slang_info_log_print (*infolog, "%f", x);
+}
+
+static GLvoid do_print_int (slang_info_log **infolog, GLfloat x)
+{
+ _mesa_printf ("slang print: %d\n", (GLint) (x));
+ ensure_infolog_created (infolog);
+ slang_info_log_print (*infolog, "%d", (GLint) (x));
+}
+
+static GLvoid do_print_bool (slang_info_log **infolog, GLfloat x)
+{
+ _mesa_printf ("slang print: %s\n", (GLint) (x) ? "true" : "false");
+ ensure_infolog_created (infolog);
+ slang_info_log_print (*infolog, "%s", (GLint) (x) ? "true" : "false");
+}
+
+#define FLOAT_ONE 0x3f800000
+#define FLOAT_ZERO 0
+
+static GLvoid codegen_assem (codegen_ctx *G, slang_assembly *a, slang_info_log **infolog)
+{
+ GLint disp, i;
+
+ switch (a->type)
+ {
+ case slang_asm_none:
+ break;
+ case slang_asm_float_copy:
+ case slang_asm_int_copy:
+ case slang_asm_bool_copy:
+ x86_mov (&G->f, G->r_eax, x86_make_disp (G->r_esp, a->param[0]));
+ x86_pop (&G->f, G->r_ecx);
+ x86_mov (&G->f, x86_make_disp (G->r_eax, a->param[1]), G->r_ecx);
+ break;
+ case slang_asm_float_move:
+ case slang_asm_int_move:
+ case slang_asm_bool_move:
+ x86_lea (&G->f, G->r_eax, x86_make_disp (G->r_esp, a->param[1]));
+ x86_add (&G->f, G->r_eax, x86_deref (G->r_esp));
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_eax));
+ x86_mov (&G->f, x86_make_disp (G->r_esp, a->param[0]), G->r_eax);
+ break;
+ case slang_asm_float_push:
+ case slang_asm_int_push:
+ case slang_asm_bool_push:
+ /* TODO: use push imm32 */
+ x86_mov_reg_imm (&G->f, G->r_eax, *((GLint *) &a->literal));
+ x86_push (&G->f, G->r_eax);
+ break;
+ case slang_asm_float_deref:
+ case slang_asm_int_deref:
+ case slang_asm_bool_deref:
+ case slang_asm_addr_deref:
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_esp));
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_eax));
+ x86_mov (&G->f, x86_deref (G->r_esp), G->r_eax);
+ break;
+ case slang_asm_float_add:
+ x87_fld (&G->f, x86_make_disp (G->r_esp, 4));
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x87_faddp (&G->f, G->r_st1);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_multiply:
+ x87_fld (&G->f, x86_make_disp (G->r_esp, 4));
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x87_fmulp (&G->f, G->r_st1);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_divide:
+ x87_fld (&G->f, x86_make_disp (G->r_esp, 4));
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x87_fdivp (&G->f, G->r_st1);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_negate:
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x87_fchs (&G->f);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_less:
+ x87_fld (&G->f, x86_make_disp (G->r_esp, 4));
+ x87_fcomp (&G->f, x86_deref (G->r_esp));
+ x87_fnstsw (&G->f, G->r_eax);
+ /* TODO: use test r8,imm8 */
+ x86_mov_reg_imm (&G->f, G->r_ecx, 0x100);
+ x86_test (&G->f, G->r_eax, G->r_ecx);
+ {
+ GLubyte *lab0, *lab1;
+
+ /* TODO: use jcc rel8 */
+ lab0 = x86_jcc_forward (&G->f, cc_E);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ONE);
+ /* TODO: use jmp rel8 */
+ lab1 = x86_jmp_forward (&G->f);
+ x86_fixup_fwd_jump (&G->f, lab0);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ZERO);
+ x86_fixup_fwd_jump (&G->f, lab1);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x86_mov (&G->f, x86_deref (G->r_esp), G->r_ecx);
+ }
+ break;
+ case slang_asm_float_equal_exp:
+ x87_fld (&G->f, x86_make_disp (G->r_esp, 4));
+ x87_fcomp (&G->f, x86_deref (G->r_esp));
+ x87_fnstsw (&G->f, G->r_eax);
+ /* TODO: use test r8,imm8 */
+ x86_mov_reg_imm (&G->f, G->r_ecx, 0x4000);
+ x86_test (&G->f, G->r_eax, G->r_ecx);
+ {
+ GLubyte *lab0, *lab1;
+
+ /* TODO: use jcc rel8 */
+ lab0 = x86_jcc_forward (&G->f, cc_E);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ONE);
+ /* TODO: use jmp rel8 */
+ lab1 = x86_jmp_forward (&G->f);
+ x86_fixup_fwd_jump (&G->f, lab0);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ZERO);
+ x86_fixup_fwd_jump (&G->f, lab1);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x86_mov (&G->f, x86_deref (G->r_esp), G->r_ecx);
+ }
+ break;
+ case slang_asm_float_equal_int:
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, -4));
+ x87_fld (&G->f, x86_make_disp (G->r_esp, a->param[0] + 4));
+ x87_fcomp (&G->f, x86_make_disp (G->r_esp, a->param[1] + 4));
+ x87_fnstsw (&G->f, G->r_eax);
+ /* TODO: use test r8,imm8 */
+ x86_mov_reg_imm (&G->f, G->r_ecx, 0x4000);
+ x86_test (&G->f, G->r_eax, G->r_ecx);
+ {
+ GLubyte *lab0, *lab1;
+
+ /* TODO: use jcc rel8 */
+ lab0 = x86_jcc_forward (&G->f, cc_E);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ONE);
+ /* TODO: use jmp rel8 */
+ lab1 = x86_jmp_forward (&G->f);
+ x86_fixup_fwd_jump (&G->f, lab0);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ZERO);
+ x86_fixup_fwd_jump (&G->f, lab1);
+ x86_mov (&G->f, x86_deref (G->r_esp), G->r_ecx);
+ }
+ break;
+ case slang_asm_float_to_int:
+ /* TODO: use fistp without rounding */
+ x86_call (&G->f, (GLubyte *) (do_ftoi));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_sine:
+ /* TODO: use fsin */
+ x86_call (&G->f, (GLubyte *) _mesa_sinf);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_arcsine:
+ /* TODO: use fpatan (?) */
+ x86_call (&G->f, (GLubyte *) _mesa_asinf);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_arctan:
+ /* TODO: use fpatan */
+ x86_call (&G->f, (GLubyte *) _mesa_atanf);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_power:
+ /* TODO: use emit_pow() */
+ x86_call (&G->f, (GLubyte *) do_powf);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_log2:
+ x87_fld1 (&G->f);
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x87_fyl2x (&G->f);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_floor:
+ x86_call (&G->f, (GLubyte *) do_floorf);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_ceil:
+ x86_call (&G->f, (GLubyte *) do_ceilf);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_noise1:
+ x86_call (&G->f, (GLubyte *) _slang_library_noise1);
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_noise2:
+ x86_call (&G->f, (GLubyte *) _slang_library_noise2);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_noise3:
+ x86_call (&G->f, (GLubyte *) _slang_library_noise4);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 8));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_float_noise4:
+ x86_call (&G->f, (GLubyte *) _slang_library_noise4);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 12));
+ x87_fstp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_int_to_float:
+ break;
+ case slang_asm_int_to_addr:
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x87_fistp (&G->f, x86_deref (G->r_esp));
+ break;
+ case slang_asm_addr_copy:
+ x86_pop (&G->f, G->r_eax);
+ x86_mov (&G->f, G->r_ecx, x86_deref (G->r_esp));
+ x86_mov (&G->f, x86_deref (G->r_ecx), G->r_eax);
+ break;
+ case slang_asm_addr_push:
+ /* TODO: use push imm32 */
+ x86_mov_reg_imm (&G->f, G->r_eax, (GLint) a->param[0]);
+ x86_push (&G->f, G->r_eax);
+ break;
+ case slang_asm_addr_add:
+ x86_pop (&G->f, G->r_eax);
+ x86_add (&G->f, x86_deref (G->r_esp), G->r_eax);
+ break;
+ case slang_asm_addr_multiply:
+ x86_pop (&G->f, G->r_ecx);
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_esp));
+ x86_mul (&G->f, G->r_ecx);
+ x86_mov (&G->f, x86_deref (G->r_esp), G->r_eax);
+ break;
+ case slang_asm_vec4_tex1d:
+ x86_call (&G->f, (GLubyte *) _slang_library_tex1d);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 12));
+ break;
+ case slang_asm_vec4_tex2d:
+ x86_call (&G->f, (GLubyte *) _slang_library_tex2d);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 16));
+ break;
+ case slang_asm_vec4_tex3d:
+ x86_call (&G->f, (GLubyte *) _slang_library_tex3d);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 20));
+ break;
+ case slang_asm_vec4_texcube:
+ x86_call (&G->f, (GLubyte *) _slang_library_texcube);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 20));
+ break;
+ case slang_asm_vec4_shad1d:
+ x86_call (&G->f, (GLubyte *) _slang_library_shad1d);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 20));
+ break;
+ case slang_asm_vec4_shad2d:
+ x86_call (&G->f, (GLubyte *) _slang_library_shad2d);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 20));
+ break;
+ case slang_asm_jump:
+ add_fixup (G, a->param[0], x86_jmp_forward (&G->f));
+ break;
+ case slang_asm_jump_if_zero:
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x86_xor (&G->f, G->r_eax, G->r_eax);
+ x86_cmp (&G->f, G->r_eax, x86_make_disp (G->r_esp, -4));
+ {
+ GLubyte *lab0;
+
+ /* TODO: use jcc rel8 */
+ lab0 = x86_jcc_forward (&G->f, cc_NE);
+ add_fixup (G, a->param[0], x86_jmp_forward (&G->f));
+ x86_fixup_fwd_jump (&G->f, lab0);
+ }
+ break;
+ case slang_asm_enter:
+ /* FIXME: x86_make_disp(esp, 0) + x86_lea() generates bogus code */
+ assert (a->param[0] != 0);
+ x86_push (&G->f, G->r_ebp);
+ x86_lea (&G->f, G->r_ebp, x86_make_disp (G->r_esp, (GLint) a->param[0]));
+ break;
+ case slang_asm_leave:
+ x86_pop (&G->f, G->r_ebp);
+ break;
+ case slang_asm_local_alloc:
+ /* FIXME: x86_make_disp(esp, 0) + x86_lea() generates bogus code */
+ assert (a->param[0] != 0);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, -(GLint) a->param[0]));
+ break;
+ case slang_asm_local_free:
+ /* FIXME: x86_make_disp(esp, 0) + x86_lea() generates bogus code */
+ assert (a->param[0] != 0);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, (GLint) a->param[0]));
+ break;
+ case slang_asm_local_addr:
+ disp = -(GLint) (a->param[0] + a->param[1]) + 4;
+ if (disp != 0)
+ {
+ x86_lea (&G->f, G->r_eax, x86_make_disp (G->r_ebp, disp));
+ x86_push (&G->f, G->r_eax);
+ }
+ else
+ x86_push (&G->f, G->r_ebp);
+ break;
+ case slang_asm_global_addr:
+ /* TODO: use push imm32 */
+ x86_mov_reg_imm (&G->f, G->r_eax, (GLint) &G->mach->mem + a->param[0]);
+ x86_push (&G->f, G->r_eax);
+ break;
+ case slang_asm_call:
+ add_fixup (G, a->param[0], x86_call_forward (&G->f));
+ break;
+ case slang_asm_return:
+ x86_ret (&G->f);
+ break;
+ case slang_asm_discard:
+ x86_jmp (&G->f, G->l_discard);
+ break;
+ case slang_asm_exit:
+ x86_jmp (&G->f, G->l_exit);
+ break;
+ /* GL_MESA_shader_debug */
+ case slang_asm_float_print:
+ /* TODO: use push imm32 */
+ x86_mov_reg_imm (&G->f, G->r_eax, (GLint) (infolog));
+ x86_push (&G->f, G->r_eax);
+ x86_call (&G->f, (GLubyte *) (do_print_float));
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ break;
+ case slang_asm_int_print:
+ /* TODO: use push imm32 */
+ x86_mov_reg_imm (&G->f, G->r_eax, (GLint) (infolog));
+ x86_push (&G->f, G->r_eax);
+ x86_call (&G->f, (GLubyte *) do_print_int);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ break;
+ case slang_asm_bool_print:
+ /* TODO: use push imm32 */
+ x86_mov_reg_imm (&G->f, G->r_eax, (GLint) (infolog));
+ x86_push (&G->f, G->r_eax);
+ x86_call (&G->f, (GLubyte *) do_print_bool);
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ break;
+ /* vec4 */
+ case slang_asm_float_to_vec4:
+ /* [vec4] | float > [vec4] */
+ x87_fld (&G->f, x86_deref (G->r_esp));
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 4));
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_esp));
+ x87_fst (&G->f, x86_make_disp (G->r_eax, 12));
+ x87_fst (&G->f, x86_make_disp (G->r_eax, 8));
+ x87_fst (&G->f, x86_make_disp (G->r_eax, 4));
+ x87_fstp (&G->f, x86_deref (G->r_eax));
+ break;
+ case slang_asm_vec4_add:
+ /* [vec4] | vec4 > [vec4] */
+ x86_mov (&G->f, G->r_eax, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_eax, i * 4));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_esp, i * 4));
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_faddp (&G->f, G->r_st4);
+ for (i = 0; i < 4; i++)
+ x87_fstp (&G->f, x86_make_disp (G->r_eax, 12 - i * 4));
+ break;
+ case slang_asm_vec4_subtract:
+ /* [vec4] | vec4 > [vec4] */
+ x86_mov (&G->f, G->r_eax, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_eax, i * 4));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_esp, i * 4));
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_fsubp (&G->f, G->r_st4);
+ for (i = 0; i < 4; i++)
+ x87_fstp (&G->f, x86_make_disp (G->r_eax, 12 - i * 4));
+ break;
+ case slang_asm_vec4_multiply:
+ /* [vec4] | vec4 > [vec4] */
+ x86_mov (&G->f, G->r_eax, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_eax, i * 4));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_esp, i * 4));
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_fmulp (&G->f, G->r_st4);
+ for (i = 0; i < 4; i++)
+ x87_fstp (&G->f, x86_make_disp (G->r_eax, 12 - i * 4));
+ break;
+ case slang_asm_vec4_divide:
+ /* [vec4] | vec4 > [vec4] */
+ x86_mov (&G->f, G->r_eax, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_eax, i * 4));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_esp, i * 4));
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 16));
+ for (i = 0; i < 4; i++)
+ x87_fdivp (&G->f, G->r_st4);
+ for (i = 0; i < 4; i++)
+ x87_fstp (&G->f, x86_make_disp (G->r_eax, 12 - i * 4));
+ break;
+ case slang_asm_vec4_negate:
+ /* [vec4] > [vec4] */
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_esp));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_eax, i * 4));
+ for (i = 0; i < 4; i++) {
+ x87_fchs (&G->f);
+ x87_fstp (&G->f, x86_make_disp (G->r_eax, 12 - i * 4));
+ }
+ break;
+ case slang_asm_vec4_dot:
+ /* [vec4] | vec4 > [float] */
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_esp, i * 4));
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, 16));
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_esp));
+ for (i = 0; i < 4; i++)
+ x87_fld (&G->f, x86_make_disp (G->r_eax, i * 4));
+ for (i = 0; i < 4; i++)
+ x87_fmulp (&G->f, G->r_st4);
+ for (i = 0; i < 3; i++)
+ x87_faddp (&G->f, G->r_st1);
+ x87_fstp (&G->f, x86_deref (G->r_eax));
+ break;
+ case slang_asm_vec4_copy:
+ /* [vec4] | vec4 > [vec4] */
+ x86_mov (&G->f, G->r_eax, x86_make_disp (G->r_esp, a->param[0]));
+ x86_pop (&G->f, G->r_ecx);
+ x86_pop (&G->f, G->r_edx);
+ x86_mov (&G->f, x86_make_disp (G->r_eax, a->param[1]), G->r_ecx);
+ x86_pop (&G->f, G->r_ebx);
+ x86_mov (&G->f, x86_make_disp (G->r_eax, a->param[1] + 4), G->r_edx);
+ x86_pop (&G->f, G->r_ecx);
+ x86_mov (&G->f, x86_make_disp (G->r_eax, a->param[1] + 8), G->r_ebx);
+ x86_mov (&G->f, x86_make_disp (G->r_eax, a->param[1] + 12), G->r_ecx);
+ break;
+ case slang_asm_vec4_deref:
+ /* [vec4] > vec4 */
+ x86_mov (&G->f, G->r_eax, x86_deref (G->r_esp));
+ x86_mov (&G->f, G->r_ecx, x86_make_disp (G->r_eax, 12));
+ x86_mov (&G->f, G->r_edx, x86_make_disp (G->r_eax, 8));
+ x86_mov (&G->f, x86_deref (G->r_esp), G->r_ecx);
+ x86_mov (&G->f, G->r_ebx, x86_make_disp (G->r_eax, 4));
+ x86_push (&G->f, G->r_edx);
+ x86_mov (&G->f, G->r_ecx, x86_deref (G->r_eax));
+ x86_push (&G->f, G->r_ebx);
+ x86_push (&G->f, G->r_ecx);
+ break;
+ case slang_asm_vec4_equal_int:
+ x86_lea (&G->f, G->r_esp, x86_make_disp (G->r_esp, -4));
+ x86_mov_reg_imm (&G->f, G->r_edx, 0x4000);
+ for (i = 0; i < 4; i++) {
+ x87_fld (&G->f, x86_make_disp (G->r_esp, a->param[0] + 4 + i * 4));
+ x87_fcomp (&G->f, x86_make_disp (G->r_esp, a->param[1] + 4 + i * 4));
+ x87_fnstsw (&G->f, G->r_eax);
+ x86_and (&G->f, G->r_edx, G->r_eax);
+ }
+ /* TODO: use test r8,imm8 */
+ x86_mov_reg_imm (&G->f, G->r_ecx, 0x4000);
+ x86_test (&G->f, G->r_edx, G->r_ecx);
+ {
+ GLubyte *lab0, *lab1;
+
+ /* TODO: use jcc rel8 */
+ lab0 = x86_jcc_forward (&G->f, cc_E);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ONE);
+ /* TODO: use jmp rel8 */
+ lab1 = x86_jmp_forward (&G->f);
+ x86_fixup_fwd_jump (&G->f, lab0);
+ x86_mov_reg_imm (&G->f, G->r_ecx, FLOAT_ZERO);
+ x86_fixup_fwd_jump (&G->f, lab1);
+ x86_mov (&G->f, x86_deref (G->r_esp), G->r_ecx);
+ }
+ break;
+ default:
+ assert (0);
+ }
+}
+
+GLboolean _slang_x86_codegen (slang_machine *mach, slang_assembly_file *file, GLuint start)
+{
+ codegen_ctx G;
+ GLubyte *j_body, *j_exit;
+ GLuint i;
+
+ /* Free the old code - if any.
+ */
+ if (mach->x86.compiled_func != NULL) {
+ _mesa_exec_free (mach->x86.compiled_func);
+ mach->x86.compiled_func = NULL;
+ }
+
+ /*
+ * We need as much as 1M because *all* assembly, including built-in library, is
+ * being translated to x86.
+ * The built-in library occupies 450K, so we can be safe for now.
+ * It is going to change in the future, when we get assembly analysis running.
+ */
+ x86_init_func_size (&G.f, 1048576);
+ G.r_eax = x86_make_reg (file_REG32, reg_AX);
+ G.r_ecx = x86_make_reg (file_REG32, reg_CX);
+ G.r_edx = x86_make_reg (file_REG32, reg_DX);
+ G.r_ebx = x86_make_reg (file_REG32, reg_BX);
+ G.r_esp = x86_make_reg (file_REG32, reg_SP);
+ G.r_ebp = x86_make_reg (file_REG32, reg_BP);
+ G.r_st0 = x86_make_reg (file_x87, 0);
+ G.r_st1 = x86_make_reg (file_x87, 1);
+ G.r_st2 = x86_make_reg (file_x87, 2);
+ G.r_st3 = x86_make_reg (file_x87, 3);
+ G.r_st4 = x86_make_reg (file_x87, 4);
+ G.fixups = NULL;
+ G.fixup_count = 0;
+ G.labels = (GLubyte **) slang_alloc_malloc (file->count * sizeof (GLubyte *));
+ G.mach = mach;
+ G.fpucntl = RESTORE_FPU;
+
+ mach->x86.fpucntl_rnd_neg = RND_NEG_FPU;
+ mach->x86.fpucntl_restore = RESTORE_FPU;
+
+ /* prepare stack and jump to start */
+ x86_push (&G.f, G.r_ebp);
+ x86_mov_reg_imm (&G.f, G.r_eax, (GLint) &mach->x86.esp_restore);
+ x86_push (&G.f, G.r_esp);
+ x86_pop (&G.f, G.r_ecx);
+ x86_mov (&G.f, x86_deref (G.r_eax), G.r_ecx);
+ j_body = x86_jmp_forward (&G.f);
+
+ /* "discard" instructions jump to this label */
+ G.l_discard = x86_get_label (&G.f);
+ x86_mov_reg_imm (&G.f, G.r_eax, (GLint) &G.mach->kill);
+ x86_mov_reg_imm (&G.f, G.r_ecx, 1);
+ x86_mov (&G.f, x86_deref (G.r_eax), G.r_ecx);
+ G.l_exit = x86_get_label (&G.f);
+ j_exit = x86_jmp_forward (&G.f);
+
+ for (i = 0; i < file->count; i++)
+ {
+ G.labels[i] = x86_get_label (&G.f);
+ if (i == start)
+ x86_fixup_fwd_jump (&G.f, j_body);
+ codegen_assem (&G, &file->code[i], &mach->infolog);
+ }
+
+ /*
+ * Restore stack and return.
+ * This must be handled this way, because "discard" can be invoked from any
+ * place in the code.
+ */
+ x86_fixup_fwd_jump (&G.f, j_exit);
+ x86_mov_reg_imm (&G.f, G.r_eax, (GLint) &mach->x86.esp_restore);
+ x86_mov (&G.f, G.r_esp, x86_deref (G.r_eax));
+ x86_pop (&G.f, G.r_ebp);
+ if (G.fpucntl != RESTORE_FPU)
+ {
+ x87_fnclex (&G.f);
+ x86_mov_reg_imm (&G.f, G.r_eax, (GLint) &G.mach->x86.fpucntl_restore);
+ x87_fldcw (&G.f, x86_deref (G.r_eax));
+ }
+ x86_ret (&G.f);
+
+ /* fixup forward labels */
+ for (i = 0; i < G.fixup_count; i++)
+ {
+ G.f.csr = G.labels[G.fixups[i].index];
+ x86_fixup_fwd_jump (&G.f, G.fixups[i].csr);
+ }
+
+ slang_alloc_free (G.fixups);
+ slang_alloc_free (G.labels);
+
+ /* install new code */
+ mach->x86.compiled_func = (GLvoid (*) (slang_machine *)) x86_get_func (&G.f);
+
+ return GL_TRUE;
+}
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_export.c b/src/mesa/shader/slang/slang_export.c
new file mode 100644
index 00000000000..9620ef07901
--- /dev/null
+++ b/src/mesa/shader/slang/slang_export.c
@@ -0,0 +1,386 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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 slang_export.c
+ * interface between assembly code and the application
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_export.h"
+
+/*
+ * slang_export_data_quant
+ */
+
+GLvoid slang_export_data_quant_ctr (slang_export_data_quant *self)
+{
+ self->name = SLANG_ATOM_NULL;
+ self->size = 0;
+ self->array_len = 0;
+ self->structure = NULL;
+ self->u.basic_type = GL_FLOAT;
+}
+
+GLvoid slang_export_data_quant_dtr (slang_export_data_quant *self)
+{
+ if (self->structure != NULL)
+ {
+ GLuint i;
+
+ for (i = 0; i < self->u.field_count; i++)
+ slang_export_data_quant_dtr (&self->structure[i]);
+ slang_alloc_free (self->structure);
+ }
+}
+
+slang_export_data_quant *slang_export_data_quant_add_field (slang_export_data_quant *self)
+{
+ const GLuint n = self->u.field_count;
+
+ self->structure = (slang_export_data_quant *) slang_alloc_realloc (self->structure,
+ n * sizeof (slang_export_data_quant), (n + 1) * sizeof (slang_export_data_quant));
+ if (self->structure == NULL)
+ return NULL;
+ slang_export_data_quant_ctr (&self->structure[n]);
+ self->u.field_count++;
+ return &self->structure[n];
+}
+
+GLboolean slang_export_data_quant_array (slang_export_data_quant *self)
+{
+ return self->array_len != 0;
+}
+
+GLboolean slang_export_data_quant_struct (slang_export_data_quant *self)
+{
+ return self->structure != NULL;
+}
+
+GLboolean slang_export_data_quant_simple (slang_export_data_quant *self)
+{
+ return self->array_len == 0 && self->structure == NULL;
+}
+
+GLenum slang_export_data_quant_type (slang_export_data_quant *self)
+{
+ assert (self->structure == NULL);
+ return self->u.basic_type;
+}
+
+GLuint slang_export_data_quant_fields (slang_export_data_quant *self)
+{
+ assert (self->structure != NULL);
+ return self->u.field_count;
+}
+
+GLuint slang_export_data_quant_elements (slang_export_data_quant *self)
+{
+ if (self->array_len == 0)
+ return 1;
+ return self->array_len;
+}
+
+GLuint slang_export_data_quant_components (slang_export_data_quant *self)
+{
+ return self->size / 4;
+}
+
+GLuint slang_export_data_quant_size (slang_export_data_quant *self)
+{
+ return self->size;
+}
+
+/*
+ * slang_export_data_entry
+ */
+
+GLvoid slang_export_data_entry_ctr (slang_export_data_entry *self)
+{
+ slang_export_data_quant_ctr (&self->quant);
+ self->access = slang_exp_uniform;
+ self->address = ~0;
+}
+
+GLvoid slang_export_data_entry_dtr (slang_export_data_entry *self)
+{
+ slang_export_data_quant_dtr (&self->quant);
+}
+
+/*
+ * slang_export_data_table
+ */
+
+GLvoid slang_export_data_table_ctr (slang_export_data_table *self)
+{
+ self->entries = NULL;
+ self->count = 0;
+ self->atoms = NULL;
+}
+
+GLvoid slang_export_data_table_dtr (slang_export_data_table *self)
+{
+ if (self->entries != NULL)
+ {
+ GLuint i;
+
+ for (i = 0; i < self->count; i++)
+ slang_export_data_entry_dtr (&self->entries[i]);
+ slang_alloc_free (self->entries);
+ }
+}
+
+slang_export_data_entry *slang_export_data_table_add (slang_export_data_table *self)
+{
+ const GLuint n = self->count;
+
+ self->entries = (slang_export_data_entry *) slang_alloc_realloc (self->entries,
+ n * sizeof (slang_export_data_entry), (n + 1) * sizeof (slang_export_data_entry));
+ if (self->entries == NULL)
+ return NULL;
+ slang_export_data_entry_ctr (&self->entries[n]);
+ self->count++;
+ return &self->entries[n];
+}
+
+/*
+ * slang_export_code_entry
+ */
+
+static GLvoid slang_export_code_entry_ctr (slang_export_code_entry *self)
+{
+ self->name = SLANG_ATOM_NULL;
+ self->address = ~0;
+}
+
+static GLvoid slang_export_code_entry_dtr (slang_export_code_entry *self)
+{
+}
+
+/*
+ * slang_export_code_table
+ */
+
+GLvoid slang_export_code_table_ctr (slang_export_code_table *self)
+{
+ self->entries = NULL;
+ self->count = 0;
+ self->atoms = NULL;
+}
+
+GLvoid slang_export_code_table_dtr (slang_export_code_table *self)
+{
+ if (self->entries != NULL)
+ {
+ GLuint i;
+
+ for (i = 0; i < self->count; i++)
+ slang_export_code_entry_dtr (&self->entries[i]);
+ slang_alloc_free (self->entries);
+ }
+}
+
+slang_export_code_entry *slang_export_code_table_add (slang_export_code_table *self)
+{
+ const GLuint n = self->count;
+
+ self->entries = (slang_export_code_entry *) slang_alloc_realloc (self->entries,
+ n * sizeof (slang_export_code_entry), (n + 1) * sizeof (slang_export_code_entry));
+ if (self->entries == NULL)
+ return NULL;
+ slang_export_code_entry_ctr (&self->entries[n]);
+ self->count++;
+ return &self->entries[n];
+}
+
+/*
+ * _slang_find_exported_data()
+ */
+
+#define EXTRACT_ERROR 0
+#define EXTRACT_BASIC 1
+#define EXTRACT_ARRAY 2
+#define EXTRACT_STRUCT 3
+#define EXTRACT_STRUCT_ARRAY 4
+
+#define EXTRACT_MAXLEN 255
+
+static GLuint extract_name (const char *name, char *parsed, GLuint *element, const char **end)
+{
+ GLuint i;
+
+ if ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_')
+ {
+ parsed[0] = name[0];
+
+ for (i = 1; i < EXTRACT_MAXLEN; i++)
+ {
+ if ((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= 'A' && name[i] <= 'Z') ||
+ (name[i] >= '0' && name[i] <= '9') || name[0] == '_')
+ {
+ parsed[i] = name[i];
+ }
+ else
+ {
+ if (name[i] == '\0')
+ {
+ parsed[i] = '\0';
+ return EXTRACT_BASIC;
+ }
+ if (name[i] == '.')
+ {
+ parsed[i] = '\0';
+ *end = &name[i + 1];
+ return EXTRACT_STRUCT;
+ }
+ if (name[i] == '[')
+ {
+ parsed[i] = '\0';
+ i++;
+ if (name[i] >= '0' && name[i] <= '9')
+ {
+ *element = name[i] - '0';
+ for (i++; ; i++)
+ {
+ if (name[i] >= '0' && name[i] <= '9')
+ *element = *element * 10 + (name[i] - '0');
+ else
+ {
+ if (name[i] == ']')
+ {
+ i++;
+ if (name[i] == '.')
+ {
+ *end = &name[i + 1];
+ return EXTRACT_STRUCT_ARRAY;
+ }
+ *end = &name[i];
+ return EXTRACT_ARRAY;
+ }
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ return EXTRACT_ERROR;
+}
+
+static GLboolean validate_extracted (slang_export_data_quant *q, GLuint element, GLuint extr)
+{
+ switch (extr)
+ {
+ case EXTRACT_BASIC:
+ return GL_TRUE;
+ case EXTRACT_ARRAY:
+ return element < slang_export_data_quant_elements (q);
+ case EXTRACT_STRUCT:
+ return slang_export_data_quant_struct (q);
+ case EXTRACT_STRUCT_ARRAY:
+ return slang_export_data_quant_struct (q) && element < slang_export_data_quant_elements (q);
+ }
+ return GL_FALSE;
+}
+
+static GLuint calculate_offset (slang_export_data_quant *q, GLuint element)
+{
+ if (slang_export_data_quant_array (q))
+ return element * slang_export_data_quant_size (q);
+ return 0;
+}
+
+static GLboolean find_exported_data (slang_export_data_quant *q, const char *name,
+ slang_export_data_quant **quant, GLuint *offset, slang_atom_pool *atoms)
+{
+ char parsed[EXTRACT_MAXLEN];
+ GLuint result, element, i;
+ const char *end;
+ slang_atom atom;
+ const GLuint fields = slang_export_data_quant_fields (q);
+
+ result = extract_name (name, parsed, &element, &end);
+ if (result == EXTRACT_ERROR)
+ return GL_FALSE;
+
+ atom = slang_atom_pool_atom (atoms, parsed);
+ if (atom == SLANG_ATOM_NULL)
+ return GL_FALSE;
+
+ for (i = 0; i < fields; i++)
+ if (q->structure[i].name == atom)
+ {
+ if (!validate_extracted (&q->structure[i], element, result))
+ return GL_FALSE;
+ *offset += calculate_offset (&q->structure[i], element);
+ if (result == EXTRACT_BASIC || result == EXTRACT_ARRAY)
+ {
+ if (*end != '\0')
+ return GL_FALSE;
+ *quant = &q->structure[i];
+ return GL_TRUE;
+ }
+ return find_exported_data (&q->structure[i], end, quant, offset, atoms);
+ }
+ return GL_FALSE;
+}
+
+GLboolean _slang_find_exported_data (slang_export_data_table *table, const char *name,
+ slang_export_data_entry **entry, slang_export_data_quant **quant, GLuint *offset)
+{
+ char parsed[EXTRACT_MAXLEN];
+ GLuint result, element, i;
+ const char *end;
+ slang_atom atom;
+
+ result = extract_name (name, parsed, &element, &end);
+ if (result == EXTRACT_ERROR)
+ return GL_FALSE;
+
+ atom = slang_atom_pool_atom (table->atoms, parsed);
+ if (atom == SLANG_ATOM_NULL)
+ return GL_FALSE;
+
+ for (i = 0; i < table->count; i++)
+ if (table->entries[i].quant.name == atom)
+ {
+ if (!validate_extracted (&table->entries[i].quant, element, result))
+ return GL_FALSE;
+ *entry = &table->entries[i];
+ *offset = calculate_offset (&table->entries[i].quant, element);
+ if (result == EXTRACT_BASIC || result == EXTRACT_ARRAY)
+ {
+ if (*end != '\0')
+ return GL_FALSE;
+ *quant = &table->entries[i].quant;
+ return GL_TRUE;
+ }
+ return find_exported_data (&table->entries[i].quant, end, quant, offset, table->atoms);
+ }
+ return GL_FALSE;
+}
+
diff --git a/src/mesa/shader/slang/slang_export.h b/src/mesa/shader/slang/slang_export.h
new file mode 100644
index 00000000000..40ceac19e10
--- /dev/null
+++ b/src/mesa/shader/slang/slang_export.h
@@ -0,0 +1,183 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#if !defined SLANG_EXPORT_H
+#define SLANG_EXPORT_H
+
+#include "slang_utility.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Basic data quantity to transfer between application and assembly.
+ * The <size> is the actual size of the data quantity including padding, if any. It is
+ * used to calculate offsets from the beginning of the data.
+ * If the <array_len> is not 0, the data quantity is an array of <array_len> size.
+ * If the <structure> is not NULL, the data quantity is a struct. The <basic_type> is
+ * invalid and the <field_count> holds the size of the <structure> array.
+ * The <basic_type> values match those of <type> parameter for glGetActiveUniformARB.
+ */
+
+typedef struct slang_export_data_quant_
+{
+ slang_atom name;
+ GLuint size;
+ GLuint array_len;
+ struct slang_export_data_quant_ *structure;
+ union
+ {
+ GLenum basic_type;
+ GLuint field_count;
+ } u;
+} slang_export_data_quant;
+
+GLvoid slang_export_data_quant_ctr (slang_export_data_quant *);
+GLvoid slang_export_data_quant_dtr (slang_export_data_quant *);
+slang_export_data_quant *slang_export_data_quant_add_field (slang_export_data_quant *);
+
+/*
+ * Returns GL_FALSE if the quant is not an array.
+ */
+GLboolean slang_export_data_quant_array (slang_export_data_quant *);
+
+/*
+ * Returns GL_FALSE if the quant is not a structure.
+ */
+GLboolean slang_export_data_quant_struct (slang_export_data_quant *);
+
+/*
+ * Returns GL_TRUE if the quant is neither an array nor a structure.
+ */
+GLboolean slang_export_data_quant_simple (slang_export_data_quant *);
+
+/*
+ * Returns basic type of the quant. It must not be a structure.
+ */
+GLenum slang_export_data_quant_type (slang_export_data_quant *);
+
+/*
+ * Returns number of fields in the quant that is a structure.
+ */
+GLuint slang_export_data_quant_fields (slang_export_data_quant *);
+
+/*
+ * Return number of elements in the quant.
+ * For arrays, return the size of the array.
+ * Otherwise, return 1.
+ */
+GLuint slang_export_data_quant_elements (slang_export_data_quant *);
+
+/*
+ * Returns total number of components withing the quant element.
+ */
+GLuint slang_export_data_quant_components (slang_export_data_quant *);
+
+/*
+ * Returns size of the quant element.
+ */
+GLuint slang_export_data_quant_size (slang_export_data_quant *);
+
+/*
+ * Data access pattern. Specifies how data is accessed at what frequency.
+ */
+
+typedef enum
+{
+ slang_exp_uniform,
+ slang_exp_varying,
+ slang_exp_attribute
+} slang_export_data_access;
+
+/*
+ * Data export entry. Holds the data type information, access pattern and base address.
+ */
+
+typedef struct
+{
+ slang_export_data_quant quant;
+ slang_export_data_access access;
+ GLuint address;
+} slang_export_data_entry;
+
+GLvoid slang_export_data_entry_ctr (slang_export_data_entry *);
+GLvoid slang_export_data_entry_dtr (slang_export_data_entry *);
+
+/*
+ * Data export table.
+ */
+
+typedef struct
+{
+ slang_export_data_entry *entries;
+ GLuint count;
+ slang_atom_pool *atoms;
+} slang_export_data_table;
+
+GLvoid slang_export_data_table_ctr (slang_export_data_table *);
+GLvoid slang_export_data_table_dtr (slang_export_data_table *);
+slang_export_data_entry *slang_export_data_table_add (slang_export_data_table *);
+
+/*
+ * Code export entry. Contains label name and its entry point (label, address).
+ */
+
+typedef struct
+{
+ slang_atom name;
+ GLuint address;
+} slang_export_code_entry;
+
+/*
+ * Code export table.
+ */
+
+typedef struct
+{
+ slang_export_code_entry *entries;
+ GLuint count;
+ slang_atom_pool *atoms;
+} slang_export_code_table;
+
+GLvoid slang_export_code_table_ctr (slang_export_code_table *);
+GLvoid slang_export_code_table_dtr (slang_export_code_table *);
+slang_export_code_entry *slang_export_code_table_add (slang_export_code_table *);
+
+/*
+ * _slang_find_exported_data()
+ *
+ * Parses the name string and returns corresponding data entry, data quantity and offset.
+ * Returns GL_TRUE if the data is found, returns GL_FALSE otherwise.
+ */
+
+GLboolean _slang_find_exported_data (slang_export_data_table *, const char *,
+ slang_export_data_entry **, slang_export_data_quant **, GLuint *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_library_noise.c b/src/mesa/shader/slang/slang_library_noise.c
new file mode 100644
index 00000000000..b30bb30ce26
--- /dev/null
+++ b/src/mesa/shader/slang/slang_library_noise.c
@@ -0,0 +1,501 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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.
+ */
+
+/*
+ * SimplexNoise1234
+ * Copyright � 2003-2005, Stefan Gustavson
+ *
+ * Contact: [email protected]
+ */
+
+/** \file
+ \brief C implementation of Perlin Simplex Noise over 1,2,3, and 4 dimensions.
+ \author Stefan Gustavson ([email protected])
+*/
+
+/*
+ * This implementation is "Simplex Noise" as presented by
+ * Ken Perlin at a relatively obscure and not often cited course
+ * session "Real-Time Shading" at Siggraph 2001 (before real
+ * time shading actually took on), under the title "hardware noise".
+ * The 3D function is numerically equivalent to his Java reference
+ * code available in the PDF course notes, although I re-implemented
+ * it from scratch to get more readable code. The 1D, 2D and 4D cases
+ * were implemented from scratch by me from Ken Perlin's text.
+ *
+ * This file has no dependencies on any other file, not even its own
+ * header file. The header file is made for use by external code only.
+ */
+
+
+#include "imports.h"
+#include "slang_library_noise.h"
+
+#define FASTFLOOR(x) ( ((x)>0) ? ((int)x) : (((int)x)-1) )
+
+/*
+ * ---------------------------------------------------------------------
+ * Static data
+ */
+
+/*
+ * Permutation table. This is just a random jumble of all numbers 0-255,
+ * repeated twice to avoid wrapping the index at 255 for each lookup.
+ * This needs to be exactly the same for all instances on all platforms,
+ * so it's easiest to just keep it as static explicit data.
+ * This also removes the need for any initialisation of this class.
+ *
+ * Note that making this an int[] instead of a char[] might make the
+ * code run faster on platforms with a high penalty for unaligned single
+ * byte addressing. Intel x86 is generally single-byte-friendly, but
+ * some other CPUs are faster with 4-aligned reads.
+ * However, a char[] is smaller, which avoids cache trashing, and that
+ * is probably the most important aspect on most architectures.
+ * This array is accessed a *lot* by the noise functions.
+ * A vector-valued noise over 3D accesses it 96 times, and a
+ * float-valued 4D noise 64 times. We want this to fit in the cache!
+ */
+unsigned char perm[512] = {151,160,137,91,90,15,
+ 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+ 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+ 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+ 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+ 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+ 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+ 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+ 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+ 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+ 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+ 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+ 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
+ 151,160,137,91,90,15,
+ 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+ 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+ 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+ 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+ 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+ 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+ 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+ 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+ 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+ 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+ 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+ 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
+};
+
+/*
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * Helper functions to compute gradients-dot-residualvectors (1D to 4D)
+ * Note that these generate gradients of more than unit length. To make
+ * a close match with the value range of classic Perlin noise, the final
+ * noise values need to be rescaled to fit nicely within [-1,1].
+ * (The simplex noise functions as such also have different scaling.)
+ * Note also that these noise functions are the most practical and useful
+ * signed version of Perlin noise. To return values according to the
+ * RenderMan specification from the SL noise() and pnoise() functions,
+ * the noise values need to be scaled and offset to [0,1], like this:
+ * float SLnoise = (SimplexNoise1234::noise(x,y,z) + 1.0) * 0.5;
+ */
+
+static float grad1( int hash, float x ) {
+ int h = hash & 15;
+ float grad = 1.0f + (h & 7); /* Gradient value 1.0, 2.0, ..., 8.0 */
+ if (h&8) grad = -grad; /* Set a random sign for the gradient */
+ return ( grad * x ); /* Multiply the gradient with the distance */
+}
+
+static float grad2( int hash, float x, float y ) {
+ int h = hash & 7; /* Convert low 3 bits of hash code */
+ float u = h<4 ? x : y; /* into 8 simple gradient directions, */
+ float v = h<4 ? y : x; /* and compute the dot product with (x,y). */
+ return ((h&1)? -u : u) + ((h&2)? -2.0f*v : 2.0f*v);
+}
+
+static float grad3( int hash, float x, float y , float z ) {
+ int h = hash & 15; /* Convert low 4 bits of hash code into 12 simple */
+ float u = h<8 ? x : y; /* gradient directions, and compute dot product. */
+ float v = h<4 ? y : h==12||h==14 ? x : z; /* Fix repeats at h = 12 to 15 */
+ return ((h&1)? -u : u) + ((h&2)? -v : v);
+}
+
+static float grad4( int hash, float x, float y, float z, float t ) {
+ int h = hash & 31; /* Convert low 5 bits of hash code into 32 simple */
+ float u = h<24 ? x : y; /* gradient directions, and compute dot product. */
+ float v = h<16 ? y : z;
+ float w = h<8 ? z : t;
+ return ((h&1)? -u : u) + ((h&2)? -v : v) + ((h&4)? -w : w);
+}
+
+ /* A lookup table to traverse the simplex around a given point in 4D. */
+ /* Details can be found where this table is used, in the 4D noise method. */
+ /* TODO: This should not be required, backport it from Bill's GLSL code! */
+ static unsigned char simplex[64][4] = {
+ {0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0},
+ {0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0},
+ {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
+ {1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0},
+ {1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0},
+ {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
+ {2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0},
+ {2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0}};
+
+/* 1D simplex noise */
+GLfloat _slang_library_noise1 (GLfloat x)
+{
+ int i0 = FASTFLOOR(x);
+ int i1 = i0 + 1;
+ float x0 = x - i0;
+ float x1 = x0 - 1.0f;
+ float t1 = 1.0f - x1*x1;
+ float n0, n1;
+
+ float t0 = 1.0f - x0*x0;
+/* if(t0 < 0.0f) t0 = 0.0f; // this never happens for the 1D case */
+ t0 *= t0;
+ n0 = t0 * t0 * grad1(perm[i0 & 0xff], x0);
+
+/* if(t1 < 0.0f) t1 = 0.0f; // this never happens for the 1D case */
+ t1 *= t1;
+ n1 = t1 * t1 * grad1(perm[i1 & 0xff], x1);
+ /* The maximum value of this noise is 8*(3/4)^4 = 2.53125 */
+ /* A factor of 0.395 would scale to fit exactly within [-1,1], but */
+ /* we want to match PRMan's 1D noise, so we scale it down some more. */
+ return 0.25f * (n0 + n1);
+}
+
+/* 2D simplex noise */
+GLfloat _slang_library_noise2 (GLfloat x, GLfloat y)
+{
+#define F2 0.366025403f /* F2 = 0.5*(sqrt(3.0)-1.0) */
+#define G2 0.211324865f /* G2 = (3.0-Math.sqrt(3.0))/6.0 */
+
+ float n0, n1, n2; /* Noise contributions from the three corners */
+
+ /* Skew the input space to determine which simplex cell we're in */
+ float s = (x+y)*F2; /* Hairy factor for 2D */
+ float xs = x + s;
+ float ys = y + s;
+ int i = FASTFLOOR(xs);
+ int j = FASTFLOOR(ys);
+
+ float t = (float)(i+j)*G2;
+ float X0 = i-t; /* Unskew the cell origin back to (x,y) space */
+ float Y0 = j-t;
+ float x0 = x-X0; /* The x,y distances from the cell origin */
+ float y0 = y-Y0;
+
+ float x1, y1, x2, y2;
+ int ii, jj;
+ float t0, t1, t2;
+
+ /* For the 2D case, the simplex shape is an equilateral triangle. */
+ /* Determine which simplex we are in. */
+ int i1, j1; /* Offsets for second (middle) corner of simplex in (i,j) coords */
+ if(x0>y0) {i1=1; j1=0;} /* lower triangle, XY order: (0,0)->(1,0)->(1,1) */
+ else {i1=0; j1=1;} /* upper triangle, YX order: (0,0)->(0,1)->(1,1) */
+
+ /* A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and */
+ /* a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where */
+ /* c = (3-sqrt(3))/6 */
+
+ x1 = x0 - i1 + G2; /* Offsets for middle corner in (x,y) unskewed coords */
+ y1 = y0 - j1 + G2;
+ x2 = x0 - 1.0f + 2.0f * G2; /* Offsets for last corner in (x,y) unskewed coords */
+ y2 = y0 - 1.0f + 2.0f * G2;
+
+ /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */
+ ii = i % 256;
+ jj = j % 256;
+
+ /* Calculate the contribution from the three corners */
+ t0 = 0.5f - x0*x0-y0*y0;
+ if(t0 < 0.0f) n0 = 0.0f;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * grad2(perm[ii+perm[jj]], x0, y0);
+ }
+
+ t1 = 0.5f - x1*x1-y1*y1;
+ if(t1 < 0.0f) n1 = 0.0f;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * grad2(perm[ii+i1+perm[jj+j1]], x1, y1);
+ }
+
+ t2 = 0.5f - x2*x2-y2*y2;
+ if(t2 < 0.0f) n2 = 0.0f;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * grad2(perm[ii+1+perm[jj+1]], x2, y2);
+ }
+
+ /* Add contributions from each corner to get the final noise value. */
+ /* The result is scaled to return values in the interval [-1,1]. */
+ return 40.0f * (n0 + n1 + n2); /* TODO: The scale factor is preliminary! */
+}
+
+/* 3D simplex noise */
+GLfloat _slang_library_noise3 (GLfloat x, GLfloat y, GLfloat z)
+{
+/* Simple skewing factors for the 3D case */
+#define F3 0.333333333f
+#define G3 0.166666667f
+
+ float n0, n1, n2, n3; /* Noise contributions from the four corners */
+
+ /* Skew the input space to determine which simplex cell we're in */
+ float s = (x+y+z)*F3; /* Very nice and simple skew factor for 3D */
+ float xs = x+s;
+ float ys = y+s;
+ float zs = z+s;
+ int i = FASTFLOOR(xs);
+ int j = FASTFLOOR(ys);
+ int k = FASTFLOOR(zs);
+
+ float t = (float)(i+j+k)*G3;
+ float X0 = i-t; /* Unskew the cell origin back to (x,y,z) space */
+ float Y0 = j-t;
+ float Z0 = k-t;
+ float x0 = x-X0; /* The x,y,z distances from the cell origin */
+ float y0 = y-Y0;
+ float z0 = z-Z0;
+
+ float x1, y1, z1, x2, y2, z2, x3, y3, z3;
+ int ii, jj, kk;
+ float t0, t1, t2, t3;
+
+ /* For the 3D case, the simplex shape is a slightly irregular tetrahedron. */
+ /* Determine which simplex we are in. */
+ int i1, j1, k1; /* Offsets for second corner of simplex in (i,j,k) coords */
+ int i2, j2, k2; /* Offsets for third corner of simplex in (i,j,k) coords */
+
+/* This code would benefit from a backport from the GLSL version! */
+ if(x0>=y0) {
+ if(y0>=z0)
+ { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } /* X Y Z order */
+ else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } /* X Z Y order */
+ else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } /* Z X Y order */
+ }
+ else { /* x0<y0 */
+ if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } /* Z Y X order */
+ else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } /* Y Z X order */
+ else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } /* Y X Z order */
+ }
+
+ /* A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), */
+ /* a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and */
+ /* a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where */
+ /* c = 1/6. */
+
+ x1 = x0 - i1 + G3; /* Offsets for second corner in (x,y,z) coords */
+ y1 = y0 - j1 + G3;
+ z1 = z0 - k1 + G3;
+ x2 = x0 - i2 + 2.0f*G3; /* Offsets for third corner in (x,y,z) coords */
+ y2 = y0 - j2 + 2.0f*G3;
+ z2 = z0 - k2 + 2.0f*G3;
+ x3 = x0 - 1.0f + 3.0f*G3; /* Offsets for last corner in (x,y,z) coords */
+ y3 = y0 - 1.0f + 3.0f*G3;
+ z3 = z0 - 1.0f + 3.0f*G3;
+
+ /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */
+ ii = i % 256;
+ jj = j % 256;
+ kk = k % 256;
+
+ /* Calculate the contribution from the four corners */
+ t0 = 0.6f - x0*x0 - y0*y0 - z0*z0;
+ if(t0 < 0.0f) n0 = 0.0f;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * grad3(perm[ii+perm[jj+perm[kk]]], x0, y0, z0);
+ }
+
+ t1 = 0.6f - x1*x1 - y1*y1 - z1*z1;
+ if(t1 < 0.0f) n1 = 0.0f;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * grad3(perm[ii+i1+perm[jj+j1+perm[kk+k1]]], x1, y1, z1);
+ }
+
+ t2 = 0.6f - x2*x2 - y2*y2 - z2*z2;
+ if(t2 < 0.0f) n2 = 0.0f;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * grad3(perm[ii+i2+perm[jj+j2+perm[kk+k2]]], x2, y2, z2);
+ }
+
+ t3 = 0.6f - x3*x3 - y3*y3 - z3*z3;
+ if(t3<0.0f) n3 = 0.0f;
+ else {
+ t3 *= t3;
+ n3 = t3 * t3 * grad3(perm[ii+1+perm[jj+1+perm[kk+1]]], x3, y3, z3);
+ }
+
+ /* Add contributions from each corner to get the final noise value. */
+ /* The result is scaled to stay just inside [-1,1] */
+ return 32.0f * (n0 + n1 + n2 + n3); /* TODO: The scale factor is preliminary! */
+}
+
+/* 4D simplex noise */
+GLfloat _slang_library_noise4 (GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ /* The skewing and unskewing factors are hairy again for the 4D case */
+#define F4 0.309016994f /* F4 = (Math.sqrt(5.0)-1.0)/4.0 */
+#define G4 0.138196601f /* G4 = (5.0-Math.sqrt(5.0))/20.0 */
+
+ float n0, n1, n2, n3, n4; /* Noise contributions from the five corners */
+
+ /* Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in */
+ float s = (x + y + z + w) * F4; /* Factor for 4D skewing */
+ float xs = x + s;
+ float ys = y + s;
+ float zs = z + s;
+ float ws = w + s;
+ int i = FASTFLOOR(xs);
+ int j = FASTFLOOR(ys);
+ int k = FASTFLOOR(zs);
+ int l = FASTFLOOR(ws);
+
+ float t = (i + j + k + l) * G4; /* Factor for 4D unskewing */
+ float X0 = i - t; /* Unskew the cell origin back to (x,y,z,w) space */
+ float Y0 = j - t;
+ float Z0 = k - t;
+ float W0 = l - t;
+
+ float x0 = x - X0; /* The x,y,z,w distances from the cell origin */
+ float y0 = y - Y0;
+ float z0 = z - Z0;
+ float w0 = w - W0;
+
+ /* For the 4D case, the simplex is a 4D shape I won't even try to describe. */
+ /* To find out which of the 24 possible simplices we're in, we need to */
+ /* determine the magnitude ordering of x0, y0, z0 and w0. */
+ /* The method below is a good way of finding the ordering of x,y,z,w and */
+ /* then find the correct traversal order for the simplex we�re in. */
+ /* First, six pair-wise comparisons are performed between each possible pair */
+ /* of the four coordinates, and the results are used to add up binary bits */
+ /* for an integer index. */
+ int c1 = (x0 > y0) ? 32 : 0;
+ int c2 = (x0 > z0) ? 16 : 0;
+ int c3 = (y0 > z0) ? 8 : 0;
+ int c4 = (x0 > w0) ? 4 : 0;
+ int c5 = (y0 > w0) ? 2 : 0;
+ int c6 = (z0 > w0) ? 1 : 0;
+ int c = c1 + c2 + c3 + c4 + c5 + c6;
+
+ int i1, j1, k1, l1; /* The integer offsets for the second simplex corner */
+ int i2, j2, k2, l2; /* The integer offsets for the third simplex corner */
+ int i3, j3, k3, l3; /* The integer offsets for the fourth simplex corner */
+
+ float x1, y1, z1, w1, x2, y2, z2, w2, x3, y3, z3, w3, x4, y4, z4, w4;
+ int ii, jj, kk, ll;
+ float t0, t1, t2, t3, t4;
+
+ /* simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. */
+ /* Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w */
+ /* impossible. Only the 24 indices which have non-zero entries make any sense. */
+ /* We use a thresholding to set the coordinates in turn from the largest magnitude. */
+ /* The number 3 in the "simplex" array is at the position of the largest coordinate. */
+ i1 = simplex[c][0]>=3 ? 1 : 0;
+ j1 = simplex[c][1]>=3 ? 1 : 0;
+ k1 = simplex[c][2]>=3 ? 1 : 0;
+ l1 = simplex[c][3]>=3 ? 1 : 0;
+ /* The number 2 in the "simplex" array is at the second largest coordinate. */
+ i2 = simplex[c][0]>=2 ? 1 : 0;
+ j2 = simplex[c][1]>=2 ? 1 : 0;
+ k2 = simplex[c][2]>=2 ? 1 : 0;
+ l2 = simplex[c][3]>=2 ? 1 : 0;
+ /* The number 1 in the "simplex" array is at the second smallest coordinate. */
+ i3 = simplex[c][0]>=1 ? 1 : 0;
+ j3 = simplex[c][1]>=1 ? 1 : 0;
+ k3 = simplex[c][2]>=1 ? 1 : 0;
+ l3 = simplex[c][3]>=1 ? 1 : 0;
+ /* The fifth corner has all coordinate offsets = 1, so no need to look that up. */
+
+ x1 = x0 - i1 + G4; /* Offsets for second corner in (x,y,z,w) coords */
+ y1 = y0 - j1 + G4;
+ z1 = z0 - k1 + G4;
+ w1 = w0 - l1 + G4;
+ x2 = x0 - i2 + 2.0f*G4; /* Offsets for third corner in (x,y,z,w) coords */
+ y2 = y0 - j2 + 2.0f*G4;
+ z2 = z0 - k2 + 2.0f*G4;
+ w2 = w0 - l2 + 2.0f*G4;
+ x3 = x0 - i3 + 3.0f*G4; /* Offsets for fourth corner in (x,y,z,w) coords */
+ y3 = y0 - j3 + 3.0f*G4;
+ z3 = z0 - k3 + 3.0f*G4;
+ w3 = w0 - l3 + 3.0f*G4;
+ x4 = x0 - 1.0f + 4.0f*G4; /* Offsets for last corner in (x,y,z,w) coords */
+ y4 = y0 - 1.0f + 4.0f*G4;
+ z4 = z0 - 1.0f + 4.0f*G4;
+ w4 = w0 - 1.0f + 4.0f*G4;
+
+ /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */
+ ii = i % 256;
+ jj = j % 256;
+ kk = k % 256;
+ ll = l % 256;
+
+ /* Calculate the contribution from the five corners */
+ t0 = 0.6f - x0*x0 - y0*y0 - z0*z0 - w0*w0;
+ if(t0 < 0.0f) n0 = 0.0f;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * grad4(perm[ii+perm[jj+perm[kk+perm[ll]]]], x0, y0, z0, w0);
+ }
+
+ t1 = 0.6f - x1*x1 - y1*y1 - z1*z1 - w1*w1;
+ if(t1 < 0.0f) n1 = 0.0f;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * grad4(perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]], x1, y1, z1, w1);
+ }
+
+ t2 = 0.6f - x2*x2 - y2*y2 - z2*z2 - w2*w2;
+ if(t2 < 0.0f) n2 = 0.0f;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * grad4(perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]], x2, y2, z2, w2);
+ }
+
+ t3 = 0.6f - x3*x3 - y3*y3 - z3*z3 - w3*w3;
+ if(t3 < 0.0f) n3 = 0.0f;
+ else {
+ t3 *= t3;
+ n3 = t3 * t3 * grad4(perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]], x3, y3, z3, w3);
+ }
+
+ t4 = 0.6f - x4*x4 - y4*y4 - z4*z4 - w4*w4;
+ if(t4 < 0.0f) n4 = 0.0f;
+ else {
+ t4 *= t4;
+ n4 = t4 * t4 * grad4(perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]], x4, y4, z4, w4);
+ }
+
+ /* Sum up and scale the result to cover the range [-1,1] */
+ return 27.0f * (n0 + n1 + n2 + n3 + n4); /* TODO: The scale factor is preliminary! */
+}
+
diff --git a/src/mesa/shader/slang/slang_library_noise.h b/src/mesa/shader/slang/slang_library_noise.h
new file mode 100644
index 00000000000..da7367c1ce1
--- /dev/null
+++ b/src/mesa/shader/slang/slang_library_noise.h
@@ -0,0 +1,42 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#if !defined SLANG_LIBRARY_NOISE_H
+#define SLANG_LIBRARY_NOISE_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+GLfloat _slang_library_noise1 (GLfloat);
+GLfloat _slang_library_noise2 (GLfloat, GLfloat);
+GLfloat _slang_library_noise3 (GLfloat, GLfloat, GLfloat);
+GLfloat _slang_library_noise4 (GLfloat, GLfloat, GLfloat, GLfloat);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_library_texsample.c b/src/mesa/shader/slang/slang_library_texsample.c
new file mode 100644
index 00000000000..7d56880400f
--- /dev/null
+++ b/src/mesa/shader/slang/slang_library_texsample.c
@@ -0,0 +1,172 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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 slang_library_texsample.c
+ * built-in library functions for texture and shadow sampling
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "context.h"
+#include "colormac.h"
+#include "swrast/s_context.h"
+#include "slang_library_texsample.h"
+
+GLvoid _slang_library_tex1d (GLfloat bias, GLfloat s, GLfloat sampler, GLfloat *color)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLuint unit = (GLuint) sampler;
+ GLfloat texcoord[4];
+ GLfloat lambda = bias;
+ GLchan rgba[4];
+
+ texcoord[0] = s;
+ texcoord[1] = 0.0f;
+ texcoord[2] = 0.0f;
+ texcoord[3] = 1.0f;
+
+ swrast->TextureSample[unit] (ctx, ctx->Texture.Unit[unit]._Current, 1,
+ (const GLfloat (*)[4]) texcoord, &lambda, &rgba);
+ color[0] = CHAN_TO_FLOAT(rgba[0]);
+ color[1] = CHAN_TO_FLOAT(rgba[1]);
+ color[2] = CHAN_TO_FLOAT(rgba[2]);
+ color[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+GLvoid _slang_library_tex2d (GLfloat bias, GLfloat s, GLfloat t, GLfloat sampler, GLfloat *color)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLuint unit = (GLuint) sampler;
+ GLfloat texcoord[4];
+ GLfloat lambda = bias;
+ GLchan rgba[4];
+
+ texcoord[0] = s;
+ texcoord[1] = t;
+ texcoord[2] = 0.0f;
+ texcoord[3] = 1.0f;
+
+ swrast->TextureSample[unit] (ctx, ctx->Texture.Unit[unit]._Current, 1,
+ (const GLfloat (*)[4]) texcoord, &lambda, &rgba);
+ color[0] = CHAN_TO_FLOAT(rgba[0]);
+ color[1] = CHAN_TO_FLOAT(rgba[1]);
+ color[2] = CHAN_TO_FLOAT(rgba[2]);
+ color[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+GLvoid _slang_library_tex3d (GLfloat bias, GLfloat s, GLfloat t, GLfloat r, GLfloat sampler,
+ GLfloat *color)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLuint unit = (GLuint) sampler;
+ GLfloat texcoord[4];
+ GLfloat lambda = bias;
+ GLchan rgba[4];
+
+ texcoord[0] = s;
+ texcoord[1] = t;
+ texcoord[2] = r;
+ texcoord[3] = 1.0f;
+
+ swrast->TextureSample[unit] (ctx, ctx->Texture.Unit[unit]._Current, 1,
+ (const GLfloat (*)[4]) texcoord, &lambda, &rgba);
+ color[0] = CHAN_TO_FLOAT(rgba[0]);
+ color[1] = CHAN_TO_FLOAT(rgba[1]);
+ color[2] = CHAN_TO_FLOAT(rgba[2]);
+ color[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+GLvoid _slang_library_texcube (GLfloat bias, GLfloat s, GLfloat t, GLfloat r, GLfloat sampler,
+ GLfloat *color)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLuint unit = (GLuint) sampler;
+ GLfloat texcoord[4];
+ GLfloat lambda = bias;
+ GLchan rgba[4];
+
+ texcoord[0] = s;
+ texcoord[1] = t;
+ texcoord[2] = r;
+ texcoord[3] = 1.0f;
+
+ swrast->TextureSample[unit] (ctx, ctx->Texture.Unit[unit]._Current, 1,
+ (const GLfloat (*)[4]) texcoord, &lambda, &rgba);
+ color[0] = CHAN_TO_FLOAT(rgba[0]);
+ color[1] = CHAN_TO_FLOAT(rgba[1]);
+ color[2] = CHAN_TO_FLOAT(rgba[2]);
+ color[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+GLvoid _slang_library_shad1d (GLfloat bias, GLfloat s, GLfloat t, GLfloat r, GLfloat sampler,
+ GLfloat *color)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLuint unit = (GLuint) sampler;
+ GLfloat texcoord[4];
+ GLfloat lambda = bias;
+ GLchan rgba[4];
+
+ texcoord[0] = s;
+ texcoord[1] = t;
+ texcoord[2] = r;
+ texcoord[3] = 1.0f;
+
+ swrast->TextureSample[unit] (ctx, ctx->Texture.Unit[unit]._Current, 1,
+ (const GLfloat (*)[4]) texcoord, &lambda, &rgba);
+ color[0] = CHAN_TO_FLOAT(rgba[0]);
+ color[1] = CHAN_TO_FLOAT(rgba[1]);
+ color[2] = CHAN_TO_FLOAT(rgba[2]);
+ color[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+GLvoid _slang_library_shad2d (GLfloat bias, GLfloat s, GLfloat t, GLfloat r, GLfloat sampler,
+ GLfloat *color)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLuint unit = (GLuint) sampler;
+ GLfloat texcoord[4];
+ GLfloat lambda = bias;
+ GLchan rgba[4];
+
+ texcoord[0] = s;
+ texcoord[1] = t;
+ texcoord[2] = r;
+ texcoord[3] = 1.0f;
+
+ swrast->TextureSample[unit] (ctx, ctx->Texture.Unit[unit]._Current, 1,
+ (const GLfloat (*)[4]) texcoord, &lambda, &rgba);
+ color[0] = CHAN_TO_FLOAT(rgba[0]);
+ color[1] = CHAN_TO_FLOAT(rgba[1]);
+ color[2] = CHAN_TO_FLOAT(rgba[2]);
+ color[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
diff --git a/src/mesa/shader/slang/slang_library_texsample.h b/src/mesa/shader/slang/slang_library_texsample.h
new file mode 100644
index 00000000000..f74738ffa1a
--- /dev/null
+++ b/src/mesa/shader/slang/slang_library_texsample.h
@@ -0,0 +1,44 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#if !defined SLANG_LIBRARY_TEXSAMPLE_H
+#define SLANG_LIBRARY_TEXSAMPLE_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+GLvoid _slang_library_tex1d (GLfloat, GLfloat, GLfloat, GLfloat *);
+GLvoid _slang_library_tex2d (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat *);
+GLvoid _slang_library_tex3d (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat *);
+GLvoid _slang_library_texcube (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat *);
+GLvoid _slang_library_shad1d (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat *);
+GLvoid _slang_library_shad2d (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c
new file mode 100644
index 00000000000..66202edf8d0
--- /dev/null
+++ b/src/mesa/shader/slang/slang_link.c
@@ -0,0 +1,805 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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 slang_link.c
+ * slang linker
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_link.h"
+#include "slang_analyse.h"
+
+static GLboolean entry_has_gl_prefix (slang_atom name, slang_atom_pool *atoms)
+{
+ const char *str = slang_atom_pool_id (atoms, name);
+ return str[0] == 'g' && str[1] == 'l' && str[2] == '_';
+}
+
+/*
+ * slang_active_variables
+ */
+
+static GLvoid slang_active_variables_ctr (slang_active_variables *self)
+{
+ self->table = NULL;
+ self->count = 0;
+}
+
+static GLvoid slang_active_variables_dtr (slang_active_variables *self)
+{
+ GLuint i;
+
+ for (i = 0; i < self->count; i++)
+ slang_alloc_free (self->table[i].name);
+ slang_alloc_free (self->table);
+}
+
+static GLboolean add_simple_variable (slang_active_variables *self, slang_export_data_quant *q,
+ const char *name)
+{
+ const GLuint n = self->count;
+
+ self->table = (slang_active_variable *) slang_alloc_realloc (self->table,
+ n * sizeof (slang_active_variable), (n + 1) * sizeof (slang_active_variable));
+ if (self->table == NULL)
+ return GL_FALSE;
+
+ self->table[n].quant = q;
+ self->table[n].name = slang_string_duplicate (name);
+ if (self->table[n].name == NULL)
+ return GL_FALSE;
+ self->count++;
+
+ return GL_TRUE;
+}
+
+static GLboolean add_complex_variable (slang_active_variables *self, slang_export_data_quant *q,
+ char *name, slang_atom_pool *atoms)
+{
+ slang_string_concat (name, slang_atom_pool_id (atoms, q->name));
+ if (slang_export_data_quant_array (q))
+ slang_string_concat (name, "[0]");
+
+ if (slang_export_data_quant_struct (q))
+ {
+ GLuint dot_pos, i;
+ const GLuint fields = slang_export_data_quant_fields (q);
+
+ slang_string_concat (name, ".");
+ dot_pos = slang_string_length (name);
+
+ for (i = 0; i < fields; i++)
+ {
+ if (!add_complex_variable (self, &q->structure[i], name, atoms))
+ return GL_FALSE;
+
+ name[dot_pos] = '\0';
+ }
+
+ return GL_TRUE;
+ }
+
+ return add_simple_variable (self, q, name);
+}
+
+static GLboolean gather_active_variables (slang_active_variables *self,
+ slang_export_data_table *tbl, slang_export_data_access access)
+{
+ GLuint i;
+
+ for (i = 0; i < tbl->count; i++)
+ if (tbl->entries[i].access == access)
+ {
+ char name[1024] = "";
+
+ if (!add_complex_variable (self, &tbl->entries[i].quant, name, tbl->atoms))
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+/*
+ * slang_attrib_overrides
+ */
+
+static GLvoid slang_attrib_overrides_ctr (slang_attrib_overrides *self)
+{
+ self->table = NULL;
+ self->count = 0;
+}
+
+static GLvoid slang_attrib_overrides_dtr (slang_attrib_overrides *self)
+{
+ GLuint i;
+
+ for (i = 0; i < self->count; i++)
+ slang_alloc_free (self->table[i].name);
+ slang_alloc_free (self->table);
+}
+
+GLboolean slang_attrib_overrides_add (slang_attrib_overrides *self, GLuint index, const GLchar *name)
+{
+ const GLuint n = self->count;
+ GLuint i;
+
+ for (i = 0; i < n; i++)
+ if (slang_string_compare (name, self->table[i].name) == 0)
+ {
+ self->table[i].index = index;
+ return GL_TRUE;
+ }
+
+ self->table = (slang_attrib_override *) slang_alloc_realloc (self->table,
+ n * sizeof (slang_attrib_override), (n + 1) * sizeof (slang_attrib_override));
+ if (self->table == NULL)
+ return GL_FALSE;
+
+ self->table[n].index = index;
+ self->table[n].name = slang_string_duplicate (name);
+ if (self->table[n].name == NULL)
+ return GL_FALSE;
+ self->count++;
+
+ return GL_TRUE;
+}
+
+static GLuint lookup_attrib_override (slang_attrib_overrides *self, const GLchar *name)
+{
+ GLuint i;
+
+ for (i = 0; i < self->count; i++)
+ if (slang_string_compare (name, self->table[i].name) == 0)
+ return self->table[i].index;
+ return MAX_VERTEX_ATTRIBS;
+}
+
+/*
+ * slang_uniform_bindings
+ */
+
+static GLvoid slang_uniform_bindings_ctr (slang_uniform_bindings *self)
+{
+ self->table = NULL;
+ self->count = 0;
+}
+
+static GLvoid slang_uniform_bindings_dtr (slang_uniform_bindings *self)
+{
+ GLuint i;
+
+ for (i = 0; i < self->count; i++)
+ slang_alloc_free (self->table[i].name);
+ slang_alloc_free (self->table);
+}
+
+static GLboolean add_simple_uniform_binding (slang_uniform_bindings *self,
+ slang_export_data_quant *q, const char *name, GLuint index, GLuint addr)
+{
+ const GLuint n = self->count;
+ GLuint i;
+
+ for (i = 0; i < n; i++)
+ if (slang_string_compare (self->table[i].name, name) == 0)
+ {
+ self->table[i].address[index] = addr;
+ return GL_TRUE;
+ }
+
+ self->table = (slang_uniform_binding *) slang_alloc_realloc (self->table,
+ n * sizeof (slang_uniform_binding), (n + 1) * sizeof (slang_uniform_binding));
+ if (self->table == NULL)
+ return GL_FALSE;
+
+ self->table[n].quant = q;
+ self->table[n].name = slang_string_duplicate (name);
+ if (self->table[n].name == NULL)
+ return GL_FALSE;
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ self->table[n].address[i] = ~0;
+ self->table[n].address[index] = addr;
+ self->count++;
+
+ return GL_TRUE;
+}
+
+static GLboolean add_complex_uniform_binding (slang_uniform_bindings *self,
+ slang_export_data_quant *q, char *name, slang_atom_pool *atoms, GLuint index, GLuint addr)
+{
+ GLuint count, i;
+
+ slang_string_concat (name, slang_atom_pool_id (atoms, q->name));
+ count = slang_export_data_quant_elements (q);
+ for (i = 0; i < count; i++)
+ {
+ GLuint bracket_pos;
+
+ bracket_pos = slang_string_length (name);
+ if (slang_export_data_quant_array (q))
+ _mesa_sprintf (name + slang_string_length (name), "[%d]", i);
+
+ if (slang_export_data_quant_struct (q))
+ {
+ GLuint dot_pos, i;
+ const GLuint fields = slang_export_data_quant_fields (q);
+
+ slang_string_concat (name, ".");
+ dot_pos = slang_string_length (name);
+
+ for (i = 0; i < fields; i++)
+ {
+ if (!add_complex_uniform_binding (self, &q->structure[i], name, atoms, index, addr))
+ return GL_FALSE;
+
+ name[dot_pos] = '\0';
+ addr += slang_export_data_quant_size (&q->structure[i]);
+ }
+ }
+ else
+ {
+ if (!add_simple_uniform_binding (self, q, name, index, addr))
+ return GL_FALSE;
+
+ addr += slang_export_data_quant_size (q);
+ }
+
+ name[bracket_pos] = '\0';
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean gather_uniform_bindings (slang_uniform_bindings *self,
+ slang_export_data_table *tbl, GLuint index)
+{
+ GLuint i;
+
+ for (i = 0; i < tbl->count; i++)
+ if (tbl->entries[i].access == slang_exp_uniform)
+ {
+ char name[1024] = "";
+
+ if (!add_complex_uniform_binding (self, &tbl->entries[i].quant, name, tbl->atoms, index,
+ tbl->entries[i].address))
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+/*
+ * slang_attrib_bindings
+ */
+
+static GLvoid slang_attrib_bindings_ctr (slang_attrib_bindings *self)
+{
+ GLuint i;
+
+ self->binding_count = 0;
+ for (i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ self->slots[i].addr = ~0;
+}
+
+static GLvoid slang_attrib_bindings_dtr (slang_attrib_bindings *self)
+{
+ GLuint i;
+
+ for (i = 0; i < self->binding_count; i++)
+ slang_alloc_free (self->bindings[i].name);
+}
+
+/*
+ * NOTE: If conventional vertex attribute gl_Vertex is used, application cannot use
+ * vertex attrib index 0 for binding override. Currently this is not checked.
+ * Although attrib index 0 is not used when not explicitly asked.
+ */
+
+static GLuint can_allocate_attrib_slots (slang_attrib_bindings *self, GLuint index, GLuint count)
+{
+ GLuint i;
+
+ for (i = 0; i < count; i++)
+ if (self->slots[index + i].addr != ~0)
+ break;
+ return i;
+}
+
+static GLuint allocate_attrib_slots (slang_attrib_bindings *self, GLuint count)
+{
+ GLuint i;
+
+ for (i = 1; i <= MAX_VERTEX_ATTRIBS - count; i++)
+ {
+ GLuint size;
+
+ size = can_allocate_attrib_slots (self, i, count);
+ if (size == count)
+ return i;
+
+ /* speed-up the search a bit */
+ i += size;
+ }
+ return MAX_VERTEX_ATTRIBS;
+}
+
+static GLboolean
+add_attrib_binding (slang_attrib_bindings *self, slang_export_data_quant *q, const char *name,
+ GLuint addr, GLuint index_override)
+{
+ const GLuint n = self->binding_count;
+ GLuint slot_span, slot_fill, slot_index;
+ GLuint i;
+
+ assert (slang_export_data_quant_simple (q));
+
+ switch (slang_export_data_quant_type (q))
+ {
+ case GL_FLOAT:
+ slot_span = 1;
+ slot_fill = 1;
+ break;
+ case GL_FLOAT_VEC2:
+ slot_span = 1;
+ slot_fill = 2;
+ break;
+ case GL_FLOAT_VEC3:
+ slot_span = 1;
+ slot_fill = 3;
+ break;
+ case GL_FLOAT_VEC4:
+ slot_span = 1;
+ slot_fill = 4;
+ break;
+ case GL_FLOAT_MAT2:
+ slot_span = 2;
+ slot_fill = 2;
+ break;
+ case GL_FLOAT_MAT3:
+ slot_span = 3;
+ slot_fill = 3;
+ break;
+ case GL_FLOAT_MAT4:
+ slot_span = 4;
+ slot_fill = 4;
+ break;
+ default:
+ assert (0);
+ }
+
+ if (index_override == MAX_VERTEX_ATTRIBS)
+ slot_index = allocate_attrib_slots (self, slot_span);
+ else if (can_allocate_attrib_slots (self, index_override, slot_span) == slot_span)
+ slot_index = index_override;
+ else
+ slot_index = MAX_VERTEX_ATTRIBS;
+
+ if (slot_index == MAX_VERTEX_ATTRIBS)
+ {
+ /* TODO: info log: error: MAX_VERTEX_ATTRIBS exceeded */
+ return GL_FALSE;
+ }
+
+ self->bindings[n].quant = q;
+ self->bindings[n].name = slang_string_duplicate (name);
+ if (self->bindings[n].name == NULL)
+ return GL_FALSE;
+ self->bindings[n].first_slot_index = slot_index;
+ self->binding_count++;
+
+ for (i = 0; i < slot_span; i++) {
+ slang_attrib_slot *slot = &self->slots[self->bindings[n].first_slot_index + i];
+ slot->addr = addr + i * slot_fill * 4;
+ slot->fill = slot_fill;
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean gather_attrib_bindings (slang_attrib_bindings *self, slang_export_data_table *tbl,
+ slang_attrib_overrides *ovr)
+{
+ GLuint i;
+
+ /* First pass. Gather attribs that have overriden index slots. */
+ for (i = 0; i < tbl->count; i++)
+ if (tbl->entries[i].access == slang_exp_attribute &&
+ !entry_has_gl_prefix (tbl->entries[i].quant.name, tbl->atoms))
+ {
+ slang_export_data_quant *quant = &tbl->entries[i].quant;
+ const GLchar *id = slang_atom_pool_id (tbl->atoms, quant->name);
+ GLuint index = lookup_attrib_override (ovr, id);
+
+ if (index != MAX_VERTEX_ATTRIBS)
+ {
+ if (!add_attrib_binding (self, quant, id, tbl->entries[i].address, index))
+ return GL_FALSE;
+ }
+ }
+
+ /* Second pass. Gather attribs that have *NOT* overriden index slots. */
+ for (i = 0; i < tbl->count; i++)
+ if (tbl->entries[i].access == slang_exp_attribute &&
+ !entry_has_gl_prefix (tbl->entries[i].quant.name, tbl->atoms))
+ {
+ slang_export_data_quant *quant = &tbl->entries[i].quant;
+ const GLchar *id = slang_atom_pool_id (tbl->atoms, quant->name);
+ GLuint index = lookup_attrib_override (ovr, id);
+
+ if (index == MAX_VERTEX_ATTRIBS)
+ {
+ if (!add_attrib_binding (self, quant, id, tbl->entries[i].address, index))
+ return GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+/*
+ * slang_varying_bindings
+ */
+
+static GLvoid slang_varying_bindings_ctr (slang_varying_bindings *self)
+{
+ self->binding_count = 0;
+ self->slot_count = 0;
+}
+
+static GLvoid slang_varying_bindings_dtr (slang_varying_bindings *self)
+{
+ GLuint i;
+
+ for (i = 0; i < self->binding_count; i++)
+ slang_alloc_free (self->bindings[i].name);
+}
+
+static GLvoid update_varying_slots (slang_varying_slot *slots, GLuint count, GLboolean is_vert,
+ GLuint addr, GLuint do_offset)
+{
+ GLuint i;
+
+ for (i = 0; i < count; i++)
+ *(is_vert ? &slots[i].vert_addr : &slots[i].frag_addr) = addr + i * 4 * do_offset;
+}
+
+static GLboolean add_varying_binding (slang_varying_bindings *self,
+ slang_export_data_quant *q, const char *name, GLboolean is_vert, GLuint addr)
+{
+ const GLuint n = self->binding_count;
+ const GLuint slot_span =
+ slang_export_data_quant_components (q) * slang_export_data_quant_elements (q);
+ GLuint i;
+
+ for (i = 0; i < n; i++)
+ if (slang_string_compare (self->bindings[i].name, name) == 0)
+ {
+ /* TODO: data quantities must match, or else link fails */
+ update_varying_slots (&self->slots[self->bindings[i].first_slot_index], slot_span,
+ is_vert, addr, 1);
+ return GL_TRUE;
+ }
+
+ if (self->slot_count + slot_span > MAX_VARYING_FLOATS)
+ {
+ /* TODO: info log: error: MAX_VARYING_FLOATS exceeded */
+ return GL_FALSE;
+ }
+
+ self->bindings[n].quant = q;
+ self->bindings[n].name = slang_string_duplicate (name);
+ if (self->bindings[n].name == NULL)
+ return GL_FALSE;
+ self->bindings[n].first_slot_index = self->slot_count;
+ self->binding_count++;
+
+ update_varying_slots (&self->slots[self->bindings[n].first_slot_index], slot_span, is_vert,
+ addr, 1);
+ update_varying_slots (&self->slots[self->bindings[n].first_slot_index], slot_span, !is_vert,
+ ~0, 0);
+ self->slot_count += slot_span;
+
+ return GL_TRUE;
+}
+
+static GLboolean gather_varying_bindings (slang_varying_bindings *self,
+ slang_export_data_table *tbl, GLboolean is_vert)
+{
+ GLuint i;
+
+ for (i = 0; i < tbl->count; i++)
+ if (tbl->entries[i].access == slang_exp_varying &&
+ !entry_has_gl_prefix (tbl->entries[i].quant.name, tbl->atoms))
+ {
+ if (!add_varying_binding (self, &tbl->entries[i].quant, slang_atom_pool_id (tbl->atoms,
+ tbl->entries[i].quant.name), is_vert, tbl->entries[i].address))
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+/*
+ * slang_texture_bindings
+ */
+
+GLvoid slang_texture_usages_ctr (slang_texture_usages *self)
+{
+ self->table = NULL;
+ self->count = 0;
+}
+
+GLvoid slang_texture_usages_dtr (slang_texture_usages *self)
+{
+ slang_alloc_free (self->table);
+}
+
+/*
+ * slang_program
+ */
+
+GLvoid slang_program_ctr (slang_program *self)
+{
+ GLuint i;
+
+ slang_active_variables_ctr (&self->active_uniforms);
+ slang_active_variables_ctr (&self->active_attribs);
+ slang_attrib_overrides_ctr (&self->attrib_overrides);
+ slang_uniform_bindings_ctr (&self->uniforms);
+ slang_attrib_bindings_ctr (&self->attribs);
+ slang_varying_bindings_ctr (&self->varyings);
+ slang_texture_usages_ctr (&self->texture_usage);
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ {
+ GLuint j;
+
+ for (j = 0; j < SLANG_COMMON_FIXED_MAX; j++)
+ self->common_fixed_entries[i][j] = ~0;
+ for (j = 0; j < SLANG_COMMON_CODE_MAX; j++)
+ self->code[i][j] = ~0;
+ self->machines[i] = NULL;
+ self->assemblies[i] = NULL;
+ }
+ for (i = 0; i < SLANG_VERTEX_FIXED_MAX; i++)
+ self->vertex_fixed_entries[i] = ~0;
+ for (i = 0; i < SLANG_FRAGMENT_FIXED_MAX; i++)
+ self->fragment_fixed_entries[i] = ~0;
+}
+
+GLvoid slang_program_dtr (slang_program *self)
+{
+ slang_active_variables_dtr (&self->active_uniforms);
+ slang_active_variables_dtr (&self->active_attribs);
+ slang_attrib_overrides_dtr (&self->attrib_overrides);
+ slang_uniform_bindings_dtr (&self->uniforms);
+ slang_attrib_bindings_dtr (&self->attribs);
+ slang_varying_bindings_dtr (&self->varyings);
+ slang_texture_usages_dtr (&self->texture_usage);
+}
+
+GLvoid slang_program_rst (slang_program *self)
+{
+ GLuint i;
+
+ slang_active_variables_dtr (&self->active_uniforms);
+ slang_active_variables_dtr (&self->active_attribs);
+ slang_uniform_bindings_dtr (&self->uniforms);
+ slang_attrib_bindings_dtr (&self->attribs);
+ slang_varying_bindings_dtr (&self->varyings);
+ slang_texture_usages_dtr (&self->texture_usage);
+
+ slang_active_variables_ctr (&self->active_uniforms);
+ slang_active_variables_ctr (&self->active_attribs);
+ slang_uniform_bindings_ctr (&self->uniforms);
+ slang_attrib_bindings_ctr (&self->attribs);
+ slang_varying_bindings_ctr (&self->varyings);
+ slang_texture_usages_ctr (&self->texture_usage);
+ for (i = 0; i < SLANG_SHADER_MAX; i++)
+ {
+ GLuint j;
+
+ for (j = 0; j < SLANG_COMMON_FIXED_MAX; j++)
+ self->common_fixed_entries[i][j] = ~0;
+ for (j = 0; j < SLANG_COMMON_CODE_MAX; j++)
+ self->code[i][j] = ~0;
+ }
+ for (i = 0; i < SLANG_VERTEX_FIXED_MAX; i++)
+ self->vertex_fixed_entries[i] = ~0;
+ for (i = 0; i < SLANG_FRAGMENT_FIXED_MAX; i++)
+ self->fragment_fixed_entries[i] = ~0;
+}
+
+/*
+ * _slang_link()
+ */
+
+static GLuint gd (slang_export_data_table *tbl, const char *name)
+{
+ slang_atom atom;
+ GLuint i;
+
+ atom = slang_atom_pool_atom (tbl->atoms, name);
+ if (atom == SLANG_ATOM_NULL)
+ return ~0;
+
+ for (i = 0; i < tbl->count; i++)
+ if (atom == tbl->entries[i].quant.name)
+ return tbl->entries[i].address;
+ return ~0;
+}
+
+static GLvoid resolve_common_fixed (GLuint e[], slang_export_data_table *tbl)
+{
+ e[SLANG_COMMON_FIXED_MODELVIEWMATRIX] = gd (tbl, "gl_ModelViewMatrix");
+ e[SLANG_COMMON_FIXED_PROJECTIONMATRIX] = gd (tbl, "gl_ProjectionMatrix");
+ e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIX] = gd (tbl, "gl_ModelViewProjectionMatrix");
+ e[SLANG_COMMON_FIXED_TEXTUREMATRIX] = gd (tbl, "gl_TextureMatrix");
+ e[SLANG_COMMON_FIXED_NORMALMATRIX] = gd (tbl, "gl_NormalMatrix");
+ e[SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSE] = gd (tbl, "gl_ModelViewMatrixInverse");
+ e[SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSE] = gd (tbl, "gl_ProjectionMatrixInverse");
+ e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSE] =
+ gd (tbl, "gl_ModelViewProjectionMatrixInverse");
+ e[SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSE] = gd (tbl, "gl_TextureMatrixInverse");
+ e[SLANG_COMMON_FIXED_MODELVIEWMATRIXTRANSPOSE] = gd (tbl, "gl_ModelViewMatrixTranspose");
+ e[SLANG_COMMON_FIXED_PROJECTIONMATRIXTRANSPOSE] = gd (tbl, "gl_ProjectionMatrixTranspose");
+ e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXTRANSPOSE] =
+ gd (tbl, "gl_ModelViewProjectionMatrixTranspose");
+ e[SLANG_COMMON_FIXED_TEXTUREMATRIXTRANSPOSE] = gd (tbl, "gl_TextureMatrixTranspose");
+ e[SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSETRANSPOSE] =
+ gd (tbl, "gl_ModelViewMatrixInverseTranspose");
+ e[SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSETRANSPOSE] =
+ gd (tbl, "gl_ProjectionMatrixInverseTranspose");
+ e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSETRANSPOSE] =
+ gd (tbl, "gl_ModelViewProjectionMatrixInverseTranspose");
+ e[SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSETRANSPOSE] =
+ gd (tbl, "gl_TextureMatrixInverseTranspose");
+ e[SLANG_COMMON_FIXED_NORMALSCALE] = gd (tbl, "gl_NormalScale");
+ e[SLANG_COMMON_FIXED_DEPTHRANGE] = gd (tbl, "gl_DepthRange");
+ e[SLANG_COMMON_FIXED_CLIPPLANE] = gd (tbl, "gl_ClipPlane");
+ e[SLANG_COMMON_FIXED_POINT] = gd (tbl, "gl_Point");
+ e[SLANG_COMMON_FIXED_FRONTMATERIAL] = gd (tbl, "gl_FrontMaterial");
+ e[SLANG_COMMON_FIXED_BACKMATERIAL] = gd (tbl, "gl_BackMaterial");
+ e[SLANG_COMMON_FIXED_LIGHTSOURCE] = gd (tbl, "gl_LightSource");
+ e[SLANG_COMMON_FIXED_LIGHTMODEL] = gd (tbl, "gl_LightModel");
+ e[SLANG_COMMON_FIXED_FRONTLIGHTMODELPRODUCT] = gd (tbl, "gl_FrontLightModelProduct");
+ e[SLANG_COMMON_FIXED_BACKLIGHTMODELPRODUCT] = gd (tbl, "gl_BackLightModelProduct");
+ e[SLANG_COMMON_FIXED_FRONTLIGHTPRODUCT] = gd (tbl, "gl_FrontLightProduct");
+ e[SLANG_COMMON_FIXED_BACKLIGHTPRODUCT] = gd (tbl, "gl_BackLightProduct");
+ e[SLANG_COMMON_FIXED_TEXTUREENVCOLOR] = gd (tbl, "gl_TextureEnvColor");
+ e[SLANG_COMMON_FIXED_EYEPLANES] = gd (tbl, "gl_EyePlaneS");
+ e[SLANG_COMMON_FIXED_EYEPLANET] = gd (tbl, "gl_EyePlaneT");
+ e[SLANG_COMMON_FIXED_EYEPLANER] = gd (tbl, "gl_EyePlaneR");
+ e[SLANG_COMMON_FIXED_EYEPLANEQ] = gd (tbl, "gl_EyePlaneQ");
+ e[SLANG_COMMON_FIXED_OBJECTPLANES] = gd (tbl, "gl_ObjectPlaneS");
+ e[SLANG_COMMON_FIXED_OBJECTPLANET] = gd (tbl, "gl_ObjectPlaneT");
+ e[SLANG_COMMON_FIXED_OBJECTPLANER] = gd (tbl, "gl_ObjectPlaneR");
+ e[SLANG_COMMON_FIXED_OBJECTPLANEQ] = gd (tbl, "gl_ObjectPlaneQ");
+ e[SLANG_COMMON_FIXED_FOG] = gd (tbl, "gl_Fog");
+}
+
+static GLvoid resolve_vertex_fixed (GLuint e[], slang_export_data_table *tbl)
+{
+ e[SLANG_VERTEX_FIXED_POSITION] = gd (tbl, "gl_Position");
+ e[SLANG_VERTEX_FIXED_POINTSIZE] = gd (tbl, "gl_PointSize");
+ e[SLANG_VERTEX_FIXED_CLIPVERTEX] = gd (tbl, "gl_ClipVertex");
+ e[SLANG_VERTEX_FIXED_COLOR] = gd (tbl, "gl_Color");
+ e[SLANG_VERTEX_FIXED_SECONDARYCOLOR] = gd (tbl, "gl_SecondaryColor");
+ e[SLANG_VERTEX_FIXED_NORMAL] = gd (tbl, "gl_Normal");
+ e[SLANG_VERTEX_FIXED_VERTEX] = gd (tbl, "gl_Vertex");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD0] = gd (tbl, "gl_MultiTexCoord0");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD1] = gd (tbl, "gl_MultiTexCoord1");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD2] = gd (tbl, "gl_MultiTexCoord2");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD3] = gd (tbl, "gl_MultiTexCoord3");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD4] = gd (tbl, "gl_MultiTexCoord4");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD5] = gd (tbl, "gl_MultiTexCoord5");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD6] = gd (tbl, "gl_MultiTexCoord6");
+ e[SLANG_VERTEX_FIXED_MULTITEXCOORD7] = gd (tbl, "gl_MultiTexCoord7");
+ e[SLANG_VERTEX_FIXED_FOGCOORD] = gd (tbl, "gl_FogCoord");
+ e[SLANG_VERTEX_FIXED_FRONTCOLOR] = gd (tbl, "gl_FrontColor");
+ e[SLANG_VERTEX_FIXED_BACKCOLOR] = gd (tbl, "gl_BackColor");
+ e[SLANG_VERTEX_FIXED_FRONTSECONDARYCOLOR] = gd (tbl, "gl_FrontSecondaryColor");
+ e[SLANG_VERTEX_FIXED_BACKSECONDARYCOLOR] = gd (tbl, "gl_BackSecondaryColor");
+ e[SLANG_VERTEX_FIXED_TEXCOORD] = gd (tbl, "gl_TexCoord");
+ e[SLANG_VERTEX_FIXED_FOGFRAGCOORD] = gd (tbl, "gl_FogFragCoord");
+}
+
+static GLvoid resolve_fragment_fixed (GLuint e[], slang_export_data_table *tbl)
+{
+ e[SLANG_FRAGMENT_FIXED_FRAGCOORD] = gd (tbl, "gl_FragCoord");
+ e[SLANG_FRAGMENT_FIXED_FRONTFACING] = gd (tbl, "gl_FrontFacing");
+ e[SLANG_FRAGMENT_FIXED_FRAGCOLOR] = gd (tbl, "gl_FragColor");
+ e[SLANG_FRAGMENT_FIXED_FRAGDATA] = gd (tbl, "gl_FragData");
+ e[SLANG_FRAGMENT_FIXED_FRAGDEPTH] = gd (tbl, "gl_FragDepth");
+ e[SLANG_FRAGMENT_FIXED_COLOR] = gd (tbl, "gl_Color");
+ e[SLANG_FRAGMENT_FIXED_SECONDARYCOLOR] = gd (tbl, "gl_SecondaryColor");
+ e[SLANG_FRAGMENT_FIXED_TEXCOORD] = gd (tbl, "gl_TexCoord");
+ e[SLANG_FRAGMENT_FIXED_FOGFRAGCOORD] = gd (tbl, "gl_FogFragCoord");
+}
+
+static GLuint gc (slang_export_code_table *tbl, const char *name)
+{
+ slang_atom atom;
+ GLuint i;
+
+ atom = slang_atom_pool_atom (tbl->atoms, name);
+ if (atom == SLANG_ATOM_NULL)
+ return ~0;
+
+ for (i = 0; i < tbl->count; i++)
+ if (atom == tbl->entries[i].name)
+ return tbl->entries[i].address;
+ return ~0;
+}
+
+static GLvoid resolve_common_code (GLuint code[], slang_export_code_table *tbl)
+{
+ code[SLANG_COMMON_CODE_MAIN] = gc (tbl, "@main");
+}
+
+GLboolean
+_slang_link (slang_program *prog, slang_code_object **objects, GLuint count)
+{
+ GLuint i;
+
+ for (i = 0; i < count; i++)
+ {
+ GLuint index;
+
+ if (objects[i]->unit.type == slang_unit_fragment_shader) {
+ index = SLANG_SHADER_FRAGMENT;
+ resolve_fragment_fixed (prog->fragment_fixed_entries, &objects[i]->expdata);
+ }
+ else
+ {
+ index = SLANG_SHADER_VERTEX;
+ resolve_vertex_fixed (prog->vertex_fixed_entries, &objects[i]->expdata);
+ if (!gather_attrib_bindings (&prog->attribs, &objects[i]->expdata,
+ &prog->attrib_overrides))
+ return GL_FALSE;
+ }
+
+ if (!gather_active_variables (&prog->active_uniforms, &objects[i]->expdata, slang_exp_uniform))
+ return GL_FALSE;
+ if (!gather_active_variables (&prog->active_attribs, &objects[i]->expdata, slang_exp_attribute))
+ return GL_FALSE;
+ if (!gather_uniform_bindings (&prog->uniforms, &objects[i]->expdata, index))
+ return GL_FALSE;
+ if (!gather_varying_bindings (&prog->varyings, &objects[i]->expdata,
+ index == SLANG_SHADER_VERTEX))
+ return GL_FALSE;
+ resolve_common_fixed (prog->common_fixed_entries[index], &objects[i]->expdata);
+ resolve_common_code (prog->code[index], &objects[i]->expcode);
+ prog->machines[index] = &objects[i]->machine;
+ prog->assemblies[index] = &objects[i]->assembly;
+ }
+
+ /* TODO: all varyings read by fragment shader must be written by vertex shader */
+
+ if (!_slang_analyse_texture_usage (prog))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_link.h b/src/mesa/shader/slang/slang_link.h
new file mode 100644
index 00000000000..a7898530318
--- /dev/null
+++ b/src/mesa/shader/slang/slang_link.h
@@ -0,0 +1,316 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#if !defined SLANG_LINK_H
+#define SLANG_LINK_H
+
+#include "slang_compile.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+ SLANG_SHADER_VERTEX,
+ SLANG_SHADER_FRAGMENT,
+ SLANG_SHADER_MAX
+};
+
+/* Active variables.
+ *
+ * Active uniforms or attribs can be queried by the application to get a list of uniforms
+ * or attribs actually used by shaders (uniforms) or vertex shader (attribs).
+ */
+
+typedef struct
+{
+ slang_export_data_quant *quant;
+ char *name;
+} slang_active_variable;
+
+typedef struct
+{
+ slang_active_variable *table;
+ GLuint count;
+} slang_active_variables;
+
+/*
+ * Attrib binding override.
+ *
+ * The application can override GL attrib binding by specifying its preferred index assignment
+ * for a given attrib name. Those overrides are taken into account while linking the program.
+ */
+
+typedef struct
+{
+ GLuint index;
+ GLchar *name;
+} slang_attrib_override;
+
+typedef struct
+{
+ slang_attrib_override *table;
+ GLuint count;
+} slang_attrib_overrides;
+
+GLboolean slang_attrib_overrides_add (slang_attrib_overrides *, GLuint, const GLchar *);
+
+/*
+ * Uniform bindings.
+ *
+ * Each slang_uniform_binding holds an array of addresses to actual memory locations in those
+ * shader types that use that uniform. Uniform bindings are held in an array and accessed
+ * by array index which is seen to the application as a uniform location.
+ *
+ * When the application writes to a particular uniform, it specifies its location.
+ * This location is treated as an array index to slang_uniform_bindings::table and tested
+ * against slang_uniform_bindings::count limit. The result is a pointer to slang_uniform_binding.
+ * The type of data being written to uniform is tested against slang_uniform_binding::quant.
+ * If the types are compatible, the array slang_uniform_binding::address is iterated for
+ * each shader type and if the address is valid (i.e. the uniform is used by this shader type),
+ * the new uniform value is written at that address.
+ */
+
+typedef struct
+{
+ slang_export_data_quant *quant;
+ char *name;
+ GLuint address[SLANG_SHADER_MAX];
+} slang_uniform_binding;
+
+typedef struct
+{
+ slang_uniform_binding *table;
+ GLuint count;
+} slang_uniform_bindings;
+
+/*
+ * Attrib bindings.
+ *
+ * There is a fixed number of vertex attrib vectors (attrib slots). The slang_attrib_slot::addr
+ * maps vertex attrib index to the actual memory location of the attrib in vertex shader.
+ * One vertex attrib can span over many attrib slots (this is the case for matrices). The
+ * slang_attrib_binding::first_slot_index holds the first slot index that the attrib is bound to.
+ */
+
+typedef struct
+{
+ slang_export_data_quant *quant;
+ char *name;
+ GLuint first_slot_index;
+} slang_attrib_binding;
+
+typedef struct
+{
+ GLuint addr; /* memory location */
+ GLuint fill; /* 1..4, number of components used */
+} slang_attrib_slot;
+
+typedef struct
+{
+ slang_attrib_binding bindings[MAX_VERTEX_ATTRIBS];
+ GLuint binding_count;
+ slang_attrib_slot slots[MAX_VERTEX_ATTRIBS];
+} slang_attrib_bindings;
+
+/*
+ * Varying bindings.
+ *
+ * There is a fixed number of varying floats (varying slots). The slang_varying_slot::vert_addr
+ * maps varying float index to the actual memory location of the output variable in vertex shader.
+ * The slang_varying_slot::frag_addr maps varying float index to the actual memory location of
+ * the input variable in fragment shader.
+ */
+
+typedef struct
+{
+ GLuint vert_addr;
+ GLuint frag_addr;
+} slang_varying_slot;
+
+typedef struct
+{
+ slang_export_data_quant *quant;
+ char *name;
+ GLuint first_slot_index;
+} slang_varying_binding;
+
+typedef struct
+{
+ slang_varying_binding bindings[MAX_VARYING_FLOATS];
+ GLuint binding_count;
+ slang_varying_slot slots[MAX_VARYING_FLOATS];
+ GLuint slot_count;
+} slang_varying_bindings;
+
+/*
+ * Texture usage.
+ *
+ * A slang_texture_usage struct holds indirect information about texture image unit usage. The
+ * slang_texture_usages::table is derived from active uniform table by extracting only uniforms
+ * that are samplers.
+ *
+ * To collect current texture usage one must iterate the slang_texture_usages::table and read
+ * uniform at address slang_texture_usage::frag_address to get texture unit index. This
+ * index, coupled with texture access type (target) taken from slang_texture_usage::quant
+ * forms texture usage for that texture unit.
+ */
+
+typedef struct
+{
+ slang_export_data_quant *quant;
+ GLuint frag_address;
+} slang_texture_usage;
+
+typedef struct
+{
+ slang_texture_usage *table;
+ GLuint count;
+} slang_texture_usages;
+
+GLvoid slang_texture_usages_ctr (slang_texture_usages *);
+GLvoid slang_texture_usages_dtr (slang_texture_usages *);
+
+enum
+{
+ SLANG_COMMON_FIXED_MODELVIEWMATRIX,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIX,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIX,
+ SLANG_COMMON_FIXED_TEXTUREMATRIX,
+ SLANG_COMMON_FIXED_NORMALMATRIX,
+ SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSE,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSE,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSE,
+ SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSE,
+ SLANG_COMMON_FIXED_MODELVIEWMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_TEXTUREMATRIXTRANSPOSE,
+ SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSETRANSPOSE,
+ SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSETRANSPOSE,
+ SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSETRANSPOSE,
+ SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSETRANSPOSE,
+ SLANG_COMMON_FIXED_NORMALSCALE,
+ SLANG_COMMON_FIXED_DEPTHRANGE,
+ SLANG_COMMON_FIXED_CLIPPLANE,
+ SLANG_COMMON_FIXED_POINT,
+ SLANG_COMMON_FIXED_FRONTMATERIAL,
+ SLANG_COMMON_FIXED_BACKMATERIAL,
+ SLANG_COMMON_FIXED_LIGHTSOURCE,
+ SLANG_COMMON_FIXED_LIGHTMODEL,
+ SLANG_COMMON_FIXED_FRONTLIGHTMODELPRODUCT,
+ SLANG_COMMON_FIXED_BACKLIGHTMODELPRODUCT,
+ SLANG_COMMON_FIXED_FRONTLIGHTPRODUCT,
+ SLANG_COMMON_FIXED_BACKLIGHTPRODUCT,
+ SLANG_COMMON_FIXED_TEXTUREENVCOLOR,
+ SLANG_COMMON_FIXED_EYEPLANES,
+ SLANG_COMMON_FIXED_EYEPLANET,
+ SLANG_COMMON_FIXED_EYEPLANER,
+ SLANG_COMMON_FIXED_EYEPLANEQ,
+ SLANG_COMMON_FIXED_OBJECTPLANES,
+ SLANG_COMMON_FIXED_OBJECTPLANET,
+ SLANG_COMMON_FIXED_OBJECTPLANER,
+ SLANG_COMMON_FIXED_OBJECTPLANEQ,
+ SLANG_COMMON_FIXED_FOG,
+ SLANG_COMMON_FIXED_MAX
+};
+
+enum
+{
+ SLANG_VERTEX_FIXED_POSITION,
+ SLANG_VERTEX_FIXED_POINTSIZE,
+ SLANG_VERTEX_FIXED_CLIPVERTEX,
+ SLANG_VERTEX_FIXED_COLOR,
+ SLANG_VERTEX_FIXED_SECONDARYCOLOR,
+ SLANG_VERTEX_FIXED_NORMAL,
+ SLANG_VERTEX_FIXED_VERTEX,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD0,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD1,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD2,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD3,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD4,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD5,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD6,
+ SLANG_VERTEX_FIXED_MULTITEXCOORD7,
+ SLANG_VERTEX_FIXED_FOGCOORD,
+ SLANG_VERTEX_FIXED_FRONTCOLOR,
+ SLANG_VERTEX_FIXED_BACKCOLOR,
+ SLANG_VERTEX_FIXED_FRONTSECONDARYCOLOR,
+ SLANG_VERTEX_FIXED_BACKSECONDARYCOLOR,
+ SLANG_VERTEX_FIXED_TEXCOORD,
+ SLANG_VERTEX_FIXED_FOGFRAGCOORD,
+ SLANG_VERTEX_FIXED_MAX
+};
+
+enum
+{
+ SLANG_FRAGMENT_FIXED_FRAGCOORD,
+ SLANG_FRAGMENT_FIXED_FRONTFACING,
+ SLANG_FRAGMENT_FIXED_FRAGCOLOR,
+ SLANG_FRAGMENT_FIXED_FRAGDATA,
+ SLANG_FRAGMENT_FIXED_FRAGDEPTH,
+ SLANG_FRAGMENT_FIXED_COLOR,
+ SLANG_FRAGMENT_FIXED_SECONDARYCOLOR,
+ SLANG_FRAGMENT_FIXED_TEXCOORD,
+ SLANG_FRAGMENT_FIXED_FOGFRAGCOORD,
+ SLANG_FRAGMENT_FIXED_MAX
+};
+
+enum
+{
+ SLANG_COMMON_CODE_MAIN,
+ SLANG_COMMON_CODE_MAX
+};
+
+typedef struct
+{
+ slang_active_variables active_uniforms;
+ slang_active_variables active_attribs;
+ slang_attrib_overrides attrib_overrides;
+ slang_uniform_bindings uniforms;
+ slang_attrib_bindings attribs;
+ slang_varying_bindings varyings;
+ slang_texture_usages texture_usage;
+ GLuint common_fixed_entries[SLANG_SHADER_MAX][SLANG_COMMON_FIXED_MAX];
+ GLuint vertex_fixed_entries[SLANG_VERTEX_FIXED_MAX];
+ GLuint fragment_fixed_entries[SLANG_FRAGMENT_FIXED_MAX];
+ GLuint code[SLANG_SHADER_MAX][SLANG_COMMON_CODE_MAX];
+ slang_machine *machines[SLANG_SHADER_MAX];
+ slang_assembly_file *assemblies[SLANG_SHADER_MAX];
+} slang_program;
+
+GLvoid slang_program_ctr (slang_program *);
+GLvoid slang_program_dtr (slang_program *);
+GLvoid slang_program_rst (slang_program *);
+
+extern GLboolean
+_slang_link (slang_program *, slang_code_object **, GLuint);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_mesa.h b/src/mesa/shader/slang/slang_mesa.h
new file mode 100644
index 00000000000..ca7af22d2a6
--- /dev/null
+++ b/src/mesa/shader/slang/slang_mesa.h
@@ -0,0 +1,36 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.3
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+int _mesa_isalnum (char);
+int _glslang_3dlabs_InitProcess ();
+int _glslang_3dlabs_ShInitialize ();
+
+#if defined __cplusplus
+}
+#endif
+
diff --git a/src/mesa/shader/slang/slang_preprocess.c b/src/mesa/shader/slang/slang_preprocess.c
new file mode 100644
index 00000000000..bd9ff9002e9
--- /dev/null
+++ b/src/mesa/shader/slang/slang_preprocess.c
@@ -0,0 +1,77 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_preprocess.c
+ * slang preprocessor
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "grammar_mesa.h"
+#include "slang_preprocess.h"
+
+static const char *slang_pp_version_syn =
+#include "library/slang_pp_version_syn.h"
+;
+
+static GLvoid
+grammar_error_to_log (slang_info_log *log)
+{
+ char buf[1024];
+ int pos;
+
+ grammar_get_last_error ((byte *) (buf), sizeof (buf), &pos);
+ slang_info_log_error (log, buf);
+}
+
+GLboolean
+_slang_preprocess_version (const char *text, GLuint *version, GLuint *eaten, slang_info_log *log)
+{
+ grammar id;
+ byte *prod, *I;
+ unsigned int size;
+
+ id = grammar_load_from_text ((const byte *) (slang_pp_version_syn));
+ if (id == 0) {
+ grammar_error_to_log (log);
+ return GL_FALSE;
+ }
+
+ if (!grammar_fast_check (id, (const byte *) (text), &prod, &size, 8)) {
+ grammar_error_to_log (log);
+ grammar_destroy (id);
+ return GL_FALSE;
+ }
+
+ /* there can be multiple #version directives - grab the last one */
+ I = &prod[size - 6];
+ *version = (GLuint) (I[0]) + (GLuint) (I[1]) * 100;
+ *eaten = (GLuint) (I[2]) + ((GLuint) (I[3]) << 8) + ((GLuint) (I[4]) << 16) + ((GLuint) (I[5]) << 24);
+
+ grammar_destroy (id);
+ grammar_alloc_free (prod);
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_preprocess.h b/src/mesa/shader/slang/slang_preprocess.h
new file mode 100644
index 00000000000..b55852dc4c0
--- /dev/null
+++ b/src/mesa/shader/slang/slang_preprocess.h
@@ -0,0 +1,42 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_PREPROCESS_H
+#define SLANG_PREPROCESS_H
+
+#include "slang_compile.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+GLboolean
+_slang_preprocess_version (const char *, GLuint *, GLuint *, slang_info_log *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_storage.c b/src/mesa/shader/slang/slang_storage.c
new file mode 100644
index 00000000000..6220b7c5bf6
--- /dev/null
+++ b/src/mesa/shader/slang/slang_storage.c
@@ -0,0 +1,342 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_storage.c
+ * slang variable storage
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_storage.h"
+
+/* slang_storage_array */
+
+GLboolean slang_storage_array_construct (slang_storage_array *arr)
+{
+ arr->type = slang_stor_aggregate;
+ arr->aggregate = NULL;
+ arr->length = 0;
+ return GL_TRUE;
+}
+
+GLvoid slang_storage_array_destruct (slang_storage_array *arr)
+{
+ if (arr->aggregate != NULL)
+ {
+ slang_storage_aggregate_destruct (arr->aggregate);
+ slang_alloc_free (arr->aggregate);
+ }
+}
+
+/* slang_storage_aggregate */
+
+GLboolean slang_storage_aggregate_construct (slang_storage_aggregate *agg)
+{
+ agg->arrays = NULL;
+ agg->count = 0;
+ return GL_TRUE;
+}
+
+GLvoid slang_storage_aggregate_destruct (slang_storage_aggregate *agg)
+{
+ GLuint i;
+
+ for (i = 0; i < agg->count; i++)
+ slang_storage_array_destruct (agg->arrays + i);
+ slang_alloc_free (agg->arrays);
+}
+
+static slang_storage_array *slang_storage_aggregate_push_new (slang_storage_aggregate *agg)
+{
+ slang_storage_array *arr = NULL;
+
+ agg->arrays = (slang_storage_array *) slang_alloc_realloc (agg->arrays, agg->count * sizeof (
+ slang_storage_array), (agg->count + 1) * sizeof (slang_storage_array));
+ if (agg->arrays != NULL)
+ {
+ arr = agg->arrays + agg->count;
+ if (!slang_storage_array_construct (arr))
+ return NULL;
+ agg->count++;
+ }
+ return arr;
+}
+
+/* _slang_aggregate_variable() */
+
+static GLboolean aggregate_vector (slang_storage_aggregate *agg, slang_storage_type basic_type,
+ GLuint row_count)
+{
+ slang_storage_array *arr = slang_storage_aggregate_push_new (agg);
+ if (arr == NULL)
+ return GL_FALSE;
+ arr->type = basic_type;
+ arr->length = row_count;
+ return GL_TRUE;
+}
+
+static GLboolean aggregate_matrix (slang_storage_aggregate *agg, slang_storage_type basic_type,
+ GLuint dimension)
+{
+ slang_storage_array *arr = slang_storage_aggregate_push_new (agg);
+ if (arr == NULL)
+ return GL_FALSE;
+ arr->type = slang_stor_aggregate;
+ arr->length = dimension;
+ arr->aggregate = (slang_storage_aggregate *) slang_alloc_malloc (sizeof (slang_storage_aggregate));
+ if (arr->aggregate == NULL)
+ return GL_FALSE;
+ if (!slang_storage_aggregate_construct (arr->aggregate))
+ {
+ slang_alloc_free (arr->aggregate);
+ arr->aggregate = NULL;
+ return GL_FALSE;
+ }
+ if (!aggregate_vector (arr->aggregate, basic_type, dimension))
+ return GL_FALSE;
+ return GL_TRUE;
+}
+
+static GLboolean aggregate_variables (slang_storage_aggregate *agg, slang_variable_scope *vars,
+ slang_function_scope *funcs, slang_struct_scope *structs, slang_variable_scope *globals,
+ slang_machine *mach, slang_assembly_file *file, slang_atom_pool *atoms)
+{
+ GLuint i;
+
+ for (i = 0; i < vars->num_variables; i++)
+ if (!_slang_aggregate_variable (agg, &vars->variables[i].type.specifier,
+ vars->variables[i].array_len, funcs, structs, globals, mach, file, atoms))
+ return GL_FALSE;
+ return GL_TRUE;
+}
+
+GLboolean _slang_evaluate_int (slang_assembly_file *file, slang_machine *pmach,
+ slang_assembly_name_space *space, slang_operation *array_size, GLuint *pint,
+ slang_atom_pool *atoms)
+{
+ slang_assembly_file_restore_point point;
+ slang_machine mach;
+ slang_assemble_ctx A;
+
+ A.file = file;
+ A.mach = pmach;
+ A.atoms = atoms;
+ A.space = *space;
+ A.local.ret_size = 0;
+ A.local.addr_tmp = 0;
+ A.local.swizzle_tmp = 4;
+
+ /* save the current assembly */
+ if (!slang_assembly_file_restore_point_save (file, &point))
+ return GL_FALSE;
+
+ /* setup the machine */
+ mach = *pmach;
+ mach.ip = file->count;
+
+ /* allocate local storage for expression */
+ if (!slang_assembly_file_push_label (file, slang_asm_local_alloc, 20))
+ return GL_FALSE;
+ if (!slang_assembly_file_push_label (file, slang_asm_enter, 20))
+ return GL_FALSE;
+
+ /* insert the actual expression */
+ if (!_slang_assemble_operation (&A, array_size, slang_ref_forbid))
+ return GL_FALSE;
+ if (!slang_assembly_file_push (file, slang_asm_exit))
+ return GL_FALSE;
+
+ /* execute the expression */
+ if (!_slang_execute2 (file, &mach))
+ return GL_FALSE;
+
+ /* the evaluated expression is on top of the stack */
+ *pint = (GLuint) mach.mem[mach.sp + SLANG_MACHINE_GLOBAL_SIZE]._float;
+
+ /* restore the old assembly */
+ if (!slang_assembly_file_restore_point_load (file, &point))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+GLboolean _slang_aggregate_variable (slang_storage_aggregate *agg, slang_type_specifier *spec,
+ GLuint array_len, slang_function_scope *funcs, slang_struct_scope *structs,
+ slang_variable_scope *vars, slang_machine *mach, slang_assembly_file *file,
+ slang_atom_pool *atoms)
+{
+ switch (spec->type)
+ {
+ case slang_spec_bool:
+ return aggregate_vector (agg, slang_stor_bool, 1);
+ case slang_spec_bvec2:
+ return aggregate_vector (agg, slang_stor_bool, 2);
+ case slang_spec_bvec3:
+ return aggregate_vector (agg, slang_stor_bool, 3);
+ case slang_spec_bvec4:
+ return aggregate_vector (agg, slang_stor_bool, 4);
+ case slang_spec_int:
+ return aggregate_vector (agg, slang_stor_int, 1);
+ case slang_spec_ivec2:
+ return aggregate_vector (agg, slang_stor_int, 2);
+ case slang_spec_ivec3:
+ return aggregate_vector (agg, slang_stor_int, 3);
+ case slang_spec_ivec4:
+ return aggregate_vector (agg, slang_stor_int, 4);
+ case slang_spec_float:
+ return aggregate_vector (agg, slang_stor_float, 1);
+ case slang_spec_vec2:
+ return aggregate_vector (agg, slang_stor_float, 2);
+ case slang_spec_vec3:
+ return aggregate_vector (agg, slang_stor_float, 3);
+ case slang_spec_vec4:
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ return aggregate_vector (agg, slang_stor_vec4, 1);
+#else
+ return aggregate_vector (agg, slang_stor_float, 4);
+#endif
+ case slang_spec_mat2:
+ return aggregate_matrix (agg, slang_stor_float, 2);
+ case slang_spec_mat3:
+ return aggregate_matrix (agg, slang_stor_float, 3);
+ case slang_spec_mat4:
+#if defined(USE_X86_ASM) || defined(SLANG_X86)
+ return aggregate_vector (agg, slang_stor_vec4, 4);
+#else
+ return aggregate_matrix (agg, slang_stor_float, 4);
+#endif
+ case slang_spec_sampler1D:
+ case slang_spec_sampler2D:
+ case slang_spec_sampler3D:
+ case slang_spec_samplerCube:
+ case slang_spec_sampler1DShadow:
+ case slang_spec_sampler2DShadow:
+ return aggregate_vector (agg, slang_stor_int, 1);
+ case slang_spec_struct:
+ return aggregate_variables (agg, spec->_struct->fields, funcs, structs, vars, mach,
+ file, atoms);
+ case slang_spec_array:
+ {
+ slang_storage_array *arr;
+
+ arr = slang_storage_aggregate_push_new (agg);
+ if (arr == NULL)
+ return GL_FALSE;
+ arr->type = slang_stor_aggregate;
+ arr->aggregate = (slang_storage_aggregate *) slang_alloc_malloc (sizeof (slang_storage_aggregate));
+ if (arr->aggregate == NULL)
+ return GL_FALSE;
+ if (!slang_storage_aggregate_construct (arr->aggregate))
+ {
+ slang_alloc_free (arr->aggregate);
+ arr->aggregate = NULL;
+ return GL_FALSE;
+ }
+ if (!_slang_aggregate_variable (arr->aggregate, spec->_array, 0, funcs, structs,
+ vars, mach, file, atoms))
+ return GL_FALSE;
+ arr->length = array_len;
+ /* TODO: check if 0 < arr->length <= 65535 */
+ }
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+/* _slang_sizeof_type() */
+
+GLuint
+_slang_sizeof_type (slang_storage_type type)
+{
+ if (type == slang_stor_aggregate)
+ return 0;
+ if (type == slang_stor_vec4)
+ return 4 * sizeof (GLfloat);
+ return sizeof (GLfloat);
+}
+
+/* _slang_sizeof_aggregate() */
+
+GLuint _slang_sizeof_aggregate (const slang_storage_aggregate *agg)
+{
+ GLuint i, size = 0;
+
+ for (i = 0; i < agg->count; i++) {
+ slang_storage_array *arr = &agg->arrays[i];
+ GLuint element_size;
+
+ if (arr->type == slang_stor_aggregate)
+ element_size = _slang_sizeof_aggregate (arr->aggregate);
+ else
+ element_size = _slang_sizeof_type (arr->type);
+ size += element_size * arr->length;
+ }
+ return size;
+}
+
+/* _slang_flatten_aggregate () */
+
+GLboolean
+_slang_flatten_aggregate (slang_storage_aggregate *flat, const slang_storage_aggregate *agg)
+{
+ GLuint i;
+
+ for (i = 0; i < agg->count; i++) {
+ GLuint j;
+
+ for (j = 0; j < agg->arrays[i].length; j++) {
+ if (agg->arrays[i].type == slang_stor_aggregate) {
+ if (!_slang_flatten_aggregate (flat, agg->arrays[i].aggregate))
+ return GL_FALSE;
+ }
+ else {
+ GLuint k, count;
+ slang_storage_type type;
+
+ if (agg->arrays[i].type == slang_stor_vec4) {
+ count = 4;
+ type = slang_stor_float;
+ }
+ else {
+ count = 1;
+ type = agg->arrays[i].type;
+ }
+
+ for (k = 0; k < count; k++) {
+ slang_storage_array *arr;
+
+ arr = slang_storage_aggregate_push_new (flat);
+ if (arr == NULL)
+ return GL_FALSE;
+ arr->type = type;
+ arr->length = 1;
+ }
+ }
+ }
+ }
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/shader/slang/slang_storage.h b/src/mesa/shader/slang/slang_storage.h
new file mode 100644
index 00000000000..209f8674d97
--- /dev/null
+++ b/src/mesa/shader/slang/slang_storage.h
@@ -0,0 +1,141 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_STORAGE_H
+#define SLANG_STORAGE_H
+
+#include "slang_compile.h"
+#include "slang_assemble.h"
+#include "slang_execute.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Program variable data storage is kept completely transparent to the front-end compiler. It is
+ * up to the back-end how the data is actually allocated. The slang_storage_type enum
+ * provides the basic information about how the memory is interpreted. This abstract piece
+ * of memory is called a data slot. A data slot of a particular type has a fixed size.
+ *
+ * For now, only the three basic types are supported, that is bool, int and float. Other built-in
+ * types like vector or matrix can easily be decomposed into a series of basic types.
+ *
+ * If the vec4 module is enabled, 4-component vectors of floats are used when possible. 4x4 matrices
+ * are constructed of 4 vec4 slots.
+ */
+typedef enum slang_storage_type_
+{
+ /* core */
+ slang_stor_aggregate,
+ slang_stor_bool,
+ slang_stor_int,
+ slang_stor_float,
+ /* vec4 */
+ slang_stor_vec4
+} slang_storage_type;
+
+/*
+ * The slang_storage_array structure groups data slots of the same type into an array. This
+ * array has a fixed length. Arrays are required to have a size equal to the sum of sizes of its
+ * elements. They are also required to support indirect addressing. That is, if B references
+ * first data slot in the array, S is the size of the data slot and I is the integral index that
+ * is not known at compile time, B+I*S references I-th data slot.
+ *
+ * This structure is also used to break down built-in data types that are not supported directly.
+ * Vectors, like vec3, are constructed from arrays of their basic types. Matrices are formed of
+ * an array of column vectors, which are in turn processed as other vectors.
+ */
+typedef struct slang_storage_array_
+{
+ slang_storage_type type;
+ struct slang_storage_aggregate_ *aggregate; /* slang_stor_aggregate */
+ GLuint length;
+} slang_storage_array;
+
+GLboolean slang_storage_array_construct (slang_storage_array *);
+GLvoid slang_storage_array_destruct (slang_storage_array *);
+
+/*
+ * The slang_storage_aggregate structure relaxes the indirect addressing requirement for
+ * slang_storage_array structure. Aggregates are always accessed statically - its member
+ * addresses are well-known at compile time. For example, user-defined types are implemented as
+ * aggregates. Aggregates can collect data of a different type.
+ */
+typedef struct slang_storage_aggregate_
+{
+ slang_storage_array *arrays;
+ GLuint count;
+} slang_storage_aggregate;
+
+GLboolean slang_storage_aggregate_construct (slang_storage_aggregate *);
+GLvoid slang_storage_aggregate_destruct (slang_storage_aggregate *);
+
+extern GLboolean
+_slang_aggregate_variable(slang_storage_aggregate *agg,
+ slang_type_specifier *spec,
+ GLuint array_len,
+ slang_function_scope *funcs,
+ slang_struct_scope *structs,
+ slang_variable_scope *vars,
+ slang_machine *mach,
+ slang_assembly_file *file,
+ slang_atom_pool *atoms);
+
+extern GLboolean
+_slang_evaluate_int(slang_assembly_file *file,
+ slang_machine *pmach,
+ slang_assembly_name_space *space,
+ slang_operation *array_size,
+ GLuint *pint,
+ slang_atom_pool *atoms);
+
+/*
+ * Returns the size (in machine units) of the given storage type.
+ * It is an error to pass-in slang_stor_aggregate.
+ * Returns 0 on error.
+ */
+extern GLuint
+_slang_sizeof_type (slang_storage_type);
+
+/*
+ * Returns total size (in machine units) of the given aggregate.
+ * Returns 0 on error.
+ */
+GLuint _slang_sizeof_aggregate (const slang_storage_aggregate *);
+
+/*
+ * Converts structured aggregate to a flat one, with arrays of generic type being
+ * one-element long.
+ * Returns GL_TRUE on success.
+ * Returns GL_FALSE otherwise.
+ */
+GLboolean _slang_flatten_aggregate (slang_storage_aggregate *, const slang_storage_aggregate *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/slang_utility.c b/src/mesa/shader/slang/slang_utility.c
new file mode 100644
index 00000000000..20ea6abae59
--- /dev/null
+++ b/src/mesa/shader/slang/slang_utility.c
@@ -0,0 +1,112 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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 slang_utility.c
+ * slang utilities
+ * \author Michal Krol
+ */
+
+#include "imports.h"
+#include "slang_utility.h"
+
+char *slang_string_concat (char *dst, const char *src)
+{
+ return _mesa_strcpy (dst + _mesa_strlen (dst), src);
+}
+
+/* slang_atom_pool */
+
+void slang_atom_pool_construct (slang_atom_pool *pool)
+{
+ GLuint i;
+
+ for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++)
+ pool->entries[i] = NULL;
+}
+
+void slang_atom_pool_destruct (slang_atom_pool *pool)
+{
+ GLuint i;
+
+ for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++)
+ {
+ slang_atom_entry *entry;
+
+ entry = pool->entries[i];
+ while (entry != NULL)
+ {
+ slang_atom_entry *next;
+
+ next = entry->next;
+ slang_alloc_free (entry->id);
+ slang_alloc_free (entry);
+ entry = next;
+ }
+ }
+}
+
+slang_atom slang_atom_pool_atom (slang_atom_pool *pool, const char *id)
+{
+ GLuint hash;
+ const char *p = id;
+ slang_atom_entry **entry;
+
+ hash = 0;
+ while (*p != '\0')
+ {
+ GLuint g;
+
+ hash = (hash << 4) + (GLuint) *p++;
+ g = hash & 0xf0000000;
+ if (g != 0)
+ hash ^= g >> 24;
+ hash &= ~g;
+ }
+ hash %= SLANG_ATOM_POOL_SIZE;
+
+ entry = &pool->entries[hash];
+ while (*entry != NULL)
+ {
+ if (slang_string_compare ((**entry).id, id) == 0)
+ return (slang_atom) (**entry).id;
+ entry = &(**entry).next;
+ }
+
+ *entry = (slang_atom_entry *) slang_alloc_malloc (sizeof (slang_atom_entry));
+ if (*entry == NULL)
+ return SLANG_ATOM_NULL;
+
+ (**entry).next = NULL;
+ (**entry).id = slang_string_duplicate (id);
+ if ((**entry).id == NULL)
+ return SLANG_ATOM_NULL;
+ return (slang_atom) (**entry).id;
+}
+
+const char *slang_atom_pool_id (slang_atom_pool *pool, slang_atom atom)
+{
+ return (const char *) atom;
+}
+
diff --git a/src/mesa/shader/slang/slang_utility.h b/src/mesa/shader/slang/slang_utility.h
new file mode 100644
index 00000000000..7a1997e5597
--- /dev/null
+++ b/src/mesa/shader/slang/slang_utility.h
@@ -0,0 +1,74 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 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.
+ */
+
+#if !defined SLANG_UTILITY_H
+#define SLANG_UTILITY_H
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/* Compile-time assertions. If the expression is zero, try to declare an
+ * array of size [-1] to cause compilation error.
+ */
+#define static_assert(expr) do { int _array[(expr) ? 1 : -1]; (void) _array[0]; } while (0)
+
+#define slang_alloc_free(ptr) _mesa_free (ptr)
+#define slang_alloc_malloc(size) _mesa_malloc (size)
+#define slang_alloc_realloc(ptr, old_size, size) _mesa_realloc (ptr, old_size, size)
+#define slang_string_compare(str1, str2) _mesa_strcmp (str1, str2)
+#define slang_string_copy(dst, src) _mesa_strcpy (dst, src)
+#define slang_string_duplicate(src) _mesa_strdup (src)
+#define slang_string_length(str) _mesa_strlen (str)
+
+char *slang_string_concat (char *, const char *);
+
+typedef GLvoid *slang_atom;
+
+#define SLANG_ATOM_NULL ((slang_atom) 0)
+
+typedef struct slang_atom_entry_
+{
+ char *id;
+ struct slang_atom_entry_ *next;
+} slang_atom_entry;
+
+#define SLANG_ATOM_POOL_SIZE 1023
+
+typedef struct slang_atom_pool_
+{
+ slang_atom_entry *entries[SLANG_ATOM_POOL_SIZE];
+} slang_atom_pool;
+
+GLvoid slang_atom_pool_construct (slang_atom_pool *);
+GLvoid slang_atom_pool_destruct (slang_atom_pool *);
+slang_atom slang_atom_pool_atom (slang_atom_pool *, const char *);
+const char *slang_atom_pool_id (slang_atom_pool *, slang_atom);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/mesa/shader/slang/traverse_wrap.h b/src/mesa/shader/slang/traverse_wrap.h
new file mode 100644
index 00000000000..b2f244ee011
--- /dev/null
+++ b/src/mesa/shader/slang/traverse_wrap.h
@@ -0,0 +1,112 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.3
+ *
+ * Copyright (C) 2005 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 traverse_wrap.h
+ * Handy TIntermTraverser class wrapper
+ * \author Michal Krol
+ */
+
+#ifndef __TRAVERSE_WRAP_H__
+#define __TRAVERSE_WRAP_H__
+
+#include "Include/intermediate.h"
+
+/*
+ The original TIntermTraverser class that is used to walk the intermediate tree,
+ is not very elegant in its design. One must define static functions with
+ appropriate prototypes, construct TIntermTraverser object, and set its member
+ function pointers to one's static functions. If traversal-specific data
+ is needed, a new class must be derived, and one must up-cast the object
+ passed as a parameter to the static function.
+
+ The class below eliminates this burden by providing virtual methods that are
+ to be overridden in the derived class.
+*/
+
+class traverse_wrap: private TIntermTraverser
+{
+private:
+ static void _visitSymbol (TIntermSymbol *S, TIntermTraverser *T) {
+ static_cast<traverse_wrap *> (T)->Symbol (*S);
+ }
+ static void _visitConstantUnion (TIntermConstantUnion *U, TIntermTraverser *T) {
+ static_cast<traverse_wrap *> (T)->ConstantUnion (*U);
+ }
+ static bool _visitBinary (bool preVisit, TIntermBinary *B, TIntermTraverser *T) {
+ return static_cast<traverse_wrap *> (T)->Binary (preVisit, *B);
+ }
+ static bool _visitUnary (bool preVisit, TIntermUnary *U, TIntermTraverser *T) {
+ return static_cast<traverse_wrap *> (T)->Unary (preVisit, *U);
+ }
+ static bool _visitSelection (bool preVisit, TIntermSelection *S, TIntermTraverser *T) {
+ return static_cast<traverse_wrap *> (T)->Selection (preVisit, *S);
+ }
+ static bool _visitAggregate (bool preVisit, TIntermAggregate *A, TIntermTraverser *T) {
+ return static_cast<traverse_wrap *> (T)->Aggregate (preVisit, *A);
+ }
+ static bool _visitLoop (bool preVisit, TIntermLoop *L, TIntermTraverser *T) {
+ return static_cast<traverse_wrap *> (T)->Loop (preVisit, *L);
+ }
+ static bool _visitBranch (bool preVisit, TIntermBranch *B, TIntermTraverser *T) {
+ return static_cast<traverse_wrap *> (T)->Branch (preVisit, *B);
+ }
+public:
+ traverse_wrap () {
+ visitSymbol = _visitSymbol;
+ visitConstantUnion = _visitConstantUnion;
+ visitBinary = _visitBinary;
+ visitUnary = _visitUnary;
+ visitSelection = _visitSelection;
+ visitAggregate = _visitAggregate;
+ visitLoop = _visitLoop;
+ visitBranch = _visitBranch;
+ }
+protected:
+ virtual void Symbol (const TIntermSymbol &) {
+ }
+ virtual void ConstantUnion (const TIntermConstantUnion &) {
+ }
+ virtual bool Binary (bool, const TIntermBinary &) {
+ return true;
+ }
+ virtual bool Unary (bool, const TIntermUnary &) {
+ return true;
+ }
+ virtual bool Selection (bool, const TIntermSelection &) {
+ return true;
+ }
+ virtual bool Aggregate (bool, const TIntermAggregate &) {
+ return true;
+ }
+ virtual bool Loop (bool, const TIntermLoop &) {
+ return true;
+ }
+ virtual bool Branch (bool, const TIntermBranch &) {
+ return true;
+ }
+};
+
+#endif
+