aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/program
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/program')
-rw-r--r--mesalib/src/mesa/program/arbprogparse.c438
-rw-r--r--mesalib/src/mesa/program/arbprogparse.h86
-rw-r--r--mesalib/src/mesa/program/ir_to_mesa.cpp6039
-rw-r--r--mesalib/src/mesa/program/ir_to_mesa.h79
-rw-r--r--mesalib/src/mesa/program/nvfragparse.c3176
-rw-r--r--mesalib/src/mesa/program/nvfragparse.h91
-rw-r--r--mesalib/src/mesa/program/nvvertparse.c2918
-rw-r--r--mesalib/src/mesa/program/nvvertparse.h95
-rw-r--r--mesalib/src/mesa/program/prog_cache.c412
-rw-r--r--mesalib/src/mesa/program/prog_cache.h117
-rw-r--r--mesalib/src/mesa/program/prog_execute.c3770
-rw-r--r--mesalib/src/mesa/program/prog_execute.h172
-rw-r--r--mesalib/src/mesa/program/prog_instruction.h908
-rw-r--r--mesalib/src/mesa/program/prog_optimize.c2500
-rw-r--r--mesalib/src/mesa/program/prog_optimize.h93
-rw-r--r--mesalib/src/mesa/program/prog_parameter.c1321
-rw-r--r--mesalib/src/mesa/program/prog_print.c2170
-rw-r--r--mesalib/src/mesa/program/prog_print.h237
-rw-r--r--mesalib/src/mesa/program/prog_statevars.c2371
-rw-r--r--mesalib/src/mesa/program/prog_statevars.h294
-rw-r--r--mesalib/src/mesa/program/program.c2049
-rw-r--r--mesalib/src/mesa/program/program.h413
-rw-r--r--mesalib/src/mesa/program/program_parse.tab.c11460
-rw-r--r--mesalib/src/mesa/program/program_parse.y5536
-rw-r--r--mesalib/src/mesa/program/program_parser.h601
-rw-r--r--mesalib/src/mesa/program/programopt.c1338
-rw-r--r--mesalib/src/mesa/program/programopt.h106
-rw-r--r--mesalib/src/mesa/program/register_allocate.c425
-rw-r--r--mesalib/src/mesa/program/register_allocate.h71
-rw-r--r--mesalib/src/mesa/program/sampler.cpp140
-rw-r--r--mesalib/src/mesa/program/sampler.h29
-rw-r--r--mesalib/src/mesa/program/symbol_table.c901
-rw-r--r--mesalib/src/mesa/program/symbol_table.h120
33 files changed, 25721 insertions, 24755 deletions
diff --git a/mesalib/src/mesa/program/arbprogparse.c b/mesalib/src/mesa/program/arbprogparse.c
index f834aaf56..ebbc195bc 100644
--- a/mesalib/src/mesa/program/arbprogparse.c
+++ b/mesalib/src/mesa/program/arbprogparse.c
@@ -1,219 +1,219 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 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
- */
-
-/**
-Notes on program parameters, etc.
-
-The instructions we emit will use six kinds of source registers:
-
- PROGRAM_INPUT - input registers
- PROGRAM_TEMPORARY - temp registers
- PROGRAM_ADDRESS - address/indirect register
- PROGRAM_SAMPLER - texture sampler
- PROGRAM_CONSTANT - indexes into program->Parameters, a known constant/literal
- PROGRAM_STATE_VAR - indexes into program->Parameters, and may actually be:
- + a state variable, like "state.fog.color", or
- + a pointer to a "program.local[k]" parameter, or
- + a pointer to a "program.env[k]" parameter
-
-Basically, all the program.local[] and program.env[] values will get mapped
-into the unified gl_program->Parameters array. This solves the problem of
-having three separate program parameter arrays.
-*/
-
-
-#include "main/glheader.h"
-#include "main/imports.h"
-#include "main/context.h"
-#include "main/mtypes.h"
-#include "arbprogparse.h"
-#include "programopt.h"
-#include "prog_parameter.h"
-#include "prog_statevars.h"
-#include "prog_instruction.h"
-#include "program_parser.h"
-
-
-void
-_mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target,
- const GLvoid *str, GLsizei len,
- struct gl_fragment_program *program)
-{
- struct gl_program prog;
- struct asm_parser_state state;
- GLuint i;
-
- ASSERT(target == GL_FRAGMENT_PROGRAM_ARB);
-
- memset(&prog, 0, sizeof(prog));
- memset(&state, 0, sizeof(state));
- state.prog = &prog;
-
- if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len,
- &state)) {
- /* Error in the program. Just return. */
- return;
- }
-
- if (program->Base.String != NULL)
- free(program->Base.String);
-
- /* Copy the relevant contents of the arb_program struct into the
- * fragment_program struct.
- */
- program->Base.String = prog.String;
- program->Base.NumInstructions = prog.NumInstructions;
- program->Base.NumTemporaries = prog.NumTemporaries;
- program->Base.NumParameters = prog.NumParameters;
- program->Base.NumAttributes = prog.NumAttributes;
- program->Base.NumAddressRegs = prog.NumAddressRegs;
- program->Base.NumNativeInstructions = prog.NumNativeInstructions;
- program->Base.NumNativeTemporaries = prog.NumNativeTemporaries;
- program->Base.NumNativeParameters = prog.NumNativeParameters;
- program->Base.NumNativeAttributes = prog.NumNativeAttributes;
- program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs;
- program->Base.NumAluInstructions = prog.NumAluInstructions;
- program->Base.NumTexInstructions = prog.NumTexInstructions;
- program->Base.NumTexIndirections = prog.NumTexIndirections;
- program->Base.NumNativeAluInstructions = prog.NumAluInstructions;
- program->Base.NumNativeTexInstructions = prog.NumTexInstructions;
- program->Base.NumNativeTexIndirections = prog.NumTexIndirections;
- program->Base.InputsRead = prog.InputsRead;
- program->Base.OutputsWritten = prog.OutputsWritten;
- program->Base.IndirectRegisterFiles = prog.IndirectRegisterFiles;
- for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++) {
- program->Base.TexturesUsed[i] = prog.TexturesUsed[i];
- if (prog.TexturesUsed[i])
- program->Base.SamplersUsed |= (1 << i);
- }
- program->Base.ShadowSamplers = prog.ShadowSamplers;
- switch (state.option.Fog) {
- case OPTION_FOG_EXP: program->FogOption = GL_EXP; break;
- case OPTION_FOG_EXP2: program->FogOption = GL_EXP2; break;
- case OPTION_FOG_LINEAR: program->FogOption = GL_LINEAR; break;
- default: program->FogOption = GL_NONE; break;
- }
- program->OriginUpperLeft = state.option.OriginUpperLeft;
- program->PixelCenterInteger = state.option.PixelCenterInteger;
-
- program->UsesKill = state.fragment.UsesKill;
-
- if (program->FogOption)
- program->Base.InputsRead |= FRAG_BIT_FOGC;
-
- if (program->Base.Instructions)
- free(program->Base.Instructions);
- program->Base.Instructions = prog.Instructions;
-
- if (program->Base.Parameters)
- _mesa_free_parameter_list(program->Base.Parameters);
- program->Base.Parameters = prog.Parameters;
-
- /* Append fog instructions now if the program has "OPTION ARB_fog_exp"
- * or similar. We used to leave this up to drivers, but it appears
- * there's no hardware that wants to do fog in a discrete stage separate
- * from the fragment shader.
- */
- if (program->FogOption != GL_NONE) {
- _mesa_append_fog_code(ctx, program);
- program->FogOption = GL_NONE;
- }
-
-#if DEBUG_FP
- printf("____________Fragment program %u ________\n", program->Base.Id);
- _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 gl_program prog;
- struct asm_parser_state state;
-
- ASSERT(target == GL_VERTEX_PROGRAM_ARB);
-
- memset(&prog, 0, sizeof(prog));
- memset(&state, 0, sizeof(state));
- state.prog = &prog;
-
- if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len,
- &state)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramString(bad program)");
- return;
- }
-
- if (program->Base.String != NULL)
- free(program->Base.String);
-
- /* Copy the relevant contents of the arb_program struct into the
- * vertex_program struct.
- */
- program->Base.String = prog.String;
- program->Base.NumInstructions = prog.NumInstructions;
- program->Base.NumTemporaries = prog.NumTemporaries;
- program->Base.NumParameters = prog.NumParameters;
- program->Base.NumAttributes = prog.NumAttributes;
- program->Base.NumAddressRegs = prog.NumAddressRegs;
- program->Base.NumNativeInstructions = prog.NumNativeInstructions;
- program->Base.NumNativeTemporaries = prog.NumNativeTemporaries;
- program->Base.NumNativeParameters = prog.NumNativeParameters;
- program->Base.NumNativeAttributes = prog.NumNativeAttributes;
- program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs;
- program->Base.InputsRead = prog.InputsRead;
- program->Base.OutputsWritten = prog.OutputsWritten;
- program->Base.IndirectRegisterFiles = prog.IndirectRegisterFiles;
- program->IsPositionInvariant = (state.option.PositionInvariant)
- ? GL_TRUE : GL_FALSE;
-
- if (program->Base.Instructions)
- free(program->Base.Instructions);
- program->Base.Instructions = prog.Instructions;
-
- if (program->Base.Parameters)
- _mesa_free_parameter_list(program->Base.Parameters);
- program->Base.Parameters = prog.Parameters;
-
-#if DEBUG_VP
- printf("____________Vertex program %u __________\n", program->Base.Id);
- _mesa_print_program(&program->Base);
-#endif
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2008 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
+ */
+
+/**
+Notes on program parameters, etc.
+
+The instructions we emit will use six kinds of source registers:
+
+ PROGRAM_INPUT - input registers
+ PROGRAM_TEMPORARY - temp registers
+ PROGRAM_ADDRESS - address/indirect register
+ PROGRAM_SAMPLER - texture sampler
+ PROGRAM_CONSTANT - indexes into program->Parameters, a known constant/literal
+ PROGRAM_STATE_VAR - indexes into program->Parameters, and may actually be:
+ + a state variable, like "state.fog.color", or
+ + a pointer to a "program.local[k]" parameter, or
+ + a pointer to a "program.env[k]" parameter
+
+Basically, all the program.local[] and program.env[] values will get mapped
+into the unified gl_program->Parameters array. This solves the problem of
+having three separate program parameter arrays.
+*/
+
+
+#include "main/glheader.h"
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/mtypes.h"
+#include "arbprogparse.h"
+#include "programopt.h"
+#include "prog_parameter.h"
+#include "prog_statevars.h"
+#include "prog_instruction.h"
+#include "program_parser.h"
+
+
+void
+_mesa_parse_arb_fragment_program(struct gl_context* ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_fragment_program *program)
+{
+ struct gl_program prog;
+ struct asm_parser_state state;
+ GLuint i;
+
+ ASSERT(target == GL_FRAGMENT_PROGRAM_ARB);
+
+ memset(&prog, 0, sizeof(prog));
+ memset(&state, 0, sizeof(state));
+ state.prog = &prog;
+
+ if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len,
+ &state)) {
+ /* Error in the program. Just return. */
+ return;
+ }
+
+ if (program->Base.String != NULL)
+ free(program->Base.String);
+
+ /* Copy the relevant contents of the arb_program struct into the
+ * fragment_program struct.
+ */
+ program->Base.String = prog.String;
+ program->Base.NumInstructions = prog.NumInstructions;
+ program->Base.NumTemporaries = prog.NumTemporaries;
+ program->Base.NumParameters = prog.NumParameters;
+ program->Base.NumAttributes = prog.NumAttributes;
+ program->Base.NumAddressRegs = prog.NumAddressRegs;
+ program->Base.NumNativeInstructions = prog.NumNativeInstructions;
+ program->Base.NumNativeTemporaries = prog.NumNativeTemporaries;
+ program->Base.NumNativeParameters = prog.NumNativeParameters;
+ program->Base.NumNativeAttributes = prog.NumNativeAttributes;
+ program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs;
+ program->Base.NumAluInstructions = prog.NumAluInstructions;
+ program->Base.NumTexInstructions = prog.NumTexInstructions;
+ program->Base.NumTexIndirections = prog.NumTexIndirections;
+ program->Base.NumNativeAluInstructions = prog.NumAluInstructions;
+ program->Base.NumNativeTexInstructions = prog.NumTexInstructions;
+ program->Base.NumNativeTexIndirections = prog.NumTexIndirections;
+ program->Base.InputsRead = prog.InputsRead;
+ program->Base.OutputsWritten = prog.OutputsWritten;
+ program->Base.IndirectRegisterFiles = prog.IndirectRegisterFiles;
+ for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++) {
+ program->Base.TexturesUsed[i] = prog.TexturesUsed[i];
+ if (prog.TexturesUsed[i])
+ program->Base.SamplersUsed |= (1 << i);
+ }
+ program->Base.ShadowSamplers = prog.ShadowSamplers;
+ switch (state.option.Fog) {
+ case OPTION_FOG_EXP: program->FogOption = GL_EXP; break;
+ case OPTION_FOG_EXP2: program->FogOption = GL_EXP2; break;
+ case OPTION_FOG_LINEAR: program->FogOption = GL_LINEAR; break;
+ default: program->FogOption = GL_NONE; break;
+ }
+ program->OriginUpperLeft = state.option.OriginUpperLeft;
+ program->PixelCenterInteger = state.option.PixelCenterInteger;
+
+ program->UsesKill = state.fragment.UsesKill;
+
+ if (program->FogOption)
+ program->Base.InputsRead |= FRAG_BIT_FOGC;
+
+ if (program->Base.Instructions)
+ free(program->Base.Instructions);
+ program->Base.Instructions = prog.Instructions;
+
+ if (program->Base.Parameters)
+ _mesa_free_parameter_list(program->Base.Parameters);
+ program->Base.Parameters = prog.Parameters;
+
+ /* Append fog instructions now if the program has "OPTION ARB_fog_exp"
+ * or similar. We used to leave this up to drivers, but it appears
+ * there's no hardware that wants to do fog in a discrete stage separate
+ * from the fragment shader.
+ */
+ if (program->FogOption != GL_NONE) {
+ _mesa_append_fog_code(ctx, program);
+ program->FogOption = GL_NONE;
+ }
+
+#if DEBUG_FP
+ printf("____________Fragment program %u ________\n", program->Base.Id);
+ _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(struct gl_context *ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_vertex_program *program)
+{
+ struct gl_program prog;
+ struct asm_parser_state state;
+
+ ASSERT(target == GL_VERTEX_PROGRAM_ARB);
+
+ memset(&prog, 0, sizeof(prog));
+ memset(&state, 0, sizeof(state));
+ state.prog = &prog;
+
+ if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len,
+ &state)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramString(bad program)");
+ return;
+ }
+
+ if (program->Base.String != NULL)
+ free(program->Base.String);
+
+ /* Copy the relevant contents of the arb_program struct into the
+ * vertex_program struct.
+ */
+ program->Base.String = prog.String;
+ program->Base.NumInstructions = prog.NumInstructions;
+ program->Base.NumTemporaries = prog.NumTemporaries;
+ program->Base.NumParameters = prog.NumParameters;
+ program->Base.NumAttributes = prog.NumAttributes;
+ program->Base.NumAddressRegs = prog.NumAddressRegs;
+ program->Base.NumNativeInstructions = prog.NumNativeInstructions;
+ program->Base.NumNativeTemporaries = prog.NumNativeTemporaries;
+ program->Base.NumNativeParameters = prog.NumNativeParameters;
+ program->Base.NumNativeAttributes = prog.NumNativeAttributes;
+ program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs;
+ program->Base.InputsRead = prog.InputsRead;
+ program->Base.OutputsWritten = prog.OutputsWritten;
+ program->Base.IndirectRegisterFiles = prog.IndirectRegisterFiles;
+ program->IsPositionInvariant = (state.option.PositionInvariant)
+ ? GL_TRUE : GL_FALSE;
+
+ if (program->Base.Instructions)
+ free(program->Base.Instructions);
+ program->Base.Instructions = prog.Instructions;
+
+ if (program->Base.Parameters)
+ _mesa_free_parameter_list(program->Base.Parameters);
+ program->Base.Parameters = prog.Parameters;
+
+#if DEBUG_VP
+ printf("____________Vertex program %u __________\n", program->Base.Id);
+ _mesa_print_program(&program->Base);
+#endif
+}
diff --git a/mesalib/src/mesa/program/arbprogparse.h b/mesalib/src/mesa/program/arbprogparse.h
index 980d39fb9..a9fe1e941 100644
--- a/mesalib/src/mesa/program/arbprogparse.h
+++ b/mesalib/src/mesa/program/arbprogparse.h
@@ -1,41 +1,45 @@
-/*
- * 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 "main/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
+/*
+ * 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 "main/glheader.h"
+
+struct gl_context;
+struct gl_fragment_program;
+struct gl_vertex_program;
+
+extern void
+_mesa_parse_arb_vertex_program(struct gl_context *ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_vertex_program *program);
+
+extern void
+_mesa_parse_arb_fragment_program(struct gl_context *ctx, GLenum target,
+ const GLvoid *str, GLsizei len,
+ struct gl_fragment_program *program);
+
+#endif
diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp
index 93b6c305f..02ca83d47 100644
--- a/mesalib/src/mesa/program/ir_to_mesa.cpp
+++ b/mesalib/src/mesa/program/ir_to_mesa.cpp
@@ -1,2965 +1,3074 @@
-/*
- * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
- * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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 ir_to_mesa.cpp
- *
- * Translates the IR to ARB_fragment_program text if possible,
- * printing the result
- */
-
-#include <stdio.h>
-#include "main/compiler.h"
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_print_visitor.h"
-#include "ir_expression_flattening.h"
-#include "glsl_types.h"
-#include "glsl_parser_extras.h"
-#include "../glsl/program.h"
-#include "ir_optimization.h"
-#include "ast.h"
-
-extern "C" {
-#include "main/mtypes.h"
-#include "main/shaderapi.h"
-#include "main/shaderobj.h"
-#include "main/uniforms.h"
-#include "program/hash_table.h"
-#include "program/prog_instruction.h"
-#include "program/prog_optimize.h"
-#include "program/prog_print.h"
-#include "program/program.h"
-#include "program/prog_uniform.h"
-#include "program/prog_parameter.h"
-}
-
-static int swizzle_for_size(int size);
-
-/**
- * This struct is a corresponding struct to Mesa prog_src_register, with
- * wider fields.
- */
-typedef struct ir_to_mesa_src_reg {
- ir_to_mesa_src_reg(int file, int index, const glsl_type *type)
- {
- this->file = file;
- this->index = index;
- if (type && (type->is_scalar() || type->is_vector() || type->is_matrix()))
- this->swizzle = swizzle_for_size(type->vector_elements);
- else
- this->swizzle = SWIZZLE_XYZW;
- this->negate = 0;
- this->reladdr = NULL;
- }
-
- ir_to_mesa_src_reg()
- {
- this->file = PROGRAM_UNDEFINED;
- this->index = 0;
- this->swizzle = 0;
- this->negate = 0;
- this->reladdr = NULL;
- }
-
- int file; /**< PROGRAM_* from Mesa */
- int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
- GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
- int negate; /**< NEGATE_XYZW mask from mesa */
- /** Register index should be offset by the integer in this reg. */
- ir_to_mesa_src_reg *reladdr;
-} ir_to_mesa_src_reg;
-
-typedef struct ir_to_mesa_dst_reg {
- int file; /**< PROGRAM_* from Mesa */
- int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
- int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
- GLuint cond_mask:4;
- /** Register index should be offset by the integer in this reg. */
- ir_to_mesa_src_reg *reladdr;
-} ir_to_mesa_dst_reg;
-
-extern ir_to_mesa_src_reg ir_to_mesa_undef;
-
-class ir_to_mesa_instruction : public exec_node {
-public:
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'ctx' (or any of its ancestors). */
- static void* operator new(size_t size, void *ctx)
- {
- void *node;
-
- node = talloc_zero_size(ctx, size);
- assert(node != NULL);
-
- return node;
- }
-
- enum prog_opcode op;
- ir_to_mesa_dst_reg dst_reg;
- ir_to_mesa_src_reg src_reg[3];
- /** Pointer to the ir source this tree came from for debugging */
- ir_instruction *ir;
- GLboolean cond_update;
- int sampler; /**< sampler index */
- int tex_target; /**< One of TEXTURE_*_INDEX */
- GLboolean tex_shadow;
-
- class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */
-};
-
-class variable_storage : public exec_node {
-public:
- variable_storage(ir_variable *var, int file, int index)
- : file(file), index(index), var(var)
- {
- /* empty */
- }
-
- int file;
- int index;
- ir_variable *var; /* variable that maps to this, if any */
-};
-
-class function_entry : public exec_node {
-public:
- ir_function_signature *sig;
-
- /**
- * identifier of this function signature used by the program.
- *
- * At the point that Mesa instructions for function calls are
- * generated, we don't know the address of the first instruction of
- * the function body. So we make the BranchTarget that is called a
- * small integer and rewrite them during set_branchtargets().
- */
- int sig_id;
-
- /**
- * Pointer to first instruction of the function body.
- *
- * Set during function body emits after main() is processed.
- */
- ir_to_mesa_instruction *bgn_inst;
-
- /**
- * Index of the first instruction of the function body in actual
- * Mesa IR.
- *
- * Set after convertion from ir_to_mesa_instruction to prog_instruction.
- */
- int inst;
-
- /** Storage for the return value. */
- ir_to_mesa_src_reg return_reg;
-};
-
-class ir_to_mesa_visitor : public ir_visitor {
-public:
- ir_to_mesa_visitor();
- ~ir_to_mesa_visitor();
-
- function_entry *current_function;
-
- GLcontext *ctx;
- struct gl_program *prog;
- struct gl_shader_program *shader_program;
- struct gl_shader_compiler_options *options;
-
- int next_temp;
-
- variable_storage *find_variable_storage(ir_variable *var);
-
- function_entry *get_function_signature(ir_function_signature *sig);
-
- ir_to_mesa_src_reg get_temp(const glsl_type *type);
- void reladdr_to_temp(ir_instruction *ir,
- ir_to_mesa_src_reg *reg, int *num_reladdr);
-
- struct ir_to_mesa_src_reg src_reg_for_float(float val);
-
- /**
- * \name Visit methods
- *
- * As typical for the visitor pattern, there must be one \c visit method for
- * each concrete subclass of \c ir_instruction. Virtual base classes within
- * the hierarchy should not have \c visit methods.
- */
- /*@{*/
- virtual void visit(ir_variable *);
- virtual void visit(ir_loop *);
- virtual void visit(ir_loop_jump *);
- virtual void visit(ir_function_signature *);
- virtual void visit(ir_function *);
- virtual void visit(ir_expression *);
- virtual void visit(ir_swizzle *);
- virtual void visit(ir_dereference_variable *);
- virtual void visit(ir_dereference_array *);
- virtual void visit(ir_dereference_record *);
- virtual void visit(ir_assignment *);
- virtual void visit(ir_constant *);
- virtual void visit(ir_call *);
- virtual void visit(ir_return *);
- virtual void visit(ir_discard *);
- virtual void visit(ir_texture *);
- virtual void visit(ir_if *);
- /*@}*/
-
- struct ir_to_mesa_src_reg result;
-
- /** List of variable_storage */
- exec_list variables;
-
- /** List of function_entry */
- exec_list function_signatures;
- int next_signature_id;
-
- /** List of ir_to_mesa_instruction */
- exec_list instructions;
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op0(ir_instruction *ir,
- enum prog_opcode op);
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0);
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1);
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1,
- ir_to_mesa_src_reg src2);
-
- void ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0);
-
- void ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1);
-
- GLboolean try_emit_mad(ir_expression *ir,
- int mul_operand);
-
- int get_sampler_uniform_value(ir_dereference *deref);
-
- void *mem_ctx;
-};
-
-ir_to_mesa_src_reg ir_to_mesa_undef = ir_to_mesa_src_reg(PROGRAM_UNDEFINED, 0, NULL);
-
-ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
- PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL,
-};
-
-ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
- PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL
-};
-
-static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
-
-static void fail_link(struct gl_shader_program *prog, const char *fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, args);
- va_end(args);
-
- prog->LinkStatus = GL_FALSE;
- }
-
-static int swizzle_for_size(int size)
-{
- int size_swizzles[4] = {
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
- };
-
- return size_swizzles[size - 1];
-}
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1,
- ir_to_mesa_src_reg src2)
-{
- ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction();
- int num_reladdr = 0;
-
- /* If we have to do relative addressing, we want to load the ARL
- * reg directly for one of the regs, and preload the other reladdr
- * sources into temps.
- */
- num_reladdr += dst.reladdr != NULL;
- num_reladdr += src0.reladdr != NULL;
- num_reladdr += src1.reladdr != NULL;
- num_reladdr += src2.reladdr != NULL;
-
- reladdr_to_temp(ir, &src2, &num_reladdr);
- reladdr_to_temp(ir, &src1, &num_reladdr);
- reladdr_to_temp(ir, &src0, &num_reladdr);
-
- if (dst.reladdr) {
- ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
- *dst.reladdr);
-
- num_reladdr--;
- }
- assert(num_reladdr == 0);
-
- inst->op = op;
- inst->dst_reg = dst;
- inst->src_reg[0] = src0;
- inst->src_reg[1] = src1;
- inst->src_reg[2] = src2;
- inst->ir = ir;
-
- inst->function = NULL;
-
- this->instructions.push_tail(inst);
-
- return inst;
-}
-
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1)
-{
- return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef);
-}
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0)
-{
- assert(dst.writemask != 0);
- return ir_to_mesa_emit_op3(ir, op, dst,
- src0, ir_to_mesa_undef, ir_to_mesa_undef);
-}
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir,
- enum prog_opcode op)
-{
- return ir_to_mesa_emit_op3(ir, op, ir_to_mesa_undef_dst,
- ir_to_mesa_undef,
- ir_to_mesa_undef,
- ir_to_mesa_undef);
-}
-
-inline ir_to_mesa_dst_reg
-ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
-{
- ir_to_mesa_dst_reg dst_reg;
-
- dst_reg.file = reg.file;
- dst_reg.index = reg.index;
- dst_reg.writemask = WRITEMASK_XYZW;
- dst_reg.cond_mask = COND_TR;
- dst_reg.reladdr = reg.reladdr;
-
- return dst_reg;
-}
-
-inline ir_to_mesa_src_reg
-ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
-{
- return ir_to_mesa_src_reg(reg.file, reg.index, NULL);
-}
-
-/**
- * Emits Mesa scalar opcodes to produce unique answers across channels.
- *
- * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X
- * channel determines the result across all channels. So to do a vec4
- * of this operation, we want to emit a scalar per source channel used
- * to produce dest channels.
- */
-void
-ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg orig_src0,
- ir_to_mesa_src_reg orig_src1)
-{
- int i, j;
- int done_mask = ~dst.writemask;
-
- /* Mesa RCP is a scalar operation splatting results to all channels,
- * like ARB_fp/vp. So emit as many RCPs as necessary to cover our
- * dst channels.
- */
- for (i = 0; i < 4; i++) {
- GLuint this_mask = (1 << i);
- ir_to_mesa_instruction *inst;
- ir_to_mesa_src_reg src0 = orig_src0;
- ir_to_mesa_src_reg src1 = orig_src1;
-
- if (done_mask & this_mask)
- continue;
-
- GLuint src0_swiz = GET_SWZ(src0.swizzle, i);
- GLuint src1_swiz = GET_SWZ(src1.swizzle, i);
- for (j = i + 1; j < 4; j++) {
- if (!(done_mask & (1 << j)) &&
- GET_SWZ(src0.swizzle, j) == src0_swiz &&
- GET_SWZ(src1.swizzle, j) == src1_swiz) {
- this_mask |= (1 << j);
- }
- }
- src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
- src0_swiz, src0_swiz);
- src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz,
- src1_swiz, src1_swiz);
-
- inst = ir_to_mesa_emit_op2(ir, op,
- dst,
- src0,
- src1);
- inst->dst_reg.writemask = this_mask;
- done_mask |= this_mask;
- }
-}
-
-void
-ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0)
-{
- ir_to_mesa_src_reg undef = ir_to_mesa_undef;
-
- undef.swizzle = SWIZZLE_XXXX;
-
- ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef);
-}
-
-struct ir_to_mesa_src_reg
-ir_to_mesa_visitor::src_reg_for_float(float val)
-{
- ir_to_mesa_src_reg src_reg(PROGRAM_CONSTANT, -1, NULL);
-
- src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- &val, 1, &src_reg.swizzle);
-
- return src_reg;
-}
-
-static int
-type_size(const struct glsl_type *type)
-{
- unsigned int i;
- int size;
-
- switch (type->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_BOOL:
- if (type->is_matrix()) {
- return type->matrix_columns;
- } else {
- /* Regardless of size of vector, it gets a vec4. This is bad
- * packing for things like floats, but otherwise arrays become a
- * mess. Hopefully a later pass over the code can pack scalars
- * down if appropriate.
- */
- return 1;
- }
- case GLSL_TYPE_ARRAY:
- return type_size(type->fields.array) * type->length;
- case GLSL_TYPE_STRUCT:
- size = 0;
- for (i = 0; i < type->length; i++) {
- size += type_size(type->fields.structure[i].type);
- }
- return size;
- case GLSL_TYPE_SAMPLER:
- /* Samplers take up one slot in UNIFORMS[], but they're baked in
- * at link time.
- */
- return 1;
- default:
- assert(0);
- return 0;
- }
-}
-
-/**
- * In the initial pass of codegen, we assign temporary numbers to
- * intermediate results. (not SSA -- variable assignments will reuse
- * storage). Actual register allocation for the Mesa VM occurs in a
- * pass over the Mesa IR later.
- */
-ir_to_mesa_src_reg
-ir_to_mesa_visitor::get_temp(const glsl_type *type)
-{
- ir_to_mesa_src_reg src_reg;
- int swizzle[4];
- int i;
-
- src_reg.file = PROGRAM_TEMPORARY;
- src_reg.index = next_temp;
- src_reg.reladdr = NULL;
- next_temp += type_size(type);
-
- if (type->is_array() || type->is_record()) {
- src_reg.swizzle = SWIZZLE_NOOP;
- } else {
- for (i = 0; i < type->vector_elements; i++)
- swizzle[i] = i;
- for (; i < 4; i++)
- swizzle[i] = type->vector_elements - 1;
- src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
- swizzle[2], swizzle[3]);
- }
- src_reg.negate = 0;
-
- return src_reg;
-}
-
-variable_storage *
-ir_to_mesa_visitor::find_variable_storage(ir_variable *var)
-{
-
- variable_storage *entry;
-
- foreach_iter(exec_list_iterator, iter, this->variables) {
- entry = (variable_storage *)iter.get();
-
- if (entry->var == var)
- return entry;
- }
-
- return NULL;
-}
-
-struct statevar_element {
- const char *field;
- int tokens[STATE_LENGTH];
- int swizzle;
-};
-
-static struct statevar_element gl_DepthRange_elements[] = {
- {"near", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_XXXX},
- {"far", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_YYYY},
- {"diff", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_ZZZZ},
-};
-
-static struct statevar_element gl_ClipPlane_elements[] = {
- {NULL, {STATE_CLIPPLANE, 0, 0}, SWIZZLE_XYZW}
-};
-
-static struct statevar_element gl_Point_elements[] = {
- {"size", {STATE_POINT_SIZE}, SWIZZLE_XXXX},
- {"sizeMin", {STATE_POINT_SIZE}, SWIZZLE_YYYY},
- {"sizeMax", {STATE_POINT_SIZE}, SWIZZLE_ZZZZ},
- {"fadeThresholdSize", {STATE_POINT_SIZE}, SWIZZLE_WWWW},
- {"distanceConstantAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_XXXX},
- {"distanceLinearAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_YYYY},
- {"distanceQuadraticAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_ZZZZ},
-};
-
-static struct statevar_element gl_FrontMaterial_elements[] = {
- {"emission", {STATE_MATERIAL, 0, STATE_EMISSION}, SWIZZLE_XYZW},
- {"ambient", {STATE_MATERIAL, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_MATERIAL, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_MATERIAL, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
- {"shininess", {STATE_MATERIAL, 0, STATE_SHININESS}, SWIZZLE_XXXX},
-};
-
-static struct statevar_element gl_BackMaterial_elements[] = {
- {"emission", {STATE_MATERIAL, 1, STATE_EMISSION}, SWIZZLE_XYZW},
- {"ambient", {STATE_MATERIAL, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_MATERIAL, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_MATERIAL, 1, STATE_SPECULAR}, SWIZZLE_XYZW},
- {"shininess", {STATE_MATERIAL, 1, STATE_SHININESS}, SWIZZLE_XXXX},
-};
-
-static struct statevar_element gl_LightSource_elements[] = {
- {"ambient", {STATE_LIGHT, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_LIGHT, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_LIGHT, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
- {"position", {STATE_LIGHT, 0, STATE_POSITION}, SWIZZLE_XYZW},
- {"halfVector", {STATE_LIGHT, 0, STATE_HALF_VECTOR}, SWIZZLE_XYZW},
- {"spotDirection", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION}, SWIZZLE_XYZW},
- {"spotCosCutoff", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION}, SWIZZLE_WWWW},
- {"spotCutoff", {STATE_LIGHT, 0, STATE_SPOT_CUTOFF}, SWIZZLE_XXXX},
- {"spotExponent", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_WWWW},
- {"constantAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_XXXX},
- {"linearAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_YYYY},
- {"quadraticAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_ZZZZ},
-};
-
-static struct statevar_element gl_LightModel_elements[] = {
- {"ambient", {STATE_LIGHTMODEL_AMBIENT, 0}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_FrontLightModelProduct_elements[] = {
- {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 0}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_BackLightModelProduct_elements[] = {
- {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 1}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_FrontLightProduct_elements[] = {
- {"ambient", {STATE_LIGHTPROD, 0, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_LIGHTPROD, 0, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_LIGHTPROD, 0, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_BackLightProduct_elements[] = {
- {"ambient", {STATE_LIGHTPROD, 0, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_LIGHTPROD, 0, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_LIGHTPROD, 0, 1, STATE_SPECULAR}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_TextureEnvColor_elements[] = {
- {NULL, {STATE_TEXENV_COLOR, 0}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_EyePlaneS_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_S}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_EyePlaneT_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_T}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_EyePlaneR_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_R}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_EyePlaneQ_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_Q}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_ObjectPlaneS_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_S}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_ObjectPlaneT_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_T}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_ObjectPlaneR_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_R}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_ObjectPlaneQ_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_Q}, SWIZZLE_XYZW},
-};
-
-static struct statevar_element gl_Fog_elements[] = {
- {"color", {STATE_FOG_COLOR}, SWIZZLE_XYZW},
- {"density", {STATE_FOG_PARAMS}, SWIZZLE_XXXX},
- {"start", {STATE_FOG_PARAMS}, SWIZZLE_YYYY},
- {"end", {STATE_FOG_PARAMS}, SWIZZLE_ZZZZ},
- {"scale", {STATE_FOG_PARAMS}, SWIZZLE_WWWW},
-};
-
-static struct statevar_element gl_NormalScale_elements[] = {
- {NULL, {STATE_NORMAL_SCALE}, SWIZZLE_XXXX},
-};
-
-#define MATRIX(name, statevar, modifier) \
- static struct statevar_element name ## _elements[] = { \
- { NULL, { statevar, 0, 0, 0, modifier}, SWIZZLE_XYZW }, \
- { NULL, { statevar, 0, 1, 1, modifier}, SWIZZLE_XYZW }, \
- { NULL, { statevar, 0, 2, 2, modifier}, SWIZZLE_XYZW }, \
- { NULL, { statevar, 0, 3, 3, modifier}, SWIZZLE_XYZW }, \
- }
-
-MATRIX(gl_ModelViewMatrix,
- STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_ModelViewMatrixInverse,
- STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_ModelViewMatrixTranspose,
- STATE_MODELVIEW_MATRIX, 0);
-MATRIX(gl_ModelViewMatrixInverseTranspose,
- STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE);
-
-MATRIX(gl_ProjectionMatrix,
- STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_ProjectionMatrixInverse,
- STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_ProjectionMatrixTranspose,
- STATE_PROJECTION_MATRIX, 0);
-MATRIX(gl_ProjectionMatrixInverseTranspose,
- STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE);
-
-MATRIX(gl_ModelViewProjectionMatrix,
- STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_ModelViewProjectionMatrixInverse,
- STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_ModelViewProjectionMatrixTranspose,
- STATE_MVP_MATRIX, 0);
-MATRIX(gl_ModelViewProjectionMatrixInverseTranspose,
- STATE_MVP_MATRIX, STATE_MATRIX_INVERSE);
-
-MATRIX(gl_TextureMatrix,
- STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_TextureMatrixInverse,
- STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_TextureMatrixTranspose,
- STATE_TEXTURE_MATRIX, 0);
-MATRIX(gl_TextureMatrixInverseTranspose,
- STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE);
-
-static struct statevar_element gl_NormalMatrix_elements[] = {
- { NULL, { STATE_MODELVIEW_MATRIX, 0, 0, 0, STATE_MATRIX_INVERSE},
- SWIZZLE_XYZW },
- { NULL, { STATE_MODELVIEW_MATRIX, 0, 1, 1, STATE_MATRIX_INVERSE},
- SWIZZLE_XYZW },
- { NULL, { STATE_MODELVIEW_MATRIX, 0, 2, 2, STATE_MATRIX_INVERSE},
- SWIZZLE_XYZW },
-};
-
-#undef MATRIX
-
-#define STATEVAR(name) {#name, name ## _elements, Elements(name ## _elements)}
-
-static const struct statevar {
- const char *name;
- struct statevar_element *elements;
- unsigned int num_elements;
-} statevars[] = {
- STATEVAR(gl_DepthRange),
- STATEVAR(gl_ClipPlane),
- STATEVAR(gl_Point),
- STATEVAR(gl_FrontMaterial),
- STATEVAR(gl_BackMaterial),
- STATEVAR(gl_LightSource),
- STATEVAR(gl_LightModel),
- STATEVAR(gl_FrontLightModelProduct),
- STATEVAR(gl_BackLightModelProduct),
- STATEVAR(gl_FrontLightProduct),
- STATEVAR(gl_BackLightProduct),
- STATEVAR(gl_TextureEnvColor),
- STATEVAR(gl_EyePlaneS),
- STATEVAR(gl_EyePlaneT),
- STATEVAR(gl_EyePlaneR),
- STATEVAR(gl_EyePlaneQ),
- STATEVAR(gl_ObjectPlaneS),
- STATEVAR(gl_ObjectPlaneT),
- STATEVAR(gl_ObjectPlaneR),
- STATEVAR(gl_ObjectPlaneQ),
- STATEVAR(gl_Fog),
-
- STATEVAR(gl_ModelViewMatrix),
- STATEVAR(gl_ModelViewMatrixInverse),
- STATEVAR(gl_ModelViewMatrixTranspose),
- STATEVAR(gl_ModelViewMatrixInverseTranspose),
-
- STATEVAR(gl_ProjectionMatrix),
- STATEVAR(gl_ProjectionMatrixInverse),
- STATEVAR(gl_ProjectionMatrixTranspose),
- STATEVAR(gl_ProjectionMatrixInverseTranspose),
-
- STATEVAR(gl_ModelViewProjectionMatrix),
- STATEVAR(gl_ModelViewProjectionMatrixInverse),
- STATEVAR(gl_ModelViewProjectionMatrixTranspose),
- STATEVAR(gl_ModelViewProjectionMatrixInverseTranspose),
-
- STATEVAR(gl_TextureMatrix),
- STATEVAR(gl_TextureMatrixInverse),
- STATEVAR(gl_TextureMatrixTranspose),
- STATEVAR(gl_TextureMatrixInverseTranspose),
-
- STATEVAR(gl_NormalMatrix),
- STATEVAR(gl_NormalScale),
-};
-
-void
-ir_to_mesa_visitor::visit(ir_variable *ir)
-{
- if (strcmp(ir->name, "gl_FragCoord") == 0) {
- struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
-
- fp->OriginUpperLeft = ir->origin_upper_left;
- fp->PixelCenterInteger = ir->pixel_center_integer;
- }
-
- if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) {
- unsigned int i;
-
- for (i = 0; i < Elements(statevars); i++) {
- if (strcmp(ir->name, statevars[i].name) == 0)
- break;
- }
-
- if (i == Elements(statevars)) {
- fail_link(this->shader_program,
- "Failed to find builtin uniform `%s'\n", ir->name);
- return;
- }
-
- const struct statevar *statevar = &statevars[i];
-
- int array_count;
- if (ir->type->is_array()) {
- array_count = ir->type->length;
- } else {
- array_count = 1;
- }
-
- /* Check if this statevar's setup in the STATE file exactly
- * matches how we'll want to reference it as a
- * struct/array/whatever. If not, then we need to move it into
- * temporary storage and hope that it'll get copy-propagated
- * out.
- */
- for (i = 0; i < statevar->num_elements; i++) {
- if (statevar->elements[i].swizzle != SWIZZLE_XYZW) {
- break;
- }
- }
-
- struct variable_storage *storage;
- ir_to_mesa_dst_reg dst;
- if (i == statevar->num_elements) {
- /* We'll set the index later. */
- storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1);
- this->variables.push_tail(storage);
-
- dst = ir_to_mesa_undef_dst;
- } else {
- storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variables.push_tail(storage);
- this->next_temp += type_size(ir->type);
-
- dst = ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg(PROGRAM_TEMPORARY,
- storage->index,
- NULL));
- }
-
-
- for (int a = 0; a < array_count; a++) {
- for (unsigned int i = 0; i < statevar->num_elements; i++) {
- struct statevar_element *element = &statevar->elements[i];
- int tokens[STATE_LENGTH];
-
- memcpy(tokens, element->tokens, sizeof(element->tokens));
- if (ir->type->is_array()) {
- tokens[1] = a;
- }
-
- int index = _mesa_add_state_reference(this->prog->Parameters,
- (gl_state_index *)tokens);
-
- if (storage->file == PROGRAM_STATE_VAR) {
- if (storage->index == -1) {
- storage->index = index;
- } else {
- assert(index ==
- (int)(storage->index + a * statevar->num_elements + i));
- }
- } else {
- ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL);
- src.swizzle = element->swizzle;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src);
- /* even a float takes up a whole vec4 reg in a struct/array. */
- dst.index++;
- }
- }
- }
- if (storage->file == PROGRAM_TEMPORARY &&
- dst.index != storage->index + type_size(ir->type)) {
- fail_link(this->shader_program,
- "failed to load builtin uniform `%s' (%d/%d regs loaded)\n",
- ir->name, dst.index - storage->index,
- type_size(ir->type));
- }
- }
-}
-
-void
-ir_to_mesa_visitor::visit(ir_loop *ir)
-{
- ir_dereference_variable *counter = NULL;
-
- if (ir->counter != NULL)
- counter = new(ir) ir_dereference_variable(ir->counter);
-
- if (ir->from != NULL) {
- assert(ir->counter != NULL);
-
- ir_assignment *a = new(ir) ir_assignment(counter, ir->from, NULL);
-
- a->accept(this);
- delete a;
- }
-
- ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP);
-
- if (ir->to) {
- ir_expression *e =
- new(ir) ir_expression(ir->cmp, glsl_type::bool_type,
- counter, ir->to);
- ir_if *if_stmt = new(ir) ir_if(e);
-
- ir_loop_jump *brk = new(ir) ir_loop_jump(ir_loop_jump::jump_break);
-
- if_stmt->then_instructions.push_tail(brk);
-
- if_stmt->accept(this);
-
- delete if_stmt;
- delete e;
- delete brk;
- }
-
- visit_exec_list(&ir->body_instructions, this);
-
- if (ir->increment) {
- ir_expression *e =
- new(ir) ir_expression(ir_binop_add, counter->type,
- counter, ir->increment);
-
- ir_assignment *a = new(ir) ir_assignment(counter, e, NULL);
-
- a->accept(this);
- delete a;
- delete e;
- }
-
- ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP);
-}
-
-void
-ir_to_mesa_visitor::visit(ir_loop_jump *ir)
-{
- switch (ir->mode) {
- case ir_loop_jump::jump_break:
- ir_to_mesa_emit_op0(NULL, OPCODE_BRK);
- break;
- case ir_loop_jump::jump_continue:
- ir_to_mesa_emit_op0(NULL, OPCODE_CONT);
- break;
- }
-}
-
-
-void
-ir_to_mesa_visitor::visit(ir_function_signature *ir)
-{
- assert(0);
- (void)ir;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_function *ir)
-{
- /* Ignore function bodies other than main() -- we shouldn't see calls to
- * them since they should all be inlined before we get to ir_to_mesa.
- */
- if (strcmp(ir->name, "main") == 0) {
- const ir_function_signature *sig;
- exec_list empty;
-
- sig = ir->matching_signature(&empty);
-
- assert(sig);
-
- foreach_iter(exec_list_iterator, iter, sig->body) {
- ir_instruction *ir = (ir_instruction *)iter.get();
-
- ir->accept(this);
- }
- }
-}
-
-GLboolean
-ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
-{
- int nonmul_operand = 1 - mul_operand;
- ir_to_mesa_src_reg a, b, c;
-
- ir_expression *expr = ir->operands[mul_operand]->as_expression();
- if (!expr || expr->operation != ir_binop_mul)
- return false;
-
- expr->operands[0]->accept(this);
- a = this->result;
- expr->operands[1]->accept(this);
- b = this->result;
- ir->operands[nonmul_operand]->accept(this);
- c = this->result;
-
- this->result = get_temp(ir->type);
- ir_to_mesa_emit_op3(ir, OPCODE_MAD,
- ir_to_mesa_dst_reg_from_src(this->result), a, b, c);
-
- return true;
-}
-
-void
-ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir,
- ir_to_mesa_src_reg *reg, int *num_reladdr)
-{
- if (!reg->reladdr)
- return;
-
- ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, *reg->reladdr);
-
- if (*num_reladdr != 1) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
-
- ir_to_mesa_emit_op1(ir, OPCODE_MOV,
- ir_to_mesa_dst_reg_from_src(temp), *reg);
- *reg = temp;
- }
-
- (*num_reladdr)--;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_expression *ir)
-{
- unsigned int operand;
- struct ir_to_mesa_src_reg op[2];
- struct ir_to_mesa_src_reg result_src;
- struct ir_to_mesa_dst_reg result_dst;
- const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1);
- const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1);
- const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1);
-
- /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c)
- */
- if (ir->operation == ir_binop_add) {
- if (try_emit_mad(ir, 1))
- return;
- if (try_emit_mad(ir, 0))
- return;
- }
-
- for (operand = 0; operand < ir->get_num_operands(); operand++) {
- this->result.file = PROGRAM_UNDEFINED;
- ir->operands[operand]->accept(this);
- if (this->result.file == PROGRAM_UNDEFINED) {
- ir_print_visitor v;
- printf("Failed to get tree for expression operand:\n");
- ir->operands[operand]->accept(&v);
- exit(1);
- }
- op[operand] = this->result;
-
- /* Matrix expression operands should have been broken down to vector
- * operations already.
- */
- assert(!ir->operands[operand]->type->is_matrix());
- }
-
- int vector_elements = ir->operands[0]->type->vector_elements;
- if (ir->operands[1]) {
- vector_elements = MAX2(vector_elements,
- ir->operands[1]->type->vector_elements);
- }
-
- this->result.file = PROGRAM_UNDEFINED;
-
- /* Storage for our result. Ideally for an assignment we'd be using
- * the actual storage for the result here, instead.
- */
- result_src = get_temp(ir->type);
- /* convenience for the emit functions below. */
- result_dst = ir_to_mesa_dst_reg_from_src(result_src);
- /* Limit writes to the channels that will be used by result_src later.
- * This does limit this temp's use as a temporary for multi-instruction
- * sequences.
- */
- result_dst.writemask = (1 << ir->type->vector_elements) - 1;
-
- switch (ir->operation) {
- case ir_unop_logic_not:
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst,
- op[0], src_reg_for_float(0.0));
- break;
- case ir_unop_neg:
- op[0].negate = ~op[0].negate;
- result_src = op[0];
- break;
- case ir_unop_abs:
- ir_to_mesa_emit_op1(ir, OPCODE_ABS, result_dst, op[0]);
- break;
- case ir_unop_sign:
- ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]);
- break;
- case ir_unop_rcp:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[0]);
- break;
-
- case ir_unop_exp2:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
- break;
- case ir_unop_exp:
- case ir_unop_log:
- assert(!"not reached: should be handled by ir_explog_to_explog2");
- break;
- case ir_unop_log2:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]);
- break;
- case ir_unop_sin:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]);
- break;
- case ir_unop_cos:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
- break;
-
- case ir_unop_dFdx:
- ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]);
- break;
- case ir_unop_dFdy:
- ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]);
- break;
-
- case ir_unop_noise: {
- const enum prog_opcode opcode =
- prog_opcode(OPCODE_NOISE1
- + (ir->operands[0]->type->vector_elements) - 1);
- assert((opcode >= OPCODE_NOISE1) && (opcode <= OPCODE_NOISE4));
-
- ir_to_mesa_emit_op1(ir, opcode, result_dst, op[0]);
- break;
- }
-
- case ir_binop_add:
- ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]);
- break;
- case ir_binop_sub:
- ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]);
- break;
-
- case ir_binop_mul:
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
- break;
- case ir_binop_div:
- assert(!"not reached: should be handled by ir_div_to_mul_rcp");
- case ir_binop_mod:
- assert(!"ir_binop_mod should have been converted to b * fract(a/b)");
- break;
-
- case ir_binop_less:
- ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]);
- break;
- case ir_binop_greater:
- ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]);
- break;
- case ir_binop_lequal:
- ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]);
- break;
- case ir_binop_gequal:
- ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]);
- break;
- case ir_binop_equal:
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
- break;
- case ir_binop_nequal:
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
- break;
- case ir_binop_all_equal:
- /* "==" operator producing a scalar boolean. */
- if (ir->operands[0]->type->is_vector() ||
- ir->operands[1]->type->is_vector()) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
- if (vector_elements == 4)
- ir_to_mesa_emit_op2(ir, OPCODE_DP4, result_dst, temp, temp);
- else if (vector_elements == 3)
- ir_to_mesa_emit_op2(ir, OPCODE_DP3, result_dst, temp, temp);
- else
- ir_to_mesa_emit_op2(ir, OPCODE_DP2, result_dst, temp, temp);
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ,
- result_dst, result_src, src_reg_for_float(0.0));
- } else {
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
- }
- break;
- case ir_binop_any_nequal:
- /* "!=" operator producing a scalar boolean. */
- if (ir->operands[0]->type->is_vector() ||
- ir->operands[1]->type->is_vector()) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
- if (vector_elements == 4)
- ir_to_mesa_emit_op2(ir, OPCODE_DP4, result_dst, temp, temp);
- else if (vector_elements == 3)
- ir_to_mesa_emit_op2(ir, OPCODE_DP3, result_dst, temp, temp);
- else
- ir_to_mesa_emit_op2(ir, OPCODE_DP2, result_dst, temp, temp);
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- result_dst, result_src, src_reg_for_float(0.0));
- } else {
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
- }
- break;
-
- case ir_unop_any:
- switch (ir->operands[0]->type->vector_elements) {
- case 4:
- ir_to_mesa_emit_op2(ir, OPCODE_DP4, result_dst, op[0], op[0]);
- break;
- case 3:
- ir_to_mesa_emit_op2(ir, OPCODE_DP3, result_dst, op[0], op[0]);
- break;
- case 2:
- ir_to_mesa_emit_op2(ir, OPCODE_DP2, result_dst, op[0], op[0]);
- break;
- default:
- assert(!"unreached: ir_unop_any of non-bvec");
- break;
- }
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- result_dst, result_src, src_reg_for_float(0.0));
- break;
-
- case ir_binop_logic_xor:
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
- break;
-
- case ir_binop_logic_or:
- /* This could be a saturated add and skip the SNE. */
- ir_to_mesa_emit_op2(ir, OPCODE_ADD,
- result_dst,
- op[0], op[1]);
-
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- result_dst,
- result_src, src_reg_for_float(0.0));
- break;
-
- case ir_binop_logic_and:
- /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */
- ir_to_mesa_emit_op2(ir, OPCODE_MUL,
- result_dst,
- op[0], op[1]);
- break;
-
- case ir_binop_dot:
- if (ir->operands[0]->type == vec4_type) {
- assert(ir->operands[1]->type == vec4_type);
- ir_to_mesa_emit_op2(ir, OPCODE_DP4,
- result_dst,
- op[0], op[1]);
- } else if (ir->operands[0]->type == vec3_type) {
- assert(ir->operands[1]->type == vec3_type);
- ir_to_mesa_emit_op2(ir, OPCODE_DP3,
- result_dst,
- op[0], op[1]);
- } else if (ir->operands[0]->type == vec2_type) {
- assert(ir->operands[1]->type == vec2_type);
- ir_to_mesa_emit_op2(ir, OPCODE_DP2,
- result_dst,
- op[0], op[1]);
- }
- break;
-
- case ir_binop_cross:
- ir_to_mesa_emit_op2(ir, OPCODE_XPD, result_dst, op[0], op[1]);
- break;
-
- case ir_unop_sqrt:
- /* sqrt(x) = x * rsq(x). */
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, result_src, op[0]);
- /* For incoming channels <= 0, set the result to 0. */
- op[0].negate = ~op[0].negate;
- ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst,
- op[0], result_src, src_reg_for_float(0.0));
- break;
- case ir_unop_rsq:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
- break;
- case ir_unop_i2f:
- case ir_unop_b2f:
- case ir_unop_b2i:
- /* Mesa IR lacks types, ints are stored as truncated floats. */
- result_src = op[0];
- break;
- case ir_unop_f2i:
- ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
- break;
- case ir_unop_f2b:
- case ir_unop_i2b:
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
- op[0], src_reg_for_float(0.0));
- break;
- case ir_unop_trunc:
- ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
- break;
- case ir_unop_ceil:
- op[0].negate = ~op[0].negate;
- ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
- result_src.negate = ~result_src.negate;
- break;
- case ir_unop_floor:
- ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
- break;
- case ir_unop_fract:
- ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]);
- break;
-
- case ir_binop_min:
- ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]);
- break;
- case ir_binop_max:
- ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]);
- break;
- case ir_binop_pow:
- ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]);
- break;
-
- case ir_unop_bit_not:
- case ir_unop_u2f:
- case ir_binop_lshift:
- case ir_binop_rshift:
- case ir_binop_bit_and:
- case ir_binop_bit_xor:
- case ir_binop_bit_or:
- assert(!"GLSL 1.30 features unsupported");
- break;
- }
-
- this->result = result_src;
-}
-
-
-void
-ir_to_mesa_visitor::visit(ir_swizzle *ir)
-{
- ir_to_mesa_src_reg src_reg;
- int i;
- int swizzle[4];
-
- /* Note that this is only swizzles in expressions, not those on the left
- * hand side of an assignment, which do write masking. See ir_assignment
- * for that.
- */
-
- ir->val->accept(this);
- src_reg = this->result;
- assert(src_reg.file != PROGRAM_UNDEFINED);
-
- for (i = 0; i < 4; i++) {
- if (i < ir->type->vector_elements) {
- switch (i) {
- case 0:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x);
- break;
- case 1:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y);
- break;
- case 2:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z);
- break;
- case 3:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w);
- break;
- }
- } else {
- /* If the type is smaller than a vec4, replicate the last
- * channel out.
- */
- swizzle[i] = swizzle[ir->type->vector_elements - 1];
- }
- }
-
- src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
- swizzle[1],
- swizzle[2],
- swizzle[3]);
-
- this->result = src_reg;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
-{
- variable_storage *entry = find_variable_storage(ir->var);
-
- if (!entry) {
- switch (ir->var->mode) {
- case ir_var_uniform:
- entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_UNIFORM,
- ir->var->location);
- this->variables.push_tail(entry);
- break;
- case ir_var_in:
- case ir_var_out:
- case ir_var_inout:
- /* The linker assigns locations for varyings and attributes,
- * including deprecated builtins (like gl_Color), user-assign
- * generic attributes (glBindVertexLocation), and
- * user-defined varyings.
- *
- * FINISHME: We would hit this path for function arguments. Fix!
- */
- assert(ir->var->location != -1);
- if (ir->var->mode == ir_var_in ||
- ir->var->mode == ir_var_inout) {
- entry = new(mem_ctx) variable_storage(ir->var,
- PROGRAM_INPUT,
- ir->var->location);
-
- if (this->prog->Target == GL_VERTEX_PROGRAM_ARB &&
- ir->var->location >= VERT_ATTRIB_GENERIC0) {
- _mesa_add_attribute(prog->Attributes,
- ir->var->name,
- _mesa_sizeof_glsl_type(ir->var->type->gl_type),
- ir->var->type->gl_type,
- ir->var->location - VERT_ATTRIB_GENERIC0);
- }
- } else {
- entry = new(mem_ctx) variable_storage(ir->var,
- PROGRAM_OUTPUT,
- ir->var->location);
- }
-
- break;
- case ir_var_auto:
- case ir_var_temporary:
- entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variables.push_tail(entry);
-
- next_temp += type_size(ir->var->type);
- break;
- }
-
- if (!entry) {
- printf("Failed to make storage for %s\n", ir->var->name);
- exit(1);
- }
- }
-
- this->result = ir_to_mesa_src_reg(entry->file, entry->index, ir->var->type);
-}
-
-void
-ir_to_mesa_visitor::visit(ir_dereference_array *ir)
-{
- ir_constant *index;
- ir_to_mesa_src_reg src_reg;
- int element_size = type_size(ir->type);
-
- index = ir->array_index->constant_expression_value();
-
- ir->array->accept(this);
- src_reg = this->result;
-
- if (index) {
- src_reg.index += index->value.i[0] * element_size;
- } else {
- ir_to_mesa_src_reg array_base = this->result;
- /* Variable index array dereference. It eats the "vec4" of the
- * base of the array and an index that offsets the Mesa register
- * index.
- */
- ir->array_index->accept(this);
-
- ir_to_mesa_src_reg index_reg;
-
- if (element_size == 1) {
- index_reg = this->result;
- } else {
- index_reg = get_temp(glsl_type::float_type);
-
- ir_to_mesa_emit_op2(ir, OPCODE_MUL,
- ir_to_mesa_dst_reg_from_src(index_reg),
- this->result, src_reg_for_float(element_size));
- }
-
- src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg);
- memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
- }
-
- /* If the type is smaller than a vec4, replicate the last channel out. */
- if (ir->type->is_scalar() || ir->type->is_vector())
- src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
- else
- src_reg.swizzle = SWIZZLE_NOOP;
-
- this->result = src_reg;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_dereference_record *ir)
-{
- unsigned int i;
- const glsl_type *struct_type = ir->record->type;
- int offset = 0;
-
- ir->record->accept(this);
-
- for (i = 0; i < struct_type->length; i++) {
- if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
- break;
- offset += type_size(struct_type->fields.structure[i].type);
- }
- this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
- this->result.index += offset;
-}
-
-/**
- * We want to be careful in assignment setup to hit the actual storage
- * instead of potentially using a temporary like we might with the
- * ir_dereference handler.
- */
-static struct ir_to_mesa_dst_reg
-get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v)
-{
- /* The LHS must be a dereference. If the LHS is a variable indexed array
- * access of a vector, it must be separated into a series conditional moves
- * before reaching this point (see ir_vec_index_to_cond_assign).
- */
- assert(ir->as_dereference());
- ir_dereference_array *deref_array = ir->as_dereference_array();
- if (deref_array) {
- assert(!deref_array->array->type->is_vector());
- }
-
- /* Use the rvalue deref handler for the most part. We'll ignore
- * swizzles in it and write swizzles using writemask, though.
- */
- ir->accept(v);
- return ir_to_mesa_dst_reg_from_src(v->result);
-}
-
-void
-ir_to_mesa_visitor::visit(ir_assignment *ir)
-{
- struct ir_to_mesa_dst_reg l;
- struct ir_to_mesa_src_reg r;
- int i;
-
- ir->rhs->accept(this);
- r = this->result;
-
- l = get_assignment_lhs(ir->lhs, this);
-
- /* FINISHME: This should really set to the correct maximal writemask for each
- * FINISHME: component written (in the loops below). This case can only
- * FINISHME: occur for matrices, arrays, and structures.
- */
- if (ir->write_mask == 0) {
- assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector());
- l.writemask = WRITEMASK_XYZW;
- } else if (ir->lhs->type->is_scalar()) {
- /* FINISHME: This hack makes writing to gl_FragDepth, which lives in the
- * FINISHME: W component of fragment shader output zero, work correctly.
- */
- l.writemask = WRITEMASK_XYZW;
- } else {
- int swizzles[4];
- int first_enabled_chan = 0;
- int rhs_chan = 0;
-
- assert(ir->lhs->type->is_vector());
- l.writemask = ir->write_mask;
-
- for (int i = 0; i < 4; i++) {
- if (l.writemask & (1 << i)) {
- first_enabled_chan = GET_SWZ(r.swizzle, i);
- break;
- }
- }
-
- /* Swizzle a small RHS vector into the channels being written.
- *
- * glsl ir treats write_mask as dictating how many channels are
- * present on the RHS while Mesa IR treats write_mask as just
- * showing which channels of the vec4 RHS get written.
- */
- for (int i = 0; i < 4; i++) {
- if (l.writemask & (1 << i))
- swizzles[i] = GET_SWZ(r.swizzle, rhs_chan++);
- else
- swizzles[i] = first_enabled_chan;
- }
- r.swizzle = MAKE_SWIZZLE4(swizzles[0], swizzles[1],
- swizzles[2], swizzles[3]);
- }
-
- assert(l.file != PROGRAM_UNDEFINED);
- assert(r.file != PROGRAM_UNDEFINED);
-
- if (ir->condition) {
- ir_to_mesa_src_reg condition;
-
- ir->condition->accept(this);
- condition = this->result;
-
- /* We use the OPCODE_CMP (a < 0 ? b : c) for conditional moves,
- * and the condition we produced is 0.0 or 1.0. By flipping the
- * sign, we can choose which value OPCODE_CMP produces without
- * an extra computing the condition.
- */
- condition.negate = ~condition.negate;
- for (i = 0; i < type_size(ir->lhs->type); i++) {
- ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
- condition, r, ir_to_mesa_src_reg_from_dst(l));
- l.index++;
- r.index++;
- }
- } else {
- for (i = 0; i < type_size(ir->lhs->type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-}
-
-
-void
-ir_to_mesa_visitor::visit(ir_constant *ir)
-{
- ir_to_mesa_src_reg src_reg;
- GLfloat stack_vals[4] = { 0 };
- GLfloat *values = stack_vals;
- unsigned int i;
-
- /* Unfortunately, 4 floats is all we can get into
- * _mesa_add_unnamed_constant. So, make a temp to store an
- * aggregate constant and move each constant value into it. If we
- * get lucky, copy propagation will eliminate the extra moves.
- */
-
- if (ir->type->base_type == GLSL_TYPE_STRUCT) {
- ir_to_mesa_src_reg temp_base = get_temp(ir->type);
- ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
-
- foreach_iter(exec_list_iterator, iter, ir->components) {
- ir_constant *field_value = (ir_constant *)iter.get();
- int size = type_size(field_value->type);
-
- assert(size > 0);
-
- field_value->accept(this);
- src_reg = this->result;
-
- for (i = 0; i < (unsigned int)size; i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
-
- src_reg.index++;
- temp.index++;
- }
- }
- this->result = temp_base;
- return;
- }
-
- if (ir->type->is_array()) {
- ir_to_mesa_src_reg temp_base = get_temp(ir->type);
- ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
- int size = type_size(ir->type->fields.array);
-
- assert(size > 0);
-
- for (i = 0; i < ir->type->length; i++) {
- ir->array_elements[i]->accept(this);
- src_reg = this->result;
- for (int j = 0; j < size; j++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
-
- src_reg.index++;
- temp.index++;
- }
- }
- this->result = temp_base;
- return;
- }
-
- if (ir->type->is_matrix()) {
- ir_to_mesa_src_reg mat = get_temp(ir->type);
- ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat);
-
- for (i = 0; i < ir->type->matrix_columns; i++) {
- assert(ir->type->base_type == GLSL_TYPE_FLOAT);
- values = &ir->value.f[i * ir->type->vector_elements];
-
- src_reg = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, NULL);
- src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- values,
- ir->type->vector_elements,
- &src_reg.swizzle);
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg);
-
- mat_column.index++;
- }
-
- this->result = mat;
- return;
- }
-
- src_reg.file = PROGRAM_CONSTANT;
- switch (ir->type->base_type) {
- case GLSL_TYPE_FLOAT:
- values = &ir->value.f[0];
- break;
- case GLSL_TYPE_UINT:
- for (i = 0; i < ir->type->vector_elements; i++) {
- values[i] = ir->value.u[i];
- }
- break;
- case GLSL_TYPE_INT:
- for (i = 0; i < ir->type->vector_elements; i++) {
- values[i] = ir->value.i[i];
- }
- break;
- case GLSL_TYPE_BOOL:
- for (i = 0; i < ir->type->vector_elements; i++) {
- values[i] = ir->value.b[i];
- }
- break;
- default:
- assert(!"Non-float/uint/int/bool constant");
- }
-
- this->result = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, ir->type);
- this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- values,
- ir->type->vector_elements,
- &this->result.swizzle);
-}
-
-function_entry *
-ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
-{
- function_entry *entry;
-
- foreach_iter(exec_list_iterator, iter, this->function_signatures) {
- entry = (function_entry *)iter.get();
-
- if (entry->sig == sig)
- return entry;
- }
-
- entry = talloc(mem_ctx, function_entry);
- entry->sig = sig;
- entry->sig_id = this->next_signature_id++;
- entry->bgn_inst = NULL;
-
- /* Allocate storage for all the parameters. */
- foreach_iter(exec_list_iterator, iter, sig->parameters) {
- ir_variable *param = (ir_variable *)iter.get();
- variable_storage *storage;
-
- storage = find_variable_storage(param);
- assert(!storage);
-
- storage = new(mem_ctx) variable_storage(param, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variables.push_tail(storage);
-
- this->next_temp += type_size(param->type);
- }
-
- if (!sig->return_type->is_void()) {
- entry->return_reg = get_temp(sig->return_type);
- } else {
- entry->return_reg = ir_to_mesa_undef;
- }
-
- this->function_signatures.push_tail(entry);
- return entry;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_call *ir)
-{
- ir_to_mesa_instruction *call_inst;
- ir_function_signature *sig = ir->get_callee();
- function_entry *entry = get_function_signature(sig);
- int i;
-
- /* Process in parameters. */
- exec_list_iterator sig_iter = sig->parameters.iterator();
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param_rval = (ir_rvalue *)iter.get();
- ir_variable *param = (ir_variable *)sig_iter.get();
-
- if (param->mode == ir_var_in ||
- param->mode == ir_var_inout) {
- variable_storage *storage = find_variable_storage(param);
- assert(storage);
-
- param_rval->accept(this);
- ir_to_mesa_src_reg r = this->result;
-
- ir_to_mesa_dst_reg l;
- l.file = storage->file;
- l.index = storage->index;
- l.reladdr = NULL;
- l.writemask = WRITEMASK_XYZW;
- l.cond_mask = COND_TR;
-
- for (i = 0; i < type_size(param->type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-
- sig_iter.next();
- }
- assert(!sig_iter.has_next());
-
- /* Emit call instruction */
- call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
- call_inst->function = entry;
-
- /* Process out parameters. */
- sig_iter = sig->parameters.iterator();
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param_rval = (ir_rvalue *)iter.get();
- ir_variable *param = (ir_variable *)sig_iter.get();
-
- if (param->mode == ir_var_out ||
- param->mode == ir_var_inout) {
- variable_storage *storage = find_variable_storage(param);
- assert(storage);
-
- ir_to_mesa_src_reg r;
- r.file = storage->file;
- r.index = storage->index;
- r.reladdr = NULL;
- r.swizzle = SWIZZLE_NOOP;
- r.negate = 0;
-
- param_rval->accept(this);
- ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result);
-
- for (i = 0; i < type_size(param->type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-
- sig_iter.next();
- }
- assert(!sig_iter.has_next());
-
- /* Process return value. */
- this->result = entry->return_reg;
-}
-
-class get_sampler_name : public ir_hierarchical_visitor
-{
-public:
- get_sampler_name(ir_to_mesa_visitor *mesa, ir_dereference *last)
- {
- this->mem_ctx = mesa->mem_ctx;
- this->mesa = mesa;
- this->name = NULL;
- this->offset = 0;
- this->last = last;
- }
-
- virtual ir_visitor_status visit(ir_dereference_variable *ir)
- {
- this->name = ir->var->name;
- return visit_continue;
- }
-
- virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
- {
- this->name = talloc_asprintf(mem_ctx, "%s.%s", name, ir->field);
- return visit_continue;
- }
-
- virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
- {
- ir_constant *index = ir->array_index->as_constant();
- int i;
-
- if (index) {
- i = index->value.i[0];
- } else {
- /* GLSL 1.10 and 1.20 allowed variable sampler array indices,
- * while GLSL 1.30 requires that the array indices be
- * constant integer expressions. We don't expect any driver
- * to actually work with a really variable array index, so
- * all that would work would be an unrolled loop counter that ends
- * up being constant above.
- */
- mesa->shader_program->InfoLog =
- talloc_asprintf_append(mesa->shader_program->InfoLog,
- "warning: Variable sampler array index "
- "unsupported.\nThis feature of the language "
- "was removed in GLSL 1.20 and is unlikely "
- "to be supported for 1.10 in Mesa.\n");
- i = 0;
- }
- if (ir != last) {
- this->name = talloc_asprintf(mem_ctx, "%s[%d]", name, i);
- } else {
- offset = i;
- }
- return visit_continue;
- }
-
- ir_to_mesa_visitor *mesa;
- const char *name;
- void *mem_ctx;
- int offset;
- ir_dereference *last;
-};
-
-int
-ir_to_mesa_visitor::get_sampler_uniform_value(ir_dereference *sampler)
-{
- get_sampler_name getname(this, sampler);
-
- sampler->accept(&getname);
-
- GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
- getname.name);
-
- if (index < 0) {
- fail_link(this->shader_program,
- "failed to find sampler named %s.\n", getname.name);
- return 0;
- }
-
- index += getname.offset;
-
- return this->prog->Parameters->ParameterValues[index][0];
-}
-
-void
-ir_to_mesa_visitor::visit(ir_texture *ir)
-{
- ir_to_mesa_src_reg result_src, coord, lod_info, projector;
- ir_to_mesa_dst_reg result_dst, coord_dst;
- ir_to_mesa_instruction *inst = NULL;
- prog_opcode opcode = OPCODE_NOP;
-
- ir->coordinate->accept(this);
-
- /* Put our coords in a temp. We'll need to modify them for shadow,
- * projection, or LOD, so the only case we'd use it as is is if
- * we're doing plain old texturing. Mesa IR optimization should
- * handle cleaning up our mess in that case.
- */
- coord = get_temp(glsl_type::vec4_type);
- coord_dst = ir_to_mesa_dst_reg_from_src(coord);
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst,
- this->result);
-
- if (ir->projector) {
- ir->projector->accept(this);
- projector = this->result;
- }
-
- /* Storage for our result. Ideally for an assignment we'd be using
- * the actual storage for the result here, instead.
- */
- result_src = get_temp(glsl_type::vec4_type);
- result_dst = ir_to_mesa_dst_reg_from_src(result_src);
-
- switch (ir->op) {
- case ir_tex:
- opcode = OPCODE_TEX;
- break;
- case ir_txb:
- opcode = OPCODE_TXB;
- ir->lod_info.bias->accept(this);
- lod_info = this->result;
- break;
- case ir_txl:
- opcode = OPCODE_TXL;
- ir->lod_info.lod->accept(this);
- lod_info = this->result;
- break;
- case ir_txd:
- case ir_txf:
- assert(!"GLSL 1.30 features unsupported");
- break;
- }
-
- if (ir->projector) {
- if (opcode == OPCODE_TEX) {
- /* Slot the projector in as the last component of the coord. */
- coord_dst.writemask = WRITEMASK_W;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, projector);
- coord_dst.writemask = WRITEMASK_XYZW;
- opcode = OPCODE_TXP;
- } else {
- ir_to_mesa_src_reg coord_w = coord;
- coord_w.swizzle = SWIZZLE_WWWW;
-
- /* For the other TEX opcodes there's no projective version
- * since the last slot is taken up by lod info. Do the
- * projective divide now.
- */
- coord_dst.writemask = WRITEMASK_W;
- ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector);
-
- coord_dst.writemask = WRITEMASK_XYZ;
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w);
-
- coord_dst.writemask = WRITEMASK_XYZW;
- coord.swizzle = SWIZZLE_XYZW;
- }
- }
-
- if (ir->shadow_comparitor) {
- /* Slot the shadow value in as the second to last component of the
- * coord.
- */
- ir->shadow_comparitor->accept(this);
- coord_dst.writemask = WRITEMASK_Z;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, this->result);
- coord_dst.writemask = WRITEMASK_XYZW;
- }
-
- if (opcode == OPCODE_TXL || opcode == OPCODE_TXB) {
- /* Mesa IR stores lod or lod bias in the last channel of the coords. */
- coord_dst.writemask = WRITEMASK_W;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, lod_info);
- coord_dst.writemask = WRITEMASK_XYZW;
- }
-
- inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord);
-
- if (ir->shadow_comparitor)
- inst->tex_shadow = GL_TRUE;
-
- inst->sampler = get_sampler_uniform_value(ir->sampler);
-
- const glsl_type *sampler_type = ir->sampler->type;
-
- switch (sampler_type->sampler_dimensionality) {
- case GLSL_SAMPLER_DIM_1D:
- inst->tex_target = (sampler_type->sampler_array)
- ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX;
- break;
- case GLSL_SAMPLER_DIM_2D:
- inst->tex_target = (sampler_type->sampler_array)
- ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX;
- break;
- case GLSL_SAMPLER_DIM_3D:
- inst->tex_target = TEXTURE_3D_INDEX;
- break;
- case GLSL_SAMPLER_DIM_CUBE:
- inst->tex_target = TEXTURE_CUBE_INDEX;
- break;
- case GLSL_SAMPLER_DIM_RECT:
- inst->tex_target = TEXTURE_RECT_INDEX;
- break;
- case GLSL_SAMPLER_DIM_BUF:
- assert(!"FINISHME: Implement ARB_texture_buffer_object");
- break;
- default:
- assert(!"Should not get here.");
- }
-
- this->result = result_src;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_return *ir)
-{
- if (ir->get_value()) {
- ir_to_mesa_dst_reg l;
- int i;
-
- assert(current_function);
-
- ir->get_value()->accept(this);
- ir_to_mesa_src_reg r = this->result;
-
- l = ir_to_mesa_dst_reg_from_src(current_function->return_reg);
-
- for (i = 0; i < type_size(current_function->sig->return_type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-
- ir_to_mesa_emit_op0(ir, OPCODE_RET);
-}
-
-void
-ir_to_mesa_visitor::visit(ir_discard *ir)
-{
- struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
-
- assert(ir->condition == NULL); /* FINISHME */
-
- ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV);
- fp->UsesKill = GL_TRUE;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_if *ir)
-{
- ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL;
- ir_to_mesa_instruction *prev_inst;
-
- prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
-
- ir->condition->accept(this);
- assert(this->result.file != PROGRAM_UNDEFINED);
-
- if (this->options->EmitCondCodes) {
- cond_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
-
- /* See if we actually generated any instruction for generating
- * the condition. If not, then cook up a move to a temp so we
- * have something to set cond_update on.
- */
- if (cond_inst == prev_inst) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::bool_type);
- cond_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_MOV,
- ir_to_mesa_dst_reg_from_src(temp),
- result);
- }
- cond_inst->cond_update = GL_TRUE;
-
- if_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_IF);
- if_inst->dst_reg.cond_mask = COND_NE;
- } else {
- if_inst = ir_to_mesa_emit_op1(ir->condition,
- OPCODE_IF, ir_to_mesa_undef_dst,
- this->result);
- }
-
- this->instructions.push_tail(if_inst);
-
- visit_exec_list(&ir->then_instructions, this);
-
- if (!ir->else_instructions.is_empty()) {
- else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE);
- visit_exec_list(&ir->else_instructions, this);
- }
-
- if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
-}
-
-ir_to_mesa_visitor::ir_to_mesa_visitor()
-{
- result.file = PROGRAM_UNDEFINED;
- next_temp = 1;
- next_signature_id = 1;
- current_function = NULL;
- mem_ctx = talloc_new(NULL);
-}
-
-ir_to_mesa_visitor::~ir_to_mesa_visitor()
-{
- talloc_free(mem_ctx);
-}
-
-static struct prog_src_register
-mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
-{
- struct prog_src_register mesa_reg;
-
- mesa_reg.File = reg.file;
- assert(reg.index < (1 << INST_INDEX_BITS) - 1);
- mesa_reg.Index = reg.index;
- mesa_reg.Swizzle = reg.swizzle;
- mesa_reg.RelAddr = reg.reladdr != NULL;
- mesa_reg.Negate = reg.negate;
- mesa_reg.Abs = 0;
- mesa_reg.HasIndex2 = GL_FALSE;
- mesa_reg.RelAddr2 = 0;
- mesa_reg.Index2 = 0;
-
- return mesa_reg;
-}
-
-static void
-set_branchtargets(ir_to_mesa_visitor *v,
- struct prog_instruction *mesa_instructions,
- int num_instructions)
-{
- int if_count = 0, loop_count = 0;
- int *if_stack, *loop_stack;
- int if_stack_pos = 0, loop_stack_pos = 0;
- int i, j;
-
- for (i = 0; i < num_instructions; i++) {
- switch (mesa_instructions[i].Opcode) {
- case OPCODE_IF:
- if_count++;
- break;
- case OPCODE_BGNLOOP:
- loop_count++;
- break;
- case OPCODE_BRK:
- case OPCODE_CONT:
- mesa_instructions[i].BranchTarget = -1;
- break;
- default:
- break;
- }
- }
-
- if_stack = talloc_zero_array(v->mem_ctx, int, if_count);
- loop_stack = talloc_zero_array(v->mem_ctx, int, loop_count);
-
- for (i = 0; i < num_instructions; i++) {
- switch (mesa_instructions[i].Opcode) {
- case OPCODE_IF:
- if_stack[if_stack_pos] = i;
- if_stack_pos++;
- break;
- case OPCODE_ELSE:
- mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
- if_stack[if_stack_pos - 1] = i;
- break;
- case OPCODE_ENDIF:
- mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
- if_stack_pos--;
- break;
- case OPCODE_BGNLOOP:
- loop_stack[loop_stack_pos] = i;
- loop_stack_pos++;
- break;
- case OPCODE_ENDLOOP:
- loop_stack_pos--;
- /* Rewrite any breaks/conts at this nesting level (haven't
- * already had a BranchTarget assigned) to point to the end
- * of the loop.
- */
- for (j = loop_stack[loop_stack_pos]; j < i; j++) {
- if (mesa_instructions[j].Opcode == OPCODE_BRK ||
- mesa_instructions[j].Opcode == OPCODE_CONT) {
- if (mesa_instructions[j].BranchTarget == -1) {
- mesa_instructions[j].BranchTarget = i;
- }
- }
- }
- /* The loop ends point at each other. */
- mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
- mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
- break;
- case OPCODE_CAL:
- foreach_iter(exec_list_iterator, iter, v->function_signatures) {
- function_entry *entry = (function_entry *)iter.get();
-
- if (entry->sig_id == mesa_instructions[i].BranchTarget) {
- mesa_instructions[i].BranchTarget = entry->inst;
- break;
- }
- }
- break;
- default:
- break;
- }
- }
-}
-
-static void
-print_program(struct prog_instruction *mesa_instructions,
- ir_instruction **mesa_instruction_annotation,
- int num_instructions)
-{
- ir_instruction *last_ir = NULL;
- int i;
- int indent = 0;
-
- for (i = 0; i < num_instructions; i++) {
- struct prog_instruction *mesa_inst = mesa_instructions + i;
- ir_instruction *ir = mesa_instruction_annotation[i];
-
- fprintf(stdout, "%3d: ", i);
-
- if (last_ir != ir && ir) {
- int j;
-
- for (j = 0; j < indent; j++) {
- fprintf(stdout, " ");
- }
- ir->print();
- printf("\n");
- last_ir = ir;
-
- fprintf(stdout, " "); /* line number spacing. */
- }
-
- indent = _mesa_fprint_instruction_opt(stdout, mesa_inst, indent,
- PROG_PRINT_DEBUG, NULL);
- }
-}
-
-static void
-count_resources(struct gl_program *prog)
-{
- unsigned int i;
-
- prog->SamplersUsed = 0;
-
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = &prog->Instructions[i];
-
- if (_mesa_is_tex_instruction(inst->Opcode)) {
- prog->SamplerTargets[inst->TexSrcUnit] =
- (gl_texture_index)inst->TexSrcTarget;
- prog->SamplersUsed |= 1 << inst->TexSrcUnit;
- if (inst->TexShadow) {
- prog->ShadowSamplers |= 1 << inst->TexSrcUnit;
- }
- }
- }
-
- _mesa_update_shader_textures_used(prog);
-}
-
-struct uniform_sort {
- struct gl_uniform *u;
- int pos;
-};
-
-/* The shader_program->Uniforms list is almost sorted in increasing
- * uniform->{Frag,Vert}Pos locations, but not quite when there are
- * uniforms shared between targets. We need to add parameters in
- * increasing order for the targets.
- */
-static int
-sort_uniforms(const void *a, const void *b)
-{
- struct uniform_sort *u1 = (struct uniform_sort *)a;
- struct uniform_sort *u2 = (struct uniform_sort *)b;
-
- return u1->pos - u2->pos;
-}
-
-/* Add the uniforms to the parameters. The linker chose locations
- * in our parameters lists (which weren't created yet), which the
- * uniforms code will use to poke values into our parameters list
- * when uniforms are updated.
- */
-static void
-add_uniforms_to_parameters_list(struct gl_shader_program *shader_program,
- struct gl_shader *shader,
- struct gl_program *prog)
-{
- unsigned int i;
- unsigned int next_sampler = 0, num_uniforms = 0;
- struct uniform_sort *sorted_uniforms;
-
- sorted_uniforms = talloc_array(NULL, struct uniform_sort,
- shader_program->Uniforms->NumUniforms);
-
- for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) {
- struct gl_uniform *uniform = shader_program->Uniforms->Uniforms + i;
- int parameter_index = -1;
-
- switch (shader->Type) {
- case GL_VERTEX_SHADER:
- parameter_index = uniform->VertPos;
- break;
- case GL_FRAGMENT_SHADER:
- parameter_index = uniform->FragPos;
- break;
- case GL_GEOMETRY_SHADER:
- parameter_index = uniform->GeomPos;
- break;
- }
-
- /* Only add uniforms used in our target. */
- if (parameter_index != -1) {
- sorted_uniforms[num_uniforms].pos = parameter_index;
- sorted_uniforms[num_uniforms].u = uniform;
- num_uniforms++;
- }
- }
-
- qsort(sorted_uniforms, num_uniforms, sizeof(struct uniform_sort),
- sort_uniforms);
-
- for (i = 0; i < num_uniforms; i++) {
- struct gl_uniform *uniform = sorted_uniforms[i].u;
- int parameter_index = sorted_uniforms[i].pos;
- const glsl_type *type = uniform->Type;
- unsigned int size;
-
- if (type->is_vector() ||
- type->is_scalar()) {
- size = type->vector_elements;
- } else {
- size = type_size(type) * 4;
- }
-
- gl_register_file file;
- if (type->is_sampler() ||
- (type->is_array() && type->fields.array->is_sampler())) {
- file = PROGRAM_SAMPLER;
- } else {
- file = PROGRAM_UNIFORM;
- }
-
- GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
- uniform->Name);
-
- if (index < 0) {
- index = _mesa_add_parameter(prog->Parameters, file,
- uniform->Name, size, type->gl_type,
- NULL, NULL, 0x0);
-
- /* Sampler uniform values are stored in prog->SamplerUnits,
- * and the entry in that array is selected by this index we
- * store in ParameterValues[].
- */
- if (file == PROGRAM_SAMPLER) {
- for (unsigned int j = 0; j < size / 4; j++)
- prog->Parameters->ParameterValues[index + j][0] = next_sampler++;
- }
-
- /* The location chosen in the Parameters list here (returned
- * from _mesa_add_uniform) has to match what the linker chose.
- */
- if (index != parameter_index) {
- fail_link(shader_program, "Allocation of uniform `%s' to target "
- "failed (%d vs %d)\n",
- uniform->Name, index, parameter_index);
- }
- }
- }
-
- talloc_free(sorted_uniforms);
-}
-
-static void
-set_uniform_initializer(GLcontext *ctx, void *mem_ctx,
- struct gl_shader_program *shader_program,
- const char *name, const glsl_type *type,
- ir_constant *val)
-{
- if (type->is_record()) {
- ir_constant *field_constant;
-
- field_constant = (ir_constant *)val->components.get_head();
-
- for (unsigned int i = 0; i < type->length; i++) {
- const glsl_type *field_type = type->fields.structure[i].type;
- const char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name,
- type->fields.structure[i].name);
- set_uniform_initializer(ctx, mem_ctx, shader_program, field_name,
- field_type, field_constant);
- field_constant = (ir_constant *)field_constant->next;
- }
- return;
- }
-
- int loc = _mesa_get_uniform_location(ctx, shader_program, name);
-
- if (loc == -1) {
- fail_link(shader_program,
- "Couldn't find uniform for initializer %s\n", name);
- return;
- }
-
- for (unsigned int i = 0; i < (type->is_array() ? type->length : 1); i++) {
- ir_constant *element;
- const glsl_type *element_type;
- if (type->is_array()) {
- element = val->array_elements[i];
- element_type = type->fields.array;
- } else {
- element = val;
- element_type = type;
- }
-
- void *values;
-
- if (element_type->base_type == GLSL_TYPE_BOOL) {
- int *conv = talloc_array(mem_ctx, int, element_type->components());
- for (unsigned int j = 0; j < element_type->components(); j++) {
- conv[j] = element->value.b[j];
- }
- values = (void *)conv;
- element_type = glsl_type::get_instance(GLSL_TYPE_INT,
- element_type->vector_elements,
- 1);
- } else {
- values = &element->value;
- }
-
- if (element_type->is_matrix()) {
- _mesa_uniform_matrix(ctx, shader_program,
- element_type->matrix_columns,
- element_type->vector_elements,
- loc, 1, GL_FALSE, (GLfloat *)values);
- loc += element_type->matrix_columns;
- } else {
- _mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns,
- values, element_type->gl_type);
- loc += type_size(element_type);
- }
- }
-}
-
-static void
-set_uniform_initializers(GLcontext *ctx,
- struct gl_shader_program *shader_program)
-{
- void *mem_ctx = NULL;
-
- for (unsigned int i = 0; i < shader_program->_NumLinkedShaders; i++) {
- struct gl_shader *shader = shader_program->_LinkedShaders[i];
- foreach_iter(exec_list_iterator, iter, *shader->ir) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- ir_variable *var = ir->as_variable();
-
- if (!var || var->mode != ir_var_uniform || !var->constant_value)
- continue;
-
- if (!mem_ctx)
- mem_ctx = talloc_new(NULL);
-
- set_uniform_initializer(ctx, mem_ctx, shader_program, var->name,
- var->type, var->constant_value);
- }
- }
-
- talloc_free(mem_ctx);
-}
-
-struct gl_program *
-get_mesa_program(GLcontext *ctx, struct gl_shader_program *shader_program,
- struct gl_shader *shader)
-{
- ir_to_mesa_visitor v;
- struct prog_instruction *mesa_instructions, *mesa_inst;
- ir_instruction **mesa_instruction_annotation;
- int i;
- struct gl_program *prog;
- GLenum target;
- const char *target_string;
- GLboolean progress;
- struct gl_shader_compiler_options *options =
- &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(shader->Type)];
-
- switch (shader->Type) {
- case GL_VERTEX_SHADER:
- target = GL_VERTEX_PROGRAM_ARB;
- target_string = "vertex";
- break;
- case GL_FRAGMENT_SHADER:
- target = GL_FRAGMENT_PROGRAM_ARB;
- target_string = "fragment";
- break;
- default:
- assert(!"should not be reached");
- return NULL;
- }
-
- validate_ir_tree(shader->ir);
-
- prog = ctx->Driver.NewProgram(ctx, target, shader_program->Name);
- if (!prog)
- return NULL;
- prog->Parameters = _mesa_new_parameter_list();
- prog->Varying = _mesa_new_parameter_list();
- prog->Attributes = _mesa_new_parameter_list();
- v.ctx = ctx;
- v.prog = prog;
- v.shader_program = shader_program;
- v.options = options;
-
- add_uniforms_to_parameters_list(shader_program, shader, prog);
-
- /* Emit Mesa IR for main(). */
- visit_exec_list(shader->ir, &v);
- v.ir_to_mesa_emit_op0(NULL, OPCODE_END);
-
- /* Now emit bodies for any functions that were used. */
- do {
- progress = GL_FALSE;
-
- foreach_iter(exec_list_iterator, iter, v.function_signatures) {
- function_entry *entry = (function_entry *)iter.get();
-
- if (!entry->bgn_inst) {
- v.current_function = entry;
-
- entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB);
- entry->bgn_inst->function = entry;
-
- visit_exec_list(&entry->sig->body, &v);
-
- ir_to_mesa_instruction *last;
- last = (ir_to_mesa_instruction *)v.instructions.get_tail();
- if (last->op != OPCODE_RET)
- v.ir_to_mesa_emit_op0(NULL, OPCODE_RET);
-
- ir_to_mesa_instruction *end;
- end = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB);
- end->function = entry;
-
- progress = GL_TRUE;
- }
- }
- } while (progress);
-
- prog->NumTemporaries = v.next_temp;
-
- int num_instructions = 0;
- foreach_iter(exec_list_iterator, iter, v.instructions) {
- num_instructions++;
- }
-
- mesa_instructions =
- (struct prog_instruction *)calloc(num_instructions,
- sizeof(*mesa_instructions));
- mesa_instruction_annotation = talloc_array(v.mem_ctx, ir_instruction *,
- num_instructions);
-
- mesa_inst = mesa_instructions;
- i = 0;
- foreach_iter(exec_list_iterator, iter, v.instructions) {
- ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
-
- mesa_inst->Opcode = inst->op;
- mesa_inst->CondUpdate = inst->cond_update;
- mesa_inst->DstReg.File = inst->dst_reg.file;
- mesa_inst->DstReg.Index = inst->dst_reg.index;
- mesa_inst->DstReg.CondMask = inst->dst_reg.cond_mask;
- mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
- mesa_inst->DstReg.RelAddr = inst->dst_reg.reladdr != NULL;
- mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
- mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
- mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
- mesa_inst->TexSrcUnit = inst->sampler;
- mesa_inst->TexSrcTarget = inst->tex_target;
- mesa_inst->TexShadow = inst->tex_shadow;
- mesa_instruction_annotation[i] = inst->ir;
-
- /* Set IndirectRegisterFiles. */
- if (mesa_inst->DstReg.RelAddr)
- prog->IndirectRegisterFiles |= 1 << mesa_inst->DstReg.File;
-
- for (unsigned src = 0; src < 3; src++)
- if (mesa_inst->SrcReg[src].RelAddr)
- prog->IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File;
-
- if (options->EmitNoIfs && mesa_inst->Opcode == OPCODE_IF) {
- fail_link(shader_program, "Couldn't flatten if statement\n");
- }
-
- switch (mesa_inst->Opcode) {
- case OPCODE_BGNSUB:
- inst->function->inst = i;
- mesa_inst->Comment = strdup(inst->function->sig->function_name());
- break;
- case OPCODE_ENDSUB:
- mesa_inst->Comment = strdup(inst->function->sig->function_name());
- break;
- case OPCODE_CAL:
- mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */
- break;
- case OPCODE_ARL:
- prog->NumAddressRegs = 1;
- break;
- default:
- break;
- }
-
- mesa_inst++;
- i++;
- }
-
- set_branchtargets(&v, mesa_instructions, num_instructions);
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- printf("\n");
- printf("GLSL IR for linked %s program %d:\n", target_string,
- shader_program->Name);
- _mesa_print_ir(shader->ir, NULL);
- printf("\n");
- printf("\n");
- printf("Mesa IR for linked %s program %d:\n", target_string,
- shader_program->Name);
- print_program(mesa_instructions, mesa_instruction_annotation,
- num_instructions);
- }
-
- prog->Instructions = mesa_instructions;
- prog->NumInstructions = num_instructions;
-
- do_set_program_inouts(shader->ir, prog);
- count_resources(prog);
-
- _mesa_reference_program(ctx, &shader->Program, prog);
-
- if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) {
- _mesa_optimize_program(ctx, prog);
- }
-
- return prog;
-}
-
-extern "C" {
-GLboolean
-_mesa_ir_compile_shader(GLcontext *ctx, struct gl_shader *shader)
-{
- assert(shader->CompileStatus);
- (void) ctx;
-
- return GL_TRUE;
-}
-
-GLboolean
-_mesa_ir_link_shader(GLcontext *ctx, struct gl_shader_program *prog)
-{
- assert(prog->LinkStatus);
-
- for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) {
- bool progress;
- exec_list *ir = prog->_LinkedShaders[i]->ir;
- struct gl_shader_compiler_options *options =
- &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(prog->_LinkedShaders[i]->Type)];
-
- do {
- progress = false;
-
- /* Lowering */
- do_mat_op_to_vec(ir);
- do_mod_to_fract(ir);
- do_div_to_mul_rcp(ir);
- do_explog_to_explog2(ir);
-
- progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress;
-
- progress = do_common_optimization(ir, true, options->MaxUnrollIterations) || progress;
-
- if (options->EmitNoIfs)
- progress = do_if_to_cond_assign(ir) || progress;
-
- if (options->EmitNoNoise)
- progress = lower_noise(ir) || progress;
-
- /* If there are forms of indirect addressing that the driver
- * cannot handle, perform the lowering pass.
- */
- if (options->EmitNoIndirectInput || options->EmitNoIndirectOutput
- || options->EmitNoIndirectTemp || options->EmitNoIndirectUniform)
- progress =
- lower_variable_index_to_cond_assign(ir,
- options->EmitNoIndirectInput,
- options->EmitNoIndirectOutput,
- options->EmitNoIndirectTemp,
- options->EmitNoIndirectUniform)
- || progress;
-
- progress = do_vec_index_to_cond_assign(ir) || progress;
- } while (progress);
-
- validate_ir_tree(ir);
- }
-
- for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) {
- struct gl_program *linked_prog;
- bool ok = true;
-
- linked_prog = get_mesa_program(ctx, prog, prog->_LinkedShaders[i]);
-
- switch (prog->_LinkedShaders[i]->Type) {
- case GL_VERTEX_SHADER:
- _mesa_reference_vertprog(ctx, &prog->VertexProgram,
- (struct gl_vertex_program *)linked_prog);
- ok = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
- linked_prog);
- break;
- case GL_FRAGMENT_SHADER:
- _mesa_reference_fragprog(ctx, &prog->FragmentProgram,
- (struct gl_fragment_program *)linked_prog);
- ok = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
- linked_prog);
- break;
- }
- if (!ok) {
- return GL_FALSE;
- }
- _mesa_reference_program(ctx, &linked_prog, NULL);
- }
-
- return GL_TRUE;
-}
-
-void
-_mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader)
-{
- struct _mesa_glsl_parse_state *state =
- new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
-
- const char *source = shader->Source;
- /* Check if the user called glCompileShader without first calling
- * glShaderSource. This should fail to compile, but not raise a GL_ERROR.
- */
- if (source == NULL) {
- shader->CompileStatus = GL_FALSE;
- return;
- }
-
- state->error = preprocess(state, &source, &state->info_log,
- &ctx->Extensions, ctx->API);
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- printf("GLSL source for shader %d:\n", shader->Name);
- printf("%s\n", shader->Source);
- }
-
- if (!state->error) {
- _mesa_glsl_lexer_ctor(state, source);
- _mesa_glsl_parse(state);
- _mesa_glsl_lexer_dtor(state);
- }
-
- talloc_free(shader->ir);
- shader->ir = new(shader) exec_list;
- if (!state->error && !state->translation_unit.is_empty())
- _mesa_ast_to_hir(shader->ir, state);
-
- if (!state->error && !shader->ir->is_empty()) {
- validate_ir_tree(shader->ir);
-
- /* Do some optimization at compile time to reduce shader IR size
- * and reduce later work if the same shader is linked multiple times
- */
- while (do_common_optimization(shader->ir, false, 32))
- ;
-
- validate_ir_tree(shader->ir);
- }
-
- shader->symbols = state->symbols;
-
- shader->CompileStatus = !state->error;
- shader->InfoLog = state->info_log;
- shader->Version = state->language_version;
- memcpy(shader->builtins_to_link, state->builtins_to_link,
- sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
- shader->num_builtins_to_link = state->num_builtins_to_link;
-
- if (ctx->Shader.Flags & GLSL_LOG) {
- _mesa_write_shader_to_file(shader);
- }
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- if (shader->CompileStatus) {
- printf("GLSL IR for shader %d:\n", shader->Name);
- _mesa_print_ir(shader->ir, NULL);
- printf("\n\n");
- } else {
- printf("GLSL shader %d failed to compile.\n", shader->Name);
- }
- if (shader->InfoLog && shader->InfoLog[0] != 0) {
- printf("GLSL shader %d info log:\n", shader->Name);
- printf("%s\n", shader->InfoLog);
- }
- }
-
- /* Retain any live IR, but trash the rest. */
- reparent_ir(shader->ir, shader->ir);
-
- talloc_free(state);
-
- if (shader->CompileStatus) {
- if (!ctx->Driver.CompileShader(ctx, shader))
- shader->CompileStatus = GL_FALSE;
- }
-}
-
-void
-_mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog)
-{
- unsigned int i;
-
- _mesa_clear_shader_program_data(ctx, prog);
-
- prog->LinkStatus = GL_TRUE;
-
- for (i = 0; i < prog->NumShaders; i++) {
- if (!prog->Shaders[i]->CompileStatus) {
- fail_link(prog, "linking with uncompiled shader");
- prog->LinkStatus = GL_FALSE;
- }
- }
-
- prog->Varying = _mesa_new_parameter_list();
- _mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL);
- _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL);
-
- if (prog->LinkStatus) {
- link_shaders(ctx, prog);
- }
-
- if (prog->LinkStatus) {
- if (!ctx->Driver.LinkShader(ctx, prog)) {
- prog->LinkStatus = GL_FALSE;
- }
- }
-
- set_uniform_initializers(ctx, prog);
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- if (!prog->LinkStatus) {
- printf("GLSL shader program %d failed to link\n", prog->Name);
- }
-
- if (prog->InfoLog && prog->InfoLog[0] != 0) {
- printf("GLSL shader program %d info log:\n", prog->Name);
- printf("%s\n", prog->InfoLog);
- }
- }
-}
-
-} /* extern "C" */
+/*
+ * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 ir_to_mesa.cpp
+ *
+ * Translate GLSL IR to Mesa's gl_program representation.
+ */
+
+#include <stdio.h>
+#include "main/compiler.h"
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_print_visitor.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+#include "glsl_parser_extras.h"
+#include "../glsl/program.h"
+#include "ir_optimization.h"
+#include "ast.h"
+
+extern "C" {
+#include "main/mtypes.h"
+#include "main/shaderapi.h"
+#include "main/shaderobj.h"
+#include "main/uniforms.h"
+#include "program/hash_table.h"
+#include "program/prog_instruction.h"
+#include "program/prog_optimize.h"
+#include "program/prog_print.h"
+#include "program/program.h"
+#include "program/prog_uniform.h"
+#include "program/prog_parameter.h"
+#include "program/sampler.h"
+}
+
+static int swizzle_for_size(int size);
+
+/**
+ * This struct is a corresponding struct to Mesa prog_src_register, with
+ * wider fields.
+ */
+typedef struct ir_to_mesa_src_reg {
+ ir_to_mesa_src_reg(int file, int index, const glsl_type *type)
+ {
+ this->file = (gl_register_file) file;
+ this->index = index;
+ if (type && (type->is_scalar() || type->is_vector() || type->is_matrix()))
+ this->swizzle = swizzle_for_size(type->vector_elements);
+ else
+ this->swizzle = SWIZZLE_XYZW;
+ this->negate = 0;
+ this->reladdr = NULL;
+ }
+
+ ir_to_mesa_src_reg()
+ {
+ this->file = PROGRAM_UNDEFINED;
+ this->index = 0;
+ this->swizzle = 0;
+ this->negate = 0;
+ this->reladdr = NULL;
+ }
+
+ gl_register_file file; /**< PROGRAM_* from Mesa */
+ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
+ GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
+ int negate; /**< NEGATE_XYZW mask from mesa */
+ /** Register index should be offset by the integer in this reg. */
+ ir_to_mesa_src_reg *reladdr;
+} ir_to_mesa_src_reg;
+
+typedef struct ir_to_mesa_dst_reg {
+ int file; /**< PROGRAM_* from Mesa */
+ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
+ int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
+ GLuint cond_mask:4;
+ /** Register index should be offset by the integer in this reg. */
+ ir_to_mesa_src_reg *reladdr;
+} ir_to_mesa_dst_reg;
+
+extern ir_to_mesa_src_reg ir_to_mesa_undef;
+
+class ir_to_mesa_instruction : public exec_node {
+public:
+ /* Callers of this talloc-based new need not call delete. It's
+ * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ static void* operator new(size_t size, void *ctx)
+ {
+ void *node;
+
+ node = talloc_zero_size(ctx, size);
+ assert(node != NULL);
+
+ return node;
+ }
+
+ enum prog_opcode op;
+ ir_to_mesa_dst_reg dst_reg;
+ ir_to_mesa_src_reg src_reg[3];
+ /** Pointer to the ir source this tree came from for debugging */
+ ir_instruction *ir;
+ GLboolean cond_update;
+ bool saturate;
+ int sampler; /**< sampler index */
+ int tex_target; /**< One of TEXTURE_*_INDEX */
+ GLboolean tex_shadow;
+
+ class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */
+};
+
+class variable_storage : public exec_node {
+public:
+ variable_storage(ir_variable *var, gl_register_file file, int index)
+ : file(file), index(index), var(var)
+ {
+ /* empty */
+ }
+
+ gl_register_file file;
+ int index;
+ ir_variable *var; /* variable that maps to this, if any */
+};
+
+class function_entry : public exec_node {
+public:
+ ir_function_signature *sig;
+
+ /**
+ * identifier of this function signature used by the program.
+ *
+ * At the point that Mesa instructions for function calls are
+ * generated, we don't know the address of the first instruction of
+ * the function body. So we make the BranchTarget that is called a
+ * small integer and rewrite them during set_branchtargets().
+ */
+ int sig_id;
+
+ /**
+ * Pointer to first instruction of the function body.
+ *
+ * Set during function body emits after main() is processed.
+ */
+ ir_to_mesa_instruction *bgn_inst;
+
+ /**
+ * Index of the first instruction of the function body in actual
+ * Mesa IR.
+ *
+ * Set after convertion from ir_to_mesa_instruction to prog_instruction.
+ */
+ int inst;
+
+ /** Storage for the return value. */
+ ir_to_mesa_src_reg return_reg;
+};
+
+class ir_to_mesa_visitor : public ir_visitor {
+public:
+ ir_to_mesa_visitor();
+ ~ir_to_mesa_visitor();
+
+ function_entry *current_function;
+
+ struct gl_context *ctx;
+ struct gl_program *prog;
+ struct gl_shader_program *shader_program;
+ struct gl_shader_compiler_options *options;
+
+ int next_temp;
+
+ variable_storage *find_variable_storage(ir_variable *var);
+
+ function_entry *get_function_signature(ir_function_signature *sig);
+
+ ir_to_mesa_src_reg get_temp(const glsl_type *type);
+ void reladdr_to_temp(ir_instruction *ir,
+ ir_to_mesa_src_reg *reg, int *num_reladdr);
+
+ struct ir_to_mesa_src_reg src_reg_for_float(float val);
+
+ /**
+ * \name Visit methods
+ *
+ * As typical for the visitor pattern, there must be one \c visit method for
+ * each concrete subclass of \c ir_instruction. Virtual base classes within
+ * the hierarchy should not have \c visit methods.
+ */
+ /*@{*/
+ virtual void visit(ir_variable *);
+ virtual void visit(ir_loop *);
+ virtual void visit(ir_loop_jump *);
+ virtual void visit(ir_function_signature *);
+ virtual void visit(ir_function *);
+ virtual void visit(ir_expression *);
+ virtual void visit(ir_swizzle *);
+ virtual void visit(ir_dereference_variable *);
+ virtual void visit(ir_dereference_array *);
+ virtual void visit(ir_dereference_record *);
+ virtual void visit(ir_assignment *);
+ virtual void visit(ir_constant *);
+ virtual void visit(ir_call *);
+ virtual void visit(ir_return *);
+ virtual void visit(ir_discard *);
+ virtual void visit(ir_texture *);
+ virtual void visit(ir_if *);
+ /*@}*/
+
+ struct ir_to_mesa_src_reg result;
+
+ /** List of variable_storage */
+ exec_list variables;
+
+ /** List of function_entry */
+ exec_list function_signatures;
+ int next_signature_id;
+
+ /** List of ir_to_mesa_instruction */
+ exec_list instructions;
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op0(ir_instruction *ir,
+ enum prog_opcode op);
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0);
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1);
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ ir_to_mesa_src_reg src2);
+
+ /**
+ * Emit the correct dot-product instruction for the type of arguments
+ *
+ * \sa ir_to_mesa_emit_op2
+ */
+ void ir_to_mesa_emit_dp(ir_instruction *ir,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ unsigned elements);
+
+ void ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0);
+
+ void ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1);
+
+ void emit_scs(ir_instruction *ir, enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ const ir_to_mesa_src_reg &src);
+
+ GLboolean try_emit_mad(ir_expression *ir,
+ int mul_operand);
+ GLboolean try_emit_sat(ir_expression *ir);
+
+ void emit_swz(ir_expression *ir);
+
+ bool process_move_condition(ir_rvalue *ir);
+
+ void *mem_ctx;
+};
+
+ir_to_mesa_src_reg ir_to_mesa_undef = ir_to_mesa_src_reg(PROGRAM_UNDEFINED, 0, NULL);
+
+ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
+ PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL,
+};
+
+ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
+ PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL
+};
+
+static void
+fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
+
+static void
+fail_link(struct gl_shader_program *prog, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, args);
+ va_end(args);
+
+ prog->LinkStatus = GL_FALSE;
+}
+
+static int
+swizzle_for_size(int size)
+{
+ int size_swizzles[4] = {
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
+ };
+
+ assert((size >= 1) && (size <= 4));
+ return size_swizzles[size - 1];
+}
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ ir_to_mesa_src_reg src2)
+{
+ ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction();
+ int num_reladdr = 0;
+
+ /* If we have to do relative addressing, we want to load the ARL
+ * reg directly for one of the regs, and preload the other reladdr
+ * sources into temps.
+ */
+ num_reladdr += dst.reladdr != NULL;
+ num_reladdr += src0.reladdr != NULL;
+ num_reladdr += src1.reladdr != NULL;
+ num_reladdr += src2.reladdr != NULL;
+
+ reladdr_to_temp(ir, &src2, &num_reladdr);
+ reladdr_to_temp(ir, &src1, &num_reladdr);
+ reladdr_to_temp(ir, &src0, &num_reladdr);
+
+ if (dst.reladdr) {
+ ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
+ *dst.reladdr);
+
+ num_reladdr--;
+ }
+ assert(num_reladdr == 0);
+
+ inst->op = op;
+ inst->dst_reg = dst;
+ inst->src_reg[0] = src0;
+ inst->src_reg[1] = src1;
+ inst->src_reg[2] = src2;
+ inst->ir = ir;
+
+ inst->function = NULL;
+
+ this->instructions.push_tail(inst);
+
+ return inst;
+}
+
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1)
+{
+ return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef);
+}
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0)
+{
+ assert(dst.writemask != 0);
+ return ir_to_mesa_emit_op3(ir, op, dst,
+ src0, ir_to_mesa_undef, ir_to_mesa_undef);
+}
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir,
+ enum prog_opcode op)
+{
+ return ir_to_mesa_emit_op3(ir, op, ir_to_mesa_undef_dst,
+ ir_to_mesa_undef,
+ ir_to_mesa_undef,
+ ir_to_mesa_undef);
+}
+
+void
+ir_to_mesa_visitor::ir_to_mesa_emit_dp(ir_instruction *ir,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ unsigned elements)
+{
+ static const gl_inst_opcode dot_opcodes[] = {
+ OPCODE_DP2, OPCODE_DP3, OPCODE_DP4
+ };
+
+ ir_to_mesa_emit_op3(ir, dot_opcodes[elements - 2],
+ dst, src0, src1, ir_to_mesa_undef);
+}
+
+inline ir_to_mesa_dst_reg
+ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
+{
+ ir_to_mesa_dst_reg dst_reg;
+
+ dst_reg.file = reg.file;
+ dst_reg.index = reg.index;
+ dst_reg.writemask = WRITEMASK_XYZW;
+ dst_reg.cond_mask = COND_TR;
+ dst_reg.reladdr = reg.reladdr;
+
+ return dst_reg;
+}
+
+inline ir_to_mesa_src_reg
+ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
+{
+ return ir_to_mesa_src_reg(reg.file, reg.index, NULL);
+}
+
+/**
+ * Emits Mesa scalar opcodes to produce unique answers across channels.
+ *
+ * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X
+ * channel determines the result across all channels. So to do a vec4
+ * of this operation, we want to emit a scalar per source channel used
+ * to produce dest channels.
+ */
+void
+ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg orig_src0,
+ ir_to_mesa_src_reg orig_src1)
+{
+ int i, j;
+ int done_mask = ~dst.writemask;
+
+ /* Mesa RCP is a scalar operation splatting results to all channels,
+ * like ARB_fp/vp. So emit as many RCPs as necessary to cover our
+ * dst channels.
+ */
+ for (i = 0; i < 4; i++) {
+ GLuint this_mask = (1 << i);
+ ir_to_mesa_instruction *inst;
+ ir_to_mesa_src_reg src0 = orig_src0;
+ ir_to_mesa_src_reg src1 = orig_src1;
+
+ if (done_mask & this_mask)
+ continue;
+
+ GLuint src0_swiz = GET_SWZ(src0.swizzle, i);
+ GLuint src1_swiz = GET_SWZ(src1.swizzle, i);
+ for (j = i + 1; j < 4; j++) {
+ /* If there is another enabled component in the destination that is
+ * derived from the same inputs, generate its value on this pass as
+ * well.
+ */
+ if (!(done_mask & (1 << j)) &&
+ GET_SWZ(src0.swizzle, j) == src0_swiz &&
+ GET_SWZ(src1.swizzle, j) == src1_swiz) {
+ this_mask |= (1 << j);
+ }
+ }
+ src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
+ src0_swiz, src0_swiz);
+ src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz,
+ src1_swiz, src1_swiz);
+
+ inst = ir_to_mesa_emit_op2(ir, op,
+ dst,
+ src0,
+ src1);
+ inst->dst_reg.writemask = this_mask;
+ done_mask |= this_mask;
+ }
+}
+
+void
+ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0)
+{
+ ir_to_mesa_src_reg undef = ir_to_mesa_undef;
+
+ undef.swizzle = SWIZZLE_XXXX;
+
+ ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef);
+}
+
+/**
+ * Emit an OPCODE_SCS instruction
+ *
+ * The \c SCS opcode functions a bit differently than the other Mesa (or
+ * ARB_fragment_program) opcodes. Instead of splatting its result across all
+ * four components of the destination, it writes one value to the \c x
+ * component and another value to the \c y component.
+ *
+ * \param ir IR instruction being processed
+ * \param op Either \c OPCODE_SIN or \c OPCODE_COS depending on which
+ * value is desired.
+ * \param dst Destination register
+ * \param src Source register
+ */
+void
+ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ const ir_to_mesa_src_reg &src)
+{
+ /* Vertex programs cannot use the SCS opcode.
+ */
+ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB) {
+ ir_to_mesa_emit_scalar_op1(ir, op, dst, src);
+ return;
+ }
+
+ const unsigned component = (op == OPCODE_SIN) ? 0 : 1;
+ const unsigned scs_mask = (1U << component);
+ int done_mask = ~dst.writemask;
+ ir_to_mesa_src_reg tmp;
+
+ assert(op == OPCODE_SIN || op == OPCODE_COS);
+
+ /* If there are compnents in the destination that differ from the component
+ * that will be written by the SCS instrution, we'll need a temporary.
+ */
+ if (scs_mask != unsigned(dst.writemask)) {
+ tmp = get_temp(glsl_type::vec4_type);
+ }
+
+ for (unsigned i = 0; i < 4; i++) {
+ unsigned this_mask = (1U << i);
+ ir_to_mesa_src_reg src0 = src;
+
+ if ((done_mask & this_mask) != 0)
+ continue;
+
+ /* The source swizzle specified which component of the source generates
+ * sine / cosine for the current component in the destination. The SCS
+ * instruction requires that this value be swizzle to the X component.
+ * Replace the current swizzle with a swizzle that puts the source in
+ * the X component.
+ */
+ unsigned src0_swiz = GET_SWZ(src.swizzle, i);
+
+ src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
+ src0_swiz, src0_swiz);
+ for (unsigned j = i + 1; j < 4; j++) {
+ /* If there is another enabled component in the destination that is
+ * derived from the same inputs, generate its value on this pass as
+ * well.
+ */
+ if (!(done_mask & (1 << j)) &&
+ GET_SWZ(src0.swizzle, j) == src0_swiz) {
+ this_mask |= (1 << j);
+ }
+ }
+
+ if (this_mask != scs_mask) {
+ ir_to_mesa_instruction *inst;
+ ir_to_mesa_dst_reg tmp_dst = ir_to_mesa_dst_reg_from_src(tmp);
+
+ /* Emit the SCS instruction.
+ */
+ inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, tmp_dst, src0);
+ inst->dst_reg.writemask = scs_mask;
+
+ /* Move the result of the SCS instruction to the desired location in
+ * the destination.
+ */
+ tmp.swizzle = MAKE_SWIZZLE4(component, component,
+ component, component);
+ inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, tmp);
+ inst->dst_reg.writemask = this_mask;
+ } else {
+ /* Emit the SCS instruction to write directly to the destination.
+ */
+ ir_to_mesa_instruction *inst =
+ ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, src0);
+ inst->dst_reg.writemask = scs_mask;
+ }
+
+ done_mask |= this_mask;
+ }
+}
+
+struct ir_to_mesa_src_reg
+ir_to_mesa_visitor::src_reg_for_float(float val)
+{
+ ir_to_mesa_src_reg src_reg(PROGRAM_CONSTANT, -1, NULL);
+
+ src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ &val, 1, &src_reg.swizzle);
+
+ return src_reg;
+}
+
+static int
+type_size(const struct glsl_type *type)
+{
+ unsigned int i;
+ int size;
+
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ if (type->is_matrix()) {
+ return type->matrix_columns;
+ } else {
+ /* Regardless of size of vector, it gets a vec4. This is bad
+ * packing for things like floats, but otherwise arrays become a
+ * mess. Hopefully a later pass over the code can pack scalars
+ * down if appropriate.
+ */
+ return 1;
+ }
+ case GLSL_TYPE_ARRAY:
+ return type_size(type->fields.array) * type->length;
+ case GLSL_TYPE_STRUCT:
+ size = 0;
+ for (i = 0; i < type->length; i++) {
+ size += type_size(type->fields.structure[i].type);
+ }
+ return size;
+ case GLSL_TYPE_SAMPLER:
+ /* Samplers take up one slot in UNIFORMS[], but they're baked in
+ * at link time.
+ */
+ return 1;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+/**
+ * In the initial pass of codegen, we assign temporary numbers to
+ * intermediate results. (not SSA -- variable assignments will reuse
+ * storage). Actual register allocation for the Mesa VM occurs in a
+ * pass over the Mesa IR later.
+ */
+ir_to_mesa_src_reg
+ir_to_mesa_visitor::get_temp(const glsl_type *type)
+{
+ ir_to_mesa_src_reg src_reg;
+ int swizzle[4];
+ int i;
+
+ src_reg.file = PROGRAM_TEMPORARY;
+ src_reg.index = next_temp;
+ src_reg.reladdr = NULL;
+ next_temp += type_size(type);
+
+ if (type->is_array() || type->is_record()) {
+ src_reg.swizzle = SWIZZLE_NOOP;
+ } else {
+ for (i = 0; i < type->vector_elements; i++)
+ swizzle[i] = i;
+ for (; i < 4; i++)
+ swizzle[i] = type->vector_elements - 1;
+ src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
+ swizzle[2], swizzle[3]);
+ }
+ src_reg.negate = 0;
+
+ return src_reg;
+}
+
+variable_storage *
+ir_to_mesa_visitor::find_variable_storage(ir_variable *var)
+{
+
+ variable_storage *entry;
+
+ foreach_iter(exec_list_iterator, iter, this->variables) {
+ entry = (variable_storage *)iter.get();
+
+ if (entry->var == var)
+ return entry;
+ }
+
+ return NULL;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_variable *ir)
+{
+ if (strcmp(ir->name, "gl_FragCoord") == 0) {
+ struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
+
+ fp->OriginUpperLeft = ir->origin_upper_left;
+ fp->PixelCenterInteger = ir->pixel_center_integer;
+ }
+
+ if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) {
+ unsigned int i;
+ const struct gl_builtin_uniform_desc *statevar;
+
+ for (i = 0; _mesa_builtin_uniform_desc[i].name; i++) {
+ if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0)
+ break;
+ }
+
+ if (!_mesa_builtin_uniform_desc[i].name) {
+ fail_link(this->shader_program,
+ "Failed to find builtin uniform `%s'\n", ir->name);
+ return;
+ }
+
+ statevar = &_mesa_builtin_uniform_desc[i];
+
+ int array_count;
+ if (ir->type->is_array()) {
+ array_count = ir->type->length;
+ } else {
+ array_count = 1;
+ }
+
+ /* Check if this statevar's setup in the STATE file exactly
+ * matches how we'll want to reference it as a
+ * struct/array/whatever. If not, then we need to move it into
+ * temporary storage and hope that it'll get copy-propagated
+ * out.
+ */
+ for (i = 0; i < statevar->num_elements; i++) {
+ if (statevar->elements[i].swizzle != SWIZZLE_XYZW) {
+ break;
+ }
+ }
+
+ struct variable_storage *storage;
+ ir_to_mesa_dst_reg dst;
+ if (i == statevar->num_elements) {
+ /* We'll set the index later. */
+ storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1);
+ this->variables.push_tail(storage);
+
+ dst = ir_to_mesa_undef_dst;
+ } else {
+ storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(storage);
+ this->next_temp += type_size(ir->type);
+
+ dst = ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg(PROGRAM_TEMPORARY,
+ storage->index,
+ NULL));
+ }
+
+
+ for (int a = 0; a < array_count; a++) {
+ for (unsigned int i = 0; i < statevar->num_elements; i++) {
+ struct gl_builtin_uniform_element *element = &statevar->elements[i];
+ int tokens[STATE_LENGTH];
+
+ memcpy(tokens, element->tokens, sizeof(element->tokens));
+ if (ir->type->is_array()) {
+ tokens[1] = a;
+ }
+
+ int index = _mesa_add_state_reference(this->prog->Parameters,
+ (gl_state_index *)tokens);
+
+ if (storage->file == PROGRAM_STATE_VAR) {
+ if (storage->index == -1) {
+ storage->index = index;
+ } else {
+ assert(index ==
+ (int)(storage->index + a * statevar->num_elements + i));
+ }
+ } else {
+ ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL);
+ src.swizzle = element->swizzle;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src);
+ /* even a float takes up a whole vec4 reg in a struct/array. */
+ dst.index++;
+ }
+ }
+ }
+ if (storage->file == PROGRAM_TEMPORARY &&
+ dst.index != storage->index + type_size(ir->type)) {
+ fail_link(this->shader_program,
+ "failed to load builtin uniform `%s' (%d/%d regs loaded)\n",
+ ir->name, dst.index - storage->index,
+ type_size(ir->type));
+ }
+ }
+}
+
+void
+ir_to_mesa_visitor::visit(ir_loop *ir)
+{
+ ir_dereference_variable *counter = NULL;
+
+ if (ir->counter != NULL)
+ counter = new(ir) ir_dereference_variable(ir->counter);
+
+ if (ir->from != NULL) {
+ assert(ir->counter != NULL);
+
+ ir_assignment *a = new(ir) ir_assignment(counter, ir->from, NULL);
+
+ a->accept(this);
+ delete a;
+ }
+
+ ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP);
+
+ if (ir->to) {
+ ir_expression *e =
+ new(ir) ir_expression(ir->cmp, glsl_type::bool_type,
+ counter, ir->to);
+ ir_if *if_stmt = new(ir) ir_if(e);
+
+ ir_loop_jump *brk = new(ir) ir_loop_jump(ir_loop_jump::jump_break);
+
+ if_stmt->then_instructions.push_tail(brk);
+
+ if_stmt->accept(this);
+
+ delete if_stmt;
+ delete e;
+ delete brk;
+ }
+
+ visit_exec_list(&ir->body_instructions, this);
+
+ if (ir->increment) {
+ ir_expression *e =
+ new(ir) ir_expression(ir_binop_add, counter->type,
+ counter, ir->increment);
+
+ ir_assignment *a = new(ir) ir_assignment(counter, e, NULL);
+
+ a->accept(this);
+ delete a;
+ delete e;
+ }
+
+ ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_loop_jump *ir)
+{
+ switch (ir->mode) {
+ case ir_loop_jump::jump_break:
+ ir_to_mesa_emit_op0(NULL, OPCODE_BRK);
+ break;
+ case ir_loop_jump::jump_continue:
+ ir_to_mesa_emit_op0(NULL, OPCODE_CONT);
+ break;
+ }
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_function_signature *ir)
+{
+ assert(0);
+ (void)ir;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_function *ir)
+{
+ /* Ignore function bodies other than main() -- we shouldn't see calls to
+ * them since they should all be inlined before we get to ir_to_mesa.
+ */
+ if (strcmp(ir->name, "main") == 0) {
+ const ir_function_signature *sig;
+ exec_list empty;
+
+ sig = ir->matching_signature(&empty);
+
+ assert(sig);
+
+ foreach_iter(exec_list_iterator, iter, sig->body) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+
+ ir->accept(this);
+ }
+ }
+}
+
+GLboolean
+ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
+{
+ int nonmul_operand = 1 - mul_operand;
+ ir_to_mesa_src_reg a, b, c;
+
+ ir_expression *expr = ir->operands[mul_operand]->as_expression();
+ if (!expr || expr->operation != ir_binop_mul)
+ return false;
+
+ expr->operands[0]->accept(this);
+ a = this->result;
+ expr->operands[1]->accept(this);
+ b = this->result;
+ ir->operands[nonmul_operand]->accept(this);
+ c = this->result;
+
+ this->result = get_temp(ir->type);
+ ir_to_mesa_emit_op3(ir, OPCODE_MAD,
+ ir_to_mesa_dst_reg_from_src(this->result), a, b, c);
+
+ return true;
+}
+
+GLboolean
+ir_to_mesa_visitor::try_emit_sat(ir_expression *ir)
+{
+ /* Saturates were only introduced to vertex programs in
+ * NV_vertex_program3, so don't give them to drivers in the VP.
+ */
+ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB)
+ return false;
+
+ ir_rvalue *sat_src = ir->as_rvalue_to_saturate();
+ if (!sat_src)
+ return false;
+
+ sat_src->accept(this);
+ ir_to_mesa_src_reg src = this->result;
+
+ this->result = get_temp(ir->type);
+ ir_to_mesa_instruction *inst;
+ inst = ir_to_mesa_emit_op1(ir, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(this->result),
+ src);
+ inst->saturate = true;
+
+ return true;
+}
+
+void
+ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir,
+ ir_to_mesa_src_reg *reg, int *num_reladdr)
+{
+ if (!reg->reladdr)
+ return;
+
+ ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, *reg->reladdr);
+
+ if (*num_reladdr != 1) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(temp), *reg);
+ *reg = temp;
+ }
+
+ (*num_reladdr)--;
+}
+
+void
+ir_to_mesa_visitor::emit_swz(ir_expression *ir)
+{
+ /* Assume that the vector operator is in a form compatible with OPCODE_SWZ.
+ * This means that each of the operands is either an immediate value of -1,
+ * 0, or 1, or is a component from one source register (possibly with
+ * negation).
+ */
+ uint8_t components[4] = { 0 };
+ bool negate[4] = { false };
+ ir_variable *var = NULL;
+
+ for (unsigned i = 0; i < ir->type->vector_elements; i++) {
+ ir_rvalue *op = ir->operands[i];
+
+ assert(op->type->is_scalar());
+
+ while (op != NULL) {
+ switch (op->ir_type) {
+ case ir_type_constant: {
+
+ assert(op->type->is_scalar());
+
+ const ir_constant *const c = op->as_constant();
+ if (c->is_one()) {
+ components[i] = SWIZZLE_ONE;
+ } else if (c->is_zero()) {
+ components[i] = SWIZZLE_ZERO;
+ } else if (c->is_negative_one()) {
+ components[i] = SWIZZLE_ONE;
+ negate[i] = true;
+ } else {
+ assert(!"SWZ constant must be 0.0 or 1.0.");
+ }
+
+ op = NULL;
+ break;
+ }
+
+ case ir_type_dereference_variable: {
+ ir_dereference_variable *const deref =
+ (ir_dereference_variable *) op;
+
+ assert((var == NULL) || (deref->var == var));
+ components[i] = SWIZZLE_X;
+ var = deref->var;
+ op = NULL;
+ break;
+ }
+
+ case ir_type_expression: {
+ ir_expression *const expr = (ir_expression *) op;
+
+ assert(expr->operation == ir_unop_neg);
+ negate[i] = true;
+
+ op = expr->operands[0];
+ break;
+ }
+
+ case ir_type_swizzle: {
+ ir_swizzle *const swiz = (ir_swizzle *) op;
+
+ components[i] = swiz->mask.x;
+ op = swiz->val;
+ break;
+ }
+
+ default:
+ assert(!"Should not get here.");
+ return;
+ }
+ }
+ }
+
+ assert(var != NULL);
+
+ ir_dereference_variable *const deref =
+ new(mem_ctx) ir_dereference_variable(var);
+
+ this->result.file = PROGRAM_UNDEFINED;
+ deref->accept(this);
+ if (this->result.file == PROGRAM_UNDEFINED) {
+ ir_print_visitor v;
+ printf("Failed to get tree for expression operand:\n");
+ deref->accept(&v);
+ exit(1);
+ }
+
+ ir_to_mesa_src_reg src;
+
+ src = this->result;
+ src.swizzle = MAKE_SWIZZLE4(components[0],
+ components[1],
+ components[2],
+ components[3]);
+ src.negate = ((unsigned(negate[0]) << 0)
+ | (unsigned(negate[1]) << 1)
+ | (unsigned(negate[2]) << 2)
+ | (unsigned(negate[3]) << 3));
+
+ /* Storage for our result. Ideally for an assignment we'd be using the
+ * actual storage for the result here, instead.
+ */
+ const ir_to_mesa_src_reg result_src = get_temp(ir->type);
+ ir_to_mesa_dst_reg result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+
+ /* Limit writes to the channels that will be used by result_src later.
+ * This does limit this temp's use as a temporary for multi-instruction
+ * sequences.
+ */
+ result_dst.writemask = (1 << ir->type->vector_elements) - 1;
+
+ ir_to_mesa_emit_op1(ir, OPCODE_SWZ, result_dst, src);
+ this->result = result_src;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_expression *ir)
+{
+ unsigned int operand;
+ struct ir_to_mesa_src_reg op[Elements(ir->operands)];
+ struct ir_to_mesa_src_reg result_src;
+ struct ir_to_mesa_dst_reg result_dst;
+
+ /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c)
+ */
+ if (ir->operation == ir_binop_add) {
+ if (try_emit_mad(ir, 1))
+ return;
+ if (try_emit_mad(ir, 0))
+ return;
+ }
+ if (try_emit_sat(ir))
+ return;
+
+ if (ir->operation == ir_quadop_vector) {
+ this->emit_swz(ir);
+ return;
+ }
+
+ for (operand = 0; operand < ir->get_num_operands(); operand++) {
+ this->result.file = PROGRAM_UNDEFINED;
+ ir->operands[operand]->accept(this);
+ if (this->result.file == PROGRAM_UNDEFINED) {
+ ir_print_visitor v;
+ printf("Failed to get tree for expression operand:\n");
+ ir->operands[operand]->accept(&v);
+ exit(1);
+ }
+ op[operand] = this->result;
+
+ /* Matrix expression operands should have been broken down to vector
+ * operations already.
+ */
+ assert(!ir->operands[operand]->type->is_matrix());
+ }
+
+ int vector_elements = ir->operands[0]->type->vector_elements;
+ if (ir->operands[1]) {
+ vector_elements = MAX2(vector_elements,
+ ir->operands[1]->type->vector_elements);
+ }
+
+ this->result.file = PROGRAM_UNDEFINED;
+
+ /* Storage for our result. Ideally for an assignment we'd be using
+ * the actual storage for the result here, instead.
+ */
+ result_src = get_temp(ir->type);
+ /* convenience for the emit functions below. */
+ result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+ /* Limit writes to the channels that will be used by result_src later.
+ * This does limit this temp's use as a temporary for multi-instruction
+ * sequences.
+ */
+ result_dst.writemask = (1 << ir->type->vector_elements) - 1;
+
+ switch (ir->operation) {
+ case ir_unop_logic_not:
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst,
+ op[0], src_reg_for_float(0.0));
+ break;
+ case ir_unop_neg:
+ op[0].negate = ~op[0].negate;
+ result_src = op[0];
+ break;
+ case ir_unop_abs:
+ ir_to_mesa_emit_op1(ir, OPCODE_ABS, result_dst, op[0]);
+ break;
+ case ir_unop_sign:
+ ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]);
+ break;
+ case ir_unop_rcp:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[0]);
+ break;
+
+ case ir_unop_exp2:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
+ break;
+ case ir_unop_exp:
+ case ir_unop_log:
+ assert(!"not reached: should be handled by ir_explog_to_explog2");
+ break;
+ case ir_unop_log2:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]);
+ break;
+ case ir_unop_sin:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]);
+ break;
+ case ir_unop_cos:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
+ break;
+ case ir_unop_sin_reduced:
+ emit_scs(ir, OPCODE_SIN, result_dst, op[0]);
+ break;
+ case ir_unop_cos_reduced:
+ emit_scs(ir, OPCODE_COS, result_dst, op[0]);
+ break;
+
+ case ir_unop_dFdx:
+ ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]);
+ break;
+ case ir_unop_dFdy:
+ ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]);
+ break;
+
+ case ir_unop_noise: {
+ const enum prog_opcode opcode =
+ prog_opcode(OPCODE_NOISE1
+ + (ir->operands[0]->type->vector_elements) - 1);
+ assert((opcode >= OPCODE_NOISE1) && (opcode <= OPCODE_NOISE4));
+
+ ir_to_mesa_emit_op1(ir, opcode, result_dst, op[0]);
+ break;
+ }
+
+ case ir_binop_add:
+ ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_sub:
+ ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]);
+ break;
+
+ case ir_binop_mul:
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_div:
+ assert(!"not reached: should be handled by ir_div_to_mul_rcp");
+ case ir_binop_mod:
+ assert(!"ir_binop_mod should have been converted to b * fract(a/b)");
+ break;
+
+ case ir_binop_less:
+ ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_greater:
+ ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_lequal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_gequal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_equal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_nequal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_all_equal:
+ /* "==" operator producing a scalar boolean. */
+ if (ir->operands[0]->type->is_vector() ||
+ ir->operands[1]->type->is_vector()) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
+ ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ,
+ result_dst, result_src, src_reg_for_float(0.0));
+ } else {
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+ }
+ break;
+ case ir_binop_any_nequal:
+ /* "!=" operator producing a scalar boolean. */
+ if (ir->operands[0]->type->is_vector() ||
+ ir->operands[1]->type->is_vector()) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
+ ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ result_dst, result_src, src_reg_for_float(0.0));
+ } else {
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ }
+ break;
+
+ case ir_unop_any:
+ assert(ir->operands[0]->type->is_vector());
+ ir_to_mesa_emit_dp(ir, result_dst, op[0], op[0],
+ ir->operands[0]->type->vector_elements);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ result_dst, result_src, src_reg_for_float(0.0));
+ break;
+
+ case ir_binop_logic_xor:
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ break;
+
+ case ir_binop_logic_or:
+ /* This could be a saturated add and skip the SNE. */
+ ir_to_mesa_emit_op2(ir, OPCODE_ADD,
+ result_dst,
+ op[0], op[1]);
+
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ result_dst,
+ result_src, src_reg_for_float(0.0));
+ break;
+
+ case ir_binop_logic_and:
+ /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+ result_dst,
+ op[0], op[1]);
+ break;
+
+ case ir_binop_dot:
+ assert(ir->operands[0]->type->is_vector());
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ ir_to_mesa_emit_dp(ir, result_dst, op[0], op[1],
+ ir->operands[0]->type->vector_elements);
+ break;
+
+ case ir_unop_sqrt:
+ /* sqrt(x) = x * rsq(x). */
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, result_src, op[0]);
+ /* For incoming channels <= 0, set the result to 0. */
+ op[0].negate = ~op[0].negate;
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst,
+ op[0], result_src, src_reg_for_float(0.0));
+ break;
+ case ir_unop_rsq:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
+ break;
+ case ir_unop_i2f:
+ case ir_unop_b2f:
+ case ir_unop_b2i:
+ /* Mesa IR lacks types, ints are stored as truncated floats. */
+ result_src = op[0];
+ break;
+ case ir_unop_f2i:
+ ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
+ break;
+ case ir_unop_f2b:
+ case ir_unop_i2b:
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
+ op[0], src_reg_for_float(0.0));
+ break;
+ case ir_unop_trunc:
+ ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
+ break;
+ case ir_unop_ceil:
+ op[0].negate = ~op[0].negate;
+ ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
+ result_src.negate = ~result_src.negate;
+ break;
+ case ir_unop_floor:
+ ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
+ break;
+ case ir_unop_fract:
+ ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]);
+ break;
+
+ case ir_binop_min:
+ ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_max:
+ ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_pow:
+ ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]);
+ break;
+
+ case ir_unop_bit_not:
+ case ir_unop_u2f:
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ case ir_unop_round_even:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+
+ case ir_quadop_vector:
+ /* This operation should have already been handled.
+ */
+ assert(!"Should not get here.");
+ break;
+ }
+
+ this->result = result_src;
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_swizzle *ir)
+{
+ ir_to_mesa_src_reg src_reg;
+ int i;
+ int swizzle[4];
+
+ /* Note that this is only swizzles in expressions, not those on the left
+ * hand side of an assignment, which do write masking. See ir_assignment
+ * for that.
+ */
+
+ ir->val->accept(this);
+ src_reg = this->result;
+ assert(src_reg.file != PROGRAM_UNDEFINED);
+
+ for (i = 0; i < 4; i++) {
+ if (i < ir->type->vector_elements) {
+ switch (i) {
+ case 0:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x);
+ break;
+ case 1:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y);
+ break;
+ case 2:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z);
+ break;
+ case 3:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w);
+ break;
+ }
+ } else {
+ /* If the type is smaller than a vec4, replicate the last
+ * channel out.
+ */
+ swizzle[i] = swizzle[ir->type->vector_elements - 1];
+ }
+ }
+
+ src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
+ swizzle[1],
+ swizzle[2],
+ swizzle[3]);
+
+ this->result = src_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
+{
+ variable_storage *entry = find_variable_storage(ir->var);
+
+ if (!entry) {
+ switch (ir->var->mode) {
+ case ir_var_uniform:
+ entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_UNIFORM,
+ ir->var->location);
+ this->variables.push_tail(entry);
+ break;
+ case ir_var_in:
+ case ir_var_out:
+ case ir_var_inout:
+ /* The linker assigns locations for varyings and attributes,
+ * including deprecated builtins (like gl_Color), user-assign
+ * generic attributes (glBindVertexLocation), and
+ * user-defined varyings.
+ *
+ * FINISHME: We would hit this path for function arguments. Fix!
+ */
+ assert(ir->var->location != -1);
+ if (ir->var->mode == ir_var_in ||
+ ir->var->mode == ir_var_inout) {
+ entry = new(mem_ctx) variable_storage(ir->var,
+ PROGRAM_INPUT,
+ ir->var->location);
+
+ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB &&
+ ir->var->location >= VERT_ATTRIB_GENERIC0) {
+ _mesa_add_attribute(prog->Attributes,
+ ir->var->name,
+ _mesa_sizeof_glsl_type(ir->var->type->gl_type),
+ ir->var->type->gl_type,
+ ir->var->location - VERT_ATTRIB_GENERIC0);
+ }
+ } else {
+ entry = new(mem_ctx) variable_storage(ir->var,
+ PROGRAM_OUTPUT,
+ ir->var->location);
+ }
+
+ break;
+ case ir_var_auto:
+ case ir_var_temporary:
+ entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(entry);
+
+ next_temp += type_size(ir->var->type);
+ break;
+ }
+
+ if (!entry) {
+ printf("Failed to make storage for %s\n", ir->var->name);
+ exit(1);
+ }
+ }
+
+ this->result = ir_to_mesa_src_reg(entry->file, entry->index, ir->var->type);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_array *ir)
+{
+ ir_constant *index;
+ ir_to_mesa_src_reg src_reg;
+ int element_size = type_size(ir->type);
+
+ index = ir->array_index->constant_expression_value();
+
+ ir->array->accept(this);
+ src_reg = this->result;
+
+ if (index) {
+ src_reg.index += index->value.i[0] * element_size;
+ } else {
+ ir_to_mesa_src_reg array_base = this->result;
+ /* Variable index array dereference. It eats the "vec4" of the
+ * base of the array and an index that offsets the Mesa register
+ * index.
+ */
+ ir->array_index->accept(this);
+
+ ir_to_mesa_src_reg index_reg;
+
+ if (element_size == 1) {
+ index_reg = this->result;
+ } else {
+ index_reg = get_temp(glsl_type::float_type);
+
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+ ir_to_mesa_dst_reg_from_src(index_reg),
+ this->result, src_reg_for_float(element_size));
+ }
+
+ src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg);
+ memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
+ }
+
+ /* If the type is smaller than a vec4, replicate the last channel out. */
+ if (ir->type->is_scalar() || ir->type->is_vector())
+ src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
+ else
+ src_reg.swizzle = SWIZZLE_NOOP;
+
+ this->result = src_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_record *ir)
+{
+ unsigned int i;
+ const glsl_type *struct_type = ir->record->type;
+ int offset = 0;
+
+ ir->record->accept(this);
+
+ for (i = 0; i < struct_type->length; i++) {
+ if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
+ break;
+ offset += type_size(struct_type->fields.structure[i].type);
+ }
+
+ /* If the type is smaller than a vec4, replicate the last channel out. */
+ if (ir->type->is_scalar() || ir->type->is_vector())
+ this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
+ else
+ this->result.swizzle = SWIZZLE_NOOP;
+
+ this->result.index += offset;
+}
+
+/**
+ * We want to be careful in assignment setup to hit the actual storage
+ * instead of potentially using a temporary like we might with the
+ * ir_dereference handler.
+ */
+static struct ir_to_mesa_dst_reg
+get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v)
+{
+ /* The LHS must be a dereference. If the LHS is a variable indexed array
+ * access of a vector, it must be separated into a series conditional moves
+ * before reaching this point (see ir_vec_index_to_cond_assign).
+ */
+ assert(ir->as_dereference());
+ ir_dereference_array *deref_array = ir->as_dereference_array();
+ if (deref_array) {
+ assert(!deref_array->array->type->is_vector());
+ }
+
+ /* Use the rvalue deref handler for the most part. We'll ignore
+ * swizzles in it and write swizzles using writemask, though.
+ */
+ ir->accept(v);
+ return ir_to_mesa_dst_reg_from_src(v->result);
+}
+
+/**
+ * Process the condition of a conditional assignment
+ *
+ * Examines the condition of a conditional assignment to generate the optimal
+ * first operand of a \c CMP instruction. If the condition is a relational
+ * operator with 0 (e.g., \c ir_binop_less), the value being compared will be
+ * used as the source for the \c CMP instruction. Otherwise the comparison
+ * is processed to a boolean result, and the boolean result is used as the
+ * operand to the CMP instruction.
+ */
+bool
+ir_to_mesa_visitor::process_move_condition(ir_rvalue *ir)
+{
+ ir_rvalue *src_ir = ir;
+ bool negate = true;
+ bool switch_order = false;
+
+ ir_expression *const expr = ir->as_expression();
+ if ((expr != NULL) && (expr->get_num_operands() == 2)) {
+ bool zero_on_left = false;
+
+ if (expr->operands[0]->is_zero()) {
+ src_ir = expr->operands[1];
+ zero_on_left = true;
+ } else if (expr->operands[1]->is_zero()) {
+ src_ir = expr->operands[0];
+ zero_on_left = false;
+ }
+
+ /* a is - 0 + - 0 +
+ * (a < 0) T F F ( a < 0) T F F
+ * (0 < a) F F T (-a < 0) F F T
+ * (a <= 0) T T F (-a < 0) F F T (swap order of other operands)
+ * (0 <= a) F T T ( a < 0) T F F (swap order of other operands)
+ * (a > 0) F F T (-a < 0) F F T
+ * (0 > a) T F F ( a < 0) T F F
+ * (a >= 0) F T T ( a < 0) T F F (swap order of other operands)
+ * (0 >= a) T T F (-a < 0) F F T (swap order of other operands)
+ *
+ * Note that exchanging the order of 0 and 'a' in the comparison simply
+ * means that the value of 'a' should be negated.
+ */
+ if (src_ir != ir) {
+ switch (expr->operation) {
+ case ir_binop_less:
+ switch_order = false;
+ negate = zero_on_left;
+ break;
+
+ case ir_binop_greater:
+ switch_order = false;
+ negate = !zero_on_left;
+ break;
+
+ case ir_binop_lequal:
+ switch_order = true;
+ negate = !zero_on_left;
+ break;
+
+ case ir_binop_gequal:
+ switch_order = true;
+ negate = zero_on_left;
+ break;
+
+ default:
+ /* This isn't the right kind of comparison afterall, so make sure
+ * the whole condition is visited.
+ */
+ src_ir = ir;
+ break;
+ }
+ }
+ }
+
+ src_ir->accept(this);
+
+ /* We use the OPCODE_CMP (a < 0 ? b : c) for conditional moves, and the
+ * condition we produced is 0.0 or 1.0. By flipping the sign, we can
+ * choose which value OPCODE_CMP produces without an extra instruction
+ * computing the condition.
+ */
+ if (negate)
+ this->result.negate = ~this->result.negate;
+
+ return switch_order;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_assignment *ir)
+{
+ struct ir_to_mesa_dst_reg l;
+ struct ir_to_mesa_src_reg r;
+ int i;
+
+ ir->rhs->accept(this);
+ r = this->result;
+
+ l = get_assignment_lhs(ir->lhs, this);
+
+ /* FINISHME: This should really set to the correct maximal writemask for each
+ * FINISHME: component written (in the loops below). This case can only
+ * FINISHME: occur for matrices, arrays, and structures.
+ */
+ if (ir->write_mask == 0) {
+ assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector());
+ l.writemask = WRITEMASK_XYZW;
+ } else if (ir->lhs->type->is_scalar()) {
+ /* FINISHME: This hack makes writing to gl_FragDepth, which lives in the
+ * FINISHME: W component of fragment shader output zero, work correctly.
+ */
+ l.writemask = WRITEMASK_XYZW;
+ } else {
+ int swizzles[4];
+ int first_enabled_chan = 0;
+ int rhs_chan = 0;
+
+ assert(ir->lhs->type->is_vector());
+ l.writemask = ir->write_mask;
+
+ for (int i = 0; i < 4; i++) {
+ if (l.writemask & (1 << i)) {
+ first_enabled_chan = GET_SWZ(r.swizzle, i);
+ break;
+ }
+ }
+
+ /* Swizzle a small RHS vector into the channels being written.
+ *
+ * glsl ir treats write_mask as dictating how many channels are
+ * present on the RHS while Mesa IR treats write_mask as just
+ * showing which channels of the vec4 RHS get written.
+ */
+ for (int i = 0; i < 4; i++) {
+ if (l.writemask & (1 << i))
+ swizzles[i] = GET_SWZ(r.swizzle, rhs_chan++);
+ else
+ swizzles[i] = first_enabled_chan;
+ }
+ r.swizzle = MAKE_SWIZZLE4(swizzles[0], swizzles[1],
+ swizzles[2], swizzles[3]);
+ }
+
+ assert(l.file != PROGRAM_UNDEFINED);
+ assert(r.file != PROGRAM_UNDEFINED);
+
+ if (ir->condition) {
+ const bool switch_order = this->process_move_condition(ir->condition);
+ ir_to_mesa_src_reg condition = this->result;
+
+ for (i = 0; i < type_size(ir->lhs->type); i++) {
+ if (switch_order) {
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
+ condition, ir_to_mesa_src_reg_from_dst(l), r);
+ } else {
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
+ condition, r, ir_to_mesa_src_reg_from_dst(l));
+ }
+
+ l.index++;
+ r.index++;
+ }
+ } else {
+ for (i = 0; i < type_size(ir->lhs->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_constant *ir)
+{
+ ir_to_mesa_src_reg src_reg;
+ GLfloat stack_vals[4] = { 0 };
+ GLfloat *values = stack_vals;
+ unsigned int i;
+
+ /* Unfortunately, 4 floats is all we can get into
+ * _mesa_add_unnamed_constant. So, make a temp to store an
+ * aggregate constant and move each constant value into it. If we
+ * get lucky, copy propagation will eliminate the extra moves.
+ */
+
+ if (ir->type->base_type == GLSL_TYPE_STRUCT) {
+ ir_to_mesa_src_reg temp_base = get_temp(ir->type);
+ ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
+
+ foreach_iter(exec_list_iterator, iter, ir->components) {
+ ir_constant *field_value = (ir_constant *)iter.get();
+ int size = type_size(field_value->type);
+
+ assert(size > 0);
+
+ field_value->accept(this);
+ src_reg = this->result;
+
+ for (i = 0; i < (unsigned int)size; i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
+
+ src_reg.index++;
+ temp.index++;
+ }
+ }
+ this->result = temp_base;
+ return;
+ }
+
+ if (ir->type->is_array()) {
+ ir_to_mesa_src_reg temp_base = get_temp(ir->type);
+ ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
+ int size = type_size(ir->type->fields.array);
+
+ assert(size > 0);
+
+ for (i = 0; i < ir->type->length; i++) {
+ ir->array_elements[i]->accept(this);
+ src_reg = this->result;
+ for (int j = 0; j < size; j++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
+
+ src_reg.index++;
+ temp.index++;
+ }
+ }
+ this->result = temp_base;
+ return;
+ }
+
+ if (ir->type->is_matrix()) {
+ ir_to_mesa_src_reg mat = get_temp(ir->type);
+ ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat);
+
+ for (i = 0; i < ir->type->matrix_columns; i++) {
+ assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+ values = &ir->value.f[i * ir->type->vector_elements];
+
+ src_reg = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, NULL);
+ src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ values,
+ ir->type->vector_elements,
+ &src_reg.swizzle);
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg);
+
+ mat_column.index++;
+ }
+
+ this->result = mat;
+ return;
+ }
+
+ src_reg.file = PROGRAM_CONSTANT;
+ switch (ir->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ values = &ir->value.f[0];
+ break;
+ case GLSL_TYPE_UINT:
+ for (i = 0; i < ir->type->vector_elements; i++) {
+ values[i] = ir->value.u[i];
+ }
+ break;
+ case GLSL_TYPE_INT:
+ for (i = 0; i < ir->type->vector_elements; i++) {
+ values[i] = ir->value.i[i];
+ }
+ break;
+ case GLSL_TYPE_BOOL:
+ for (i = 0; i < ir->type->vector_elements; i++) {
+ values[i] = ir->value.b[i];
+ }
+ break;
+ default:
+ assert(!"Non-float/uint/int/bool constant");
+ }
+
+ this->result = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, ir->type);
+ this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ values,
+ ir->type->vector_elements,
+ &this->result.swizzle);
+}
+
+function_entry *
+ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
+{
+ function_entry *entry;
+
+ foreach_iter(exec_list_iterator, iter, this->function_signatures) {
+ entry = (function_entry *)iter.get();
+
+ if (entry->sig == sig)
+ return entry;
+ }
+
+ entry = talloc(mem_ctx, function_entry);
+ entry->sig = sig;
+ entry->sig_id = this->next_signature_id++;
+ entry->bgn_inst = NULL;
+
+ /* Allocate storage for all the parameters. */
+ foreach_iter(exec_list_iterator, iter, sig->parameters) {
+ ir_variable *param = (ir_variable *)iter.get();
+ variable_storage *storage;
+
+ storage = find_variable_storage(param);
+ assert(!storage);
+
+ storage = new(mem_ctx) variable_storage(param, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(storage);
+
+ this->next_temp += type_size(param->type);
+ }
+
+ if (!sig->return_type->is_void()) {
+ entry->return_reg = get_temp(sig->return_type);
+ } else {
+ entry->return_reg = ir_to_mesa_undef;
+ }
+
+ this->function_signatures.push_tail(entry);
+ return entry;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_call *ir)
+{
+ ir_to_mesa_instruction *call_inst;
+ ir_function_signature *sig = ir->get_callee();
+ function_entry *entry = get_function_signature(sig);
+ int i;
+
+ /* Process in parameters. */
+ exec_list_iterator sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_in ||
+ param->mode == ir_var_inout) {
+ variable_storage *storage = find_variable_storage(param);
+ assert(storage);
+
+ param_rval->accept(this);
+ ir_to_mesa_src_reg r = this->result;
+
+ ir_to_mesa_dst_reg l;
+ l.file = storage->file;
+ l.index = storage->index;
+ l.reladdr = NULL;
+ l.writemask = WRITEMASK_XYZW;
+ l.cond_mask = COND_TR;
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Emit call instruction */
+ call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL,
+ ir_to_mesa_undef_dst, ir_to_mesa_undef);
+ call_inst->function = entry;
+
+ /* Process out parameters. */
+ sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_out ||
+ param->mode == ir_var_inout) {
+ variable_storage *storage = find_variable_storage(param);
+ assert(storage);
+
+ ir_to_mesa_src_reg r;
+ r.file = storage->file;
+ r.index = storage->index;
+ r.reladdr = NULL;
+ r.swizzle = SWIZZLE_NOOP;
+ r.negate = 0;
+
+ param_rval->accept(this);
+ ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result);
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Process return value. */
+ this->result = entry->return_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_texture *ir)
+{
+ ir_to_mesa_src_reg result_src, coord, lod_info, projector;
+ ir_to_mesa_dst_reg result_dst, coord_dst;
+ ir_to_mesa_instruction *inst = NULL;
+ prog_opcode opcode = OPCODE_NOP;
+
+ ir->coordinate->accept(this);
+
+ /* Put our coords in a temp. We'll need to modify them for shadow,
+ * projection, or LOD, so the only case we'd use it as is is if
+ * we're doing plain old texturing. Mesa IR optimization should
+ * handle cleaning up our mess in that case.
+ */
+ coord = get_temp(glsl_type::vec4_type);
+ coord_dst = ir_to_mesa_dst_reg_from_src(coord);
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst,
+ this->result);
+
+ if (ir->projector) {
+ ir->projector->accept(this);
+ projector = this->result;
+ }
+
+ /* Storage for our result. Ideally for an assignment we'd be using
+ * the actual storage for the result here, instead.
+ */
+ result_src = get_temp(glsl_type::vec4_type);
+ result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+
+ switch (ir->op) {
+ case ir_tex:
+ opcode = OPCODE_TEX;
+ break;
+ case ir_txb:
+ opcode = OPCODE_TXB;
+ ir->lod_info.bias->accept(this);
+ lod_info = this->result;
+ break;
+ case ir_txl:
+ opcode = OPCODE_TXL;
+ ir->lod_info.lod->accept(this);
+ lod_info = this->result;
+ break;
+ case ir_txd:
+ case ir_txf:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+ }
+
+ if (ir->projector) {
+ if (opcode == OPCODE_TEX) {
+ /* Slot the projector in as the last component of the coord. */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, projector);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ opcode = OPCODE_TXP;
+ } else {
+ ir_to_mesa_src_reg coord_w = coord;
+ coord_w.swizzle = SWIZZLE_WWWW;
+
+ /* For the other TEX opcodes there's no projective version
+ * since the last slot is taken up by lod info. Do the
+ * projective divide now.
+ */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector);
+
+ coord_dst.writemask = WRITEMASK_XYZ;
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w);
+
+ coord_dst.writemask = WRITEMASK_XYZW;
+ coord.swizzle = SWIZZLE_XYZW;
+ }
+ }
+
+ if (ir->shadow_comparitor) {
+ /* Slot the shadow value in as the second to last component of the
+ * coord.
+ */
+ ir->shadow_comparitor->accept(this);
+ coord_dst.writemask = WRITEMASK_Z;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, this->result);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ }
+
+ if (opcode == OPCODE_TXL || opcode == OPCODE_TXB) {
+ /* Mesa IR stores lod or lod bias in the last channel of the coords. */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, lod_info);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ }
+
+ inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord);
+
+ if (ir->shadow_comparitor)
+ inst->tex_shadow = GL_TRUE;
+
+ inst->sampler = _mesa_get_sampler_uniform_value(ir->sampler,
+ this->shader_program,
+ this->prog);
+
+ const glsl_type *sampler_type = ir->sampler->type;
+
+ switch (sampler_type->sampler_dimensionality) {
+ case GLSL_SAMPLER_DIM_1D:
+ inst->tex_target = (sampler_type->sampler_array)
+ ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_2D:
+ inst->tex_target = (sampler_type->sampler_array)
+ ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_3D:
+ inst->tex_target = TEXTURE_3D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_CUBE:
+ inst->tex_target = TEXTURE_CUBE_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_RECT:
+ inst->tex_target = TEXTURE_RECT_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_BUF:
+ assert(!"FINISHME: Implement ARB_texture_buffer_object");
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+
+ this->result = result_src;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_return *ir)
+{
+ if (ir->get_value()) {
+ ir_to_mesa_dst_reg l;
+ int i;
+
+ assert(current_function);
+
+ ir->get_value()->accept(this);
+ ir_to_mesa_src_reg r = this->result;
+
+ l = ir_to_mesa_dst_reg_from_src(current_function->return_reg);
+
+ for (i = 0; i < type_size(current_function->sig->return_type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ ir_to_mesa_emit_op0(ir, OPCODE_RET);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_discard *ir)
+{
+ struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
+
+ if (ir->condition) {
+ ir->condition->accept(this);
+ this->result.negate = ~this->result.negate;
+ ir_to_mesa_emit_op1(ir, OPCODE_KIL, ir_to_mesa_undef_dst, this->result);
+ } else {
+ ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV);
+ }
+
+ fp->UsesKill = GL_TRUE;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_if *ir)
+{
+ ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL;
+ ir_to_mesa_instruction *prev_inst;
+
+ prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
+
+ ir->condition->accept(this);
+ assert(this->result.file != PROGRAM_UNDEFINED);
+
+ if (this->options->EmitCondCodes) {
+ cond_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
+
+ /* See if we actually generated any instruction for generating
+ * the condition. If not, then cook up a move to a temp so we
+ * have something to set cond_update on.
+ */
+ if (cond_inst == prev_inst) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::bool_type);
+ cond_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(temp),
+ result);
+ }
+ cond_inst->cond_update = GL_TRUE;
+
+ if_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_IF);
+ if_inst->dst_reg.cond_mask = COND_NE;
+ } else {
+ if_inst = ir_to_mesa_emit_op1(ir->condition,
+ OPCODE_IF, ir_to_mesa_undef_dst,
+ this->result);
+ }
+
+ this->instructions.push_tail(if_inst);
+
+ visit_exec_list(&ir->then_instructions, this);
+
+ if (!ir->else_instructions.is_empty()) {
+ else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE);
+ visit_exec_list(&ir->else_instructions, this);
+ }
+
+ if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
+ ir_to_mesa_undef_dst, ir_to_mesa_undef);
+}
+
+ir_to_mesa_visitor::ir_to_mesa_visitor()
+{
+ result.file = PROGRAM_UNDEFINED;
+ next_temp = 1;
+ next_signature_id = 1;
+ current_function = NULL;
+ mem_ctx = talloc_new(NULL);
+}
+
+ir_to_mesa_visitor::~ir_to_mesa_visitor()
+{
+ talloc_free(mem_ctx);
+}
+
+static struct prog_src_register
+mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
+{
+ struct prog_src_register mesa_reg;
+
+ mesa_reg.File = reg.file;
+ assert(reg.index < (1 << INST_INDEX_BITS));
+ mesa_reg.Index = reg.index;
+ mesa_reg.Swizzle = reg.swizzle;
+ mesa_reg.RelAddr = reg.reladdr != NULL;
+ mesa_reg.Negate = reg.negate;
+ mesa_reg.Abs = 0;
+ mesa_reg.HasIndex2 = GL_FALSE;
+ mesa_reg.RelAddr2 = 0;
+ mesa_reg.Index2 = 0;
+
+ return mesa_reg;
+}
+
+static void
+set_branchtargets(ir_to_mesa_visitor *v,
+ struct prog_instruction *mesa_instructions,
+ int num_instructions)
+{
+ int if_count = 0, loop_count = 0;
+ int *if_stack, *loop_stack;
+ int if_stack_pos = 0, loop_stack_pos = 0;
+ int i, j;
+
+ for (i = 0; i < num_instructions; i++) {
+ switch (mesa_instructions[i].Opcode) {
+ case OPCODE_IF:
+ if_count++;
+ break;
+ case OPCODE_BGNLOOP:
+ loop_count++;
+ break;
+ case OPCODE_BRK:
+ case OPCODE_CONT:
+ mesa_instructions[i].BranchTarget = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if_stack = talloc_zero_array(v->mem_ctx, int, if_count);
+ loop_stack = talloc_zero_array(v->mem_ctx, int, loop_count);
+
+ for (i = 0; i < num_instructions; i++) {
+ switch (mesa_instructions[i].Opcode) {
+ case OPCODE_IF:
+ if_stack[if_stack_pos] = i;
+ if_stack_pos++;
+ break;
+ case OPCODE_ELSE:
+ mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
+ if_stack[if_stack_pos - 1] = i;
+ break;
+ case OPCODE_ENDIF:
+ mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
+ if_stack_pos--;
+ break;
+ case OPCODE_BGNLOOP:
+ loop_stack[loop_stack_pos] = i;
+ loop_stack_pos++;
+ break;
+ case OPCODE_ENDLOOP:
+ loop_stack_pos--;
+ /* Rewrite any breaks/conts at this nesting level (haven't
+ * already had a BranchTarget assigned) to point to the end
+ * of the loop.
+ */
+ for (j = loop_stack[loop_stack_pos]; j < i; j++) {
+ if (mesa_instructions[j].Opcode == OPCODE_BRK ||
+ mesa_instructions[j].Opcode == OPCODE_CONT) {
+ if (mesa_instructions[j].BranchTarget == -1) {
+ mesa_instructions[j].BranchTarget = i;
+ }
+ }
+ }
+ /* The loop ends point at each other. */
+ mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
+ mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
+ break;
+ case OPCODE_CAL:
+ foreach_iter(exec_list_iterator, iter, v->function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (entry->sig_id == mesa_instructions[i].BranchTarget) {
+ mesa_instructions[i].BranchTarget = entry->inst;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+print_program(struct prog_instruction *mesa_instructions,
+ ir_instruction **mesa_instruction_annotation,
+ int num_instructions)
+{
+ ir_instruction *last_ir = NULL;
+ int i;
+ int indent = 0;
+
+ for (i = 0; i < num_instructions; i++) {
+ struct prog_instruction *mesa_inst = mesa_instructions + i;
+ ir_instruction *ir = mesa_instruction_annotation[i];
+
+ fprintf(stdout, "%3d: ", i);
+
+ if (last_ir != ir && ir) {
+ int j;
+
+ for (j = 0; j < indent; j++) {
+ fprintf(stdout, " ");
+ }
+ ir->print();
+ printf("\n");
+ last_ir = ir;
+
+ fprintf(stdout, " "); /* line number spacing. */
+ }
+
+ indent = _mesa_fprint_instruction_opt(stdout, mesa_inst, indent,
+ PROG_PRINT_DEBUG, NULL);
+ }
+}
+
+static void
+count_resources(struct gl_program *prog)
+{
+ unsigned int i;
+
+ prog->SamplersUsed = 0;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = &prog->Instructions[i];
+
+ if (_mesa_is_tex_instruction(inst->Opcode)) {
+ prog->SamplerTargets[inst->TexSrcUnit] =
+ (gl_texture_index)inst->TexSrcTarget;
+ prog->SamplersUsed |= 1 << inst->TexSrcUnit;
+ if (inst->TexShadow) {
+ prog->ShadowSamplers |= 1 << inst->TexSrcUnit;
+ }
+ }
+ }
+
+ _mesa_update_shader_textures_used(prog);
+}
+
+struct uniform_sort {
+ struct gl_uniform *u;
+ int pos;
+};
+
+/* The shader_program->Uniforms list is almost sorted in increasing
+ * uniform->{Frag,Vert}Pos locations, but not quite when there are
+ * uniforms shared between targets. We need to add parameters in
+ * increasing order for the targets.
+ */
+static int
+sort_uniforms(const void *a, const void *b)
+{
+ struct uniform_sort *u1 = (struct uniform_sort *)a;
+ struct uniform_sort *u2 = (struct uniform_sort *)b;
+
+ return u1->pos - u2->pos;
+}
+
+/* Add the uniforms to the parameters. The linker chose locations
+ * in our parameters lists (which weren't created yet), which the
+ * uniforms code will use to poke values into our parameters list
+ * when uniforms are updated.
+ */
+static void
+add_uniforms_to_parameters_list(struct gl_shader_program *shader_program,
+ struct gl_shader *shader,
+ struct gl_program *prog)
+{
+ unsigned int i;
+ unsigned int next_sampler = 0, num_uniforms = 0;
+ struct uniform_sort *sorted_uniforms;
+
+ sorted_uniforms = talloc_array(NULL, struct uniform_sort,
+ shader_program->Uniforms->NumUniforms);
+
+ for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) {
+ struct gl_uniform *uniform = shader_program->Uniforms->Uniforms + i;
+ int parameter_index = -1;
+
+ switch (shader->Type) {
+ case GL_VERTEX_SHADER:
+ parameter_index = uniform->VertPos;
+ break;
+ case GL_FRAGMENT_SHADER:
+ parameter_index = uniform->FragPos;
+ break;
+ case GL_GEOMETRY_SHADER:
+ parameter_index = uniform->GeomPos;
+ break;
+ }
+
+ /* Only add uniforms used in our target. */
+ if (parameter_index != -1) {
+ sorted_uniforms[num_uniforms].pos = parameter_index;
+ sorted_uniforms[num_uniforms].u = uniform;
+ num_uniforms++;
+ }
+ }
+
+ qsort(sorted_uniforms, num_uniforms, sizeof(struct uniform_sort),
+ sort_uniforms);
+
+ for (i = 0; i < num_uniforms; i++) {
+ struct gl_uniform *uniform = sorted_uniforms[i].u;
+ int parameter_index = sorted_uniforms[i].pos;
+ const glsl_type *type = uniform->Type;
+ unsigned int size;
+
+ if (type->is_vector() ||
+ type->is_scalar()) {
+ size = type->vector_elements;
+ } else {
+ size = type_size(type) * 4;
+ }
+
+ gl_register_file file;
+ if (type->is_sampler() ||
+ (type->is_array() && type->fields.array->is_sampler())) {
+ file = PROGRAM_SAMPLER;
+ } else {
+ file = PROGRAM_UNIFORM;
+ }
+
+ GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
+ uniform->Name);
+
+ if (index < 0) {
+ index = _mesa_add_parameter(prog->Parameters, file,
+ uniform->Name, size, type->gl_type,
+ NULL, NULL, 0x0);
+
+ /* Sampler uniform values are stored in prog->SamplerUnits,
+ * and the entry in that array is selected by this index we
+ * store in ParameterValues[].
+ */
+ if (file == PROGRAM_SAMPLER) {
+ for (unsigned int j = 0; j < size / 4; j++)
+ prog->Parameters->ParameterValues[index + j][0] = next_sampler++;
+ }
+
+ /* The location chosen in the Parameters list here (returned
+ * from _mesa_add_uniform) has to match what the linker chose.
+ */
+ if (index != parameter_index) {
+ fail_link(shader_program, "Allocation of uniform `%s' to target "
+ "failed (%d vs %d)\n",
+ uniform->Name, index, parameter_index);
+ }
+ }
+ }
+
+ talloc_free(sorted_uniforms);
+}
+
+static void
+set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
+ struct gl_shader_program *shader_program,
+ const char *name, const glsl_type *type,
+ ir_constant *val)
+{
+ if (type->is_record()) {
+ ir_constant *field_constant;
+
+ field_constant = (ir_constant *)val->components.get_head();
+
+ for (unsigned int i = 0; i < type->length; i++) {
+ const glsl_type *field_type = type->fields.structure[i].type;
+ const char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name,
+ type->fields.structure[i].name);
+ set_uniform_initializer(ctx, mem_ctx, shader_program, field_name,
+ field_type, field_constant);
+ field_constant = (ir_constant *)field_constant->next;
+ }
+ return;
+ }
+
+ int loc = _mesa_get_uniform_location(ctx, shader_program, name);
+
+ if (loc == -1) {
+ fail_link(shader_program,
+ "Couldn't find uniform for initializer %s\n", name);
+ return;
+ }
+
+ for (unsigned int i = 0; i < (type->is_array() ? type->length : 1); i++) {
+ ir_constant *element;
+ const glsl_type *element_type;
+ if (type->is_array()) {
+ element = val->array_elements[i];
+ element_type = type->fields.array;
+ } else {
+ element = val;
+ element_type = type;
+ }
+
+ void *values;
+
+ if (element_type->base_type == GLSL_TYPE_BOOL) {
+ int *conv = talloc_array(mem_ctx, int, element_type->components());
+ for (unsigned int j = 0; j < element_type->components(); j++) {
+ conv[j] = element->value.b[j];
+ }
+ values = (void *)conv;
+ element_type = glsl_type::get_instance(GLSL_TYPE_INT,
+ element_type->vector_elements,
+ 1);
+ } else {
+ values = &element->value;
+ }
+
+ if (element_type->is_matrix()) {
+ _mesa_uniform_matrix(ctx, shader_program,
+ element_type->matrix_columns,
+ element_type->vector_elements,
+ loc, 1, GL_FALSE, (GLfloat *)values);
+ loc += element_type->matrix_columns;
+ } else {
+ _mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns,
+ values, element_type->gl_type);
+ loc += type_size(element_type);
+ }
+ }
+}
+
+static void
+set_uniform_initializers(struct gl_context *ctx,
+ struct gl_shader_program *shader_program)
+{
+ void *mem_ctx = NULL;
+
+ for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_shader *shader = shader_program->_LinkedShaders[i];
+
+ if (shader == NULL)
+ continue;
+
+ foreach_iter(exec_list_iterator, iter, *shader->ir) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir_variable *var = ir->as_variable();
+
+ if (!var || var->mode != ir_var_uniform || !var->constant_value)
+ continue;
+
+ if (!mem_ctx)
+ mem_ctx = talloc_new(NULL);
+
+ set_uniform_initializer(ctx, mem_ctx, shader_program, var->name,
+ var->type, var->constant_value);
+ }
+ }
+
+ talloc_free(mem_ctx);
+}
+
+
+/**
+ * Convert a shader's GLSL IR into a Mesa gl_program.
+ */
+static struct gl_program *
+get_mesa_program(struct gl_context *ctx,
+ struct gl_shader_program *shader_program,
+ struct gl_shader *shader)
+{
+ ir_to_mesa_visitor v;
+ struct prog_instruction *mesa_instructions, *mesa_inst;
+ ir_instruction **mesa_instruction_annotation;
+ int i;
+ struct gl_program *prog;
+ GLenum target;
+ const char *target_string;
+ GLboolean progress;
+ struct gl_shader_compiler_options *options =
+ &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(shader->Type)];
+
+ switch (shader->Type) {
+ case GL_VERTEX_SHADER:
+ target = GL_VERTEX_PROGRAM_ARB;
+ target_string = "vertex";
+ break;
+ case GL_FRAGMENT_SHADER:
+ target = GL_FRAGMENT_PROGRAM_ARB;
+ target_string = "fragment";
+ break;
+ case GL_GEOMETRY_SHADER:
+ target = GL_GEOMETRY_PROGRAM_NV;
+ target_string = "geometry";
+ break;
+ default:
+ assert(!"should not be reached");
+ return NULL;
+ }
+
+ validate_ir_tree(shader->ir);
+
+ prog = ctx->Driver.NewProgram(ctx, target, shader_program->Name);
+ if (!prog)
+ return NULL;
+ prog->Parameters = _mesa_new_parameter_list();
+ prog->Varying = _mesa_new_parameter_list();
+ prog->Attributes = _mesa_new_parameter_list();
+ v.ctx = ctx;
+ v.prog = prog;
+ v.shader_program = shader_program;
+ v.options = options;
+
+ add_uniforms_to_parameters_list(shader_program, shader, prog);
+
+ /* Emit Mesa IR for main(). */
+ visit_exec_list(shader->ir, &v);
+ v.ir_to_mesa_emit_op0(NULL, OPCODE_END);
+
+ /* Now emit bodies for any functions that were used. */
+ do {
+ progress = GL_FALSE;
+
+ foreach_iter(exec_list_iterator, iter, v.function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (!entry->bgn_inst) {
+ v.current_function = entry;
+
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB);
+ entry->bgn_inst->function = entry;
+
+ visit_exec_list(&entry->sig->body, &v);
+
+ ir_to_mesa_instruction *last;
+ last = (ir_to_mesa_instruction *)v.instructions.get_tail();
+ if (last->op != OPCODE_RET)
+ v.ir_to_mesa_emit_op0(NULL, OPCODE_RET);
+
+ ir_to_mesa_instruction *end;
+ end = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB);
+ end->function = entry;
+
+ progress = GL_TRUE;
+ }
+ }
+ } while (progress);
+
+ prog->NumTemporaries = v.next_temp;
+
+ int num_instructions = 0;
+ foreach_iter(exec_list_iterator, iter, v.instructions) {
+ num_instructions++;
+ }
+
+ mesa_instructions =
+ (struct prog_instruction *)calloc(num_instructions,
+ sizeof(*mesa_instructions));
+ mesa_instruction_annotation = talloc_array(v.mem_ctx, ir_instruction *,
+ num_instructions);
+
+ /* Convert ir_mesa_instructions into prog_instructions.
+ */
+ mesa_inst = mesa_instructions;
+ i = 0;
+ foreach_iter(exec_list_iterator, iter, v.instructions) {
+ const ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
+
+ mesa_inst->Opcode = inst->op;
+ mesa_inst->CondUpdate = inst->cond_update;
+ if (inst->saturate)
+ mesa_inst->SaturateMode = SATURATE_ZERO_ONE;
+ mesa_inst->DstReg.File = inst->dst_reg.file;
+ mesa_inst->DstReg.Index = inst->dst_reg.index;
+ mesa_inst->DstReg.CondMask = inst->dst_reg.cond_mask;
+ mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
+ mesa_inst->DstReg.RelAddr = inst->dst_reg.reladdr != NULL;
+ mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
+ mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
+ mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
+ mesa_inst->TexSrcUnit = inst->sampler;
+ mesa_inst->TexSrcTarget = inst->tex_target;
+ mesa_inst->TexShadow = inst->tex_shadow;
+ mesa_instruction_annotation[i] = inst->ir;
+
+ /* Set IndirectRegisterFiles. */
+ if (mesa_inst->DstReg.RelAddr)
+ prog->IndirectRegisterFiles |= 1 << mesa_inst->DstReg.File;
+
+ /* Update program's bitmask of indirectly accessed register files */
+ for (unsigned src = 0; src < 3; src++)
+ if (mesa_inst->SrcReg[src].RelAddr)
+ prog->IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File;
+
+ if (options->EmitNoIfs && mesa_inst->Opcode == OPCODE_IF) {
+ fail_link(shader_program, "Couldn't flatten if statement\n");
+ }
+
+ switch (mesa_inst->Opcode) {
+ case OPCODE_BGNSUB:
+ inst->function->inst = i;
+ mesa_inst->Comment = strdup(inst->function->sig->function_name());
+ break;
+ case OPCODE_ENDSUB:
+ mesa_inst->Comment = strdup(inst->function->sig->function_name());
+ break;
+ case OPCODE_CAL:
+ mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */
+ break;
+ case OPCODE_ARL:
+ prog->NumAddressRegs = 1;
+ break;
+ default:
+ break;
+ }
+
+ mesa_inst++;
+ i++;
+
+ if (!shader_program->LinkStatus)
+ break;
+ }
+
+ if (!shader_program->LinkStatus) {
+ free(mesa_instructions);
+ _mesa_reference_program(ctx, &shader->Program, NULL);
+ return NULL;
+ }
+
+ set_branchtargets(&v, mesa_instructions, num_instructions);
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ printf("\n");
+ printf("GLSL IR for linked %s program %d:\n", target_string,
+ shader_program->Name);
+ _mesa_print_ir(shader->ir, NULL);
+ printf("\n");
+ printf("\n");
+ printf("Mesa IR for linked %s program %d:\n", target_string,
+ shader_program->Name);
+ print_program(mesa_instructions, mesa_instruction_annotation,
+ num_instructions);
+ }
+
+ prog->Instructions = mesa_instructions;
+ prog->NumInstructions = num_instructions;
+
+ do_set_program_inouts(shader->ir, prog);
+ count_resources(prog);
+
+ _mesa_reference_program(ctx, &shader->Program, prog);
+
+ if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) {
+ _mesa_optimize_program(ctx, prog);
+ }
+
+ return prog;
+}
+
+extern "C" {
+
+/**
+ * Called via ctx->Driver.CompilerShader().
+ * This is a no-op.
+ * XXX can we remove the ctx->Driver.CompileShader() hook?
+ */
+GLboolean
+_mesa_ir_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
+{
+ assert(shader->CompileStatus);
+ (void) ctx;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Link a shader.
+ * Called via ctx->Driver.LinkShader()
+ * This actually involves converting GLSL IR into Mesa gl_programs with
+ * code lowering and other optimizations.
+ */
+GLboolean
+_mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ assert(prog->LinkStatus);
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ bool progress;
+ exec_list *ir = prog->_LinkedShaders[i]->ir;
+ const struct gl_shader_compiler_options *options =
+ &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(prog->_LinkedShaders[i]->Type)];
+
+ do {
+ progress = false;
+
+ /* Lowering */
+ do_mat_op_to_vec(ir);
+ lower_instructions(ir, (MOD_TO_FRACT | DIV_TO_MUL_RCP | EXP_TO_EXP2
+ | LOG_TO_LOG2
+ | ((options->EmitNoPow) ? POW_TO_EXP2 : 0)));
+
+ progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress;
+
+ progress = do_common_optimization(ir, true, options->MaxUnrollIterations) || progress;
+
+ progress = lower_quadop_vector(ir, true) || progress;
+
+ if (options->EmitNoIfs) {
+ progress = lower_discard(ir) || progress;
+ progress = lower_if_to_cond_assign(ir) || progress;
+ }
+
+ if (options->EmitNoNoise)
+ progress = lower_noise(ir) || progress;
+
+ /* If there are forms of indirect addressing that the driver
+ * cannot handle, perform the lowering pass.
+ */
+ if (options->EmitNoIndirectInput || options->EmitNoIndirectOutput
+ || options->EmitNoIndirectTemp || options->EmitNoIndirectUniform)
+ progress =
+ lower_variable_index_to_cond_assign(ir,
+ options->EmitNoIndirectInput,
+ options->EmitNoIndirectOutput,
+ options->EmitNoIndirectTemp,
+ options->EmitNoIndirectUniform)
+ || progress;
+
+ progress = do_vec_index_to_cond_assign(ir) || progress;
+ } while (progress);
+
+ validate_ir_tree(ir);
+ }
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_program *linked_prog;
+
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ linked_prog = get_mesa_program(ctx, prog, prog->_LinkedShaders[i]);
+
+ if (linked_prog) {
+ bool ok = true;
+
+ switch (prog->_LinkedShaders[i]->Type) {
+ case GL_VERTEX_SHADER:
+ _mesa_reference_vertprog(ctx, &prog->VertexProgram,
+ (struct gl_vertex_program *)linked_prog);
+ ok = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
+ linked_prog);
+ break;
+ case GL_FRAGMENT_SHADER:
+ _mesa_reference_fragprog(ctx, &prog->FragmentProgram,
+ (struct gl_fragment_program *)linked_prog);
+ ok = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
+ linked_prog);
+ break;
+ case GL_GEOMETRY_SHADER:
+ _mesa_reference_geomprog(ctx, &prog->GeometryProgram,
+ (struct gl_geometry_program *)linked_prog);
+ ok = ctx->Driver.ProgramStringNotify(ctx, GL_GEOMETRY_PROGRAM_NV,
+ linked_prog);
+ break;
+ }
+ if (!ok) {
+ return GL_FALSE;
+ }
+ }
+
+ _mesa_reference_program(ctx, &linked_prog, NULL);
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Compile a GLSL shader. Called via glCompileShader().
+ */
+void
+_mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
+{
+ struct _mesa_glsl_parse_state *state =
+ new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
+
+ const char *source = shader->Source;
+ /* Check if the user called glCompileShader without first calling
+ * glShaderSource. This should fail to compile, but not raise a GL_ERROR.
+ */
+ if (source == NULL) {
+ shader->CompileStatus = GL_FALSE;
+ return;
+ }
+
+ state->error = preprocess(state, &source, &state->info_log,
+ &ctx->Extensions, ctx->API);
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ printf("GLSL source for shader %d:\n", shader->Name);
+ printf("%s\n", shader->Source);
+ }
+
+ if (!state->error) {
+ _mesa_glsl_lexer_ctor(state, source);
+ _mesa_glsl_parse(state);
+ _mesa_glsl_lexer_dtor(state);
+ }
+
+ talloc_free(shader->ir);
+ shader->ir = new(shader) exec_list;
+ if (!state->error && !state->translation_unit.is_empty())
+ _mesa_ast_to_hir(shader->ir, state);
+
+ if (!state->error && !shader->ir->is_empty()) {
+ validate_ir_tree(shader->ir);
+
+ /* Do some optimization at compile time to reduce shader IR size
+ * and reduce later work if the same shader is linked multiple times
+ */
+ while (do_common_optimization(shader->ir, false, 32))
+ ;
+
+ validate_ir_tree(shader->ir);
+ }
+
+ shader->symbols = state->symbols;
+
+ shader->CompileStatus = !state->error;
+ shader->InfoLog = state->info_log;
+ shader->Version = state->language_version;
+ memcpy(shader->builtins_to_link, state->builtins_to_link,
+ sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
+ shader->num_builtins_to_link = state->num_builtins_to_link;
+
+ if (ctx->Shader.Flags & GLSL_LOG) {
+ _mesa_write_shader_to_file(shader);
+ }
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ if (shader->CompileStatus) {
+ printf("GLSL IR for shader %d:\n", shader->Name);
+ _mesa_print_ir(shader->ir, NULL);
+ printf("\n\n");
+ } else {
+ printf("GLSL shader %d failed to compile.\n", shader->Name);
+ }
+ if (shader->InfoLog && shader->InfoLog[0] != 0) {
+ printf("GLSL shader %d info log:\n", shader->Name);
+ printf("%s\n", shader->InfoLog);
+ }
+ }
+
+ /* Retain any live IR, but trash the rest. */
+ reparent_ir(shader->ir, shader->ir);
+
+ talloc_free(state);
+
+ if (shader->CompileStatus) {
+ if (!ctx->Driver.CompileShader(ctx, shader))
+ shader->CompileStatus = GL_FALSE;
+ }
+}
+
+
+/**
+ * Link a GLSL shader program. Called via glLinkProgram().
+ */
+void
+_mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ unsigned int i;
+
+ _mesa_clear_shader_program_data(ctx, prog);
+
+ prog->LinkStatus = GL_TRUE;
+
+ for (i = 0; i < prog->NumShaders; i++) {
+ if (!prog->Shaders[i]->CompileStatus) {
+ fail_link(prog, "linking with uncompiled shader");
+ prog->LinkStatus = GL_FALSE;
+ }
+ }
+
+ prog->Varying = _mesa_new_parameter_list();
+ _mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL);
+ _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL);
+ _mesa_reference_geomprog(ctx, &prog->GeometryProgram, NULL);
+
+ if (prog->LinkStatus) {
+ link_shaders(ctx, prog);
+ }
+
+ if (prog->LinkStatus) {
+ if (!ctx->Driver.LinkShader(ctx, prog)) {
+ prog->LinkStatus = GL_FALSE;
+ }
+ }
+
+ set_uniform_initializers(ctx, prog);
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ if (!prog->LinkStatus) {
+ printf("GLSL shader program %d failed to link\n", prog->Name);
+ }
+
+ if (prog->InfoLog && prog->InfoLog[0] != 0) {
+ printf("GLSL shader program %d info log:\n", prog->Name);
+ printf("%s\n", prog->InfoLog);
+ }
+ }
+}
+
+} /* extern "C" */
diff --git a/mesalib/src/mesa/program/ir_to_mesa.h b/mesalib/src/mesa/program/ir_to_mesa.h
index ecaacde4b..e708bb769 100644
--- a/mesalib/src/mesa/program/ir_to_mesa.h
+++ b/mesalib/src/mesa/program/ir_to_mesa.h
@@ -1,38 +1,41 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "main/config.h"
-#include "main/mtypes.h"
-
-void _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *sh);
-void _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog);
-GLboolean _mesa_ir_compile_shader(GLcontext *ctx, struct gl_shader *shader);
-GLboolean _mesa_ir_link_shader(GLcontext *ctx, struct gl_shader_program *prog);
-
-#ifdef __cplusplus
-}
-#endif
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "main/glheader.h"
+
+struct gl_context;
+struct gl_shader;
+struct gl_shader_program;
+
+void _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *sh);
+void _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);
+GLboolean _mesa_ir_compile_shader(struct gl_context *ctx, struct gl_shader *shader);
+GLboolean _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/mesalib/src/mesa/program/nvfragparse.c b/mesalib/src/mesa/program/nvfragparse.c
index 0de3c5804..04538e071 100644
--- a/mesalib/src/mesa/program/nvfragparse.c
+++ b/mesalib/src/mesa/program/nvfragparse.c
@@ -1,1588 +1,1588 @@
-/*
- * 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 "main/glheader.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "program.h"
-#include "prog_parameter.h"
-#include "prog_print.h"
-#include "prog_instruction.h"
-#include "nvfragparse.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);
- 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]; \
- 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;
-
- result.name = NULL;
- result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
- result.inputs = 0;
- result.outputs = 0;
- result.suffixes = 0;
-
- for (inst = Instructions; inst->name; inst++) {
- if (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;
- }
- }
-
- 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) 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
-};
-
-
-
-/**********************************************************************/
-
-/**
- * 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_strtof((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 = 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; k < 4 && token[k]; 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 = 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 = 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 (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];
-
- /* 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 */
- if (strcmp((char *) token, "COLR") == 0 ||
- strcmp((char *) token, "COLH") == 0) {
- /* note that we don't distinguish between COLR and COLH */
- *outputRegNum = FRAG_RESULT_COLOR;
- parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
- }
- else if (strcmp((char *) token, "DEPR") == 0) {
- *outputRegNum = FRAG_RESULT_DEPTH;
- parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
- }
- else {
- 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 (strcmp((const char *) token, "RC") == 0 ||
- 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;
- GLuint negateBase, negateAbs;
-
- /*
- * 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;
- negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
-
- if (Parse_String(parseState, "-"))
- negateBase = NEGATE_XYZW;
- else if (Parse_String(parseState, "+"))
- negateBase = NEGATE_NONE;
- else
- negateBase = NEGATE_NONE;
- }
- else {
- srcReg->Abs = GL_FALSE;
- negateAbs = NEGATE_NONE;
- negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
- }
-
- srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
-
- /* 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, 4, NULL);
- 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, 4, NULL);
- 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;
- GLuint negateBase, negateAbs;
-
- /*
- * 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;
- negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
-
- if (Parse_String(parseState, "-"))
- negateBase = NEGATE_XYZW;
- else if (Parse_String(parseState, "+"))
- negateBase = NEGATE_NONE;
- else
- negateBase = NEGATE_NONE;
- }
- else {
- srcReg->Abs = GL_FALSE;
- negateAbs = NEGATE_NONE;
- negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
- }
-
- srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
-
- 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, 4, NULL);
- 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, 4, NULL);
- 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*) malloc(len + 1);
-
- 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].Abs = GL_FALSE;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-
- 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_instructions(inst, 1);
-
- /* 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;
- 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;
-
- /*
- * 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 */
- memset(&parseState, 0, 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 (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
- target = GL_FRAGMENT_PROGRAM_NV;
- parseState.pos = programString + 7;
- }
- else if (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_copy_instructions(newInst, instBuffer, parseState.numInst);
-
- /* 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) {
- 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->Base.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
- printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
- _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
- printf("----------------------------------\n");
-#endif
- }
- else {
- /* Error! */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
- /* NOTE: _mesa_set_program_error would have been called already */
- }
-}
-
-
-const char *
-_mesa_nv_fragment_input_register_name(GLuint i)
-{
- ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
- return InputRegisters[i];
-}
-
+/*
+ * 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 "main/glheader.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "program.h"
+#include "prog_parameter.h"
+#include "prog_print.h"
+#include "prog_instruction.h"
+#include "nvfragparse.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 {
+ struct gl_context *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);
+ 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]; \
+ 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;
+
+ result.name = NULL;
+ result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
+ result.inputs = 0;
+ result.outputs = 0;
+ result.suffixes = 0;
+
+ for (inst = Instructions; inst->name; inst++) {
+ if (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;
+ }
+ }
+
+ 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) 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
+};
+
+
+
+/**********************************************************************/
+
+/**
+ * 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_strtof((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 = 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; k < 4 && token[k]; 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 = 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 = 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 (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];
+
+ /* 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 */
+ if (strcmp((char *) token, "COLR") == 0 ||
+ strcmp((char *) token, "COLH") == 0) {
+ /* note that we don't distinguish between COLR and COLH */
+ *outputRegNum = FRAG_RESULT_COLOR;
+ parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
+ }
+ else if (strcmp((char *) token, "DEPR") == 0) {
+ *outputRegNum = FRAG_RESULT_DEPTH;
+ parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
+ }
+ else {
+ 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 (strcmp((const char *) token, "RC") == 0 ||
+ 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;
+ GLuint negateBase, negateAbs;
+
+ /*
+ * 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;
+ negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
+
+ if (Parse_String(parseState, "-"))
+ negateBase = NEGATE_XYZW;
+ else if (Parse_String(parseState, "+"))
+ negateBase = NEGATE_NONE;
+ else
+ negateBase = NEGATE_NONE;
+ }
+ else {
+ srcReg->Abs = GL_FALSE;
+ negateAbs = NEGATE_NONE;
+ negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
+ }
+
+ srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
+
+ /* 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, 4, NULL);
+ 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, 4, NULL);
+ 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;
+ GLuint negateBase, negateAbs;
+
+ /*
+ * 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;
+ negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
+
+ if (Parse_String(parseState, "-"))
+ negateBase = NEGATE_XYZW;
+ else if (Parse_String(parseState, "+"))
+ negateBase = NEGATE_NONE;
+ else
+ negateBase = NEGATE_NONE;
+ }
+ else {
+ srcReg->Abs = GL_FALSE;
+ negateAbs = NEGATE_NONE;
+ negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
+ }
+
+ srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
+
+ 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, 4, NULL);
+ 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, 4, NULL);
+ 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*) malloc(len + 1);
+
+ 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].Abs = GL_FALSE;
+ inst->SrcReg[0].Negate = NEGATE_NONE;
+
+ 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_instructions(inst, 1);
+
+ /* 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;
+ 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;
+
+ /*
+ * 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(struct gl_context *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 */
+ memset(&parseState, 0, 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 (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
+ target = GL_FRAGMENT_PROGRAM_NV;
+ parseState.pos = programString + 7;
+ }
+ else if (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_copy_instructions(newInst, instBuffer, parseState.numInst);
+
+ /* 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) {
+ 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->Base.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
+ printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
+ _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
+ printf("----------------------------------\n");
+#endif
+ }
+ else {
+ /* Error! */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
+ /* NOTE: _mesa_set_program_error would have been called already */
+ }
+}
+
+
+const char *
+_mesa_nv_fragment_input_register_name(GLuint i)
+{
+ ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
+ return InputRegisters[i];
+}
+
diff --git a/mesalib/src/mesa/program/nvfragparse.h b/mesalib/src/mesa/program/nvfragparse.h
index e28a6c493..a8ab8d6fe 100644
--- a/mesalib/src/mesa/program/nvfragparse.h
+++ b/mesalib/src/mesa/program/nvfragparse.h
@@ -1,44 +1,47 @@
-
-/*
- * 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
-
-#include "main/mtypes.h"
-
-extern void
-_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum target,
- const GLubyte *str, GLsizei len,
- struct gl_fragment_program *program);
-
-
-extern const char *
-_mesa_nv_fragment_input_register_name(GLuint i);
-
-#endif
+
+/*
+ * 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
+
+#include "main/glheader.h"
+
+struct gl_context;
+struct gl_fragment_program;
+
+extern void
+_mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum target,
+ const GLubyte *str, GLsizei len,
+ struct gl_fragment_program *program);
+
+
+extern const char *
+_mesa_nv_fragment_input_register_name(GLuint i);
+
+#endif
diff --git a/mesalib/src/mesa/program/nvvertparse.c b/mesalib/src/mesa/program/nvvertparse.c
index 1ac83d0e5..8f7199a99 100644
--- a/mesalib/src/mesa/program/nvvertparse.c
+++ b/mesalib/src/mesa/program/nvvertparse.c
@@ -1,1459 +1,1459 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.2
- *
- * 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 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 "main/glheader.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "main/nvprogram.h"
-#include "nvvertparse.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_print.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;
- GLbitfield inputsRead;
- GLbitfield outputsWritten;
- GLboolean anyProgRegsWritten;
- GLboolean indirectRegisterFiles;
- 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);
- 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]; \
- 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) 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 = 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 = 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 = 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 (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;
- parseState->indirectRegisterFiles |= (1 << srcReg->File);
- /* 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 = 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 = 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 (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 (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->Negate = NEGATE_XYZW;
- if (!Peek_Token(parseState, token))
- RETURN_ERROR;
- }
- else {
- srcReg->Negate = 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 = SWIZZLE_XXXX;
- else if (token[0] == 'y')
- srcReg->Swizzle = SWIZZLE_YYYY;
- else if (token[0] == 'z')
- srcReg->Swizzle = SWIZZLE_ZZZZ;
- else if (token[0] == 'w')
- srcReg->Swizzle = SWIZZLE_WWWW;
- 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->Negate = NEGATE_XYZW;
- (void) Parse_String(parseState, "-"); /* consume '-' */
- if (!Peek_Token(parseState, token))
- RETURN_ERROR;
- }
- else {
- srcReg->Negate = 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;
-
- /* 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;
-
- /* 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;
-
- /* 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;
-
- /* 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;
-
- /* 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;
-
- /* 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;
-
- /* 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*) malloc(len + 1);
-
- 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->Negate = 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 = PROGRAM_UNDEFINED;
- }
-
- /* 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_instructions(inst, 1);
-
- 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;
- parseState.indirectRegisterFiles = 0x0;
-
- /* Reset error state */
- _mesa_set_program_error(ctx, -1, NULL);
-
- /* check the program header */
- if (strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
- target = GL_VERTEX_PROGRAM_NV;
- parseState.pos = programString + 7;
- parseState.isStateProgram = GL_FALSE;
- }
- else if (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 (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)) {
- gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0};
- int i;
-
- /* 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");
- free(programString);
- return; /* out of memory */
- }
- _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
-
- /* 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) {
- free(program->Base.Instructions);
- }
- program->Base.Instructions = newInst;
- program->Base.InputsRead = parseState.inputsRead;
- if (parseState.isPositionInvariant)
- program->Base.InputsRead |= VERT_BIT_POS;
- program->Base.NumInstructions = parseState.numInst;
- program->Base.OutputsWritten = parseState.outputsWritten;
- program->IsPositionInvariant = parseState.isPositionInvariant;
- program->IsNVProgram = GL_TRUE;
-
-#ifdef DEBUG_foo
- printf("--- glLoadProgramNV result ---\n");
- _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
- printf("------------------------------\n");
-#endif
-
- if (program->Base.Parameters)
- _mesa_free_parameter_list(program->Base.Parameters);
-
- program->Base.Parameters = _mesa_new_parameter_list ();
- program->Base.NumParameters = 0;
-
- program->Base.IndirectRegisterFiles = parseState.indirectRegisterFiles;
-
- state_tokens[0] = STATE_VERTEX_PROGRAM;
- state_tokens[1] = STATE_ENV;
- /* Add refs to all of the potential params, in order. If we want to not
- * upload everything, _mesa_layout_parameters is the answer.
- */
- for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) {
- GLint index;
- state_tokens[2] = i;
- index = _mesa_add_state_reference(program->Base.Parameters,
- state_tokens);
- assert(index == i);
- }
- program->Base.NumParameters = program->Base.Parameters->NumParameters;
-
- _mesa_setup_nv_temporary_count(ctx, &program->Base);
- _mesa_emit_nv_temp_initialization(ctx, &program->Base);
- }
- 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);
- }
-}
-
-
-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];
-}
-
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.2
+ *
+ * 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 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 "main/glheader.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/nvprogram.h"
+#include "nvvertparse.h"
+#include "prog_instruction.h"
+#include "prog_parameter.h"
+#include "prog_print.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 {
+ struct gl_context *ctx;
+ const GLubyte *start;
+ const GLubyte *pos;
+ const GLubyte *curLine;
+ GLboolean isStateProgram;
+ GLboolean isPositionInvariant;
+ GLboolean isVersion1_1;
+ GLbitfield inputsRead;
+ GLbitfield outputsWritten;
+ GLboolean anyProgRegsWritten;
+ GLboolean indirectRegisterFiles;
+ 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);
+ 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]; \
+ 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) 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 = 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 = 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 = 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 (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;
+ parseState->indirectRegisterFiles |= (1 << srcReg->File);
+ /* 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 = 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 = 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 (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 (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->Negate = NEGATE_XYZW;
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+ }
+ else {
+ srcReg->Negate = 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 = SWIZZLE_XXXX;
+ else if (token[0] == 'y')
+ srcReg->Swizzle = SWIZZLE_YYYY;
+ else if (token[0] == 'z')
+ srcReg->Swizzle = SWIZZLE_ZZZZ;
+ else if (token[0] == 'w')
+ srcReg->Swizzle = SWIZZLE_WWWW;
+ 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->Negate = NEGATE_XYZW;
+ (void) Parse_String(parseState, "-"); /* consume '-' */
+ if (!Peek_Token(parseState, token))
+ RETURN_ERROR;
+ }
+ else {
+ srcReg->Negate = 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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*) malloc(len + 1);
+
+ 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->Negate = 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 = PROGRAM_UNDEFINED;
+ }
+
+ /* 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_instructions(inst, 1);
+
+ 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(struct gl_context *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;
+ parseState.indirectRegisterFiles = 0x0;
+
+ /* Reset error state */
+ _mesa_set_program_error(ctx, -1, NULL);
+
+ /* check the program header */
+ if (strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
+ target = GL_VERTEX_PROGRAM_NV;
+ parseState.pos = programString + 7;
+ parseState.isStateProgram = GL_FALSE;
+ }
+ else if (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 (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)) {
+ gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0};
+ int i;
+
+ /* 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");
+ free(programString);
+ return; /* out of memory */
+ }
+ _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
+
+ /* 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) {
+ free(program->Base.Instructions);
+ }
+ program->Base.Instructions = newInst;
+ program->Base.InputsRead = parseState.inputsRead;
+ if (parseState.isPositionInvariant)
+ program->Base.InputsRead |= VERT_BIT_POS;
+ program->Base.NumInstructions = parseState.numInst;
+ program->Base.OutputsWritten = parseState.outputsWritten;
+ program->IsPositionInvariant = parseState.isPositionInvariant;
+ program->IsNVProgram = GL_TRUE;
+
+#ifdef DEBUG_foo
+ printf("--- glLoadProgramNV result ---\n");
+ _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
+ printf("------------------------------\n");
+#endif
+
+ if (program->Base.Parameters)
+ _mesa_free_parameter_list(program->Base.Parameters);
+
+ program->Base.Parameters = _mesa_new_parameter_list ();
+ program->Base.NumParameters = 0;
+
+ program->Base.IndirectRegisterFiles = parseState.indirectRegisterFiles;
+
+ state_tokens[0] = STATE_VERTEX_PROGRAM;
+ state_tokens[1] = STATE_ENV;
+ /* Add refs to all of the potential params, in order. If we want to not
+ * upload everything, _mesa_layout_parameters is the answer.
+ */
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) {
+ GLint index;
+ state_tokens[2] = i;
+ index = _mesa_add_state_reference(program->Base.Parameters,
+ state_tokens);
+ assert(index == i);
+ }
+ program->Base.NumParameters = program->Base.Parameters->NumParameters;
+
+ _mesa_setup_nv_temporary_count(ctx, &program->Base);
+ _mesa_emit_nv_temp_initialization(ctx, &program->Base);
+ }
+ 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);
+ }
+}
+
+
+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/mesalib/src/mesa/program/nvvertparse.h b/mesalib/src/mesa/program/nvvertparse.h
index 91ef79e6c..bee6dea3c 100644
--- a/mesalib/src/mesa/program/nvvertparse.h
+++ b/mesalib/src/mesa/program/nvvertparse.h
@@ -1,46 +1,49 @@
-/*
- * 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
-
-#include "main/mtypes.h"
-
-extern void
-_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum target,
- const GLubyte *str, GLsizei len,
- 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
+/*
+ * 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
+
+#include "main/glheader.h"
+
+struct gl_context;
+struct gl_vertex_program;
+
+extern void
+_mesa_parse_nv_vertex_program(struct gl_context *ctx, GLenum target,
+ const GLubyte *str, GLsizei len,
+ 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/mesalib/src/mesa/program/prog_cache.c b/mesalib/src/mesa/program/prog_cache.c
index 8af689754..93612b4a0 100644
--- a/mesalib/src/mesa/program/prog_cache.c
+++ b/mesalib/src/mesa/program/prog_cache.c
@@ -1,206 +1,206 @@
-/**************************************************************************
- *
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include "main/glheader.h"
-#include "main/mtypes.h"
-#include "main/imports.h"
-#include "program/prog_cache.h"
-#include "program/program.h"
-
-
-struct cache_item
-{
- GLuint hash;
- void *key;
- struct gl_program *program;
- struct cache_item *next;
-};
-
-struct gl_program_cache
-{
- struct cache_item **items;
- struct cache_item *last;
- GLuint size, n_items;
-};
-
-
-
-/**
- * Compute hash index from state key.
- */
-static GLuint
-hash_key(const void *key, GLuint key_size)
-{
- const GLuint *ikey = (const GLuint *) key;
- GLuint hash = 0, i;
-
- assert(key_size >= 4);
-
- /* Make a slightly better attempt at a hash function:
- */
- for (i = 0; i < key_size / sizeof(*ikey); i++)
- {
- hash += ikey[i];
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
-
- return hash;
-}
-
-
-/**
- * Rebuild/expand the hash table to accomodate more entries
- */
-static void
-rehash(struct gl_program_cache *cache)
-{
- struct cache_item **items;
- struct cache_item *c, *next;
- GLuint size, i;
-
- cache->last = NULL;
-
- size = cache->size * 3;
- items = (struct cache_item**) malloc(size * sizeof(*items));
- memset(items, 0, size * sizeof(*items));
-
- for (i = 0; i < cache->size; i++)
- for (c = cache->items[i]; c; c = next) {
- next = c->next;
- c->next = items[c->hash % size];
- items[c->hash % size] = c;
- }
-
- free(cache->items);
- cache->items = items;
- cache->size = size;
-}
-
-
-static void
-clear_cache(GLcontext *ctx, struct gl_program_cache *cache)
-{
- struct cache_item *c, *next;
- GLuint i;
-
- cache->last = NULL;
-
- for (i = 0; i < cache->size; i++) {
- for (c = cache->items[i]; c; c = next) {
- next = c->next;
- free(c->key);
- _mesa_reference_program(ctx, &c->program, NULL);
- free(c);
- }
- cache->items[i] = NULL;
- }
-
-
- cache->n_items = 0;
-}
-
-
-
-struct gl_program_cache *
-_mesa_new_program_cache(void)
-{
- struct gl_program_cache *cache = CALLOC_STRUCT(gl_program_cache);
- if (cache) {
- cache->size = 17;
- cache->items = (struct cache_item **)
- calloc(1, cache->size * sizeof(struct cache_item));
- if (!cache->items) {
- free(cache);
- return NULL;
- }
- }
- return cache;
-}
-
-
-void
-_mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *cache)
-{
- clear_cache(ctx, cache);
- free(cache->items);
- free(cache);
-}
-
-
-struct gl_program *
-_mesa_search_program_cache(struct gl_program_cache *cache,
- const void *key, GLuint keysize)
-{
- if (cache->last &&
- memcmp(cache->last->key, key, keysize) == 0) {
- return cache->last->program;
- }
- else {
- const GLuint hash = hash_key(key, keysize);
- struct cache_item *c;
-
- for (c = cache->items[hash % cache->size]; c; c = c->next) {
- if (c->hash == hash && memcmp(c->key, key, keysize) == 0) {
- cache->last = c;
- return c->program;
- }
- }
-
- return NULL;
- }
-}
-
-
-void
-_mesa_program_cache_insert(GLcontext *ctx,
- struct gl_program_cache *cache,
- const void *key, GLuint keysize,
- struct gl_program *program)
-{
- const GLuint hash = hash_key(key, keysize);
- struct cache_item *c = CALLOC_STRUCT(cache_item);
-
- c->hash = hash;
-
- c->key = malloc(keysize);
- memcpy(c->key, key, keysize);
-
- c->program = program; /* no refcount change */
-
- if (cache->n_items > cache->size * 1.5) {
- if (cache->size < 1000)
- rehash(cache);
- else
- clear_cache(ctx, cache);
- }
-
- cache->n_items++;
- c->next = cache->items[hash % cache->size];
- cache->items[hash % cache->size] = c;
-}
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "main/glheader.h"
+#include "main/mtypes.h"
+#include "main/imports.h"
+#include "program/prog_cache.h"
+#include "program/program.h"
+
+
+struct cache_item
+{
+ GLuint hash;
+ void *key;
+ struct gl_program *program;
+ struct cache_item *next;
+};
+
+struct gl_program_cache
+{
+ struct cache_item **items;
+ struct cache_item *last;
+ GLuint size, n_items;
+};
+
+
+
+/**
+ * Compute hash index from state key.
+ */
+static GLuint
+hash_key(const void *key, GLuint key_size)
+{
+ const GLuint *ikey = (const GLuint *) key;
+ GLuint hash = 0, i;
+
+ assert(key_size >= 4);
+
+ /* Make a slightly better attempt at a hash function:
+ */
+ for (i = 0; i < key_size / sizeof(*ikey); i++)
+ {
+ hash += ikey[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ return hash;
+}
+
+
+/**
+ * Rebuild/expand the hash table to accomodate more entries
+ */
+static void
+rehash(struct gl_program_cache *cache)
+{
+ struct cache_item **items;
+ struct cache_item *c, *next;
+ GLuint size, i;
+
+ cache->last = NULL;
+
+ size = cache->size * 3;
+ items = (struct cache_item**) malloc(size * sizeof(*items));
+ memset(items, 0, size * sizeof(*items));
+
+ for (i = 0; i < cache->size; i++)
+ for (c = cache->items[i]; c; c = next) {
+ next = c->next;
+ c->next = items[c->hash % size];
+ items[c->hash % size] = c;
+ }
+
+ free(cache->items);
+ cache->items = items;
+ cache->size = size;
+}
+
+
+static void
+clear_cache(struct gl_context *ctx, struct gl_program_cache *cache)
+{
+ struct cache_item *c, *next;
+ GLuint i;
+
+ cache->last = NULL;
+
+ for (i = 0; i < cache->size; i++) {
+ for (c = cache->items[i]; c; c = next) {
+ next = c->next;
+ free(c->key);
+ _mesa_reference_program(ctx, &c->program, NULL);
+ free(c);
+ }
+ cache->items[i] = NULL;
+ }
+
+
+ cache->n_items = 0;
+}
+
+
+
+struct gl_program_cache *
+_mesa_new_program_cache(void)
+{
+ struct gl_program_cache *cache = CALLOC_STRUCT(gl_program_cache);
+ if (cache) {
+ cache->size = 17;
+ cache->items = (struct cache_item **)
+ calloc(1, cache->size * sizeof(struct cache_item));
+ if (!cache->items) {
+ free(cache);
+ return NULL;
+ }
+ }
+ return cache;
+}
+
+
+void
+_mesa_delete_program_cache(struct gl_context *ctx, struct gl_program_cache *cache)
+{
+ clear_cache(ctx, cache);
+ free(cache->items);
+ free(cache);
+}
+
+
+struct gl_program *
+_mesa_search_program_cache(struct gl_program_cache *cache,
+ const void *key, GLuint keysize)
+{
+ if (cache->last &&
+ memcmp(cache->last->key, key, keysize) == 0) {
+ return cache->last->program;
+ }
+ else {
+ const GLuint hash = hash_key(key, keysize);
+ struct cache_item *c;
+
+ for (c = cache->items[hash % cache->size]; c; c = c->next) {
+ if (c->hash == hash && memcmp(c->key, key, keysize) == 0) {
+ cache->last = c;
+ return c->program;
+ }
+ }
+
+ return NULL;
+ }
+}
+
+
+void
+_mesa_program_cache_insert(struct gl_context *ctx,
+ struct gl_program_cache *cache,
+ const void *key, GLuint keysize,
+ struct gl_program *program)
+{
+ const GLuint hash = hash_key(key, keysize);
+ struct cache_item *c = CALLOC_STRUCT(cache_item);
+
+ c->hash = hash;
+
+ c->key = malloc(keysize);
+ memcpy(c->key, key, keysize);
+
+ c->program = program; /* no refcount change */
+
+ if (cache->n_items > cache->size * 1.5) {
+ if (cache->size < 1000)
+ rehash(cache);
+ else
+ clear_cache(ctx, cache);
+ }
+
+ cache->n_items++;
+ c->next = cache->items[hash % cache->size];
+ cache->items[hash % cache->size] = c;
+}
diff --git a/mesalib/src/mesa/program/prog_cache.h b/mesalib/src/mesa/program/prog_cache.h
index bfe8f99d4..aae2b7df2 100644
--- a/mesalib/src/mesa/program/prog_cache.h
+++ b/mesalib/src/mesa/program/prog_cache.h
@@ -1,58 +1,59 @@
-/**************************************************************************
- *
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#ifndef PROG_CACHE_H
-#define PROG_CACHE_H
-
-
-#include "main/mtypes.h"
-
-
-/** Opaque type */
-struct gl_program_cache;
-
-
-extern struct gl_program_cache *
-_mesa_new_program_cache(void);
-
-extern void
-_mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *pc);
-
-
-extern struct gl_program *
-_mesa_search_program_cache(struct gl_program_cache *cache,
- const void *key, GLuint keysize);
-
-extern void
-_mesa_program_cache_insert(GLcontext *ctx,
- struct gl_program_cache *cache,
- const void *key, GLuint keysize,
- struct gl_program *program);
-
-
-#endif /* PROG_CACHE_H */
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#ifndef PROG_CACHE_H
+#define PROG_CACHE_H
+
+
+#include "main/glheader.h"
+
+struct gl_context;
+
+/** Opaque type */
+struct gl_program_cache;
+
+
+extern struct gl_program_cache *
+_mesa_new_program_cache(void);
+
+extern void
+_mesa_delete_program_cache(struct gl_context *ctx, struct gl_program_cache *pc);
+
+
+extern struct gl_program *
+_mesa_search_program_cache(struct gl_program_cache *cache,
+ const void *key, GLuint keysize);
+
+extern void
+_mesa_program_cache_insert(struct gl_context *ctx,
+ struct gl_program_cache *cache,
+ const void *key, GLuint keysize,
+ struct gl_program *program);
+
+
+#endif /* PROG_CACHE_H */
diff --git a/mesalib/src/mesa/program/prog_execute.c b/mesalib/src/mesa/program/prog_execute.c
index 2ae5bc572..4faed2663 100644
--- a/mesalib/src/mesa/program/prog_execute.c
+++ b/mesalib/src/mesa/program/prog_execute.c
@@ -1,1879 +1,1891 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2008 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_execute.c
- * Software interpreter for vertex/fragment programs.
- * \author Brian Paul
- */
-
-/*
- * NOTE: we do everything in single-precision floating point; we don't
- * currently observe the single/half/fixed-precision qualifiers.
- *
- */
-
-
-#include "main/glheader.h"
-#include "main/colormac.h"
-#include "main/macros.h"
-#include "prog_execute.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_print.h"
-#include "prog_noise.h"
-
-
-/* debug predicate */
-#define DEBUG_PROG 0
-
-
-/**
- * Set x to positive or negative infinity.
- */
-#if defined(USE_IEEE) || defined(_WIN32)
-#define SET_POS_INFINITY(x) \
- do { \
- fi_type fi; \
- fi.i = 0x7F800000; \
- x = fi.f; \
- } while (0)
-#define SET_NEG_INFINITY(x) \
- do { \
- fi_type fi; \
- fi.i = 0xFF800000; \
- x = fi.f; \
- } while (0)
-#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
-
-
-static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
-
-
-
-/**
- * Return TRUE for +0 and other positive values, FALSE otherwise.
- * Used for RCC opcode.
- */
-static INLINE GLboolean
-positive(float x)
-{
- fi_type fi;
- fi.f = x;
- if (fi.i & 0x80000000)
- return GL_FALSE;
- return GL_TRUE;
-}
-
-
-
-/**
- * Return a pointer to the 4-element float vector specified by the given
- * source register.
- */
-static INLINE const GLfloat *
-get_src_register_pointer(const struct prog_src_register *source,
- const struct gl_program_machine *machine)
-{
- const struct gl_program *prog = machine->CurProgram;
- GLint reg = source->Index;
-
- if (source->RelAddr) {
- /* add address register value to src index/offset */
- reg += machine->AddressReg[0][0];
- if (reg < 0) {
- return ZeroVec;
- }
- }
-
- switch (source->File) {
- case PROGRAM_TEMPORARY:
- if (reg >= MAX_PROGRAM_TEMPS)
- return ZeroVec;
- return machine->Temporaries[reg];
-
- case PROGRAM_INPUT:
- if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
- if (reg >= VERT_ATTRIB_MAX)
- return ZeroVec;
- return machine->VertAttribs[reg];
- }
- else {
- if (reg >= FRAG_ATTRIB_MAX)
- return ZeroVec;
- return machine->Attribs[reg][machine->CurElement];
- }
-
- case PROGRAM_OUTPUT:
- if (reg >= MAX_PROGRAM_OUTPUTS)
- return ZeroVec;
- return machine->Outputs[reg];
-
- case PROGRAM_LOCAL_PARAM:
- if (reg >= MAX_PROGRAM_LOCAL_PARAMS)
- return ZeroVec;
- return machine->CurProgram->LocalParams[reg];
-
- case PROGRAM_ENV_PARAM:
- if (reg >= MAX_PROGRAM_ENV_PARAMS)
- return ZeroVec;
- return machine->EnvParams[reg];
-
- case PROGRAM_STATE_VAR:
- /* Fallthrough */
- case PROGRAM_CONSTANT:
- /* Fallthrough */
- case PROGRAM_UNIFORM:
- /* Fallthrough */
- case PROGRAM_NAMED_PARAM:
- if (reg >= (GLint) prog->Parameters->NumParameters)
- return ZeroVec;
- return prog->Parameters->ParameterValues[reg];
-
- default:
- _mesa_problem(NULL,
- "Invalid src register file %d in get_src_register_pointer()",
- source->File);
- return NULL;
- }
-}
-
-
-/**
- * Return a pointer to the 4-element float vector specified by the given
- * destination register.
- */
-static INLINE GLfloat *
-get_dst_register_pointer(const struct prog_dst_register *dest,
- struct gl_program_machine *machine)
-{
- static GLfloat dummyReg[4];
- GLint reg = dest->Index;
-
- if (dest->RelAddr) {
- /* add address register value to src index/offset */
- reg += machine->AddressReg[0][0];
- if (reg < 0) {
- return dummyReg;
- }
- }
-
- switch (dest->File) {
- case PROGRAM_TEMPORARY:
- if (reg >= MAX_PROGRAM_TEMPS)
- return dummyReg;
- return machine->Temporaries[reg];
-
- case PROGRAM_OUTPUT:
- if (reg >= MAX_PROGRAM_OUTPUTS)
- return dummyReg;
- return machine->Outputs[reg];
-
- case PROGRAM_WRITE_ONLY:
- return dummyReg;
-
- default:
- _mesa_problem(NULL,
- "Invalid dest register file %d in get_dst_register_pointer()",
- dest->File);
- return NULL;
- }
-}
-
-
-
-/**
- * Fetch a 4-element float vector from the given source register.
- * Apply swizzling and negating as needed.
- */
-static void
-fetch_vector4(const struct prog_src_register *source,
- const struct gl_program_machine *machine, GLfloat result[4])
-{
- const GLfloat *src = get_src_register_pointer(source, machine);
- ASSERT(src);
-
- if (source->Swizzle == SWIZZLE_NOOP) {
- /* no swizzling */
- COPY_4V(result, src);
- }
- else {
- ASSERT(GET_SWZ(source->Swizzle, 0) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 1) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 2) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 3) <= 3);
- 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)];
- }
-
- if (source->Abs) {
- result[0] = FABSF(result[0]);
- result[1] = FABSF(result[1]);
- result[2] = FABSF(result[2]);
- result[3] = FABSF(result[3]);
- }
- if (source->Negate) {
- ASSERT(source->Negate == NEGATE_XYZW);
- result[0] = -result[0];
- result[1] = -result[1];
- result[2] = -result[2];
- result[3] = -result[3];
- }
-
-#ifdef NAN_CHECK
- assert(!IS_INF_OR_NAN(result[0]));
- assert(!IS_INF_OR_NAN(result[0]));
- assert(!IS_INF_OR_NAN(result[0]));
- assert(!IS_INF_OR_NAN(result[0]));
-#endif
-}
-
-
-/**
- * Fetch a 4-element uint vector from the given source register.
- * Apply swizzling but not negation/abs.
- */
-static void
-fetch_vector4ui(const struct prog_src_register *source,
- const struct gl_program_machine *machine, GLuint result[4])
-{
- const GLuint *src = (GLuint *) get_src_register_pointer(source, machine);
- ASSERT(src);
-
- if (source->Swizzle == SWIZZLE_NOOP) {
- /* no swizzling */
- COPY_4V(result, src);
- }
- else {
- ASSERT(GET_SWZ(source->Swizzle, 0) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 1) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 2) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 3) <= 3);
- 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)];
- }
-
- /* Note: no Negate or Abs here */
-}
-
-
-
-/**
- * Fetch the derivative with respect to X or Y for the given register.
- * XXX this currently only works for fragment program input attribs.
- */
-static void
-fetch_vector4_deriv(GLcontext * ctx,
- const struct prog_src_register *source,
- const struct gl_program_machine *machine,
- char xOrY, GLfloat result[4])
-{
- if (source->File == PROGRAM_INPUT &&
- source->Index < (GLint) machine->NumDeriv) {
- const GLint col = machine->CurElement;
- const GLfloat w = machine->Attribs[FRAG_ATTRIB_WPOS][col][3];
- const GLfloat invQ = 1.0f / w;
- GLfloat deriv[4];
-
- if (xOrY == 'X') {
- deriv[0] = machine->DerivX[source->Index][0] * invQ;
- deriv[1] = machine->DerivX[source->Index][1] * invQ;
- deriv[2] = machine->DerivX[source->Index][2] * invQ;
- deriv[3] = machine->DerivX[source->Index][3] * invQ;
- }
- else {
- deriv[0] = machine->DerivY[source->Index][0] * invQ;
- deriv[1] = machine->DerivY[source->Index][1] * invQ;
- deriv[2] = machine->DerivY[source->Index][2] * invQ;
- deriv[3] = machine->DerivY[source->Index][3] * invQ;
- }
-
- result[0] = deriv[GET_SWZ(source->Swizzle, 0)];
- result[1] = deriv[GET_SWZ(source->Swizzle, 1)];
- result[2] = deriv[GET_SWZ(source->Swizzle, 2)];
- result[3] = deriv[GET_SWZ(source->Swizzle, 3)];
-
- if (source->Abs) {
- result[0] = FABSF(result[0]);
- result[1] = FABSF(result[1]);
- result[2] = FABSF(result[2]);
- result[3] = FABSF(result[3]);
- }
- if (source->Negate) {
- ASSERT(source->Negate == NEGATE_XYZW);
- result[0] = -result[0];
- result[1] = -result[1];
- result[2] = -result[2];
- result[3] = -result[3];
- }
- }
- else {
- ASSIGN_4V(result, 0.0, 0.0, 0.0, 0.0);
- }
-}
-
-
-/**
- * As above, but only return result[0] element.
- */
-static void
-fetch_vector1(const struct prog_src_register *source,
- const struct gl_program_machine *machine, GLfloat result[4])
-{
- const GLfloat *src = get_src_register_pointer(source, machine);
- ASSERT(src);
-
- result[0] = src[GET_SWZ(source->Swizzle, 0)];
-
- if (source->Abs) {
- result[0] = FABSF(result[0]);
- }
- if (source->Negate) {
- result[0] = -result[0];
- }
-}
-
-
-static GLuint
-fetch_vector1ui(const struct prog_src_register *source,
- const struct gl_program_machine *machine)
-{
- const GLuint *src = (GLuint *) get_src_register_pointer(source, machine);
- return src[GET_SWZ(source->Swizzle, 0)];
-}
-
-
-/**
- * Fetch texel from texture. Use partial derivatives when possible.
- */
-static INLINE void
-fetch_texel(GLcontext *ctx,
- const struct gl_program_machine *machine,
- const struct prog_instruction *inst,
- const GLfloat texcoord[4], GLfloat lodBias,
- GLfloat color[4])
-{
- const GLuint unit = machine->Samplers[inst->TexSrcUnit];
-
- /* Note: we only have the right derivatives for fragment input attribs.
- */
- if (machine->NumDeriv > 0 &&
- inst->SrcReg[0].File == PROGRAM_INPUT &&
- inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit) {
- /* simple texture fetch for which we should have derivatives */
- GLuint attr = inst->SrcReg[0].Index;
- machine->FetchTexelDeriv(ctx, texcoord,
- machine->DerivX[attr],
- machine->DerivY[attr],
- lodBias, unit, color);
- }
- else {
- machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color);
- }
-}
-
-
-/**
- * Test value against zero and return GT, LT, EQ or UN if NaN.
- */
-static INLINE GLuint
-generate_cc(float value)
-{
- if (value != value)
- return COND_UN; /* NaN */
- if (value > 0.0F)
- return COND_GT;
- if (value < 0.0F)
- return COND_LT;
- return COND_EQ;
-}
-
-
-/**
- * Test if the ccMaskRule is satisfied by the given condition code.
- * Used to mask destination writes according to the current condition code.
- */
-static INLINE GLboolean
-test_cc(GLuint condCode, GLuint ccMaskRule)
-{
- switch (ccMaskRule) {
- case COND_EQ: return (condCode == COND_EQ);
- case COND_NE: return (condCode != COND_EQ);
- case COND_LT: return (condCode == COND_LT);
- case COND_GE: return (condCode == COND_GT || condCode == COND_EQ);
- case COND_LE: return (condCode == COND_LT || condCode == COND_EQ);
- case COND_GT: return (condCode == COND_GT);
- case COND_TR: return GL_TRUE;
- case COND_FL: return GL_FALSE;
- default: return GL_TRUE;
- }
-}
-
-
-/**
- * Evaluate the 4 condition codes against a predicate and return GL_TRUE
- * or GL_FALSE to indicate result.
- */
-static INLINE GLboolean
-eval_condition(const struct gl_program_machine *machine,
- const struct prog_instruction *inst)
-{
- const GLuint swizzle = inst->DstReg.CondSwizzle;
- const GLuint condMask = inst->DstReg.CondMask;
- if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) ||
- test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) ||
- test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) ||
- test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) {
- return GL_TRUE;
- }
- else {
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * Store 4 floats into a register. Observe the instructions saturate and
- * set-condition-code flags.
- */
-static void
-store_vector4(const struct prog_instruction *inst,
- struct gl_program_machine *machine, const GLfloat value[4])
-{
- const struct prog_dst_register *dstReg = &(inst->DstReg);
- const GLboolean clamp = inst->SaturateMode == SATURATE_ZERO_ONE;
- GLuint writeMask = dstReg->WriteMask;
- GLfloat clampedValue[4];
- GLfloat *dst = get_dst_register_pointer(dstReg, machine);
-
-#if 0
- if (value[0] > 1.0e10 ||
- IS_INF_OR_NAN(value[0]) ||
- IS_INF_OR_NAN(value[1]) ||
- IS_INF_OR_NAN(value[2]) || IS_INF_OR_NAN(value[3]))
- printf("store %g %g %g %g\n", value[0], value[1], value[2], value[3]);
-#endif
-
- if (clamp) {
- clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F);
- clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F);
- clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F);
- clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F);
- value = clampedValue;
- }
-
- if (dstReg->CondMask != COND_TR) {
- /* condition codes may turn off some writes */
- if (writeMask & WRITEMASK_X) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_X;
- }
- if (writeMask & WRITEMASK_Y) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Y;
- }
- if (writeMask & WRITEMASK_Z) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Z;
- }
- if (writeMask & WRITEMASK_W) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_W;
- }
- }
-
-#ifdef NAN_CHECK
- assert(!IS_INF_OR_NAN(value[0]));
- assert(!IS_INF_OR_NAN(value[0]));
- assert(!IS_INF_OR_NAN(value[0]));
- assert(!IS_INF_OR_NAN(value[0]));
-#endif
-
- if (writeMask & WRITEMASK_X)
- dst[0] = value[0];
- if (writeMask & WRITEMASK_Y)
- dst[1] = value[1];
- if (writeMask & WRITEMASK_Z)
- dst[2] = value[2];
- if (writeMask & WRITEMASK_W)
- dst[3] = value[3];
-
- if (inst->CondUpdate) {
- if (writeMask & WRITEMASK_X)
- machine->CondCodes[0] = generate_cc(value[0]);
- if (writeMask & WRITEMASK_Y)
- machine->CondCodes[1] = generate_cc(value[1]);
- if (writeMask & WRITEMASK_Z)
- machine->CondCodes[2] = generate_cc(value[2]);
- if (writeMask & WRITEMASK_W)
- machine->CondCodes[3] = generate_cc(value[3]);
-#if DEBUG_PROG
- printf("CondCodes=(%s,%s,%s,%s) for:\n",
- _mesa_condcode_string(machine->CondCodes[0]),
- _mesa_condcode_string(machine->CondCodes[1]),
- _mesa_condcode_string(machine->CondCodes[2]),
- _mesa_condcode_string(machine->CondCodes[3]));
-#endif
- }
-}
-
-
-/**
- * Store 4 uints into a register. Observe the set-condition-code flags.
- */
-static void
-store_vector4ui(const struct prog_instruction *inst,
- struct gl_program_machine *machine, const GLuint value[4])
-{
- const struct prog_dst_register *dstReg = &(inst->DstReg);
- GLuint writeMask = dstReg->WriteMask;
- GLuint *dst = (GLuint *) get_dst_register_pointer(dstReg, machine);
-
- if (dstReg->CondMask != COND_TR) {
- /* condition codes may turn off some writes */
- if (writeMask & WRITEMASK_X) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_X;
- }
- if (writeMask & WRITEMASK_Y) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Y;
- }
- if (writeMask & WRITEMASK_Z) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Z;
- }
- if (writeMask & WRITEMASK_W) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_W;
- }
- }
-
- if (writeMask & WRITEMASK_X)
- dst[0] = value[0];
- if (writeMask & WRITEMASK_Y)
- dst[1] = value[1];
- if (writeMask & WRITEMASK_Z)
- dst[2] = value[2];
- if (writeMask & WRITEMASK_W)
- dst[3] = value[3];
-
- if (inst->CondUpdate) {
- if (writeMask & WRITEMASK_X)
- machine->CondCodes[0] = generate_cc((float)value[0]);
- if (writeMask & WRITEMASK_Y)
- machine->CondCodes[1] = generate_cc((float)value[1]);
- if (writeMask & WRITEMASK_Z)
- machine->CondCodes[2] = generate_cc((float)value[2]);
- if (writeMask & WRITEMASK_W)
- machine->CondCodes[3] = generate_cc((float)value[3]);
-#if DEBUG_PROG
- printf("CondCodes=(%s,%s,%s,%s) for:\n",
- _mesa_condcode_string(machine->CondCodes[0]),
- _mesa_condcode_string(machine->CondCodes[1]),
- _mesa_condcode_string(machine->CondCodes[2]),
- _mesa_condcode_string(machine->CondCodes[3]));
-#endif
- }
-}
-
-
-
-/**
- * Execute the given vertex/fragment program.
- *
- * \param ctx rendering context
- * \param program the program to execute
- * \param machine machine state (must be initialized)
- * \return GL_TRUE if program completed or GL_FALSE if program executed KIL.
- */
-GLboolean
-_mesa_execute_program(GLcontext * ctx,
- const struct gl_program *program,
- struct gl_program_machine *machine)
-{
- const GLuint numInst = program->NumInstructions;
- const GLuint maxExec = 10000;
- GLuint pc, numExec = 0;
-
- machine->CurProgram = program;
-
- if (DEBUG_PROG) {
- printf("execute program %u --------------------\n", program->Id);
- }
-
- if (program->Target == GL_VERTEX_PROGRAM_ARB) {
- machine->EnvParams = ctx->VertexProgram.Parameters;
- }
- else {
- machine->EnvParams = ctx->FragmentProgram.Parameters;
- }
-
- for (pc = 0; pc < numInst; pc++) {
- const struct prog_instruction *inst = program->Instructions + pc;
-
- if (DEBUG_PROG) {
- _mesa_print_instruction(inst);
- }
-
- switch (inst->Opcode) {
- case OPCODE_ABS:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = FABSF(a[0]);
- result[1] = FABSF(a[1]);
- result[2] = FABSF(a[2]);
- result[3] = FABSF(a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_ADD:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[0] + b[0];
- result[1] = a[1] + b[1];
- result[2] = a[2] + b[2];
- result[3] = a[3] + b[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("ADD (%g %g %g %g) = (%g %g %g %g) + (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_AND: /* bitwise AND */
- {
- GLuint a[4], b[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- fetch_vector4ui(&inst->SrcReg[1], machine, b);
- result[0] = a[0] & b[0];
- result[1] = a[1] & b[1];
- result[2] = a[2] & b[2];
- result[3] = a[3] & b[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_ARL:
- {
- GLfloat t[4];
- fetch_vector4(&inst->SrcReg[0], machine, t);
- machine->AddressReg[0][0] = IFLOOR(t[0]);
- if (DEBUG_PROG) {
- printf("ARL %d\n", machine->AddressReg[0][0]);
- }
- }
- break;
- case OPCODE_BGNLOOP:
- /* no-op */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDLOOP);
- break;
- case OPCODE_ENDLOOP:
- /* subtract 1 here since pc is incremented by for(pc) loop */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_BGNLOOP);
- pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */
- break;
- case OPCODE_BGNSUB: /* begin subroutine */
- break;
- case OPCODE_ENDSUB: /* end subroutine */
- break;
- case OPCODE_BRA: /* branch (conditional) */
- if (eval_condition(machine, inst)) {
- /* take branch */
- /* Subtract 1 here since we'll do pc++ below */
- pc = inst->BranchTarget - 1;
- }
- break;
- case OPCODE_BRK: /* break out of loop (conditional) */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDLOOP);
- if (eval_condition(machine, inst)) {
- /* break out of loop */
- /* pc++ at end of for-loop will put us after the ENDLOOP inst */
- pc = inst->BranchTarget;
- }
- break;
- case OPCODE_CONT: /* continue loop (conditional) */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDLOOP);
- if (eval_condition(machine, inst)) {
- /* continue at ENDLOOP */
- /* Subtract 1 here since we'll do pc++ at end of for-loop */
- pc = inst->BranchTarget - 1;
- }
- break;
- case OPCODE_CAL: /* Call subroutine (conditional) */
- if (eval_condition(machine, inst)) {
- /* call the subroutine */
- if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) {
- return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
- }
- machine->CallStack[machine->StackDepth++] = pc + 1; /* next inst */
- /* Subtract 1 here since we'll do pc++ at end of for-loop */
- pc = inst->BranchTarget - 1;
- }
- break;
- case OPCODE_CMP:
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] < 0.0F ? b[0] : c[0];
- result[1] = a[1] < 0.0F ? b[1] : c[1];
- result[2] = a[2] < 0.0F ? b[2] : c[2];
- result[3] = a[3] < 0.0F ? b[3] : c[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("CMP (%g %g %g %g) = (%g %g %g %g) < 0 ? (%g %g %g %g) : (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3],
- c[0], c[1], c[2], c[3]);
- }
- }
- break;
- case OPCODE_COS:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] = result[1] = result[2] = result[3]
- = (GLfloat) cos(a[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DDX: /* Partial derivative with respect to X */
- {
- GLfloat result[4];
- fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine,
- 'X', result);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DDY: /* Partial derivative with respect to Y */
- {
- GLfloat result[4];
- fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine,
- 'Y', result);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DP2:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT2(a, b);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP2 %g = (%g %g) . (%g %g)\n",
- result[0], a[0], a[1], b[0], b[1]);
- }
- }
- break;
- case OPCODE_DP2A:
- {
- GLfloat a[4], b[4], c, result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector1(&inst->SrcReg[1], machine, &c);
- result[0] = result[1] = result[2] = result[3] = DOT2(a, b) + c;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP2A %g = (%g %g) . (%g %g) + %g\n",
- result[0], a[0], a[1], b[0], b[1], c);
- }
- }
- break;
- case OPCODE_DP3:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT3(a, b);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP3 %g = (%g %g %g) . (%g %g %g)\n",
- result[0], a[0], a[1], a[2], b[0], b[1], b[2]);
- }
- }
- break;
- case OPCODE_DP4:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT4(a, b);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP4 %g = (%g, %g %g %g) . (%g, %g %g %g)\n",
- result[0], a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_DPH:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT3(a, b) + b[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DST: /* Distance vector */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = 1.0F;
- result[1] = a[1] * b[1];
- result[2] = a[2];
- result[3] = b[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_EXP:
- {
- GLfloat t[4], q[4], floor_t0;
- fetch_vector1(&inst->SrcReg[0], machine, 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 {
- q[0] = LDEXPF(1.0, (int) floor_t0);
- /* Note: GL_NV_vertex_program expects
- * result.z = result.x * APPX(result.y)
- * We do what the ARB extension says.
- */
- q[2] = (GLfloat) pow(2.0, t[0]);
- }
- q[1] = t[0] - floor_t0;
- q[3] = 1.0F;
- store_vector4( inst, machine, q );
- }
- break;
- case OPCODE_EX2: /* Exponential base 2 */
- {
- GLfloat a[4], result[4], val;
- fetch_vector1(&inst->SrcReg[0], machine, a);
- val = (GLfloat) pow(2.0, a[0]);
- /*
- if (IS_INF_OR_NAN(val))
- val = 1.0e10;
- */
- result[0] = result[1] = result[2] = result[3] = val;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_FLR:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = FLOORF(a[0]);
- result[1] = FLOORF(a[1]);
- result[2] = FLOORF(a[2]);
- result[3] = FLOORF(a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_FRC:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = a[0] - FLOORF(a[0]);
- result[1] = a[1] - FLOORF(a[1]);
- result[2] = a[2] - FLOORF(a[2]);
- result[3] = a[3] - FLOORF(a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_IF:
- {
- GLboolean cond;
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ELSE ||
- program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDIF);
- /* eval condition */
- if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
- GLfloat a[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- cond = (a[0] != 0.0);
- }
- else {
- cond = eval_condition(machine, inst);
- }
- if (DEBUG_PROG) {
- printf("IF: %d\n", cond);
- }
- /* do if/else */
- if (cond) {
- /* do if-clause (just continue execution) */
- }
- else {
- /* go to the instruction after ELSE or ENDIF */
- assert(inst->BranchTarget >= 0);
- pc = inst->BranchTarget;
- }
- }
- break;
- case OPCODE_ELSE:
- /* goto ENDIF */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDIF);
- assert(inst->BranchTarget >= 0);
- pc = inst->BranchTarget;
- break;
- case OPCODE_ENDIF:
- /* nothing */
- break;
- case OPCODE_KIL_NV: /* NV_f_p only (conditional) */
- if (eval_condition(machine, inst)) {
- return GL_FALSE;
- }
- break;
- case OPCODE_KIL: /* ARB_f_p only */
- {
- GLfloat a[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- if (DEBUG_PROG) {
- printf("KIL if (%g %g %g %g) <= 0.0\n",
- a[0], a[1], a[2], a[3]);
- }
-
- if (a[0] < 0.0F || a[1] < 0.0F || a[2] < 0.0F || a[3] < 0.0F) {
- return GL_FALSE;
- }
- }
- break;
- case OPCODE_LG2: /* log base 2 */
- {
- GLfloat a[4], result[4], val;
- fetch_vector1(&inst->SrcReg[0], machine, a);
- /* The fast LOG2 macro doesn't meet the precision requirements.
- */
- if (a[0] == 0.0F) {
- val = -FLT_MAX;
- }
- else {
- val = (float)(log(a[0]) * 1.442695F);
- }
- result[0] = result[1] = result[2] = result[3] = val;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_LIT:
- {
- const GLfloat epsilon = 1.0F / 256.0F; /* from NV VP spec */
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = MAX2(a[0], 0.0F);
- a[1] = MAX2(a[1], 0.0F);
- /* XXX ARB version clamps a[3], NV version doesn't */
- a[3] = CLAMP(a[3], -(128.0F - epsilon), (128.0F - epsilon));
- result[0] = 1.0F;
- result[1] = a[0];
- /* XXX we could probably just use pow() here */
- if (a[0] > 0.0F) {
- if (a[1] == 0.0 && a[3] == 0.0)
- result[2] = 1.0F;
- else
- result[2] = (GLfloat) pow(a[1], a[3]);
- }
- else {
- result[2] = 0.0F;
- }
- result[3] = 1.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("LIT (%g %g %g %g) : (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3]);
- }
- }
- break;
- case OPCODE_LOG:
- {
- GLfloat t[4], q[4], abs_t0;
- fetch_vector1(&inst->SrcReg[0], machine, 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) */
-
- /* The fast LOG2 macro doesn't meet the precision
- * requirements.
- */
- q[2] = (float)(log(t[0]) * 1.442695F);
- }
- }
- else {
- SET_NEG_INFINITY(q[0]);
- q[1] = 1.0F;
- SET_NEG_INFINITY(q[2]);
- }
- q[3] = 1.0;
- store_vector4(inst, machine, q);
- }
- break;
- case OPCODE_LRP:
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0];
- result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1];
- result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2];
- result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("LRP (%g %g %g %g) = (%g %g %g %g), "
- "(%g %g %g %g), (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
- }
- }
- break;
- case OPCODE_MAD:
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] * b[0] + c[0];
- result[1] = a[1] * b[1] + c[1];
- result[2] = a[2] * b[2] + c[2];
- result[3] = a[3] * b[3] + c[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MAD (%g %g %g %g) = (%g %g %g %g) * "
- "(%g %g %g %g) + (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
- }
- }
- break;
- case OPCODE_MAX:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = MAX2(a[0], b[0]);
- result[1] = MAX2(a[1], b[1]);
- result[2] = MAX2(a[2], b[2]);
- result[3] = MAX2(a[3], b[3]);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MAX (%g %g %g %g) = (%g %g %g %g), (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_MIN:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = MIN2(a[0], b[0]);
- result[1] = MIN2(a[1], b[1]);
- result[2] = MIN2(a[2], b[2]);
- result[3] = MIN2(a[3], b[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_MOV:
- {
- GLfloat result[4];
- fetch_vector4(&inst->SrcReg[0], machine, result);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MOV (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3]);
- }
- }
- break;
- case OPCODE_MUL:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[0] * b[0];
- result[1] = a[1] * b[1];
- result[2] = a[2] * b[2];
- result[3] = a[3] * b[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MUL (%g %g %g %g) = (%g %g %g %g) * (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_NOISE1:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] =
- result[3] = _mesa_noise1(a[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOISE2:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] = result[3] = _mesa_noise2(a[0], a[1]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOISE3:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] =
- result[3] = _mesa_noise3(a[0], a[1], a[2]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOISE4:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] =
- result[3] = _mesa_noise4(a[0], a[1], a[2], a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOP:
- break;
- case OPCODE_NOT: /* bitwise NOT */
- {
- GLuint a[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- result[0] = ~a[0];
- result[1] = ~a[1];
- result[2] = ~a[2];
- result[3] = ~a[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_NRM3: /* 3-component normalization */
- {
- GLfloat a[4], result[4];
- GLfloat tmp;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
- if (tmp != 0.0F)
- tmp = INV_SQRTF(tmp);
- result[0] = tmp * a[0];
- result[1] = tmp * a[1];
- result[2] = tmp * a[2];
- result[3] = 0.0; /* undefined, but prevent valgrind warnings */
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NRM4: /* 4-component normalization */
- {
- GLfloat a[4], result[4];
- GLfloat tmp;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3];
- if (tmp != 0.0F)
- tmp = INV_SQRTF(tmp);
- result[0] = tmp * a[0];
- result[1] = tmp * a[1];
- result[2] = tmp * a[2];
- result[3] = tmp * a[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_OR: /* bitwise OR */
- {
- GLuint a[4], b[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- fetch_vector4ui(&inst->SrcReg[1], machine, b);
- result[0] = a[0] | b[0];
- result[1] = a[1] | b[1];
- result[2] = a[2] | b[2];
- result[3] = a[3] | b[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK2H: /* pack two 16-bit floats in one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4];
- GLhalfNV hx, hy;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- hx = _mesa_float_to_half(a[0]);
- hy = _mesa_float_to_half(a[1]);
- result[0] =
- result[1] =
- result[2] =
- result[3] = hx | (hy << 16);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK2US: /* pack two GLushorts into one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4], usx, usy;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = CLAMP(a[0], 0.0F, 1.0F);
- a[1] = CLAMP(a[1], 0.0F, 1.0F);
- usx = IROUND(a[0] * 65535.0F);
- usy = IROUND(a[1] * 65535.0F);
- result[0] =
- result[1] =
- result[2] =
- result[3] = usx | (usy << 16);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK4B: /* pack four GLbytes into one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4], ubx, uby, ubz, ubw;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = CLAMP(a[0], -128.0F / 127.0F, 1.0F);
- a[1] = CLAMP(a[1], -128.0F / 127.0F, 1.0F);
- a[2] = CLAMP(a[2], -128.0F / 127.0F, 1.0F);
- a[3] = CLAMP(a[3], -128.0F / 127.0F, 1.0F);
- ubx = IROUND(127.0F * a[0] + 128.0F);
- uby = IROUND(127.0F * a[1] + 128.0F);
- ubz = IROUND(127.0F * a[2] + 128.0F);
- ubw = IROUND(127.0F * a[3] + 128.0F);
- result[0] =
- result[1] =
- result[2] =
- result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK4UB: /* pack four GLubytes into one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4], ubx, uby, ubz, ubw;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = CLAMP(a[0], 0.0F, 1.0F);
- a[1] = CLAMP(a[1], 0.0F, 1.0F);
- a[2] = CLAMP(a[2], 0.0F, 1.0F);
- a[3] = CLAMP(a[3], 0.0F, 1.0F);
- ubx = IROUND(255.0F * a[0]);
- uby = IROUND(255.0F * a[1]);
- ubz = IROUND(255.0F * a[2]);
- ubw = IROUND(255.0F * a[3]);
- result[0] =
- result[1] =
- result[2] =
- result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_POW:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- fetch_vector1(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3]
- = (GLfloat) pow(a[0], b[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_RCC: /* clamped riciprocal */
- {
- const float largest = 1.884467e+19, smallest = 5.42101e-20;
- GLfloat a[4], r, result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- if (DEBUG_PROG) {
- if (a[0] == 0)
- printf("RCC(0)\n");
- else if (IS_INF_OR_NAN(a[0]))
- printf("RCC(inf)\n");
- }
- if (a[0] == 1.0F) {
- r = 1.0F;
- }
- else {
- r = 1.0F / a[0];
- }
- if (positive(r)) {
- if (r > largest) {
- r = largest;
- }
- else if (r < smallest) {
- r = smallest;
- }
- }
- else {
- if (r < -largest) {
- r = -largest;
- }
- else if (r > -smallest) {
- r = -smallest;
- }
- }
- result[0] = result[1] = result[2] = result[3] = r;
- store_vector4(inst, machine, result);
- }
- break;
-
- case OPCODE_RCP:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- if (DEBUG_PROG) {
- if (a[0] == 0)
- printf("RCP(0)\n");
- else if (IS_INF_OR_NAN(a[0]))
- printf("RCP(inf)\n");
- }
- result[0] = result[1] = result[2] = result[3] = 1.0F / a[0];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_RET: /* return from subroutine (conditional) */
- if (eval_condition(machine, inst)) {
- if (machine->StackDepth == 0) {
- return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
- }
- /* subtract one because of pc++ in the for loop */
- pc = machine->CallStack[--machine->StackDepth] - 1;
- }
- break;
- case OPCODE_RFL: /* reflection vector */
- {
- GLfloat axis[4], dir[4], result[4], tmpX, tmpW;
- fetch_vector4(&inst->SrcReg[0], machine, axis);
- fetch_vector4(&inst->SrcReg[1], machine, dir);
- tmpW = DOT3(axis, axis);
- tmpX = (2.0F * DOT3(axis, dir)) / tmpW;
- result[0] = tmpX * axis[0] - dir[0];
- result[1] = tmpX * axis[1] - dir[1];
- result[2] = tmpX * axis[2] - dir[2];
- /* result[3] is never written! XXX enforce in parser! */
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_RSQ: /* 1 / sqrt() */
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- a[0] = FABSF(a[0]);
- result[0] = result[1] = result[2] = result[3] = INV_SQRTF(a[0]);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("RSQ %g = 1/sqrt(|%g|)\n", result[0], a[0]);
- }
- }
- break;
- case OPCODE_SCS: /* sine and cos */
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] = (GLfloat) cos(a[0]);
- result[1] = (GLfloat) sin(a[0]);
- result[2] = 0.0; /* undefined! */
- result[3] = 0.0; /* undefined! */
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SEQ: /* set on equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] == b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] == b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] == b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] == b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SEQ (%g %g %g %g) = (%g %g %g %g) == (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SFL: /* set false, operands ignored */
- {
- static const GLfloat result[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SGE: /* set on greater or equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] >= b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] >= b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] >= b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] >= b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SGE (%g %g %g %g) = (%g %g %g %g) >= (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SGT: /* set on greater */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] > b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] > b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] > b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] > b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SGT (%g %g %g %g) = (%g %g %g %g) > (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SIN:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] = result[1] = result[2] = result[3]
- = (GLfloat) sin(a[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SLE: /* set on less or equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] <= b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] <= b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] <= b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] <= b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SLE (%g %g %g %g) = (%g %g %g %g) <= (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SLT: /* set on less */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] < b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] < b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] < b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] < b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SLT (%g %g %g %g) = (%g %g %g %g) < (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SNE: /* set on not equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] != b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] != b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] != b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] != b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SNE (%g %g %g %g) = (%g %g %g %g) != (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SSG: /* set sign (-1, 0 or +1) */
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = (GLfloat) ((a[0] > 0.0F) - (a[0] < 0.0F));
- result[1] = (GLfloat) ((a[1] > 0.0F) - (a[1] < 0.0F));
- result[2] = (GLfloat) ((a[2] > 0.0F) - (a[2] < 0.0F));
- result[3] = (GLfloat) ((a[3] > 0.0F) - (a[3] < 0.0F));
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_STR: /* set true, operands ignored */
- {
- static const GLfloat result[4] = { 1.0F, 1.0F, 1.0F, 1.0F };
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SUB:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[0] - b[0];
- result[1] = a[1] - b[1];
- result[2] = a[2] - b[2];
- result[3] = a[3] - b[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SUB (%g %g %g %g) = (%g %g %g %g) - (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SWZ: /* extended swizzle */
- {
- const struct prog_src_register *source = &inst->SrcReg[0];
- const GLfloat *src = get_src_register_pointer(source, machine);
- GLfloat result[4];
- GLuint i;
- for (i = 0; i < 4; i++) {
- const GLuint swz = GET_SWZ(source->Swizzle, i);
- if (swz == SWIZZLE_ZERO)
- result[i] = 0.0;
- else if (swz == SWIZZLE_ONE)
- result[i] = 1.0;
- else {
- ASSERT(swz >= 0);
- ASSERT(swz <= 3);
- result[i] = src[swz];
- }
- if (source->Negate & (1 << i))
- result[i] = -result[i];
- }
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_TEX: /* Both ARB and NV frag prog */
- /* Simple texel lookup */
- {
- GLfloat texcoord[4], color[4];
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
-
- fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
-
- if (DEBUG_PROG) {
- printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g]\n",
- color[0], color[1], color[2], color[3],
- inst->TexSrcUnit,
- texcoord[0], texcoord[1], texcoord[2], texcoord[3]);
- }
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXB: /* GL_ARB_fragment_program only */
- /* Texel lookup with LOD bias */
- {
- GLfloat texcoord[4], color[4], lodBias;
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
-
- /* texcoord[3] is the bias to add to lambda */
- lodBias = texcoord[3];
-
- fetch_texel(ctx, machine, inst, texcoord, lodBias, color);
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXD: /* GL_NV_fragment_program only */
- /* Texture lookup w/ partial derivatives for LOD */
- {
- GLfloat texcoord[4], dtdx[4], dtdy[4], color[4];
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
- fetch_vector4(&inst->SrcReg[1], machine, dtdx);
- fetch_vector4(&inst->SrcReg[2], machine, dtdy);
- machine->FetchTexelDeriv(ctx, texcoord, dtdx, dtdy,
- 0.0, /* lodBias */
- inst->TexSrcUnit, color);
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXL:
- /* Texel lookup with explicit LOD */
- {
- GLfloat texcoord[4], color[4], lod;
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
-
- /* texcoord[3] is the LOD */
- lod = texcoord[3];
-
- machine->FetchTexelLod(ctx, texcoord, lod,
- machine->Samplers[inst->TexSrcUnit], color);
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXP: /* GL_ARB_fragment_program only */
- /* Texture lookup w/ projective divide */
- {
- GLfloat texcoord[4], color[4];
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
- /* Not so sure about this test - if texcoord[3] is
- * zero, we'd probably be fine except for an ASSERT in
- * IROUND_POS() which gets triggered by the inf values created.
- */
- if (texcoord[3] != 0.0) {
- texcoord[0] /= texcoord[3];
- texcoord[1] /= texcoord[3];
- texcoord[2] /= texcoord[3];
- }
-
- fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXP_NV: /* GL_NV_fragment_program only */
- /* Texture lookup w/ projective divide, as above, but do not
- * do the divide by w if sampling from a cube map.
- */
- {
- GLfloat texcoord[4], color[4];
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
- if (inst->TexSrcTarget != TEXTURE_CUBE_INDEX &&
- texcoord[3] != 0.0) {
- texcoord[0] /= texcoord[3];
- texcoord[1] /= texcoord[3];
- texcoord[2] /= texcoord[3];
- }
-
- fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TRUNC: /* truncate toward zero */
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = (GLfloat) (GLint) a[0];
- result[1] = (GLfloat) (GLint) a[1];
- result[2] = (GLfloat) (GLint) a[2];
- result[3] = (GLfloat) (GLint) a[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP2H: /* unpack two 16-bit floats */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- GLushort hx, hy;
- hx = raw & 0xffff;
- hy = raw >> 16;
- result[0] = result[2] = _mesa_half_to_float(hx);
- result[1] = result[3] = _mesa_half_to_float(hy);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP2US: /* unpack two GLushorts */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- GLushort usx, usy;
- usx = raw & 0xffff;
- usy = raw >> 16;
- result[0] = result[2] = usx * (1.0f / 65535.0f);
- result[1] = result[3] = usy * (1.0f / 65535.0f);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP4B: /* unpack four GLbytes */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- result[0] = (((raw >> 0) & 0xff) - 128) / 127.0F;
- result[1] = (((raw >> 8) & 0xff) - 128) / 127.0F;
- result[2] = (((raw >> 16) & 0xff) - 128) / 127.0F;
- result[3] = (((raw >> 24) & 0xff) - 128) / 127.0F;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP4UB: /* unpack four GLubytes */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- result[0] = ((raw >> 0) & 0xff) / 255.0F;
- result[1] = ((raw >> 8) & 0xff) / 255.0F;
- result[2] = ((raw >> 16) & 0xff) / 255.0F;
- result[3] = ((raw >> 24) & 0xff) / 255.0F;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_XOR: /* bitwise XOR */
- {
- GLuint a[4], b[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- fetch_vector4ui(&inst->SrcReg[1], machine, b);
- result[0] = a[0] ^ b[0];
- result[1] = a[1] ^ b[1];
- result[2] = a[2] ^ b[2];
- result[3] = a[3] ^ b[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_XPD: /* cross product */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[1] * b[2] - a[2] * b[1];
- result[1] = a[2] * b[0] - a[0] * b[2];
- result[2] = a[0] * b[1] - a[1] * b[0];
- result[3] = 1.0;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("XPD (%g %g %g %g) = (%g %g %g) X (%g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], b[0], b[1], b[2]);
- }
- }
- break;
- case OPCODE_X2D: /* 2-D matrix transform */
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] + b[0] * c[0] + b[1] * c[1];
- result[1] = a[1] + b[0] * c[2] + b[1] * c[3];
- result[2] = a[2] + b[0] * c[0] + b[1] * c[1];
- result[3] = a[3] + b[0] * c[2] + b[1] * c[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_PRINT:
- {
- if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
- GLfloat a[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- printf("%s%g, %g, %g, %g\n", (const char *) inst->Data,
- a[0], a[1], a[2], a[3]);
- }
- else {
- printf("%s\n", (const char *) inst->Data);
- }
- }
- break;
- case OPCODE_END:
- return GL_TRUE;
- default:
- _mesa_problem(ctx, "Bad opcode %d in _mesa_execute_program",
- inst->Opcode);
- return GL_TRUE; /* return value doesn't matter */
- }
-
- numExec++;
- if (numExec > maxExec) {
- static GLboolean reported = GL_FALSE;
- if (!reported) {
- _mesa_problem(ctx, "Infinite loop detected in fragment program");
- reported = GL_TRUE;
- }
- return GL_TRUE;
- }
-
- } /* for pc */
-
- return GL_TRUE;
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.3
+ *
+ * Copyright (C) 1999-2008 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_execute.c
+ * Software interpreter for vertex/fragment programs.
+ * \author Brian Paul
+ */
+
+/*
+ * NOTE: we do everything in single-precision floating point; we don't
+ * currently observe the single/half/fixed-precision qualifiers.
+ *
+ */
+
+
+#include "main/glheader.h"
+#include "main/colormac.h"
+#include "main/macros.h"
+#include "prog_execute.h"
+#include "prog_instruction.h"
+#include "prog_parameter.h"
+#include "prog_print.h"
+#include "prog_noise.h"
+
+
+/* debug predicate */
+#define DEBUG_PROG 0
+
+
+/**
+ * Set x to positive or negative infinity.
+ */
+#if defined(USE_IEEE) || defined(_WIN32)
+#define SET_POS_INFINITY(x) \
+ do { \
+ fi_type fi; \
+ fi.i = 0x7F800000; \
+ x = fi.f; \
+ } while (0)
+#define SET_NEG_INFINITY(x) \
+ do { \
+ fi_type fi; \
+ fi.i = 0xFF800000; \
+ x = fi.f; \
+ } while (0)
+#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
+
+
+static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
+
+
+
+/**
+ * Return TRUE for +0 and other positive values, FALSE otherwise.
+ * Used for RCC opcode.
+ */
+static INLINE GLboolean
+positive(float x)
+{
+ fi_type fi;
+ fi.f = x;
+ if (fi.i & 0x80000000)
+ return GL_FALSE;
+ return GL_TRUE;
+}
+
+
+
+/**
+ * Return a pointer to the 4-element float vector specified by the given
+ * source register.
+ */
+static INLINE const GLfloat *
+get_src_register_pointer(const struct prog_src_register *source,
+ const struct gl_program_machine *machine)
+{
+ const struct gl_program *prog = machine->CurProgram;
+ GLint reg = source->Index;
+
+ if (source->RelAddr) {
+ /* add address register value to src index/offset */
+ reg += machine->AddressReg[0][0];
+ if (reg < 0) {
+ return ZeroVec;
+ }
+ }
+
+ switch (source->File) {
+ case PROGRAM_TEMPORARY:
+ if (reg >= MAX_PROGRAM_TEMPS)
+ return ZeroVec;
+ return machine->Temporaries[reg];
+
+ case PROGRAM_INPUT:
+ if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
+ if (reg >= VERT_ATTRIB_MAX)
+ return ZeroVec;
+ return machine->VertAttribs[reg];
+ }
+ else {
+ if (reg >= FRAG_ATTRIB_MAX)
+ return ZeroVec;
+ return machine->Attribs[reg][machine->CurElement];
+ }
+
+ case PROGRAM_OUTPUT:
+ if (reg >= MAX_PROGRAM_OUTPUTS)
+ return ZeroVec;
+ return machine->Outputs[reg];
+
+ case PROGRAM_LOCAL_PARAM:
+ if (reg >= MAX_PROGRAM_LOCAL_PARAMS)
+ return ZeroVec;
+ return machine->CurProgram->LocalParams[reg];
+
+ case PROGRAM_ENV_PARAM:
+ if (reg >= MAX_PROGRAM_ENV_PARAMS)
+ return ZeroVec;
+ return machine->EnvParams[reg];
+
+ case PROGRAM_STATE_VAR:
+ /* Fallthrough */
+ case PROGRAM_CONSTANT:
+ /* Fallthrough */
+ case PROGRAM_UNIFORM:
+ /* Fallthrough */
+ case PROGRAM_NAMED_PARAM:
+ if (reg >= (GLint) prog->Parameters->NumParameters)
+ return ZeroVec;
+ return prog->Parameters->ParameterValues[reg];
+
+ default:
+ _mesa_problem(NULL,
+ "Invalid src register file %d in get_src_register_pointer()",
+ source->File);
+ return NULL;
+ }
+}
+
+
+/**
+ * Return a pointer to the 4-element float vector specified by the given
+ * destination register.
+ */
+static INLINE GLfloat *
+get_dst_register_pointer(const struct prog_dst_register *dest,
+ struct gl_program_machine *machine)
+{
+ static GLfloat dummyReg[4];
+ GLint reg = dest->Index;
+
+ if (dest->RelAddr) {
+ /* add address register value to src index/offset */
+ reg += machine->AddressReg[0][0];
+ if (reg < 0) {
+ return dummyReg;
+ }
+ }
+
+ switch (dest->File) {
+ case PROGRAM_TEMPORARY:
+ if (reg >= MAX_PROGRAM_TEMPS)
+ return dummyReg;
+ return machine->Temporaries[reg];
+
+ case PROGRAM_OUTPUT:
+ if (reg >= MAX_PROGRAM_OUTPUTS)
+ return dummyReg;
+ return machine->Outputs[reg];
+
+ case PROGRAM_WRITE_ONLY:
+ return dummyReg;
+
+ default:
+ _mesa_problem(NULL,
+ "Invalid dest register file %d in get_dst_register_pointer()",
+ dest->File);
+ return NULL;
+ }
+}
+
+
+
+/**
+ * Fetch a 4-element float vector from the given source register.
+ * Apply swizzling and negating as needed.
+ */
+static void
+fetch_vector4(const struct prog_src_register *source,
+ const struct gl_program_machine *machine, GLfloat result[4])
+{
+ const GLfloat *src = get_src_register_pointer(source, machine);
+ ASSERT(src);
+
+ if (source->Swizzle == SWIZZLE_NOOP) {
+ /* no swizzling */
+ COPY_4V(result, src);
+ }
+ else {
+ ASSERT(GET_SWZ(source->Swizzle, 0) <= 3);
+ ASSERT(GET_SWZ(source->Swizzle, 1) <= 3);
+ ASSERT(GET_SWZ(source->Swizzle, 2) <= 3);
+ ASSERT(GET_SWZ(source->Swizzle, 3) <= 3);
+ 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)];
+ }
+
+ if (source->Abs) {
+ result[0] = FABSF(result[0]);
+ result[1] = FABSF(result[1]);
+ result[2] = FABSF(result[2]);
+ result[3] = FABSF(result[3]);
+ }
+ if (source->Negate) {
+ ASSERT(source->Negate == NEGATE_XYZW);
+ result[0] = -result[0];
+ result[1] = -result[1];
+ result[2] = -result[2];
+ result[3] = -result[3];
+ }
+
+#ifdef NAN_CHECK
+ assert(!IS_INF_OR_NAN(result[0]));
+ assert(!IS_INF_OR_NAN(result[0]));
+ assert(!IS_INF_OR_NAN(result[0]));
+ assert(!IS_INF_OR_NAN(result[0]));
+#endif
+}
+
+
+/**
+ * Fetch a 4-element uint vector from the given source register.
+ * Apply swizzling but not negation/abs.
+ */
+static void
+fetch_vector4ui(const struct prog_src_register *source,
+ const struct gl_program_machine *machine, GLuint result[4])
+{
+ const GLuint *src = (GLuint *) get_src_register_pointer(source, machine);
+ ASSERT(src);
+
+ if (source->Swizzle == SWIZZLE_NOOP) {
+ /* no swizzling */
+ COPY_4V(result, src);
+ }
+ else {
+ ASSERT(GET_SWZ(source->Swizzle, 0) <= 3);
+ ASSERT(GET_SWZ(source->Swizzle, 1) <= 3);
+ ASSERT(GET_SWZ(source->Swizzle, 2) <= 3);
+ ASSERT(GET_SWZ(source->Swizzle, 3) <= 3);
+ 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)];
+ }
+
+ /* Note: no Negate or Abs here */
+}
+
+
+
+/**
+ * Fetch the derivative with respect to X or Y for the given register.
+ * XXX this currently only works for fragment program input attribs.
+ */
+static void
+fetch_vector4_deriv(struct gl_context * ctx,
+ const struct prog_src_register *source,
+ const struct gl_program_machine *machine,
+ char xOrY, GLfloat result[4])
+{
+ if (source->File == PROGRAM_INPUT &&
+ source->Index < (GLint) machine->NumDeriv) {
+ const GLint col = machine->CurElement;
+ const GLfloat w = machine->Attribs[FRAG_ATTRIB_WPOS][col][3];
+ const GLfloat invQ = 1.0f / w;
+ GLfloat deriv[4];
+
+ if (xOrY == 'X') {
+ deriv[0] = machine->DerivX[source->Index][0] * invQ;
+ deriv[1] = machine->DerivX[source->Index][1] * invQ;
+ deriv[2] = machine->DerivX[source->Index][2] * invQ;
+ deriv[3] = machine->DerivX[source->Index][3] * invQ;
+ }
+ else {
+ deriv[0] = machine->DerivY[source->Index][0] * invQ;
+ deriv[1] = machine->DerivY[source->Index][1] * invQ;
+ deriv[2] = machine->DerivY[source->Index][2] * invQ;
+ deriv[3] = machine->DerivY[source->Index][3] * invQ;
+ }
+
+ result[0] = deriv[GET_SWZ(source->Swizzle, 0)];
+ result[1] = deriv[GET_SWZ(source->Swizzle, 1)];
+ result[2] = deriv[GET_SWZ(source->Swizzle, 2)];
+ result[3] = deriv[GET_SWZ(source->Swizzle, 3)];
+
+ if (source->Abs) {
+ result[0] = FABSF(result[0]);
+ result[1] = FABSF(result[1]);
+ result[2] = FABSF(result[2]);
+ result[3] = FABSF(result[3]);
+ }
+ if (source->Negate) {
+ ASSERT(source->Negate == NEGATE_XYZW);
+ result[0] = -result[0];
+ result[1] = -result[1];
+ result[2] = -result[2];
+ result[3] = -result[3];
+ }
+ }
+ else {
+ ASSIGN_4V(result, 0.0, 0.0, 0.0, 0.0);
+ }
+}
+
+
+/**
+ * As above, but only return result[0] element.
+ */
+static void
+fetch_vector1(const struct prog_src_register *source,
+ const struct gl_program_machine *machine, GLfloat result[4])
+{
+ const GLfloat *src = get_src_register_pointer(source, machine);
+ ASSERT(src);
+
+ result[0] = src[GET_SWZ(source->Swizzle, 0)];
+
+ if (source->Abs) {
+ result[0] = FABSF(result[0]);
+ }
+ if (source->Negate) {
+ result[0] = -result[0];
+ }
+}
+
+
+static GLuint
+fetch_vector1ui(const struct prog_src_register *source,
+ const struct gl_program_machine *machine)
+{
+ const GLuint *src = (GLuint *) get_src_register_pointer(source, machine);
+ return src[GET_SWZ(source->Swizzle, 0)];
+}
+
+
+/**
+ * Fetch texel from texture. Use partial derivatives when possible.
+ */
+static INLINE void
+fetch_texel(struct gl_context *ctx,
+ const struct gl_program_machine *machine,
+ const struct prog_instruction *inst,
+ const GLfloat texcoord[4], GLfloat lodBias,
+ GLfloat color[4])
+{
+ const GLuint unit = machine->Samplers[inst->TexSrcUnit];
+
+ /* Note: we only have the right derivatives for fragment input attribs.
+ */
+ if (machine->NumDeriv > 0 &&
+ inst->SrcReg[0].File == PROGRAM_INPUT &&
+ inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit) {
+ /* simple texture fetch for which we should have derivatives */
+ GLuint attr = inst->SrcReg[0].Index;
+ machine->FetchTexelDeriv(ctx, texcoord,
+ machine->DerivX[attr],
+ machine->DerivY[attr],
+ lodBias, unit, color);
+ }
+ else {
+ machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color);
+ }
+}
+
+
+/**
+ * Test value against zero and return GT, LT, EQ or UN if NaN.
+ */
+static INLINE GLuint
+generate_cc(float value)
+{
+ if (value != value)
+ return COND_UN; /* NaN */
+ if (value > 0.0F)
+ return COND_GT;
+ if (value < 0.0F)
+ return COND_LT;
+ return COND_EQ;
+}
+
+
+/**
+ * Test if the ccMaskRule is satisfied by the given condition code.
+ * Used to mask destination writes according to the current condition code.
+ */
+static INLINE GLboolean
+test_cc(GLuint condCode, GLuint ccMaskRule)
+{
+ switch (ccMaskRule) {
+ case COND_EQ: return (condCode == COND_EQ);
+ case COND_NE: return (condCode != COND_EQ);
+ case COND_LT: return (condCode == COND_LT);
+ case COND_GE: return (condCode == COND_GT || condCode == COND_EQ);
+ case COND_LE: return (condCode == COND_LT || condCode == COND_EQ);
+ case COND_GT: return (condCode == COND_GT);
+ case COND_TR: return GL_TRUE;
+ case COND_FL: return GL_FALSE;
+ default: return GL_TRUE;
+ }
+}
+
+
+/**
+ * Evaluate the 4 condition codes against a predicate and return GL_TRUE
+ * or GL_FALSE to indicate result.
+ */
+static INLINE GLboolean
+eval_condition(const struct gl_program_machine *machine,
+ const struct prog_instruction *inst)
+{
+ const GLuint swizzle = inst->DstReg.CondSwizzle;
+ const GLuint condMask = inst->DstReg.CondMask;
+ if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) {
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+}
+
+
+
+/**
+ * Store 4 floats into a register. Observe the instructions saturate and
+ * set-condition-code flags.
+ */
+static void
+store_vector4(const struct prog_instruction *inst,
+ struct gl_program_machine *machine, const GLfloat value[4])
+{
+ const struct prog_dst_register *dstReg = &(inst->DstReg);
+ const GLboolean clamp = inst->SaturateMode == SATURATE_ZERO_ONE;
+ GLuint writeMask = dstReg->WriteMask;
+ GLfloat clampedValue[4];
+ GLfloat *dst = get_dst_register_pointer(dstReg, machine);
+
+#if 0
+ if (value[0] > 1.0e10 ||
+ IS_INF_OR_NAN(value[0]) ||
+ IS_INF_OR_NAN(value[1]) ||
+ IS_INF_OR_NAN(value[2]) || IS_INF_OR_NAN(value[3]))
+ printf("store %g %g %g %g\n", value[0], value[1], value[2], value[3]);
+#endif
+
+ if (clamp) {
+ clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F);
+ clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F);
+ clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F);
+ clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F);
+ value = clampedValue;
+ }
+
+ if (dstReg->CondMask != COND_TR) {
+ /* condition codes may turn off some writes */
+ if (writeMask & WRITEMASK_X) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_X;
+ }
+ if (writeMask & WRITEMASK_Y) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_Y;
+ }
+ if (writeMask & WRITEMASK_Z) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_Z;
+ }
+ if (writeMask & WRITEMASK_W) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_W;
+ }
+ }
+
+#ifdef NAN_CHECK
+ assert(!IS_INF_OR_NAN(value[0]));
+ assert(!IS_INF_OR_NAN(value[0]));
+ assert(!IS_INF_OR_NAN(value[0]));
+ assert(!IS_INF_OR_NAN(value[0]));
+#endif
+
+ if (writeMask & WRITEMASK_X)
+ dst[0] = value[0];
+ if (writeMask & WRITEMASK_Y)
+ dst[1] = value[1];
+ if (writeMask & WRITEMASK_Z)
+ dst[2] = value[2];
+ if (writeMask & WRITEMASK_W)
+ dst[3] = value[3];
+
+ if (inst->CondUpdate) {
+ if (writeMask & WRITEMASK_X)
+ machine->CondCodes[0] = generate_cc(value[0]);
+ if (writeMask & WRITEMASK_Y)
+ machine->CondCodes[1] = generate_cc(value[1]);
+ if (writeMask & WRITEMASK_Z)
+ machine->CondCodes[2] = generate_cc(value[2]);
+ if (writeMask & WRITEMASK_W)
+ machine->CondCodes[3] = generate_cc(value[3]);
+#if DEBUG_PROG
+ printf("CondCodes=(%s,%s,%s,%s) for:\n",
+ _mesa_condcode_string(machine->CondCodes[0]),
+ _mesa_condcode_string(machine->CondCodes[1]),
+ _mesa_condcode_string(machine->CondCodes[2]),
+ _mesa_condcode_string(machine->CondCodes[3]));
+#endif
+ }
+}
+
+
+/**
+ * Store 4 uints into a register. Observe the set-condition-code flags.
+ */
+static void
+store_vector4ui(const struct prog_instruction *inst,
+ struct gl_program_machine *machine, const GLuint value[4])
+{
+ const struct prog_dst_register *dstReg = &(inst->DstReg);
+ GLuint writeMask = dstReg->WriteMask;
+ GLuint *dst = (GLuint *) get_dst_register_pointer(dstReg, machine);
+
+ if (dstReg->CondMask != COND_TR) {
+ /* condition codes may turn off some writes */
+ if (writeMask & WRITEMASK_X) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_X;
+ }
+ if (writeMask & WRITEMASK_Y) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_Y;
+ }
+ if (writeMask & WRITEMASK_Z) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_Z;
+ }
+ if (writeMask & WRITEMASK_W) {
+ if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)],
+ dstReg->CondMask))
+ writeMask &= ~WRITEMASK_W;
+ }
+ }
+
+ if (writeMask & WRITEMASK_X)
+ dst[0] = value[0];
+ if (writeMask & WRITEMASK_Y)
+ dst[1] = value[1];
+ if (writeMask & WRITEMASK_Z)
+ dst[2] = value[2];
+ if (writeMask & WRITEMASK_W)
+ dst[3] = value[3];
+
+ if (inst->CondUpdate) {
+ if (writeMask & WRITEMASK_X)
+ machine->CondCodes[0] = generate_cc((float)value[0]);
+ if (writeMask & WRITEMASK_Y)
+ machine->CondCodes[1] = generate_cc((float)value[1]);
+ if (writeMask & WRITEMASK_Z)
+ machine->CondCodes[2] = generate_cc((float)value[2]);
+ if (writeMask & WRITEMASK_W)
+ machine->CondCodes[3] = generate_cc((float)value[3]);
+#if DEBUG_PROG
+ printf("CondCodes=(%s,%s,%s,%s) for:\n",
+ _mesa_condcode_string(machine->CondCodes[0]),
+ _mesa_condcode_string(machine->CondCodes[1]),
+ _mesa_condcode_string(machine->CondCodes[2]),
+ _mesa_condcode_string(machine->CondCodes[3]));
+#endif
+ }
+}
+
+
+
+/**
+ * Execute the given vertex/fragment program.
+ *
+ * \param ctx rendering context
+ * \param program the program to execute
+ * \param machine machine state (must be initialized)
+ * \return GL_TRUE if program completed or GL_FALSE if program executed KIL.
+ */
+GLboolean
+_mesa_execute_program(struct gl_context * ctx,
+ const struct gl_program *program,
+ struct gl_program_machine *machine)
+{
+ const GLuint numInst = program->NumInstructions;
+ const GLuint maxExec = 10000;
+ GLuint pc, numExec = 0;
+
+ machine->CurProgram = program;
+
+ if (DEBUG_PROG) {
+ printf("execute program %u --------------------\n", program->Id);
+ }
+
+ if (program->Target == GL_VERTEX_PROGRAM_ARB) {
+ machine->EnvParams = ctx->VertexProgram.Parameters;
+ }
+ else {
+ machine->EnvParams = ctx->FragmentProgram.Parameters;
+ }
+
+ for (pc = 0; pc < numInst; pc++) {
+ const struct prog_instruction *inst = program->Instructions + pc;
+
+ if (DEBUG_PROG) {
+ _mesa_print_instruction(inst);
+ }
+
+ switch (inst->Opcode) {
+ case OPCODE_ABS:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] = FABSF(a[0]);
+ result[1] = FABSF(a[1]);
+ result[2] = FABSF(a[2]);
+ result[3] = FABSF(a[3]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_ADD:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = a[0] + b[0];
+ result[1] = a[1] + b[1];
+ result[2] = a[2] + b[2];
+ result[3] = a[3] + b[3];
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("ADD (%g %g %g %g) = (%g %g %g %g) + (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_AND: /* bitwise AND */
+ {
+ GLuint a[4], b[4], result[4];
+ fetch_vector4ui(&inst->SrcReg[0], machine, a);
+ fetch_vector4ui(&inst->SrcReg[1], machine, b);
+ result[0] = a[0] & b[0];
+ result[1] = a[1] & b[1];
+ result[2] = a[2] & b[2];
+ result[3] = a[3] & b[3];
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_ARL:
+ {
+ GLfloat t[4];
+ fetch_vector4(&inst->SrcReg[0], machine, t);
+ machine->AddressReg[0][0] = IFLOOR(t[0]);
+ if (DEBUG_PROG) {
+ printf("ARL %d\n", machine->AddressReg[0][0]);
+ }
+ }
+ break;
+ case OPCODE_BGNLOOP:
+ /* no-op */
+ ASSERT(program->Instructions[inst->BranchTarget].Opcode
+ == OPCODE_ENDLOOP);
+ break;
+ case OPCODE_ENDLOOP:
+ /* subtract 1 here since pc is incremented by for(pc) loop */
+ ASSERT(program->Instructions[inst->BranchTarget].Opcode
+ == OPCODE_BGNLOOP);
+ pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */
+ break;
+ case OPCODE_BGNSUB: /* begin subroutine */
+ break;
+ case OPCODE_ENDSUB: /* end subroutine */
+ break;
+ case OPCODE_BRA: /* branch (conditional) */
+ if (eval_condition(machine, inst)) {
+ /* take branch */
+ /* Subtract 1 here since we'll do pc++ below */
+ pc = inst->BranchTarget - 1;
+ }
+ break;
+ case OPCODE_BRK: /* break out of loop (conditional) */
+ ASSERT(program->Instructions[inst->BranchTarget].Opcode
+ == OPCODE_ENDLOOP);
+ if (eval_condition(machine, inst)) {
+ /* break out of loop */
+ /* pc++ at end of for-loop will put us after the ENDLOOP inst */
+ pc = inst->BranchTarget;
+ }
+ break;
+ case OPCODE_CONT: /* continue loop (conditional) */
+ ASSERT(program->Instructions[inst->BranchTarget].Opcode
+ == OPCODE_ENDLOOP);
+ if (eval_condition(machine, inst)) {
+ /* continue at ENDLOOP */
+ /* Subtract 1 here since we'll do pc++ at end of for-loop */
+ pc = inst->BranchTarget - 1;
+ }
+ break;
+ case OPCODE_CAL: /* Call subroutine (conditional) */
+ if (eval_condition(machine, inst)) {
+ /* call the subroutine */
+ if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) {
+ return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
+ }
+ machine->CallStack[machine->StackDepth++] = pc + 1; /* next inst */
+ /* Subtract 1 here since we'll do pc++ at end of for-loop */
+ pc = inst->BranchTarget - 1;
+ }
+ break;
+ case OPCODE_CMP:
+ {
+ GLfloat a[4], b[4], c[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ fetch_vector4(&inst->SrcReg[2], machine, c);
+ result[0] = a[0] < 0.0F ? b[0] : c[0];
+ result[1] = a[1] < 0.0F ? b[1] : c[1];
+ result[2] = a[2] < 0.0F ? b[2] : c[2];
+ result[3] = a[3] < 0.0F ? b[3] : c[3];
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("CMP (%g %g %g %g) = (%g %g %g %g) < 0 ? (%g %g %g %g) : (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3],
+ c[0], c[1], c[2], c[3]);
+ }
+ }
+ break;
+ case OPCODE_COS:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ result[0] = result[1] = result[2] = result[3]
+ = (GLfloat) cos(a[0]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_DDX: /* Partial derivative with respect to X */
+ {
+ GLfloat result[4];
+ fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine,
+ 'X', result);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_DDY: /* Partial derivative with respect to Y */
+ {
+ GLfloat result[4];
+ fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine,
+ 'Y', result);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_DP2:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = result[1] = result[2] = result[3] = DOT2(a, b);
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("DP2 %g = (%g %g) . (%g %g)\n",
+ result[0], a[0], a[1], b[0], b[1]);
+ }
+ }
+ break;
+ case OPCODE_DP2A:
+ {
+ GLfloat a[4], b[4], c, result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ fetch_vector1(&inst->SrcReg[1], machine, &c);
+ result[0] = result[1] = result[2] = result[3] = DOT2(a, b) + c;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("DP2A %g = (%g %g) . (%g %g) + %g\n",
+ result[0], a[0], a[1], b[0], b[1], c);
+ }
+ }
+ break;
+ case OPCODE_DP3:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = result[1] = result[2] = result[3] = DOT3(a, b);
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("DP3 %g = (%g %g %g) . (%g %g %g)\n",
+ result[0], a[0], a[1], a[2], b[0], b[1], b[2]);
+ }
+ }
+ break;
+ case OPCODE_DP4:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = result[1] = result[2] = result[3] = DOT4(a, b);
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("DP4 %g = (%g, %g %g %g) . (%g, %g %g %g)\n",
+ result[0], a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_DPH:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = result[1] = result[2] = result[3] = DOT3(a, b) + b[3];
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_DST: /* Distance vector */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = 1.0F;
+ result[1] = a[1] * b[1];
+ result[2] = a[2];
+ result[3] = b[3];
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_EXP:
+ {
+ GLfloat t[4], q[4], floor_t0;
+ fetch_vector1(&inst->SrcReg[0], machine, 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 {
+ q[0] = LDEXPF(1.0, (int) floor_t0);
+ /* Note: GL_NV_vertex_program expects
+ * result.z = result.x * APPX(result.y)
+ * We do what the ARB extension says.
+ */
+ q[2] = (GLfloat) pow(2.0, t[0]);
+ }
+ q[1] = t[0] - floor_t0;
+ q[3] = 1.0F;
+ store_vector4( inst, machine, q );
+ }
+ break;
+ case OPCODE_EX2: /* Exponential base 2 */
+ {
+ GLfloat a[4], result[4], val;
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ val = (GLfloat) pow(2.0, a[0]);
+ /*
+ if (IS_INF_OR_NAN(val))
+ val = 1.0e10;
+ */
+ result[0] = result[1] = result[2] = result[3] = val;
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_FLR:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] = FLOORF(a[0]);
+ result[1] = FLOORF(a[1]);
+ result[2] = FLOORF(a[2]);
+ result[3] = FLOORF(a[3]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_FRC:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] = a[0] - FLOORF(a[0]);
+ result[1] = a[1] - FLOORF(a[1]);
+ result[2] = a[2] - FLOORF(a[2]);
+ result[3] = a[3] - FLOORF(a[3]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_IF:
+ {
+ GLboolean cond;
+ ASSERT(program->Instructions[inst->BranchTarget].Opcode
+ == OPCODE_ELSE ||
+ program->Instructions[inst->BranchTarget].Opcode
+ == OPCODE_ENDIF);
+ /* eval condition */
+ if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+ GLfloat a[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ cond = (a[0] != 0.0);
+ }
+ else {
+ cond = eval_condition(machine, inst);
+ }
+ if (DEBUG_PROG) {
+ printf("IF: %d\n", cond);
+ }
+ /* do if/else */
+ if (cond) {
+ /* do if-clause (just continue execution) */
+ }
+ else {
+ /* go to the instruction after ELSE or ENDIF */
+ assert(inst->BranchTarget >= 0);
+ pc = inst->BranchTarget;
+ }
+ }
+ break;
+ case OPCODE_ELSE:
+ /* goto ENDIF */
+ ASSERT(program->Instructions[inst->BranchTarget].Opcode
+ == OPCODE_ENDIF);
+ assert(inst->BranchTarget >= 0);
+ pc = inst->BranchTarget;
+ break;
+ case OPCODE_ENDIF:
+ /* nothing */
+ break;
+ case OPCODE_KIL_NV: /* NV_f_p only (conditional) */
+ if (eval_condition(machine, inst)) {
+ return GL_FALSE;
+ }
+ break;
+ case OPCODE_KIL: /* ARB_f_p only */
+ {
+ GLfloat a[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ if (DEBUG_PROG) {
+ printf("KIL if (%g %g %g %g) <= 0.0\n",
+ a[0], a[1], a[2], a[3]);
+ }
+
+ if (a[0] < 0.0F || a[1] < 0.0F || a[2] < 0.0F || a[3] < 0.0F) {
+ return GL_FALSE;
+ }
+ }
+ break;
+ case OPCODE_LG2: /* log base 2 */
+ {
+ GLfloat a[4], result[4], val;
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ /* The fast LOG2 macro doesn't meet the precision requirements.
+ */
+ if (a[0] == 0.0F) {
+ val = -FLT_MAX;
+ }
+ else {
+ val = (float)(log(a[0]) * 1.442695F);
+ }
+ result[0] = result[1] = result[2] = result[3] = val;
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_LIT:
+ {
+ const GLfloat epsilon = 1.0F / 256.0F; /* from NV VP spec */
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ a[0] = MAX2(a[0], 0.0F);
+ a[1] = MAX2(a[1], 0.0F);
+ /* XXX ARB version clamps a[3], NV version doesn't */
+ a[3] = CLAMP(a[3], -(128.0F - epsilon), (128.0F - epsilon));
+ result[0] = 1.0F;
+ result[1] = a[0];
+ /* XXX we could probably just use pow() here */
+ if (a[0] > 0.0F) {
+ if (a[1] == 0.0 && a[3] == 0.0)
+ result[2] = 1.0F;
+ else
+ result[2] = (GLfloat) pow(a[1], a[3]);
+ }
+ else {
+ result[2] = 0.0F;
+ }
+ result[3] = 1.0F;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("LIT (%g %g %g %g) : (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3]);
+ }
+ }
+ break;
+ case OPCODE_LOG:
+ {
+ GLfloat t[4], q[4], abs_t0;
+ fetch_vector1(&inst->SrcReg[0], machine, 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) */
+
+ /* The fast LOG2 macro doesn't meet the precision
+ * requirements.
+ */
+ q[2] = (float)(log(t[0]) * 1.442695F);
+ }
+ }
+ else {
+ SET_NEG_INFINITY(q[0]);
+ q[1] = 1.0F;
+ SET_NEG_INFINITY(q[2]);
+ }
+ q[3] = 1.0;
+ store_vector4(inst, machine, q);
+ }
+ break;
+ case OPCODE_LRP:
+ {
+ GLfloat a[4], b[4], c[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ fetch_vector4(&inst->SrcReg[2], machine, c);
+ result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0];
+ result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1];
+ result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2];
+ result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3];
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("LRP (%g %g %g %g) = (%g %g %g %g), "
+ "(%g %g %g %g), (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
+ }
+ }
+ break;
+ case OPCODE_MAD:
+ {
+ GLfloat a[4], b[4], c[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ fetch_vector4(&inst->SrcReg[2], machine, c);
+ result[0] = a[0] * b[0] + c[0];
+ result[1] = a[1] * b[1] + c[1];
+ result[2] = a[2] * b[2] + c[2];
+ result[3] = a[3] * b[3] + c[3];
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("MAD (%g %g %g %g) = (%g %g %g %g) * "
+ "(%g %g %g %g) + (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
+ }
+ }
+ break;
+ case OPCODE_MAX:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = MAX2(a[0], b[0]);
+ result[1] = MAX2(a[1], b[1]);
+ result[2] = MAX2(a[2], b[2]);
+ result[3] = MAX2(a[3], b[3]);
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("MAX (%g %g %g %g) = (%g %g %g %g), (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_MIN:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = MIN2(a[0], b[0]);
+ result[1] = MIN2(a[1], b[1]);
+ result[2] = MIN2(a[2], b[2]);
+ result[3] = MIN2(a[3], b[3]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_MOV:
+ {
+ GLfloat result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, result);
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("MOV (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3]);
+ }
+ }
+ break;
+ case OPCODE_MUL:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = a[0] * b[0];
+ result[1] = a[1] * b[1];
+ result[2] = a[2] * b[2];
+ result[3] = a[3] * b[3];
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("MUL (%g %g %g %g) = (%g %g %g %g) * (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_NOISE1:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ result[0] =
+ result[1] =
+ result[2] =
+ result[3] = _mesa_noise1(a[0]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_NOISE2:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] =
+ result[1] =
+ result[2] = result[3] = _mesa_noise2(a[0], a[1]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_NOISE3:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] =
+ result[1] =
+ result[2] =
+ result[3] = _mesa_noise3(a[0], a[1], a[2]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_NOISE4:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] =
+ result[1] =
+ result[2] =
+ result[3] = _mesa_noise4(a[0], a[1], a[2], a[3]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_NOP:
+ break;
+ case OPCODE_NOT: /* bitwise NOT */
+ {
+ GLuint a[4], result[4];
+ fetch_vector4ui(&inst->SrcReg[0], machine, a);
+ result[0] = ~a[0];
+ result[1] = ~a[1];
+ result[2] = ~a[2];
+ result[3] = ~a[3];
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_NRM3: /* 3-component normalization */
+ {
+ GLfloat a[4], result[4];
+ GLfloat tmp;
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
+ if (tmp != 0.0F)
+ tmp = INV_SQRTF(tmp);
+ result[0] = tmp * a[0];
+ result[1] = tmp * a[1];
+ result[2] = tmp * a[2];
+ result[3] = 0.0; /* undefined, but prevent valgrind warnings */
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_NRM4: /* 4-component normalization */
+ {
+ GLfloat a[4], result[4];
+ GLfloat tmp;
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3];
+ if (tmp != 0.0F)
+ tmp = INV_SQRTF(tmp);
+ result[0] = tmp * a[0];
+ result[1] = tmp * a[1];
+ result[2] = tmp * a[2];
+ result[3] = tmp * a[3];
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_OR: /* bitwise OR */
+ {
+ GLuint a[4], b[4], result[4];
+ fetch_vector4ui(&inst->SrcReg[0], machine, a);
+ fetch_vector4ui(&inst->SrcReg[1], machine, b);
+ result[0] = a[0] | b[0];
+ result[1] = a[1] | b[1];
+ result[2] = a[2] | b[2];
+ result[3] = a[3] | b[3];
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_PK2H: /* pack two 16-bit floats in one 32-bit float */
+ {
+ GLfloat a[4];
+ GLuint result[4];
+ GLhalfNV hx, hy;
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ hx = _mesa_float_to_half(a[0]);
+ hy = _mesa_float_to_half(a[1]);
+ result[0] =
+ result[1] =
+ result[2] =
+ result[3] = hx | (hy << 16);
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_PK2US: /* pack two GLushorts into one 32-bit float */
+ {
+ GLfloat a[4];
+ GLuint result[4], usx, usy;
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ a[0] = CLAMP(a[0], 0.0F, 1.0F);
+ a[1] = CLAMP(a[1], 0.0F, 1.0F);
+ usx = IROUND(a[0] * 65535.0F);
+ usy = IROUND(a[1] * 65535.0F);
+ result[0] =
+ result[1] =
+ result[2] =
+ result[3] = usx | (usy << 16);
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_PK4B: /* pack four GLbytes into one 32-bit float */
+ {
+ GLfloat a[4];
+ GLuint result[4], ubx, uby, ubz, ubw;
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ a[0] = CLAMP(a[0], -128.0F / 127.0F, 1.0F);
+ a[1] = CLAMP(a[1], -128.0F / 127.0F, 1.0F);
+ a[2] = CLAMP(a[2], -128.0F / 127.0F, 1.0F);
+ a[3] = CLAMP(a[3], -128.0F / 127.0F, 1.0F);
+ ubx = IROUND(127.0F * a[0] + 128.0F);
+ uby = IROUND(127.0F * a[1] + 128.0F);
+ ubz = IROUND(127.0F * a[2] + 128.0F);
+ ubw = IROUND(127.0F * a[3] + 128.0F);
+ result[0] =
+ result[1] =
+ result[2] =
+ result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24);
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_PK4UB: /* pack four GLubytes into one 32-bit float */
+ {
+ GLfloat a[4];
+ GLuint result[4], ubx, uby, ubz, ubw;
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ a[0] = CLAMP(a[0], 0.0F, 1.0F);
+ a[1] = CLAMP(a[1], 0.0F, 1.0F);
+ a[2] = CLAMP(a[2], 0.0F, 1.0F);
+ a[3] = CLAMP(a[3], 0.0F, 1.0F);
+ ubx = IROUND(255.0F * a[0]);
+ uby = IROUND(255.0F * a[1]);
+ ubz = IROUND(255.0F * a[2]);
+ ubw = IROUND(255.0F * a[3]);
+ result[0] =
+ result[1] =
+ result[2] =
+ result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24);
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_POW:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ fetch_vector1(&inst->SrcReg[1], machine, b);
+ result[0] = result[1] = result[2] = result[3]
+ = (GLfloat) pow(a[0], b[0]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_RCC: /* clamped riciprocal */
+ {
+ const float largest = 1.884467e+19, smallest = 5.42101e-20;
+ GLfloat a[4], r, result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ if (DEBUG_PROG) {
+ if (a[0] == 0)
+ printf("RCC(0)\n");
+ else if (IS_INF_OR_NAN(a[0]))
+ printf("RCC(inf)\n");
+ }
+ if (a[0] == 1.0F) {
+ r = 1.0F;
+ }
+ else {
+ r = 1.0F / a[0];
+ }
+ if (positive(r)) {
+ if (r > largest) {
+ r = largest;
+ }
+ else if (r < smallest) {
+ r = smallest;
+ }
+ }
+ else {
+ if (r < -largest) {
+ r = -largest;
+ }
+ else if (r > -smallest) {
+ r = -smallest;
+ }
+ }
+ result[0] = result[1] = result[2] = result[3] = r;
+ store_vector4(inst, machine, result);
+ }
+ break;
+
+ case OPCODE_RCP:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ if (DEBUG_PROG) {
+ if (a[0] == 0)
+ printf("RCP(0)\n");
+ else if (IS_INF_OR_NAN(a[0]))
+ printf("RCP(inf)\n");
+ }
+ result[0] = result[1] = result[2] = result[3] = 1.0F / a[0];
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_RET: /* return from subroutine (conditional) */
+ if (eval_condition(machine, inst)) {
+ if (machine->StackDepth == 0) {
+ return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
+ }
+ /* subtract one because of pc++ in the for loop */
+ pc = machine->CallStack[--machine->StackDepth] - 1;
+ }
+ break;
+ case OPCODE_RFL: /* reflection vector */
+ {
+ GLfloat axis[4], dir[4], result[4], tmpX, tmpW;
+ fetch_vector4(&inst->SrcReg[0], machine, axis);
+ fetch_vector4(&inst->SrcReg[1], machine, dir);
+ tmpW = DOT3(axis, axis);
+ tmpX = (2.0F * DOT3(axis, dir)) / tmpW;
+ result[0] = tmpX * axis[0] - dir[0];
+ result[1] = tmpX * axis[1] - dir[1];
+ result[2] = tmpX * axis[2] - dir[2];
+ /* result[3] is never written! XXX enforce in parser! */
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_RSQ: /* 1 / sqrt() */
+ {
+ GLfloat a[4], result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ a[0] = FABSF(a[0]);
+ result[0] = result[1] = result[2] = result[3] = INV_SQRTF(a[0]);
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("RSQ %g = 1/sqrt(|%g|)\n", result[0], a[0]);
+ }
+ }
+ break;
+ case OPCODE_SCS: /* sine and cos */
+ {
+ GLfloat a[4], result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ result[0] = (GLfloat) cos(a[0]);
+ result[1] = (GLfloat) sin(a[0]);
+ result[2] = 0.0; /* undefined! */
+ result[3] = 0.0; /* undefined! */
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_SEQ: /* set on equal */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = (a[0] == b[0]) ? 1.0F : 0.0F;
+ result[1] = (a[1] == b[1]) ? 1.0F : 0.0F;
+ result[2] = (a[2] == b[2]) ? 1.0F : 0.0F;
+ result[3] = (a[3] == b[3]) ? 1.0F : 0.0F;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("SEQ (%g %g %g %g) = (%g %g %g %g) == (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_SFL: /* set false, operands ignored */
+ {
+ static const GLfloat result[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_SGE: /* set on greater or equal */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = (a[0] >= b[0]) ? 1.0F : 0.0F;
+ result[1] = (a[1] >= b[1]) ? 1.0F : 0.0F;
+ result[2] = (a[2] >= b[2]) ? 1.0F : 0.0F;
+ result[3] = (a[3] >= b[3]) ? 1.0F : 0.0F;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("SGE (%g %g %g %g) = (%g %g %g %g) >= (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_SGT: /* set on greater */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = (a[0] > b[0]) ? 1.0F : 0.0F;
+ result[1] = (a[1] > b[1]) ? 1.0F : 0.0F;
+ result[2] = (a[2] > b[2]) ? 1.0F : 0.0F;
+ result[3] = (a[3] > b[3]) ? 1.0F : 0.0F;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("SGT (%g %g %g %g) = (%g %g %g %g) > (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_SIN:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector1(&inst->SrcReg[0], machine, a);
+ result[0] = result[1] = result[2] = result[3]
+ = (GLfloat) sin(a[0]);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_SLE: /* set on less or equal */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = (a[0] <= b[0]) ? 1.0F : 0.0F;
+ result[1] = (a[1] <= b[1]) ? 1.0F : 0.0F;
+ result[2] = (a[2] <= b[2]) ? 1.0F : 0.0F;
+ result[3] = (a[3] <= b[3]) ? 1.0F : 0.0F;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("SLE (%g %g %g %g) = (%g %g %g %g) <= (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_SLT: /* set on less */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = (a[0] < b[0]) ? 1.0F : 0.0F;
+ result[1] = (a[1] < b[1]) ? 1.0F : 0.0F;
+ result[2] = (a[2] < b[2]) ? 1.0F : 0.0F;
+ result[3] = (a[3] < b[3]) ? 1.0F : 0.0F;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("SLT (%g %g %g %g) = (%g %g %g %g) < (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_SNE: /* set on not equal */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = (a[0] != b[0]) ? 1.0F : 0.0F;
+ result[1] = (a[1] != b[1]) ? 1.0F : 0.0F;
+ result[2] = (a[2] != b[2]) ? 1.0F : 0.0F;
+ result[3] = (a[3] != b[3]) ? 1.0F : 0.0F;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("SNE (%g %g %g %g) = (%g %g %g %g) != (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3],
+ b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_SSG: /* set sign (-1, 0 or +1) */
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] = (GLfloat) ((a[0] > 0.0F) - (a[0] < 0.0F));
+ result[1] = (GLfloat) ((a[1] > 0.0F) - (a[1] < 0.0F));
+ result[2] = (GLfloat) ((a[2] > 0.0F) - (a[2] < 0.0F));
+ result[3] = (GLfloat) ((a[3] > 0.0F) - (a[3] < 0.0F));
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_STR: /* set true, operands ignored */
+ {
+ static const GLfloat result[4] = { 1.0F, 1.0F, 1.0F, 1.0F };
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_SUB:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = a[0] - b[0];
+ result[1] = a[1] - b[1];
+ result[2] = a[2] - b[2];
+ result[3] = a[3] - b[3];
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("SUB (%g %g %g %g) = (%g %g %g %g) - (%g %g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
+ }
+ }
+ break;
+ case OPCODE_SWZ: /* extended swizzle */
+ {
+ const struct prog_src_register *source = &inst->SrcReg[0];
+ const GLfloat *src = get_src_register_pointer(source, machine);
+ GLfloat result[4];
+ GLuint i;
+ for (i = 0; i < 4; i++) {
+ const GLuint swz = GET_SWZ(source->Swizzle, i);
+ if (swz == SWIZZLE_ZERO)
+ result[i] = 0.0;
+ else if (swz == SWIZZLE_ONE)
+ result[i] = 1.0;
+ else {
+ ASSERT(swz >= 0);
+ ASSERT(swz <= 3);
+ result[i] = src[swz];
+ }
+ if (source->Negate & (1 << i))
+ result[i] = -result[i];
+ }
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_TEX: /* Both ARB and NV frag prog */
+ /* Simple texel lookup */
+ {
+ GLfloat texcoord[4], color[4];
+ fetch_vector4(&inst->SrcReg[0], machine, texcoord);
+
+ fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
+
+ if (DEBUG_PROG) {
+ printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g]\n",
+ color[0], color[1], color[2], color[3],
+ inst->TexSrcUnit,
+ texcoord[0], texcoord[1], texcoord[2], texcoord[3]);
+ }
+ store_vector4(inst, machine, color);
+ }
+ break;
+ case OPCODE_TXB: /* GL_ARB_fragment_program only */
+ /* Texel lookup with LOD bias */
+ {
+ GLfloat texcoord[4], color[4], lodBias;
+
+ fetch_vector4(&inst->SrcReg[0], machine, texcoord);
+
+ /* texcoord[3] is the bias to add to lambda */
+ lodBias = texcoord[3];
+
+ fetch_texel(ctx, machine, inst, texcoord, lodBias, color);
+
+ if (DEBUG_PROG) {
+ printf("TXB (%g, %g, %g, %g) = texture[%d][%g %g %g %g]"
+ " bias %g\n",
+ color[0], color[1], color[2], color[3],
+ inst->TexSrcUnit,
+ texcoord[0],
+ texcoord[1],
+ texcoord[2],
+ texcoord[3],
+ lodBias);
+ }
+
+ store_vector4(inst, machine, color);
+ }
+ break;
+ case OPCODE_TXD: /* GL_NV_fragment_program only */
+ /* Texture lookup w/ partial derivatives for LOD */
+ {
+ GLfloat texcoord[4], dtdx[4], dtdy[4], color[4];
+ fetch_vector4(&inst->SrcReg[0], machine, texcoord);
+ fetch_vector4(&inst->SrcReg[1], machine, dtdx);
+ fetch_vector4(&inst->SrcReg[2], machine, dtdy);
+ machine->FetchTexelDeriv(ctx, texcoord, dtdx, dtdy,
+ 0.0, /* lodBias */
+ inst->TexSrcUnit, color);
+ store_vector4(inst, machine, color);
+ }
+ break;
+ case OPCODE_TXL:
+ /* Texel lookup with explicit LOD */
+ {
+ GLfloat texcoord[4], color[4], lod;
+
+ fetch_vector4(&inst->SrcReg[0], machine, texcoord);
+
+ /* texcoord[3] is the LOD */
+ lod = texcoord[3];
+
+ machine->FetchTexelLod(ctx, texcoord, lod,
+ machine->Samplers[inst->TexSrcUnit], color);
+
+ store_vector4(inst, machine, color);
+ }
+ break;
+ case OPCODE_TXP: /* GL_ARB_fragment_program only */
+ /* Texture lookup w/ projective divide */
+ {
+ GLfloat texcoord[4], color[4];
+
+ fetch_vector4(&inst->SrcReg[0], machine, texcoord);
+ /* Not so sure about this test - if texcoord[3] is
+ * zero, we'd probably be fine except for an ASSERT in
+ * IROUND_POS() which gets triggered by the inf values created.
+ */
+ if (texcoord[3] != 0.0) {
+ texcoord[0] /= texcoord[3];
+ texcoord[1] /= texcoord[3];
+ texcoord[2] /= texcoord[3];
+ }
+
+ fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
+
+ store_vector4(inst, machine, color);
+ }
+ break;
+ case OPCODE_TXP_NV: /* GL_NV_fragment_program only */
+ /* Texture lookup w/ projective divide, as above, but do not
+ * do the divide by w if sampling from a cube map.
+ */
+ {
+ GLfloat texcoord[4], color[4];
+
+ fetch_vector4(&inst->SrcReg[0], machine, texcoord);
+ if (inst->TexSrcTarget != TEXTURE_CUBE_INDEX &&
+ texcoord[3] != 0.0) {
+ texcoord[0] /= texcoord[3];
+ texcoord[1] /= texcoord[3];
+ texcoord[2] /= texcoord[3];
+ }
+
+ fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
+
+ store_vector4(inst, machine, color);
+ }
+ break;
+ case OPCODE_TRUNC: /* truncate toward zero */
+ {
+ GLfloat a[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ result[0] = (GLfloat) (GLint) a[0];
+ result[1] = (GLfloat) (GLint) a[1];
+ result[2] = (GLfloat) (GLint) a[2];
+ result[3] = (GLfloat) (GLint) a[3];
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_UP2H: /* unpack two 16-bit floats */
+ {
+ const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
+ GLfloat result[4];
+ GLushort hx, hy;
+ hx = raw & 0xffff;
+ hy = raw >> 16;
+ result[0] = result[2] = _mesa_half_to_float(hx);
+ result[1] = result[3] = _mesa_half_to_float(hy);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_UP2US: /* unpack two GLushorts */
+ {
+ const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
+ GLfloat result[4];
+ GLushort usx, usy;
+ usx = raw & 0xffff;
+ usy = raw >> 16;
+ result[0] = result[2] = usx * (1.0f / 65535.0f);
+ result[1] = result[3] = usy * (1.0f / 65535.0f);
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_UP4B: /* unpack four GLbytes */
+ {
+ const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
+ GLfloat result[4];
+ result[0] = (((raw >> 0) & 0xff) - 128) / 127.0F;
+ result[1] = (((raw >> 8) & 0xff) - 128) / 127.0F;
+ result[2] = (((raw >> 16) & 0xff) - 128) / 127.0F;
+ result[3] = (((raw >> 24) & 0xff) - 128) / 127.0F;
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_UP4UB: /* unpack four GLubytes */
+ {
+ const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
+ GLfloat result[4];
+ result[0] = ((raw >> 0) & 0xff) / 255.0F;
+ result[1] = ((raw >> 8) & 0xff) / 255.0F;
+ result[2] = ((raw >> 16) & 0xff) / 255.0F;
+ result[3] = ((raw >> 24) & 0xff) / 255.0F;
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_XOR: /* bitwise XOR */
+ {
+ GLuint a[4], b[4], result[4];
+ fetch_vector4ui(&inst->SrcReg[0], machine, a);
+ fetch_vector4ui(&inst->SrcReg[1], machine, b);
+ result[0] = a[0] ^ b[0];
+ result[1] = a[1] ^ b[1];
+ result[2] = a[2] ^ b[2];
+ result[3] = a[3] ^ b[3];
+ store_vector4ui(inst, machine, result);
+ }
+ break;
+ case OPCODE_XPD: /* cross product */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ result[0] = a[1] * b[2] - a[2] * b[1];
+ result[1] = a[2] * b[0] - a[0] * b[2];
+ result[2] = a[0] * b[1] - a[1] * b[0];
+ result[3] = 1.0;
+ store_vector4(inst, machine, result);
+ if (DEBUG_PROG) {
+ printf("XPD (%g %g %g %g) = (%g %g %g) X (%g %g %g)\n",
+ result[0], result[1], result[2], result[3],
+ a[0], a[1], a[2], b[0], b[1], b[2]);
+ }
+ }
+ break;
+ case OPCODE_X2D: /* 2-D matrix transform */
+ {
+ GLfloat a[4], b[4], c[4], result[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ fetch_vector4(&inst->SrcReg[1], machine, b);
+ fetch_vector4(&inst->SrcReg[2], machine, c);
+ result[0] = a[0] + b[0] * c[0] + b[1] * c[1];
+ result[1] = a[1] + b[0] * c[2] + b[1] * c[3];
+ result[2] = a[2] + b[0] * c[0] + b[1] * c[1];
+ result[3] = a[3] + b[0] * c[2] + b[1] * c[3];
+ store_vector4(inst, machine, result);
+ }
+ break;
+ case OPCODE_PRINT:
+ {
+ if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+ GLfloat a[4];
+ fetch_vector4(&inst->SrcReg[0], machine, a);
+ printf("%s%g, %g, %g, %g\n", (const char *) inst->Data,
+ a[0], a[1], a[2], a[3]);
+ }
+ else {
+ printf("%s\n", (const char *) inst->Data);
+ }
+ }
+ break;
+ case OPCODE_END:
+ return GL_TRUE;
+ default:
+ _mesa_problem(ctx, "Bad opcode %d in _mesa_execute_program",
+ inst->Opcode);
+ return GL_TRUE; /* return value doesn't matter */
+ }
+
+ numExec++;
+ if (numExec > maxExec) {
+ static GLboolean reported = GL_FALSE;
+ if (!reported) {
+ _mesa_problem(ctx, "Infinite loop detected in fragment program");
+ reported = GL_TRUE;
+ }
+ return GL_TRUE;
+ }
+
+ } /* for pc */
+
+ return GL_TRUE;
+}
diff --git a/mesalib/src/mesa/program/prog_execute.h b/mesalib/src/mesa/program/prog_execute.h
index f59b65176..ac71c0da3 100644
--- a/mesalib/src/mesa/program/prog_execute.h
+++ b/mesalib/src/mesa/program/prog_execute.h
@@ -1,86 +1,86 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.0.3
- *
- * Copyright (C) 1999-2007 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 PROG_EXECUTE_H
-#define PROG_EXECUTE_H
-
-#include "main/config.h"
-#include "main/mtypes.h"
-
-
-typedef void (*FetchTexelLodFunc)(GLcontext *ctx, const GLfloat texcoord[4],
- GLfloat lambda, GLuint unit, GLfloat color[4]);
-
-typedef void (*FetchTexelDerivFunc)(GLcontext *ctx, const GLfloat texcoord[4],
- const GLfloat texdx[4],
- const GLfloat texdy[4],
- GLfloat lodBias,
- GLuint unit, GLfloat color[4]);
-
-
-/**
- * Virtual machine state used during execution of vertex/fragment programs.
- */
-struct gl_program_machine
-{
- const struct gl_program *CurProgram;
-
- /** Fragment Input attributes */
- GLfloat (*Attribs)[MAX_WIDTH][4];
- GLfloat (*DerivX)[4];
- GLfloat (*DerivY)[4];
- GLuint NumDeriv; /**< Max index into DerivX/Y arrays */
- GLuint CurElement; /**< Index into Attribs arrays */
-
- /** Vertex Input attribs */
- GLfloat VertAttribs[VERT_ATTRIB_MAX][4];
-
- GLfloat Temporaries[MAX_PROGRAM_TEMPS][4];
- GLfloat Outputs[MAX_PROGRAM_OUTPUTS][4];
- GLfloat (*EnvParams)[4]; /**< Vertex or Fragment env parameters */
- GLuint CondCodes[4]; /**< COND_* value for x/y/z/w */
- GLint AddressReg[MAX_PROGRAM_ADDRESS_REGS][4];
-
- const GLubyte *Samplers; /** Array mapping sampler var to tex unit */
-
- GLuint CallStack[MAX_PROGRAM_CALL_DEPTH]; /**< For CAL/RET instructions */
- GLuint StackDepth; /**< Index/ptr to top of CallStack[] */
-
- /** Texture fetch functions */
- FetchTexelLodFunc FetchTexelLod;
- FetchTexelDerivFunc FetchTexelDeriv;
-};
-
-
-extern void
-_mesa_get_program_register(GLcontext *ctx, gl_register_file file,
- GLuint index, GLfloat val[4]);
-
-extern GLboolean
-_mesa_execute_program(GLcontext *ctx,
- const struct gl_program *program,
- struct gl_program_machine *machine);
-
-
-#endif /* PROG_EXECUTE_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.0.3
+ *
+ * Copyright (C) 1999-2007 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 PROG_EXECUTE_H
+#define PROG_EXECUTE_H
+
+#include "main/config.h"
+#include "main/mtypes.h"
+
+
+typedef void (*FetchTexelLodFunc)(struct gl_context *ctx, const GLfloat texcoord[4],
+ GLfloat lambda, GLuint unit, GLfloat color[4]);
+
+typedef void (*FetchTexelDerivFunc)(struct gl_context *ctx, const GLfloat texcoord[4],
+ const GLfloat texdx[4],
+ const GLfloat texdy[4],
+ GLfloat lodBias,
+ GLuint unit, GLfloat color[4]);
+
+
+/**
+ * Virtual machine state used during execution of vertex/fragment programs.
+ */
+struct gl_program_machine
+{
+ const struct gl_program *CurProgram;
+
+ /** Fragment Input attributes */
+ GLfloat (*Attribs)[MAX_WIDTH][4];
+ GLfloat (*DerivX)[4];
+ GLfloat (*DerivY)[4];
+ GLuint NumDeriv; /**< Max index into DerivX/Y arrays */
+ GLuint CurElement; /**< Index into Attribs arrays */
+
+ /** Vertex Input attribs */
+ GLfloat VertAttribs[VERT_ATTRIB_MAX][4];
+
+ GLfloat Temporaries[MAX_PROGRAM_TEMPS][4];
+ GLfloat Outputs[MAX_PROGRAM_OUTPUTS][4];
+ GLfloat (*EnvParams)[4]; /**< Vertex or Fragment env parameters */
+ GLuint CondCodes[4]; /**< COND_* value for x/y/z/w */
+ GLint AddressReg[MAX_PROGRAM_ADDRESS_REGS][4];
+
+ const GLubyte *Samplers; /** Array mapping sampler var to tex unit */
+
+ GLuint CallStack[MAX_PROGRAM_CALL_DEPTH]; /**< For CAL/RET instructions */
+ GLuint StackDepth; /**< Index/ptr to top of CallStack[] */
+
+ /** Texture fetch functions */
+ FetchTexelLodFunc FetchTexelLod;
+ FetchTexelDerivFunc FetchTexelDeriv;
+};
+
+
+extern void
+_mesa_get_program_register(struct gl_context *ctx, gl_register_file file,
+ GLuint index, GLfloat val[4]);
+
+extern GLboolean
+_mesa_execute_program(struct gl_context *ctx,
+ const struct gl_program *program,
+ struct gl_program_machine *machine);
+
+
+#endif /* PROG_EXECUTE_H */
diff --git a/mesalib/src/mesa/program/prog_instruction.h b/mesalib/src/mesa/program/prog_instruction.h
index ca90de7ce..0a88e0d70 100644
--- a/mesalib/src/mesa/program/prog_instruction.h
+++ b/mesalib/src/mesa/program/prog_instruction.h
@@ -1,454 +1,454 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2008 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
- *
- * Vertex/fragment program instruction datatypes and constants.
- *
- * \author Brian Paul
- * \author Keith Whitwell
- * \author Ian Romanick <idr@us.ibm.com>
- */
-
-
-#ifndef PROG_INSTRUCTION_H
-#define PROG_INSTRUCTION_H
-
-
-#include "main/glheader.h"
-
-
-/**
- * Swizzle indexes.
- * Do not change!
- */
-/*@{*/
-#define SWIZZLE_X 0
-#define SWIZZLE_Y 1
-#define SWIZZLE_Z 2
-#define SWIZZLE_W 3
-#define SWIZZLE_ZERO 4 /**< For SWZ instruction only */
-#define SWIZZLE_ONE 5 /**< For SWZ instruction only */
-#define SWIZZLE_NIL 7 /**< used during shader code gen (undefined value) */
-/*@}*/
-
-#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 SWIZZLE_XYZW MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W)
-#define SWIZZLE_XXXX MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X)
-#define SWIZZLE_YYYY MAKE_SWIZZLE4(SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y)
-#define SWIZZLE_ZZZZ MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z)
-#define SWIZZLE_WWWW MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W)
-
-
-/**
- * Writemask values, 1 bit per component.
- */
-/*@{*/
-#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
-/*@}*/
-
-
-/**
- * Condition codes
- */
-/*@{*/
-#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 than or equal to zero */
-#define COND_LE 6 /**< less than 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
-/*@}*/
-
-
-/**
- * Per-component negation masks
- */
-/*@{*/
-#define NEGATE_X 0x1
-#define NEGATE_Y 0x2
-#define NEGATE_Z 0x4
-#define NEGATE_W 0x8
-#define NEGATE_XYZ 0x7
-#define NEGATE_XYZW 0xf
-#define NEGATE_NONE 0x0
-/*@}*/
-
-
-/**
- * Program instruction opcodes for vertex, fragment and geometry programs.
- */
-typedef enum prog_opcode {
- /* ARB_vp ARB_fp NV_vp NV_fp GLSL */
- /*------------------------------------------*/
- OPCODE_NOP = 0, /* X */
- OPCODE_ABS, /* X X 1.1 X */
- OPCODE_ADD, /* X X X X X */
- OPCODE_AND, /* */
- OPCODE_ARA, /* 2 */
- OPCODE_ARL, /* X X X */
- OPCODE_ARL_NV, /* 2 */
- OPCODE_ARR, /* 2 */
- OPCODE_BGNLOOP, /* opt */
- OPCODE_BGNSUB, /* opt */
- OPCODE_BRA, /* 2 X */
- OPCODE_BRK, /* 2 opt */
- OPCODE_CAL, /* 2 2 X */
- OPCODE_CMP, /* X X */
- OPCODE_CONT, /* opt */
- OPCODE_COS, /* X 2 X X */
- OPCODE_DDX, /* X X */
- OPCODE_DDY, /* X X */
- OPCODE_DP2, /* 2 X */
- OPCODE_DP2A, /* 2 */
- OPCODE_DP3, /* X X X X X */
- OPCODE_DP4, /* X X X X X */
- OPCODE_DPH, /* X X 1.1 */
- OPCODE_DST, /* X X X X */
- OPCODE_ELSE, /* X */
- OPCODE_EMIT_VERTEX,/* X */
- OPCODE_END, /* X X X X opt */
- OPCODE_END_PRIMITIVE,/* X */
- OPCODE_ENDIF, /* opt */
- OPCODE_ENDLOOP, /* opt */
- OPCODE_ENDSUB, /* opt */
- OPCODE_EX2, /* X X 2 X X */
- OPCODE_EXP, /* X X X */
- OPCODE_FLR, /* X X 2 X X */
- OPCODE_FRC, /* X X 2 X X */
- OPCODE_IF, /* opt */
- OPCODE_KIL, /* X */
- OPCODE_KIL_NV, /* X X */
- OPCODE_LG2, /* X X 2 X X */
- OPCODE_LIT, /* X X X X */
- OPCODE_LOG, /* X X X */
- OPCODE_LRP, /* X X X */
- OPCODE_MAD, /* X X X X X */
- OPCODE_MAX, /* X X X X X */
- OPCODE_MIN, /* X X X X X */
- OPCODE_MOV, /* X X X X X */
- OPCODE_MUL, /* X X X X X */
- OPCODE_NOISE1, /* X */
- OPCODE_NOISE2, /* X */
- OPCODE_NOISE3, /* X */
- OPCODE_NOISE4, /* X */
- OPCODE_NOT, /* */
- OPCODE_NRM3, /* X */
- OPCODE_NRM4, /* X */
- OPCODE_OR, /* */
- OPCODE_PK2H, /* X */
- OPCODE_PK2US, /* X */
- OPCODE_PK4B, /* X */
- OPCODE_PK4UB, /* X */
- OPCODE_POW, /* X X X X */
- OPCODE_POPA, /* 3 */
- OPCODE_PRINT, /* X X */
- OPCODE_PUSHA, /* 3 */
- OPCODE_RCC, /* 1.1 */
- OPCODE_RCP, /* X X X X X */
- OPCODE_RET, /* 2 2 X */
- OPCODE_RFL, /* X X */
- OPCODE_RSQ, /* X X X X X */
- OPCODE_SCS, /* X */
- OPCODE_SEQ, /* 2 X X */
- OPCODE_SFL, /* 2 X */
- OPCODE_SGE, /* X X X X X */
- OPCODE_SGT, /* 2 X X */
- OPCODE_SIN, /* X 2 X X */
- OPCODE_SLE, /* 2 X X */
- OPCODE_SLT, /* X X X X X */
- OPCODE_SNE, /* 2 X X */
- OPCODE_SSG, /* 2 */
- OPCODE_STR, /* 2 X */
- OPCODE_SUB, /* X X 1.1 X X */
- OPCODE_SWZ, /* X X */
- OPCODE_TEX, /* X 3 X X */
- OPCODE_TXB, /* X 3 X */
- OPCODE_TXD, /* X X */
- OPCODE_TXL, /* 3 2 X */
- OPCODE_TXP, /* X X */
- OPCODE_TXP_NV, /* 3 X */
- OPCODE_TRUNC, /* X */
- OPCODE_UP2H, /* X */
- OPCODE_UP2US, /* X */
- OPCODE_UP4B, /* X */
- OPCODE_UP4UB, /* X */
- OPCODE_X2D, /* X */
- OPCODE_XOR, /* */
- OPCODE_XPD, /* X X X */
- MAX_OPCODE
-} gl_inst_opcode;
-
-
-/**
- * Number of bits for the src/dst register Index field.
- * This limits the size of temp/uniform register files.
- */
-#define INST_INDEX_BITS 10
-
-
-/**
- * Instruction source register.
- */
-struct prog_src_register
-{
- GLuint File:4; /**< One of the PROGRAM_* register file values. */
- GLint Index:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit.
- * May be negative for relative addressing.
- */
- GLuint Swizzle:12;
- GLuint RelAddr:1;
-
- /** Take the component-wise absolute value */
- GLuint Abs:1;
-
- /**
- * Post-Abs negation.
- * This will either be NEGATE_NONE or NEGATE_XYZW, except for the SWZ
- * instruction which allows per-component negation.
- */
- GLuint Negate:4;
-
- /**
- * Is the register two-dimensional.
- * Two dimensional registers are of the
- * REGISTER[index][index2] format.
- * They are used by the geometry shaders where
- * the first index is the index within an array
- * and the second index is the semantic of the
- * array, e.g. gl_PositionIn[index] would become
- * INPUT[index][gl_PositionIn]
- */
- GLuint HasIndex2:1;
- GLuint RelAddr2:1;
- GLint Index2:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit.
- * May be negative for relative
- * addressing. */
-};
-
-
-/**
- * Instruction destination register.
- */
-struct prog_dst_register
-{
- GLuint File:4; /**< One of the PROGRAM_* register file values */
- GLuint Index:INST_INDEX_BITS; /**< Unsigned, never negative */
- GLuint WriteMask:4;
- GLuint RelAddr:1;
-
- /**
- * \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). Dest reg is only written to 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;
- /*@}*/
-};
-
-
-/**
- * Vertex/fragment program instruction.
- */
-struct prog_instruction
-{
- gl_inst_opcode Opcode;
- 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::CondUpdate 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: FLOAT32, FLOAT16, FIXED12.
- *
- * \since
- * NV_fragment_program, NV_fragment_program_option.
- */
- GLuint Precision:3;
-
- /**
- * \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions.
- */
- /*@{*/
- /** Source texture unit. */
- GLuint TexSrcUnit:5;
-
- /** Source texture target, one of TEXTURE_{1D,2D,3D,CUBE,RECT}_INDEX */
- GLuint TexSrcTarget:3;
-
- /** True if tex instruction should do shadow comparison */
- GLuint TexShadow:1;
- /*@}*/
-
- /**
- * For BRA and CAL instructions, the location to jump to.
- * For BGNLOOP, points to ENDLOOP (and vice-versa).
- * For BRK, points to ENDLOOP
- * For IF, points to ELSE or ENDIF.
- * For ELSE, points to ENDIF.
- */
- GLint BranchTarget;
-
- /** for debugging purposes */
- const char *Comment;
-
- /** Arbitrary data. Used for OPCODE_PRINT and some drivers */
- void *Data;
-
- /** for driver use (try to remove someday) */
- GLint Aux;
-};
-
-
-extern void
-_mesa_init_instructions(struct prog_instruction *inst, GLuint count);
-
-extern struct prog_instruction *
-_mesa_alloc_instructions(GLuint numInst);
-
-extern struct prog_instruction *
-_mesa_realloc_instructions(struct prog_instruction *oldInst,
- GLuint numOldInst, GLuint numNewInst);
-
-extern struct prog_instruction *
-_mesa_copy_instructions(struct prog_instruction *dest,
- const struct prog_instruction *src, GLuint n);
-
-extern void
-_mesa_free_instructions(struct prog_instruction *inst, GLuint count);
-
-extern GLuint
-_mesa_num_inst_src_regs(gl_inst_opcode opcode);
-
-extern GLuint
-_mesa_num_inst_dst_regs(gl_inst_opcode opcode);
-
-extern GLboolean
-_mesa_is_tex_instruction(gl_inst_opcode opcode);
-
-extern GLboolean
-_mesa_check_soa_dependencies(const struct prog_instruction *inst);
-
-extern const char *
-_mesa_opcode_string(gl_inst_opcode opcode);
-
-
-#endif /* PROG_INSTRUCTION_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.3
+ *
+ * Copyright (C) 1999-2008 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
+ *
+ * Vertex/fragment program instruction datatypes and constants.
+ *
+ * \author Brian Paul
+ * \author Keith Whitwell
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+
+#ifndef PROG_INSTRUCTION_H
+#define PROG_INSTRUCTION_H
+
+
+#include "main/glheader.h"
+
+
+/**
+ * Swizzle indexes.
+ * Do not change!
+ */
+/*@{*/
+#define SWIZZLE_X 0
+#define SWIZZLE_Y 1
+#define SWIZZLE_Z 2
+#define SWIZZLE_W 3
+#define SWIZZLE_ZERO 4 /**< For SWZ instruction only */
+#define SWIZZLE_ONE 5 /**< For SWZ instruction only */
+#define SWIZZLE_NIL 7 /**< used during shader code gen (undefined value) */
+/*@}*/
+
+#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 SWIZZLE_XYZW MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W)
+#define SWIZZLE_XXXX MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X)
+#define SWIZZLE_YYYY MAKE_SWIZZLE4(SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y)
+#define SWIZZLE_ZZZZ MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z)
+#define SWIZZLE_WWWW MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W)
+
+
+/**
+ * Writemask values, 1 bit per component.
+ */
+/*@{*/
+#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
+/*@}*/
+
+
+/**
+ * Condition codes
+ */
+/*@{*/
+#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 than or equal to zero */
+#define COND_LE 6 /**< less than 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
+/*@}*/
+
+
+/**
+ * Per-component negation masks
+ */
+/*@{*/
+#define NEGATE_X 0x1
+#define NEGATE_Y 0x2
+#define NEGATE_Z 0x4
+#define NEGATE_W 0x8
+#define NEGATE_XYZ 0x7
+#define NEGATE_XYZW 0xf
+#define NEGATE_NONE 0x0
+/*@}*/
+
+
+/**
+ * Program instruction opcodes for vertex, fragment and geometry programs.
+ */
+typedef enum prog_opcode {
+ /* ARB_vp ARB_fp NV_vp NV_fp GLSL */
+ /*------------------------------------------*/
+ OPCODE_NOP = 0, /* X */
+ OPCODE_ABS, /* X X 1.1 X */
+ OPCODE_ADD, /* X X X X X */
+ OPCODE_AND, /* */
+ OPCODE_ARA, /* 2 */
+ OPCODE_ARL, /* X X X */
+ OPCODE_ARL_NV, /* 2 */
+ OPCODE_ARR, /* 2 */
+ OPCODE_BGNLOOP, /* opt */
+ OPCODE_BGNSUB, /* opt */
+ OPCODE_BRA, /* 2 X */
+ OPCODE_BRK, /* 2 opt */
+ OPCODE_CAL, /* 2 2 X */
+ OPCODE_CMP, /* X X */
+ OPCODE_CONT, /* opt */
+ OPCODE_COS, /* X 2 X X */
+ OPCODE_DDX, /* X X */
+ OPCODE_DDY, /* X X */
+ OPCODE_DP2, /* 2 X */
+ OPCODE_DP2A, /* 2 */
+ OPCODE_DP3, /* X X X X X */
+ OPCODE_DP4, /* X X X X X */
+ OPCODE_DPH, /* X X 1.1 */
+ OPCODE_DST, /* X X X X */
+ OPCODE_ELSE, /* X */
+ OPCODE_EMIT_VERTEX,/* X */
+ OPCODE_END, /* X X X X opt */
+ OPCODE_END_PRIMITIVE,/* X */
+ OPCODE_ENDIF, /* opt */
+ OPCODE_ENDLOOP, /* opt */
+ OPCODE_ENDSUB, /* opt */
+ OPCODE_EX2, /* X X 2 X X */
+ OPCODE_EXP, /* X X X */
+ OPCODE_FLR, /* X X 2 X X */
+ OPCODE_FRC, /* X X 2 X X */
+ OPCODE_IF, /* opt */
+ OPCODE_KIL, /* X */
+ OPCODE_KIL_NV, /* X X */
+ OPCODE_LG2, /* X X 2 X X */
+ OPCODE_LIT, /* X X X X */
+ OPCODE_LOG, /* X X X */
+ OPCODE_LRP, /* X X X */
+ OPCODE_MAD, /* X X X X X */
+ OPCODE_MAX, /* X X X X X */
+ OPCODE_MIN, /* X X X X X */
+ OPCODE_MOV, /* X X X X X */
+ OPCODE_MUL, /* X X X X X */
+ OPCODE_NOISE1, /* X */
+ OPCODE_NOISE2, /* X */
+ OPCODE_NOISE3, /* X */
+ OPCODE_NOISE4, /* X */
+ OPCODE_NOT, /* */
+ OPCODE_NRM3, /* X */
+ OPCODE_NRM4, /* X */
+ OPCODE_OR, /* */
+ OPCODE_PK2H, /* X */
+ OPCODE_PK2US, /* X */
+ OPCODE_PK4B, /* X */
+ OPCODE_PK4UB, /* X */
+ OPCODE_POW, /* X X X X */
+ OPCODE_POPA, /* 3 */
+ OPCODE_PRINT, /* X X */
+ OPCODE_PUSHA, /* 3 */
+ OPCODE_RCC, /* 1.1 */
+ OPCODE_RCP, /* X X X X X */
+ OPCODE_RET, /* 2 2 X */
+ OPCODE_RFL, /* X X */
+ OPCODE_RSQ, /* X X X X X */
+ OPCODE_SCS, /* X */
+ OPCODE_SEQ, /* 2 X X */
+ OPCODE_SFL, /* 2 X */
+ OPCODE_SGE, /* X X X X X */
+ OPCODE_SGT, /* 2 X X */
+ OPCODE_SIN, /* X 2 X X */
+ OPCODE_SLE, /* 2 X X */
+ OPCODE_SLT, /* X X X X X */
+ OPCODE_SNE, /* 2 X X */
+ OPCODE_SSG, /* 2 */
+ OPCODE_STR, /* 2 X */
+ OPCODE_SUB, /* X X 1.1 X X */
+ OPCODE_SWZ, /* X X */
+ OPCODE_TEX, /* X 3 X X */
+ OPCODE_TXB, /* X 3 X */
+ OPCODE_TXD, /* X X */
+ OPCODE_TXL, /* 3 2 X */
+ OPCODE_TXP, /* X X */
+ OPCODE_TXP_NV, /* 3 X */
+ OPCODE_TRUNC, /* X */
+ OPCODE_UP2H, /* X */
+ OPCODE_UP2US, /* X */
+ OPCODE_UP4B, /* X */
+ OPCODE_UP4UB, /* X */
+ OPCODE_X2D, /* X */
+ OPCODE_XOR, /* */
+ OPCODE_XPD, /* X X X */
+ MAX_OPCODE
+} gl_inst_opcode;
+
+
+/**
+ * Number of bits for the src/dst register Index field.
+ * This limits the size of temp/uniform register files.
+ */
+#define INST_INDEX_BITS 11
+
+
+/**
+ * Instruction source register.
+ */
+struct prog_src_register
+{
+ GLuint File:4; /**< One of the PROGRAM_* register file values. */
+ GLint Index:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit.
+ * May be negative for relative addressing.
+ */
+ GLuint Swizzle:12;
+ GLuint RelAddr:1;
+
+ /** Take the component-wise absolute value */
+ GLuint Abs:1;
+
+ /**
+ * Post-Abs negation.
+ * This will either be NEGATE_NONE or NEGATE_XYZW, except for the SWZ
+ * instruction which allows per-component negation.
+ */
+ GLuint Negate:4;
+
+ /**
+ * Is the register two-dimensional.
+ * Two dimensional registers are of the
+ * REGISTER[index][index2] format.
+ * They are used by the geometry shaders where
+ * the first index is the index within an array
+ * and the second index is the semantic of the
+ * array, e.g. gl_PositionIn[index] would become
+ * INPUT[index][gl_PositionIn]
+ */
+ GLuint HasIndex2:1;
+ GLuint RelAddr2:1;
+ GLint Index2:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit.
+ * May be negative for relative
+ * addressing. */
+};
+
+
+/**
+ * Instruction destination register.
+ */
+struct prog_dst_register
+{
+ GLuint File:4; /**< One of the PROGRAM_* register file values */
+ GLuint Index:INST_INDEX_BITS; /**< Unsigned, never negative */
+ GLuint WriteMask:4;
+ GLuint RelAddr:1;
+
+ /**
+ * \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). Dest reg is only written to 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;
+ /*@}*/
+};
+
+
+/**
+ * Vertex/fragment program instruction.
+ */
+struct prog_instruction
+{
+ gl_inst_opcode Opcode;
+ 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::CondUpdate 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: FLOAT32, FLOAT16, FIXED12.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option.
+ */
+ GLuint Precision:3;
+
+ /**
+ * \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions.
+ */
+ /*@{*/
+ /** Source texture unit. */
+ GLuint TexSrcUnit:5;
+
+ /** Source texture target, one of TEXTURE_{1D,2D,3D,CUBE,RECT}_INDEX */
+ GLuint TexSrcTarget:3;
+
+ /** True if tex instruction should do shadow comparison */
+ GLuint TexShadow:1;
+ /*@}*/
+
+ /**
+ * For BRA and CAL instructions, the location to jump to.
+ * For BGNLOOP, points to ENDLOOP (and vice-versa).
+ * For BRK, points to ENDLOOP
+ * For IF, points to ELSE or ENDIF.
+ * For ELSE, points to ENDIF.
+ */
+ GLint BranchTarget;
+
+ /** for debugging purposes */
+ const char *Comment;
+
+ /** Arbitrary data. Used for OPCODE_PRINT and some drivers */
+ void *Data;
+
+ /** for driver use (try to remove someday) */
+ GLint Aux;
+};
+
+
+extern void
+_mesa_init_instructions(struct prog_instruction *inst, GLuint count);
+
+extern struct prog_instruction *
+_mesa_alloc_instructions(GLuint numInst);
+
+extern struct prog_instruction *
+_mesa_realloc_instructions(struct prog_instruction *oldInst,
+ GLuint numOldInst, GLuint numNewInst);
+
+extern struct prog_instruction *
+_mesa_copy_instructions(struct prog_instruction *dest,
+ const struct prog_instruction *src, GLuint n);
+
+extern void
+_mesa_free_instructions(struct prog_instruction *inst, GLuint count);
+
+extern GLuint
+_mesa_num_inst_src_regs(gl_inst_opcode opcode);
+
+extern GLuint
+_mesa_num_inst_dst_regs(gl_inst_opcode opcode);
+
+extern GLboolean
+_mesa_is_tex_instruction(gl_inst_opcode opcode);
+
+extern GLboolean
+_mesa_check_soa_dependencies(const struct prog_instruction *inst);
+
+extern const char *
+_mesa_opcode_string(gl_inst_opcode opcode);
+
+
+#endif /* PROG_INSTRUCTION_H */
diff --git a/mesalib/src/mesa/program/prog_optimize.c b/mesalib/src/mesa/program/prog_optimize.c
index 0dc779073..892f5b6ec 100644
--- a/mesalib/src/mesa/program/prog_optimize.c
+++ b/mesalib/src/mesa/program/prog_optimize.c
@@ -1,1250 +1,1250 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.5
- *
- * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, 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
- * VMWARE 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 "main/glheader.h"
-#include "main/context.h"
-#include "main/macros.h"
-#include "program.h"
-#include "prog_instruction.h"
-#include "prog_optimize.h"
-#include "prog_print.h"
-
-
-#define MAX_LOOP_NESTING 50
-/* MAX_PROGRAM_TEMPS is a low number (256), and we want to be able to
- * register allocate many temporary values into that small number of
- * temps. So allow large temporary indices coming into the register
- * allocator.
- */
-#define REG_ALLOCATE_MAX_PROGRAM_TEMPS ((1 << INST_INDEX_BITS) - 1)
-
-static GLboolean dbg = GL_FALSE;
-
-#define NO_MASK 0xf
-
-/**
- * Returns the mask of channels (bitmask of WRITEMASK_X,Y,Z,W) which
- * are read from the given src in this instruction, We also provide
- * one optional masks which may mask other components in the dst
- * register
- */
-static GLuint
-get_src_arg_mask(const struct prog_instruction *inst,
- GLuint arg, GLuint dst_mask)
-{
- GLuint read_mask, channel_mask;
- GLuint comp;
-
- ASSERT(arg < _mesa_num_inst_src_regs(inst->Opcode));
-
- /* Form the dst register, find the written channels */
- if (inst->CondUpdate) {
- channel_mask = WRITEMASK_XYZW;
- }
- else {
- switch (inst->Opcode) {
- case OPCODE_MOV:
- case OPCODE_MIN:
- case OPCODE_MAX:
- case OPCODE_ABS:
- case OPCODE_ADD:
- case OPCODE_MAD:
- case OPCODE_MUL:
- case OPCODE_SUB:
- channel_mask = inst->DstReg.WriteMask & dst_mask;
- break;
- case OPCODE_RCP:
- case OPCODE_SIN:
- case OPCODE_COS:
- case OPCODE_RSQ:
- case OPCODE_POW:
- case OPCODE_EX2:
- case OPCODE_LOG:
- channel_mask = WRITEMASK_X;
- break;
- case OPCODE_DP2:
- channel_mask = WRITEMASK_XY;
- break;
- case OPCODE_DP3:
- case OPCODE_XPD:
- channel_mask = WRITEMASK_XYZ;
- break;
- default:
- channel_mask = WRITEMASK_XYZW;
- break;
- }
- }
-
- /* Now, given the src swizzle and the written channels, find which
- * components are actually read
- */
- read_mask = 0x0;
- for (comp = 0; comp < 4; ++comp) {
- const GLuint coord = GET_SWZ(inst->SrcReg[arg].Swizzle, comp);
- ASSERT(coord < 4);
- if (channel_mask & (1 << comp) && coord <= SWIZZLE_W)
- read_mask |= 1 << coord;
- }
-
- return read_mask;
-}
-
-
-/**
- * For a MOV instruction, compute a write mask when src register also has
- * a mask
- */
-static GLuint
-get_dst_mask_for_mov(const struct prog_instruction *mov, GLuint src_mask)
-{
- const GLuint mask = mov->DstReg.WriteMask;
- GLuint comp;
- GLuint updated_mask = 0x0;
-
- ASSERT(mov->Opcode == OPCODE_MOV);
-
- for (comp = 0; comp < 4; ++comp) {
- GLuint src_comp;
- if ((mask & (1 << comp)) == 0)
- continue;
- src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, comp);
- if ((src_mask & (1 << src_comp)) == 0)
- continue;
- updated_mask |= 1 << comp;
- }
-
- return updated_mask;
-}
-
-
-/**
- * Ensure that the swizzle is regular. That is, all of the swizzle
- * terms are SWIZZLE_X,Y,Z,W and not SWIZZLE_ZERO or SWIZZLE_ONE.
- */
-static GLboolean
-is_swizzle_regular(GLuint swz)
-{
- return GET_SWZ(swz,0) <= SWIZZLE_W &&
- GET_SWZ(swz,1) <= SWIZZLE_W &&
- GET_SWZ(swz,2) <= SWIZZLE_W &&
- GET_SWZ(swz,3) <= SWIZZLE_W;
-}
-
-
-/**
- * In 'prog' remove instruction[i] if removeFlags[i] == TRUE.
- * \return number of instructions removed
- */
-static GLuint
-remove_instructions(struct gl_program *prog, const GLboolean *removeFlags)
-{
- GLint i, removeEnd = 0, removeCount = 0;
- GLuint totalRemoved = 0;
-
- /* go backward */
- for (i = prog->NumInstructions - 1; i >= 0; i--) {
- if (removeFlags[i]) {
- totalRemoved++;
- if (removeCount == 0) {
- /* begin a run of instructions to remove */
- removeEnd = i;
- removeCount = 1;
- }
- else {
- /* extend the run of instructions to remove */
- removeCount++;
- }
- }
- else {
- /* don't remove this instruction, but check if the preceeding
- * instructions are to be removed.
- */
- if (removeCount > 0) {
- GLint removeStart = removeEnd - removeCount + 1;
- _mesa_delete_instructions(prog, removeStart, removeCount);
- removeStart = removeCount = 0; /* reset removal info */
- }
- }
- }
- /* Finish removing if the first instruction was to be removed. */
- if (removeCount > 0) {
- GLint removeStart = removeEnd - removeCount + 1;
- _mesa_delete_instructions(prog, removeStart, removeCount);
- }
- return totalRemoved;
-}
-
-
-/**
- * Remap register indexes according to map.
- * \param prog the program to search/replace
- * \param file the type of register file to search/replace
- * \param map maps old register indexes to new indexes
- */
-static void
-replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[])
-{
- GLuint i;
-
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
- GLuint j;
- for (j = 0; j < numSrc; j++) {
- if (inst->SrcReg[j].File == file) {
- GLuint index = inst->SrcReg[j].Index;
- ASSERT(map[index] >= 0);
- inst->SrcReg[j].Index = map[index];
- }
- }
- if (inst->DstReg.File == file) {
- const GLuint index = inst->DstReg.Index;
- ASSERT(map[index] >= 0);
- inst->DstReg.Index = map[index];
- }
- }
-}
-
-
-/**
- * Remove dead instructions from the given program.
- * This is very primitive for now. Basically look for temp registers
- * that are written to but never read. Remove any instructions that
- * write to such registers. Be careful with condition code setters.
- */
-static GLboolean
-_mesa_remove_dead_code_global(struct gl_program *prog)
-{
- GLboolean tempRead[REG_ALLOCATE_MAX_PROGRAM_TEMPS][4];
- GLboolean *removeInst; /* per-instruction removal flag */
- GLuint i, rem = 0, comp;
-
- memset(tempRead, 0, sizeof(tempRead));
-
- if (dbg) {
- printf("Optimize: Begin dead code removal\n");
- /*_mesa_print_program(prog);*/
- }
-
- removeInst = (GLboolean *)
- calloc(1, prog->NumInstructions * sizeof(GLboolean));
-
- /* Determine which temps are read and written */
- for (i = 0; i < prog->NumInstructions; i++) {
- const struct prog_instruction *inst = prog->Instructions + i;
- const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
- GLuint j;
-
- /* check src regs */
- for (j = 0; j < numSrc; j++) {
- if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
- const GLuint index = inst->SrcReg[j].Index;
- GLuint read_mask;
- ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
- read_mask = get_src_arg_mask(inst, j, NO_MASK);
-
- if (inst->SrcReg[j].RelAddr) {
- if (dbg)
- printf("abort remove dead code (indirect temp)\n");
- goto done;
- }
-
- for (comp = 0; comp < 4; comp++) {
- const GLuint swz = GET_SWZ(inst->SrcReg[j].Swizzle, comp);
- ASSERT(swz < 4);
- if ((read_mask & (1 << swz)) == 0)
- continue;
- if (swz <= SWIZZLE_W)
- tempRead[index][swz] = GL_TRUE;
- }
- }
- }
-
- /* check dst reg */
- if (inst->DstReg.File == PROGRAM_TEMPORARY) {
- const GLuint index = inst->DstReg.Index;
- ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
-
- if (inst->DstReg.RelAddr) {
- if (dbg)
- printf("abort remove dead code (indirect temp)\n");
- goto done;
- }
-
- if (inst->CondUpdate) {
- /* If we're writing to this register and setting condition
- * codes we cannot remove the instruction. Prevent removal
- * by setting the 'read' flag.
- */
- tempRead[index][0] = GL_TRUE;
- tempRead[index][1] = GL_TRUE;
- tempRead[index][2] = GL_TRUE;
- tempRead[index][3] = GL_TRUE;
- }
- }
- }
-
- /* find instructions that write to dead registers, flag for removal */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode);
-
- if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) {
- GLint chan, index = inst->DstReg.Index;
-
- for (chan = 0; chan < 4; chan++) {
- if (!tempRead[index][chan] &&
- inst->DstReg.WriteMask & (1 << chan)) {
- if (dbg) {
- printf("Remove writemask on %u.%c\n", i,
- chan == 3 ? 'w' : 'x' + chan);
- }
- inst->DstReg.WriteMask &= ~(1 << chan);
- rem++;
- }
- }
-
- if (inst->DstReg.WriteMask == 0) {
- /* If we cleared all writes, the instruction can be removed. */
- if (dbg)
- printf("Remove instruction %u: \n", i);
- removeInst[i] = GL_TRUE;
- }
- }
- }
-
- /* now remove the instructions which aren't needed */
- rem = remove_instructions(prog, removeInst);
-
- if (dbg) {
- printf("Optimize: End dead code removal.\n");
- printf(" %u channel writes removed\n", rem);
- printf(" %u instructions removed\n", rem);
- /*_mesa_print_program(prog);*/
- }
-
-done:
- free(removeInst);
- return rem != 0;
-}
-
-
-enum inst_use
-{
- READ,
- WRITE,
- FLOW,
- END
-};
-
-
-/**
- * Scan forward in program from 'start' for the next occurances of TEMP[index].
- * We look if an instruction reads the component given by the masks and if they
- * are overwritten.
- * Return READ, WRITE, FLOW or END to indicate the next usage or an indicator
- * that we can't look further.
- */
-static enum inst_use
-find_next_use(const struct gl_program *prog,
- GLuint start,
- GLuint index,
- GLuint mask)
-{
- GLuint i;
-
- for (i = start; i < prog->NumInstructions; i++) {
- const struct prog_instruction *inst = prog->Instructions + i;
- switch (inst->Opcode) {
- case OPCODE_BGNLOOP:
- case OPCODE_BGNSUB:
- case OPCODE_BRA:
- case OPCODE_CAL:
- case OPCODE_CONT:
- case OPCODE_IF:
- case OPCODE_ELSE:
- case OPCODE_ENDIF:
- case OPCODE_ENDLOOP:
- case OPCODE_ENDSUB:
- case OPCODE_RET:
- return FLOW;
- case OPCODE_END:
- return END;
- default:
- {
- const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
- GLuint j;
- for (j = 0; j < numSrc; j++) {
- if (inst->SrcReg[j].RelAddr ||
- (inst->SrcReg[j].File == PROGRAM_TEMPORARY &&
- inst->SrcReg[j].Index == index &&
- (get_src_arg_mask(inst,j,NO_MASK) & mask)))
- return READ;
- }
- if (_mesa_num_inst_dst_regs(inst->Opcode) == 1 &&
- inst->DstReg.File == PROGRAM_TEMPORARY &&
- inst->DstReg.Index == index) {
- mask &= ~inst->DstReg.WriteMask;
- if (mask == 0)
- return WRITE;
- }
- }
- }
- }
- return END;
-}
-
-
-/**
- * Is the given instruction opcode a flow-control opcode?
- * XXX maybe move this into prog_instruction.[ch]
- */
-static GLboolean
-_mesa_is_flow_control_opcode(enum prog_opcode opcode)
-{
- switch (opcode) {
- case OPCODE_BGNLOOP:
- case OPCODE_BGNSUB:
- case OPCODE_BRA:
- case OPCODE_CAL:
- case OPCODE_CONT:
- case OPCODE_IF:
- case OPCODE_ELSE:
- case OPCODE_END:
- case OPCODE_ENDIF:
- case OPCODE_ENDLOOP:
- case OPCODE_ENDSUB:
- case OPCODE_RET:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * Test if the given instruction is a simple MOV (no conditional updating,
- * not relative addressing, no negation/abs, etc).
- */
-static GLboolean
-can_downward_mov_be_modifed(const struct prog_instruction *mov)
-{
- return
- mov->Opcode == OPCODE_MOV &&
- mov->CondUpdate == GL_FALSE &&
- mov->SrcReg[0].RelAddr == 0 &&
- mov->SrcReg[0].Negate == 0 &&
- mov->SrcReg[0].Abs == 0 &&
- mov->SrcReg[0].HasIndex2 == 0 &&
- mov->SrcReg[0].RelAddr2 == 0 &&
- mov->DstReg.RelAddr == 0 &&
- mov->DstReg.CondMask == COND_TR &&
- mov->SaturateMode == SATURATE_OFF;
-}
-
-
-static GLboolean
-can_upward_mov_be_modifed(const struct prog_instruction *mov)
-{
- return
- can_downward_mov_be_modifed(mov) &&
- mov->DstReg.File == PROGRAM_TEMPORARY;
-}
-
-
-/**
- * Try to remove use of extraneous MOV instructions, to free them up for dead
- * code removal.
- */
-static void
-_mesa_remove_extra_move_use(struct gl_program *prog)
-{
- GLuint i, j;
-
- if (dbg) {
- printf("Optimize: Begin remove extra move use\n");
- _mesa_print_program(prog);
- }
-
- /*
- * Look for sequences such as this:
- * MOV tmpX, arg0;
- * ...
- * FOO tmpY, tmpX, arg1;
- * and convert into:
- * MOV tmpX, arg0;
- * ...
- * FOO tmpY, arg0, arg1;
- */
-
- for (i = 0; i + 1 < prog->NumInstructions; i++) {
- const struct prog_instruction *mov = prog->Instructions + i;
- GLuint dst_mask, src_mask;
- if (can_upward_mov_be_modifed(mov) == GL_FALSE)
- continue;
-
- /* Scanning the code, we maintain the components which are still active in
- * these two masks
- */
- dst_mask = mov->DstReg.WriteMask;
- src_mask = get_src_arg_mask(mov, 0, NO_MASK);
-
- /* Walk through remaining instructions until the or src reg gets
- * rewritten or we get into some flow-control, eliminating the use of
- * this MOV.
- */
- for (j = i + 1; j < prog->NumInstructions; j++) {
- struct prog_instruction *inst2 = prog->Instructions + j;
- GLuint arg;
-
- if (_mesa_is_flow_control_opcode(inst2->Opcode))
- break;
-
- /* First rewrite this instruction's args if appropriate. */
- for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
- GLuint comp, read_mask;
-
- if (inst2->SrcReg[arg].File != mov->DstReg.File ||
- inst2->SrcReg[arg].Index != mov->DstReg.Index ||
- inst2->SrcReg[arg].RelAddr ||
- inst2->SrcReg[arg].Abs)
- continue;
- read_mask = get_src_arg_mask(inst2, arg, NO_MASK);
-
- /* Adjust the swizzles of inst2 to point at MOV's source if ALL the
- * components read still come from the mov instructions
- */
- if (is_swizzle_regular(inst2->SrcReg[arg].Swizzle) &&
- (read_mask & dst_mask) == read_mask) {
- for (comp = 0; comp < 4; comp++) {
- const GLuint inst2_swz =
- GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
- const GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
- inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
- inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
- inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
- inst2_swz) & 0x1) << comp);
- }
- inst2->SrcReg[arg].File = mov->SrcReg[0].File;
- inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
- }
- }
-
- /* The source of MOV is written. This potentially deactivates some
- * components from the src and dst of the MOV instruction
- */
- if (inst2->DstReg.File == mov->DstReg.File &&
- (inst2->DstReg.RelAddr ||
- inst2->DstReg.Index == mov->DstReg.Index)) {
- dst_mask &= ~inst2->DstReg.WriteMask;
- src_mask = get_src_arg_mask(mov, 0, dst_mask);
- }
-
- /* Idem when the destination of mov is written */
- if (inst2->DstReg.File == mov->SrcReg[0].File &&
- (inst2->DstReg.RelAddr ||
- inst2->DstReg.Index == mov->SrcReg[0].Index)) {
- src_mask &= ~inst2->DstReg.WriteMask;
- dst_mask &= get_dst_mask_for_mov(mov, src_mask);
- }
- if (dst_mask == 0)
- break;
- }
- }
-
- if (dbg) {
- printf("Optimize: End remove extra move use.\n");
- /*_mesa_print_program(prog);*/
- }
-}
-
-
-/**
- * Complements dead_code_global. Try to remove code in block of code by
- * carefully monitoring the swizzles. Both functions should be merged into one
- * with a proper control flow graph
- */
-static GLboolean
-_mesa_remove_dead_code_local(struct gl_program *prog)
-{
- GLboolean *removeInst;
- GLuint i, arg, rem = 0;
-
- removeInst = (GLboolean *)
- calloc(1, prog->NumInstructions * sizeof(GLboolean));
-
- for (i = 0; i < prog->NumInstructions; i++) {
- const struct prog_instruction *inst = prog->Instructions + i;
- const GLuint index = inst->DstReg.Index;
- const GLuint mask = inst->DstReg.WriteMask;
- enum inst_use use;
-
- /* We must deactivate the pass as soon as some indirection is used */
- if (inst->DstReg.RelAddr)
- goto done;
- for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++)
- if (inst->SrcReg[arg].RelAddr)
- goto done;
-
- if (_mesa_is_flow_control_opcode(inst->Opcode) ||
- _mesa_num_inst_dst_regs(inst->Opcode) == 0 ||
- inst->DstReg.File != PROGRAM_TEMPORARY ||
- inst->DstReg.RelAddr)
- continue;
-
- use = find_next_use(prog, i+1, index, mask);
- if (use == WRITE || use == END)
- removeInst[i] = GL_TRUE;
- }
-
- rem = remove_instructions(prog, removeInst);
-
-done:
- free(removeInst);
- return rem != 0;
-}
-
-
-/**
- * Try to inject the destination of mov as the destination of inst and recompute
- * the swizzles operators for the sources of inst if required. Return GL_TRUE
- * of the substitution was possible, GL_FALSE otherwise
- */
-static GLboolean
-_mesa_merge_mov_into_inst(struct prog_instruction *inst,
- const struct prog_instruction *mov)
-{
- /* Indirection table which associates destination and source components for
- * the mov instruction
- */
- const GLuint mask = get_src_arg_mask(mov, 0, NO_MASK);
-
- /* Some components are not written by inst. We cannot remove the mov */
- if (mask != (inst->DstReg.WriteMask & mask))
- return GL_FALSE;
-
- /* Depending on the instruction, we may need to recompute the swizzles.
- * Also, some other instructions (like TEX) are not linear. We will only
- * consider completely active sources and destinations
- */
- switch (inst->Opcode) {
-
- /* Carstesian instructions: we compute the swizzle */
- case OPCODE_MOV:
- case OPCODE_MIN:
- case OPCODE_MAX:
- case OPCODE_ABS:
- case OPCODE_ADD:
- case OPCODE_MAD:
- case OPCODE_MUL:
- case OPCODE_SUB:
- {
- GLuint dst_to_src_comp[4] = {0,0,0,0};
- GLuint dst_comp, arg;
- for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
- if (mov->DstReg.WriteMask & (1 << dst_comp)) {
- const GLuint src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, dst_comp);
- ASSERT(src_comp < 4);
- dst_to_src_comp[dst_comp] = src_comp;
- }
- }
-
- /* Patch each source of the instruction */
- for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++) {
- const GLuint arg_swz = inst->SrcReg[arg].Swizzle;
- inst->SrcReg[arg].Swizzle = 0;
-
- /* Reset each active component of the swizzle */
- for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
- GLuint src_comp, arg_comp;
- if ((mov->DstReg.WriteMask & (1 << dst_comp)) == 0)
- continue;
- src_comp = dst_to_src_comp[dst_comp];
- ASSERT(src_comp < 4);
- arg_comp = GET_SWZ(arg_swz, src_comp);
- ASSERT(arg_comp < 4);
- inst->SrcReg[arg].Swizzle |= arg_comp << (3*dst_comp);
- }
- }
- inst->DstReg = mov->DstReg;
- return GL_TRUE;
- }
-
- /* Dot products and scalar instructions: we only change the destination */
- case OPCODE_RCP:
- case OPCODE_SIN:
- case OPCODE_COS:
- case OPCODE_RSQ:
- case OPCODE_POW:
- case OPCODE_EX2:
- case OPCODE_LOG:
- case OPCODE_DP2:
- case OPCODE_DP3:
- case OPCODE_DP4:
- inst->DstReg = mov->DstReg;
- return GL_TRUE;
-
- /* All other instructions require fully active components with no swizzle */
- default:
- if (mov->SrcReg[0].Swizzle != SWIZZLE_XYZW ||
- inst->DstReg.WriteMask != WRITEMASK_XYZW)
- return GL_FALSE;
- inst->DstReg = mov->DstReg;
- return GL_TRUE;
- }
-}
-
-
-/**
- * Try to remove extraneous MOV instructions from the given program.
- */
-static GLboolean
-_mesa_remove_extra_moves(struct gl_program *prog)
-{
- GLboolean *removeInst; /* per-instruction removal flag */
- GLuint i, rem = 0, nesting = 0;
-
- if (dbg) {
- printf("Optimize: Begin remove extra moves\n");
- _mesa_print_program(prog);
- }
-
- removeInst = (GLboolean *)
- calloc(1, prog->NumInstructions * sizeof(GLboolean));
-
- /*
- * Look for sequences such as this:
- * FOO tmpX, arg0, arg1;
- * MOV tmpY, tmpX;
- * and convert into:
- * FOO tmpY, arg0, arg1;
- */
-
- for (i = 0; i < prog->NumInstructions; i++) {
- const struct prog_instruction *mov = prog->Instructions + i;
-
- switch (mov->Opcode) {
- case OPCODE_BGNLOOP:
- case OPCODE_BGNSUB:
- case OPCODE_IF:
- nesting++;
- break;
- case OPCODE_ENDLOOP:
- case OPCODE_ENDSUB:
- case OPCODE_ENDIF:
- nesting--;
- break;
- case OPCODE_MOV:
- if (i > 0 &&
- can_downward_mov_be_modifed(mov) &&
- mov->SrcReg[0].File == PROGRAM_TEMPORARY &&
- nesting == 0)
- {
-
- /* see if this MOV can be removed */
- const GLuint id = mov->SrcReg[0].Index;
- struct prog_instruction *prevInst;
- GLuint prevI;
-
- /* get pointer to previous instruction */
- prevI = i - 1;
- while (prevI > 0 && removeInst[prevI])
- prevI--;
- prevInst = prog->Instructions + prevI;
-
- if (prevInst->DstReg.File == PROGRAM_TEMPORARY &&
- prevInst->DstReg.Index == id &&
- prevInst->DstReg.RelAddr == 0 &&
- prevInst->DstReg.CondSrc == 0 &&
- prevInst->DstReg.CondMask == COND_TR) {
-
- const GLuint dst_mask = prevInst->DstReg.WriteMask;
- enum inst_use next_use = find_next_use(prog, i+1, id, dst_mask);
-
- if (next_use == WRITE || next_use == END) {
- /* OK, we can safely remove this MOV instruction.
- * Transform:
- * prevI: FOO tempIndex, x, y;
- * i: MOV z, tempIndex;
- * Into:
- * prevI: FOO z, x, y;
- */
- if (_mesa_merge_mov_into_inst(prevInst, mov)) {
- removeInst[i] = GL_TRUE;
- if (dbg) {
- printf("Remove MOV at %u\n", i);
- printf("new prev inst %u: ", prevI);
- _mesa_print_instruction(prevInst);
- }
- }
- }
- }
- }
- break;
- default:
- ; /* nothing */
- }
- }
-
- /* now remove the instructions which aren't needed */
- rem = remove_instructions(prog, removeInst);
-
- free(removeInst);
-
- if (dbg) {
- printf("Optimize: End remove extra moves. %u instructions removed\n", rem);
- /*_mesa_print_program(prog);*/
- }
-
- return rem != 0;
-}
-
-
-/** A live register interval */
-struct interval
-{
- GLuint Reg; /** The temporary register index */
- GLuint Start, End; /** Start/end instruction numbers */
-};
-
-
-/** A list of register intervals */
-struct interval_list
-{
- GLuint Num;
- struct interval Intervals[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
-};
-
-
-static void
-append_interval(struct interval_list *list, const struct interval *inv)
-{
- list->Intervals[list->Num++] = *inv;
-}
-
-
-/** Insert interval inv into list, sorted by interval end */
-static void
-insert_interval_by_end(struct interval_list *list, const struct interval *inv)
-{
- /* XXX we could do a binary search insertion here since list is sorted */
- GLint i = list->Num - 1;
- while (i >= 0 && list->Intervals[i].End > inv->End) {
- list->Intervals[i + 1] = list->Intervals[i];
- i--;
- }
- list->Intervals[i + 1] = *inv;
- list->Num++;
-
-#ifdef DEBUG
- {
- GLuint i;
- for (i = 0; i + 1 < list->Num; i++) {
- ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End);
- }
- }
-#endif
-}
-
-
-/** Remove the given interval from the interval list */
-static void
-remove_interval(struct interval_list *list, const struct interval *inv)
-{
- /* XXX we could binary search since list is sorted */
- GLuint k;
- for (k = 0; k < list->Num; k++) {
- if (list->Intervals[k].Reg == inv->Reg) {
- /* found, remove it */
- ASSERT(list->Intervals[k].Start == inv->Start);
- ASSERT(list->Intervals[k].End == inv->End);
- while (k < list->Num - 1) {
- list->Intervals[k] = list->Intervals[k + 1];
- k++;
- }
- list->Num--;
- return;
- }
- }
-}
-
-
-/** called by qsort() */
-static int
-compare_start(const void *a, const void *b)
-{
- const struct interval *ia = (const struct interval *) a;
- const struct interval *ib = (const struct interval *) b;
- if (ia->Start < ib->Start)
- return -1;
- else if (ia->Start > ib->Start)
- return +1;
- else
- return 0;
-}
-
-
-/** sort the interval list according to interval starts */
-static void
-sort_interval_list_by_start(struct interval_list *list)
-{
- qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start);
-#ifdef DEBUG
- {
- GLuint i;
- for (i = 0; i + 1 < list->Num; i++) {
- ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start);
- }
- }
-#endif
-}
-
-struct loop_info
-{
- GLuint Start, End; /**< Start, end instructions of loop */
-};
-
-/**
- * Update the intermediate interval info for register 'index' and
- * instruction 'ic'.
- */
-static void
-update_interval(GLint intBegin[], GLint intEnd[],
- struct loop_info *loopStack, GLuint loopStackDepth,
- GLuint index, GLuint ic)
-{
- int i;
-
- /* If the register is used in a loop, extend its lifetime through the end
- * of the outermost loop that doesn't contain its definition.
- */
- for (i = 0; i < loopStackDepth; i++) {
- if (intBegin[index] < loopStack[i].Start) {
- ic = loopStack[i].End;
- break;
- }
- }
-
- ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
- if (intBegin[index] == -1) {
- ASSERT(intEnd[index] == -1);
- intBegin[index] = intEnd[index] = ic;
- }
- else {
- intEnd[index] = ic;
- }
-}
-
-
-/**
- * Find first/last instruction that references each temporary register.
- */
-GLboolean
-_mesa_find_temp_intervals(const struct prog_instruction *instructions,
- GLuint numInstructions,
- GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS],
- GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
-{
- struct loop_info loopStack[MAX_LOOP_NESTING];
- GLuint loopStackDepth = 0;
- GLuint i;
-
- for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
- intBegin[i] = intEnd[i] = -1;
- }
-
- /* Scan instructions looking for temporary registers */
- for (i = 0; i < numInstructions; i++) {
- const struct prog_instruction *inst = instructions + i;
- if (inst->Opcode == OPCODE_BGNLOOP) {
- loopStack[loopStackDepth].Start = i;
- loopStack[loopStackDepth].End = inst->BranchTarget;
- loopStackDepth++;
- }
- else if (inst->Opcode == OPCODE_ENDLOOP) {
- loopStackDepth--;
- }
- else if (inst->Opcode == OPCODE_CAL) {
- return GL_FALSE;
- }
- else {
- const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/
- GLuint j;
- for (j = 0; j < numSrc; j++) {
- if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
- const GLuint index = inst->SrcReg[j].Index;
- if (inst->SrcReg[j].RelAddr)
- return GL_FALSE;
- update_interval(intBegin, intEnd, loopStack, loopStackDepth,
- index, i);
- }
- }
- if (inst->DstReg.File == PROGRAM_TEMPORARY) {
- const GLuint index = inst->DstReg.Index;
- if (inst->DstReg.RelAddr)
- return GL_FALSE;
- update_interval(intBegin, intEnd, loopStack, loopStackDepth,
- index, i);
- }
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Find the live intervals for each temporary register in the program.
- * For register R, the interval [A,B] indicates that R is referenced
- * from instruction A through instruction B.
- * Special consideration is needed for loops and subroutines.
- * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason
- */
-static GLboolean
-find_live_intervals(struct gl_program *prog,
- struct interval_list *liveIntervals)
-{
- GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
- GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
- GLuint i;
-
- /*
- * Note: we'll return GL_FALSE below if we find relative indexing
- * into the TEMP register file. We can't handle that yet.
- * We also give up on subroutines for now.
- */
-
- if (dbg) {
- printf("Optimize: Begin find intervals\n");
- }
-
- /* build intermediate arrays */
- if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions,
- intBegin, intEnd))
- return GL_FALSE;
-
- /* Build live intervals list from intermediate arrays */
- liveIntervals->Num = 0;
- for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
- if (intBegin[i] >= 0) {
- struct interval inv;
- inv.Reg = i;
- inv.Start = intBegin[i];
- inv.End = intEnd[i];
- append_interval(liveIntervals, &inv);
- }
- }
-
- /* Sort the list according to interval starts */
- sort_interval_list_by_start(liveIntervals);
-
- if (dbg) {
- /* print interval info */
- for (i = 0; i < liveIntervals->Num; i++) {
- const struct interval *inv = liveIntervals->Intervals + i;
- printf("Reg[%d] live [%d, %d]:",
- inv->Reg, inv->Start, inv->End);
- if (1) {
- GLuint j;
- for (j = 0; j < inv->Start; j++)
- printf(" ");
- for (j = inv->Start; j <= inv->End; j++)
- printf("x");
- }
- printf("\n");
- }
- }
-
- return GL_TRUE;
-}
-
-
-/** Scan the array of used register flags to find free entry */
-static GLint
-alloc_register(GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
-{
- GLuint k;
- for (k = 0; k < REG_ALLOCATE_MAX_PROGRAM_TEMPS; k++) {
- if (!usedRegs[k]) {
- usedRegs[k] = GL_TRUE;
- return k;
- }
- }
- return -1;
-}
-
-
-/**
- * This function implements "Linear Scan Register Allocation" to reduce
- * the number of temporary registers used by the program.
- *
- * We compute the "live interval" for all temporary registers then
- * examine the overlap of the intervals to allocate new registers.
- * Basically, if two intervals do not overlap, they can use the same register.
- */
-static void
-_mesa_reallocate_registers(struct gl_program *prog)
-{
- struct interval_list liveIntervals;
- GLint registerMap[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
- GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
- GLuint i;
- GLint maxTemp = -1;
-
- if (dbg) {
- printf("Optimize: Begin live-interval register reallocation\n");
- _mesa_print_program(prog);
- }
-
- for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
- registerMap[i] = -1;
- usedRegs[i] = GL_FALSE;
- }
-
- if (!find_live_intervals(prog, &liveIntervals)) {
- if (dbg)
- printf("Aborting register reallocation\n");
- return;
- }
-
- {
- struct interval_list activeIntervals;
- activeIntervals.Num = 0;
-
- /* loop over live intervals, allocating a new register for each */
- for (i = 0; i < liveIntervals.Num; i++) {
- const struct interval *live = liveIntervals.Intervals + i;
-
- if (dbg)
- printf("Consider register %u\n", live->Reg);
-
- /* Expire old intervals. Intervals which have ended with respect
- * to the live interval can have their remapped registers freed.
- */
- {
- GLint j;
- for (j = 0; j < (GLint) activeIntervals.Num; j++) {
- const struct interval *inv = activeIntervals.Intervals + j;
- if (inv->End >= live->Start) {
- /* Stop now. Since the activeInterval list is sorted
- * we know we don't have to go further.
- */
- break;
- }
- else {
- /* Interval 'inv' has expired */
- const GLint regNew = registerMap[inv->Reg];
- ASSERT(regNew >= 0);
-
- if (dbg)
- printf(" expire interval for reg %u\n", inv->Reg);
-
- /* remove interval j from active list */
- remove_interval(&activeIntervals, inv);
- j--; /* counter-act j++ in for-loop above */
-
- /* return register regNew to the free pool */
- if (dbg)
- printf(" free reg %d\n", regNew);
- ASSERT(usedRegs[regNew] == GL_TRUE);
- usedRegs[regNew] = GL_FALSE;
- }
- }
- }
-
- /* find a free register for this live interval */
- {
- const GLint k = alloc_register(usedRegs);
- if (k < 0) {
- /* out of registers, give up */
- return;
- }
- registerMap[live->Reg] = k;
- maxTemp = MAX2(maxTemp, k);
- if (dbg)
- printf(" remap register %u -> %d\n", live->Reg, k);
- }
-
- /* Insert this live interval into the active list which is sorted
- * by increasing end points.
- */
- insert_interval_by_end(&activeIntervals, live);
- }
- }
-
- if (maxTemp + 1 < (GLint) liveIntervals.Num) {
- /* OK, we've reduced the number of registers needed.
- * Scan the program and replace all the old temporary register
- * indexes with the new indexes.
- */
- replace_regs(prog, PROGRAM_TEMPORARY, registerMap);
-
- prog->NumTemporaries = maxTemp + 1;
- }
-
- if (dbg) {
- printf("Optimize: End live-interval register reallocation\n");
- printf("Num temp regs before: %u after: %u\n",
- liveIntervals.Num, maxTemp + 1);
- _mesa_print_program(prog);
- }
-}
-
-
-#if 0
-static void
-print_it(GLcontext *ctx, struct gl_program *program, const char *txt) {
- fprintf(stderr, "%s (%u inst):\n", txt, program->NumInstructions);
- _mesa_print_program(program);
- _mesa_print_program_parameters(ctx, program);
- fprintf(stderr, "\n\n");
-}
-#endif
-
-
-/**
- * Apply optimizations to the given program to eliminate unnecessary
- * instructions, temp regs, etc.
- */
-void
-_mesa_optimize_program(GLcontext *ctx, struct gl_program *program)
-{
- GLboolean any_change;
-
- /* Stop when no modifications were output */
- do {
- any_change = GL_FALSE;
- _mesa_remove_extra_move_use(program);
- if (_mesa_remove_dead_code_global(program))
- any_change = GL_TRUE;
- if (_mesa_remove_extra_moves(program))
- any_change = GL_TRUE;
- if (_mesa_remove_dead_code_local(program))
- any_change = GL_TRUE;
- _mesa_reallocate_registers(program);
- } while (any_change);
-}
-
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.5
+ *
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, 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
+ * VMWARE 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 "main/glheader.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "program.h"
+#include "prog_instruction.h"
+#include "prog_optimize.h"
+#include "prog_print.h"
+
+
+#define MAX_LOOP_NESTING 50
+/* MAX_PROGRAM_TEMPS is a low number (256), and we want to be able to
+ * register allocate many temporary values into that small number of
+ * temps. So allow large temporary indices coming into the register
+ * allocator.
+ */
+#define REG_ALLOCATE_MAX_PROGRAM_TEMPS ((1 << INST_INDEX_BITS) - 1)
+
+static GLboolean dbg = GL_FALSE;
+
+#define NO_MASK 0xf
+
+/**
+ * Returns the mask of channels (bitmask of WRITEMASK_X,Y,Z,W) which
+ * are read from the given src in this instruction, We also provide
+ * one optional masks which may mask other components in the dst
+ * register
+ */
+static GLuint
+get_src_arg_mask(const struct prog_instruction *inst,
+ GLuint arg, GLuint dst_mask)
+{
+ GLuint read_mask, channel_mask;
+ GLuint comp;
+
+ ASSERT(arg < _mesa_num_inst_src_regs(inst->Opcode));
+
+ /* Form the dst register, find the written channels */
+ if (inst->CondUpdate) {
+ channel_mask = WRITEMASK_XYZW;
+ }
+ else {
+ switch (inst->Opcode) {
+ case OPCODE_MOV:
+ case OPCODE_MIN:
+ case OPCODE_MAX:
+ case OPCODE_ABS:
+ case OPCODE_ADD:
+ case OPCODE_MAD:
+ case OPCODE_MUL:
+ case OPCODE_SUB:
+ channel_mask = inst->DstReg.WriteMask & dst_mask;
+ break;
+ case OPCODE_RCP:
+ case OPCODE_SIN:
+ case OPCODE_COS:
+ case OPCODE_RSQ:
+ case OPCODE_POW:
+ case OPCODE_EX2:
+ case OPCODE_LOG:
+ channel_mask = WRITEMASK_X;
+ break;
+ case OPCODE_DP2:
+ channel_mask = WRITEMASK_XY;
+ break;
+ case OPCODE_DP3:
+ case OPCODE_XPD:
+ channel_mask = WRITEMASK_XYZ;
+ break;
+ default:
+ channel_mask = WRITEMASK_XYZW;
+ break;
+ }
+ }
+
+ /* Now, given the src swizzle and the written channels, find which
+ * components are actually read
+ */
+ read_mask = 0x0;
+ for (comp = 0; comp < 4; ++comp) {
+ const GLuint coord = GET_SWZ(inst->SrcReg[arg].Swizzle, comp);
+ ASSERT(coord < 4);
+ if (channel_mask & (1 << comp) && coord <= SWIZZLE_W)
+ read_mask |= 1 << coord;
+ }
+
+ return read_mask;
+}
+
+
+/**
+ * For a MOV instruction, compute a write mask when src register also has
+ * a mask
+ */
+static GLuint
+get_dst_mask_for_mov(const struct prog_instruction *mov, GLuint src_mask)
+{
+ const GLuint mask = mov->DstReg.WriteMask;
+ GLuint comp;
+ GLuint updated_mask = 0x0;
+
+ ASSERT(mov->Opcode == OPCODE_MOV);
+
+ for (comp = 0; comp < 4; ++comp) {
+ GLuint src_comp;
+ if ((mask & (1 << comp)) == 0)
+ continue;
+ src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, comp);
+ if ((src_mask & (1 << src_comp)) == 0)
+ continue;
+ updated_mask |= 1 << comp;
+ }
+
+ return updated_mask;
+}
+
+
+/**
+ * Ensure that the swizzle is regular. That is, all of the swizzle
+ * terms are SWIZZLE_X,Y,Z,W and not SWIZZLE_ZERO or SWIZZLE_ONE.
+ */
+static GLboolean
+is_swizzle_regular(GLuint swz)
+{
+ return GET_SWZ(swz,0) <= SWIZZLE_W &&
+ GET_SWZ(swz,1) <= SWIZZLE_W &&
+ GET_SWZ(swz,2) <= SWIZZLE_W &&
+ GET_SWZ(swz,3) <= SWIZZLE_W;
+}
+
+
+/**
+ * In 'prog' remove instruction[i] if removeFlags[i] == TRUE.
+ * \return number of instructions removed
+ */
+static GLuint
+remove_instructions(struct gl_program *prog, const GLboolean *removeFlags)
+{
+ GLint i, removeEnd = 0, removeCount = 0;
+ GLuint totalRemoved = 0;
+
+ /* go backward */
+ for (i = prog->NumInstructions - 1; i >= 0; i--) {
+ if (removeFlags[i]) {
+ totalRemoved++;
+ if (removeCount == 0) {
+ /* begin a run of instructions to remove */
+ removeEnd = i;
+ removeCount = 1;
+ }
+ else {
+ /* extend the run of instructions to remove */
+ removeCount++;
+ }
+ }
+ else {
+ /* don't remove this instruction, but check if the preceeding
+ * instructions are to be removed.
+ */
+ if (removeCount > 0) {
+ GLint removeStart = removeEnd - removeCount + 1;
+ _mesa_delete_instructions(prog, removeStart, removeCount);
+ removeStart = removeCount = 0; /* reset removal info */
+ }
+ }
+ }
+ /* Finish removing if the first instruction was to be removed. */
+ if (removeCount > 0) {
+ GLint removeStart = removeEnd - removeCount + 1;
+ _mesa_delete_instructions(prog, removeStart, removeCount);
+ }
+ return totalRemoved;
+}
+
+
+/**
+ * Remap register indexes according to map.
+ * \param prog the program to search/replace
+ * \param file the type of register file to search/replace
+ * \param map maps old register indexes to new indexes
+ */
+static void
+replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[])
+{
+ GLuint i;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ GLuint j;
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == file) {
+ GLuint index = inst->SrcReg[j].Index;
+ ASSERT(map[index] >= 0);
+ inst->SrcReg[j].Index = map[index];
+ }
+ }
+ if (inst->DstReg.File == file) {
+ const GLuint index = inst->DstReg.Index;
+ ASSERT(map[index] >= 0);
+ inst->DstReg.Index = map[index];
+ }
+ }
+}
+
+
+/**
+ * Remove dead instructions from the given program.
+ * This is very primitive for now. Basically look for temp registers
+ * that are written to but never read. Remove any instructions that
+ * write to such registers. Be careful with condition code setters.
+ */
+static GLboolean
+_mesa_remove_dead_code_global(struct gl_program *prog)
+{
+ GLboolean tempRead[REG_ALLOCATE_MAX_PROGRAM_TEMPS][4];
+ GLboolean *removeInst; /* per-instruction removal flag */
+ GLuint i, rem = 0, comp;
+
+ memset(tempRead, 0, sizeof(tempRead));
+
+ if (dbg) {
+ printf("Optimize: Begin dead code removal\n");
+ /*_mesa_print_program(prog);*/
+ }
+
+ removeInst = (GLboolean *)
+ calloc(1, prog->NumInstructions * sizeof(GLboolean));
+
+ /* Determine which temps are read and written */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ GLuint j;
+
+ /* check src regs */
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
+ const GLuint index = inst->SrcReg[j].Index;
+ GLuint read_mask;
+ ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
+ read_mask = get_src_arg_mask(inst, j, NO_MASK);
+
+ if (inst->SrcReg[j].RelAddr) {
+ if (dbg)
+ printf("abort remove dead code (indirect temp)\n");
+ goto done;
+ }
+
+ for (comp = 0; comp < 4; comp++) {
+ const GLuint swz = GET_SWZ(inst->SrcReg[j].Swizzle, comp);
+ ASSERT(swz < 4);
+ if ((read_mask & (1 << swz)) == 0)
+ continue;
+ if (swz <= SWIZZLE_W)
+ tempRead[index][swz] = GL_TRUE;
+ }
+ }
+ }
+
+ /* check dst reg */
+ if (inst->DstReg.File == PROGRAM_TEMPORARY) {
+ const GLuint index = inst->DstReg.Index;
+ ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
+
+ if (inst->DstReg.RelAddr) {
+ if (dbg)
+ printf("abort remove dead code (indirect temp)\n");
+ goto done;
+ }
+
+ if (inst->CondUpdate) {
+ /* If we're writing to this register and setting condition
+ * codes we cannot remove the instruction. Prevent removal
+ * by setting the 'read' flag.
+ */
+ tempRead[index][0] = GL_TRUE;
+ tempRead[index][1] = GL_TRUE;
+ tempRead[index][2] = GL_TRUE;
+ tempRead[index][3] = GL_TRUE;
+ }
+ }
+ }
+
+ /* find instructions that write to dead registers, flag for removal */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode);
+
+ if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) {
+ GLint chan, index = inst->DstReg.Index;
+
+ for (chan = 0; chan < 4; chan++) {
+ if (!tempRead[index][chan] &&
+ inst->DstReg.WriteMask & (1 << chan)) {
+ if (dbg) {
+ printf("Remove writemask on %u.%c\n", i,
+ chan == 3 ? 'w' : 'x' + chan);
+ }
+ inst->DstReg.WriteMask &= ~(1 << chan);
+ rem++;
+ }
+ }
+
+ if (inst->DstReg.WriteMask == 0) {
+ /* If we cleared all writes, the instruction can be removed. */
+ if (dbg)
+ printf("Remove instruction %u: \n", i);
+ removeInst[i] = GL_TRUE;
+ }
+ }
+ }
+
+ /* now remove the instructions which aren't needed */
+ rem = remove_instructions(prog, removeInst);
+
+ if (dbg) {
+ printf("Optimize: End dead code removal.\n");
+ printf(" %u channel writes removed\n", rem);
+ printf(" %u instructions removed\n", rem);
+ /*_mesa_print_program(prog);*/
+ }
+
+done:
+ free(removeInst);
+ return rem != 0;
+}
+
+
+enum inst_use
+{
+ READ,
+ WRITE,
+ FLOW,
+ END
+};
+
+
+/**
+ * Scan forward in program from 'start' for the next occurances of TEMP[index].
+ * We look if an instruction reads the component given by the masks and if they
+ * are overwritten.
+ * Return READ, WRITE, FLOW or END to indicate the next usage or an indicator
+ * that we can't look further.
+ */
+static enum inst_use
+find_next_use(const struct gl_program *prog,
+ GLuint start,
+ GLuint index,
+ GLuint mask)
+{
+ GLuint i;
+
+ for (i = start; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ switch (inst->Opcode) {
+ case OPCODE_BGNLOOP:
+ case OPCODE_BGNSUB:
+ case OPCODE_BRA:
+ case OPCODE_CAL:
+ case OPCODE_CONT:
+ case OPCODE_IF:
+ case OPCODE_ELSE:
+ case OPCODE_ENDIF:
+ case OPCODE_ENDLOOP:
+ case OPCODE_ENDSUB:
+ case OPCODE_RET:
+ return FLOW;
+ case OPCODE_END:
+ return END;
+ default:
+ {
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ GLuint j;
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].RelAddr ||
+ (inst->SrcReg[j].File == PROGRAM_TEMPORARY &&
+ inst->SrcReg[j].Index == index &&
+ (get_src_arg_mask(inst,j,NO_MASK) & mask)))
+ return READ;
+ }
+ if (_mesa_num_inst_dst_regs(inst->Opcode) == 1 &&
+ inst->DstReg.File == PROGRAM_TEMPORARY &&
+ inst->DstReg.Index == index) {
+ mask &= ~inst->DstReg.WriteMask;
+ if (mask == 0)
+ return WRITE;
+ }
+ }
+ }
+ }
+ return END;
+}
+
+
+/**
+ * Is the given instruction opcode a flow-control opcode?
+ * XXX maybe move this into prog_instruction.[ch]
+ */
+static GLboolean
+_mesa_is_flow_control_opcode(enum prog_opcode opcode)
+{
+ switch (opcode) {
+ case OPCODE_BGNLOOP:
+ case OPCODE_BGNSUB:
+ case OPCODE_BRA:
+ case OPCODE_CAL:
+ case OPCODE_CONT:
+ case OPCODE_IF:
+ case OPCODE_ELSE:
+ case OPCODE_END:
+ case OPCODE_ENDIF:
+ case OPCODE_ENDLOOP:
+ case OPCODE_ENDSUB:
+ case OPCODE_RET:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Test if the given instruction is a simple MOV (no conditional updating,
+ * not relative addressing, no negation/abs, etc).
+ */
+static GLboolean
+can_downward_mov_be_modifed(const struct prog_instruction *mov)
+{
+ return
+ mov->Opcode == OPCODE_MOV &&
+ mov->CondUpdate == GL_FALSE &&
+ mov->SrcReg[0].RelAddr == 0 &&
+ mov->SrcReg[0].Negate == 0 &&
+ mov->SrcReg[0].Abs == 0 &&
+ mov->SrcReg[0].HasIndex2 == 0 &&
+ mov->SrcReg[0].RelAddr2 == 0 &&
+ mov->DstReg.RelAddr == 0 &&
+ mov->DstReg.CondMask == COND_TR &&
+ mov->SaturateMode == SATURATE_OFF;
+}
+
+
+static GLboolean
+can_upward_mov_be_modifed(const struct prog_instruction *mov)
+{
+ return
+ can_downward_mov_be_modifed(mov) &&
+ mov->DstReg.File == PROGRAM_TEMPORARY;
+}
+
+
+/**
+ * Try to remove use of extraneous MOV instructions, to free them up for dead
+ * code removal.
+ */
+static void
+_mesa_remove_extra_move_use(struct gl_program *prog)
+{
+ GLuint i, j;
+
+ if (dbg) {
+ printf("Optimize: Begin remove extra move use\n");
+ _mesa_print_program(prog);
+ }
+
+ /*
+ * Look for sequences such as this:
+ * MOV tmpX, arg0;
+ * ...
+ * FOO tmpY, tmpX, arg1;
+ * and convert into:
+ * MOV tmpX, arg0;
+ * ...
+ * FOO tmpY, arg0, arg1;
+ */
+
+ for (i = 0; i + 1 < prog->NumInstructions; i++) {
+ const struct prog_instruction *mov = prog->Instructions + i;
+ GLuint dst_mask, src_mask;
+ if (can_upward_mov_be_modifed(mov) == GL_FALSE)
+ continue;
+
+ /* Scanning the code, we maintain the components which are still active in
+ * these two masks
+ */
+ dst_mask = mov->DstReg.WriteMask;
+ src_mask = get_src_arg_mask(mov, 0, NO_MASK);
+
+ /* Walk through remaining instructions until the or src reg gets
+ * rewritten or we get into some flow-control, eliminating the use of
+ * this MOV.
+ */
+ for (j = i + 1; j < prog->NumInstructions; j++) {
+ struct prog_instruction *inst2 = prog->Instructions + j;
+ GLuint arg;
+
+ if (_mesa_is_flow_control_opcode(inst2->Opcode))
+ break;
+
+ /* First rewrite this instruction's args if appropriate. */
+ for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
+ GLuint comp, read_mask;
+
+ if (inst2->SrcReg[arg].File != mov->DstReg.File ||
+ inst2->SrcReg[arg].Index != mov->DstReg.Index ||
+ inst2->SrcReg[arg].RelAddr ||
+ inst2->SrcReg[arg].Abs)
+ continue;
+ read_mask = get_src_arg_mask(inst2, arg, NO_MASK);
+
+ /* Adjust the swizzles of inst2 to point at MOV's source if ALL the
+ * components read still come from the mov instructions
+ */
+ if (is_swizzle_regular(inst2->SrcReg[arg].Swizzle) &&
+ (read_mask & dst_mask) == read_mask) {
+ for (comp = 0; comp < 4; comp++) {
+ const GLuint inst2_swz =
+ GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
+ const GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
+ inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
+ inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
+ inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
+ inst2_swz) & 0x1) << comp);
+ }
+ inst2->SrcReg[arg].File = mov->SrcReg[0].File;
+ inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
+ }
+ }
+
+ /* The source of MOV is written. This potentially deactivates some
+ * components from the src and dst of the MOV instruction
+ */
+ if (inst2->DstReg.File == mov->DstReg.File &&
+ (inst2->DstReg.RelAddr ||
+ inst2->DstReg.Index == mov->DstReg.Index)) {
+ dst_mask &= ~inst2->DstReg.WriteMask;
+ src_mask = get_src_arg_mask(mov, 0, dst_mask);
+ }
+
+ /* Idem when the destination of mov is written */
+ if (inst2->DstReg.File == mov->SrcReg[0].File &&
+ (inst2->DstReg.RelAddr ||
+ inst2->DstReg.Index == mov->SrcReg[0].Index)) {
+ src_mask &= ~inst2->DstReg.WriteMask;
+ dst_mask &= get_dst_mask_for_mov(mov, src_mask);
+ }
+ if (dst_mask == 0)
+ break;
+ }
+ }
+
+ if (dbg) {
+ printf("Optimize: End remove extra move use.\n");
+ /*_mesa_print_program(prog);*/
+ }
+}
+
+
+/**
+ * Complements dead_code_global. Try to remove code in block of code by
+ * carefully monitoring the swizzles. Both functions should be merged into one
+ * with a proper control flow graph
+ */
+static GLboolean
+_mesa_remove_dead_code_local(struct gl_program *prog)
+{
+ GLboolean *removeInst;
+ GLuint i, arg, rem = 0;
+
+ removeInst = (GLboolean *)
+ calloc(1, prog->NumInstructions * sizeof(GLboolean));
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint index = inst->DstReg.Index;
+ const GLuint mask = inst->DstReg.WriteMask;
+ enum inst_use use;
+
+ /* We must deactivate the pass as soon as some indirection is used */
+ if (inst->DstReg.RelAddr)
+ goto done;
+ for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++)
+ if (inst->SrcReg[arg].RelAddr)
+ goto done;
+
+ if (_mesa_is_flow_control_opcode(inst->Opcode) ||
+ _mesa_num_inst_dst_regs(inst->Opcode) == 0 ||
+ inst->DstReg.File != PROGRAM_TEMPORARY ||
+ inst->DstReg.RelAddr)
+ continue;
+
+ use = find_next_use(prog, i+1, index, mask);
+ if (use == WRITE || use == END)
+ removeInst[i] = GL_TRUE;
+ }
+
+ rem = remove_instructions(prog, removeInst);
+
+done:
+ free(removeInst);
+ return rem != 0;
+}
+
+
+/**
+ * Try to inject the destination of mov as the destination of inst and recompute
+ * the swizzles operators for the sources of inst if required. Return GL_TRUE
+ * of the substitution was possible, GL_FALSE otherwise
+ */
+static GLboolean
+_mesa_merge_mov_into_inst(struct prog_instruction *inst,
+ const struct prog_instruction *mov)
+{
+ /* Indirection table which associates destination and source components for
+ * the mov instruction
+ */
+ const GLuint mask = get_src_arg_mask(mov, 0, NO_MASK);
+
+ /* Some components are not written by inst. We cannot remove the mov */
+ if (mask != (inst->DstReg.WriteMask & mask))
+ return GL_FALSE;
+
+ /* Depending on the instruction, we may need to recompute the swizzles.
+ * Also, some other instructions (like TEX) are not linear. We will only
+ * consider completely active sources and destinations
+ */
+ switch (inst->Opcode) {
+
+ /* Carstesian instructions: we compute the swizzle */
+ case OPCODE_MOV:
+ case OPCODE_MIN:
+ case OPCODE_MAX:
+ case OPCODE_ABS:
+ case OPCODE_ADD:
+ case OPCODE_MAD:
+ case OPCODE_MUL:
+ case OPCODE_SUB:
+ {
+ GLuint dst_to_src_comp[4] = {0,0,0,0};
+ GLuint dst_comp, arg;
+ for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
+ if (mov->DstReg.WriteMask & (1 << dst_comp)) {
+ const GLuint src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, dst_comp);
+ ASSERT(src_comp < 4);
+ dst_to_src_comp[dst_comp] = src_comp;
+ }
+ }
+
+ /* Patch each source of the instruction */
+ for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++) {
+ const GLuint arg_swz = inst->SrcReg[arg].Swizzle;
+ inst->SrcReg[arg].Swizzle = 0;
+
+ /* Reset each active component of the swizzle */
+ for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
+ GLuint src_comp, arg_comp;
+ if ((mov->DstReg.WriteMask & (1 << dst_comp)) == 0)
+ continue;
+ src_comp = dst_to_src_comp[dst_comp];
+ ASSERT(src_comp < 4);
+ arg_comp = GET_SWZ(arg_swz, src_comp);
+ ASSERT(arg_comp < 4);
+ inst->SrcReg[arg].Swizzle |= arg_comp << (3*dst_comp);
+ }
+ }
+ inst->DstReg = mov->DstReg;
+ return GL_TRUE;
+ }
+
+ /* Dot products and scalar instructions: we only change the destination */
+ case OPCODE_RCP:
+ case OPCODE_SIN:
+ case OPCODE_COS:
+ case OPCODE_RSQ:
+ case OPCODE_POW:
+ case OPCODE_EX2:
+ case OPCODE_LOG:
+ case OPCODE_DP2:
+ case OPCODE_DP3:
+ case OPCODE_DP4:
+ inst->DstReg = mov->DstReg;
+ return GL_TRUE;
+
+ /* All other instructions require fully active components with no swizzle */
+ default:
+ if (mov->SrcReg[0].Swizzle != SWIZZLE_XYZW ||
+ inst->DstReg.WriteMask != WRITEMASK_XYZW)
+ return GL_FALSE;
+ inst->DstReg = mov->DstReg;
+ return GL_TRUE;
+ }
+}
+
+
+/**
+ * Try to remove extraneous MOV instructions from the given program.
+ */
+static GLboolean
+_mesa_remove_extra_moves(struct gl_program *prog)
+{
+ GLboolean *removeInst; /* per-instruction removal flag */
+ GLuint i, rem = 0, nesting = 0;
+
+ if (dbg) {
+ printf("Optimize: Begin remove extra moves\n");
+ _mesa_print_program(prog);
+ }
+
+ removeInst = (GLboolean *)
+ calloc(1, prog->NumInstructions * sizeof(GLboolean));
+
+ /*
+ * Look for sequences such as this:
+ * FOO tmpX, arg0, arg1;
+ * MOV tmpY, tmpX;
+ * and convert into:
+ * FOO tmpY, arg0, arg1;
+ */
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *mov = prog->Instructions + i;
+
+ switch (mov->Opcode) {
+ case OPCODE_BGNLOOP:
+ case OPCODE_BGNSUB:
+ case OPCODE_IF:
+ nesting++;
+ break;
+ case OPCODE_ENDLOOP:
+ case OPCODE_ENDSUB:
+ case OPCODE_ENDIF:
+ nesting--;
+ break;
+ case OPCODE_MOV:
+ if (i > 0 &&
+ can_downward_mov_be_modifed(mov) &&
+ mov->SrcReg[0].File == PROGRAM_TEMPORARY &&
+ nesting == 0)
+ {
+
+ /* see if this MOV can be removed */
+ const GLuint id = mov->SrcReg[0].Index;
+ struct prog_instruction *prevInst;
+ GLuint prevI;
+
+ /* get pointer to previous instruction */
+ prevI = i - 1;
+ while (prevI > 0 && removeInst[prevI])
+ prevI--;
+ prevInst = prog->Instructions + prevI;
+
+ if (prevInst->DstReg.File == PROGRAM_TEMPORARY &&
+ prevInst->DstReg.Index == id &&
+ prevInst->DstReg.RelAddr == 0 &&
+ prevInst->DstReg.CondSrc == 0 &&
+ prevInst->DstReg.CondMask == COND_TR) {
+
+ const GLuint dst_mask = prevInst->DstReg.WriteMask;
+ enum inst_use next_use = find_next_use(prog, i+1, id, dst_mask);
+
+ if (next_use == WRITE || next_use == END) {
+ /* OK, we can safely remove this MOV instruction.
+ * Transform:
+ * prevI: FOO tempIndex, x, y;
+ * i: MOV z, tempIndex;
+ * Into:
+ * prevI: FOO z, x, y;
+ */
+ if (_mesa_merge_mov_into_inst(prevInst, mov)) {
+ removeInst[i] = GL_TRUE;
+ if (dbg) {
+ printf("Remove MOV at %u\n", i);
+ printf("new prev inst %u: ", prevI);
+ _mesa_print_instruction(prevInst);
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ ; /* nothing */
+ }
+ }
+
+ /* now remove the instructions which aren't needed */
+ rem = remove_instructions(prog, removeInst);
+
+ free(removeInst);
+
+ if (dbg) {
+ printf("Optimize: End remove extra moves. %u instructions removed\n", rem);
+ /*_mesa_print_program(prog);*/
+ }
+
+ return rem != 0;
+}
+
+
+/** A live register interval */
+struct interval
+{
+ GLuint Reg; /** The temporary register index */
+ GLuint Start, End; /** Start/end instruction numbers */
+};
+
+
+/** A list of register intervals */
+struct interval_list
+{
+ GLuint Num;
+ struct interval Intervals[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
+};
+
+
+static void
+append_interval(struct interval_list *list, const struct interval *inv)
+{
+ list->Intervals[list->Num++] = *inv;
+}
+
+
+/** Insert interval inv into list, sorted by interval end */
+static void
+insert_interval_by_end(struct interval_list *list, const struct interval *inv)
+{
+ /* XXX we could do a binary search insertion here since list is sorted */
+ GLint i = list->Num - 1;
+ while (i >= 0 && list->Intervals[i].End > inv->End) {
+ list->Intervals[i + 1] = list->Intervals[i];
+ i--;
+ }
+ list->Intervals[i + 1] = *inv;
+ list->Num++;
+
+#ifdef DEBUG
+ {
+ GLuint i;
+ for (i = 0; i + 1 < list->Num; i++) {
+ ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End);
+ }
+ }
+#endif
+}
+
+
+/** Remove the given interval from the interval list */
+static void
+remove_interval(struct interval_list *list, const struct interval *inv)
+{
+ /* XXX we could binary search since list is sorted */
+ GLuint k;
+ for (k = 0; k < list->Num; k++) {
+ if (list->Intervals[k].Reg == inv->Reg) {
+ /* found, remove it */
+ ASSERT(list->Intervals[k].Start == inv->Start);
+ ASSERT(list->Intervals[k].End == inv->End);
+ while (k < list->Num - 1) {
+ list->Intervals[k] = list->Intervals[k + 1];
+ k++;
+ }
+ list->Num--;
+ return;
+ }
+ }
+}
+
+
+/** called by qsort() */
+static int
+compare_start(const void *a, const void *b)
+{
+ const struct interval *ia = (const struct interval *) a;
+ const struct interval *ib = (const struct interval *) b;
+ if (ia->Start < ib->Start)
+ return -1;
+ else if (ia->Start > ib->Start)
+ return +1;
+ else
+ return 0;
+}
+
+
+/** sort the interval list according to interval starts */
+static void
+sort_interval_list_by_start(struct interval_list *list)
+{
+ qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start);
+#ifdef DEBUG
+ {
+ GLuint i;
+ for (i = 0; i + 1 < list->Num; i++) {
+ ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start);
+ }
+ }
+#endif
+}
+
+struct loop_info
+{
+ GLuint Start, End; /**< Start, end instructions of loop */
+};
+
+/**
+ * Update the intermediate interval info for register 'index' and
+ * instruction 'ic'.
+ */
+static void
+update_interval(GLint intBegin[], GLint intEnd[],
+ struct loop_info *loopStack, GLuint loopStackDepth,
+ GLuint index, GLuint ic)
+{
+ int i;
+
+ /* If the register is used in a loop, extend its lifetime through the end
+ * of the outermost loop that doesn't contain its definition.
+ */
+ for (i = 0; i < loopStackDepth; i++) {
+ if (intBegin[index] < loopStack[i].Start) {
+ ic = loopStack[i].End;
+ break;
+ }
+ }
+
+ ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
+ if (intBegin[index] == -1) {
+ ASSERT(intEnd[index] == -1);
+ intBegin[index] = intEnd[index] = ic;
+ }
+ else {
+ intEnd[index] = ic;
+ }
+}
+
+
+/**
+ * Find first/last instruction that references each temporary register.
+ */
+GLboolean
+_mesa_find_temp_intervals(const struct prog_instruction *instructions,
+ GLuint numInstructions,
+ GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS],
+ GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
+{
+ struct loop_info loopStack[MAX_LOOP_NESTING];
+ GLuint loopStackDepth = 0;
+ GLuint i;
+
+ for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
+ intBegin[i] = intEnd[i] = -1;
+ }
+
+ /* Scan instructions looking for temporary registers */
+ for (i = 0; i < numInstructions; i++) {
+ const struct prog_instruction *inst = instructions + i;
+ if (inst->Opcode == OPCODE_BGNLOOP) {
+ loopStack[loopStackDepth].Start = i;
+ loopStack[loopStackDepth].End = inst->BranchTarget;
+ loopStackDepth++;
+ }
+ else if (inst->Opcode == OPCODE_ENDLOOP) {
+ loopStackDepth--;
+ }
+ else if (inst->Opcode == OPCODE_CAL) {
+ return GL_FALSE;
+ }
+ else {
+ const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/
+ GLuint j;
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
+ const GLuint index = inst->SrcReg[j].Index;
+ if (inst->SrcReg[j].RelAddr)
+ return GL_FALSE;
+ update_interval(intBegin, intEnd, loopStack, loopStackDepth,
+ index, i);
+ }
+ }
+ if (inst->DstReg.File == PROGRAM_TEMPORARY) {
+ const GLuint index = inst->DstReg.Index;
+ if (inst->DstReg.RelAddr)
+ return GL_FALSE;
+ update_interval(intBegin, intEnd, loopStack, loopStackDepth,
+ index, i);
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Find the live intervals for each temporary register in the program.
+ * For register R, the interval [A,B] indicates that R is referenced
+ * from instruction A through instruction B.
+ * Special consideration is needed for loops and subroutines.
+ * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason
+ */
+static GLboolean
+find_live_intervals(struct gl_program *prog,
+ struct interval_list *liveIntervals)
+{
+ GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
+ GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
+ GLuint i;
+
+ /*
+ * Note: we'll return GL_FALSE below if we find relative indexing
+ * into the TEMP register file. We can't handle that yet.
+ * We also give up on subroutines for now.
+ */
+
+ if (dbg) {
+ printf("Optimize: Begin find intervals\n");
+ }
+
+ /* build intermediate arrays */
+ if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions,
+ intBegin, intEnd))
+ return GL_FALSE;
+
+ /* Build live intervals list from intermediate arrays */
+ liveIntervals->Num = 0;
+ for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
+ if (intBegin[i] >= 0) {
+ struct interval inv;
+ inv.Reg = i;
+ inv.Start = intBegin[i];
+ inv.End = intEnd[i];
+ append_interval(liveIntervals, &inv);
+ }
+ }
+
+ /* Sort the list according to interval starts */
+ sort_interval_list_by_start(liveIntervals);
+
+ if (dbg) {
+ /* print interval info */
+ for (i = 0; i < liveIntervals->Num; i++) {
+ const struct interval *inv = liveIntervals->Intervals + i;
+ printf("Reg[%d] live [%d, %d]:",
+ inv->Reg, inv->Start, inv->End);
+ if (1) {
+ GLuint j;
+ for (j = 0; j < inv->Start; j++)
+ printf(" ");
+ for (j = inv->Start; j <= inv->End; j++)
+ printf("x");
+ }
+ printf("\n");
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+/** Scan the array of used register flags to find free entry */
+static GLint
+alloc_register(GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
+{
+ GLuint k;
+ for (k = 0; k < REG_ALLOCATE_MAX_PROGRAM_TEMPS; k++) {
+ if (!usedRegs[k]) {
+ usedRegs[k] = GL_TRUE;
+ return k;
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * This function implements "Linear Scan Register Allocation" to reduce
+ * the number of temporary registers used by the program.
+ *
+ * We compute the "live interval" for all temporary registers then
+ * examine the overlap of the intervals to allocate new registers.
+ * Basically, if two intervals do not overlap, they can use the same register.
+ */
+static void
+_mesa_reallocate_registers(struct gl_program *prog)
+{
+ struct interval_list liveIntervals;
+ GLint registerMap[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
+ GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
+ GLuint i;
+ GLint maxTemp = -1;
+
+ if (dbg) {
+ printf("Optimize: Begin live-interval register reallocation\n");
+ _mesa_print_program(prog);
+ }
+
+ for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
+ registerMap[i] = -1;
+ usedRegs[i] = GL_FALSE;
+ }
+
+ if (!find_live_intervals(prog, &liveIntervals)) {
+ if (dbg)
+ printf("Aborting register reallocation\n");
+ return;
+ }
+
+ {
+ struct interval_list activeIntervals;
+ activeIntervals.Num = 0;
+
+ /* loop over live intervals, allocating a new register for each */
+ for (i = 0; i < liveIntervals.Num; i++) {
+ const struct interval *live = liveIntervals.Intervals + i;
+
+ if (dbg)
+ printf("Consider register %u\n", live->Reg);
+
+ /* Expire old intervals. Intervals which have ended with respect
+ * to the live interval can have their remapped registers freed.
+ */
+ {
+ GLint j;
+ for (j = 0; j < (GLint) activeIntervals.Num; j++) {
+ const struct interval *inv = activeIntervals.Intervals + j;
+ if (inv->End >= live->Start) {
+ /* Stop now. Since the activeInterval list is sorted
+ * we know we don't have to go further.
+ */
+ break;
+ }
+ else {
+ /* Interval 'inv' has expired */
+ const GLint regNew = registerMap[inv->Reg];
+ ASSERT(regNew >= 0);
+
+ if (dbg)
+ printf(" expire interval for reg %u\n", inv->Reg);
+
+ /* remove interval j from active list */
+ remove_interval(&activeIntervals, inv);
+ j--; /* counter-act j++ in for-loop above */
+
+ /* return register regNew to the free pool */
+ if (dbg)
+ printf(" free reg %d\n", regNew);
+ ASSERT(usedRegs[regNew] == GL_TRUE);
+ usedRegs[regNew] = GL_FALSE;
+ }
+ }
+ }
+
+ /* find a free register for this live interval */
+ {
+ const GLint k = alloc_register(usedRegs);
+ if (k < 0) {
+ /* out of registers, give up */
+ return;
+ }
+ registerMap[live->Reg] = k;
+ maxTemp = MAX2(maxTemp, k);
+ if (dbg)
+ printf(" remap register %u -> %d\n", live->Reg, k);
+ }
+
+ /* Insert this live interval into the active list which is sorted
+ * by increasing end points.
+ */
+ insert_interval_by_end(&activeIntervals, live);
+ }
+ }
+
+ if (maxTemp + 1 < (GLint) liveIntervals.Num) {
+ /* OK, we've reduced the number of registers needed.
+ * Scan the program and replace all the old temporary register
+ * indexes with the new indexes.
+ */
+ replace_regs(prog, PROGRAM_TEMPORARY, registerMap);
+
+ prog->NumTemporaries = maxTemp + 1;
+ }
+
+ if (dbg) {
+ printf("Optimize: End live-interval register reallocation\n");
+ printf("Num temp regs before: %u after: %u\n",
+ liveIntervals.Num, maxTemp + 1);
+ _mesa_print_program(prog);
+ }
+}
+
+
+#if 0
+static void
+print_it(struct gl_context *ctx, struct gl_program *program, const char *txt) {
+ fprintf(stderr, "%s (%u inst):\n", txt, program->NumInstructions);
+ _mesa_print_program(program);
+ _mesa_print_program_parameters(ctx, program);
+ fprintf(stderr, "\n\n");
+}
+#endif
+
+
+/**
+ * Apply optimizations to the given program to eliminate unnecessary
+ * instructions, temp regs, etc.
+ */
+void
+_mesa_optimize_program(struct gl_context *ctx, struct gl_program *program)
+{
+ GLboolean any_change;
+
+ /* Stop when no modifications were output */
+ do {
+ any_change = GL_FALSE;
+ _mesa_remove_extra_move_use(program);
+ if (_mesa_remove_dead_code_global(program))
+ any_change = GL_TRUE;
+ if (_mesa_remove_extra_moves(program))
+ any_change = GL_TRUE;
+ if (_mesa_remove_dead_code_local(program))
+ any_change = GL_TRUE;
+ _mesa_reallocate_registers(program);
+ } while (any_change);
+}
+
diff --git a/mesalib/src/mesa/program/prog_optimize.h b/mesalib/src/mesa/program/prog_optimize.h
index 06cd9cb2c..8dc58ee52 100644
--- a/mesalib/src/mesa/program/prog_optimize.h
+++ b/mesalib/src/mesa/program/prog_optimize.h
@@ -1,46 +1,47 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.5
- *
- * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, 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
- * VMWARE 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 PROG_OPT_H
-#define PROG_OPT_H
-
-
-#include "main/config.h"
-#include "main/mtypes.h"
-
-
-struct gl_program;
-struct prog_instruction;
-
-
-extern GLboolean
-_mesa_find_temp_intervals(const struct prog_instruction *instructions,
- GLuint numInstructions,
- GLint intBegin[MAX_PROGRAM_TEMPS],
- GLint intEnd[MAX_PROGRAM_TEMPS]);
-
-extern void
-_mesa_optimize_program(GLcontext *ctx, struct gl_program *program);
-
-#endif
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.5
+ *
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, 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
+ * VMWARE 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 PROG_OPT_H
+#define PROG_OPT_H
+
+
+#include "main/config.h"
+#include "main/glheader.h"
+
+
+struct gl_context;
+struct gl_program;
+struct prog_instruction;
+
+
+extern GLboolean
+_mesa_find_temp_intervals(const struct prog_instruction *instructions,
+ GLuint numInstructions,
+ GLint intBegin[MAX_PROGRAM_TEMPS],
+ GLint intEnd[MAX_PROGRAM_TEMPS]);
+
+extern void
+_mesa_optimize_program(struct gl_context *ctx, struct gl_program *program);
+
+#endif
diff --git a/mesalib/src/mesa/program/prog_parameter.c b/mesalib/src/mesa/program/prog_parameter.c
index 6bf8a081b..157e31b56 100644
--- a/mesalib/src/mesa/program/prog_parameter.c
+++ b/mesalib/src/mesa/program/prog_parameter.c
@@ -1,665 +1,656 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2008 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_parameter.c
- * Program parameter lists and functions.
- * \author Brian Paul
- */
-
-
-#include "main/glheader.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_statevars.h"
-
-
-struct gl_program_parameter_list *
-_mesa_new_parameter_list(void)
-{
- return CALLOC_STRUCT(gl_program_parameter_list);
-}
-
-
-struct gl_program_parameter_list *
-_mesa_new_parameter_list_sized(unsigned size)
-{
- struct gl_program_parameter_list *p = _mesa_new_parameter_list();
-
- if ((p != NULL) && (size != 0)) {
- p->Size = size;
-
- /* alloc arrays */
- p->Parameters = (struct gl_program_parameter *)
- calloc(1, size * sizeof(struct gl_program_parameter));
-
- p->ParameterValues = (GLfloat (*)[4])
- _mesa_align_malloc(size * 4 *sizeof(GLfloat), 16);
-
-
- if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) {
- free(p->Parameters);
- _mesa_align_free(p->ParameterValues);
- free(p);
- p = NULL;
- }
- }
-
- return p;
-}
-
-
-/**
- * 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)
- free((void *) paramList->Parameters[i].Name);
- }
- free(paramList->Parameters);
- if (paramList->ParameterValues)
- _mesa_align_free(paramList->ParameterValues);
- free(paramList);
-}
-
-
-/**
- * Add a new parameter to a parameter list.
- * Note that parameter values are usually 4-element GLfloat vectors.
- * When size > 4 we'll allocate a sequential block of parameters to
- * store all the values (in blocks of 4).
- *
- * \param paramList the list to add the parameter to
- * \param type type of parameter, such as
- * \param name the parameter name, will be duplicated/copied!
- * \param size number of elements in 'values' vector (1..4, or more)
- * \param datatype GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE.
- * \param values initial parameter value, up to 4 GLfloats, or NULL
- * \param state state indexes, or NULL
- * \return index of new parameter in the list, or -1 if error (out of mem)
- */
-GLint
-_mesa_add_parameter(struct gl_program_parameter_list *paramList,
- gl_register_file type, const char *name,
- GLuint size, GLenum datatype, const GLfloat *values,
- const gl_state_index state[STATE_LENGTH],
- GLbitfield flags)
-{
- const GLuint oldNum = paramList->NumParameters;
- const GLuint sz4 = (size + 3) / 4; /* no. of new param slots needed */
-
- assert(size > 0);
-
- if (oldNum + sz4 > paramList->Size) {
- /* Need to grow the parameter list array (alloc some extra) */
- paramList->Size = paramList->Size + 4 * sz4;
-
- /* realloc arrays */
- paramList->Parameters = (struct gl_program_parameter *)
- _mesa_realloc(paramList->Parameters,
- oldNum * sizeof(struct gl_program_parameter),
- paramList->Size * sizeof(struct gl_program_parameter));
-
- paramList->ParameterValues = (GLfloat (*)[4])
- _mesa_align_realloc(paramList->ParameterValues, /* old buf */
- oldNum * 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 {
- GLuint i;
-
- paramList->NumParameters = oldNum + sz4;
-
- memset(&paramList->Parameters[oldNum], 0,
- sz4 * sizeof(struct gl_program_parameter));
-
- for (i = 0; i < sz4; i++) {
- struct gl_program_parameter *p = paramList->Parameters + oldNum + i;
- p->Name = name ? _mesa_strdup(name) : NULL;
- p->Type = type;
- p->Size = size;
- p->DataType = datatype;
- p->Flags = flags;
- if (values) {
- COPY_4V(paramList->ParameterValues[oldNum + i], values);
- values += 4;
- p->Initialized = GL_TRUE;
- }
- else {
- /* silence valgrind */
- ASSIGN_4V(paramList->ParameterValues[oldNum + i], 0, 0, 0, 0);
- }
- size -= 4;
- }
-
- if (state) {
- for (i = 0; i < STATE_LENGTH; i++)
- paramList->Parameters[oldNum].StateIndexes[i] = state[i];
- }
-
- return (GLint) oldNum;
- }
-}
-
-
-/**
- * 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 _mesa_add_parameter(paramList, PROGRAM_NAMED_PARAM, name,
- 4, GL_NONE, values, NULL, 0x0);
-
-}
-
-
-/**
- * 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 name the name for the constant
- * \param values four float values
- * \return index/position of the new parameter in the parameter list
- */
-GLint
-_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
- const char *name, const GLfloat values[4],
- GLuint size)
-{
- /* first check if this is a duplicate constant */
- GLint pos;
- for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) {
- const GLfloat *pvals = paramList->ParameterValues[pos];
- if (pvals[0] == values[0] &&
- pvals[1] == values[1] &&
- pvals[2] == values[2] &&
- pvals[3] == values[3] &&
- strcmp(paramList->Parameters[pos].Name, name) == 0) {
- /* Same name and value is already in the param list - reuse it */
- return pos;
- }
- }
- /* not found, add new parameter */
- return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name,
- size, GL_NONE, values, NULL, 0x0);
-}
-
-
-/**
- * Add a new unnamed constant to the parameter list. This will be used
- * when a fragment/vertex program contains something like this:
- * MOV r, { 0, 1, 2, 3 };
- * If swizzleOut is non-null we'll search the parameter list for an
- * existing instance of the constant which matches with a swizzle.
- *
- * \param paramList the parameter list
- * \param values four float values
- * \param swizzleOut returns swizzle mask for accessing the constant
- * \return index/position of the new parameter in the parameter list.
- */
-GLint
-_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
- const GLfloat values[4], GLuint size,
- GLuint *swizzleOut)
-{
- GLint pos;
- ASSERT(size >= 1);
- ASSERT(size <= 4);
-
- if (swizzleOut &&
- _mesa_lookup_parameter_constant(paramList, values,
- size, &pos, swizzleOut)) {
- return pos;
- }
-
- /* Look for empty space in an already unnamed constant parameter
- * to add this constant. This will only work for single-element
- * constants because we rely on smearing (i.e. .yyyy or .zzzz).
- */
- if (size == 1 && swizzleOut) {
- for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) {
- struct gl_program_parameter *p = paramList->Parameters + pos;
- if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) {
- /* ok, found room */
- GLfloat *pVal = paramList->ParameterValues[pos];
- GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */
- pVal[p->Size] = values[0];
- p->Size++;
- *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz);
- return pos;
- }
- }
- }
-
- /* add a new parameter to store this constant */
- pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL,
- size, GL_NONE, values, NULL, 0x0);
- if (pos >= 0 && swizzleOut) {
- if (size == 1)
- *swizzleOut = SWIZZLE_XXXX;
- else
- *swizzleOut = SWIZZLE_NOOP;
- }
- return pos;
-}
-
-/**
- * Add parameter representing a varying variable.
- */
-GLint
-_mesa_add_varying(struct gl_program_parameter_list *paramList,
- const char *name, GLuint size, GLenum datatype,
- GLbitfield flags)
-{
- GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
- if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) {
- /* already in list */
- return i;
- }
- else {
- /*assert(size == 4);*/
- i = _mesa_add_parameter(paramList, PROGRAM_VARYING, name,
- size, datatype, NULL, NULL, flags);
- return i;
- }
-}
-
-
-/**
- * Add parameter representing a vertex program attribute.
- * \param size size of attribute (in floats), may be -1 if unknown
- * \param attrib the attribute index, or -1 if unknown
- */
-GLint
-_mesa_add_attribute(struct gl_program_parameter_list *paramList,
- const char *name, GLint size, GLenum datatype, GLint attrib)
-{
- GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
- if (i >= 0) {
- /* replace */
- if (attrib < 0)
- attrib = i;
- paramList->Parameters[i].StateIndexes[0] = attrib;
- }
- else {
- /* add */
- gl_state_index state[STATE_LENGTH];
- state[0] = (gl_state_index) attrib;
- if (size < 0)
- size = 4;
- i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name,
- size, datatype, NULL, state, 0x0);
- }
- return i;
-}
-
-
-
-#if 0 /* not used yet */
-/**
- * Returns the number of 4-component registers needed to store a piece
- * of GL state. For matrices this may be as many as 4 registers,
- * everything else needs
- * just 1 register.
- */
-static GLuint
-sizeof_state_reference(const GLint *stateTokens)
-{
- if (stateTokens[0] == STATE_MATRIX) {
- GLuint rows = stateTokens[4] - stateTokens[3] + 1;
- assert(rows >= 1);
- assert(rows <= 4);
- return rows;
- }
- else {
- return 1;
- }
-}
-#endif
-
-
-/**
- * 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 stateTokens an array of 5 (STATE_LENGTH) state tokens
- * \return index of the new parameter.
- */
-GLint
-_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
- const gl_state_index stateTokens[STATE_LENGTH])
-{
- const GLuint size = 4; /* XXX fix */
- char *name;
- GLint index;
-
- /* Check if the state reference is already in the list */
- for (index = 0; index < (GLint) paramList->NumParameters; index++) {
- GLuint i, match = 0;
- for (i = 0; i < STATE_LENGTH; i++) {
- if (paramList->Parameters[index].StateIndexes[i] == stateTokens[i]) {
- match++;
- }
- else {
- break;
- }
- }
- if (match == STATE_LENGTH) {
- /* this state reference is already in the parameter list */
- return index;
- }
- }
-
- name = _mesa_program_state_string(stateTokens);
- index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name,
- size, GL_NONE,
- NULL, (gl_state_index *) stateTokens, 0x0);
- paramList->StateFlags |= _mesa_program_state_flags(stateTokens);
-
- /* free name string here since we duplicated it in add_parameter() */
- free(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(const struct gl_program_parameter_list *paramList,
- GLsizei nameLen, const char *name)
-{
- GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name);
- if (i < 0)
- return NULL;
- else
- return paramList->ParameterValues[i];
-}
-
-
-/**
- * Given a program parameter name, find its position in the list of parameters.
- * \param paramList the parameter list to search
- * \param nameLen length of name (in chars).
- * If length is negative, assume that name is null-terminated.
- * \param name the name to search for
- * \return index of parameter in the list.
- */
-GLint
-_mesa_lookup_parameter_index(const 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 &&
- 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 &&
- strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
- && strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
- return i;
- }
- }
- return -1;
-}
-
-
-/**
- * Look for a float vector in the given parameter list. The float vector
- * may be of length 1, 2, 3 or 4. If swizzleOut is non-null, we'll try
- * swizzling to find a match.
- * \param list the parameter list to search
- * \param v the float vector to search for
- * \param vSize number of element in v
- * \param posOut returns the position of the constant, if found
- * \param swizzleOut returns a swizzle mask describing location of the
- * vector elements if found.
- * \return GL_TRUE if found, GL_FALSE if not found
- */
-GLboolean
-_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list,
- const GLfloat v[], GLuint vSize,
- GLint *posOut, GLuint *swizzleOut)
-{
- GLuint i;
-
- assert(vSize >= 1);
- assert(vSize <= 4);
-
- if (!list) {
- *posOut = -1;
- return GL_FALSE;
- }
-
- for (i = 0; i < list->NumParameters; i++) {
- if (list->Parameters[i].Type == PROGRAM_CONSTANT) {
- if (!swizzleOut) {
- /* swizzle not allowed */
- GLuint j, match = 0;
- for (j = 0; j < vSize; j++) {
- if (v[j] == list->ParameterValues[i][j])
- match++;
- }
- if (match == vSize) {
- *posOut = i;
- return GL_TRUE;
- }
- }
- else {
- /* try matching w/ swizzle */
- if (vSize == 1) {
- /* look for v[0] anywhere within float[4] value */
- GLuint j;
- for (j = 0; j < list->Parameters[i].Size; j++) {
- if (list->ParameterValues[i][j] == v[0]) {
- /* found it */
- *posOut = i;
- *swizzleOut = MAKE_SWIZZLE4(j, j, j, j);
- return GL_TRUE;
- }
- }
- }
- else if (vSize <= list->Parameters[i].Size) {
- /* see if we can match this constant (with a swizzle) */
- GLuint swz[4];
- GLuint match = 0, j, k;
- for (j = 0; j < vSize; j++) {
- if (v[j] == list->ParameterValues[i][j]) {
- swz[j] = j;
- match++;
- }
- else {
- for (k = 0; k < list->Parameters[i].Size; k++) {
- if (v[j] == list->ParameterValues[i][k]) {
- swz[j] = k;
- match++;
- break;
- }
- }
- }
- }
- /* smear last value to remaining positions */
- for (; j < 4; j++)
- swz[j] = swz[j-1];
-
- if (match == vSize) {
- *posOut = i;
- *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
- return GL_TRUE;
- }
- }
- }
- }
- }
-
- *posOut = -1;
- return GL_FALSE;
-}
-
-
-struct gl_program_parameter_list *
-_mesa_clone_parameter_list(const struct gl_program_parameter_list *list)
-{
- struct gl_program_parameter_list *clone;
- GLuint i;
-
- clone = _mesa_new_parameter_list();
- if (!clone)
- return NULL;
-
- /** Not too efficient, but correct */
- for (i = 0; i < list->NumParameters; i++) {
- struct gl_program_parameter *p = list->Parameters + i;
- struct gl_program_parameter *pCopy;
- GLuint size = MIN2(p->Size, 4);
- GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType,
- list->ParameterValues[i], NULL, 0x0);
- ASSERT(j >= 0);
- pCopy = clone->Parameters + j;
- pCopy->Flags = p->Flags;
- /* copy state indexes */
- if (p->Type == PROGRAM_STATE_VAR) {
- GLint k;
- for (k = 0; k < STATE_LENGTH; k++) {
- pCopy->StateIndexes[k] = p->StateIndexes[k];
- }
- }
- else {
- clone->Parameters[j].Size = p->Size;
- }
-
- }
-
- clone->StateFlags = list->StateFlags;
-
- return clone;
-}
-
-
-/**
- * Return a new parameter list which is listA + listB.
- */
-struct gl_program_parameter_list *
-_mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA,
- const struct gl_program_parameter_list *listB)
-{
- struct gl_program_parameter_list *list;
-
- if (listA) {
- list = _mesa_clone_parameter_list(listA);
- if (list && listB) {
- GLuint i;
- for (i = 0; i < listB->NumParameters; i++) {
- struct gl_program_parameter *param = listB->Parameters + i;
- _mesa_add_parameter(list, param->Type, param->Name, param->Size,
- param->DataType,
- listB->ParameterValues[i],
- param->StateIndexes,
- param->Flags);
- }
- }
- }
- else if (listB) {
- list = _mesa_clone_parameter_list(listB);
- }
- else {
- list = NULL;
- }
- return list;
-}
-
-
-
-/**
- * Find longest name of all uniform parameters in list.
- */
-GLuint
-_mesa_longest_parameter_name(const struct gl_program_parameter_list *list,
- gl_register_file type)
-{
- GLuint i, maxLen = 0;
- if (!list)
- return 0;
- for (i = 0; i < list->NumParameters; i++) {
- if (list->Parameters[i].Type == type) {
- GLuint len = strlen(list->Parameters[i].Name);
- if (len > maxLen)
- maxLen = len;
- }
- }
- return maxLen;
-}
-
-
-/**
- * Count the number of parameters in the last that match the given type.
- */
-GLuint
-_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list,
- gl_register_file type)
-{
- GLuint i, count = 0;
- if (list) {
- for (i = 0; i < list->NumParameters; i++) {
- if (list->Parameters[i].Type == type)
- count++;
- }
- }
- return count;
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.3
+ *
+ * Copyright (C) 1999-2008 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_parameter.c
+ * Program parameter lists and functions.
+ * \author Brian Paul
+ */
+
+
+#include "main/glheader.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "prog_instruction.h"
+#include "prog_parameter.h"
+#include "prog_statevars.h"
+
+
+struct gl_program_parameter_list *
+_mesa_new_parameter_list(void)
+{
+ return CALLOC_STRUCT(gl_program_parameter_list);
+}
+
+
+struct gl_program_parameter_list *
+_mesa_new_parameter_list_sized(unsigned size)
+{
+ struct gl_program_parameter_list *p = _mesa_new_parameter_list();
+
+ if ((p != NULL) && (size != 0)) {
+ p->Size = size;
+
+ /* alloc arrays */
+ p->Parameters = (struct gl_program_parameter *)
+ calloc(1, size * sizeof(struct gl_program_parameter));
+
+ p->ParameterValues = (GLfloat (*)[4])
+ _mesa_align_malloc(size * 4 *sizeof(GLfloat), 16);
+
+
+ if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) {
+ free(p->Parameters);
+ _mesa_align_free(p->ParameterValues);
+ free(p);
+ p = NULL;
+ }
+ }
+
+ return p;
+}
+
+
+/**
+ * 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)
+ free((void *) paramList->Parameters[i].Name);
+ }
+ free(paramList->Parameters);
+ if (paramList->ParameterValues)
+ _mesa_align_free(paramList->ParameterValues);
+ free(paramList);
+}
+
+
+/**
+ * Add a new parameter to a parameter list.
+ * Note that parameter values are usually 4-element GLfloat vectors.
+ * When size > 4 we'll allocate a sequential block of parameters to
+ * store all the values (in blocks of 4).
+ *
+ * \param paramList the list to add the parameter to
+ * \param type type of parameter, such as
+ * \param name the parameter name, will be duplicated/copied!
+ * \param size number of elements in 'values' vector (1..4, or more)
+ * \param datatype GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE.
+ * \param values initial parameter value, up to 4 GLfloats, or NULL
+ * \param state state indexes, or NULL
+ * \return index of new parameter in the list, or -1 if error (out of mem)
+ */
+GLint
+_mesa_add_parameter(struct gl_program_parameter_list *paramList,
+ gl_register_file type, const char *name,
+ GLuint size, GLenum datatype, const GLfloat *values,
+ const gl_state_index state[STATE_LENGTH],
+ GLbitfield flags)
+{
+ const GLuint oldNum = paramList->NumParameters;
+ const GLuint sz4 = (size + 3) / 4; /* no. of new param slots needed */
+
+ assert(size > 0);
+
+ if (oldNum + sz4 > paramList->Size) {
+ /* Need to grow the parameter list array (alloc some extra) */
+ paramList->Size = paramList->Size + 4 * sz4;
+
+ /* realloc arrays */
+ paramList->Parameters = (struct gl_program_parameter *)
+ _mesa_realloc(paramList->Parameters,
+ oldNum * sizeof(struct gl_program_parameter),
+ paramList->Size * sizeof(struct gl_program_parameter));
+
+ paramList->ParameterValues = (GLfloat (*)[4])
+ _mesa_align_realloc(paramList->ParameterValues, /* old buf */
+ oldNum * 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 {
+ GLuint i;
+
+ paramList->NumParameters = oldNum + sz4;
+
+ memset(&paramList->Parameters[oldNum], 0,
+ sz4 * sizeof(struct gl_program_parameter));
+
+ for (i = 0; i < sz4; i++) {
+ struct gl_program_parameter *p = paramList->Parameters + oldNum + i;
+ p->Name = name ? _mesa_strdup(name) : NULL;
+ p->Type = type;
+ p->Size = size;
+ p->DataType = datatype;
+ p->Flags = flags;
+ if (values) {
+ COPY_4V(paramList->ParameterValues[oldNum + i], values);
+ values += 4;
+ p->Initialized = GL_TRUE;
+ }
+ else {
+ /* silence valgrind */
+ ASSIGN_4V(paramList->ParameterValues[oldNum + i], 0, 0, 0, 0);
+ }
+ size -= 4;
+ }
+
+ if (state) {
+ for (i = 0; i < STATE_LENGTH; i++)
+ paramList->Parameters[oldNum].StateIndexes[i] = state[i];
+ }
+
+ return (GLint) oldNum;
+ }
+}
+
+
+/**
+ * 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 _mesa_add_parameter(paramList, PROGRAM_NAMED_PARAM, name,
+ 4, GL_NONE, values, NULL, 0x0);
+
+}
+
+
+/**
+ * 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 name the name for the constant
+ * \param values four float values
+ * \return index/position of the new parameter in the parameter list
+ */
+GLint
+_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
+ const char *name, const GLfloat values[4],
+ GLuint size)
+{
+ /* first check if this is a duplicate constant */
+ GLint pos;
+ for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) {
+ const GLfloat *pvals = paramList->ParameterValues[pos];
+ if (pvals[0] == values[0] &&
+ pvals[1] == values[1] &&
+ pvals[2] == values[2] &&
+ pvals[3] == values[3] &&
+ strcmp(paramList->Parameters[pos].Name, name) == 0) {
+ /* Same name and value is already in the param list - reuse it */
+ return pos;
+ }
+ }
+ /* not found, add new parameter */
+ return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name,
+ size, GL_NONE, values, NULL, 0x0);
+}
+
+
+/**
+ * Add a new unnamed constant to the parameter list. This will be used
+ * when a fragment/vertex program contains something like this:
+ * MOV r, { 0, 1, 2, 3 };
+ * If swizzleOut is non-null we'll search the parameter list for an
+ * existing instance of the constant which matches with a swizzle.
+ *
+ * \param paramList the parameter list
+ * \param values four float values
+ * \param swizzleOut returns swizzle mask for accessing the constant
+ * \return index/position of the new parameter in the parameter list.
+ */
+GLint
+_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
+ const GLfloat values[4], GLuint size,
+ GLuint *swizzleOut)
+{
+ GLint pos;
+ ASSERT(size >= 1);
+ ASSERT(size <= 4);
+
+ if (swizzleOut &&
+ _mesa_lookup_parameter_constant(paramList, values,
+ size, &pos, swizzleOut)) {
+ return pos;
+ }
+
+ /* Look for empty space in an already unnamed constant parameter
+ * to add this constant. This will only work for single-element
+ * constants because we rely on smearing (i.e. .yyyy or .zzzz).
+ */
+ if (size == 1 && swizzleOut) {
+ for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) {
+ struct gl_program_parameter *p = paramList->Parameters + pos;
+ if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) {
+ /* ok, found room */
+ GLfloat *pVal = paramList->ParameterValues[pos];
+ GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */
+ pVal[p->Size] = values[0];
+ p->Size++;
+ *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz);
+ return pos;
+ }
+ }
+ }
+
+ /* add a new parameter to store this constant */
+ pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL,
+ size, GL_NONE, values, NULL, 0x0);
+ if (pos >= 0 && swizzleOut) {
+ if (size == 1)
+ *swizzleOut = SWIZZLE_XXXX;
+ else
+ *swizzleOut = SWIZZLE_NOOP;
+ }
+ return pos;
+}
+
+/**
+ * Add parameter representing a varying variable.
+ */
+GLint
+_mesa_add_varying(struct gl_program_parameter_list *paramList,
+ const char *name, GLuint size, GLenum datatype,
+ GLbitfield flags)
+{
+ GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
+ if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) {
+ /* already in list */
+ return i;
+ }
+ else {
+ /*assert(size == 4);*/
+ i = _mesa_add_parameter(paramList, PROGRAM_VARYING, name,
+ size, datatype, NULL, NULL, flags);
+ return i;
+ }
+}
+
+
+/**
+ * Add parameter representing a vertex program attribute.
+ * \param size size of attribute (in floats), may be -1 if unknown
+ * \param attrib the attribute index, or -1 if unknown
+ */
+GLint
+_mesa_add_attribute(struct gl_program_parameter_list *paramList,
+ const char *name, GLint size, GLenum datatype, GLint attrib)
+{
+ GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
+ if (i >= 0) {
+ /* replace */
+ if (attrib < 0)
+ attrib = i;
+ paramList->Parameters[i].StateIndexes[0] = attrib;
+ }
+ else {
+ /* add */
+ gl_state_index state[STATE_LENGTH];
+ state[0] = (gl_state_index) attrib;
+ if (size < 0)
+ size = 4;
+ i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name,
+ size, datatype, NULL, state, 0x0);
+ }
+ return i;
+}
+
+
+
+#if 0 /* not used yet */
+/**
+ * Returns the number of 4-component registers needed to store a piece
+ * of GL state. For matrices this may be as many as 4 registers,
+ * everything else needs
+ * just 1 register.
+ */
+static GLuint
+sizeof_state_reference(const GLint *stateTokens)
+{
+ if (stateTokens[0] == STATE_MATRIX) {
+ GLuint rows = stateTokens[4] - stateTokens[3] + 1;
+ assert(rows >= 1);
+ assert(rows <= 4);
+ return rows;
+ }
+ else {
+ return 1;
+ }
+}
+#endif
+
+
+/**
+ * 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 stateTokens an array of 5 (STATE_LENGTH) state tokens
+ * \return index of the new parameter.
+ */
+GLint
+_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
+ const gl_state_index stateTokens[STATE_LENGTH])
+{
+ const GLuint size = 4; /* XXX fix */
+ char *name;
+ GLint index;
+
+ /* Check if the state reference is already in the list */
+ for (index = 0; index < (GLint) paramList->NumParameters; index++) {
+ if (!memcmp(paramList->Parameters[index].StateIndexes,
+ stateTokens, STATE_LENGTH * sizeof(gl_state_index))) {
+ return index;
+ }
+ }
+
+ name = _mesa_program_state_string(stateTokens);
+ index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name,
+ size, GL_NONE,
+ NULL, (gl_state_index *) stateTokens, 0x0);
+ paramList->StateFlags |= _mesa_program_state_flags(stateTokens);
+
+ /* free name string here since we duplicated it in add_parameter() */
+ free(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(const struct gl_program_parameter_list *paramList,
+ GLsizei nameLen, const char *name)
+{
+ GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name);
+ if (i < 0)
+ return NULL;
+ else
+ return paramList->ParameterValues[i];
+}
+
+
+/**
+ * Given a program parameter name, find its position in the list of parameters.
+ * \param paramList the parameter list to search
+ * \param nameLen length of name (in chars).
+ * If length is negative, assume that name is null-terminated.
+ * \param name the name to search for
+ * \return index of parameter in the list.
+ */
+GLint
+_mesa_lookup_parameter_index(const 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 &&
+ 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 &&
+ strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
+ && strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * Look for a float vector in the given parameter list. The float vector
+ * may be of length 1, 2, 3 or 4. If swizzleOut is non-null, we'll try
+ * swizzling to find a match.
+ * \param list the parameter list to search
+ * \param v the float vector to search for
+ * \param vSize number of element in v
+ * \param posOut returns the position of the constant, if found
+ * \param swizzleOut returns a swizzle mask describing location of the
+ * vector elements if found.
+ * \return GL_TRUE if found, GL_FALSE if not found
+ */
+GLboolean
+_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list,
+ const GLfloat v[], GLuint vSize,
+ GLint *posOut, GLuint *swizzleOut)
+{
+ GLuint i;
+
+ assert(vSize >= 1);
+ assert(vSize <= 4);
+
+ if (!list) {
+ *posOut = -1;
+ return GL_FALSE;
+ }
+
+ for (i = 0; i < list->NumParameters; i++) {
+ if (list->Parameters[i].Type == PROGRAM_CONSTANT) {
+ if (!swizzleOut) {
+ /* swizzle not allowed */
+ GLuint j, match = 0;
+ for (j = 0; j < vSize; j++) {
+ if (v[j] == list->ParameterValues[i][j])
+ match++;
+ }
+ if (match == vSize) {
+ *posOut = i;
+ return GL_TRUE;
+ }
+ }
+ else {
+ /* try matching w/ swizzle */
+ if (vSize == 1) {
+ /* look for v[0] anywhere within float[4] value */
+ GLuint j;
+ for (j = 0; j < list->Parameters[i].Size; j++) {
+ if (list->ParameterValues[i][j] == v[0]) {
+ /* found it */
+ *posOut = i;
+ *swizzleOut = MAKE_SWIZZLE4(j, j, j, j);
+ return GL_TRUE;
+ }
+ }
+ }
+ else if (vSize <= list->Parameters[i].Size) {
+ /* see if we can match this constant (with a swizzle) */
+ GLuint swz[4];
+ GLuint match = 0, j, k;
+ for (j = 0; j < vSize; j++) {
+ if (v[j] == list->ParameterValues[i][j]) {
+ swz[j] = j;
+ match++;
+ }
+ else {
+ for (k = 0; k < list->Parameters[i].Size; k++) {
+ if (v[j] == list->ParameterValues[i][k]) {
+ swz[j] = k;
+ match++;
+ break;
+ }
+ }
+ }
+ }
+ /* smear last value to remaining positions */
+ for (; j < 4; j++)
+ swz[j] = swz[j-1];
+
+ if (match == vSize) {
+ *posOut = i;
+ *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
+ return GL_TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ *posOut = -1;
+ return GL_FALSE;
+}
+
+
+struct gl_program_parameter_list *
+_mesa_clone_parameter_list(const struct gl_program_parameter_list *list)
+{
+ struct gl_program_parameter_list *clone;
+ GLuint i;
+
+ clone = _mesa_new_parameter_list();
+ if (!clone)
+ return NULL;
+
+ /** Not too efficient, but correct */
+ for (i = 0; i < list->NumParameters; i++) {
+ struct gl_program_parameter *p = list->Parameters + i;
+ struct gl_program_parameter *pCopy;
+ GLuint size = MIN2(p->Size, 4);
+ GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType,
+ list->ParameterValues[i], NULL, 0x0);
+ ASSERT(j >= 0);
+ pCopy = clone->Parameters + j;
+ pCopy->Flags = p->Flags;
+ /* copy state indexes */
+ if (p->Type == PROGRAM_STATE_VAR) {
+ GLint k;
+ for (k = 0; k < STATE_LENGTH; k++) {
+ pCopy->StateIndexes[k] = p->StateIndexes[k];
+ }
+ }
+ else {
+ clone->Parameters[j].Size = p->Size;
+ }
+
+ }
+
+ clone->StateFlags = list->StateFlags;
+
+ return clone;
+}
+
+
+/**
+ * Return a new parameter list which is listA + listB.
+ */
+struct gl_program_parameter_list *
+_mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA,
+ const struct gl_program_parameter_list *listB)
+{
+ struct gl_program_parameter_list *list;
+
+ if (listA) {
+ list = _mesa_clone_parameter_list(listA);
+ if (list && listB) {
+ GLuint i;
+ for (i = 0; i < listB->NumParameters; i++) {
+ struct gl_program_parameter *param = listB->Parameters + i;
+ _mesa_add_parameter(list, param->Type, param->Name, param->Size,
+ param->DataType,
+ listB->ParameterValues[i],
+ param->StateIndexes,
+ param->Flags);
+ }
+ }
+ }
+ else if (listB) {
+ list = _mesa_clone_parameter_list(listB);
+ }
+ else {
+ list = NULL;
+ }
+ return list;
+}
+
+
+
+/**
+ * Find longest name of all uniform parameters in list.
+ */
+GLuint
+_mesa_longest_parameter_name(const struct gl_program_parameter_list *list,
+ gl_register_file type)
+{
+ GLuint i, maxLen = 0;
+ if (!list)
+ return 0;
+ for (i = 0; i < list->NumParameters; i++) {
+ if (list->Parameters[i].Type == type) {
+ GLuint len = strlen(list->Parameters[i].Name);
+ if (len > maxLen)
+ maxLen = len;
+ }
+ }
+ return maxLen;
+}
+
+
+/**
+ * Count the number of parameters in the last that match the given type.
+ */
+GLuint
+_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list,
+ gl_register_file type)
+{
+ GLuint i, count = 0;
+ if (list) {
+ for (i = 0; i < list->NumParameters; i++) {
+ if (list->Parameters[i].Type == type)
+ count++;
+ }
+ }
+ return count;
+}
diff --git a/mesalib/src/mesa/program/prog_print.c b/mesalib/src/mesa/program/prog_print.c
index 00aa6de96..de0ca1c4f 100644
--- a/mesalib/src/mesa/program/prog_print.c
+++ b/mesalib/src/mesa/program/prog_print.c
@@ -1,1086 +1,1084 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, 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_print.c
- * Print vertex/fragment programs - for debugging.
- * \author Brian Paul
- */
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_print.h"
-#include "prog_statevars.h"
-
-
-
-/**
- * Return string name for given program/register file.
- */
-static const char *
-file_string(gl_register_file f, gl_prog_print_mode mode)
-{
- 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_UNIFORM:
- return "UNIFORM";
- case PROGRAM_VARYING:
- return "VARYING";
- case PROGRAM_WRITE_ONLY:
- return "WRITE_ONLY";
- case PROGRAM_ADDRESS:
- return "ADDR";
- case PROGRAM_SAMPLER:
- return "SAMPLER";
- case PROGRAM_UNDEFINED:
- return "UNDEFINED";
- default:
- {
- static char s[20];
- _mesa_snprintf(s, sizeof(s), "FILE%u", f);
- return s;
- }
- }
-}
-
-
-/**
- * Return ARB_v/f_prog-style input attrib string.
- */
-static const char *
-arb_input_attrib_string(GLint index, GLenum progType)
-{
- /*
- * These strings should match the VERT_ATTRIB_x and FRAG_ATTRIB_x tokens.
- */
- const char *vertAttribs[] = {
- "vertex.position",
- "vertex.weight",
- "vertex.normal",
- "vertex.color.primary",
- "vertex.color.secondary",
- "vertex.fogcoord",
- "vertex.(six)",
- "vertex.(seven)",
- "vertex.texcoord[0]",
- "vertex.texcoord[1]",
- "vertex.texcoord[2]",
- "vertex.texcoord[3]",
- "vertex.texcoord[4]",
- "vertex.texcoord[5]",
- "vertex.texcoord[6]",
- "vertex.texcoord[7]",
- "vertex.attrib[0]",
- "vertex.attrib[1]",
- "vertex.attrib[2]",
- "vertex.attrib[3]",
- "vertex.attrib[4]",
- "vertex.attrib[5]",
- "vertex.attrib[6]",
- "vertex.attrib[7]",
- "vertex.attrib[8]",
- "vertex.attrib[9]",
- "vertex.attrib[10]",
- "vertex.attrib[11]",
- "vertex.attrib[12]",
- "vertex.attrib[13]",
- "vertex.attrib[14]",
- "vertex.attrib[15]"
- };
- const char *fragAttribs[] = {
- "fragment.position",
- "fragment.color.primary",
- "fragment.color.secondary",
- "fragment.fogcoord",
- "fragment.texcoord[0]",
- "fragment.texcoord[1]",
- "fragment.texcoord[2]",
- "fragment.texcoord[3]",
- "fragment.texcoord[4]",
- "fragment.texcoord[5]",
- "fragment.texcoord[6]",
- "fragment.texcoord[7]",
- "fragment.varying[0]",
- "fragment.varying[1]",
- "fragment.varying[2]",
- "fragment.varying[3]",
- "fragment.varying[4]",
- "fragment.varying[5]",
- "fragment.varying[6]",
- "fragment.varying[7]"
- };
-
- /* sanity checks */
- assert(strcmp(vertAttribs[VERT_ATTRIB_TEX0], "vertex.texcoord[0]") == 0);
- assert(strcmp(vertAttribs[VERT_ATTRIB_GENERIC15], "vertex.attrib[15]") == 0);
-
- if (progType == GL_VERTEX_PROGRAM_ARB) {
- assert(index < sizeof(vertAttribs) / sizeof(vertAttribs[0]));
- return vertAttribs[index];
- }
- else {
- assert(index < sizeof(fragAttribs) / sizeof(fragAttribs[0]));
- return fragAttribs[index];
- }
-}
-
-
-/**
- * Print a vertex program's InputsRead field in human-readable format.
- * For debugging.
- */
-void
-_mesa_print_vp_inputs(GLbitfield inputs)
-{
- printf("VP Inputs 0x%x: \n", inputs);
- while (inputs) {
- GLint attr = _mesa_ffs(inputs) - 1;
- const char *name = arb_input_attrib_string(attr,
- GL_VERTEX_PROGRAM_ARB);
- printf(" %d: %s\n", attr, name);
- inputs &= ~(1 << attr);
- }
-}
-
-
-/**
- * Print a fragment program's InputsRead field in human-readable format.
- * For debugging.
- */
-void
-_mesa_print_fp_inputs(GLbitfield inputs)
-{
- printf("FP Inputs 0x%x: \n", inputs);
- while (inputs) {
- GLint attr = _mesa_ffs(inputs) - 1;
- const char *name = arb_input_attrib_string(attr,
- GL_FRAGMENT_PROGRAM_ARB);
- printf(" %d: %s\n", attr, name);
- inputs &= ~(1 << attr);
- }
-}
-
-
-
-/**
- * Return ARB_v/f_prog-style output attrib string.
- */
-static const char *
-arb_output_attrib_string(GLint index, GLenum progType)
-{
- /*
- * These strings should match the VERT_RESULT_x and FRAG_RESULT_x tokens.
- */
- const char *vertResults[] = {
- "result.position",
- "result.color.primary",
- "result.color.secondary",
- "result.fogcoord",
- "result.texcoord[0]",
- "result.texcoord[1]",
- "result.texcoord[2]",
- "result.texcoord[3]",
- "result.texcoord[4]",
- "result.texcoord[5]",
- "result.texcoord[6]",
- "result.texcoord[7]",
- "result.varying[0]",
- "result.varying[1]",
- "result.varying[2]",
- "result.varying[3]",
- "result.varying[4]",
- "result.varying[5]",
- "result.varying[6]",
- "result.varying[7]"
- };
- const char *fragResults[] = {
- "result.color",
- "result.color(half)",
- "result.depth",
- "result.color[0]",
- "result.color[1]",
- "result.color[2]",
- "result.color[3]"
- };
-
- if (progType == GL_VERTEX_PROGRAM_ARB) {
- assert(index < sizeof(vertResults) / sizeof(vertResults[0]));
- return vertResults[index];
- }
- else {
- assert(index < sizeof(fragResults) / sizeof(fragResults[0]));
- return fragResults[index];
- }
-}
-
-
-/**
- * Return string representation of the given register.
- * Note that some types of registers (like PROGRAM_UNIFORM) aren't defined
- * by the ARB/NV program languages so we've taken some liberties here.
- * \param f the register file (PROGRAM_INPUT, PROGRAM_TEMPORARY, etc)
- * \param index number of the register in the register file
- * \param mode the output format/mode/style
- * \param prog pointer to containing program
- */
-static const char *
-reg_string(gl_register_file f, GLint index, gl_prog_print_mode mode,
- GLboolean relAddr, const struct gl_program *prog,
- GLboolean hasIndex2, GLboolean relAddr2, GLint index2)
-{
- static char str[100];
- const char *addr = relAddr ? "ADDR+" : "";
-
- str[0] = 0;
-
- switch (mode) {
- case PROG_PRINT_DEBUG:
- sprintf(str, "%s[%s%d]", file_string(f, mode), addr, index);
- if (hasIndex2) {
- int offset = strlen(str);
- const char *addr2 = relAddr2 ? "ADDR+" : "";
- sprintf(str+offset, "[%s%d]", addr2, index2);
- }
- break;
-
- case PROG_PRINT_ARB:
- switch (f) {
- case PROGRAM_INPUT:
- sprintf(str, "%s", arb_input_attrib_string(index, prog->Target));
- break;
- case PROGRAM_OUTPUT:
- sprintf(str, "%s", arb_output_attrib_string(index, prog->Target));
- break;
- case PROGRAM_TEMPORARY:
- sprintf(str, "temp%d", index);
- break;
- case PROGRAM_ENV_PARAM:
- sprintf(str, "program.env[%s%d]", addr, index);
- break;
- case PROGRAM_LOCAL_PARAM:
- sprintf(str, "program.local[%s%d]", addr, index);
- break;
- case PROGRAM_VARYING: /* extension */
- sprintf(str, "varying[%s%d]", addr, index);
- break;
- case PROGRAM_CONSTANT: /* extension */
- sprintf(str, "constant[%s%d]", addr, index);
- break;
- case PROGRAM_UNIFORM: /* extension */
- sprintf(str, "uniform[%s%d]", addr, index);
- break;
- case PROGRAM_STATE_VAR:
- {
- struct gl_program_parameter *param
- = prog->Parameters->Parameters + index;
- char *state = _mesa_program_state_string(param->StateIndexes);
- sprintf(str, "%s", state);
- free(state);
- }
- break;
- case PROGRAM_ADDRESS:
- sprintf(str, "A%d", index);
- break;
- default:
- _mesa_problem(NULL, "bad file in reg_string()");
- }
- break;
-
- case PROG_PRINT_NV:
- switch (f) {
- case PROGRAM_INPUT:
- if (prog->Target == GL_VERTEX_PROGRAM_ARB)
- sprintf(str, "v[%d]", index);
- else
- sprintf(str, "f[%d]", index);
- break;
- case PROGRAM_OUTPUT:
- sprintf(str, "o[%d]", index);
- break;
- case PROGRAM_TEMPORARY:
- sprintf(str, "R%d", index);
- break;
- case PROGRAM_ENV_PARAM:
- sprintf(str, "c[%d]", index);
- break;
- case PROGRAM_VARYING: /* extension */
- sprintf(str, "varying[%s%d]", addr, index);
- break;
- case PROGRAM_UNIFORM: /* extension */
- sprintf(str, "uniform[%s%d]", addr, index);
- break;
- case PROGRAM_CONSTANT: /* extension */
- sprintf(str, "constant[%s%d]", addr, index);
- break;
- case PROGRAM_STATE_VAR: /* extension */
- sprintf(str, "state[%s%d]", addr, index);
- break;
- default:
- _mesa_problem(NULL, "bad file in reg_string()");
- }
- break;
-
- default:
- _mesa_problem(NULL, "bad mode in reg_string()");
- }
-
- return str;
-}
-
-
-/**
- * Return a string representation of the given swizzle word.
- * If extended is true, use extended (comma-separated) format.
- * \param swizzle the swizzle field
- * \param negateBase 4-bit negation vector
- * \param extended if true, also allow 0, 1 values
- */
-const char *
-_mesa_swizzle_string(GLuint swizzle, GLuint negateMask, GLboolean extended)
-{
- static const char swz[] = "xyzw01!?"; /* See SWIZZLE_x definitions */
- static char s[20];
- GLuint i = 0;
-
- if (!extended && swizzle == SWIZZLE_NOOP && negateMask == 0)
- return ""; /* no swizzle/negation */
-
- if (!extended)
- s[i++] = '.';
-
- if (negateMask & NEGATE_X)
- s[i++] = '-';
- s[i++] = swz[GET_SWZ(swizzle, 0)];
-
- if (extended) {
- s[i++] = ',';
- }
-
- if (negateMask & NEGATE_Y)
- s[i++] = '-';
- s[i++] = swz[GET_SWZ(swizzle, 1)];
-
- if (extended) {
- s[i++] = ',';
- }
-
- if (negateMask & NEGATE_Z)
- s[i++] = '-';
- s[i++] = swz[GET_SWZ(swizzle, 2)];
-
- if (extended) {
- s[i++] = ',';
- }
-
- if (negateMask & NEGATE_W)
- s[i++] = '-';
- s[i++] = swz[GET_SWZ(swizzle, 3)];
-
- s[i] = 0;
- return s;
-}
-
-
-void
-_mesa_print_swizzle(GLuint swizzle)
-{
- if (swizzle == SWIZZLE_XYZW) {
- printf(".xyzw\n");
- }
- else {
- const char *s = _mesa_swizzle_string(swizzle, 0, 0);
- printf("%s\n", s);
- }
-}
-
-
-const char *
-_mesa_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;
-}
-
-
-const char *
-_mesa_condcode_string(GLuint condcode)
-{
- switch (condcode) {
- case COND_GT: return "GT";
- case COND_EQ: return "EQ";
- case COND_LT: return "LT";
- case COND_UN: return "UN";
- case COND_GE: return "GE";
- case COND_LE: return "LE";
- case COND_NE: return "NE";
- case COND_TR: return "TR";
- case COND_FL: return "FL";
- default: return "cond???";
- }
-}
-
-
-static void
-fprint_dst_reg(FILE * f,
- const struct prog_dst_register *dstReg,
- gl_prog_print_mode mode,
- const struct gl_program *prog)
-{
- fprintf(f, "%s%s",
- reg_string((gl_register_file) dstReg->File,
- dstReg->Index, mode, dstReg->RelAddr, prog,
- GL_FALSE, GL_FALSE, 0),
- _mesa_writemask_string(dstReg->WriteMask));
-
- if (dstReg->CondMask != COND_TR) {
- fprintf(f, " (%s.%s)",
- _mesa_condcode_string(dstReg->CondMask),
- _mesa_swizzle_string(dstReg->CondSwizzle,
- GL_FALSE, GL_FALSE));
- }
-
-#if 0
- fprintf(f, "%s[%d]%s",
- file_string((gl_register_file) dstReg->File, mode),
- dstReg->Index,
- _mesa_writemask_string(dstReg->WriteMask));
-#endif
-}
-
-
-static void
-fprint_src_reg(FILE *f,
- const struct prog_src_register *srcReg,
- gl_prog_print_mode mode,
- const struct gl_program *prog)
-{
- const char *abs = srcReg->Abs ? "|" : "";
-
- fprintf(f, "%s%s%s%s",
- abs,
- reg_string((gl_register_file) srcReg->File,
- srcReg->Index, mode, srcReg->RelAddr, prog,
- srcReg->HasIndex2, srcReg->RelAddr2, srcReg->Index2),
- _mesa_swizzle_string(srcReg->Swizzle,
- srcReg->Negate, GL_FALSE),
- abs);
-#if 0
- fprintf(f, "%s[%d]%s",
- file_string((gl_register_file) srcReg->File, mode),
- srcReg->Index,
- _mesa_swizzle_string(srcReg->Swizzle,
- srcReg->Negate, GL_FALSE));
-#endif
-}
-
-
-static void
-fprint_comment(FILE *f, const struct prog_instruction *inst)
-{
- if (inst->Comment)
- fprintf(f, "; # %s\n", inst->Comment);
- else
- fprintf(f, ";\n");
-}
-
-
-void
-_mesa_fprint_alu_instruction(FILE *f,
- const struct prog_instruction *inst,
- const char *opcode_string, GLuint numRegs,
- gl_prog_print_mode mode,
- const struct gl_program *prog)
-{
- GLuint j;
-
- fprintf(f, "%s", opcode_string);
- if (inst->CondUpdate)
- fprintf(f, ".C");
-
- /* frag prog only */
- if (inst->SaturateMode == SATURATE_ZERO_ONE)
- fprintf(f, "_SAT");
-
- fprintf(f, " ");
- if (inst->DstReg.File != PROGRAM_UNDEFINED) {
- fprint_dst_reg(f, &inst->DstReg, mode, prog);
- }
- else {
- fprintf(f, " ???");
- }
-
- if (numRegs > 0)
- fprintf(f, ", ");
-
- for (j = 0; j < numRegs; j++) {
- fprint_src_reg(f, inst->SrcReg + j, mode, prog);
- if (j + 1 < numRegs)
- fprintf(f, ", ");
- }
-
- fprint_comment(f, inst);
-}
-
-
-void
-_mesa_print_alu_instruction(const struct prog_instruction *inst,
- const char *opcode_string, GLuint numRegs)
-{
- _mesa_fprint_alu_instruction(stderr, inst, opcode_string,
- numRegs, PROG_PRINT_DEBUG, NULL);
-}
-
-
-/**
- * Print a single vertex/fragment program instruction.
- */
-GLint
-_mesa_fprint_instruction_opt(FILE *f,
- const struct prog_instruction *inst,
- GLint indent,
- gl_prog_print_mode mode,
- const struct gl_program *prog)
-{
- GLint i;
-
- if (inst->Opcode == OPCODE_ELSE ||
- inst->Opcode == OPCODE_ENDIF ||
- inst->Opcode == OPCODE_ENDLOOP ||
- inst->Opcode == OPCODE_ENDSUB) {
- indent -= 3;
- }
- for (i = 0; i < indent; i++) {
- fprintf(f, " ");
- }
-
- switch (inst->Opcode) {
- case OPCODE_PRINT:
- fprintf(f, "PRINT '%s'", (char *) inst->Data);
- if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
- fprintf(f, ", ");
- fprintf(f, "%s[%d]%s",
- file_string((gl_register_file) inst->SrcReg[0].File,
- mode),
- inst->SrcReg[0].Index,
- _mesa_swizzle_string(inst->SrcReg[0].Swizzle,
- inst->SrcReg[0].Negate, GL_FALSE));
- }
- if (inst->Comment)
- fprintf(f, " # %s", inst->Comment);
- fprint_comment(f, inst);
- break;
- case OPCODE_SWZ:
- fprintf(f, "SWZ");
- if (inst->SaturateMode == SATURATE_ZERO_ONE)
- fprintf(f, "_SAT");
- fprintf(f, " ");
- fprint_dst_reg(f, &inst->DstReg, mode, prog);
- fprintf(f, ", %s[%d], %s",
- file_string((gl_register_file) inst->SrcReg[0].File,
- mode),
- inst->SrcReg[0].Index,
- _mesa_swizzle_string(inst->SrcReg[0].Swizzle,
- inst->SrcReg[0].Negate, GL_TRUE));
- fprint_comment(f, inst);
- break;
- case OPCODE_TEX:
- case OPCODE_TXP:
- case OPCODE_TXL:
- case OPCODE_TXB:
- fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
- if (inst->SaturateMode == SATURATE_ZERO_ONE)
- fprintf(f, "_SAT");
- fprintf(f, " ");
- fprint_dst_reg(f, &inst->DstReg, mode, prog);
- fprintf(f, ", ");
- fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
- fprintf(f, ", texture[%d], ", inst->TexSrcUnit);
- switch (inst->TexSrcTarget) {
- case TEXTURE_1D_INDEX: fprintf(f, "1D"); break;
- case TEXTURE_2D_INDEX: fprintf(f, "2D"); break;
- case TEXTURE_3D_INDEX: fprintf(f, "3D"); break;
- case TEXTURE_CUBE_INDEX: fprintf(f, "CUBE"); break;
- case TEXTURE_RECT_INDEX: fprintf(f, "RECT"); break;
- case TEXTURE_1D_ARRAY_INDEX: fprintf(f, "1D_ARRAY"); break;
- case TEXTURE_2D_ARRAY_INDEX: fprintf(f, "2D_ARRAY"); break;
- default:
- ;
- }
- if (inst->TexShadow)
- fprintf(f, " SHADOW");
- fprint_comment(f, inst);
- break;
-
- case OPCODE_KIL:
- fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
- fprintf(f, " ");
- fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
- fprint_comment(f, inst);
- break;
- case OPCODE_KIL_NV:
- fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
- fprintf(f, " ");
- fprintf(f, "%s.%s",
- _mesa_condcode_string(inst->DstReg.CondMask),
- _mesa_swizzle_string(inst->DstReg.CondSwizzle,
- GL_FALSE, GL_FALSE));
- fprint_comment(f, inst);
- break;
-
- case OPCODE_ARL:
- fprintf(f, "ARL ");
- fprint_dst_reg(f, &inst->DstReg, mode, prog);
- fprintf(f, ", ");
- fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
- fprint_comment(f, inst);
- break;
- case OPCODE_BRA:
- fprintf(f, "BRA %d (%s%s)",
- inst->BranchTarget,
- _mesa_condcode_string(inst->DstReg.CondMask),
- _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
- fprint_comment(f, inst);
- break;
- case OPCODE_IF:
- if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
- /* Use ordinary register */
- fprintf(f, "IF ");
- fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
- fprintf(f, "; ");
- }
- else {
- /* Use cond codes */
- fprintf(f, "IF (%s%s);",
- _mesa_condcode_string(inst->DstReg.CondMask),
- _mesa_swizzle_string(inst->DstReg.CondSwizzle,
- 0, GL_FALSE));
- }
- fprintf(f, " # (if false, goto %d)", inst->BranchTarget);
- fprint_comment(f, inst);
- return indent + 3;
- case OPCODE_ELSE:
- fprintf(f, "ELSE; # (goto %d)\n", inst->BranchTarget);
- return indent + 3;
- case OPCODE_ENDIF:
- fprintf(f, "ENDIF;\n");
- break;
- case OPCODE_BGNLOOP:
- fprintf(f, "BGNLOOP; # (end at %d)\n", inst->BranchTarget);
- return indent + 3;
- case OPCODE_ENDLOOP:
- fprintf(f, "ENDLOOP; # (goto %d)\n", inst->BranchTarget);
- break;
- case OPCODE_BRK:
- case OPCODE_CONT:
- fprintf(f, "%s (%s%s); # (goto %d)",
- _mesa_opcode_string(inst->Opcode),
- _mesa_condcode_string(inst->DstReg.CondMask),
- _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
- inst->BranchTarget);
- fprint_comment(f, inst);
- break;
-
- case OPCODE_BGNSUB:
- if (mode == PROG_PRINT_NV) {
- fprintf(f, "%s:\n", inst->Comment); /* comment is label */
- return indent;
- }
- else {
- fprintf(f, "BGNSUB");
- fprint_comment(f, inst);
- return indent + 3;
- }
- case OPCODE_ENDSUB:
- if (mode == PROG_PRINT_DEBUG) {
- fprintf(f, "ENDSUB");
- fprint_comment(f, inst);
- }
- break;
- case OPCODE_CAL:
- if (mode == PROG_PRINT_NV) {
- fprintf(f, "CAL %s; # (goto %d)\n", inst->Comment, inst->BranchTarget);
- }
- else {
- fprintf(f, "CAL %u", inst->BranchTarget);
- fprint_comment(f, inst);
- }
- break;
- case OPCODE_RET:
- fprintf(f, "RET (%s%s)",
- _mesa_condcode_string(inst->DstReg.CondMask),
- _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
- fprint_comment(f, inst);
- break;
-
- case OPCODE_END:
- fprintf(f, "END\n");
- break;
- case OPCODE_NOP:
- if (mode == PROG_PRINT_DEBUG) {
- fprintf(f, "NOP");
- fprint_comment(f, inst);
- }
- else if (inst->Comment) {
- /* ARB/NV extensions don't have NOP instruction */
- fprintf(f, "# %s\n", inst->Comment);
- }
- break;
- case OPCODE_EMIT_VERTEX:
- fprintf(f, "EMIT_VERTEX\n");
- break;
- case OPCODE_END_PRIMITIVE:
- fprintf(f, "END_PRIMITIVE\n");
- break;
- /* XXX may need other special-case instructions */
- default:
- if (inst->Opcode < MAX_OPCODE) {
- /* typical alu instruction */
- _mesa_fprint_alu_instruction(f, inst,
- _mesa_opcode_string(inst->Opcode),
- _mesa_num_inst_src_regs(inst->Opcode),
- mode, prog);
- }
- else {
- _mesa_fprint_alu_instruction(f, inst,
- _mesa_opcode_string(inst->Opcode),
- 3/*_mesa_num_inst_src_regs(inst->Opcode)*/,
- mode, prog);
- }
- break;
- }
- return indent;
-}
-
-
-GLint
-_mesa_print_instruction_opt(const struct prog_instruction *inst,
- GLint indent,
- gl_prog_print_mode mode,
- const struct gl_program *prog)
-{
- return _mesa_fprint_instruction_opt(stderr, inst, indent, mode, prog);
-}
-
-
-void
-_mesa_print_instruction(const struct prog_instruction *inst)
-{
- /* note: 4th param should be ignored for PROG_PRINT_DEBUG */
- _mesa_fprint_instruction_opt(stderr, inst, 0, PROG_PRINT_DEBUG, NULL);
-}
-
-
-
-/**
- * Print program, with options.
- */
-void
-_mesa_fprint_program_opt(FILE *f,
- const struct gl_program *prog,
- gl_prog_print_mode mode,
- GLboolean lineNumbers)
-{
- GLuint i, indent = 0;
-
- switch (prog->Target) {
- case GL_VERTEX_PROGRAM_ARB:
- if (mode == PROG_PRINT_ARB)
- fprintf(f, "!!ARBvp1.0\n");
- else if (mode == PROG_PRINT_NV)
- fprintf(f, "!!VP1.0\n");
- else
- fprintf(f, "# Vertex Program/Shader %u\n", prog->Id);
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- case GL_FRAGMENT_PROGRAM_NV:
- if (mode == PROG_PRINT_ARB)
- fprintf(f, "!!ARBfp1.0\n");
- else if (mode == PROG_PRINT_NV)
- fprintf(f, "!!FP1.0\n");
- else
- fprintf(f, "# Fragment Program/Shader %u\n", prog->Id);
- break;
- case MESA_GEOMETRY_PROGRAM:
- fprintf(f, "# Geometry Shader\n");
- }
-
- for (i = 0; i < prog->NumInstructions; i++) {
- if (lineNumbers)
- fprintf(f, "%3d: ", i);
- indent = _mesa_fprint_instruction_opt(f, prog->Instructions + i,
- indent, mode, prog);
- }
-}
-
-
-/**
- * Print program to stderr, default options.
- */
-void
-_mesa_print_program(const struct gl_program *prog)
-{
- _mesa_fprint_program_opt(stderr, prog, PROG_PRINT_DEBUG, GL_TRUE);
-}
-
-
-/**
- * Return binary representation of 64-bit value (as a string).
- * Insert a comma to separate each group of 8 bits.
- * Note we return a pointer to local static storage so this is not
- * re-entrant, etc.
- * XXX move to imports.[ch] if useful elsewhere.
- */
-static const char *
-binary(GLbitfield64 val)
-{
- static char buf[80];
- GLint i, len = 0;
- for (i = 63; i >= 0; --i) {
- if (val & (BITFIELD64_BIT(i)))
- buf[len++] = '1';
- else if (len > 0 || i == 0)
- buf[len++] = '0';
- if (len > 0 && ((i-1) % 8) == 7)
- buf[len++] = ',';
- }
- buf[len] = '\0';
- return buf;
-}
-
-
-/**
- * Print all of a program's parameters/fields to given file.
- */
-static void
-_mesa_fprint_program_parameters(FILE *f,
- GLcontext *ctx,
- const struct gl_program *prog)
-{
- GLuint i;
-
- fprintf(f, "InputsRead: 0x%x (0b%s)\n",
- prog->InputsRead, binary(prog->InputsRead));
- fprintf(f, "OutputsWritten: 0x%llx (0b%s)\n",
- (unsigned long long)prog->OutputsWritten,
- binary(prog->OutputsWritten));
- fprintf(f, "NumInstructions=%d\n", prog->NumInstructions);
- fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries);
- fprintf(f, "NumParameters=%d\n", prog->NumParameters);
- fprintf(f, "NumAttributes=%d\n", prog->NumAttributes);
- fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs);
- fprintf(f, "IndirectRegisterFiles: 0x%x (0b%s)\n",
- prog->IndirectRegisterFiles, binary(prog->IndirectRegisterFiles));
- fprintf(f, "SamplersUsed: 0x%x (0b%s)\n",
- prog->SamplersUsed, binary(prog->SamplersUsed));
- fprintf(f, "Samplers=[ ");
- for (i = 0; i < MAX_SAMPLERS; i++) {
- fprintf(f, "%d ", prog->SamplerUnits[i]);
- }
- fprintf(f, "]\n");
-
- _mesa_load_state_parameters(ctx, prog->Parameters);
-
-#if 0
- fprintf(f, "Local Params:\n");
- for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){
- const GLfloat *p = prog->LocalParams[i];
- fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]);
- }
-#endif
- _mesa_print_parameter_list(prog->Parameters);
-}
-
-
-/**
- * Print all of a program's parameters/fields to stderr.
- */
-void
-_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog)
-{
- _mesa_fprint_program_parameters(stderr, ctx, prog);
-}
-
-
-/**
- * Print a program parameter list to given file.
- */
-static void
-_mesa_fprint_parameter_list(FILE *f,
- const struct gl_program_parameter_list *list)
-{
- const gl_prog_print_mode mode = PROG_PRINT_DEBUG;
- GLuint i;
-
- if (!list)
- return;
-
- if (0)
- fprintf(f, "param list %p\n", (void *) list);
- fprintf(f, "dirty state flags: 0x%x\n", list->StateFlags);
- for (i = 0; i < list->NumParameters; i++){
- struct gl_program_parameter *param = list->Parameters + i;
- const GLfloat *v = list->ParameterValues[i];
- fprintf(f, "param[%d] sz=%d %s %s = {%.3g, %.3g, %.3g, %.3g}",
- i, param->Size,
- file_string(list->Parameters[i].Type, mode),
- param->Name, v[0], v[1], v[2], v[3]);
- if (param->Flags & PROG_PARAM_BIT_CENTROID)
- fprintf(f, " Centroid");
- if (param->Flags & PROG_PARAM_BIT_INVARIANT)
- fprintf(f, " Invariant");
- if (param->Flags & PROG_PARAM_BIT_FLAT)
- fprintf(f, " Flat");
- if (param->Flags & PROG_PARAM_BIT_LINEAR)
- fprintf(f, " Linear");
- fprintf(f, "\n");
- }
-}
-
-
-/**
- * Print a program parameter list to stderr.
- */
-void
-_mesa_print_parameter_list(const struct gl_program_parameter_list *list)
-{
- _mesa_fprint_parameter_list(stderr, list);
-}
-
-
-/**
- * Write shader and associated info to a file.
- */
-void
-_mesa_write_shader_to_file(const struct gl_shader *shader)
-{
- const char *type;
- char filename[100];
- FILE *f;
-
- if (shader->Type == GL_FRAGMENT_SHADER)
- type = "frag";
- else if (shader->Type == GL_VERTEX_SHADER)
- type = "vert";
- else
- type = "geom";
-
- _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type);
- f = fopen(filename, "w");
- if (!f) {
- fprintf(stderr, "Unable to open %s for writing\n", filename);
- return;
- }
-
- fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum);
- fputs(shader->Source, f);
- fprintf(f, "\n");
-
- fprintf(f, "/* Compile status: %s */\n",
- shader->CompileStatus ? "ok" : "fail");
- fprintf(f, "/* Log Info: */\n");
- if (shader->InfoLog) {
- fputs(shader->InfoLog, f);
- }
- if (shader->CompileStatus && shader->Program) {
- fprintf(f, "/* GPU code */\n");
- fprintf(f, "/*\n");
- _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE);
- fprintf(f, "*/\n");
- fprintf(f, "/* Parameters / constants */\n");
- fprintf(f, "/*\n");
- _mesa_fprint_parameter_list(f, shader->Program->Parameters);
- fprintf(f, "*/\n");
- }
-
- fclose(f);
-}
-
-
-/**
- * Append the shader's uniform info/values to the shader log file.
- * The log file will typically have been created by the
- * _mesa_write_shader_to_file function.
- */
-void
-_mesa_append_uniforms_to_file(const struct gl_shader *shader,
- const struct gl_program *prog)
-{
- const char *type;
- char filename[100];
- FILE *f;
-
- if (shader->Type == GL_FRAGMENT_SHADER)
- type = "frag";
- else
- type = "vert";
-
- _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type);
- f = fopen(filename, "a"); /* append */
- if (!f) {
- fprintf(stderr, "Unable to open %s for appending\n", filename);
- return;
- }
-
- fprintf(f, "/* First-draw parameters / constants */\n");
- fprintf(f, "/*\n");
- _mesa_fprint_parameter_list(f, prog->Parameters);
- fprintf(f, "*/\n");
-
- fclose(f);
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.3
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, 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_print.c
+ * Print vertex/fragment programs - for debugging.
+ * \author Brian Paul
+ */
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "prog_instruction.h"
+#include "prog_parameter.h"
+#include "prog_print.h"
+#include "prog_statevars.h"
+
+
+
+/**
+ * Return string name for given program/register file.
+ */
+const char *
+_mesa_register_file_name(gl_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_UNIFORM:
+ return "UNIFORM";
+ case PROGRAM_VARYING:
+ return "VARYING";
+ case PROGRAM_WRITE_ONLY:
+ return "WRITE_ONLY";
+ case PROGRAM_ADDRESS:
+ return "ADDR";
+ case PROGRAM_SAMPLER:
+ return "SAMPLER";
+ case PROGRAM_UNDEFINED:
+ return "UNDEFINED";
+ default:
+ {
+ static char s[20];
+ _mesa_snprintf(s, sizeof(s), "FILE%u", f);
+ return s;
+ }
+ }
+}
+
+
+/**
+ * Return ARB_v/f_prog-style input attrib string.
+ */
+static const char *
+arb_input_attrib_string(GLint index, GLenum progType)
+{
+ /*
+ * These strings should match the VERT_ATTRIB_x and FRAG_ATTRIB_x tokens.
+ */
+ const char *vertAttribs[] = {
+ "vertex.position",
+ "vertex.weight",
+ "vertex.normal",
+ "vertex.color.primary",
+ "vertex.color.secondary",
+ "vertex.fogcoord",
+ "vertex.(six)",
+ "vertex.(seven)",
+ "vertex.texcoord[0]",
+ "vertex.texcoord[1]",
+ "vertex.texcoord[2]",
+ "vertex.texcoord[3]",
+ "vertex.texcoord[4]",
+ "vertex.texcoord[5]",
+ "vertex.texcoord[6]",
+ "vertex.texcoord[7]",
+ "vertex.attrib[0]",
+ "vertex.attrib[1]",
+ "vertex.attrib[2]",
+ "vertex.attrib[3]",
+ "vertex.attrib[4]",
+ "vertex.attrib[5]",
+ "vertex.attrib[6]",
+ "vertex.attrib[7]",
+ "vertex.attrib[8]",
+ "vertex.attrib[9]",
+ "vertex.attrib[10]",
+ "vertex.attrib[11]",
+ "vertex.attrib[12]",
+ "vertex.attrib[13]",
+ "vertex.attrib[14]",
+ "vertex.attrib[15]"
+ };
+ const char *fragAttribs[] = {
+ "fragment.position",
+ "fragment.color.primary",
+ "fragment.color.secondary",
+ "fragment.fogcoord",
+ "fragment.texcoord[0]",
+ "fragment.texcoord[1]",
+ "fragment.texcoord[2]",
+ "fragment.texcoord[3]",
+ "fragment.texcoord[4]",
+ "fragment.texcoord[5]",
+ "fragment.texcoord[6]",
+ "fragment.texcoord[7]",
+ "fragment.varying[0]",
+ "fragment.varying[1]",
+ "fragment.varying[2]",
+ "fragment.varying[3]",
+ "fragment.varying[4]",
+ "fragment.varying[5]",
+ "fragment.varying[6]",
+ "fragment.varying[7]"
+ };
+
+ /* sanity checks */
+ assert(strcmp(vertAttribs[VERT_ATTRIB_TEX0], "vertex.texcoord[0]") == 0);
+ assert(strcmp(vertAttribs[VERT_ATTRIB_GENERIC15], "vertex.attrib[15]") == 0);
+
+ if (progType == GL_VERTEX_PROGRAM_ARB) {
+ assert(index < sizeof(vertAttribs) / sizeof(vertAttribs[0]));
+ return vertAttribs[index];
+ }
+ else {
+ assert(index < sizeof(fragAttribs) / sizeof(fragAttribs[0]));
+ return fragAttribs[index];
+ }
+}
+
+
+/**
+ * Print a vertex program's InputsRead field in human-readable format.
+ * For debugging.
+ */
+void
+_mesa_print_vp_inputs(GLbitfield inputs)
+{
+ printf("VP Inputs 0x%x: \n", inputs);
+ while (inputs) {
+ GLint attr = _mesa_ffs(inputs) - 1;
+ const char *name = arb_input_attrib_string(attr,
+ GL_VERTEX_PROGRAM_ARB);
+ printf(" %d: %s\n", attr, name);
+ inputs &= ~(1 << attr);
+ }
+}
+
+
+/**
+ * Print a fragment program's InputsRead field in human-readable format.
+ * For debugging.
+ */
+void
+_mesa_print_fp_inputs(GLbitfield inputs)
+{
+ printf("FP Inputs 0x%x: \n", inputs);
+ while (inputs) {
+ GLint attr = _mesa_ffs(inputs) - 1;
+ const char *name = arb_input_attrib_string(attr,
+ GL_FRAGMENT_PROGRAM_ARB);
+ printf(" %d: %s\n", attr, name);
+ inputs &= ~(1 << attr);
+ }
+}
+
+
+
+/**
+ * Return ARB_v/f_prog-style output attrib string.
+ */
+static const char *
+arb_output_attrib_string(GLint index, GLenum progType)
+{
+ /*
+ * These strings should match the VERT_RESULT_x and FRAG_RESULT_x tokens.
+ */
+ const char *vertResults[] = {
+ "result.position",
+ "result.color.primary",
+ "result.color.secondary",
+ "result.fogcoord",
+ "result.texcoord[0]",
+ "result.texcoord[1]",
+ "result.texcoord[2]",
+ "result.texcoord[3]",
+ "result.texcoord[4]",
+ "result.texcoord[5]",
+ "result.texcoord[6]",
+ "result.texcoord[7]",
+ "result.varying[0]",
+ "result.varying[1]",
+ "result.varying[2]",
+ "result.varying[3]",
+ "result.varying[4]",
+ "result.varying[5]",
+ "result.varying[6]",
+ "result.varying[7]"
+ };
+ const char *fragResults[] = {
+ "result.color",
+ "result.color(half)",
+ "result.depth",
+ "result.color[0]",
+ "result.color[1]",
+ "result.color[2]",
+ "result.color[3]"
+ };
+
+ if (progType == GL_VERTEX_PROGRAM_ARB) {
+ assert(index < sizeof(vertResults) / sizeof(vertResults[0]));
+ return vertResults[index];
+ }
+ else {
+ assert(index < sizeof(fragResults) / sizeof(fragResults[0]));
+ return fragResults[index];
+ }
+}
+
+
+/**
+ * Return string representation of the given register.
+ * Note that some types of registers (like PROGRAM_UNIFORM) aren't defined
+ * by the ARB/NV program languages so we've taken some liberties here.
+ * \param f the register file (PROGRAM_INPUT, PROGRAM_TEMPORARY, etc)
+ * \param index number of the register in the register file
+ * \param mode the output format/mode/style
+ * \param prog pointer to containing program
+ */
+static const char *
+reg_string(gl_register_file f, GLint index, gl_prog_print_mode mode,
+ GLboolean relAddr, const struct gl_program *prog,
+ GLboolean hasIndex2, GLboolean relAddr2, GLint index2)
+{
+ static char str[100];
+ const char *addr = relAddr ? "ADDR+" : "";
+
+ str[0] = 0;
+
+ switch (mode) {
+ case PROG_PRINT_DEBUG:
+ sprintf(str, "%s[%s%d]",
+ _mesa_register_file_name(f), addr, index);
+ if (hasIndex2) {
+ int offset = strlen(str);
+ const char *addr2 = relAddr2 ? "ADDR+" : "";
+ sprintf(str+offset, "[%s%d]", addr2, index2);
+ }
+ break;
+
+ case PROG_PRINT_ARB:
+ switch (f) {
+ case PROGRAM_INPUT:
+ sprintf(str, "%s", arb_input_attrib_string(index, prog->Target));
+ break;
+ case PROGRAM_OUTPUT:
+ sprintf(str, "%s", arb_output_attrib_string(index, prog->Target));
+ break;
+ case PROGRAM_TEMPORARY:
+ sprintf(str, "temp%d", index);
+ break;
+ case PROGRAM_ENV_PARAM:
+ sprintf(str, "program.env[%s%d]", addr, index);
+ break;
+ case PROGRAM_LOCAL_PARAM:
+ sprintf(str, "program.local[%s%d]", addr, index);
+ break;
+ case PROGRAM_VARYING: /* extension */
+ sprintf(str, "varying[%s%d]", addr, index);
+ break;
+ case PROGRAM_CONSTANT: /* extension */
+ sprintf(str, "constant[%s%d]", addr, index);
+ break;
+ case PROGRAM_UNIFORM: /* extension */
+ sprintf(str, "uniform[%s%d]", addr, index);
+ break;
+ case PROGRAM_STATE_VAR:
+ {
+ struct gl_program_parameter *param
+ = prog->Parameters->Parameters + index;
+ char *state = _mesa_program_state_string(param->StateIndexes);
+ sprintf(str, "%s", state);
+ free(state);
+ }
+ break;
+ case PROGRAM_ADDRESS:
+ sprintf(str, "A%d", index);
+ break;
+ default:
+ _mesa_problem(NULL, "bad file in reg_string()");
+ }
+ break;
+
+ case PROG_PRINT_NV:
+ switch (f) {
+ case PROGRAM_INPUT:
+ if (prog->Target == GL_VERTEX_PROGRAM_ARB)
+ sprintf(str, "v[%d]", index);
+ else
+ sprintf(str, "f[%d]", index);
+ break;
+ case PROGRAM_OUTPUT:
+ sprintf(str, "o[%d]", index);
+ break;
+ case PROGRAM_TEMPORARY:
+ sprintf(str, "R%d", index);
+ break;
+ case PROGRAM_ENV_PARAM:
+ sprintf(str, "c[%d]", index);
+ break;
+ case PROGRAM_VARYING: /* extension */
+ sprintf(str, "varying[%s%d]", addr, index);
+ break;
+ case PROGRAM_UNIFORM: /* extension */
+ sprintf(str, "uniform[%s%d]", addr, index);
+ break;
+ case PROGRAM_CONSTANT: /* extension */
+ sprintf(str, "constant[%s%d]", addr, index);
+ break;
+ case PROGRAM_STATE_VAR: /* extension */
+ sprintf(str, "state[%s%d]", addr, index);
+ break;
+ default:
+ _mesa_problem(NULL, "bad file in reg_string()");
+ }
+ break;
+
+ default:
+ _mesa_problem(NULL, "bad mode in reg_string()");
+ }
+
+ return str;
+}
+
+
+/**
+ * Return a string representation of the given swizzle word.
+ * If extended is true, use extended (comma-separated) format.
+ * \param swizzle the swizzle field
+ * \param negateBase 4-bit negation vector
+ * \param extended if true, also allow 0, 1 values
+ */
+const char *
+_mesa_swizzle_string(GLuint swizzle, GLuint negateMask, GLboolean extended)
+{
+ static const char swz[] = "xyzw01!?"; /* See SWIZZLE_x definitions */
+ static char s[20];
+ GLuint i = 0;
+
+ if (!extended && swizzle == SWIZZLE_NOOP && negateMask == 0)
+ return ""; /* no swizzle/negation */
+
+ if (!extended)
+ s[i++] = '.';
+
+ if (negateMask & NEGATE_X)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 0)];
+
+ if (extended) {
+ s[i++] = ',';
+ }
+
+ if (negateMask & NEGATE_Y)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 1)];
+
+ if (extended) {
+ s[i++] = ',';
+ }
+
+ if (negateMask & NEGATE_Z)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 2)];
+
+ if (extended) {
+ s[i++] = ',';
+ }
+
+ if (negateMask & NEGATE_W)
+ s[i++] = '-';
+ s[i++] = swz[GET_SWZ(swizzle, 3)];
+
+ s[i] = 0;
+ return s;
+}
+
+
+void
+_mesa_print_swizzle(GLuint swizzle)
+{
+ if (swizzle == SWIZZLE_XYZW) {
+ printf(".xyzw\n");
+ }
+ else {
+ const char *s = _mesa_swizzle_string(swizzle, 0, 0);
+ printf("%s\n", s);
+ }
+}
+
+
+const char *
+_mesa_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;
+}
+
+
+const char *
+_mesa_condcode_string(GLuint condcode)
+{
+ switch (condcode) {
+ case COND_GT: return "GT";
+ case COND_EQ: return "EQ";
+ case COND_LT: return "LT";
+ case COND_UN: return "UN";
+ case COND_GE: return "GE";
+ case COND_LE: return "LE";
+ case COND_NE: return "NE";
+ case COND_TR: return "TR";
+ case COND_FL: return "FL";
+ default: return "cond???";
+ }
+}
+
+
+static void
+fprint_dst_reg(FILE * f,
+ const struct prog_dst_register *dstReg,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog)
+{
+ fprintf(f, "%s%s",
+ reg_string((gl_register_file) dstReg->File,
+ dstReg->Index, mode, dstReg->RelAddr, prog,
+ GL_FALSE, GL_FALSE, 0),
+ _mesa_writemask_string(dstReg->WriteMask));
+
+ if (dstReg->CondMask != COND_TR) {
+ fprintf(f, " (%s.%s)",
+ _mesa_condcode_string(dstReg->CondMask),
+ _mesa_swizzle_string(dstReg->CondSwizzle,
+ GL_FALSE, GL_FALSE));
+ }
+
+#if 0
+ fprintf(f, "%s[%d]%s",
+ _mesa_register_file_name((gl_register_file) dstReg->File),
+ dstReg->Index,
+ _mesa_writemask_string(dstReg->WriteMask));
+#endif
+}
+
+
+static void
+fprint_src_reg(FILE *f,
+ const struct prog_src_register *srcReg,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog)
+{
+ const char *abs = srcReg->Abs ? "|" : "";
+
+ fprintf(f, "%s%s%s%s",
+ abs,
+ reg_string((gl_register_file) srcReg->File,
+ srcReg->Index, mode, srcReg->RelAddr, prog,
+ srcReg->HasIndex2, srcReg->RelAddr2, srcReg->Index2),
+ _mesa_swizzle_string(srcReg->Swizzle,
+ srcReg->Negate, GL_FALSE),
+ abs);
+#if 0
+ fprintf(f, "%s[%d]%s",
+ _mesa_register_file_name((gl_register_file) srcReg->File),
+ srcReg->Index,
+ _mesa_swizzle_string(srcReg->Swizzle,
+ srcReg->Negate, GL_FALSE));
+#endif
+}
+
+
+static void
+fprint_comment(FILE *f, const struct prog_instruction *inst)
+{
+ if (inst->Comment)
+ fprintf(f, "; # %s\n", inst->Comment);
+ else
+ fprintf(f, ";\n");
+}
+
+
+void
+_mesa_fprint_alu_instruction(FILE *f,
+ const struct prog_instruction *inst,
+ const char *opcode_string, GLuint numRegs,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog)
+{
+ GLuint j;
+
+ fprintf(f, "%s", opcode_string);
+ if (inst->CondUpdate)
+ fprintf(f, ".C");
+
+ /* frag prog only */
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ fprintf(f, "_SAT");
+
+ fprintf(f, " ");
+ if (inst->DstReg.File != PROGRAM_UNDEFINED) {
+ fprint_dst_reg(f, &inst->DstReg, mode, prog);
+ }
+ else {
+ fprintf(f, " ???");
+ }
+
+ if (numRegs > 0)
+ fprintf(f, ", ");
+
+ for (j = 0; j < numRegs; j++) {
+ fprint_src_reg(f, inst->SrcReg + j, mode, prog);
+ if (j + 1 < numRegs)
+ fprintf(f, ", ");
+ }
+
+ fprint_comment(f, inst);
+}
+
+
+void
+_mesa_print_alu_instruction(const struct prog_instruction *inst,
+ const char *opcode_string, GLuint numRegs)
+{
+ _mesa_fprint_alu_instruction(stderr, inst, opcode_string,
+ numRegs, PROG_PRINT_DEBUG, NULL);
+}
+
+
+/**
+ * Print a single vertex/fragment program instruction.
+ */
+GLint
+_mesa_fprint_instruction_opt(FILE *f,
+ const struct prog_instruction *inst,
+ GLint indent,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog)
+{
+ GLint i;
+
+ if (inst->Opcode == OPCODE_ELSE ||
+ inst->Opcode == OPCODE_ENDIF ||
+ inst->Opcode == OPCODE_ENDLOOP ||
+ inst->Opcode == OPCODE_ENDSUB) {
+ indent -= 3;
+ }
+ for (i = 0; i < indent; i++) {
+ fprintf(f, " ");
+ }
+
+ switch (inst->Opcode) {
+ case OPCODE_PRINT:
+ fprintf(f, "PRINT '%s'", (char *) inst->Data);
+ if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+ fprintf(f, ", ");
+ fprintf(f, "%s[%d]%s",
+ _mesa_register_file_name((gl_register_file) inst->SrcReg[0].File),
+ inst->SrcReg[0].Index,
+ _mesa_swizzle_string(inst->SrcReg[0].Swizzle,
+ inst->SrcReg[0].Negate, GL_FALSE));
+ }
+ if (inst->Comment)
+ fprintf(f, " # %s", inst->Comment);
+ fprint_comment(f, inst);
+ break;
+ case OPCODE_SWZ:
+ fprintf(f, "SWZ");
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ fprintf(f, "_SAT");
+ fprintf(f, " ");
+ fprint_dst_reg(f, &inst->DstReg, mode, prog);
+ fprintf(f, ", %s[%d], %s",
+ _mesa_register_file_name((gl_register_file) inst->SrcReg[0].File),
+ inst->SrcReg[0].Index,
+ _mesa_swizzle_string(inst->SrcReg[0].Swizzle,
+ inst->SrcReg[0].Negate, GL_TRUE));
+ fprint_comment(f, inst);
+ break;
+ case OPCODE_TEX:
+ case OPCODE_TXP:
+ case OPCODE_TXL:
+ case OPCODE_TXB:
+ fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ fprintf(f, "_SAT");
+ fprintf(f, " ");
+ fprint_dst_reg(f, &inst->DstReg, mode, prog);
+ fprintf(f, ", ");
+ fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+ fprintf(f, ", texture[%d], ", inst->TexSrcUnit);
+ switch (inst->TexSrcTarget) {
+ case TEXTURE_1D_INDEX: fprintf(f, "1D"); break;
+ case TEXTURE_2D_INDEX: fprintf(f, "2D"); break;
+ case TEXTURE_3D_INDEX: fprintf(f, "3D"); break;
+ case TEXTURE_CUBE_INDEX: fprintf(f, "CUBE"); break;
+ case TEXTURE_RECT_INDEX: fprintf(f, "RECT"); break;
+ case TEXTURE_1D_ARRAY_INDEX: fprintf(f, "1D_ARRAY"); break;
+ case TEXTURE_2D_ARRAY_INDEX: fprintf(f, "2D_ARRAY"); break;
+ default:
+ ;
+ }
+ if (inst->TexShadow)
+ fprintf(f, " SHADOW");
+ fprint_comment(f, inst);
+ break;
+
+ case OPCODE_KIL:
+ fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
+ fprintf(f, " ");
+ fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+ fprint_comment(f, inst);
+ break;
+ case OPCODE_KIL_NV:
+ fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
+ fprintf(f, " ");
+ fprintf(f, "%s.%s",
+ _mesa_condcode_string(inst->DstReg.CondMask),
+ _mesa_swizzle_string(inst->DstReg.CondSwizzle,
+ GL_FALSE, GL_FALSE));
+ fprint_comment(f, inst);
+ break;
+
+ case OPCODE_ARL:
+ fprintf(f, "ARL ");
+ fprint_dst_reg(f, &inst->DstReg, mode, prog);
+ fprintf(f, ", ");
+ fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+ fprint_comment(f, inst);
+ break;
+ case OPCODE_BRA:
+ fprintf(f, "BRA %d (%s%s)",
+ inst->BranchTarget,
+ _mesa_condcode_string(inst->DstReg.CondMask),
+ _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
+ fprint_comment(f, inst);
+ break;
+ case OPCODE_IF:
+ if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+ /* Use ordinary register */
+ fprintf(f, "IF ");
+ fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+ fprintf(f, "; ");
+ }
+ else {
+ /* Use cond codes */
+ fprintf(f, "IF (%s%s);",
+ _mesa_condcode_string(inst->DstReg.CondMask),
+ _mesa_swizzle_string(inst->DstReg.CondSwizzle,
+ 0, GL_FALSE));
+ }
+ fprintf(f, " # (if false, goto %d)", inst->BranchTarget);
+ fprint_comment(f, inst);
+ return indent + 3;
+ case OPCODE_ELSE:
+ fprintf(f, "ELSE; # (goto %d)\n", inst->BranchTarget);
+ return indent + 3;
+ case OPCODE_ENDIF:
+ fprintf(f, "ENDIF;\n");
+ break;
+ case OPCODE_BGNLOOP:
+ fprintf(f, "BGNLOOP; # (end at %d)\n", inst->BranchTarget);
+ return indent + 3;
+ case OPCODE_ENDLOOP:
+ fprintf(f, "ENDLOOP; # (goto %d)\n", inst->BranchTarget);
+ break;
+ case OPCODE_BRK:
+ case OPCODE_CONT:
+ fprintf(f, "%s (%s%s); # (goto %d)",
+ _mesa_opcode_string(inst->Opcode),
+ _mesa_condcode_string(inst->DstReg.CondMask),
+ _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
+ inst->BranchTarget);
+ fprint_comment(f, inst);
+ break;
+
+ case OPCODE_BGNSUB:
+ if (mode == PROG_PRINT_NV) {
+ fprintf(f, "%s:\n", inst->Comment); /* comment is label */
+ return indent;
+ }
+ else {
+ fprintf(f, "BGNSUB");
+ fprint_comment(f, inst);
+ return indent + 3;
+ }
+ case OPCODE_ENDSUB:
+ if (mode == PROG_PRINT_DEBUG) {
+ fprintf(f, "ENDSUB");
+ fprint_comment(f, inst);
+ }
+ break;
+ case OPCODE_CAL:
+ if (mode == PROG_PRINT_NV) {
+ fprintf(f, "CAL %s; # (goto %d)\n", inst->Comment, inst->BranchTarget);
+ }
+ else {
+ fprintf(f, "CAL %u", inst->BranchTarget);
+ fprint_comment(f, inst);
+ }
+ break;
+ case OPCODE_RET:
+ fprintf(f, "RET (%s%s)",
+ _mesa_condcode_string(inst->DstReg.CondMask),
+ _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
+ fprint_comment(f, inst);
+ break;
+
+ case OPCODE_END:
+ fprintf(f, "END\n");
+ break;
+ case OPCODE_NOP:
+ if (mode == PROG_PRINT_DEBUG) {
+ fprintf(f, "NOP");
+ fprint_comment(f, inst);
+ }
+ else if (inst->Comment) {
+ /* ARB/NV extensions don't have NOP instruction */
+ fprintf(f, "# %s\n", inst->Comment);
+ }
+ break;
+ case OPCODE_EMIT_VERTEX:
+ fprintf(f, "EMIT_VERTEX\n");
+ break;
+ case OPCODE_END_PRIMITIVE:
+ fprintf(f, "END_PRIMITIVE\n");
+ break;
+ /* XXX may need other special-case instructions */
+ default:
+ if (inst->Opcode < MAX_OPCODE) {
+ /* typical alu instruction */
+ _mesa_fprint_alu_instruction(f, inst,
+ _mesa_opcode_string(inst->Opcode),
+ _mesa_num_inst_src_regs(inst->Opcode),
+ mode, prog);
+ }
+ else {
+ _mesa_fprint_alu_instruction(f, inst,
+ _mesa_opcode_string(inst->Opcode),
+ 3/*_mesa_num_inst_src_regs(inst->Opcode)*/,
+ mode, prog);
+ }
+ break;
+ }
+ return indent;
+}
+
+
+GLint
+_mesa_print_instruction_opt(const struct prog_instruction *inst,
+ GLint indent,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog)
+{
+ return _mesa_fprint_instruction_opt(stderr, inst, indent, mode, prog);
+}
+
+
+void
+_mesa_print_instruction(const struct prog_instruction *inst)
+{
+ /* note: 4th param should be ignored for PROG_PRINT_DEBUG */
+ _mesa_fprint_instruction_opt(stderr, inst, 0, PROG_PRINT_DEBUG, NULL);
+}
+
+
+
+/**
+ * Print program, with options.
+ */
+void
+_mesa_fprint_program_opt(FILE *f,
+ const struct gl_program *prog,
+ gl_prog_print_mode mode,
+ GLboolean lineNumbers)
+{
+ GLuint i, indent = 0;
+
+ switch (prog->Target) {
+ case GL_VERTEX_PROGRAM_ARB:
+ if (mode == PROG_PRINT_ARB)
+ fprintf(f, "!!ARBvp1.0\n");
+ else if (mode == PROG_PRINT_NV)
+ fprintf(f, "!!VP1.0\n");
+ else
+ fprintf(f, "# Vertex Program/Shader %u\n", prog->Id);
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ case GL_FRAGMENT_PROGRAM_NV:
+ if (mode == PROG_PRINT_ARB)
+ fprintf(f, "!!ARBfp1.0\n");
+ else if (mode == PROG_PRINT_NV)
+ fprintf(f, "!!FP1.0\n");
+ else
+ fprintf(f, "# Fragment Program/Shader %u\n", prog->Id);
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ fprintf(f, "# Geometry Shader\n");
+ }
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ if (lineNumbers)
+ fprintf(f, "%3d: ", i);
+ indent = _mesa_fprint_instruction_opt(f, prog->Instructions + i,
+ indent, mode, prog);
+ }
+}
+
+
+/**
+ * Print program to stderr, default options.
+ */
+void
+_mesa_print_program(const struct gl_program *prog)
+{
+ _mesa_fprint_program_opt(stderr, prog, PROG_PRINT_DEBUG, GL_TRUE);
+}
+
+
+/**
+ * Return binary representation of 64-bit value (as a string).
+ * Insert a comma to separate each group of 8 bits.
+ * Note we return a pointer to local static storage so this is not
+ * re-entrant, etc.
+ * XXX move to imports.[ch] if useful elsewhere.
+ */
+static const char *
+binary(GLbitfield64 val)
+{
+ static char buf[80];
+ GLint i, len = 0;
+ for (i = 63; i >= 0; --i) {
+ if (val & (BITFIELD64_BIT(i)))
+ buf[len++] = '1';
+ else if (len > 0 || i == 0)
+ buf[len++] = '0';
+ if (len > 0 && ((i-1) % 8) == 7)
+ buf[len++] = ',';
+ }
+ buf[len] = '\0';
+ return buf;
+}
+
+
+/**
+ * Print all of a program's parameters/fields to given file.
+ */
+static void
+_mesa_fprint_program_parameters(FILE *f,
+ struct gl_context *ctx,
+ const struct gl_program *prog)
+{
+ GLuint i;
+
+ fprintf(f, "InputsRead: 0x%x (0b%s)\n",
+ prog->InputsRead, binary(prog->InputsRead));
+ fprintf(f, "OutputsWritten: 0x%llx (0b%s)\n",
+ (unsigned long long)prog->OutputsWritten,
+ binary(prog->OutputsWritten));
+ fprintf(f, "NumInstructions=%d\n", prog->NumInstructions);
+ fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries);
+ fprintf(f, "NumParameters=%d\n", prog->NumParameters);
+ fprintf(f, "NumAttributes=%d\n", prog->NumAttributes);
+ fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs);
+ fprintf(f, "IndirectRegisterFiles: 0x%x (0b%s)\n",
+ prog->IndirectRegisterFiles, binary(prog->IndirectRegisterFiles));
+ fprintf(f, "SamplersUsed: 0x%x (0b%s)\n",
+ prog->SamplersUsed, binary(prog->SamplersUsed));
+ fprintf(f, "Samplers=[ ");
+ for (i = 0; i < MAX_SAMPLERS; i++) {
+ fprintf(f, "%d ", prog->SamplerUnits[i]);
+ }
+ fprintf(f, "]\n");
+
+ _mesa_load_state_parameters(ctx, prog->Parameters);
+
+#if 0
+ fprintf(f, "Local Params:\n");
+ for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){
+ const GLfloat *p = prog->LocalParams[i];
+ fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]);
+ }
+#endif
+ _mesa_print_parameter_list(prog->Parameters);
+}
+
+
+/**
+ * Print all of a program's parameters/fields to stderr.
+ */
+void
+_mesa_print_program_parameters(struct gl_context *ctx, const struct gl_program *prog)
+{
+ _mesa_fprint_program_parameters(stderr, ctx, prog);
+}
+
+
+/**
+ * Print a program parameter list to given file.
+ */
+static void
+_mesa_fprint_parameter_list(FILE *f,
+ const struct gl_program_parameter_list *list)
+{
+ GLuint i;
+
+ if (!list)
+ return;
+
+ if (0)
+ fprintf(f, "param list %p\n", (void *) list);
+ fprintf(f, "dirty state flags: 0x%x\n", list->StateFlags);
+ for (i = 0; i < list->NumParameters; i++){
+ struct gl_program_parameter *param = list->Parameters + i;
+ const GLfloat *v = list->ParameterValues[i];
+ fprintf(f, "param[%d] sz=%d %s %s = {%.3g, %.3g, %.3g, %.3g}",
+ i, param->Size,
+ _mesa_register_file_name(list->Parameters[i].Type),
+ param->Name, v[0], v[1], v[2], v[3]);
+ if (param->Flags & PROG_PARAM_BIT_CENTROID)
+ fprintf(f, " Centroid");
+ if (param->Flags & PROG_PARAM_BIT_INVARIANT)
+ fprintf(f, " Invariant");
+ if (param->Flags & PROG_PARAM_BIT_FLAT)
+ fprintf(f, " Flat");
+ if (param->Flags & PROG_PARAM_BIT_LINEAR)
+ fprintf(f, " Linear");
+ fprintf(f, "\n");
+ }
+}
+
+
+/**
+ * Print a program parameter list to stderr.
+ */
+void
+_mesa_print_parameter_list(const struct gl_program_parameter_list *list)
+{
+ _mesa_fprint_parameter_list(stderr, list);
+}
+
+
+/**
+ * Write shader and associated info to a file.
+ */
+void
+_mesa_write_shader_to_file(const struct gl_shader *shader)
+{
+ const char *type;
+ char filename[100];
+ FILE *f;
+
+ if (shader->Type == GL_FRAGMENT_SHADER)
+ type = "frag";
+ else if (shader->Type == GL_VERTEX_SHADER)
+ type = "vert";
+ else
+ type = "geom";
+
+ _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type);
+ f = fopen(filename, "w");
+ if (!f) {
+ fprintf(stderr, "Unable to open %s for writing\n", filename);
+ return;
+ }
+
+ fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum);
+ fputs(shader->Source, f);
+ fprintf(f, "\n");
+
+ fprintf(f, "/* Compile status: %s */\n",
+ shader->CompileStatus ? "ok" : "fail");
+ fprintf(f, "/* Log Info: */\n");
+ if (shader->InfoLog) {
+ fputs(shader->InfoLog, f);
+ }
+ if (shader->CompileStatus && shader->Program) {
+ fprintf(f, "/* GPU code */\n");
+ fprintf(f, "/*\n");
+ _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE);
+ fprintf(f, "*/\n");
+ fprintf(f, "/* Parameters / constants */\n");
+ fprintf(f, "/*\n");
+ _mesa_fprint_parameter_list(f, shader->Program->Parameters);
+ fprintf(f, "*/\n");
+ }
+
+ fclose(f);
+}
+
+
+/**
+ * Append the shader's uniform info/values to the shader log file.
+ * The log file will typically have been created by the
+ * _mesa_write_shader_to_file function.
+ */
+void
+_mesa_append_uniforms_to_file(const struct gl_shader *shader,
+ const struct gl_program *prog)
+{
+ const char *type;
+ char filename[100];
+ FILE *f;
+
+ if (shader->Type == GL_FRAGMENT_SHADER)
+ type = "frag";
+ else
+ type = "vert";
+
+ _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type);
+ f = fopen(filename, "a"); /* append */
+ if (!f) {
+ fprintf(stderr, "Unable to open %s for appending\n", filename);
+ return;
+ }
+
+ fprintf(f, "/* First-draw parameters / constants */\n");
+ fprintf(f, "/*\n");
+ _mesa_fprint_parameter_list(f, prog->Parameters);
+ fprintf(f, "*/\n");
+
+ fclose(f);
+}
diff --git a/mesalib/src/mesa/program/prog_print.h b/mesalib/src/mesa/program/prog_print.h
index 78b90aeb4..caeedb779 100644
--- a/mesalib/src/mesa/program/prog_print.h
+++ b/mesalib/src/mesa/program/prog_print.h
@@ -1,117 +1,120 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.3
- *
- * Copyright (C) 1999-2007 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 PROG_PRINT_H
-#define PROG_PRINT_H
-
-#include <stdio.h>
-
-#include "main/glheader.h"
-#include "main/mtypes.h"
-
-struct gl_program;
-struct gl_program_parameter_list;
-struct gl_shader;
-struct prog_instruction;
-
-
-/**
- * The output style to use when printing programs.
- */
-typedef enum {
- PROG_PRINT_ARB,
- PROG_PRINT_NV,
- PROG_PRINT_DEBUG
-} gl_prog_print_mode;
-
-
-extern void
-_mesa_print_vp_inputs(GLbitfield inputs);
-
-extern void
-_mesa_print_fp_inputs(GLbitfield inputs);
-
-extern const char *
-_mesa_condcode_string(GLuint condcode);
-
-extern const char *
-_mesa_swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended);
-
-const char *
-_mesa_writemask_string(GLuint writeMask);
-
-extern void
-_mesa_print_swizzle(GLuint swizzle);
-
-extern void
-_mesa_fprint_alu_instruction(FILE *f,
- const struct prog_instruction *inst,
- const char *opcode_string, GLuint numRegs,
- gl_prog_print_mode mode,
- const struct gl_program *prog);
-
-extern void
-_mesa_print_alu_instruction(const struct prog_instruction *inst,
- const char *opcode_string, GLuint numRegs);
-
-extern void
-_mesa_print_instruction(const struct prog_instruction *inst);
-
-extern GLint
-_mesa_fprint_instruction_opt(FILE *f,
- const struct prog_instruction *inst,
- GLint indent,
- gl_prog_print_mode mode,
- const struct gl_program *prog);
-
-extern GLint
-_mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent,
- gl_prog_print_mode mode,
- const struct gl_program *prog);
-
-extern void
-_mesa_print_program(const struct gl_program *prog);
-
-extern void
-_mesa_fprint_program_opt(FILE *f,
- const struct gl_program *prog, gl_prog_print_mode mode,
- GLboolean lineNumbers);
-
-extern void
-_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog);
-
-extern void
-_mesa_print_parameter_list(const struct gl_program_parameter_list *list);
-
-
-extern void
-_mesa_write_shader_to_file(const struct gl_shader *shader);
-
-extern void
-_mesa_append_uniforms_to_file(const struct gl_shader *shader,
- const struct gl_program *prog);
-
-
-#endif /* PROG_PRINT_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.3
+ *
+ * Copyright (C) 1999-2007 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 PROG_PRINT_H
+#define PROG_PRINT_H
+
+#include <stdio.h>
+
+#include "main/glheader.h"
+#include "main/mtypes.h"
+
+struct gl_program;
+struct gl_program_parameter_list;
+struct gl_shader;
+struct prog_instruction;
+
+
+/**
+ * The output style to use when printing programs.
+ */
+typedef enum {
+ PROG_PRINT_ARB,
+ PROG_PRINT_NV,
+ PROG_PRINT_DEBUG
+} gl_prog_print_mode;
+
+
+extern const char *
+_mesa_register_file_name(gl_register_file f);
+
+extern void
+_mesa_print_vp_inputs(GLbitfield inputs);
+
+extern void
+_mesa_print_fp_inputs(GLbitfield inputs);
+
+extern const char *
+_mesa_condcode_string(GLuint condcode);
+
+extern const char *
+_mesa_swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended);
+
+const char *
+_mesa_writemask_string(GLuint writeMask);
+
+extern void
+_mesa_print_swizzle(GLuint swizzle);
+
+extern void
+_mesa_fprint_alu_instruction(FILE *f,
+ const struct prog_instruction *inst,
+ const char *opcode_string, GLuint numRegs,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog);
+
+extern void
+_mesa_print_alu_instruction(const struct prog_instruction *inst,
+ const char *opcode_string, GLuint numRegs);
+
+extern void
+_mesa_print_instruction(const struct prog_instruction *inst);
+
+extern GLint
+_mesa_fprint_instruction_opt(FILE *f,
+ const struct prog_instruction *inst,
+ GLint indent,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog);
+
+extern GLint
+_mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent,
+ gl_prog_print_mode mode,
+ const struct gl_program *prog);
+
+extern void
+_mesa_print_program(const struct gl_program *prog);
+
+extern void
+_mesa_fprint_program_opt(FILE *f,
+ const struct gl_program *prog, gl_prog_print_mode mode,
+ GLboolean lineNumbers);
+
+extern void
+_mesa_print_program_parameters(struct gl_context *ctx, const struct gl_program *prog);
+
+extern void
+_mesa_print_parameter_list(const struct gl_program_parameter_list *list);
+
+
+extern void
+_mesa_write_shader_to_file(const struct gl_shader *shader);
+
+extern void
+_mesa_append_uniforms_to_file(const struct gl_shader *shader,
+ const struct gl_program *prog);
+
+
+#endif /* PROG_PRINT_H */
diff --git a/mesalib/src/mesa/program/prog_statevars.c b/mesalib/src/mesa/program/prog_statevars.c
index 2687f8ae2..df3c76d18 100644
--- a/mesalib/src/mesa/program/prog_statevars.c
+++ b/mesalib/src/mesa/program/prog_statevars.c
@@ -1,1189 +1,1182 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2007 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_statevars.c
- * Program state variable management.
- * \author Brian Paul
- */
-
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "main/mtypes.h"
-#include "prog_statevars.h"
-#include "prog_parameter.h"
-
-
-/**
- * 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 gl_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];
- const struct gl_material *mat = &ctx->Light.Material;
- ASSERT(face == 0 || face == 1);
- /* we rely on tokens numbered so that _BACK_ == _FRONT_+ 1 */
- ASSERT(MAT_ATTRIB_FRONT_AMBIENT + 1 == MAT_ATTRIB_BACK_AMBIENT);
- /* XXX we could get rid of this switch entirely with a little
- * work in arbprogparse.c's parse_state_single_item().
- */
- /* state[2] is the material attribute */
- switch (state[2]) {
- case STATE_AMBIENT:
- COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_AMBIENT + face]);
- return;
- case STATE_DIFFUSE:
- COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_DIFFUSE + face]);
- return;
- case STATE_SPECULAR:
- COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_SPECULAR + face]);
- return;
- case STATE_EMISSION:
- COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_EMISSION + face]);
- return;
- case STATE_SHININESS:
- value[0] = mat->Attrib[MAT_ATTRIB_FRONT_SHININESS + face][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].SpotDirection);
- value[3] = ctx->Light.Light[ln]._CosCutoff;
- return;
- case STATE_SPOT_CUTOFF:
- value[0] = ctx->Light.Light[ln].SpotCutoff;
- return;
- case STATE_HALF_VECTOR:
- {
- static const GLfloat eye_z[] = {0, 0, 1};
- GLfloat p[3];
- /* Compute infinite half angle vector:
- * halfVector = normalize(normalize(lightPos) + (0, 0, 1))
- * light.EyePosition.w should be 0 for infinite lights.
- */
- COPY_3V(p, ctx->Light.Light[ln].EyePosition);
- NORMALIZE_3FV(p);
- ADD_3V(value, p, eye_z);
- NORMALIZE_3FV(value);
- value[3] = 1.0;
- }
- 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_AMBIENT+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_SPECULAR+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].GenS.EyePlane);
- return;
- case STATE_TEXGEN_EYE_T:
- COPY_4V(value, ctx->Texture.Unit[unit].GenT.EyePlane);
- return;
- case STATE_TEXGEN_EYE_R:
- COPY_4V(value, ctx->Texture.Unit[unit].GenR.EyePlane);
- return;
- case STATE_TEXGEN_EYE_Q:
- COPY_4V(value, ctx->Texture.Unit[unit].GenQ.EyePlane);
- return;
- case STATE_TEXGEN_OBJECT_S:
- COPY_4V(value, ctx->Texture.Unit[unit].GenS.ObjectPlane);
- return;
- case STATE_TEXGEN_OBJECT_T:
- COPY_4V(value, ctx->Texture.Unit[unit].GenT.ObjectPlane);
- return;
- case STATE_TEXGEN_OBJECT_R:
- COPY_4V(value, ctx->Texture.Unit[unit].GenR.ObjectPlane);
- return;
- case STATE_TEXGEN_OBJECT_Q:
- COPY_4V(value, ctx->Texture.Unit[unit].GenQ.ObjectPlane);
- 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] = (ctx->Fog.End == ctx->Fog.Start)
- ? 1.0f : (GLfloat)(1.0 / (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_MODELVIEW_MATRIX:
- case STATE_PROJECTION_MATRIX:
- case STATE_MVP_MATRIX:
- case STATE_TEXTURE_MATRIX:
- case STATE_PROGRAM_MATRIX:
- case STATE_COLOR_MATRIX:
- {
- /* state[0] = modelview, projection, texture, etc. */
- /* state[1] = which texture matrix or program matrix */
- /* state[2] = first row to fetch */
- /* state[3] = last row to fetch */
- /* state[4] = transpose, inverse or invtrans */
- const GLmatrix *matrix;
- const gl_state_index mat = state[0];
- const GLuint index = (GLuint) state[1];
- const GLuint firstRow = (GLuint) state[2];
- const GLuint lastRow = (GLuint) state[3];
- const gl_state_index modifier = state[4];
- const GLfloat *m;
- GLuint row, i;
- ASSERT(firstRow >= 0);
- ASSERT(firstRow < 4);
- ASSERT(lastRow >= 0);
- ASSERT(lastRow < 4);
- if (mat == STATE_MODELVIEW_MATRIX) {
- matrix = ctx->ModelviewMatrixStack.Top;
- }
- else if (mat == STATE_PROJECTION_MATRIX) {
- matrix = ctx->ProjectionMatrixStack.Top;
- }
- else if (mat == STATE_MVP_MATRIX) {
- matrix = &ctx->_ModelProjectMatrix;
- }
- else if (mat == STATE_TEXTURE_MATRIX) {
- ASSERT(index < Elements(ctx->TextureMatrixStack));
- matrix = ctx->TextureMatrixStack[index].Top;
- }
- else if (mat == STATE_PROGRAM_MATRIX) {
- ASSERT(index < Elements(ctx->ProgramMatrixStack));
- matrix = ctx->ProgramMatrixStack[index].Top;
- }
- else if (mat == STATE_COLOR_MATRIX) {
- matrix = ctx->ColorMatrixStack.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 = firstRow; row <= lastRow; 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 = firstRow; row <= lastRow; 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] = 1.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]);
- return;
- case STATE_LOCAL:
- COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
- return;
- 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]);
- return;
- case STATE_LOCAL:
- COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
- return;
- default:
- _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
- return;
- }
- }
- return;
-
- case STATE_NORMAL_SCALE:
- ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
- return;
-
- case STATE_INTERNAL:
- switch (state[1]) {
- case STATE_CURRENT_ATTRIB:
- {
- const GLuint idx = (GLuint) state[2];
- COPY_4V(value, ctx->Current.Attrib[idx]);
- }
- return;
-
- case STATE_NORMAL_SCALE:
- ASSIGN_4V(value,
- ctx->_ModelViewInvScale,
- ctx->_ModelViewInvScale,
- ctx->_ModelViewInvScale,
- 1);
- return;
-
- case STATE_TEXRECT_SCALE:
- /* Value = { 1/texWidth, 1/texHeight, 0, 1 }.
- * Used to convert unnormalized texcoords to normalized texcoords.
- */
- {
- const int unit = (int) state[2];
- const struct gl_texture_object *texObj
- = ctx->Texture.Unit[unit]._Current;
- if (texObj) {
- struct gl_texture_image *texImage = texObj->Image[0][0];
- ASSIGN_4V(value,
- (GLfloat) (1.0 / texImage->Width),
- (GLfloat) (1.0 / texImage->Height),
- 0.0f, 1.0f);
- }
- }
- return;
-
- case STATE_FOG_PARAMS_OPTIMIZED:
- /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog)
- * might be more expensive than EX2 on some hw, plus it needs
- * another constant (e) anyway. Linear fog can now be done with a
- * single MAD.
- * linear: fogcoord * -1/(end-start) + end/(end-start)
- * exp: 2^-(density/ln(2) * fogcoord)
- * exp2: 2^-((density/(ln(2)^2) * fogcoord)^2)
- */
- value[0] = (ctx->Fog.End == ctx->Fog.Start)
- ? 1.0f : (GLfloat)(-1.0F / (ctx->Fog.End - ctx->Fog.Start));
- value[1] = ctx->Fog.End * -value[0];
- value[2] = (GLfloat)(ctx->Fog.Density * ONE_DIV_LN2);
- value[3] = (GLfloat)(ctx->Fog.Density * ONE_DIV_SQRT_LN2);
- return;
-
- case STATE_POINT_SIZE_CLAMPED:
- {
- /* this includes implementation dependent limits, to avoid
- * another potentially necessary clamp.
- * Note: for sprites, point smooth (point AA) is ignored
- * and we'll clamp to MinPointSizeAA and MaxPointSize, because we
- * expect drivers will want to say their minimum for AA size is 0.0
- * but for non-AA it's 1.0 (because normal points with size below 1.0
- * need to get rounded up to 1.0, hence never disappear). GL does
- * not specify max clamp size for sprites, other than it needs to be
- * at least as large as max AA size, hence use non-AA size there.
- */
- GLfloat minImplSize;
- GLfloat maxImplSize;
- if (ctx->Point.PointSprite) {
- minImplSize = ctx->Const.MinPointSizeAA;
- maxImplSize = ctx->Const.MaxPointSize;
- }
- else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) {
- minImplSize = ctx->Const.MinPointSizeAA;
- maxImplSize = ctx->Const.MaxPointSizeAA;
- }
- else {
- minImplSize = ctx->Const.MinPointSize;
- maxImplSize = ctx->Const.MaxPointSize;
- }
- value[0] = ctx->Point.Size;
- value[1] = ctx->Point.MinSize >= minImplSize ? ctx->Point.MinSize : minImplSize;
- value[2] = ctx->Point.MaxSize <= maxImplSize ? ctx->Point.MaxSize : maxImplSize;
- value[3] = ctx->Point.Threshold;
- }
- return;
- case STATE_POINT_SIZE_IMPL_CLAMP:
- {
- /* for implementation clamp only in vs */
- GLfloat minImplSize;
- GLfloat maxImplSize;
- if (ctx->Point.PointSprite) {
- minImplSize = ctx->Const.MinPointSizeAA;
- maxImplSize = ctx->Const.MaxPointSize;
- }
- else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) {
- minImplSize = ctx->Const.MinPointSizeAA;
- maxImplSize = ctx->Const.MaxPointSizeAA;
- }
- else {
- minImplSize = ctx->Const.MinPointSize;
- maxImplSize = ctx->Const.MaxPointSize;
- }
- value[0] = ctx->Point.Size;
- value[1] = minImplSize;
- value[2] = maxImplSize;
- value[3] = ctx->Point.Threshold;
- }
- return;
- case STATE_LIGHT_SPOT_DIR_NORMALIZED:
- {
- /* here, state[2] is the light number */
- /* pre-normalize spot dir */
- const GLuint ln = (GLuint) state[2];
- COPY_3V(value, ctx->Light.Light[ln]._NormSpotDirection);
- value[3] = ctx->Light.Light[ln]._CosCutoff;
- }
- return;
-
- case STATE_LIGHT_POSITION:
- {
- const GLuint ln = (GLuint) state[2];
- COPY_4V(value, ctx->Light.Light[ln]._Position);
- }
- return;
-
- case STATE_LIGHT_POSITION_NORMALIZED:
- {
- const GLuint ln = (GLuint) state[2];
- COPY_4V(value, ctx->Light.Light[ln]._Position);
- NORMALIZE_3FV( value );
- }
- return;
-
- case STATE_LIGHT_HALF_VECTOR:
- {
- const GLuint ln = (GLuint) state[2];
- GLfloat p[3];
- /* Compute infinite half angle vector:
- * halfVector = normalize(normalize(lightPos) + (0, 0, 1))
- * light.EyePosition.w should be 0 for infinite lights.
- */
- COPY_3V(p, ctx->Light.Light[ln]._Position);
- NORMALIZE_3FV(p);
- ADD_3V(value, p, ctx->_EyeZDir);
- NORMALIZE_3FV(value);
- value[3] = 1.0;
- }
- return;
-
- case STATE_PT_SCALE:
- value[0] = ctx->Pixel.RedScale;
- value[1] = ctx->Pixel.GreenScale;
- value[2] = ctx->Pixel.BlueScale;
- value[3] = ctx->Pixel.AlphaScale;
- return;
-
- case STATE_PT_BIAS:
- value[0] = ctx->Pixel.RedBias;
- value[1] = ctx->Pixel.GreenBias;
- value[2] = ctx->Pixel.BlueBias;
- value[3] = ctx->Pixel.AlphaBias;
- return;
-
- case STATE_PCM_SCALE:
- COPY_4V(value, ctx->Pixel.PostColorMatrixScale);
- return;
-
- case STATE_PCM_BIAS:
- COPY_4V(value, ctx->Pixel.PostColorMatrixBias);
- return;
-
- case STATE_SHADOW_AMBIENT:
- {
- const int unit = (int) state[2];
- const struct gl_texture_object *texObj
- = ctx->Texture.Unit[unit]._Current;
- if (texObj) {
- value[0] =
- value[1] =
- value[2] =
- value[3] = texObj->CompareFailValue;
- }
- }
- return;
-
- case STATE_FB_SIZE:
- value[0] = (GLfloat) (ctx->DrawBuffer->Width - 1);
- value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1);
- value[2] = 0.0F;
- value[3] = 0.0F;
- return;
-
- case STATE_ROT_MATRIX_0:
- {
- const int unit = (int) state[2];
- GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix;
- value[0] = rotMat22[0];
- value[1] = rotMat22[2];
- value[2] = 0.0;
- value[3] = 0.0;
- }
- return;
-
- case STATE_ROT_MATRIX_1:
- {
- const int unit = (int) state[2];
- GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix;
- value[0] = rotMat22[1];
- value[1] = rotMat22[3];
- value[2] = 0.0;
- value[3] = 0.0;
- }
- return;
-
- /* XXX: make sure new tokens added here are also handled in the
- * _mesa_program_state_flags() switch, below.
- */
- default:
- /* Unknown state indexes are silently ignored here.
- * Drivers may do something special.
- */
- return;
- }
- return;
-
- default:
- _mesa_problem(ctx, "Invalid state in _mesa_fetch_state");
- return;
- }
-}
-
-
-/**
- * Return a bitmask of the Mesa state flags (_NEW_* values) which would
- * indicate that the given context state may have changed.
- * The bitmask is used during validation to determine if we need to update
- * vertex/fragment program parameters (like "state.material.color") when
- * some GL state has changed.
- */
-GLbitfield
-_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH])
-{
- 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_MODELVIEW_MATRIX:
- return _NEW_MODELVIEW;
- case STATE_PROJECTION_MATRIX:
- return _NEW_PROJECTION;
- case STATE_MVP_MATRIX:
- return _NEW_MODELVIEW | _NEW_PROJECTION;
- case STATE_TEXTURE_MATRIX:
- return _NEW_TEXTURE_MATRIX;
- case STATE_PROGRAM_MATRIX:
- return _NEW_TRACK_MATRIX;
- case STATE_COLOR_MATRIX:
- return _NEW_COLOR_MATRIX;
-
- case STATE_DEPTH_RANGE:
- return _NEW_VIEWPORT;
-
- case STATE_FRAGMENT_PROGRAM:
- case STATE_VERTEX_PROGRAM:
- return _NEW_PROGRAM;
-
- case STATE_NORMAL_SCALE:
- return _NEW_MODELVIEW;
-
- case STATE_INTERNAL:
- switch (state[1]) {
- case STATE_CURRENT_ATTRIB:
- return _NEW_CURRENT_ATTRIB;
-
- case STATE_NORMAL_SCALE:
- return _NEW_MODELVIEW;
-
- case STATE_TEXRECT_SCALE:
- case STATE_SHADOW_AMBIENT:
- case STATE_ROT_MATRIX_0:
- case STATE_ROT_MATRIX_1:
- return _NEW_TEXTURE;
- case STATE_FOG_PARAMS_OPTIMIZED:
- return _NEW_FOG;
- case STATE_POINT_SIZE_CLAMPED:
- case STATE_POINT_SIZE_IMPL_CLAMP:
- return _NEW_POINT | _NEW_MULTISAMPLE;
- case STATE_LIGHT_SPOT_DIR_NORMALIZED:
- case STATE_LIGHT_POSITION:
- case STATE_LIGHT_POSITION_NORMALIZED:
- case STATE_LIGHT_HALF_VECTOR:
- return _NEW_LIGHT;
-
- case STATE_PT_SCALE:
- case STATE_PT_BIAS:
- case STATE_PCM_SCALE:
- case STATE_PCM_BIAS:
- return _NEW_PIXEL;
-
- case STATE_FB_SIZE:
- return _NEW_BUFFERS;
-
- default:
- /* unknown state indexes are silently ignored and
- * no flag set, since it is handled by the driver.
- */
- 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;
-}
-
-
-/**
- * Convert token 'k' to a string, append it onto 'dst' string.
- */
-static void
-append_token(char *dst, gl_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_MODELVIEW_MATRIX:
- append(dst, "matrix.modelview");
- break;
- case STATE_PROJECTION_MATRIX:
- append(dst, "matrix.projection");
- break;
- case STATE_MVP_MATRIX:
- append(dst, "matrix.mvp");
- break;
- case STATE_TEXTURE_MATRIX:
- append(dst, "matrix.texture");
- break;
- case STATE_PROGRAM_MATRIX:
- append(dst, "matrix.program");
- break;
- case STATE_COLOR_MATRIX:
- append(dst, "matrix.color");
- 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, "lshininess");
- break;
- case STATE_HALF_VECTOR:
- 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_SPOT_CUTOFF:
- append(dst, ".spot.cutoff");
- 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;
- /* BEGIN internal state vars */
- case STATE_INTERNAL:
- append(dst, ".internal.");
- break;
- case STATE_CURRENT_ATTRIB:
- append(dst, "current");
- break;
- case STATE_NORMAL_SCALE:
- append(dst, "normalScale");
- break;
- case STATE_TEXRECT_SCALE:
- append(dst, "texrectScale");
- break;
- case STATE_FOG_PARAMS_OPTIMIZED:
- append(dst, "fogParamsOptimized");
- break;
- case STATE_POINT_SIZE_CLAMPED:
- append(dst, "pointSizeClamped");
- break;
- case STATE_POINT_SIZE_IMPL_CLAMP:
- append(dst, "pointSizeImplClamp");
- break;
- case STATE_LIGHT_SPOT_DIR_NORMALIZED:
- append(dst, "lightSpotDirNormalized");
- break;
- case STATE_LIGHT_POSITION:
- append(dst, "lightPosition");
- break;
- case STATE_LIGHT_POSITION_NORMALIZED:
- append(dst, "light.position.normalized");
- break;
- case STATE_LIGHT_HALF_VECTOR:
- append(dst, "lightHalfVector");
- break;
- case STATE_PT_SCALE:
- append(dst, "PTscale");
- break;
- case STATE_PT_BIAS:
- append(dst, "PTbias");
- break;
- case STATE_PCM_SCALE:
- append(dst, "PCMscale");
- break;
- case STATE_PCM_BIAS:
- append(dst, "PCMbias");
- break;
- case STATE_SHADOW_AMBIENT:
- append(dst, "CompareFailValue");
- break;
- case STATE_FB_SIZE:
- append(dst, "FbSize");
- break;
- case STATE_ROT_MATRIX_0:
- append(dst, "rotMatrixRow0");
- break;
- case STATE_ROT_MATRIX_1:
- append(dst, "rotMatrixRow1");
- break;
- default:
- /* probably STATE_INTERNAL_DRIVER+i (driver private state) */
- append(dst, "driverState");
- }
-}
-
-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];
- sprintf(s, "[%d]", index);
- append(dst, s);
-}
-
-/**
- * Make a string from the given state vector.
- * For example, return "state.matrix.texture[2].inverse".
- * Use free() to deallocate the string.
- */
-char *
-_mesa_program_state_string(const gl_state_index state[STATE_LENGTH])
-{
- char str[1000] = "";
- char tmp[30];
-
- append(str, "state.");
- append_token(str, state[0]);
-
- switch (state[0]) {
- case STATE_MATERIAL:
- append_face(str, state[1]);
- append_token(str, state[2]);
- break;
- case STATE_LIGHT:
- append_index(str, state[1]); /* light number [i]. */
- append_token(str, 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, state[3]);
- break;
- case STATE_TEXGEN:
- append_index(str, state[1]); /* tex unit [i] */
- append_token(str, state[2]); /* plane coef */
- break;
- case STATE_TEXENV_COLOR:
- append_index(str, state[1]); /* tex unit [i] */
- append(str, "color");
- break;
- case STATE_CLIPPLANE:
- append_index(str, state[1]); /* plane [i] */
- append(str, ".plane");
- break;
- case STATE_MODELVIEW_MATRIX:
- case STATE_PROJECTION_MATRIX:
- case STATE_MVP_MATRIX:
- case STATE_TEXTURE_MATRIX:
- case STATE_PROGRAM_MATRIX:
- case STATE_COLOR_MATRIX:
- {
- /* state[0] = modelview, projection, texture, etc. */
- /* state[1] = which texture matrix or program matrix */
- /* state[2] = first row to fetch */
- /* state[3] = last row to fetch */
- /* state[4] = transpose, inverse or invtrans */
- const gl_state_index mat = state[0];
- const GLuint index = (GLuint) state[1];
- const GLuint firstRow = (GLuint) state[2];
- const GLuint lastRow = (GLuint) state[3];
- const gl_state_index modifier = state[4];
- if (index ||
- mat == STATE_TEXTURE_MATRIX ||
- mat == STATE_PROGRAM_MATRIX)
- append_index(str, index);
- if (modifier)
- append_token(str, modifier);
- if (firstRow == lastRow)
- sprintf(tmp, ".row[%d]", firstRow);
- else
- sprintf(tmp, ".row[%d..%d]", firstRow, lastRow);
- append(str, tmp);
- }
- break;
- case STATE_POINT_SIZE:
- break;
- case STATE_POINT_ATTENUATION:
- break;
- case STATE_FOG_PARAMS:
- break;
- case STATE_FOG_COLOR:
- 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, state[1]);
- append_index(str, state[2]);
- break;
- case STATE_NORMAL_SCALE:
- break;
- case STATE_INTERNAL:
- append_token(str, state[1]);
- if (state[1] == STATE_CURRENT_ATTRIB)
- append_index(str, state[2]);
- break;
- default:
- _mesa_problem(NULL, "Invalid state in _mesa_program_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;
-
- /*assert(ctx->Driver.NeedFlush == 0);*/
-
- for (i = 0; i < paramList->NumParameters; i++) {
- if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) {
- _mesa_fetch_state(ctx,
- (gl_state_index *) paramList->Parameters[i].StateIndexes,
- paramList->ParameterValues[i]);
- }
- }
-}
-
-
-/**
- * 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 current vertex program's parameter registers with tracked
- * matrices (if NV program). This only needs to be done per
- * glBegin/glEnd, not per-vertex.
- */
-void
-_mesa_load_tracked_matrices(GLcontext *ctx)
-{
- 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) {
- GLuint unit = MIN2(ctx->Texture.CurrentUnit,
- Elements(ctx->TextureMatrixStack) - 1);
- mat = ctx->TextureMatrixStack[unit].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 < Elements(ctx->ProgramMatrixStack));
- 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 values into sequential registers */
- 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);
- }
- }
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2007 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_statevars.c
+ * Program state variable management.
+ * \author Brian Paul
+ */
+
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "prog_statevars.h"
+#include "prog_parameter.h"
+
+
+/**
+ * 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(struct gl_context *ctx, const gl_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];
+ const struct gl_material *mat = &ctx->Light.Material;
+ ASSERT(face == 0 || face == 1);
+ /* we rely on tokens numbered so that _BACK_ == _FRONT_+ 1 */
+ ASSERT(MAT_ATTRIB_FRONT_AMBIENT + 1 == MAT_ATTRIB_BACK_AMBIENT);
+ /* XXX we could get rid of this switch entirely with a little
+ * work in arbprogparse.c's parse_state_single_item().
+ */
+ /* state[2] is the material attribute */
+ switch (state[2]) {
+ case STATE_AMBIENT:
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_AMBIENT + face]);
+ return;
+ case STATE_DIFFUSE:
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_DIFFUSE + face]);
+ return;
+ case STATE_SPECULAR:
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_SPECULAR + face]);
+ return;
+ case STATE_EMISSION:
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_EMISSION + face]);
+ return;
+ case STATE_SHININESS:
+ value[0] = mat->Attrib[MAT_ATTRIB_FRONT_SHININESS + face][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].SpotDirection);
+ value[3] = ctx->Light.Light[ln]._CosCutoff;
+ return;
+ case STATE_SPOT_CUTOFF:
+ value[0] = ctx->Light.Light[ln].SpotCutoff;
+ return;
+ case STATE_HALF_VECTOR:
+ {
+ static const GLfloat eye_z[] = {0, 0, 1};
+ GLfloat p[3];
+ /* Compute infinite half angle vector:
+ * halfVector = normalize(normalize(lightPos) + (0, 0, 1))
+ * light.EyePosition.w should be 0 for infinite lights.
+ */
+ COPY_3V(p, ctx->Light.Light[ln].EyePosition);
+ NORMALIZE_3FV(p);
+ ADD_3V(value, p, eye_z);
+ NORMALIZE_3FV(value);
+ value[3] = 1.0;
+ }
+ 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_AMBIENT+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_SPECULAR+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].GenS.EyePlane);
+ return;
+ case STATE_TEXGEN_EYE_T:
+ COPY_4V(value, ctx->Texture.Unit[unit].GenT.EyePlane);
+ return;
+ case STATE_TEXGEN_EYE_R:
+ COPY_4V(value, ctx->Texture.Unit[unit].GenR.EyePlane);
+ return;
+ case STATE_TEXGEN_EYE_Q:
+ COPY_4V(value, ctx->Texture.Unit[unit].GenQ.EyePlane);
+ return;
+ case STATE_TEXGEN_OBJECT_S:
+ COPY_4V(value, ctx->Texture.Unit[unit].GenS.ObjectPlane);
+ return;
+ case STATE_TEXGEN_OBJECT_T:
+ COPY_4V(value, ctx->Texture.Unit[unit].GenT.ObjectPlane);
+ return;
+ case STATE_TEXGEN_OBJECT_R:
+ COPY_4V(value, ctx->Texture.Unit[unit].GenR.ObjectPlane);
+ return;
+ case STATE_TEXGEN_OBJECT_Q:
+ COPY_4V(value, ctx->Texture.Unit[unit].GenQ.ObjectPlane);
+ 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] = (ctx->Fog.End == ctx->Fog.Start)
+ ? 1.0f : (GLfloat)(1.0 / (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_MODELVIEW_MATRIX:
+ case STATE_PROJECTION_MATRIX:
+ case STATE_MVP_MATRIX:
+ case STATE_TEXTURE_MATRIX:
+ case STATE_PROGRAM_MATRIX:
+ {
+ /* state[0] = modelview, projection, texture, etc. */
+ /* state[1] = which texture matrix or program matrix */
+ /* state[2] = first row to fetch */
+ /* state[3] = last row to fetch */
+ /* state[4] = transpose, inverse or invtrans */
+ const GLmatrix *matrix;
+ const gl_state_index mat = state[0];
+ const GLuint index = (GLuint) state[1];
+ const GLuint firstRow = (GLuint) state[2];
+ const GLuint lastRow = (GLuint) state[3];
+ const gl_state_index modifier = state[4];
+ const GLfloat *m;
+ GLuint row, i;
+ ASSERT(firstRow >= 0);
+ ASSERT(firstRow < 4);
+ ASSERT(lastRow >= 0);
+ ASSERT(lastRow < 4);
+ if (mat == STATE_MODELVIEW_MATRIX) {
+ matrix = ctx->ModelviewMatrixStack.Top;
+ }
+ else if (mat == STATE_PROJECTION_MATRIX) {
+ matrix = ctx->ProjectionMatrixStack.Top;
+ }
+ else if (mat == STATE_MVP_MATRIX) {
+ matrix = &ctx->_ModelProjectMatrix;
+ }
+ else if (mat == STATE_TEXTURE_MATRIX) {
+ ASSERT(index < Elements(ctx->TextureMatrixStack));
+ matrix = ctx->TextureMatrixStack[index].Top;
+ }
+ else if (mat == STATE_PROGRAM_MATRIX) {
+ ASSERT(index < Elements(ctx->ProgramMatrixStack));
+ 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 = firstRow; row <= lastRow; 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 = firstRow; row <= lastRow; 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] = 1.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]);
+ return;
+ case STATE_LOCAL:
+ COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
+ return;
+ 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]);
+ return;
+ case STATE_LOCAL:
+ COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
+ return;
+ default:
+ _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
+ return;
+ }
+ }
+ return;
+
+ case STATE_NORMAL_SCALE:
+ ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
+ return;
+
+ case STATE_INTERNAL:
+ switch (state[1]) {
+ case STATE_CURRENT_ATTRIB:
+ {
+ const GLuint idx = (GLuint) state[2];
+ COPY_4V(value, ctx->Current.Attrib[idx]);
+ }
+ return;
+
+ case STATE_NORMAL_SCALE:
+ ASSIGN_4V(value,
+ ctx->_ModelViewInvScale,
+ ctx->_ModelViewInvScale,
+ ctx->_ModelViewInvScale,
+ 1);
+ return;
+
+ case STATE_TEXRECT_SCALE:
+ /* Value = { 1/texWidth, 1/texHeight, 0, 1 }.
+ * Used to convert unnormalized texcoords to normalized texcoords.
+ */
+ {
+ const int unit = (int) state[2];
+ const struct gl_texture_object *texObj
+ = ctx->Texture.Unit[unit]._Current;
+ if (texObj) {
+ struct gl_texture_image *texImage = texObj->Image[0][0];
+ ASSIGN_4V(value,
+ (GLfloat) (1.0 / texImage->Width),
+ (GLfloat) (1.0 / texImage->Height),
+ 0.0f, 1.0f);
+ }
+ }
+ return;
+
+ case STATE_FOG_PARAMS_OPTIMIZED:
+ /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog)
+ * might be more expensive than EX2 on some hw, plus it needs
+ * another constant (e) anyway. Linear fog can now be done with a
+ * single MAD.
+ * linear: fogcoord * -1/(end-start) + end/(end-start)
+ * exp: 2^-(density/ln(2) * fogcoord)
+ * exp2: 2^-((density/(ln(2)^2) * fogcoord)^2)
+ */
+ value[0] = (ctx->Fog.End == ctx->Fog.Start)
+ ? 1.0f : (GLfloat)(-1.0F / (ctx->Fog.End - ctx->Fog.Start));
+ value[1] = ctx->Fog.End * -value[0];
+ value[2] = (GLfloat)(ctx->Fog.Density * ONE_DIV_LN2);
+ value[3] = (GLfloat)(ctx->Fog.Density * ONE_DIV_SQRT_LN2);
+ return;
+
+ case STATE_POINT_SIZE_CLAMPED:
+ {
+ /* this includes implementation dependent limits, to avoid
+ * another potentially necessary clamp.
+ * Note: for sprites, point smooth (point AA) is ignored
+ * and we'll clamp to MinPointSizeAA and MaxPointSize, because we
+ * expect drivers will want to say their minimum for AA size is 0.0
+ * but for non-AA it's 1.0 (because normal points with size below 1.0
+ * need to get rounded up to 1.0, hence never disappear). GL does
+ * not specify max clamp size for sprites, other than it needs to be
+ * at least as large as max AA size, hence use non-AA size there.
+ */
+ GLfloat minImplSize;
+ GLfloat maxImplSize;
+ if (ctx->Point.PointSprite) {
+ minImplSize = ctx->Const.MinPointSizeAA;
+ maxImplSize = ctx->Const.MaxPointSize;
+ }
+ else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) {
+ minImplSize = ctx->Const.MinPointSizeAA;
+ maxImplSize = ctx->Const.MaxPointSizeAA;
+ }
+ else {
+ minImplSize = ctx->Const.MinPointSize;
+ maxImplSize = ctx->Const.MaxPointSize;
+ }
+ value[0] = ctx->Point.Size;
+ value[1] = ctx->Point.MinSize >= minImplSize ? ctx->Point.MinSize : minImplSize;
+ value[2] = ctx->Point.MaxSize <= maxImplSize ? ctx->Point.MaxSize : maxImplSize;
+ value[3] = ctx->Point.Threshold;
+ }
+ return;
+ case STATE_POINT_SIZE_IMPL_CLAMP:
+ {
+ /* for implementation clamp only in vs */
+ GLfloat minImplSize;
+ GLfloat maxImplSize;
+ if (ctx->Point.PointSprite) {
+ minImplSize = ctx->Const.MinPointSizeAA;
+ maxImplSize = ctx->Const.MaxPointSize;
+ }
+ else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) {
+ minImplSize = ctx->Const.MinPointSizeAA;
+ maxImplSize = ctx->Const.MaxPointSizeAA;
+ }
+ else {
+ minImplSize = ctx->Const.MinPointSize;
+ maxImplSize = ctx->Const.MaxPointSize;
+ }
+ value[0] = ctx->Point.Size;
+ value[1] = minImplSize;
+ value[2] = maxImplSize;
+ value[3] = ctx->Point.Threshold;
+ }
+ return;
+ case STATE_LIGHT_SPOT_DIR_NORMALIZED:
+ {
+ /* here, state[2] is the light number */
+ /* pre-normalize spot dir */
+ const GLuint ln = (GLuint) state[2];
+ COPY_3V(value, ctx->Light.Light[ln]._NormSpotDirection);
+ value[3] = ctx->Light.Light[ln]._CosCutoff;
+ }
+ return;
+
+ case STATE_LIGHT_POSITION:
+ {
+ const GLuint ln = (GLuint) state[2];
+ COPY_4V(value, ctx->Light.Light[ln]._Position);
+ }
+ return;
+
+ case STATE_LIGHT_POSITION_NORMALIZED:
+ {
+ const GLuint ln = (GLuint) state[2];
+ COPY_4V(value, ctx->Light.Light[ln]._Position);
+ NORMALIZE_3FV( value );
+ }
+ return;
+
+ case STATE_LIGHT_HALF_VECTOR:
+ {
+ const GLuint ln = (GLuint) state[2];
+ GLfloat p[3];
+ /* Compute infinite half angle vector:
+ * halfVector = normalize(normalize(lightPos) + (0, 0, 1))
+ * light.EyePosition.w should be 0 for infinite lights.
+ */
+ COPY_3V(p, ctx->Light.Light[ln]._Position);
+ NORMALIZE_3FV(p);
+ ADD_3V(value, p, ctx->_EyeZDir);
+ NORMALIZE_3FV(value);
+ value[3] = 1.0;
+ }
+ return;
+
+ case STATE_PT_SCALE:
+ value[0] = ctx->Pixel.RedScale;
+ value[1] = ctx->Pixel.GreenScale;
+ value[2] = ctx->Pixel.BlueScale;
+ value[3] = ctx->Pixel.AlphaScale;
+ return;
+
+ case STATE_PT_BIAS:
+ value[0] = ctx->Pixel.RedBias;
+ value[1] = ctx->Pixel.GreenBias;
+ value[2] = ctx->Pixel.BlueBias;
+ value[3] = ctx->Pixel.AlphaBias;
+ return;
+
+ case STATE_SHADOW_AMBIENT:
+ {
+ const int unit = (int) state[2];
+ const struct gl_texture_object *texObj
+ = ctx->Texture.Unit[unit]._Current;
+ if (texObj) {
+ value[0] =
+ value[1] =
+ value[2] =
+ value[3] = texObj->CompareFailValue;
+ }
+ }
+ return;
+
+ case STATE_FB_SIZE:
+ value[0] = (GLfloat) (ctx->DrawBuffer->Width - 1);
+ value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1);
+ value[2] = 0.0F;
+ value[3] = 0.0F;
+ return;
+
+ case STATE_FB_WPOS_Y_TRANSFORM:
+ /* A driver may negate this conditional by using ZW swizzle
+ * instead of XY (based on e.g. some other state). */
+ if (ctx->DrawBuffer->Name != 0) {
+ /* Identity (XY) followed by flipping Y upside down (ZW). */
+ value[0] = 1.0F;
+ value[1] = 0.0F;
+ value[2] = -1.0F;
+ value[3] = (GLfloat) (ctx->DrawBuffer->Height - 1);
+ } else {
+ /* Flipping Y upside down (XY) followed by identity (ZW). */
+ value[0] = -1.0F;
+ value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1);
+ value[2] = 1.0F;
+ value[3] = 0.0F;
+ }
+ return;
+
+ case STATE_ROT_MATRIX_0:
+ {
+ const int unit = (int) state[2];
+ GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix;
+ value[0] = rotMat22[0];
+ value[1] = rotMat22[2];
+ value[2] = 0.0;
+ value[3] = 0.0;
+ }
+ return;
+
+ case STATE_ROT_MATRIX_1:
+ {
+ const int unit = (int) state[2];
+ GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix;
+ value[0] = rotMat22[1];
+ value[1] = rotMat22[3];
+ value[2] = 0.0;
+ value[3] = 0.0;
+ }
+ return;
+
+ /* XXX: make sure new tokens added here are also handled in the
+ * _mesa_program_state_flags() switch, below.
+ */
+ default:
+ /* Unknown state indexes are silently ignored here.
+ * Drivers may do something special.
+ */
+ return;
+ }
+ return;
+
+ default:
+ _mesa_problem(ctx, "Invalid state in _mesa_fetch_state");
+ return;
+ }
+}
+
+
+/**
+ * Return a bitmask of the Mesa state flags (_NEW_* values) which would
+ * indicate that the given context state may have changed.
+ * The bitmask is used during validation to determine if we need to update
+ * vertex/fragment program parameters (like "state.material.color") when
+ * some GL state has changed.
+ */
+GLbitfield
+_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH])
+{
+ 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_MODELVIEW_MATRIX:
+ return _NEW_MODELVIEW;
+ case STATE_PROJECTION_MATRIX:
+ return _NEW_PROJECTION;
+ case STATE_MVP_MATRIX:
+ return _NEW_MODELVIEW | _NEW_PROJECTION;
+ case STATE_TEXTURE_MATRIX:
+ return _NEW_TEXTURE_MATRIX;
+ case STATE_PROGRAM_MATRIX:
+ return _NEW_TRACK_MATRIX;
+
+ case STATE_DEPTH_RANGE:
+ return _NEW_VIEWPORT;
+
+ case STATE_FRAGMENT_PROGRAM:
+ case STATE_VERTEX_PROGRAM:
+ return _NEW_PROGRAM;
+
+ case STATE_NORMAL_SCALE:
+ return _NEW_MODELVIEW;
+
+ case STATE_INTERNAL:
+ switch (state[1]) {
+ case STATE_CURRENT_ATTRIB:
+ return _NEW_CURRENT_ATTRIB;
+
+ case STATE_NORMAL_SCALE:
+ return _NEW_MODELVIEW;
+
+ case STATE_TEXRECT_SCALE:
+ case STATE_SHADOW_AMBIENT:
+ case STATE_ROT_MATRIX_0:
+ case STATE_ROT_MATRIX_1:
+ return _NEW_TEXTURE;
+ case STATE_FOG_PARAMS_OPTIMIZED:
+ return _NEW_FOG;
+ case STATE_POINT_SIZE_CLAMPED:
+ case STATE_POINT_SIZE_IMPL_CLAMP:
+ return _NEW_POINT | _NEW_MULTISAMPLE;
+ case STATE_LIGHT_SPOT_DIR_NORMALIZED:
+ case STATE_LIGHT_POSITION:
+ case STATE_LIGHT_POSITION_NORMALIZED:
+ case STATE_LIGHT_HALF_VECTOR:
+ return _NEW_LIGHT;
+
+ case STATE_PT_SCALE:
+ case STATE_PT_BIAS:
+ return _NEW_PIXEL;
+
+ case STATE_FB_SIZE:
+ case STATE_FB_WPOS_Y_TRANSFORM:
+ return _NEW_BUFFERS;
+
+ default:
+ /* unknown state indexes are silently ignored and
+ * no flag set, since it is handled by the driver.
+ */
+ 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;
+}
+
+
+/**
+ * Convert token 'k' to a string, append it onto 'dst' string.
+ */
+static void
+append_token(char *dst, gl_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_MODELVIEW_MATRIX:
+ append(dst, "matrix.modelview");
+ break;
+ case STATE_PROJECTION_MATRIX:
+ append(dst, "matrix.projection");
+ break;
+ case STATE_MVP_MATRIX:
+ append(dst, "matrix.mvp");
+ break;
+ case STATE_TEXTURE_MATRIX:
+ append(dst, "matrix.texture");
+ break;
+ case STATE_PROGRAM_MATRIX:
+ append(dst, "matrix.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, "lshininess");
+ break;
+ case STATE_HALF_VECTOR:
+ 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_SPOT_CUTOFF:
+ append(dst, ".spot.cutoff");
+ 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;
+ /* BEGIN internal state vars */
+ case STATE_INTERNAL:
+ append(dst, ".internal.");
+ break;
+ case STATE_CURRENT_ATTRIB:
+ append(dst, "current");
+ break;
+ case STATE_NORMAL_SCALE:
+ append(dst, "normalScale");
+ break;
+ case STATE_TEXRECT_SCALE:
+ append(dst, "texrectScale");
+ break;
+ case STATE_FOG_PARAMS_OPTIMIZED:
+ append(dst, "fogParamsOptimized");
+ break;
+ case STATE_POINT_SIZE_CLAMPED:
+ append(dst, "pointSizeClamped");
+ break;
+ case STATE_POINT_SIZE_IMPL_CLAMP:
+ append(dst, "pointSizeImplClamp");
+ break;
+ case STATE_LIGHT_SPOT_DIR_NORMALIZED:
+ append(dst, "lightSpotDirNormalized");
+ break;
+ case STATE_LIGHT_POSITION:
+ append(dst, "lightPosition");
+ break;
+ case STATE_LIGHT_POSITION_NORMALIZED:
+ append(dst, "light.position.normalized");
+ break;
+ case STATE_LIGHT_HALF_VECTOR:
+ append(dst, "lightHalfVector");
+ break;
+ case STATE_PT_SCALE:
+ append(dst, "PTscale");
+ break;
+ case STATE_PT_BIAS:
+ append(dst, "PTbias");
+ break;
+ case STATE_SHADOW_AMBIENT:
+ append(dst, "CompareFailValue");
+ break;
+ case STATE_FB_SIZE:
+ append(dst, "FbSize");
+ break;
+ case STATE_FB_WPOS_Y_TRANSFORM:
+ append(dst, "FbWposYTransform");
+ break;
+ case STATE_ROT_MATRIX_0:
+ append(dst, "rotMatrixRow0");
+ break;
+ case STATE_ROT_MATRIX_1:
+ append(dst, "rotMatrixRow1");
+ break;
+ default:
+ /* probably STATE_INTERNAL_DRIVER+i (driver private state) */
+ append(dst, "driverState");
+ }
+}
+
+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];
+ sprintf(s, "[%d]", index);
+ append(dst, s);
+}
+
+/**
+ * Make a string from the given state vector.
+ * For example, return "state.matrix.texture[2].inverse".
+ * Use free() to deallocate the string.
+ */
+char *
+_mesa_program_state_string(const gl_state_index state[STATE_LENGTH])
+{
+ char str[1000] = "";
+ char tmp[30];
+
+ append(str, "state.");
+ append_token(str, state[0]);
+
+ switch (state[0]) {
+ case STATE_MATERIAL:
+ append_face(str, state[1]);
+ append_token(str, state[2]);
+ break;
+ case STATE_LIGHT:
+ append_index(str, state[1]); /* light number [i]. */
+ append_token(str, 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, state[3]);
+ break;
+ case STATE_TEXGEN:
+ append_index(str, state[1]); /* tex unit [i] */
+ append_token(str, state[2]); /* plane coef */
+ break;
+ case STATE_TEXENV_COLOR:
+ append_index(str, state[1]); /* tex unit [i] */
+ append(str, "color");
+ break;
+ case STATE_CLIPPLANE:
+ append_index(str, state[1]); /* plane [i] */
+ append(str, ".plane");
+ break;
+ case STATE_MODELVIEW_MATRIX:
+ case STATE_PROJECTION_MATRIX:
+ case STATE_MVP_MATRIX:
+ case STATE_TEXTURE_MATRIX:
+ case STATE_PROGRAM_MATRIX:
+ {
+ /* state[0] = modelview, projection, texture, etc. */
+ /* state[1] = which texture matrix or program matrix */
+ /* state[2] = first row to fetch */
+ /* state[3] = last row to fetch */
+ /* state[4] = transpose, inverse or invtrans */
+ const gl_state_index mat = state[0];
+ const GLuint index = (GLuint) state[1];
+ const GLuint firstRow = (GLuint) state[2];
+ const GLuint lastRow = (GLuint) state[3];
+ const gl_state_index modifier = state[4];
+ if (index ||
+ mat == STATE_TEXTURE_MATRIX ||
+ mat == STATE_PROGRAM_MATRIX)
+ append_index(str, index);
+ if (modifier)
+ append_token(str, modifier);
+ if (firstRow == lastRow)
+ sprintf(tmp, ".row[%d]", firstRow);
+ else
+ sprintf(tmp, ".row[%d..%d]", firstRow, lastRow);
+ append(str, tmp);
+ }
+ break;
+ case STATE_POINT_SIZE:
+ break;
+ case STATE_POINT_ATTENUATION:
+ break;
+ case STATE_FOG_PARAMS:
+ break;
+ case STATE_FOG_COLOR:
+ 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, state[1]);
+ append_index(str, state[2]);
+ break;
+ case STATE_NORMAL_SCALE:
+ break;
+ case STATE_INTERNAL:
+ append_token(str, state[1]);
+ if (state[1] == STATE_CURRENT_ATTRIB)
+ append_index(str, state[2]);
+ break;
+ default:
+ _mesa_problem(NULL, "Invalid state in _mesa_program_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.
+ * Other parameter types never change or are explicitly set by the user
+ * with glUniform() or glProgramParameter(), etc.
+ * This would be called at glBegin time.
+ */
+void
+_mesa_load_state_parameters(struct gl_context *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]);
+ }
+ }
+}
+
+
+/**
+ * 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 current vertex program's parameter registers with tracked
+ * matrices (if NV program). This only needs to be done per
+ * glBegin/glEnd, not per-vertex.
+ */
+void
+_mesa_load_tracked_matrices(struct gl_context *ctx)
+{
+ 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) {
+ GLuint unit = MIN2(ctx->Texture.CurrentUnit,
+ Elements(ctx->TextureMatrixStack) - 1);
+ mat = ctx->TextureMatrixStack[unit].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 < Elements(ctx->ProgramMatrixStack));
+ 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 values into sequential registers */
+ 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);
+ }
+ }
+}
diff --git a/mesalib/src/mesa/program/prog_statevars.h b/mesalib/src/mesa/program/prog_statevars.h
index 1753471ff..a92b77855 100644
--- a/mesalib/src/mesa/program/prog_statevars.h
+++ b/mesalib/src/mesa/program/prog_statevars.h
@@ -1,147 +1,147 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2007 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 PROG_STATEVARS_H
-#define PROG_STATEVARS_H
-
-#include "main/mtypes.h"
-
-
-/**
- * Number of STATE_* values we need to address any GL state.
- * Used to dimension arrays.
- */
-#define STATE_LENGTH 5
-
-
-/**
- * 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 ].
- *
- * For state that's an array, like STATE_CLIPPLANE, the 2nd token [1] should
- * always be the array index.
- */
-typedef enum gl_state_index_ {
- STATE_MATERIAL = 100, /* start at 100 so small ints are seen as ints */
-
- 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_MODELVIEW_MATRIX,
- STATE_PROJECTION_MATRIX,
- STATE_MVP_MATRIX,
- STATE_TEXTURE_MATRIX,
- STATE_PROGRAM_MATRIX,
- STATE_COLOR_MATRIX,
- STATE_MATRIX_INVERSE,
- STATE_MATRIX_TRANSPOSE,
- STATE_MATRIX_INVTRANS,
-
- STATE_AMBIENT,
- STATE_DIFFUSE,
- STATE_SPECULAR,
- STATE_EMISSION,
- STATE_SHININESS,
- STATE_HALF_VECTOR,
-
- STATE_POSITION, /**< xyzw = position */
- STATE_ATTENUATION, /**< xyz = attenuation, w = spot exponent */
- STATE_SPOT_DIRECTION, /**< xyz = direction, w = cos(cutoff) */
- STATE_SPOT_CUTOFF, /**< x = cutoff, yzw = undefined */
-
- 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_CURRENT_ATTRIB, /* ctx->Current vertex attrib value */
- STATE_NORMAL_SCALE,
- STATE_TEXRECT_SCALE,
- STATE_FOG_PARAMS_OPTIMIZED, /* for faster fog calc */
- STATE_POINT_SIZE_CLAMPED, /* includes implementation dependent size clamp */
- STATE_POINT_SIZE_IMPL_CLAMP, /* for implementation clamp only in vs */
- STATE_LIGHT_SPOT_DIR_NORMALIZED, /* pre-normalized spot dir */
- STATE_LIGHT_POSITION, /* object vs eye space */
- STATE_LIGHT_POSITION_NORMALIZED, /* object vs eye space */
- STATE_LIGHT_HALF_VECTOR, /* object vs eye space */
- STATE_PT_SCALE, /**< Pixel transfer RGBA scale */
- STATE_PT_BIAS, /**< Pixel transfer RGBA bias */
- STATE_PCM_SCALE, /**< Post color matrix RGBA scale */
- STATE_PCM_BIAS, /**< Post color matrix RGBA bias */
- STATE_SHADOW_AMBIENT, /**< ARB_shadow_ambient fail value; token[2] is texture unit index */
- STATE_FB_SIZE, /**< (width-1, height-1, 0, 0) */
- STATE_ROT_MATRIX_0, /**< ATI_envmap_bumpmap, rot matrix row 0 */
- STATE_ROT_MATRIX_1, /**< ATI_envmap_bumpmap, rot matrix row 1 */
- STATE_INTERNAL_DRIVER /* first available state index for drivers (must be last) */
-} gl_state_index;
-
-
-
-extern void
-_mesa_load_state_parameters(GLcontext *ctx,
- struct gl_program_parameter_list *paramList);
-
-
-extern GLbitfield
-_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]);
-
-
-extern char *
-_mesa_program_state_string(const gl_state_index state[STATE_LENGTH]);
-
-
-extern void
-_mesa_load_tracked_matrices(GLcontext *ctx);
-
-
-#endif /* PROG_STATEVARS_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2007 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 PROG_STATEVARS_H
+#define PROG_STATEVARS_H
+
+#include "main/glheader.h"
+
+struct gl_context;
+struct gl_program_parameter_list;
+
+/**
+ * Number of STATE_* values we need to address any GL state.
+ * Used to dimension arrays.
+ */
+#define STATE_LENGTH 5
+
+
+/**
+ * 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 ].
+ *
+ * For state that's an array, like STATE_CLIPPLANE, the 2nd token [1] should
+ * always be the array index.
+ */
+typedef enum gl_state_index_ {
+ STATE_MATERIAL = 100, /* start at 100 so small ints are seen as ints */
+
+ 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_MODELVIEW_MATRIX,
+ STATE_PROJECTION_MATRIX,
+ STATE_MVP_MATRIX,
+ STATE_TEXTURE_MATRIX,
+ STATE_PROGRAM_MATRIX,
+ STATE_MATRIX_INVERSE,
+ STATE_MATRIX_TRANSPOSE,
+ STATE_MATRIX_INVTRANS,
+
+ STATE_AMBIENT,
+ STATE_DIFFUSE,
+ STATE_SPECULAR,
+ STATE_EMISSION,
+ STATE_SHININESS,
+ STATE_HALF_VECTOR,
+
+ STATE_POSITION, /**< xyzw = position */
+ STATE_ATTENUATION, /**< xyz = attenuation, w = spot exponent */
+ STATE_SPOT_DIRECTION, /**< xyz = direction, w = cos(cutoff) */
+ STATE_SPOT_CUTOFF, /**< x = cutoff, yzw = undefined */
+
+ 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_CURRENT_ATTRIB, /* ctx->Current vertex attrib value */
+ STATE_NORMAL_SCALE,
+ STATE_TEXRECT_SCALE,
+ STATE_FOG_PARAMS_OPTIMIZED, /* for faster fog calc */
+ STATE_POINT_SIZE_CLAMPED, /* includes implementation dependent size clamp */
+ STATE_POINT_SIZE_IMPL_CLAMP, /* for implementation clamp only in vs */
+ STATE_LIGHT_SPOT_DIR_NORMALIZED, /* pre-normalized spot dir */
+ STATE_LIGHT_POSITION, /* object vs eye space */
+ STATE_LIGHT_POSITION_NORMALIZED, /* object vs eye space */
+ STATE_LIGHT_HALF_VECTOR, /* object vs eye space */
+ STATE_PT_SCALE, /**< Pixel transfer RGBA scale */
+ STATE_PT_BIAS, /**< Pixel transfer RGBA bias */
+ STATE_SHADOW_AMBIENT, /**< ARB_shadow_ambient fail value; token[2] is texture unit index */
+ STATE_FB_SIZE, /**< (width-1, height-1, 0, 0) */
+ STATE_FB_WPOS_Y_TRANSFORM, /**< (1, 0, -1, height-1) if a FBO is bound, (-1, height-1, 1, 0) otherwise */
+ STATE_ROT_MATRIX_0, /**< ATI_envmap_bumpmap, rot matrix row 0 */
+ STATE_ROT_MATRIX_1, /**< ATI_envmap_bumpmap, rot matrix row 1 */
+ STATE_INTERNAL_DRIVER /* first available state index for drivers (must be last) */
+} gl_state_index;
+
+
+
+extern void
+_mesa_load_state_parameters(struct gl_context *ctx,
+ struct gl_program_parameter_list *paramList);
+
+
+extern GLbitfield
+_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]);
+
+
+extern char *
+_mesa_program_state_string(const gl_state_index state[STATE_LENGTH]);
+
+
+extern void
+_mesa_load_tracked_matrices(struct gl_context *ctx);
+
+
+#endif /* PROG_STATEVARS_H */
diff --git a/mesalib/src/mesa/program/program.c b/mesalib/src/mesa/program/program.c
index 06b9539bd..eff600685 100644
--- a/mesalib/src/mesa/program/program.c
+++ b/mesalib/src/mesa/program/program.c
@@ -1,976 +1,1073 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.3
- *
- * Copyright (C) 1999-2007 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 "main/glheader.h"
-#include "main/context.h"
-#include "main/hash.h"
-#include "program.h"
-#include "prog_cache.h"
-#include "prog_parameter.h"
-#include "prog_instruction.h"
-
-
-/**
- * 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;
-
- /*
- * If this assertion fails, we need to increase the field
- * size for register indexes (see INST_INDEX_BITS).
- */
- ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4
- <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4
- <= (1 << INST_INDEX_BITS));
-
- ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
-
- ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
- ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
-
- /* If this fails, increase prog_instruction::TexSrcUnit size */
- ASSERT(MAX_TEXTURE_UNITS < (1 << 5));
-
- /* If this fails, increase prog_instruction::TexSrcTarget size */
- ASSERT(NUM_TEXTURE_TARGETS < (1 << 3));
-
- ctx->Program.ErrorPos = -1;
- ctx->Program.ErrorString = _mesa_strdup("");
-
-#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
- ctx->VertexProgram.Enabled = GL_FALSE;
-#if FEATURE_es2_glsl
- ctx->VertexProgram.PointSizeEnabled =
- (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
-#else
- ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
-#endif
- ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
- ctx->Shared->DefaultVertexProgram);
- assert(ctx->VertexProgram.Current);
- for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
- ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
- ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
- }
- ctx->VertexProgram.Cache = _mesa_new_program_cache();
-#endif
-
-#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
- ctx->FragmentProgram.Enabled = GL_FALSE;
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
- ctx->Shared->DefaultFragmentProgram);
- assert(ctx->FragmentProgram.Current);
- ctx->FragmentProgram.Cache = _mesa_new_program_cache();
-#endif
-
-#if FEATURE_ARB_geometry_shader4
- ctx->GeometryProgram.Enabled = GL_FALSE;
- /* right now by default we don't have a geometry program */
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
- NULL);
- ctx->GeometryProgram.Cache = _mesa_new_program_cache();
-#endif
-
- /* XXX probably move this stuff */
-#if FEATURE_ATI_fragment_shader
- ctx->ATIFragmentShader.Enabled = GL_FALSE;
- ctx->ATIFragmentShader.Current = 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
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
- _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
-#endif
-#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
- _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache);
-#endif
-#if FEATURE_ARB_geometry_shader4
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
- _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache);
-#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) {
- free(ctx->ATIFragmentShader.Current);
- }
- }
-#endif
- free((void *) ctx->Program.ErrorString);
-}
-
-
-/**
- * Update the default program objects in the given context to reference those
- * specified in the shared state and release those referencing the old
- * shared state.
- */
-void
-_mesa_update_default_objects_program(GLcontext *ctx)
-{
-#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
- (struct gl_vertex_program *)
- ctx->Shared->DefaultVertexProgram);
- assert(ctx->VertexProgram.Current);
-#endif
-
-#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
- (struct gl_fragment_program *)
- ctx->Shared->DefaultFragmentProgram);
- assert(ctx->FragmentProgram.Current);
-#endif
-
-#if FEATURE_ARB_geometry_shader4
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
- (struct gl_geometry_program *)
- ctx->Shared->DefaultGeometryProgram);
-#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) {
- free(ctx->ATIFragmentShader.Current);
- }
- }
- ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
- assert(ctx->ATIFragmentShader.Current);
- ctx->ATIFragmentShader.Current->RefCount++;
-#endif
-}
-
-
-/**
- * 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;
- 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
- * 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 *) malloc(len + 1);
- 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) {
- GLuint i;
- memset(prog, 0, sizeof(*prog));
- prog->Id = id;
- prog->Target = target;
- prog->Resident = GL_TRUE;
- prog->RefCount = 1;
- prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
-
- /* default mapping from samplers to texture units */
- for (i = 0; i < MAX_SAMPLERS; i++)
- prog->SamplerUnits[i] = i;
- }
-
- 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;
-}
-
-
-/**
- * Initialize a new geometry program object.
- */
-struct gl_program *
-_mesa_init_geometry_program( GLcontext *ctx, struct gl_geometry_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)
-{
- struct gl_program *prog;
- switch (target) {
- case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
- case GL_VERTEX_STATE_PROGRAM_NV:
- prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
- target, id );
- break;
- case GL_FRAGMENT_PROGRAM_NV:
- case GL_FRAGMENT_PROGRAM_ARB:
- prog =_mesa_init_fragment_program(ctx,
- CALLOC_STRUCT(gl_fragment_program),
- target, id );
- break;
- case MESA_GEOMETRY_PROGRAM:
- prog = _mesa_init_geometry_program(ctx,
- CALLOC_STRUCT(gl_geometry_program),
- target, id);
- break;
- default:
- _mesa_problem(ctx, "bad target in _mesa_new_program");
- prog = NULL;
- }
- return prog;
-}
-
-
-/**
- * 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);
- ASSERT(prog->RefCount==0);
-
- if (prog == &_mesa_DummyProgram)
- return;
-
- if (prog->String)
- free(prog->String);
-
- _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
-
- if (prog->Parameters) {
- _mesa_free_parameter_list(prog->Parameters);
- }
- if (prog->Varying) {
- _mesa_free_parameter_list(prog->Varying);
- }
- if (prog->Attributes) {
- _mesa_free_parameter_list(prog->Attributes);
- }
-
- 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;
-}
-
-
-/**
- * Reference counting for vertex/fragment programs
- */
-void
-_mesa_reference_program(GLcontext *ctx,
- struct gl_program **ptr,
- struct gl_program *prog)
-{
- assert(ptr);
- if (*ptr && prog) {
- /* sanity check */
- if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
- ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB);
- else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
- ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
- prog->Target == GL_FRAGMENT_PROGRAM_NV);
- else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM)
- ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM);
- }
- if (*ptr == prog) {
- return; /* no change */
- }
- if (*ptr) {
- GLboolean deleteFlag;
-
- /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
-#if 0
- printf("Program %p ID=%u Target=%s Refcount-- to %d\n",
- *ptr, (*ptr)->Id,
- ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
- ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
- (*ptr)->RefCount - 1);
-#endif
- ASSERT((*ptr)->RefCount > 0);
- (*ptr)->RefCount--;
-
- deleteFlag = ((*ptr)->RefCount == 0);
- /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
-
- if (deleteFlag) {
- ASSERT(ctx);
- ctx->Driver.DeleteProgram(ctx, *ptr);
- }
-
- *ptr = NULL;
- }
-
- assert(!*ptr);
- if (prog) {
- /*_glthread_LOCK_MUTEX(prog->Mutex);*/
- prog->RefCount++;
-#if 0
- printf("Program %p ID=%u Target=%s Refcount++ to %d\n",
- prog, prog->Id,
- (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
- (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
- prog->RefCount);
-#endif
- /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
- }
-
- *ptr = prog;
-}
-
-
-/**
- * Return a copy of a program.
- * XXX Problem here if the program object is actually OO-derivation
- * made by a device driver.
- */
-struct gl_program *
-_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog)
-{
- struct gl_program *clone;
-
- clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id);
- if (!clone)
- return NULL;
-
- assert(clone->Target == prog->Target);
- assert(clone->RefCount == 1);
-
- clone->String = (GLubyte *) _mesa_strdup((char *) prog->String);
- clone->Format = prog->Format;
- clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions);
- if (!clone->Instructions) {
- _mesa_reference_program(ctx, &clone, NULL);
- return NULL;
- }
- _mesa_copy_instructions(clone->Instructions, prog->Instructions,
- prog->NumInstructions);
- clone->InputsRead = prog->InputsRead;
- clone->OutputsWritten = prog->OutputsWritten;
- clone->SamplersUsed = prog->SamplersUsed;
- clone->ShadowSamplers = prog->ShadowSamplers;
- memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
-
- if (prog->Parameters)
- clone->Parameters = _mesa_clone_parameter_list(prog->Parameters);
- memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
- if (prog->Varying)
- clone->Varying = _mesa_clone_parameter_list(prog->Varying);
- if (prog->Attributes)
- clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
- memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
- clone->IndirectRegisterFiles = prog->IndirectRegisterFiles;
- clone->NumInstructions = prog->NumInstructions;
- clone->NumTemporaries = prog->NumTemporaries;
- clone->NumParameters = prog->NumParameters;
- clone->NumAttributes = prog->NumAttributes;
- clone->NumAddressRegs = prog->NumAddressRegs;
- clone->NumNativeInstructions = prog->NumNativeInstructions;
- clone->NumNativeTemporaries = prog->NumNativeTemporaries;
- clone->NumNativeParameters = prog->NumNativeParameters;
- clone->NumNativeAttributes = prog->NumNativeAttributes;
- clone->NumNativeAddressRegs = prog->NumNativeAddressRegs;
- clone->NumAluInstructions = prog->NumAluInstructions;
- clone->NumTexInstructions = prog->NumTexInstructions;
- clone->NumTexIndirections = prog->NumTexIndirections;
- clone->NumNativeAluInstructions = prog->NumNativeAluInstructions;
- clone->NumNativeTexInstructions = prog->NumNativeTexInstructions;
- clone->NumNativeTexIndirections = prog->NumNativeTexIndirections;
-
- switch (prog->Target) {
- case GL_VERTEX_PROGRAM_ARB:
- {
- const struct gl_vertex_program *vp
- = (const struct gl_vertex_program *) prog;
- struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone;
- vpc->IsPositionInvariant = vp->IsPositionInvariant;
- vpc->IsNVProgram = vp->IsNVProgram;
- }
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- {
- const struct gl_fragment_program *fp
- = (const struct gl_fragment_program *) prog;
- struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone;
- fpc->FogOption = fp->FogOption;
- fpc->UsesKill = fp->UsesKill;
- fpc->OriginUpperLeft = fp->OriginUpperLeft;
- fpc->PixelCenterInteger = fp->PixelCenterInteger;
- }
- break;
- case MESA_GEOMETRY_PROGRAM:
- {
- const struct gl_geometry_program *gp
- = (const struct gl_geometry_program *) prog;
- struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone;
- gpc->VerticesOut = gp->VerticesOut;
- gpc->InputType = gp->InputType;
- gpc->OutputType = gp->OutputType;
- }
- break;
- default:
- _mesa_problem(NULL, "Unexpected target in _mesa_clone_program");
- }
-
- return clone;
-}
-
-
-/**
- * Insert 'count' NOP instructions at 'start' in the given program.
- * Adjust branch targets accordingly.
- */
-GLboolean
-_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
-{
- const GLuint origLen = prog->NumInstructions;
- const GLuint newLen = origLen + count;
- struct prog_instruction *newInst;
- GLuint i;
-
- /* adjust branches */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- if (inst->BranchTarget > 0) {
- if ((GLuint)inst->BranchTarget >= start) {
- inst->BranchTarget += count;
- }
- }
- }
-
- /* Alloc storage for new instructions */
- newInst = _mesa_alloc_instructions(newLen);
- if (!newInst) {
- return GL_FALSE;
- }
-
- /* Copy 'start' instructions into new instruction buffer */
- _mesa_copy_instructions(newInst, prog->Instructions, start);
-
- /* init the new instructions */
- _mesa_init_instructions(newInst + start, count);
-
- /* Copy the remaining/tail instructions to new inst buffer */
- _mesa_copy_instructions(newInst + start + count,
- prog->Instructions + start,
- origLen - start);
-
- /* free old instructions */
- _mesa_free_instructions(prog->Instructions, origLen);
-
- /* install new instructions */
- prog->Instructions = newInst;
- prog->NumInstructions = newLen;
-
- return GL_TRUE;
-}
-
-/**
- * Delete 'count' instructions at 'start' in the given program.
- * Adjust branch targets accordingly.
- */
-GLboolean
-_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
-{
- const GLuint origLen = prog->NumInstructions;
- const GLuint newLen = origLen - count;
- struct prog_instruction *newInst;
- GLuint i;
-
- /* adjust branches */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- if (inst->BranchTarget > 0) {
- if (inst->BranchTarget > (GLint) start) {
- inst->BranchTarget -= count;
- }
- }
- }
-
- /* Alloc storage for new instructions */
- newInst = _mesa_alloc_instructions(newLen);
- if (!newInst) {
- return GL_FALSE;
- }
-
- /* Copy 'start' instructions into new instruction buffer */
- _mesa_copy_instructions(newInst, prog->Instructions, start);
-
- /* Copy the remaining/tail instructions to new inst buffer */
- _mesa_copy_instructions(newInst + start,
- prog->Instructions + start + count,
- newLen - start);
-
- /* free old instructions */
- _mesa_free_instructions(prog->Instructions, origLen);
-
- /* install new instructions */
- prog->Instructions = newInst;
- prog->NumInstructions = newLen;
-
- return GL_TRUE;
-}
-
-
-/**
- * Search instructions for registers that match (oldFile, oldIndex),
- * replacing them with (newFile, newIndex).
- */
-static void
-replace_registers(struct prog_instruction *inst, GLuint numInst,
- GLuint oldFile, GLuint oldIndex,
- GLuint newFile, GLuint newIndex)
-{
- GLuint i, j;
- for (i = 0; i < numInst; i++) {
- /* src regs */
- for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
- if (inst[i].SrcReg[j].File == oldFile &&
- inst[i].SrcReg[j].Index == oldIndex) {
- inst[i].SrcReg[j].File = newFile;
- inst[i].SrcReg[j].Index = newIndex;
- }
- }
- /* dst reg */
- if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
- inst[i].DstReg.File = newFile;
- inst[i].DstReg.Index = newIndex;
- }
- }
-}
-
-
-/**
- * Search instructions for references to program parameters. When found,
- * increment the parameter index by 'offset'.
- * Used when combining programs.
- */
-static void
-adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
- GLuint offset)
-{
- GLuint i, j;
- for (i = 0; i < numInst; i++) {
- for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
- GLuint f = inst[i].SrcReg[j].File;
- if (f == PROGRAM_CONSTANT ||
- f == PROGRAM_UNIFORM ||
- f == PROGRAM_STATE_VAR) {
- inst[i].SrcReg[j].Index += offset;
- }
- }
- }
-}
-
-
-/**
- * Combine two programs into one. Fix instructions so the outputs of
- * the first program go to the inputs of the second program.
- */
-struct gl_program *
-_mesa_combine_programs(GLcontext *ctx,
- const struct gl_program *progA,
- const struct gl_program *progB)
-{
- struct prog_instruction *newInst;
- struct gl_program *newProg;
- const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
- const GLuint lenB = progB->NumInstructions;
- const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
- const GLuint newLength = lenA + lenB;
- GLboolean usedTemps[MAX_PROGRAM_TEMPS];
- GLuint firstTemp = 0;
- GLbitfield inputsB;
- GLuint i;
-
- ASSERT(progA->Target == progB->Target);
-
- newInst = _mesa_alloc_instructions(newLength);
- if (!newInst)
- return GL_FALSE;
-
- _mesa_copy_instructions(newInst, progA->Instructions, lenA);
- _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);
-
- /* adjust branch / instruction addresses for B's instructions */
- for (i = 0; i < lenB; i++) {
- newInst[lenA + i].BranchTarget += lenA;
- }
-
- newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
- newProg->Instructions = newInst;
- newProg->NumInstructions = newLength;
-
- /* find used temp regs (we may need new temps below) */
- _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY,
- usedTemps, MAX_PROGRAM_TEMPS);
-
- if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
- struct gl_fragment_program *fprogA, *fprogB, *newFprog;
- GLbitfield progB_inputsRead = progB->InputsRead;
- GLint progB_colorFile, progB_colorIndex;
-
- fprogA = (struct gl_fragment_program *) progA;
- fprogB = (struct gl_fragment_program *) progB;
- newFprog = (struct gl_fragment_program *) newProg;
-
- newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;
-
- /* We'll do a search and replace for instances
- * of progB_colorFile/progB_colorIndex below...
- */
- progB_colorFile = PROGRAM_INPUT;
- progB_colorIndex = FRAG_ATTRIB_COL0;
-
- /*
- * The fragment program may get color from a state var rather than
- * a fragment input (vertex output) if it's constant.
- * See the texenvprogram.c code.
- * So, search the program's parameter list now to see if the program
- * gets color from a state var instead of a conventional fragment
- * input register.
- */
- for (i = 0; i < progB->Parameters->NumParameters; i++) {
- struct gl_program_parameter *p = &progB->Parameters->Parameters[i];
- if (p->Type == PROGRAM_STATE_VAR &&
- p->StateIndexes[0] == STATE_INTERNAL &&
- p->StateIndexes[1] == STATE_CURRENT_ATTRIB &&
- p->StateIndexes[2] == VERT_ATTRIB_COLOR0) {
- progB_inputsRead |= FRAG_BIT_COL0;
- progB_colorFile = PROGRAM_STATE_VAR;
- progB_colorIndex = i;
- break;
- }
- }
-
- /* Connect color outputs of fprogA to color inputs of fprogB, via a
- * new temporary register.
- */
- if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) &&
- (progB_inputsRead & FRAG_BIT_COL0)) {
- GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS,
- firstTemp);
- if (tempReg < 0) {
- _mesa_problem(ctx, "No free temp regs found in "
- "_mesa_combine_programs(), using 31");
- tempReg = 31;
- }
- firstTemp = tempReg + 1;
-
- /* replace writes to result.color[0] with tempReg */
- replace_registers(newInst, lenA,
- PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
- PROGRAM_TEMPORARY, tempReg);
- /* replace reads from the input color with tempReg */
- replace_registers(newInst + lenA, lenB,
- progB_colorFile, progB_colorIndex, /* search for */
- PROGRAM_TEMPORARY, tempReg /* replace with */ );
- }
-
- /* compute combined program's InputsRead */
- inputsB = progB_inputsRead;
- if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) {
- inputsB &= ~(1 << FRAG_ATTRIB_COL0);
- }
- newProg->InputsRead = progA->InputsRead | inputsB;
- newProg->OutputsWritten = progB->OutputsWritten;
- newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
- }
- else {
- /* vertex program */
- assert(0); /* XXX todo */
- }
-
- /*
- * Merge parameters (uniforms, constants, etc)
- */
- newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
- progB->Parameters);
-
- adjust_param_indexes(newInst + lenA, lenB, numParamsA);
-
-
- return newProg;
-}
-
-
-/**
- * Populate the 'used' array with flags indicating which registers (TEMPs,
- * INPUTs, OUTPUTs, etc, are used by the given program.
- * \param file type of register to scan for
- * \param used returns true/false flags for in use / free
- * \param usedSize size of the 'used' array
- */
-void
-_mesa_find_used_registers(const struct gl_program *prog,
- gl_register_file file,
- GLboolean used[], GLuint usedSize)
-{
- GLuint i, j;
-
- memset(used, 0, usedSize);
-
- for (i = 0; i < prog->NumInstructions; i++) {
- const struct prog_instruction *inst = prog->Instructions + i;
- const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
-
- if (inst->DstReg.File == file) {
- ASSERT(inst->DstReg.Index < usedSize);
- if(inst->DstReg.Index < usedSize)
- used[inst->DstReg.Index] = GL_TRUE;
- }
-
- for (j = 0; j < n; j++) {
- if (inst->SrcReg[j].File == file) {
- ASSERT(inst->SrcReg[j].Index < usedSize);
- if(inst->SrcReg[j].Index < usedSize)
- used[inst->SrcReg[j].Index] = GL_TRUE;
- }
- }
- }
-}
-
-
-/**
- * Scan the given 'used' register flag array for the first entry
- * that's >= firstReg.
- * \param used vector of flags indicating registers in use (as returned
- * by _mesa_find_used_registers())
- * \param usedSize size of the 'used' array
- * \param firstReg first register to start searching at
- * \return index of unused register, or -1 if none.
- */
-GLint
-_mesa_find_free_register(const GLboolean used[],
- GLuint usedSize, GLuint firstReg)
-{
- GLuint i;
-
- assert(firstReg < usedSize);
-
- for (i = firstReg; i < usedSize; i++)
- if (!used[i])
- return i;
-
- return -1;
-}
-
-
-/**
- * "Post-process" a GPU program. This is intended to be used for debugging.
- * Example actions include no-op'ing instructions or changing instruction
- * behaviour.
- */
-void
-_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog)
-{
- static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
- GLuint i;
- GLuint whiteSwizzle;
- GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
- white, 4, &whiteSwizzle);
-
- (void) whiteIndex;
-
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
-
- (void) n;
-
- if (_mesa_is_tex_instruction(inst->Opcode)) {
-#if 0
- /* replace TEX/TXP/TXB with MOV */
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.WriteMask = WRITEMASK_XYZW;
- inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-#endif
-
-#if 0
- /* disable shadow texture mode */
- inst->TexShadow = 0;
-#endif
- }
-
- if (inst->Opcode == OPCODE_TXP) {
-#if 0
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.WriteMask = WRITEMASK_XYZW;
- inst->SrcReg[0].File = PROGRAM_CONSTANT;
- inst->SrcReg[0].Index = whiteIndex;
- inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-#endif
-#if 0
- inst->TexShadow = 0;
-#endif
-#if 0
- inst->Opcode = OPCODE_TEX;
- inst->TexShadow = 0;
-#endif
- }
-
- }
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.3
+ *
+ * Copyright (C) 1999-2007 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 "main/glheader.h"
+#include "main/context.h"
+#include "main/hash.h"
+#include "program.h"
+#include "prog_cache.h"
+#include "prog_parameter.h"
+#include "prog_instruction.h"
+
+
+/**
+ * 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(struct gl_context *ctx)
+{
+ GLuint i;
+
+ /*
+ * If this assertion fails, we need to increase the field
+ * size for register indexes (see INST_INDEX_BITS).
+ */
+ ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4
+ <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4
+ <= (1 << INST_INDEX_BITS));
+
+ ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
+
+ ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
+ ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
+
+ /* If this fails, increase prog_instruction::TexSrcUnit size */
+ ASSERT(MAX_TEXTURE_UNITS < (1 << 5));
+
+ /* If this fails, increase prog_instruction::TexSrcTarget size */
+ ASSERT(NUM_TEXTURE_TARGETS < (1 << 3));
+
+ ctx->Program.ErrorPos = -1;
+ ctx->Program.ErrorString = _mesa_strdup("");
+
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ ctx->VertexProgram.Enabled = GL_FALSE;
+#if FEATURE_es2_glsl
+ ctx->VertexProgram.PointSizeEnabled =
+ (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
+#else
+ ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
+#endif
+ ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+ ctx->Shared->DefaultVertexProgram);
+ assert(ctx->VertexProgram.Current);
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
+ ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
+ ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
+ }
+ ctx->VertexProgram.Cache = _mesa_new_program_cache();
+#endif
+
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ ctx->FragmentProgram.Enabled = GL_FALSE;
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+ ctx->Shared->DefaultFragmentProgram);
+ assert(ctx->FragmentProgram.Current);
+ ctx->FragmentProgram.Cache = _mesa_new_program_cache();
+#endif
+
+#if FEATURE_ARB_geometry_shader4
+ ctx->GeometryProgram.Enabled = GL_FALSE;
+ /* right now by default we don't have a geometry program */
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
+ NULL);
+ ctx->GeometryProgram.Cache = _mesa_new_program_cache();
+#endif
+
+ /* XXX probably move this stuff */
+#if FEATURE_ATI_fragment_shader
+ ctx->ATIFragmentShader.Enabled = GL_FALSE;
+ ctx->ATIFragmentShader.Current = 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(struct gl_context *ctx)
+{
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
+ _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
+#endif
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
+ _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache);
+#endif
+#if FEATURE_ARB_geometry_shader4
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
+ _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache);
+#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) {
+ free(ctx->ATIFragmentShader.Current);
+ }
+ }
+#endif
+ free((void *) ctx->Program.ErrorString);
+}
+
+
+/**
+ * Update the default program objects in the given context to reference those
+ * specified in the shared state and release those referencing the old
+ * shared state.
+ */
+void
+_mesa_update_default_objects_program(struct gl_context *ctx)
+{
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+ (struct gl_vertex_program *)
+ ctx->Shared->DefaultVertexProgram);
+ assert(ctx->VertexProgram.Current);
+#endif
+
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+ (struct gl_fragment_program *)
+ ctx->Shared->DefaultFragmentProgram);
+ assert(ctx->FragmentProgram.Current);
+#endif
+
+#if FEATURE_ARB_geometry_shader4
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
+ (struct gl_geometry_program *)
+ ctx->Shared->DefaultGeometryProgram);
+#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) {
+ free(ctx->ATIFragmentShader.Current);
+ }
+ }
+ ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
+ assert(ctx->ATIFragmentShader.Current);
+ ctx->ATIFragmentShader.Current->RefCount++;
+#endif
+}
+
+
+/**
+ * Set the vertex/fragment program error state (position and error string).
+ * This is generally called from within the parsers.
+ */
+void
+_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
+{
+ ctx->Program.ErrorPos = pos;
+ 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
+ * 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 *) malloc(len + 1);
+ memcpy(s, lineStart, len);
+ s[len] = 0;
+
+ return s;
+}
+
+
+/**
+ * Initialize a new vertex/fragment program object.
+ */
+static struct gl_program *
+_mesa_init_program_struct( struct gl_context *ctx, struct gl_program *prog,
+ GLenum target, GLuint id)
+{
+ (void) ctx;
+ if (prog) {
+ GLuint i;
+ memset(prog, 0, sizeof(*prog));
+ prog->Id = id;
+ prog->Target = target;
+ prog->Resident = GL_TRUE;
+ prog->RefCount = 1;
+ prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
+
+ /* default mapping from samplers to texture units */
+ for (i = 0; i < MAX_SAMPLERS; i++)
+ prog->SamplerUnits[i] = i;
+ }
+
+ return prog;
+}
+
+
+/**
+ * Initialize a new fragment program object.
+ */
+struct gl_program *
+_mesa_init_fragment_program( struct gl_context *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( struct gl_context *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;
+}
+
+
+/**
+ * Initialize a new geometry program object.
+ */
+struct gl_program *
+_mesa_init_geometry_program( struct gl_context *ctx, struct gl_geometry_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(struct gl_context *ctx, GLenum target, GLuint id)
+{
+ struct gl_program *prog;
+ switch (target) {
+ case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
+ case GL_VERTEX_STATE_PROGRAM_NV:
+ prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
+ target, id );
+ break;
+ case GL_FRAGMENT_PROGRAM_NV:
+ case GL_FRAGMENT_PROGRAM_ARB:
+ prog =_mesa_init_fragment_program(ctx,
+ CALLOC_STRUCT(gl_fragment_program),
+ target, id );
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ prog = _mesa_init_geometry_program(ctx,
+ CALLOC_STRUCT(gl_geometry_program),
+ target, id);
+ break;
+ default:
+ _mesa_problem(ctx, "bad target in _mesa_new_program");
+ prog = NULL;
+ }
+ return prog;
+}
+
+
+/**
+ * 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(struct gl_context *ctx, struct gl_program *prog)
+{
+ (void) ctx;
+ ASSERT(prog);
+ ASSERT(prog->RefCount==0);
+
+ if (prog == &_mesa_DummyProgram)
+ return;
+
+ if (prog->String)
+ free(prog->String);
+
+ _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
+
+ if (prog->Parameters) {
+ _mesa_free_parameter_list(prog->Parameters);
+ }
+ if (prog->Varying) {
+ _mesa_free_parameter_list(prog->Varying);
+ }
+ if (prog->Attributes) {
+ _mesa_free_parameter_list(prog->Attributes);
+ }
+
+ 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(struct gl_context *ctx, GLuint id)
+{
+ if (id)
+ return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+ else
+ return NULL;
+}
+
+
+/**
+ * Reference counting for vertex/fragment programs
+ */
+void
+_mesa_reference_program(struct gl_context *ctx,
+ struct gl_program **ptr,
+ struct gl_program *prog)
+{
+ assert(ptr);
+ if (*ptr && prog) {
+ /* sanity check */
+ if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
+ ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB);
+ else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
+ ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
+ prog->Target == GL_FRAGMENT_PROGRAM_NV);
+ else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM)
+ ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM);
+ }
+ if (*ptr == prog) {
+ return; /* no change */
+ }
+ if (*ptr) {
+ GLboolean deleteFlag;
+
+ /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
+#if 0
+ printf("Program %p ID=%u Target=%s Refcount-- to %d\n",
+ *ptr, (*ptr)->Id,
+ ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
+ ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
+ (*ptr)->RefCount - 1);
+#endif
+ ASSERT((*ptr)->RefCount > 0);
+ (*ptr)->RefCount--;
+
+ deleteFlag = ((*ptr)->RefCount == 0);
+ /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
+
+ if (deleteFlag) {
+ ASSERT(ctx);
+ ctx->Driver.DeleteProgram(ctx, *ptr);
+ }
+
+ *ptr = NULL;
+ }
+
+ assert(!*ptr);
+ if (prog) {
+ /*_glthread_LOCK_MUTEX(prog->Mutex);*/
+ prog->RefCount++;
+#if 0
+ printf("Program %p ID=%u Target=%s Refcount++ to %d\n",
+ prog, prog->Id,
+ (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
+ (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
+ prog->RefCount);
+#endif
+ /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
+ }
+
+ *ptr = prog;
+}
+
+
+/**
+ * Return a copy of a program.
+ * XXX Problem here if the program object is actually OO-derivation
+ * made by a device driver.
+ */
+struct gl_program *
+_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog)
+{
+ struct gl_program *clone;
+
+ clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id);
+ if (!clone)
+ return NULL;
+
+ assert(clone->Target == prog->Target);
+ assert(clone->RefCount == 1);
+
+ clone->String = (GLubyte *) _mesa_strdup((char *) prog->String);
+ clone->Format = prog->Format;
+ clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions);
+ if (!clone->Instructions) {
+ _mesa_reference_program(ctx, &clone, NULL);
+ return NULL;
+ }
+ _mesa_copy_instructions(clone->Instructions, prog->Instructions,
+ prog->NumInstructions);
+ clone->InputsRead = prog->InputsRead;
+ clone->OutputsWritten = prog->OutputsWritten;
+ clone->SamplersUsed = prog->SamplersUsed;
+ clone->ShadowSamplers = prog->ShadowSamplers;
+ memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
+
+ if (prog->Parameters)
+ clone->Parameters = _mesa_clone_parameter_list(prog->Parameters);
+ memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
+ if (prog->Varying)
+ clone->Varying = _mesa_clone_parameter_list(prog->Varying);
+ if (prog->Attributes)
+ clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
+ memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
+ clone->IndirectRegisterFiles = prog->IndirectRegisterFiles;
+ clone->NumInstructions = prog->NumInstructions;
+ clone->NumTemporaries = prog->NumTemporaries;
+ clone->NumParameters = prog->NumParameters;
+ clone->NumAttributes = prog->NumAttributes;
+ clone->NumAddressRegs = prog->NumAddressRegs;
+ clone->NumNativeInstructions = prog->NumNativeInstructions;
+ clone->NumNativeTemporaries = prog->NumNativeTemporaries;
+ clone->NumNativeParameters = prog->NumNativeParameters;
+ clone->NumNativeAttributes = prog->NumNativeAttributes;
+ clone->NumNativeAddressRegs = prog->NumNativeAddressRegs;
+ clone->NumAluInstructions = prog->NumAluInstructions;
+ clone->NumTexInstructions = prog->NumTexInstructions;
+ clone->NumTexIndirections = prog->NumTexIndirections;
+ clone->NumNativeAluInstructions = prog->NumNativeAluInstructions;
+ clone->NumNativeTexInstructions = prog->NumNativeTexInstructions;
+ clone->NumNativeTexIndirections = prog->NumNativeTexIndirections;
+
+ switch (prog->Target) {
+ case GL_VERTEX_PROGRAM_ARB:
+ {
+ const struct gl_vertex_program *vp
+ = (const struct gl_vertex_program *) prog;
+ struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone;
+ vpc->IsPositionInvariant = vp->IsPositionInvariant;
+ vpc->IsNVProgram = vp->IsNVProgram;
+ }
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ {
+ const struct gl_fragment_program *fp
+ = (const struct gl_fragment_program *) prog;
+ struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone;
+ fpc->FogOption = fp->FogOption;
+ fpc->UsesKill = fp->UsesKill;
+ fpc->OriginUpperLeft = fp->OriginUpperLeft;
+ fpc->PixelCenterInteger = fp->PixelCenterInteger;
+ }
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ {
+ const struct gl_geometry_program *gp
+ = (const struct gl_geometry_program *) prog;
+ struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone;
+ gpc->VerticesOut = gp->VerticesOut;
+ gpc->InputType = gp->InputType;
+ gpc->OutputType = gp->OutputType;
+ }
+ break;
+ default:
+ _mesa_problem(NULL, "Unexpected target in _mesa_clone_program");
+ }
+
+ return clone;
+}
+
+
+/**
+ * Insert 'count' NOP instructions at 'start' in the given program.
+ * Adjust branch targets accordingly.
+ */
+GLboolean
+_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
+{
+ const GLuint origLen = prog->NumInstructions;
+ const GLuint newLen = origLen + count;
+ struct prog_instruction *newInst;
+ GLuint i;
+
+ /* adjust branches */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->BranchTarget > 0) {
+ if ((GLuint)inst->BranchTarget >= start) {
+ inst->BranchTarget += count;
+ }
+ }
+ }
+
+ /* Alloc storage for new instructions */
+ newInst = _mesa_alloc_instructions(newLen);
+ if (!newInst) {
+ return GL_FALSE;
+ }
+
+ /* Copy 'start' instructions into new instruction buffer */
+ _mesa_copy_instructions(newInst, prog->Instructions, start);
+
+ /* init the new instructions */
+ _mesa_init_instructions(newInst + start, count);
+
+ /* Copy the remaining/tail instructions to new inst buffer */
+ _mesa_copy_instructions(newInst + start + count,
+ prog->Instructions + start,
+ origLen - start);
+
+ /* free old instructions */
+ _mesa_free_instructions(prog->Instructions, origLen);
+
+ /* install new instructions */
+ prog->Instructions = newInst;
+ prog->NumInstructions = newLen;
+
+ return GL_TRUE;
+}
+
+/**
+ * Delete 'count' instructions at 'start' in the given program.
+ * Adjust branch targets accordingly.
+ */
+GLboolean
+_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
+{
+ const GLuint origLen = prog->NumInstructions;
+ const GLuint newLen = origLen - count;
+ struct prog_instruction *newInst;
+ GLuint i;
+
+ /* adjust branches */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->BranchTarget > 0) {
+ if (inst->BranchTarget > (GLint) start) {
+ inst->BranchTarget -= count;
+ }
+ }
+ }
+
+ /* Alloc storage for new instructions */
+ newInst = _mesa_alloc_instructions(newLen);
+ if (!newInst) {
+ return GL_FALSE;
+ }
+
+ /* Copy 'start' instructions into new instruction buffer */
+ _mesa_copy_instructions(newInst, prog->Instructions, start);
+
+ /* Copy the remaining/tail instructions to new inst buffer */
+ _mesa_copy_instructions(newInst + start,
+ prog->Instructions + start + count,
+ newLen - start);
+
+ /* free old instructions */
+ _mesa_free_instructions(prog->Instructions, origLen);
+
+ /* install new instructions */
+ prog->Instructions = newInst;
+ prog->NumInstructions = newLen;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Search instructions for registers that match (oldFile, oldIndex),
+ * replacing them with (newFile, newIndex).
+ */
+static void
+replace_registers(struct prog_instruction *inst, GLuint numInst,
+ GLuint oldFile, GLuint oldIndex,
+ GLuint newFile, GLuint newIndex)
+{
+ GLuint i, j;
+ for (i = 0; i < numInst; i++) {
+ /* src regs */
+ for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
+ if (inst[i].SrcReg[j].File == oldFile &&
+ inst[i].SrcReg[j].Index == oldIndex) {
+ inst[i].SrcReg[j].File = newFile;
+ inst[i].SrcReg[j].Index = newIndex;
+ }
+ }
+ /* dst reg */
+ if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
+ inst[i].DstReg.File = newFile;
+ inst[i].DstReg.Index = newIndex;
+ }
+ }
+}
+
+
+/**
+ * Search instructions for references to program parameters. When found,
+ * increment the parameter index by 'offset'.
+ * Used when combining programs.
+ */
+static void
+adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
+ GLuint offset)
+{
+ GLuint i, j;
+ for (i = 0; i < numInst; i++) {
+ for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
+ GLuint f = inst[i].SrcReg[j].File;
+ if (f == PROGRAM_CONSTANT ||
+ f == PROGRAM_UNIFORM ||
+ f == PROGRAM_STATE_VAR) {
+ inst[i].SrcReg[j].Index += offset;
+ }
+ }
+ }
+}
+
+
+/**
+ * Combine two programs into one. Fix instructions so the outputs of
+ * the first program go to the inputs of the second program.
+ */
+struct gl_program *
+_mesa_combine_programs(struct gl_context *ctx,
+ const struct gl_program *progA,
+ const struct gl_program *progB)
+{
+ struct prog_instruction *newInst;
+ struct gl_program *newProg;
+ const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
+ const GLuint lenB = progB->NumInstructions;
+ const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
+ const GLuint newLength = lenA + lenB;
+ GLboolean usedTemps[MAX_PROGRAM_TEMPS];
+ GLuint firstTemp = 0;
+ GLbitfield inputsB;
+ GLuint i;
+
+ ASSERT(progA->Target == progB->Target);
+
+ newInst = _mesa_alloc_instructions(newLength);
+ if (!newInst)
+ return GL_FALSE;
+
+ _mesa_copy_instructions(newInst, progA->Instructions, lenA);
+ _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);
+
+ /* adjust branch / instruction addresses for B's instructions */
+ for (i = 0; i < lenB; i++) {
+ newInst[lenA + i].BranchTarget += lenA;
+ }
+
+ newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
+ newProg->Instructions = newInst;
+ newProg->NumInstructions = newLength;
+
+ /* find used temp regs (we may need new temps below) */
+ _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY,
+ usedTemps, MAX_PROGRAM_TEMPS);
+
+ if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
+ struct gl_fragment_program *fprogA, *fprogB, *newFprog;
+ GLbitfield progB_inputsRead = progB->InputsRead;
+ GLint progB_colorFile, progB_colorIndex;
+
+ fprogA = (struct gl_fragment_program *) progA;
+ fprogB = (struct gl_fragment_program *) progB;
+ newFprog = (struct gl_fragment_program *) newProg;
+
+ newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;
+
+ /* We'll do a search and replace for instances
+ * of progB_colorFile/progB_colorIndex below...
+ */
+ progB_colorFile = PROGRAM_INPUT;
+ progB_colorIndex = FRAG_ATTRIB_COL0;
+
+ /*
+ * The fragment program may get color from a state var rather than
+ * a fragment input (vertex output) if it's constant.
+ * See the texenvprogram.c code.
+ * So, search the program's parameter list now to see if the program
+ * gets color from a state var instead of a conventional fragment
+ * input register.
+ */
+ for (i = 0; i < progB->Parameters->NumParameters; i++) {
+ struct gl_program_parameter *p = &progB->Parameters->Parameters[i];
+ if (p->Type == PROGRAM_STATE_VAR &&
+ p->StateIndexes[0] == STATE_INTERNAL &&
+ p->StateIndexes[1] == STATE_CURRENT_ATTRIB &&
+ (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) {
+ progB_inputsRead |= FRAG_BIT_COL0;
+ progB_colorFile = PROGRAM_STATE_VAR;
+ progB_colorIndex = i;
+ break;
+ }
+ }
+
+ /* Connect color outputs of fprogA to color inputs of fprogB, via a
+ * new temporary register.
+ */
+ if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) &&
+ (progB_inputsRead & FRAG_BIT_COL0)) {
+ GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS,
+ firstTemp);
+ if (tempReg < 0) {
+ _mesa_problem(ctx, "No free temp regs found in "
+ "_mesa_combine_programs(), using 31");
+ tempReg = 31;
+ }
+ firstTemp = tempReg + 1;
+
+ /* replace writes to result.color[0] with tempReg */
+ replace_registers(newInst, lenA,
+ PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
+ PROGRAM_TEMPORARY, tempReg);
+ /* replace reads from the input color with tempReg */
+ replace_registers(newInst + lenA, lenB,
+ progB_colorFile, progB_colorIndex, /* search for */
+ PROGRAM_TEMPORARY, tempReg /* replace with */ );
+ }
+
+ /* compute combined program's InputsRead */
+ inputsB = progB_inputsRead;
+ if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) {
+ inputsB &= ~(1 << FRAG_ATTRIB_COL0);
+ }
+ newProg->InputsRead = progA->InputsRead | inputsB;
+ newProg->OutputsWritten = progB->OutputsWritten;
+ newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
+ }
+ else {
+ /* vertex program */
+ assert(0); /* XXX todo */
+ }
+
+ /*
+ * Merge parameters (uniforms, constants, etc)
+ */
+ newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
+ progB->Parameters);
+
+ adjust_param_indexes(newInst + lenA, lenB, numParamsA);
+
+
+ return newProg;
+}
+
+
+/**
+ * Populate the 'used' array with flags indicating which registers (TEMPs,
+ * INPUTs, OUTPUTs, etc, are used by the given program.
+ * \param file type of register to scan for
+ * \param used returns true/false flags for in use / free
+ * \param usedSize size of the 'used' array
+ */
+void
+_mesa_find_used_registers(const struct gl_program *prog,
+ gl_register_file file,
+ GLboolean used[], GLuint usedSize)
+{
+ GLuint i, j;
+
+ memset(used, 0, usedSize);
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
+
+ if (inst->DstReg.File == file) {
+ ASSERT(inst->DstReg.Index < usedSize);
+ if(inst->DstReg.Index < usedSize)
+ used[inst->DstReg.Index] = GL_TRUE;
+ }
+
+ for (j = 0; j < n; j++) {
+ if (inst->SrcReg[j].File == file) {
+ ASSERT(inst->SrcReg[j].Index < usedSize);
+ if(inst->SrcReg[j].Index < usedSize)
+ used[inst->SrcReg[j].Index] = GL_TRUE;
+ }
+ }
+ }
+}
+
+
+/**
+ * Scan the given 'used' register flag array for the first entry
+ * that's >= firstReg.
+ * \param used vector of flags indicating registers in use (as returned
+ * by _mesa_find_used_registers())
+ * \param usedSize size of the 'used' array
+ * \param firstReg first register to start searching at
+ * \return index of unused register, or -1 if none.
+ */
+GLint
+_mesa_find_free_register(const GLboolean used[],
+ GLuint usedSize, GLuint firstReg)
+{
+ GLuint i;
+
+ assert(firstReg < usedSize);
+
+ for (i = firstReg; i < usedSize; i++)
+ if (!used[i])
+ return i;
+
+ return -1;
+}
+
+
+
+/**
+ * Check if the given register index is valid (doesn't exceed implementation-
+ * dependent limits).
+ * \return GL_TRUE if OK, GL_FALSE if bad index
+ */
+GLboolean
+_mesa_valid_register_index(const struct gl_context *ctx,
+ gl_shader_type shaderType,
+ gl_register_file file, GLint index)
+{
+ const struct gl_program_constants *c;
+
+ switch (shaderType) {
+ case MESA_SHADER_VERTEX:
+ c = &ctx->Const.VertexProgram;
+ break;
+ case MESA_SHADER_FRAGMENT:
+ c = &ctx->Const.FragmentProgram;
+ break;
+ case MESA_SHADER_GEOMETRY:
+ c = &ctx->Const.GeometryProgram;
+ break;
+ default:
+ _mesa_problem(ctx,
+ "unexpected shader type in _mesa_valid_register_index()");
+ return GL_FALSE;
+ }
+
+ switch (file) {
+ case PROGRAM_UNDEFINED:
+ return GL_TRUE; /* XXX or maybe false? */
+
+ case PROGRAM_TEMPORARY:
+ return index >= 0 && index < c->MaxTemps;
+
+ case PROGRAM_ENV_PARAM:
+ return index >= 0 && index < c->MaxEnvParams;
+
+ case PROGRAM_LOCAL_PARAM:
+ return index >= 0 && index < c->MaxLocalParams;
+
+ case PROGRAM_NAMED_PARAM:
+ return index >= 0 && index < c->MaxParameters;
+
+ case PROGRAM_UNIFORM:
+ case PROGRAM_STATE_VAR:
+ /* aka constant buffer */
+ return index >= 0 && index < c->MaxUniformComponents / 4;
+
+ case PROGRAM_CONSTANT:
+ /* constant buffer w/ possible relative negative addressing */
+ return (index > (int) c->MaxUniformComponents / -4 &&
+ index < c->MaxUniformComponents / 4);
+
+ case PROGRAM_INPUT:
+ if (index < 0)
+ return GL_FALSE;
+
+ switch (shaderType) {
+ case MESA_SHADER_VERTEX:
+ return index < VERT_ATTRIB_GENERIC0 + c->MaxAttribs;
+ case MESA_SHADER_FRAGMENT:
+ return index < FRAG_ATTRIB_VAR0 + ctx->Const.MaxVarying;
+ case MESA_SHADER_GEOMETRY:
+ return index < GEOM_ATTRIB_VAR0 + ctx->Const.MaxVarying;
+ default:
+ return GL_FALSE;
+ }
+
+ case PROGRAM_OUTPUT:
+ if (index < 0)
+ return GL_FALSE;
+
+ switch (shaderType) {
+ case MESA_SHADER_VERTEX:
+ return index < VERT_RESULT_VAR0 + ctx->Const.MaxVarying;
+ case MESA_SHADER_FRAGMENT:
+ return index < FRAG_RESULT_DATA0 + ctx->Const.MaxDrawBuffers;
+ case MESA_SHADER_GEOMETRY:
+ return index < GEOM_RESULT_VAR0 + ctx->Const.MaxVarying;
+ default:
+ return GL_FALSE;
+ }
+
+ case PROGRAM_ADDRESS:
+ return index >= 0 && index < c->MaxAddressRegs;
+
+ default:
+ _mesa_problem(ctx,
+ "unexpected register file in _mesa_valid_register_index()");
+ return GL_FALSE;
+ }
+}
+
+
+
+/**
+ * "Post-process" a GPU program. This is intended to be used for debugging.
+ * Example actions include no-op'ing instructions or changing instruction
+ * behaviour.
+ */
+void
+_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog)
+{
+ static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
+ GLuint i;
+ GLuint whiteSwizzle;
+ GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
+ white, 4, &whiteSwizzle);
+
+ (void) whiteIndex;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
+
+ (void) n;
+
+ if (_mesa_is_tex_instruction(inst->Opcode)) {
+#if 0
+ /* replace TEX/TXP/TXB with MOV */
+ inst->Opcode = OPCODE_MOV;
+ inst->DstReg.WriteMask = WRITEMASK_XYZW;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
+ inst->SrcReg[0].Negate = NEGATE_NONE;
+#endif
+
+#if 0
+ /* disable shadow texture mode */
+ inst->TexShadow = 0;
+#endif
+ }
+
+ if (inst->Opcode == OPCODE_TXP) {
+#if 0
+ inst->Opcode = OPCODE_MOV;
+ inst->DstReg.WriteMask = WRITEMASK_XYZW;
+ inst->SrcReg[0].File = PROGRAM_CONSTANT;
+ inst->SrcReg[0].Index = whiteIndex;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
+ inst->SrcReg[0].Negate = NEGATE_NONE;
+#endif
+#if 0
+ inst->TexShadow = 0;
+#endif
+#if 0
+ inst->Opcode = OPCODE_TEX;
+ inst->TexShadow = 0;
+#endif
+ }
+
+ }
+}
diff --git a/mesalib/src/mesa/program/program.h b/mesalib/src/mesa/program/program.h
index f8f379808..dcf8d1c25 100644
--- a/mesalib/src/mesa/program/program.h
+++ b/mesalib/src/mesa/program/program.h
@@ -1,203 +1,210 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.3
- *
- * Copyright (C) 1999-2007 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 "main/mtypes.h"
-
-
-extern struct gl_program _mesa_DummyProgram;
-
-
-extern void
-_mesa_init_program(GLcontext *ctx);
-
-extern void
-_mesa_free_program_data(GLcontext *ctx);
-
-extern void
-_mesa_update_default_objects_program(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_init_geometry_program(GLcontext *ctx,
- struct gl_geometry_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 void
-_mesa_reference_program(GLcontext *ctx,
- struct gl_program **ptr,
- struct gl_program *prog);
-
-static INLINE void
-_mesa_reference_vertprog(GLcontext *ctx,
- struct gl_vertex_program **ptr,
- struct gl_vertex_program *prog)
-{
- _mesa_reference_program(ctx, (struct gl_program **) ptr,
- (struct gl_program *) prog);
-}
-
-static INLINE void
-_mesa_reference_fragprog(GLcontext *ctx,
- struct gl_fragment_program **ptr,
- struct gl_fragment_program *prog)
-{
- _mesa_reference_program(ctx, (struct gl_program **) ptr,
- (struct gl_program *) prog);
-}
-
-static INLINE void
-_mesa_reference_geomprog(GLcontext *ctx,
- struct gl_geometry_program **ptr,
- struct gl_geometry_program *prog)
-{
- _mesa_reference_program(ctx, (struct gl_program **) ptr,
- (struct gl_program *) prog);
-}
-
-extern struct gl_program *
-_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog);
-
-static INLINE struct gl_vertex_program *
-_mesa_clone_vertex_program(GLcontext *ctx,
- const struct gl_vertex_program *prog)
-{
- return (struct gl_vertex_program *) _mesa_clone_program(ctx, &prog->Base);
-}
-
-static INLINE struct gl_geometry_program *
-_mesa_clone_geometry_program(GLcontext *ctx,
- const struct gl_geometry_program *prog)
-{
- return (struct gl_geometry_program *) _mesa_clone_program(ctx, &prog->Base);
-}
-
-static INLINE struct gl_fragment_program *
-_mesa_clone_fragment_program(GLcontext *ctx,
- const struct gl_fragment_program *prog)
-{
- return (struct gl_fragment_program *) _mesa_clone_program(ctx, &prog->Base);
-}
-
-
-extern GLboolean
-_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count);
-
-extern GLboolean
-_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count);
-
-extern struct gl_program *
-_mesa_combine_programs(GLcontext *ctx,
- const struct gl_program *progA,
- const struct gl_program *progB);
-
-extern void
-_mesa_find_used_registers(const struct gl_program *prog,
- gl_register_file file,
- GLboolean used[], GLuint usedSize);
-
-extern GLint
-_mesa_find_free_register(const GLboolean used[],
- GLuint maxRegs, GLuint firstReg);
-
-extern void
-_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog);
-
-/* keep these in the same order as TGSI_PROCESSOR_* */
-
-static INLINE GLuint
-_mesa_program_target_to_index(GLenum v)
-{
- switch(v)
- {
- case GL_VERTEX_PROGRAM_ARB:
- return MESA_SHADER_VERTEX;
- case GL_FRAGMENT_PROGRAM_ARB:
- return MESA_SHADER_FRAGMENT;
- case GL_GEOMETRY_PROGRAM_NV:
- return MESA_SHADER_GEOMETRY;
- default:
- ASSERT(0);
- return ~0;
- }
-}
-
-static INLINE GLenum
-_mesa_program_index_to_target(GLuint i)
-{
- GLenum enums[MESA_SHADER_TYPES] = {
- GL_VERTEX_PROGRAM_ARB,
- GL_FRAGMENT_PROGRAM_ARB,
- GL_GEOMETRY_PROGRAM_NV,
- };
- if(i >= MESA_SHADER_TYPES)
- return 0;
- else
- return enums[i];
-}
-
-#endif /* PROGRAM_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.3
+ *
+ * Copyright (C) 1999-2007 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 "main/compiler.h"
+#include "main/mtypes.h"
+
+
+extern struct gl_program _mesa_DummyProgram;
+
+
+extern void
+_mesa_init_program(struct gl_context *ctx);
+
+extern void
+_mesa_free_program_data(struct gl_context *ctx);
+
+extern void
+_mesa_update_default_objects_program(struct gl_context *ctx);
+
+extern void
+_mesa_set_program_error(struct gl_context *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(struct gl_context *ctx,
+ struct gl_vertex_program *prog,
+ GLenum target, GLuint id);
+
+extern struct gl_program *
+_mesa_init_fragment_program(struct gl_context *ctx,
+ struct gl_fragment_program *prog,
+ GLenum target, GLuint id);
+
+extern struct gl_program *
+_mesa_init_geometry_program(struct gl_context *ctx,
+ struct gl_geometry_program *prog,
+ GLenum target, GLuint id);
+
+extern struct gl_program *
+_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id);
+
+extern void
+_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog);
+
+extern struct gl_program *
+_mesa_lookup_program(struct gl_context *ctx, GLuint id);
+
+extern void
+_mesa_reference_program(struct gl_context *ctx,
+ struct gl_program **ptr,
+ struct gl_program *prog);
+
+static INLINE void
+_mesa_reference_vertprog(struct gl_context *ctx,
+ struct gl_vertex_program **ptr,
+ struct gl_vertex_program *prog)
+{
+ _mesa_reference_program(ctx, (struct gl_program **) ptr,
+ (struct gl_program *) prog);
+}
+
+static INLINE void
+_mesa_reference_fragprog(struct gl_context *ctx,
+ struct gl_fragment_program **ptr,
+ struct gl_fragment_program *prog)
+{
+ _mesa_reference_program(ctx, (struct gl_program **) ptr,
+ (struct gl_program *) prog);
+}
+
+static INLINE void
+_mesa_reference_geomprog(struct gl_context *ctx,
+ struct gl_geometry_program **ptr,
+ struct gl_geometry_program *prog)
+{
+ _mesa_reference_program(ctx, (struct gl_program **) ptr,
+ (struct gl_program *) prog);
+}
+
+extern struct gl_program *
+_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog);
+
+static INLINE struct gl_vertex_program *
+_mesa_clone_vertex_program(struct gl_context *ctx,
+ const struct gl_vertex_program *prog)
+{
+ return (struct gl_vertex_program *) _mesa_clone_program(ctx, &prog->Base);
+}
+
+static INLINE struct gl_geometry_program *
+_mesa_clone_geometry_program(struct gl_context *ctx,
+ const struct gl_geometry_program *prog)
+{
+ return (struct gl_geometry_program *) _mesa_clone_program(ctx, &prog->Base);
+}
+
+static INLINE struct gl_fragment_program *
+_mesa_clone_fragment_program(struct gl_context *ctx,
+ const struct gl_fragment_program *prog)
+{
+ return (struct gl_fragment_program *) _mesa_clone_program(ctx, &prog->Base);
+}
+
+
+extern GLboolean
+_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count);
+
+extern GLboolean
+_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count);
+
+extern struct gl_program *
+_mesa_combine_programs(struct gl_context *ctx,
+ const struct gl_program *progA,
+ const struct gl_program *progB);
+
+extern void
+_mesa_find_used_registers(const struct gl_program *prog,
+ gl_register_file file,
+ GLboolean used[], GLuint usedSize);
+
+extern GLint
+_mesa_find_free_register(const GLboolean used[],
+ GLuint maxRegs, GLuint firstReg);
+
+
+extern GLboolean
+_mesa_valid_register_index(const struct gl_context *ctx,
+ gl_shader_type shaderType,
+ gl_register_file file, GLint index);
+
+extern void
+_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog);
+
+/* keep these in the same order as TGSI_PROCESSOR_* */
+
+static INLINE GLuint
+_mesa_program_target_to_index(GLenum v)
+{
+ switch(v)
+ {
+ case GL_VERTEX_PROGRAM_ARB:
+ return MESA_SHADER_VERTEX;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ return MESA_SHADER_FRAGMENT;
+ case GL_GEOMETRY_PROGRAM_NV:
+ return MESA_SHADER_GEOMETRY;
+ default:
+ ASSERT(0);
+ return ~0;
+ }
+}
+
+static INLINE GLenum
+_mesa_program_index_to_target(GLuint i)
+{
+ GLenum enums[MESA_SHADER_TYPES] = {
+ GL_VERTEX_PROGRAM_ARB,
+ GL_FRAGMENT_PROGRAM_ARB,
+ GL_GEOMETRY_PROGRAM_NV,
+ };
+ if(i >= MESA_SHADER_TYPES)
+ return 0;
+ else
+ return enums[i];
+}
+
+#endif /* PROGRAM_H */
diff --git a/mesalib/src/mesa/program/program_parse.tab.c b/mesalib/src/mesa/program/program_parse.tab.c
index 08ead30de..80735af85 100644
--- a/mesalib/src/mesa/program/program_parse.tab.c
+++ b/mesalib/src/mesa/program/program_parse.tab.c
@@ -1,5730 +1,5730 @@
-
-/* A Bison parser, made by GNU Bison 2.4.1. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.4.1"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 1
-
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
-/* Using locations. */
-#define YYLSP_NEEDED 1
-
-
-
-/* Copy the first part of user declarations. */
-
-/* Line 189 of yacc.c */
-#line 1 "program_parse.y"
-
-/*
- * Copyright © 2009 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "main/mtypes.h"
-#include "main/imports.h"
-#include "program/program.h"
-#include "program/prog_parameter.h"
-#include "program/prog_parameter_layout.h"
-#include "program/prog_statevars.h"
-#include "program/prog_instruction.h"
-
-#include "program/symbol_table.h"
-#include "program/program_parser.h"
-
-extern void *yy_scan_string(char *);
-extern void yy_delete_buffer(void *);
-
-static struct asm_symbol *declare_variable(struct asm_parser_state *state,
- char *name, enum asm_type t, struct YYLTYPE *locp);
-
-static int add_state_reference(struct gl_program_parameter_list *param_list,
- const gl_state_index tokens[STATE_LENGTH]);
-
-static int initialize_symbol_from_state(struct gl_program *prog,
- struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
-
-static int initialize_symbol_from_param(struct gl_program *prog,
- struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
-
-static int initialize_symbol_from_const(struct gl_program *prog,
- struct asm_symbol *param_var, const struct asm_vector *vec,
- GLboolean allowSwizzle);
-
-static int yyparse(struct asm_parser_state *state);
-
-static char *make_error_string(const char *fmt, ...);
-
-static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state,
- const char *s);
-
-static int validate_inputs(struct YYLTYPE *locp,
- struct asm_parser_state *state);
-
-static void init_dst_reg(struct prog_dst_register *r);
-
-static void set_dst_reg(struct prog_dst_register *r,
- gl_register_file file, GLint index);
-
-static void init_src_reg(struct asm_src_register *r);
-
-static void set_src_reg(struct asm_src_register *r,
- gl_register_file file, GLint index);
-
-static void set_src_reg_swz(struct asm_src_register *r,
- gl_register_file file, GLint index, GLuint swizzle);
-
-static void asm_instruction_set_operands(struct asm_instruction *inst,
- const struct prog_dst_register *dst, const struct asm_src_register *src0,
- const struct asm_src_register *src1, const struct asm_src_register *src2);
-
-static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
- const struct prog_dst_register *dst, const struct asm_src_register *src0,
- const struct asm_src_register *src1, const struct asm_src_register *src2);
-
-static struct asm_instruction *asm_instruction_copy_ctor(
- const struct prog_instruction *base, const struct prog_dst_register *dst,
- const struct asm_src_register *src0, const struct asm_src_register *src1,
- const struct asm_src_register *src2);
-
-#ifndef FALSE
-#define FALSE 0
-#define TRUE (!FALSE)
-#endif
-
-#define YYLLOC_DEFAULT(Current, Rhs, N) \
- do { \
- if (YYID(N)) { \
- (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
- (Current).position = YYRHSLOC(Rhs, 1).position; \
- (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC(Rhs, N).last_column; \
- } else { \
- (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
- (Current).last_line = (Current).first_line; \
- (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \
- (Current).last_column = (Current).first_column; \
- (Current).position = YYRHSLOC(Rhs, 0).position \
- + (Current).first_column; \
- } \
- } while(YYID(0))
-
-#define YYLEX_PARAM state->scanner
-
-
-/* Line 189 of yacc.c */
-#line 193 "program_parse.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- ARBvp_10 = 258,
- ARBfp_10 = 259,
- ADDRESS = 260,
- ALIAS = 261,
- ATTRIB = 262,
- OPTION = 263,
- OUTPUT = 264,
- PARAM = 265,
- TEMP = 266,
- END = 267,
- BIN_OP = 268,
- BINSC_OP = 269,
- SAMPLE_OP = 270,
- SCALAR_OP = 271,
- TRI_OP = 272,
- VECTOR_OP = 273,
- ARL = 274,
- KIL = 275,
- SWZ = 276,
- TXD_OP = 277,
- INTEGER = 278,
- REAL = 279,
- AMBIENT = 280,
- ATTENUATION = 281,
- BACK = 282,
- CLIP = 283,
- COLOR = 284,
- DEPTH = 285,
- DIFFUSE = 286,
- DIRECTION = 287,
- EMISSION = 288,
- ENV = 289,
- EYE = 290,
- FOG = 291,
- FOGCOORD = 292,
- FRAGMENT = 293,
- FRONT = 294,
- HALF = 295,
- INVERSE = 296,
- INVTRANS = 297,
- LIGHT = 298,
- LIGHTMODEL = 299,
- LIGHTPROD = 300,
- LOCAL = 301,
- MATERIAL = 302,
- MAT_PROGRAM = 303,
- MATRIX = 304,
- MATRIXINDEX = 305,
- MODELVIEW = 306,
- MVP = 307,
- NORMAL = 308,
- OBJECT = 309,
- PALETTE = 310,
- PARAMS = 311,
- PLANE = 312,
- POINT_TOK = 313,
- POINTSIZE = 314,
- POSITION = 315,
- PRIMARY = 316,
- PROGRAM = 317,
- PROJECTION = 318,
- RANGE = 319,
- RESULT = 320,
- ROW = 321,
- SCENECOLOR = 322,
- SECONDARY = 323,
- SHININESS = 324,
- SIZE_TOK = 325,
- SPECULAR = 326,
- SPOT = 327,
- STATE = 328,
- TEXCOORD = 329,
- TEXENV = 330,
- TEXGEN = 331,
- TEXGEN_Q = 332,
- TEXGEN_R = 333,
- TEXGEN_S = 334,
- TEXGEN_T = 335,
- TEXTURE = 336,
- TRANSPOSE = 337,
- TEXTURE_UNIT = 338,
- TEX_1D = 339,
- TEX_2D = 340,
- TEX_3D = 341,
- TEX_CUBE = 342,
- TEX_RECT = 343,
- TEX_SHADOW1D = 344,
- TEX_SHADOW2D = 345,
- TEX_SHADOWRECT = 346,
- TEX_ARRAY1D = 347,
- TEX_ARRAY2D = 348,
- TEX_ARRAYSHADOW1D = 349,
- TEX_ARRAYSHADOW2D = 350,
- VERTEX = 351,
- VTXATTRIB = 352,
- WEIGHT = 353,
- IDENTIFIER = 354,
- USED_IDENTIFIER = 355,
- MASK4 = 356,
- MASK3 = 357,
- MASK2 = 358,
- MASK1 = 359,
- SWIZZLE = 360,
- DOT_DOT = 361,
- DOT = 362
- };
-#endif
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-{
-
-/* Line 214 of yacc.c */
-#line 126 "program_parse.y"
-
- struct asm_instruction *inst;
- struct asm_symbol *sym;
- struct asm_symbol temp_sym;
- struct asm_swizzle_mask swiz_mask;
- struct asm_src_register src_reg;
- struct prog_dst_register dst_reg;
- struct prog_instruction temp_inst;
- char *string;
- unsigned result;
- unsigned attrib;
- int integer;
- float real;
- gl_state_index state[STATE_LENGTH];
- int negate;
- struct asm_vector vector;
- gl_inst_opcode opcode;
-
- struct {
- unsigned swz;
- unsigned rgba_valid:1;
- unsigned xyzw_valid:1;
- unsigned negate:1;
- } ext_swizzle;
-
-
-
-/* Line 214 of yacc.c */
-#line 364 "program_parse.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
-{
- int first_line;
- int first_column;
- int last_line;
- int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
-# define YYLTYPE_IS_DECLARED 1
-# define YYLTYPE_IS_TRIVIAL 1
-#endif
-
-
-/* Copy the second part of user declarations. */
-
-/* Line 264 of yacc.c */
-#line 271 "program_parse.y"
-
-extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param,
- void *yyscanner);
-
-
-/* Line 264 of yacc.c */
-#line 395 "program_parse.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
-#else
-static int
-YYID (yyi)
- int yyi;
-#endif
-{
- return yyi;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
- && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
- YYLTYPE yyls_alloc;
-};
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
- + 2 * YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 5
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 396
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 120
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 143
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 282
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 475
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 362
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 115, 116, 2, 113, 109, 114, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 108,
- 2, 117, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 111, 2, 112, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 118, 110, 119, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
- 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
- 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
- 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
- 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
- 105, 106, 107
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 8, 10, 12, 15, 16, 20, 23,
- 24, 27, 30, 32, 34, 36, 38, 40, 42, 44,
- 46, 48, 50, 52, 54, 59, 64, 69, 76, 83,
- 92, 101, 104, 107, 120, 123, 125, 127, 129, 131,
- 133, 135, 137, 139, 141, 143, 145, 147, 154, 157,
- 162, 165, 167, 171, 177, 181, 184, 192, 195, 197,
- 199, 201, 203, 208, 210, 212, 214, 216, 218, 220,
- 222, 226, 227, 230, 233, 235, 237, 239, 241, 243,
- 245, 247, 249, 251, 252, 254, 256, 258, 260, 261,
- 265, 269, 270, 273, 276, 278, 280, 282, 284, 286,
- 288, 290, 292, 297, 300, 303, 305, 308, 310, 313,
- 315, 318, 323, 328, 330, 331, 335, 337, 339, 342,
- 344, 347, 349, 351, 355, 362, 363, 365, 368, 373,
- 375, 379, 381, 383, 385, 387, 389, 391, 393, 395,
- 397, 399, 402, 405, 408, 411, 414, 417, 420, 423,
- 426, 429, 432, 435, 439, 441, 443, 445, 451, 453,
- 455, 457, 460, 462, 464, 467, 469, 472, 479, 481,
- 485, 487, 489, 491, 493, 495, 500, 502, 504, 506,
- 508, 510, 512, 515, 517, 519, 525, 527, 530, 532,
- 534, 540, 543, 544, 551, 555, 556, 558, 560, 562,
- 564, 566, 569, 571, 573, 576, 581, 586, 587, 591,
- 593, 595, 597, 600, 602, 604, 606, 608, 614, 616,
- 620, 626, 632, 634, 638, 644, 646, 648, 650, 652,
- 654, 656, 658, 660, 662, 666, 672, 680, 690, 693,
- 696, 698, 700, 701, 702, 707, 709, 710, 711, 715,
- 719, 721, 727, 730, 733, 736, 739, 743, 746, 750,
- 751, 753, 755, 756, 758, 760, 761, 763, 765, 766,
- 768, 770, 771, 775, 776, 780, 781, 785, 787, 789,
- 791, 796, 798
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int16 yyrhs[] =
-{
- 121, 0, -1, 122, 123, 125, 12, -1, 3, -1,
- 4, -1, 123, 124, -1, -1, 8, 262, 108, -1,
- 125, 126, -1, -1, 127, 108, -1, 170, 108, -1,
- 128, -1, 129, -1, 130, -1, 131, -1, 132, -1,
- 133, -1, 134, -1, 135, -1, 141, -1, 136, -1,
- 137, -1, 138, -1, 19, 146, 109, 142, -1, 18,
- 145, 109, 144, -1, 16, 145, 109, 142, -1, 14,
- 145, 109, 142, 109, 142, -1, 13, 145, 109, 144,
- 109, 144, -1, 17, 145, 109, 144, 109, 144, 109,
- 144, -1, 15, 145, 109, 144, 109, 139, 109, 140,
- -1, 20, 144, -1, 20, 166, -1, 22, 145, 109,
- 144, 109, 144, 109, 144, 109, 139, 109, 140, -1,
- 83, 256, -1, 84, -1, 85, -1, 86, -1, 87,
- -1, 88, -1, 89, -1, 90, -1, 91, -1, 92,
- -1, 93, -1, 94, -1, 95, -1, 21, 145, 109,
- 150, 109, 147, -1, 241, 143, -1, 241, 110, 143,
- 110, -1, 150, 162, -1, 238, -1, 241, 150, 163,
- -1, 241, 110, 150, 163, 110, -1, 151, 164, 165,
- -1, 159, 161, -1, 148, 109, 148, 109, 148, 109,
- 148, -1, 241, 149, -1, 23, -1, 262, -1, 100,
- -1, 172, -1, 152, 111, 153, 112, -1, 186, -1,
- 249, -1, 100, -1, 100, -1, 154, -1, 155, -1,
- 23, -1, 159, 160, 156, -1, -1, 113, 157, -1,
- 114, 158, -1, 23, -1, 23, -1, 100, -1, 104,
- -1, 104, -1, 104, -1, 104, -1, 101, -1, 105,
- -1, -1, 101, -1, 102, -1, 103, -1, 104, -1,
- -1, 115, 166, 116, -1, 115, 167, 116, -1, -1,
- 168, 163, -1, 169, 163, -1, 99, -1, 100, -1,
- 171, -1, 178, -1, 242, -1, 245, -1, 248, -1,
- 261, -1, 7, 99, 117, 172, -1, 96, 173, -1,
- 38, 177, -1, 60, -1, 98, 175, -1, 53, -1,
- 29, 254, -1, 37, -1, 74, 255, -1, 50, 111,
- 176, 112, -1, 97, 111, 174, 112, -1, 23, -1,
- -1, 111, 176, 112, -1, 23, -1, 60, -1, 29,
- 254, -1, 37, -1, 74, 255, -1, 179, -1, 180,
- -1, 10, 99, 182, -1, 10, 99, 111, 181, 112,
- 183, -1, -1, 23, -1, 117, 185, -1, 117, 118,
- 184, 119, -1, 187, -1, 184, 109, 187, -1, 189,
- -1, 225, -1, 235, -1, 189, -1, 225, -1, 236,
- -1, 188, -1, 226, -1, 235, -1, 189, -1, 73,
- 213, -1, 73, 190, -1, 73, 192, -1, 73, 195,
- -1, 73, 197, -1, 73, 203, -1, 73, 199, -1,
- 73, 206, -1, 73, 208, -1, 73, 210, -1, 73,
- 212, -1, 73, 224, -1, 47, 253, 191, -1, 201,
- -1, 33, -1, 69, -1, 43, 111, 202, 112, 193,
- -1, 201, -1, 60, -1, 26, -1, 72, 194, -1,
- 40, -1, 32, -1, 44, 196, -1, 25, -1, 253,
- 67, -1, 45, 111, 202, 112, 253, 198, -1, 201,
- -1, 75, 257, 200, -1, 29, -1, 25, -1, 31,
- -1, 71, -1, 23, -1, 76, 255, 204, 205, -1,
- 35, -1, 54, -1, 79, -1, 80, -1, 78, -1,
- 77, -1, 36, 207, -1, 29, -1, 56, -1, 28,
- 111, 209, 112, 57, -1, 23, -1, 58, 211, -1,
- 70, -1, 26, -1, 215, 66, 111, 218, 112, -1,
- 215, 214, -1, -1, 66, 111, 218, 106, 218, 112,
- -1, 49, 219, 216, -1, -1, 217, -1, 41, -1,
- 82, -1, 42, -1, 23, -1, 51, 220, -1, 63,
- -1, 52, -1, 81, 255, -1, 55, 111, 222, 112,
- -1, 48, 111, 223, 112, -1, -1, 111, 221, 112,
- -1, 23, -1, 23, -1, 23, -1, 30, 64, -1,
- 229, -1, 232, -1, 227, -1, 230, -1, 62, 34,
- 111, 228, 112, -1, 233, -1, 233, 106, 233, -1,
- 62, 34, 111, 233, 112, -1, 62, 46, 111, 231,
- 112, -1, 234, -1, 234, 106, 234, -1, 62, 46,
- 111, 234, 112, -1, 23, -1, 23, -1, 237, -1,
- 239, -1, 238, -1, 239, -1, 240, -1, 24, -1,
- 23, -1, 118, 240, 119, -1, 118, 240, 109, 240,
- 119, -1, 118, 240, 109, 240, 109, 240, 119, -1,
- 118, 240, 109, 240, 109, 240, 109, 240, 119, -1,
- 241, 24, -1, 241, 23, -1, 113, -1, 114, -1,
- -1, -1, 244, 11, 243, 247, -1, 262, -1, -1,
- -1, 5, 246, 247, -1, 247, 109, 99, -1, 99,
- -1, 244, 9, 99, 117, 249, -1, 65, 60, -1,
- 65, 37, -1, 65, 250, -1, 65, 59, -1, 65,
- 74, 255, -1, 65, 30, -1, 29, 251, 252, -1,
- -1, 39, -1, 27, -1, -1, 61, -1, 68, -1,
- -1, 39, -1, 27, -1, -1, 61, -1, 68, -1,
- -1, 111, 258, 112, -1, -1, 111, 259, 112, -1,
- -1, 111, 260, 112, -1, 23, -1, 23, -1, 23,
- -1, 6, 99, 117, 100, -1, 99, -1, 100, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 278, 278, 281, 289, 301, 302, 305, 329, 330,
- 333, 348, 351, 356, 363, 364, 365, 366, 367, 368,
- 369, 372, 373, 374, 377, 383, 389, 395, 402, 408,
- 415, 459, 464, 474, 518, 524, 525, 526, 527, 528,
- 529, 530, 531, 532, 533, 534, 535, 538, 550, 558,
- 575, 582, 601, 612, 632, 657, 664, 697, 704, 719,
- 774, 817, 826, 848, 858, 862, 891, 910, 910, 912,
- 919, 931, 932, 933, 936, 950, 964, 984, 995, 1007,
- 1009, 1010, 1011, 1012, 1015, 1015, 1015, 1015, 1016, 1019,
- 1023, 1028, 1035, 1042, 1049, 1072, 1095, 1096, 1097, 1098,
- 1099, 1100, 1103, 1122, 1126, 1132, 1136, 1140, 1144, 1153,
- 1162, 1166, 1171, 1177, 1188, 1188, 1189, 1191, 1195, 1199,
- 1203, 1209, 1209, 1211, 1229, 1255, 1258, 1269, 1275, 1281,
- 1282, 1289, 1295, 1301, 1309, 1315, 1321, 1329, 1335, 1341,
- 1349, 1350, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360,
- 1361, 1362, 1363, 1366, 1375, 1379, 1383, 1389, 1398, 1402,
- 1406, 1415, 1419, 1425, 1431, 1438, 1443, 1451, 1461, 1463,
- 1471, 1477, 1481, 1485, 1491, 1502, 1511, 1515, 1520, 1524,
- 1528, 1532, 1538, 1545, 1549, 1555, 1563, 1574, 1581, 1585,
- 1591, 1601, 1612, 1616, 1634, 1643, 1646, 1652, 1656, 1660,
- 1666, 1677, 1682, 1687, 1692, 1697, 1702, 1710, 1713, 1718,
- 1731, 1739, 1750, 1758, 1758, 1760, 1760, 1762, 1772, 1777,
- 1784, 1794, 1803, 1808, 1815, 1825, 1835, 1847, 1847, 1848,
- 1848, 1850, 1860, 1868, 1878, 1886, 1894, 1903, 1914, 1918,
- 1924, 1925, 1926, 1929, 1929, 1932, 1967, 1971, 1971, 1974,
- 1981, 1990, 2004, 2013, 2022, 2026, 2035, 2044, 2055, 2062,
- 2067, 2076, 2088, 2091, 2100, 2111, 2112, 2113, 2116, 2117,
- 2118, 2121, 2122, 2125, 2126, 2129, 2130, 2133, 2144, 2155,
- 2166, 2192, 2193
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "ARBvp_10", "ARBfp_10", "ADDRESS",
- "ALIAS", "ATTRIB", "OPTION", "OUTPUT", "PARAM", "TEMP", "END", "BIN_OP",
- "BINSC_OP", "SAMPLE_OP", "SCALAR_OP", "TRI_OP", "VECTOR_OP", "ARL",
- "KIL", "SWZ", "TXD_OP", "INTEGER", "REAL", "AMBIENT", "ATTENUATION",
- "BACK", "CLIP", "COLOR", "DEPTH", "DIFFUSE", "DIRECTION", "EMISSION",
- "ENV", "EYE", "FOG", "FOGCOORD", "FRAGMENT", "FRONT", "HALF", "INVERSE",
- "INVTRANS", "LIGHT", "LIGHTMODEL", "LIGHTPROD", "LOCAL", "MATERIAL",
- "MAT_PROGRAM", "MATRIX", "MATRIXINDEX", "MODELVIEW", "MVP", "NORMAL",
- "OBJECT", "PALETTE", "PARAMS", "PLANE", "POINT_TOK", "POINTSIZE",
- "POSITION", "PRIMARY", "PROGRAM", "PROJECTION", "RANGE", "RESULT", "ROW",
- "SCENECOLOR", "SECONDARY", "SHININESS", "SIZE_TOK", "SPECULAR", "SPOT",
- "STATE", "TEXCOORD", "TEXENV", "TEXGEN", "TEXGEN_Q", "TEXGEN_R",
- "TEXGEN_S", "TEXGEN_T", "TEXTURE", "TRANSPOSE", "TEXTURE_UNIT", "TEX_1D",
- "TEX_2D", "TEX_3D", "TEX_CUBE", "TEX_RECT", "TEX_SHADOW1D",
- "TEX_SHADOW2D", "TEX_SHADOWRECT", "TEX_ARRAY1D", "TEX_ARRAY2D",
- "TEX_ARRAYSHADOW1D", "TEX_ARRAYSHADOW2D", "VERTEX", "VTXATTRIB",
- "WEIGHT", "IDENTIFIER", "USED_IDENTIFIER", "MASK4", "MASK3", "MASK2",
- "MASK1", "SWIZZLE", "DOT_DOT", "DOT", "';'", "','", "'|'", "'['", "']'",
- "'+'", "'-'", "'('", "')'", "'='", "'{'", "'}'", "$accept", "program",
- "language", "optionSequence", "option", "statementSequence", "statement",
- "instruction", "ALU_instruction", "TexInstruction", "ARL_instruction",
- "VECTORop_instruction", "SCALARop_instruction", "BINSCop_instruction",
- "BINop_instruction", "TRIop_instruction", "SAMPLE_instruction",
- "KIL_instruction", "TXD_instruction", "texImageUnit", "texTarget",
- "SWZ_instruction", "scalarSrcReg", "scalarUse", "swizzleSrcReg",
- "maskedDstReg", "maskedAddrReg", "extendedSwizzle", "extSwizComp",
- "extSwizSel", "srcReg", "dstReg", "progParamArray", "progParamArrayMem",
- "progParamArrayAbs", "progParamArrayRel", "addrRegRelOffset",
- "addrRegPosOffset", "addrRegNegOffset", "addrReg", "addrComponent",
- "addrWriteMask", "scalarSuffix", "swizzleSuffix", "optionalMask",
- "optionalCcMask", "ccTest", "ccTest2", "ccMaskRule", "ccMaskRule2",
- "namingStatement", "ATTRIB_statement", "attribBinding", "vtxAttribItem",
- "vtxAttribNum", "vtxOptWeightNum", "vtxWeightNum", "fragAttribItem",
- "PARAM_statement", "PARAM_singleStmt", "PARAM_multipleStmt",
- "optArraySize", "paramSingleInit", "paramMultipleInit",
- "paramMultInitList", "paramSingleItemDecl", "paramSingleItemUse",
- "paramMultipleItem", "stateMultipleItem", "stateSingleItem",
- "stateMaterialItem", "stateMatProperty", "stateLightItem",
- "stateLightProperty", "stateSpotProperty", "stateLightModelItem",
- "stateLModProperty", "stateLightProdItem", "stateLProdProperty",
- "stateTexEnvItem", "stateTexEnvProperty", "ambDiffSpecProperty",
- "stateLightNumber", "stateTexGenItem", "stateTexGenType",
- "stateTexGenCoord", "stateFogItem", "stateFogProperty",
- "stateClipPlaneItem", "stateClipPlaneNum", "statePointItem",
- "statePointProperty", "stateMatrixRow", "stateMatrixRows",
- "optMatrixRows", "stateMatrixItem", "stateOptMatModifier",
- "stateMatModifier", "stateMatrixRowNum", "stateMatrixName",
- "stateOptModMatNum", "stateModMatNum", "statePaletteMatNum",
- "stateProgramMatNum", "stateDepthItem", "programSingleItem",
- "programMultipleItem", "progEnvParams", "progEnvParamNums",
- "progEnvParam", "progLocalParams", "progLocalParamNums",
- "progLocalParam", "progEnvParamNum", "progLocalParamNum",
- "paramConstDecl", "paramConstUse", "paramConstScalarDecl",
- "paramConstScalarUse", "paramConstVector", "signedFloatConstant",
- "optionalSign", "TEMP_statement", "@1", "optVarSize",
- "ADDRESS_statement", "@2", "varNameList", "OUTPUT_statement",
- "resultBinding", "resultColBinding", "optResultFaceType",
- "optResultColorType", "optFaceType", "optColorType",
- "optTexCoordUnitNum", "optTexImageUnitNum", "optLegacyTexUnitNum",
- "texCoordUnitNum", "texImageUnitNum", "legacyTexUnitNum",
- "ALIAS_statement", "string", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
- 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
- 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
- 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
- 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
- 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
- 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
- 355, 356, 357, 358, 359, 360, 361, 362, 59, 44,
- 124, 91, 93, 43, 45, 40, 41, 61, 123, 125
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint16 yyr1[] =
-{
- 0, 120, 121, 122, 122, 123, 123, 124, 125, 125,
- 126, 126, 127, 127, 128, 128, 128, 128, 128, 128,
- 128, 129, 129, 129, 130, 131, 132, 133, 134, 135,
- 136, 137, 137, 138, 139, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 141, 142, 142,
- 143, 143, 144, 144, 145, 146, 147, 148, 149, 149,
- 150, 150, 150, 150, 151, 151, 152, 153, 153, 154,
- 155, 156, 156, 156, 157, 158, 159, 160, 161, 162,
- 163, 163, 163, 163, 164, 164, 164, 164, 164, 165,
- 165, 165, 166, 167, 168, 169, 170, 170, 170, 170,
- 170, 170, 171, 172, 172, 173, 173, 173, 173, 173,
- 173, 173, 173, 174, 175, 175, 176, 177, 177, 177,
- 177, 178, 178, 179, 180, 181, 181, 182, 183, 184,
- 184, 185, 185, 185, 186, 186, 186, 187, 187, 187,
- 188, 188, 189, 189, 189, 189, 189, 189, 189, 189,
- 189, 189, 189, 190, 191, 191, 191, 192, 193, 193,
- 193, 193, 193, 194, 195, 196, 196, 197, 198, 199,
- 200, 201, 201, 201, 202, 203, 204, 204, 205, 205,
- 205, 205, 206, 207, 207, 208, 209, 210, 211, 211,
- 212, 213, 214, 214, 215, 216, 216, 217, 217, 217,
- 218, 219, 219, 219, 219, 219, 219, 220, 220, 221,
- 222, 223, 224, 225, 225, 226, 226, 227, 228, 228,
- 229, 230, 231, 231, 232, 233, 234, 235, 235, 236,
- 236, 237, 238, 238, 239, 239, 239, 239, 240, 240,
- 241, 241, 241, 243, 242, 244, 244, 246, 245, 247,
- 247, 248, 249, 249, 249, 249, 249, 249, 250, 251,
- 251, 251, 252, 252, 252, 253, 253, 253, 254, 254,
- 254, 255, 255, 256, 256, 257, 257, 258, 259, 260,
- 261, 262, 262
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 4, 1, 1, 2, 0, 3, 2, 0,
- 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 4, 4, 4, 6, 6, 8,
- 8, 2, 2, 12, 2, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 6, 2, 4,
- 2, 1, 3, 5, 3, 2, 7, 2, 1, 1,
- 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
- 3, 0, 2, 2, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 0, 1, 1, 1, 1, 0, 3,
- 3, 0, 2, 2, 1, 1, 1, 1, 1, 1,
- 1, 1, 4, 2, 2, 1, 2, 1, 2, 1,
- 2, 4, 4, 1, 0, 3, 1, 1, 2, 1,
- 2, 1, 1, 3, 6, 0, 1, 2, 4, 1,
- 3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 3, 1, 1, 1, 5, 1, 1,
- 1, 2, 1, 1, 2, 1, 2, 6, 1, 3,
- 1, 1, 1, 1, 1, 4, 1, 1, 1, 1,
- 1, 1, 2, 1, 1, 5, 1, 2, 1, 1,
- 5, 2, 0, 6, 3, 0, 1, 1, 1, 1,
- 1, 2, 1, 1, 2, 4, 4, 0, 3, 1,
- 1, 1, 2, 1, 1, 1, 1, 5, 1, 3,
- 5, 5, 1, 3, 5, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 3, 5, 7, 9, 2, 2,
- 1, 1, 0, 0, 4, 1, 0, 0, 3, 3,
- 1, 5, 2, 2, 2, 2, 3, 2, 3, 0,
- 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
- 1, 0, 3, 0, 3, 0, 3, 1, 1, 1,
- 4, 1, 1
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint16 yydefact[] =
-{
- 0, 3, 4, 0, 6, 1, 9, 0, 5, 246,
- 281, 282, 0, 247, 0, 0, 0, 2, 0, 0,
- 0, 0, 0, 0, 0, 242, 0, 0, 8, 0,
- 12, 13, 14, 15, 16, 17, 18, 19, 21, 22,
- 23, 20, 0, 96, 97, 121, 122, 98, 0, 99,
- 100, 101, 245, 7, 0, 0, 0, 0, 0, 65,
- 0, 88, 64, 0, 0, 0, 0, 0, 76, 0,
- 0, 94, 240, 241, 31, 32, 83, 0, 0, 0,
- 10, 11, 0, 243, 250, 248, 0, 0, 125, 242,
- 123, 259, 257, 253, 255, 252, 271, 254, 242, 84,
- 85, 86, 87, 91, 242, 242, 242, 242, 242, 242,
- 78, 55, 81, 80, 82, 92, 233, 232, 0, 0,
- 0, 0, 60, 0, 242, 83, 0, 61, 63, 134,
- 135, 213, 214, 136, 229, 230, 0, 242, 0, 0,
- 0, 280, 102, 126, 0, 127, 131, 132, 133, 227,
- 228, 231, 0, 261, 260, 262, 0, 256, 0, 0,
- 54, 0, 0, 0, 26, 0, 25, 24, 268, 119,
- 117, 271, 104, 0, 0, 0, 0, 0, 0, 265,
- 0, 265, 0, 0, 275, 271, 142, 143, 144, 145,
- 147, 146, 148, 149, 150, 151, 0, 152, 268, 109,
- 0, 107, 105, 271, 0, 114, 103, 83, 0, 52,
- 0, 0, 0, 0, 244, 249, 0, 239, 238, 263,
- 264, 258, 277, 0, 242, 95, 0, 0, 83, 242,
- 0, 48, 0, 51, 0, 242, 269, 270, 118, 120,
- 0, 0, 0, 212, 183, 184, 182, 0, 165, 267,
- 266, 164, 0, 0, 0, 0, 207, 203, 0, 202,
- 271, 195, 189, 188, 187, 0, 0, 0, 0, 108,
- 0, 110, 0, 0, 106, 0, 242, 234, 69, 0,
- 67, 68, 0, 242, 242, 251, 0, 124, 272, 28,
- 89, 90, 93, 27, 0, 79, 50, 273, 0, 0,
- 225, 0, 226, 0, 186, 0, 174, 0, 166, 0,
- 171, 172, 155, 156, 173, 153, 154, 0, 0, 201,
- 0, 204, 197, 199, 198, 194, 196, 279, 0, 170,
- 169, 176, 177, 0, 0, 116, 0, 113, 0, 0,
- 53, 0, 62, 77, 71, 47, 0, 0, 0, 242,
- 49, 0, 34, 0, 242, 220, 224, 0, 0, 265,
- 211, 0, 209, 0, 210, 0, 276, 181, 180, 178,
- 179, 175, 200, 0, 111, 112, 115, 242, 235, 0,
- 0, 70, 242, 58, 57, 59, 242, 0, 0, 0,
- 129, 137, 140, 138, 215, 216, 139, 278, 0, 35,
- 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
- 46, 30, 29, 185, 160, 162, 159, 0, 157, 158,
- 0, 206, 208, 205, 190, 0, 74, 72, 75, 73,
- 0, 0, 0, 0, 141, 192, 242, 128, 274, 163,
- 161, 167, 168, 242, 236, 242, 0, 0, 0, 0,
- 191, 130, 0, 0, 0, 0, 218, 0, 222, 0,
- 237, 242, 0, 217, 0, 221, 0, 0, 56, 33,
- 219, 223, 0, 0, 193
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 3, 4, 6, 8, 9, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 298,
- 411, 41, 161, 231, 74, 60, 69, 345, 346, 384,
- 232, 61, 126, 279, 280, 281, 381, 427, 429, 70,
- 344, 111, 296, 115, 103, 160, 75, 227, 76, 228,
- 42, 43, 127, 206, 338, 274, 336, 172, 44, 45,
- 46, 144, 90, 287, 389, 145, 128, 390, 391, 129,
- 186, 315, 187, 418, 440, 188, 251, 189, 441, 190,
- 330, 316, 307, 191, 333, 371, 192, 246, 193, 305,
- 194, 264, 195, 434, 450, 196, 325, 326, 373, 261,
- 319, 363, 365, 361, 197, 130, 393, 394, 455, 131,
- 395, 457, 132, 301, 303, 396, 133, 149, 134, 135,
- 151, 77, 47, 139, 48, 49, 54, 85, 50, 62,
- 97, 155, 221, 252, 238, 157, 352, 266, 223, 398,
- 328, 51, 12
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -401
-static const yytype_int16 yypact[] =
-{
- 193, -401, -401, 27, -401, -401, 62, 143, -401, 24,
- -401, -401, -30, -401, -18, 12, 83, -401, 15, 15,
- 15, 15, 15, 15, 67, 61, 15, 15, -401, 127,
- -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
- -401, -401, 144, -401, -401, -401, -401, -401, 204, -401,
- -401, -401, -401, -401, 155, 136, 138, 34, 140, -401,
- 147, 108, -401, 150, 156, 157, 158, 160, -401, 162,
- 159, -401, -401, -401, -401, -401, 102, -13, 163, 164,
- -401, -401, 165, -401, -401, 166, 170, 10, 235, 0,
- -401, 141, -401, -401, -401, -401, 167, -401, 131, -401,
- -401, -401, -401, 168, 131, 131, 131, 131, 131, 131,
- -401, -401, -401, -401, -401, -401, -401, -401, 104, 97,
- 114, 38, 169, 30, 131, 102, 171, -401, -401, -401,
- -401, -401, -401, -401, -401, -401, 30, 131, 172, 155,
- 175, -401, -401, -401, 173, -401, -401, -401, -401, -401,
- -401, -401, 223, -401, -401, 123, 253, -401, 177, 149,
- -401, 178, -10, 181, -401, 182, -401, -401, 134, -401,
- -401, 167, -401, 183, 184, 185, 213, 99, 186, 154,
- 187, 146, 153, 7, 188, 167, -401, -401, -401, -401,
- -401, -401, -401, -401, -401, -401, 215, -401, 134, -401,
- 190, -401, -401, 167, 191, 192, -401, 102, -48, -401,
- 1, 195, 196, 214, 166, -401, 189, -401, -401, -401,
- -401, -401, -401, 180, 131, -401, 194, 197, 102, 131,
- 30, -401, 203, 205, 201, 131, -401, -401, -401, -401,
- 285, 288, 289, -401, -401, -401, -401, 291, -401, -401,
- -401, -401, 248, 291, 33, 206, 207, -401, 208, -401,
- 167, 14, -401, -401, -401, 293, 292, 92, 209, -401,
- 299, -401, 301, 299, -401, 216, 131, -401, -401, 217,
- -401, -401, 221, 131, 131, -401, 212, -401, -401, -401,
- -401, -401, -401, -401, 218, -401, -401, 220, 224, 225,
- -401, 226, -401, 227, -401, 228, -401, 230, -401, 231,
- -401, -401, -401, -401, -401, -401, -401, 304, 309, -401,
- 312, -401, -401, -401, -401, -401, -401, -401, 232, -401,
- -401, -401, -401, 161, 313, -401, 233, -401, 234, 238,
- -401, 13, -401, -401, 137, -401, 242, -15, 243, 3,
- -401, 314, -401, 133, 131, -401, -401, 296, 94, 146,
- -401, 245, -401, 246, -401, 247, -401, -401, -401, -401,
- -401, -401, -401, 249, -401, -401, -401, 131, -401, 332,
- 337, -401, 131, -401, -401, -401, 131, 142, 114, 28,
- -401, -401, -401, -401, -401, -401, -401, -401, 250, -401,
- -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
- -401, -401, -401, -401, -401, -401, -401, 331, -401, -401,
- 68, -401, -401, -401, -401, 43, -401, -401, -401, -401,
- 255, 256, 257, 258, -401, 300, 3, -401, -401, -401,
- -401, -401, -401, 131, -401, 131, 201, 285, 288, 259,
- -401, -401, 252, 264, 265, 263, 261, 266, 270, 313,
- -401, 131, 133, -401, 285, -401, 288, 80, -401, -401,
- -401, -401, 313, 267, -401
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
- -401, -401, -401, -401, -401, -401, -401, -401, -401, -69,
- -82, -401, -100, 151, -86, 210, -401, -401, -366, -401,
- -54, -401, -401, -401, -401, -401, -401, -401, -401, 174,
- -401, -401, -401, -118, -401, -401, 229, -401, -401, -401,
- -401, -401, 295, -401, -401, -401, 110, -401, -401, -401,
- -401, -401, -401, -401, -401, -401, -401, -51, -401, -88,
- -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
- -401, -311, 139, -401, -401, -401, -401, -401, -401, -401,
- -401, -401, -401, -401, -401, -2, -401, -401, -400, -401,
- -401, -401, -401, -401, -401, 298, -401, -401, -401, -401,
- -401, -401, -401, -390, -295, 302, -401, -401, -136, -87,
- -120, -89, -401, -401, -401, -401, -401, 251, -401, 176,
- -401, -401, -401, -176, 198, -153, -401, -401, -401, -401,
- -401, -401, -6
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -230
-static const yytype_int16 yytable[] =
-{
- 152, 146, 150, 52, 208, 254, 164, 209, 383, 167,
- 116, 117, 158, 116, 117, 162, 430, 162, 239, 163,
- 162, 165, 166, 125, 278, 118, 233, 5, 118, 13,
- 14, 15, 267, 262, 16, 152, 17, 18, 19, 20,
- 21, 22, 23, 24, 25, 26, 27, 419, 118, 119,
- 271, 212, 119, 116, 117, 322, 323, 456, 310, 467,
- 120, 276, 119, 120, 311, 387, 312, 198, 118, 207,
- 7, 277, 473, 120, 470, 199, 388, 263, 53, 453,
- 58, 55, 211, 121, 10, 11, 121, 122, 200, 275,
- 122, 201, 119, 310, 233, 468, 324, 123, 202, 311,
- 230, 68, 313, 120, 314, 124, 121, 321, 124, 442,
- 292, 56, 203, 72, 73, 59, 72, 73, 124, 310,
- 414, 124, 377, 10, 11, 311, 121, 331, 244, 293,
- 122, 173, 378, 168, 415, 204, 205, 436, 289, 314,
- 162, 169, 175, 174, 176, 88, 332, 437, 124, 299,
- 177, 89, 443, 458, 416, 245, 341, 178, 179, 180,
- 71, 181, 444, 182, 170, 314, 417, 68, 153, 91,
- 92, 471, 183, 249, 72, 73, 432, 93, 171, 248,
- 154, 249, 57, 420, 219, 250, 472, 152, 433, 184,
- 185, 220, 424, 250, 347, 236, 1, 2, 348, 94,
- 95, 255, 237, 112, 256, 257, 113, 114, 258, 99,
- 100, 101, 102, 82, 96, 83, 259, 399, 400, 401,
- 402, 403, 404, 405, 406, 407, 408, 409, 410, 63,
- 64, 65, 66, 67, 260, 80, 78, 79, 367, 368,
- 369, 370, 10, 11, 72, 73, 217, 218, 71, 225,
- 379, 380, 81, 86, 84, 87, 98, 425, 143, 104,
- 152, 392, 150, 110, 138, 105, 106, 107, 412, 108,
- 141, 109, 136, 137, 215, 140, 222, 243, 156, 58,
- -66, 268, 210, 159, 297, 216, 224, 229, 152, 213,
- 234, 235, 288, 347, 240, 241, 242, 247, 253, 265,
- 431, 270, 272, 273, 283, 284, 286, 295, 300, -229,
- 290, 302, 304, 291, 306, 308, 327, 317, 318, 320,
- 334, 329, 335, 452, 337, 343, 340, 360, 350, 342,
- 349, 351, 362, 353, 354, 364, 372, 397, 355, 356,
- 357, 385, 358, 359, 366, 374, 375, 152, 392, 150,
- 376, 382, 386, 413, 152, 426, 347, 421, 422, 423,
- 428, 424, 438, 439, 445, 446, 449, 464, 447, 448,
- 459, 460, 347, 461, 462, 463, 466, 454, 465, 474,
- 469, 294, 142, 339, 282, 451, 435, 147, 226, 285,
- 214, 148, 309, 0, 0, 0, 269
-};
-
-static const yytype_int16 yycheck[] =
-{
- 89, 89, 89, 9, 124, 181, 106, 125, 23, 109,
- 23, 24, 98, 23, 24, 104, 382, 106, 171, 105,
- 109, 107, 108, 77, 23, 38, 162, 0, 38, 5,
- 6, 7, 185, 26, 10, 124, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 358, 38, 62,
- 203, 137, 62, 23, 24, 41, 42, 447, 25, 459,
- 73, 109, 62, 73, 31, 62, 33, 29, 38, 123,
- 8, 119, 472, 73, 464, 37, 73, 70, 108, 445,
- 65, 99, 136, 96, 99, 100, 96, 100, 50, 207,
- 100, 53, 62, 25, 230, 461, 82, 110, 60, 31,
- 110, 100, 69, 73, 71, 118, 96, 260, 118, 420,
- 228, 99, 74, 113, 114, 100, 113, 114, 118, 25,
- 26, 118, 109, 99, 100, 31, 96, 35, 29, 229,
- 100, 34, 119, 29, 40, 97, 98, 109, 224, 71,
- 229, 37, 28, 46, 30, 111, 54, 119, 118, 235,
- 36, 117, 109, 448, 60, 56, 276, 43, 44, 45,
- 99, 47, 119, 49, 60, 71, 72, 100, 27, 29,
- 30, 466, 58, 27, 113, 114, 34, 37, 74, 25,
- 39, 27, 99, 359, 61, 39, 106, 276, 46, 75,
- 76, 68, 112, 39, 283, 61, 3, 4, 284, 59,
- 60, 48, 68, 101, 51, 52, 104, 105, 55, 101,
- 102, 103, 104, 9, 74, 11, 63, 84, 85, 86,
- 87, 88, 89, 90, 91, 92, 93, 94, 95, 19,
- 20, 21, 22, 23, 81, 108, 26, 27, 77, 78,
- 79, 80, 99, 100, 113, 114, 23, 24, 99, 100,
- 113, 114, 108, 117, 99, 117, 109, 377, 23, 109,
- 349, 349, 349, 104, 99, 109, 109, 109, 354, 109,
- 100, 109, 109, 109, 99, 109, 23, 64, 111, 65,
- 111, 66, 111, 115, 83, 112, 109, 109, 377, 117,
- 109, 109, 112, 382, 111, 111, 111, 111, 111, 111,
- 386, 111, 111, 111, 109, 109, 117, 104, 23, 104,
- 116, 23, 23, 116, 23, 67, 23, 111, 111, 111,
- 111, 29, 23, 443, 23, 104, 110, 23, 110, 112,
- 118, 111, 23, 109, 109, 23, 23, 23, 112, 112,
- 112, 347, 112, 112, 112, 112, 112, 436, 436, 436,
- 112, 109, 109, 57, 443, 23, 445, 112, 112, 112,
- 23, 112, 112, 32, 109, 109, 66, 106, 111, 111,
- 111, 119, 461, 109, 109, 112, 106, 446, 112, 112,
- 462, 230, 87, 273, 210, 436, 388, 89, 159, 213,
- 139, 89, 253, -1, -1, -1, 198
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint16 yystos[] =
-{
- 0, 3, 4, 121, 122, 0, 123, 8, 124, 125,
- 99, 100, 262, 5, 6, 7, 10, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 126, 127,
- 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
- 138, 141, 170, 171, 178, 179, 180, 242, 244, 245,
- 248, 261, 262, 108, 246, 99, 99, 99, 65, 100,
- 145, 151, 249, 145, 145, 145, 145, 145, 100, 146,
- 159, 99, 113, 114, 144, 166, 168, 241, 145, 145,
- 108, 108, 9, 11, 99, 247, 117, 117, 111, 117,
- 182, 29, 30, 37, 59, 60, 74, 250, 109, 101,
- 102, 103, 104, 164, 109, 109, 109, 109, 109, 109,
- 104, 161, 101, 104, 105, 163, 23, 24, 38, 62,
- 73, 96, 100, 110, 118, 150, 152, 172, 186, 189,
- 225, 229, 232, 236, 238, 239, 109, 109, 99, 243,
- 109, 100, 172, 23, 181, 185, 189, 225, 235, 237,
- 239, 240, 241, 27, 39, 251, 111, 255, 144, 115,
- 165, 142, 241, 144, 142, 144, 144, 142, 29, 37,
- 60, 74, 177, 34, 46, 28, 30, 36, 43, 44,
- 45, 47, 49, 58, 75, 76, 190, 192, 195, 197,
- 199, 203, 206, 208, 210, 212, 215, 224, 29, 37,
- 50, 53, 60, 74, 97, 98, 173, 150, 240, 163,
- 111, 150, 144, 117, 247, 99, 112, 23, 24, 61,
- 68, 252, 23, 258, 109, 100, 166, 167, 169, 109,
- 110, 143, 150, 238, 109, 109, 61, 68, 254, 255,
- 111, 111, 111, 64, 29, 56, 207, 111, 25, 27,
- 39, 196, 253, 111, 253, 48, 51, 52, 55, 63,
- 81, 219, 26, 70, 211, 111, 257, 255, 66, 254,
- 111, 255, 111, 111, 175, 163, 109, 119, 23, 153,
- 154, 155, 159, 109, 109, 249, 117, 183, 112, 144,
- 116, 116, 163, 142, 143, 104, 162, 83, 139, 144,
- 23, 233, 23, 234, 23, 209, 23, 202, 67, 202,
- 25, 31, 33, 69, 71, 191, 201, 111, 111, 220,
- 111, 255, 41, 42, 82, 216, 217, 23, 260, 29,
- 200, 35, 54, 204, 111, 23, 176, 23, 174, 176,
- 110, 240, 112, 104, 160, 147, 148, 241, 144, 118,
- 110, 111, 256, 109, 109, 112, 112, 112, 112, 112,
- 23, 223, 23, 221, 23, 222, 112, 77, 78, 79,
- 80, 205, 23, 218, 112, 112, 112, 109, 119, 113,
- 114, 156, 109, 23, 149, 262, 109, 62, 73, 184,
- 187, 188, 189, 226, 227, 230, 235, 23, 259, 84,
- 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
- 95, 140, 144, 57, 26, 40, 60, 72, 193, 201,
- 253, 112, 112, 112, 112, 240, 23, 157, 23, 158,
- 148, 144, 34, 46, 213, 215, 109, 119, 112, 32,
- 194, 198, 201, 109, 119, 109, 109, 111, 111, 66,
- 214, 187, 240, 148, 139, 228, 233, 231, 234, 111,
- 119, 109, 109, 112, 106, 112, 106, 218, 148, 140,
- 233, 234, 106, 218, 112
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (&yylloc, state, YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
-#else
-# define YYLEX yylex (&yylval, &yylloc, scanner)
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value, Location, state); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
- YYLTYPE const * const yylocationp;
- struct asm_parser_state *state;
-#endif
-{
- if (!yyvaluep)
- return;
- YYUSE (yylocationp);
- YYUSE (state);
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, state)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
- YYLTYPE const * const yylocationp;
- struct asm_parser_state *state;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- YY_LOCATION_PRINT (yyoutput, *yylocationp);
- YYFPRINTF (yyoutput, ": ");
- yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct asm_parser_state *state)
-#else
-static void
-yy_reduce_print (yyvsp, yylsp, yyrule, state)
- YYSTYPE *yyvsp;
- YYLTYPE *yylsp;
- int yyrule;
- struct asm_parser_state *state;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- , &(yylsp[(yyi + 1) - (yynrhs)]) , state);
- YYFPRINTF (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, yylsp, Rule, state); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct asm_parser_state *state)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep, yylocationp, state)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
- YYLTYPE *yylocationp;
- struct asm_parser_state *state;
-#endif
-{
- YYUSE (yyvaluep);
- YYUSE (yylocationp);
- YYUSE (state);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (struct asm_parser_state *state);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-
-
-/*-------------------------.
-| yyparse or yypush_parse. |
-`-------------------------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (struct asm_parser_state *state)
-#else
-int
-yyparse (state)
- struct asm_parser_state *state;
-#endif
-#endif
-{
-/* The lookahead symbol. */
-int yychar;
-
-/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
-
-/* Location data for the lookahead symbol. */
-YYLTYPE yylloc;
-
- /* Number of syntax errors so far. */
- int yynerrs;
-
- int yystate;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- /* The location stack. */
- YYLTYPE yylsa[YYINITDEPTH];
- YYLTYPE *yyls;
- YYLTYPE *yylsp;
-
- /* The locations where the error started and ended. */
- YYLTYPE yyerror_range[2];
-
- YYSIZE_T yystacksize;
-
- int yyn;
- int yyresult;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
- YYLTYPE yyloc;
-
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
- yyls = yylsa;
- yystacksize = YYINITDEPTH;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
- yylsp = yyls;
-
-#if YYLTYPE_IS_TRIVIAL
- /* Initialize the default location before parsing starts. */
- yylloc.first_line = yylloc.last_line = 1;
- yylloc.first_column = yylloc.last_column = 1;
-#endif
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
- YYLTYPE *yyls1 = yyls;
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yyls1, yysize * sizeof (*yylsp),
- &yystacksize);
-
- yyls = yyls1;
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
- YYSTACK_RELOCATE (yyls_alloc, yyls);
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
- yylsp = yyls + yysize - 1;
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- if (yystate == YYFINAL)
- YYACCEPT;
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to lookahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a lookahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the lookahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token. */
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
- *++yylsp = yylloc;
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
- /* Default location. */
- YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 3:
-
-/* Line 1455 of yacc.c */
-#line 282 "program_parse.y"
- {
- if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid fragment program header");
-
- }
- state->mode = ARB_vertex;
- ;}
- break;
-
- case 4:
-
-/* Line 1455 of yacc.c */
-#line 290 "program_parse.y"
- {
- if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex program header");
- }
- state->mode = ARB_fragment;
-
- state->option.TexRect =
- (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE);
- ;}
- break;
-
- case 7:
-
-/* Line 1455 of yacc.c */
-#line 306 "program_parse.y"
- {
- int valid = 0;
-
- if (state->mode == ARB_vertex) {
- valid = _mesa_ARBvp_parse_option(state, (yyvsp[(2) - (3)].string));
- } else if (state->mode == ARB_fragment) {
- valid = _mesa_ARBfp_parse_option(state, (yyvsp[(2) - (3)].string));
- }
-
-
- free((yyvsp[(2) - (3)].string));
-
- if (!valid) {
- const char *const err_str = (state->mode == ARB_vertex)
- ? "invalid ARB vertex program option"
- : "invalid ARB fragment program option";
-
- yyerror(& (yylsp[(2) - (3)]), state, err_str);
- YYERROR;
- }
- ;}
- break;
-
- case 10:
-
-/* Line 1455 of yacc.c */
-#line 334 "program_parse.y"
- {
- if ((yyvsp[(1) - (2)].inst) != NULL) {
- if (state->inst_tail == NULL) {
- state->inst_head = (yyvsp[(1) - (2)].inst);
- } else {
- state->inst_tail->next = (yyvsp[(1) - (2)].inst);
- }
-
- state->inst_tail = (yyvsp[(1) - (2)].inst);
- (yyvsp[(1) - (2)].inst)->next = NULL;
-
- state->prog->NumInstructions++;
- }
- ;}
- break;
-
- case 12:
-
-/* Line 1455 of yacc.c */
-#line 352 "program_parse.y"
- {
- (yyval.inst) = (yyvsp[(1) - (1)].inst);
- state->prog->NumAluInstructions++;
- ;}
- break;
-
- case 13:
-
-/* Line 1455 of yacc.c */
-#line 357 "program_parse.y"
- {
- (yyval.inst) = (yyvsp[(1) - (1)].inst);
- state->prog->NumTexInstructions++;
- ;}
- break;
-
- case 24:
-
-/* Line 1455 of yacc.c */
-#line 378 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_ctor(OPCODE_ARL, & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL);
- ;}
- break;
-
- case 25:
-
-/* Line 1455 of yacc.c */
-#line 384 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL);
- ;}
- break;
-
- case 26:
-
-/* Line 1455 of yacc.c */
-#line 390 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL);
- ;}
- break;
-
- case 27:
-
-/* Line 1455 of yacc.c */
-#line 396 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL);
- ;}
- break;
-
- case 28:
-
-/* Line 1455 of yacc.c */
-#line 403 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL);
- ;}
- break;
-
- case 29:
-
-/* Line 1455 of yacc.c */
-#line 410 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), & (yyvsp[(6) - (8)].src_reg), & (yyvsp[(8) - (8)].src_reg));
- ;}
- break;
-
- case 30:
-
-/* Line 1455 of yacc.c */
-#line 416 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), NULL, NULL);
- if ((yyval.inst) != NULL) {
- const GLbitfield tex_mask = (1U << (yyvsp[(6) - (8)].integer));
- GLbitfield shadow_tex = 0;
- GLbitfield target_mask = 0;
-
-
- (yyval.inst)->Base.TexSrcUnit = (yyvsp[(6) - (8)].integer);
-
- if ((yyvsp[(8) - (8)].integer) < 0) {
- shadow_tex = tex_mask;
-
- (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(8) - (8)].integer);
- (yyval.inst)->Base.TexShadow = 1;
- } else {
- (yyval.inst)->Base.TexSrcTarget = (yyvsp[(8) - (8)].integer);
- }
-
- target_mask = (1U << (yyval.inst)->Base.TexSrcTarget);
-
- /* If this texture unit was previously accessed and that access
- * had a different texture target, generate an error.
- *
- * If this texture unit was previously accessed and that access
- * had a different shadow mode, generate an error.
- */
- if ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != 0)
- && ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != target_mask)
- || ((state->prog->ShadowSamplers & tex_mask)
- != shadow_tex))) {
- yyerror(& (yylsp[(8) - (8)]), state,
- "multiple targets used on one texture image unit");
- YYERROR;
- }
-
-
- state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] |= target_mask;
- state->prog->ShadowSamplers |= shadow_tex;
- }
- ;}
- break;
-
- case 31:
-
-/* Line 1455 of yacc.c */
-#line 460 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_ctor(OPCODE_KIL, NULL, & (yyvsp[(2) - (2)].src_reg), NULL, NULL);
- state->fragment.UsesKill = 1;
- ;}
- break;
-
- case 32:
-
-/* Line 1455 of yacc.c */
-#line 465 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL);
- (yyval.inst)->Base.DstReg.CondMask = (yyvsp[(2) - (2)].dst_reg).CondMask;
- (yyval.inst)->Base.DstReg.CondSwizzle = (yyvsp[(2) - (2)].dst_reg).CondSwizzle;
- (yyval.inst)->Base.DstReg.CondSrc = (yyvsp[(2) - (2)].dst_reg).CondSrc;
- state->fragment.UsesKill = 1;
- ;}
- break;
-
- case 33:
-
-/* Line 1455 of yacc.c */
-#line 475 "program_parse.y"
- {
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (12)].temp_inst), & (yyvsp[(2) - (12)].dst_reg), & (yyvsp[(4) - (12)].src_reg), & (yyvsp[(6) - (12)].src_reg), & (yyvsp[(8) - (12)].src_reg));
- if ((yyval.inst) != NULL) {
- const GLbitfield tex_mask = (1U << (yyvsp[(10) - (12)].integer));
- GLbitfield shadow_tex = 0;
- GLbitfield target_mask = 0;
-
-
- (yyval.inst)->Base.TexSrcUnit = (yyvsp[(10) - (12)].integer);
-
- if ((yyvsp[(12) - (12)].integer) < 0) {
- shadow_tex = tex_mask;
-
- (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(12) - (12)].integer);
- (yyval.inst)->Base.TexShadow = 1;
- } else {
- (yyval.inst)->Base.TexSrcTarget = (yyvsp[(12) - (12)].integer);
- }
-
- target_mask = (1U << (yyval.inst)->Base.TexSrcTarget);
-
- /* If this texture unit was previously accessed and that access
- * had a different texture target, generate an error.
- *
- * If this texture unit was previously accessed and that access
- * had a different shadow mode, generate an error.
- */
- if ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != 0)
- && ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != target_mask)
- || ((state->prog->ShadowSamplers & tex_mask)
- != shadow_tex))) {
- yyerror(& (yylsp[(12) - (12)]), state,
- "multiple targets used on one texture image unit");
- YYERROR;
- }
-
-
- state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] |= target_mask;
- state->prog->ShadowSamplers |= shadow_tex;
- }
- ;}
- break;
-
- case 34:
-
-/* Line 1455 of yacc.c */
-#line 519 "program_parse.y"
- {
- (yyval.integer) = (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 35:
-
-/* Line 1455 of yacc.c */
-#line 524 "program_parse.y"
- { (yyval.integer) = TEXTURE_1D_INDEX; ;}
- break;
-
- case 36:
-
-/* Line 1455 of yacc.c */
-#line 525 "program_parse.y"
- { (yyval.integer) = TEXTURE_2D_INDEX; ;}
- break;
-
- case 37:
-
-/* Line 1455 of yacc.c */
-#line 526 "program_parse.y"
- { (yyval.integer) = TEXTURE_3D_INDEX; ;}
- break;
-
- case 38:
-
-/* Line 1455 of yacc.c */
-#line 527 "program_parse.y"
- { (yyval.integer) = TEXTURE_CUBE_INDEX; ;}
- break;
-
- case 39:
-
-/* Line 1455 of yacc.c */
-#line 528 "program_parse.y"
- { (yyval.integer) = TEXTURE_RECT_INDEX; ;}
- break;
-
- case 40:
-
-/* Line 1455 of yacc.c */
-#line 529 "program_parse.y"
- { (yyval.integer) = -TEXTURE_1D_INDEX; ;}
- break;
-
- case 41:
-
-/* Line 1455 of yacc.c */
-#line 530 "program_parse.y"
- { (yyval.integer) = -TEXTURE_2D_INDEX; ;}
- break;
-
- case 42:
-
-/* Line 1455 of yacc.c */
-#line 531 "program_parse.y"
- { (yyval.integer) = -TEXTURE_RECT_INDEX; ;}
- break;
-
- case 43:
-
-/* Line 1455 of yacc.c */
-#line 532 "program_parse.y"
- { (yyval.integer) = TEXTURE_1D_ARRAY_INDEX; ;}
- break;
-
- case 44:
-
-/* Line 1455 of yacc.c */
-#line 533 "program_parse.y"
- { (yyval.integer) = TEXTURE_2D_ARRAY_INDEX; ;}
- break;
-
- case 45:
-
-/* Line 1455 of yacc.c */
-#line 534 "program_parse.y"
- { (yyval.integer) = -TEXTURE_1D_ARRAY_INDEX; ;}
- break;
-
- case 46:
-
-/* Line 1455 of yacc.c */
-#line 535 "program_parse.y"
- { (yyval.integer) = -TEXTURE_2D_ARRAY_INDEX; ;}
- break;
-
- case 47:
-
-/* Line 1455 of yacc.c */
-#line 539 "program_parse.y"
- {
- /* FIXME: Is this correct? Should the extenedSwizzle be applied
- * FIXME: to the existing swizzle?
- */
- (yyvsp[(4) - (6)].src_reg).Base.Swizzle = (yyvsp[(6) - (6)].swiz_mask).swizzle;
- (yyvsp[(4) - (6)].src_reg).Base.Negate = (yyvsp[(6) - (6)].swiz_mask).mask;
-
- (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), NULL, NULL);
- ;}
- break;
-
- case 48:
-
-/* Line 1455 of yacc.c */
-#line 551 "program_parse.y"
- {
- (yyval.src_reg) = (yyvsp[(2) - (2)].src_reg);
-
- if ((yyvsp[(1) - (2)].negate)) {
- (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
- }
- ;}
- break;
-
- case 49:
-
-/* Line 1455 of yacc.c */
-#line 559 "program_parse.y"
- {
- (yyval.src_reg) = (yyvsp[(3) - (4)].src_reg);
-
- if (!state->option.NV_fragment) {
- yyerror(& (yylsp[(2) - (4)]), state, "unexpected character '|'");
- YYERROR;
- }
-
- if ((yyvsp[(1) - (4)].negate)) {
- (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
- }
-
- (yyval.src_reg).Base.Abs = 1;
- ;}
- break;
-
- case 50:
-
-/* Line 1455 of yacc.c */
-#line 576 "program_parse.y"
- {
- (yyval.src_reg) = (yyvsp[(1) - (2)].src_reg);
-
- (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle,
- (yyvsp[(2) - (2)].swiz_mask).swizzle);
- ;}
- break;
-
- case 51:
-
-/* Line 1455 of yacc.c */
-#line 583 "program_parse.y"
- {
- struct asm_symbol temp_sym;
-
- if (!state->option.NV_fragment) {
- yyerror(& (yylsp[(1) - (1)]), state, "expected scalar suffix");
- YYERROR;
- }
-
- memset(& temp_sym, 0, sizeof(temp_sym));
- temp_sym.param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & temp_sym, & (yyvsp[(1) - (1)].vector), GL_TRUE);
-
- set_src_reg_swz(& (yyval.src_reg), PROGRAM_CONSTANT,
- temp_sym.param_binding_begin,
- temp_sym.param_binding_swizzle);
- ;}
- break;
-
- case 52:
-
-/* Line 1455 of yacc.c */
-#line 602 "program_parse.y"
- {
- (yyval.src_reg) = (yyvsp[(2) - (3)].src_reg);
-
- if ((yyvsp[(1) - (3)].negate)) {
- (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
- }
-
- (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle,
- (yyvsp[(3) - (3)].swiz_mask).swizzle);
- ;}
- break;
-
- case 53:
-
-/* Line 1455 of yacc.c */
-#line 613 "program_parse.y"
- {
- (yyval.src_reg) = (yyvsp[(3) - (5)].src_reg);
-
- if (!state->option.NV_fragment) {
- yyerror(& (yylsp[(2) - (5)]), state, "unexpected character '|'");
- YYERROR;
- }
-
- if ((yyvsp[(1) - (5)].negate)) {
- (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
- }
-
- (yyval.src_reg).Base.Abs = 1;
- (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle,
- (yyvsp[(4) - (5)].swiz_mask).swizzle);
- ;}
- break;
-
- case 54:
-
-/* Line 1455 of yacc.c */
-#line 633 "program_parse.y"
- {
- (yyval.dst_reg) = (yyvsp[(1) - (3)].dst_reg);
- (yyval.dst_reg).WriteMask = (yyvsp[(2) - (3)].swiz_mask).mask;
- (yyval.dst_reg).CondMask = (yyvsp[(3) - (3)].dst_reg).CondMask;
- (yyval.dst_reg).CondSwizzle = (yyvsp[(3) - (3)].dst_reg).CondSwizzle;
- (yyval.dst_reg).CondSrc = (yyvsp[(3) - (3)].dst_reg).CondSrc;
-
- if ((yyval.dst_reg).File == PROGRAM_OUTPUT) {
- /* Technically speaking, this should check that it is in
- * vertex program mode. However, PositionInvariant can never be
- * set in fragment program mode, so it is somewhat irrelevant.
- */
- if (state->option.PositionInvariant
- && ((yyval.dst_reg).Index == VERT_RESULT_HPOS)) {
- yyerror(& (yylsp[(1) - (3)]), state, "position-invariant programs cannot "
- "write position");
- YYERROR;
- }
-
- state->prog->OutputsWritten |= BITFIELD64_BIT((yyval.dst_reg).Index);
- }
- ;}
- break;
-
- case 55:
-
-/* Line 1455 of yacc.c */
-#line 658 "program_parse.y"
- {
- set_dst_reg(& (yyval.dst_reg), PROGRAM_ADDRESS, 0);
- (yyval.dst_reg).WriteMask = (yyvsp[(2) - (2)].swiz_mask).mask;
- ;}
- break;
-
- case 56:
-
-/* Line 1455 of yacc.c */
-#line 665 "program_parse.y"
- {
- const unsigned xyzw_valid =
- ((yyvsp[(1) - (7)].ext_swizzle).xyzw_valid << 0)
- | ((yyvsp[(3) - (7)].ext_swizzle).xyzw_valid << 1)
- | ((yyvsp[(5) - (7)].ext_swizzle).xyzw_valid << 2)
- | ((yyvsp[(7) - (7)].ext_swizzle).xyzw_valid << 3);
- const unsigned rgba_valid =
- ((yyvsp[(1) - (7)].ext_swizzle).rgba_valid << 0)
- | ((yyvsp[(3) - (7)].ext_swizzle).rgba_valid << 1)
- | ((yyvsp[(5) - (7)].ext_swizzle).rgba_valid << 2)
- | ((yyvsp[(7) - (7)].ext_swizzle).rgba_valid << 3);
-
- /* All of the swizzle components have to be valid in either RGBA
- * or XYZW. Note that 0 and 1 are valid in both, so both masks
- * can have some bits set.
- *
- * We somewhat deviate from the spec here. It would be really hard
- * to figure out which component is the error, and there probably
- * isn't a lot of benefit.
- */
- if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) {
- yyerror(& (yylsp[(1) - (7)]), state, "cannot combine RGBA and XYZW swizzle "
- "components");
- YYERROR;
- }
-
- (yyval.swiz_mask).swizzle = MAKE_SWIZZLE4((yyvsp[(1) - (7)].ext_swizzle).swz, (yyvsp[(3) - (7)].ext_swizzle).swz, (yyvsp[(5) - (7)].ext_swizzle).swz, (yyvsp[(7) - (7)].ext_swizzle).swz);
- (yyval.swiz_mask).mask = ((yyvsp[(1) - (7)].ext_swizzle).negate) | ((yyvsp[(3) - (7)].ext_swizzle).negate << 1) | ((yyvsp[(5) - (7)].ext_swizzle).negate << 2)
- | ((yyvsp[(7) - (7)].ext_swizzle).negate << 3);
- ;}
- break;
-
- case 57:
-
-/* Line 1455 of yacc.c */
-#line 698 "program_parse.y"
- {
- (yyval.ext_swizzle) = (yyvsp[(2) - (2)].ext_swizzle);
- (yyval.ext_swizzle).negate = ((yyvsp[(1) - (2)].negate)) ? 1 : 0;
- ;}
- break;
-
- case 58:
-
-/* Line 1455 of yacc.c */
-#line 705 "program_parse.y"
- {
- if (((yyvsp[(1) - (1)].integer) != 0) && ((yyvsp[(1) - (1)].integer) != 1)) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector");
- YYERROR;
- }
-
- (yyval.ext_swizzle).swz = ((yyvsp[(1) - (1)].integer) == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
-
- /* 0 and 1 are valid for both RGBA swizzle names and XYZW
- * swizzle names.
- */
- (yyval.ext_swizzle).xyzw_valid = 1;
- (yyval.ext_swizzle).rgba_valid = 1;
- ;}
- break;
-
- case 59:
-
-/* Line 1455 of yacc.c */
-#line 720 "program_parse.y"
- {
- char s;
-
- if (strlen((yyvsp[(1) - (1)].string)) > 1) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector");
- YYERROR;
- }
-
- s = (yyvsp[(1) - (1)].string)[0];
- free((yyvsp[(1) - (1)].string));
-
- switch (s) {
- case 'x':
- (yyval.ext_swizzle).swz = SWIZZLE_X;
- (yyval.ext_swizzle).xyzw_valid = 1;
- break;
- case 'y':
- (yyval.ext_swizzle).swz = SWIZZLE_Y;
- (yyval.ext_swizzle).xyzw_valid = 1;
- break;
- case 'z':
- (yyval.ext_swizzle).swz = SWIZZLE_Z;
- (yyval.ext_swizzle).xyzw_valid = 1;
- break;
- case 'w':
- (yyval.ext_swizzle).swz = SWIZZLE_W;
- (yyval.ext_swizzle).xyzw_valid = 1;
- break;
-
- case 'r':
- (yyval.ext_swizzle).swz = SWIZZLE_X;
- (yyval.ext_swizzle).rgba_valid = 1;
- break;
- case 'g':
- (yyval.ext_swizzle).swz = SWIZZLE_Y;
- (yyval.ext_swizzle).rgba_valid = 1;
- break;
- case 'b':
- (yyval.ext_swizzle).swz = SWIZZLE_Z;
- (yyval.ext_swizzle).rgba_valid = 1;
- break;
- case 'a':
- (yyval.ext_swizzle).swz = SWIZZLE_W;
- (yyval.ext_swizzle).rgba_valid = 1;
- break;
-
- default:
- yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector");
- YYERROR;
- break;
- }
- ;}
- break;
-
- case 60:
-
-/* Line 1455 of yacc.c */
-#line 775 "program_parse.y"
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
-
- free((yyvsp[(1) - (1)].string));
-
- if (s == NULL) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
- YYERROR;
- } else if ((s->type != at_param) && (s->type != at_temp)
- && (s->type != at_attrib)) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
- YYERROR;
- } else if ((s->type == at_param) && s->param_is_array) {
- yyerror(& (yylsp[(1) - (1)]), state, "non-array access to array PARAM");
- YYERROR;
- }
-
- init_src_reg(& (yyval.src_reg));
- switch (s->type) {
- case at_temp:
- set_src_reg(& (yyval.src_reg), PROGRAM_TEMPORARY, s->temp_binding);
- break;
- case at_param:
- set_src_reg_swz(& (yyval.src_reg), s->param_binding_type,
- s->param_binding_begin,
- s->param_binding_swizzle);
- break;
- case at_attrib:
- set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, s->attrib_binding);
- state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index);
-
- if (!validate_inputs(& (yylsp[(1) - (1)]), state)) {
- YYERROR;
- }
- break;
-
- default:
- YYERROR;
- break;
- }
- ;}
- break;
-
- case 61:
-
-/* Line 1455 of yacc.c */
-#line 818 "program_parse.y"
- {
- set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, (yyvsp[(1) - (1)].attrib));
- state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index);
-
- if (!validate_inputs(& (yylsp[(1) - (1)]), state)) {
- YYERROR;
- }
- ;}
- break;
-
- case 62:
-
-/* Line 1455 of yacc.c */
-#line 827 "program_parse.y"
- {
- if (! (yyvsp[(3) - (4)].src_reg).Base.RelAddr
- && ((unsigned) (yyvsp[(3) - (4)].src_reg).Base.Index >= (yyvsp[(1) - (4)].sym)->param_binding_length)) {
- yyerror(& (yylsp[(3) - (4)]), state, "out of bounds array access");
- YYERROR;
- }
-
- init_src_reg(& (yyval.src_reg));
- (yyval.src_reg).Base.File = (yyvsp[(1) - (4)].sym)->param_binding_type;
-
- if ((yyvsp[(3) - (4)].src_reg).Base.RelAddr) {
- state->prog->IndirectRegisterFiles |= (1 << (yyval.src_reg).Base.File);
- (yyvsp[(1) - (4)].sym)->param_accessed_indirectly = 1;
-
- (yyval.src_reg).Base.RelAddr = 1;
- (yyval.src_reg).Base.Index = (yyvsp[(3) - (4)].src_reg).Base.Index;
- (yyval.src_reg).Symbol = (yyvsp[(1) - (4)].sym);
- } else {
- (yyval.src_reg).Base.Index = (yyvsp[(1) - (4)].sym)->param_binding_begin + (yyvsp[(3) - (4)].src_reg).Base.Index;
- }
- ;}
- break;
-
- case 63:
-
-/* Line 1455 of yacc.c */
-#line 849 "program_parse.y"
- {
- gl_register_file file = ((yyvsp[(1) - (1)].temp_sym).name != NULL)
- ? (yyvsp[(1) - (1)].temp_sym).param_binding_type
- : PROGRAM_CONSTANT;
- set_src_reg_swz(& (yyval.src_reg), file, (yyvsp[(1) - (1)].temp_sym).param_binding_begin,
- (yyvsp[(1) - (1)].temp_sym).param_binding_swizzle);
- ;}
- break;
-
- case 64:
-
-/* Line 1455 of yacc.c */
-#line 859 "program_parse.y"
- {
- set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, (yyvsp[(1) - (1)].result));
- ;}
- break;
-
- case 65:
-
-/* Line 1455 of yacc.c */
-#line 863 "program_parse.y"
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
-
- free((yyvsp[(1) - (1)].string));
-
- if (s == NULL) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
- YYERROR;
- } else if ((s->type != at_output) && (s->type != at_temp)) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
- YYERROR;
- }
-
- switch (s->type) {
- case at_temp:
- set_dst_reg(& (yyval.dst_reg), PROGRAM_TEMPORARY, s->temp_binding);
- break;
- case at_output:
- set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, s->output_binding);
- break;
- default:
- set_dst_reg(& (yyval.dst_reg), s->param_binding_type, s->param_binding_begin);
- break;
- }
- ;}
- break;
-
- case 66:
-
-/* Line 1455 of yacc.c */
-#line 892 "program_parse.y"
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
-
- free((yyvsp[(1) - (1)].string));
-
- if (s == NULL) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
- YYERROR;
- } else if ((s->type != at_param) || !s->param_is_array) {
- yyerror(& (yylsp[(1) - (1)]), state, "array access to non-PARAM variable");
- YYERROR;
- } else {
- (yyval.sym) = s;
- }
- ;}
- break;
-
- case 69:
-
-/* Line 1455 of yacc.c */
-#line 913 "program_parse.y"
- {
- init_src_reg(& (yyval.src_reg));
- (yyval.src_reg).Base.Index = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 70:
-
-/* Line 1455 of yacc.c */
-#line 920 "program_parse.y"
- {
- /* FINISHME: Add support for multiple address registers.
- */
- /* FINISHME: Add support for 4-component address registers.
- */
- init_src_reg(& (yyval.src_reg));
- (yyval.src_reg).Base.RelAddr = 1;
- (yyval.src_reg).Base.Index = (yyvsp[(3) - (3)].integer);
- ;}
- break;
-
- case 71:
-
-/* Line 1455 of yacc.c */
-#line 931 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 72:
-
-/* Line 1455 of yacc.c */
-#line 932 "program_parse.y"
- { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;}
- break;
-
- case 73:
-
-/* Line 1455 of yacc.c */
-#line 933 "program_parse.y"
- { (yyval.integer) = -(yyvsp[(2) - (2)].integer); ;}
- break;
-
- case 74:
-
-/* Line 1455 of yacc.c */
-#line 937 "program_parse.y"
- {
- if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 4095)) {
- char s[100];
- _mesa_snprintf(s, sizeof(s),
- "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer));
- yyerror(& (yylsp[(1) - (1)]), state, s);
- YYERROR;
- } else {
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- }
- ;}
- break;
-
- case 75:
-
-/* Line 1455 of yacc.c */
-#line 951 "program_parse.y"
- {
- if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 4096)) {
- char s[100];
- _mesa_snprintf(s, sizeof(s),
- "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer));
- yyerror(& (yylsp[(1) - (1)]), state, s);
- YYERROR;
- } else {
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- }
- ;}
- break;
-
- case 76:
-
-/* Line 1455 of yacc.c */
-#line 965 "program_parse.y"
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
-
- free((yyvsp[(1) - (1)].string));
-
- if (s == NULL) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid array member");
- YYERROR;
- } else if (s->type != at_address) {
- yyerror(& (yylsp[(1) - (1)]), state,
- "invalid variable for indexed array access");
- YYERROR;
- } else {
- (yyval.sym) = s;
- }
- ;}
- break;
-
- case 77:
-
-/* Line 1455 of yacc.c */
-#line 985 "program_parse.y"
- {
- if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid address component selector");
- YYERROR;
- } else {
- (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask);
- }
- ;}
- break;
-
- case 78:
-
-/* Line 1455 of yacc.c */
-#line 996 "program_parse.y"
- {
- if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) {
- yyerror(& (yylsp[(1) - (1)]), state,
- "address register write mask must be \".x\"");
- YYERROR;
- } else {
- (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask);
- }
- ;}
- break;
-
- case 83:
-
-/* Line 1455 of yacc.c */
-#line 1012 "program_parse.y"
- { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;}
- break;
-
- case 88:
-
-/* Line 1455 of yacc.c */
-#line 1016 "program_parse.y"
- { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;}
- break;
-
- case 89:
-
-/* Line 1455 of yacc.c */
-#line 1020 "program_parse.y"
- {
- (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg);
- ;}
- break;
-
- case 90:
-
-/* Line 1455 of yacc.c */
-#line 1024 "program_parse.y"
- {
- (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg);
- ;}
- break;
-
- case 91:
-
-/* Line 1455 of yacc.c */
-#line 1028 "program_parse.y"
- {
- (yyval.dst_reg).CondMask = COND_TR;
- (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP;
- (yyval.dst_reg).CondSrc = 0;
- ;}
- break;
-
- case 92:
-
-/* Line 1455 of yacc.c */
-#line 1036 "program_parse.y"
- {
- (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg);
- (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle;
- ;}
- break;
-
- case 93:
-
-/* Line 1455 of yacc.c */
-#line 1043 "program_parse.y"
- {
- (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg);
- (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle;
- ;}
- break;
-
- case 94:
-
-/* Line 1455 of yacc.c */
-#line 1050 "program_parse.y"
- {
- const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string));
- if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) {
- char *const err_str =
- make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string));
-
- yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL)
- ? err_str : "invalid condition code");
-
- if (err_str != NULL) {
- free(err_str);
- }
-
- YYERROR;
- }
-
- (yyval.dst_reg).CondMask = cond;
- (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP;
- (yyval.dst_reg).CondSrc = 0;
- ;}
- break;
-
- case 95:
-
-/* Line 1455 of yacc.c */
-#line 1073 "program_parse.y"
- {
- const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string));
- if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) {
- char *const err_str =
- make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string));
-
- yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL)
- ? err_str : "invalid condition code");
-
- if (err_str != NULL) {
- free(err_str);
- }
-
- YYERROR;
- }
-
- (yyval.dst_reg).CondMask = cond;
- (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP;
- (yyval.dst_reg).CondSrc = 0;
- ;}
- break;
-
- case 102:
-
-/* Line 1455 of yacc.c */
-#line 1104 "program_parse.y"
- {
- struct asm_symbol *const s =
- declare_variable(state, (yyvsp[(2) - (4)].string), at_attrib, & (yylsp[(2) - (4)]));
-
- if (s == NULL) {
- free((yyvsp[(2) - (4)].string));
- YYERROR;
- } else {
- s->attrib_binding = (yyvsp[(4) - (4)].attrib);
- state->InputsBound |= (1U << s->attrib_binding);
-
- if (!validate_inputs(& (yylsp[(4) - (4)]), state)) {
- YYERROR;
- }
- }
- ;}
- break;
-
- case 103:
-
-/* Line 1455 of yacc.c */
-#line 1123 "program_parse.y"
- {
- (yyval.attrib) = (yyvsp[(2) - (2)].attrib);
- ;}
- break;
-
- case 104:
-
-/* Line 1455 of yacc.c */
-#line 1127 "program_parse.y"
- {
- (yyval.attrib) = (yyvsp[(2) - (2)].attrib);
- ;}
- break;
-
- case 105:
-
-/* Line 1455 of yacc.c */
-#line 1133 "program_parse.y"
- {
- (yyval.attrib) = VERT_ATTRIB_POS;
- ;}
- break;
-
- case 106:
-
-/* Line 1455 of yacc.c */
-#line 1137 "program_parse.y"
- {
- (yyval.attrib) = VERT_ATTRIB_WEIGHT;
- ;}
- break;
-
- case 107:
-
-/* Line 1455 of yacc.c */
-#line 1141 "program_parse.y"
- {
- (yyval.attrib) = VERT_ATTRIB_NORMAL;
- ;}
- break;
-
- case 108:
-
-/* Line 1455 of yacc.c */
-#line 1145 "program_parse.y"
- {
- if (!state->ctx->Extensions.EXT_secondary_color) {
- yyerror(& (yylsp[(2) - (2)]), state, "GL_EXT_secondary_color not supported");
- YYERROR;
- }
-
- (yyval.attrib) = VERT_ATTRIB_COLOR0 + (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 109:
-
-/* Line 1455 of yacc.c */
-#line 1154 "program_parse.y"
- {
- if (!state->ctx->Extensions.EXT_fog_coord) {
- yyerror(& (yylsp[(1) - (1)]), state, "GL_EXT_fog_coord not supported");
- YYERROR;
- }
-
- (yyval.attrib) = VERT_ATTRIB_FOG;
- ;}
- break;
-
- case 110:
-
-/* Line 1455 of yacc.c */
-#line 1163 "program_parse.y"
- {
- (yyval.attrib) = VERT_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 111:
-
-/* Line 1455 of yacc.c */
-#line 1167 "program_parse.y"
- {
- yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported");
- YYERROR;
- ;}
- break;
-
- case 112:
-
-/* Line 1455 of yacc.c */
-#line 1172 "program_parse.y"
- {
- (yyval.attrib) = VERT_ATTRIB_GENERIC0 + (yyvsp[(3) - (4)].integer);
- ;}
- break;
-
- case 113:
-
-/* Line 1455 of yacc.c */
-#line 1178 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxAttribs) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex attribute reference");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 117:
-
-/* Line 1455 of yacc.c */
-#line 1192 "program_parse.y"
- {
- (yyval.attrib) = FRAG_ATTRIB_WPOS;
- ;}
- break;
-
- case 118:
-
-/* Line 1455 of yacc.c */
-#line 1196 "program_parse.y"
- {
- (yyval.attrib) = FRAG_ATTRIB_COL0 + (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 119:
-
-/* Line 1455 of yacc.c */
-#line 1200 "program_parse.y"
- {
- (yyval.attrib) = FRAG_ATTRIB_FOGC;
- ;}
- break;
-
- case 120:
-
-/* Line 1455 of yacc.c */
-#line 1204 "program_parse.y"
- {
- (yyval.attrib) = FRAG_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 123:
-
-/* Line 1455 of yacc.c */
-#line 1212 "program_parse.y"
- {
- struct asm_symbol *const s =
- declare_variable(state, (yyvsp[(2) - (3)].string), at_param, & (yylsp[(2) - (3)]));
-
- if (s == NULL) {
- free((yyvsp[(2) - (3)].string));
- YYERROR;
- } else {
- s->param_binding_type = (yyvsp[(3) - (3)].temp_sym).param_binding_type;
- s->param_binding_begin = (yyvsp[(3) - (3)].temp_sym).param_binding_begin;
- s->param_binding_length = (yyvsp[(3) - (3)].temp_sym).param_binding_length;
- s->param_binding_swizzle = (yyvsp[(3) - (3)].temp_sym).param_binding_swizzle;
- s->param_is_array = 0;
- }
- ;}
- break;
-
- case 124:
-
-/* Line 1455 of yacc.c */
-#line 1230 "program_parse.y"
- {
- if (((yyvsp[(4) - (6)].integer) != 0) && ((unsigned) (yyvsp[(4) - (6)].integer) != (yyvsp[(6) - (6)].temp_sym).param_binding_length)) {
- free((yyvsp[(2) - (6)].string));
- yyerror(& (yylsp[(4) - (6)]), state,
- "parameter array size and number of bindings must match");
- YYERROR;
- } else {
- struct asm_symbol *const s =
- declare_variable(state, (yyvsp[(2) - (6)].string), (yyvsp[(6) - (6)].temp_sym).type, & (yylsp[(2) - (6)]));
-
- if (s == NULL) {
- free((yyvsp[(2) - (6)].string));
- YYERROR;
- } else {
- s->param_binding_type = (yyvsp[(6) - (6)].temp_sym).param_binding_type;
- s->param_binding_begin = (yyvsp[(6) - (6)].temp_sym).param_binding_begin;
- s->param_binding_length = (yyvsp[(6) - (6)].temp_sym).param_binding_length;
- s->param_binding_swizzle = SWIZZLE_XYZW;
- s->param_is_array = 1;
- }
- }
- ;}
- break;
-
- case 125:
-
-/* Line 1455 of yacc.c */
-#line 1255 "program_parse.y"
- {
- (yyval.integer) = 0;
- ;}
- break;
-
- case 126:
-
-/* Line 1455 of yacc.c */
-#line 1259 "program_parse.y"
- {
- if (((yyvsp[(1) - (1)].integer) < 1) || ((unsigned) (yyvsp[(1) - (1)].integer) > state->limits->MaxParameters)) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid parameter array size");
- YYERROR;
- } else {
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- }
- ;}
- break;
-
- case 127:
-
-/* Line 1455 of yacc.c */
-#line 1270 "program_parse.y"
- {
- (yyval.temp_sym) = (yyvsp[(2) - (2)].temp_sym);
- ;}
- break;
-
- case 128:
-
-/* Line 1455 of yacc.c */
-#line 1276 "program_parse.y"
- {
- (yyval.temp_sym) = (yyvsp[(3) - (4)].temp_sym);
- ;}
- break;
-
- case 130:
-
-/* Line 1455 of yacc.c */
-#line 1283 "program_parse.y"
- {
- (yyvsp[(1) - (3)].temp_sym).param_binding_length += (yyvsp[(3) - (3)].temp_sym).param_binding_length;
- (yyval.temp_sym) = (yyvsp[(1) - (3)].temp_sym);
- ;}
- break;
-
- case 131:
-
-/* Line 1455 of yacc.c */
-#line 1290 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
- ;}
- break;
-
- case 132:
-
-/* Line 1455 of yacc.c */
-#line 1296 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
- ;}
- break;
-
- case 133:
-
-/* Line 1455 of yacc.c */
-#line 1302 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE);
- ;}
- break;
-
- case 134:
-
-/* Line 1455 of yacc.c */
-#line 1310 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
- ;}
- break;
-
- case 135:
-
-/* Line 1455 of yacc.c */
-#line 1316 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
- ;}
- break;
-
- case 136:
-
-/* Line 1455 of yacc.c */
-#line 1322 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE);
- ;}
- break;
-
- case 137:
-
-/* Line 1455 of yacc.c */
-#line 1330 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
- ;}
- break;
-
- case 138:
-
-/* Line 1455 of yacc.c */
-#line 1336 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
- ;}
- break;
-
- case 139:
-
-/* Line 1455 of yacc.c */
-#line 1342 "program_parse.y"
- {
- memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
- (yyval.temp_sym).param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_FALSE);
- ;}
- break;
-
- case 140:
-
-/* Line 1455 of yacc.c */
-#line 1349 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(1) - (1)].state), sizeof((yyval.state))); ;}
- break;
-
- case 141:
-
-/* Line 1455 of yacc.c */
-#line 1350 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 142:
-
-/* Line 1455 of yacc.c */
-#line 1353 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 143:
-
-/* Line 1455 of yacc.c */
-#line 1354 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 144:
-
-/* Line 1455 of yacc.c */
-#line 1355 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 145:
-
-/* Line 1455 of yacc.c */
-#line 1356 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 146:
-
-/* Line 1455 of yacc.c */
-#line 1357 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 147:
-
-/* Line 1455 of yacc.c */
-#line 1358 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 148:
-
-/* Line 1455 of yacc.c */
-#line 1359 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 149:
-
-/* Line 1455 of yacc.c */
-#line 1360 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 150:
-
-/* Line 1455 of yacc.c */
-#line 1361 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 151:
-
-/* Line 1455 of yacc.c */
-#line 1362 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 152:
-
-/* Line 1455 of yacc.c */
-#line 1363 "program_parse.y"
- { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
- break;
-
- case 153:
-
-/* Line 1455 of yacc.c */
-#line 1367 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_MATERIAL;
- (yyval.state)[1] = (yyvsp[(2) - (3)].integer);
- (yyval.state)[2] = (yyvsp[(3) - (3)].integer);
- ;}
- break;
-
- case 154:
-
-/* Line 1455 of yacc.c */
-#line 1376 "program_parse.y"
- {
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 155:
-
-/* Line 1455 of yacc.c */
-#line 1380 "program_parse.y"
- {
- (yyval.integer) = STATE_EMISSION;
- ;}
- break;
-
- case 156:
-
-/* Line 1455 of yacc.c */
-#line 1384 "program_parse.y"
- {
- (yyval.integer) = STATE_SHININESS;
- ;}
- break;
-
- case 157:
-
-/* Line 1455 of yacc.c */
-#line 1390 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_LIGHT;
- (yyval.state)[1] = (yyvsp[(3) - (5)].integer);
- (yyval.state)[2] = (yyvsp[(5) - (5)].integer);
- ;}
- break;
-
- case 158:
-
-/* Line 1455 of yacc.c */
-#line 1399 "program_parse.y"
- {
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 159:
-
-/* Line 1455 of yacc.c */
-#line 1403 "program_parse.y"
- {
- (yyval.integer) = STATE_POSITION;
- ;}
- break;
-
- case 160:
-
-/* Line 1455 of yacc.c */
-#line 1407 "program_parse.y"
- {
- if (!state->ctx->Extensions.EXT_point_parameters) {
- yyerror(& (yylsp[(1) - (1)]), state, "GL_ARB_point_parameters not supported");
- YYERROR;
- }
-
- (yyval.integer) = STATE_ATTENUATION;
- ;}
- break;
-
- case 161:
-
-/* Line 1455 of yacc.c */
-#line 1416 "program_parse.y"
- {
- (yyval.integer) = (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 162:
-
-/* Line 1455 of yacc.c */
-#line 1420 "program_parse.y"
- {
- (yyval.integer) = STATE_HALF_VECTOR;
- ;}
- break;
-
- case 163:
-
-/* Line 1455 of yacc.c */
-#line 1426 "program_parse.y"
- {
- (yyval.integer) = STATE_SPOT_DIRECTION;
- ;}
- break;
-
- case 164:
-
-/* Line 1455 of yacc.c */
-#line 1432 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(2) - (2)].state)[0];
- (yyval.state)[1] = (yyvsp[(2) - (2)].state)[1];
- ;}
- break;
-
- case 165:
-
-/* Line 1455 of yacc.c */
-#line 1439 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_LIGHTMODEL_AMBIENT;
- ;}
- break;
-
- case 166:
-
-/* Line 1455 of yacc.c */
-#line 1444 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_LIGHTMODEL_SCENECOLOR;
- (yyval.state)[1] = (yyvsp[(1) - (2)].integer);
- ;}
- break;
-
- case 167:
-
-/* Line 1455 of yacc.c */
-#line 1452 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_LIGHTPROD;
- (yyval.state)[1] = (yyvsp[(3) - (6)].integer);
- (yyval.state)[2] = (yyvsp[(5) - (6)].integer);
- (yyval.state)[3] = (yyvsp[(6) - (6)].integer);
- ;}
- break;
-
- case 169:
-
-/* Line 1455 of yacc.c */
-#line 1464 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = (yyvsp[(3) - (3)].integer);
- (yyval.state)[1] = (yyvsp[(2) - (3)].integer);
- ;}
- break;
-
- case 170:
-
-/* Line 1455 of yacc.c */
-#line 1472 "program_parse.y"
- {
- (yyval.integer) = STATE_TEXENV_COLOR;
- ;}
- break;
-
- case 171:
-
-/* Line 1455 of yacc.c */
-#line 1478 "program_parse.y"
- {
- (yyval.integer) = STATE_AMBIENT;
- ;}
- break;
-
- case 172:
-
-/* Line 1455 of yacc.c */
-#line 1482 "program_parse.y"
- {
- (yyval.integer) = STATE_DIFFUSE;
- ;}
- break;
-
- case 173:
-
-/* Line 1455 of yacc.c */
-#line 1486 "program_parse.y"
- {
- (yyval.integer) = STATE_SPECULAR;
- ;}
- break;
-
- case 174:
-
-/* Line 1455 of yacc.c */
-#line 1492 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxLights) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid light selector");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 175:
-
-/* Line 1455 of yacc.c */
-#line 1503 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_TEXGEN;
- (yyval.state)[1] = (yyvsp[(2) - (4)].integer);
- (yyval.state)[2] = (yyvsp[(3) - (4)].integer) + (yyvsp[(4) - (4)].integer);
- ;}
- break;
-
- case 176:
-
-/* Line 1455 of yacc.c */
-#line 1512 "program_parse.y"
- {
- (yyval.integer) = STATE_TEXGEN_EYE_S;
- ;}
- break;
-
- case 177:
-
-/* Line 1455 of yacc.c */
-#line 1516 "program_parse.y"
- {
- (yyval.integer) = STATE_TEXGEN_OBJECT_S;
- ;}
- break;
-
- case 178:
-
-/* Line 1455 of yacc.c */
-#line 1521 "program_parse.y"
- {
- (yyval.integer) = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S;
- ;}
- break;
-
- case 179:
-
-/* Line 1455 of yacc.c */
-#line 1525 "program_parse.y"
- {
- (yyval.integer) = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S;
- ;}
- break;
-
- case 180:
-
-/* Line 1455 of yacc.c */
-#line 1529 "program_parse.y"
- {
- (yyval.integer) = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S;
- ;}
- break;
-
- case 181:
-
-/* Line 1455 of yacc.c */
-#line 1533 "program_parse.y"
- {
- (yyval.integer) = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S;
- ;}
- break;
-
- case 182:
-
-/* Line 1455 of yacc.c */
-#line 1539 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 183:
-
-/* Line 1455 of yacc.c */
-#line 1546 "program_parse.y"
- {
- (yyval.integer) = STATE_FOG_COLOR;
- ;}
- break;
-
- case 184:
-
-/* Line 1455 of yacc.c */
-#line 1550 "program_parse.y"
- {
- (yyval.integer) = STATE_FOG_PARAMS;
- ;}
- break;
-
- case 185:
-
-/* Line 1455 of yacc.c */
-#line 1556 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_CLIPPLANE;
- (yyval.state)[1] = (yyvsp[(3) - (5)].integer);
- ;}
- break;
-
- case 186:
-
-/* Line 1455 of yacc.c */
-#line 1564 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxClipPlanes) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid clip plane selector");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 187:
-
-/* Line 1455 of yacc.c */
-#line 1575 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 188:
-
-/* Line 1455 of yacc.c */
-#line 1582 "program_parse.y"
- {
- (yyval.integer) = STATE_POINT_SIZE;
- ;}
- break;
-
- case 189:
-
-/* Line 1455 of yacc.c */
-#line 1586 "program_parse.y"
- {
- (yyval.integer) = STATE_POINT_ATTENUATION;
- ;}
- break;
-
- case 190:
-
-/* Line 1455 of yacc.c */
-#line 1592 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(1) - (5)].state)[0];
- (yyval.state)[1] = (yyvsp[(1) - (5)].state)[1];
- (yyval.state)[2] = (yyvsp[(4) - (5)].integer);
- (yyval.state)[3] = (yyvsp[(4) - (5)].integer);
- (yyval.state)[4] = (yyvsp[(1) - (5)].state)[2];
- ;}
- break;
-
- case 191:
-
-/* Line 1455 of yacc.c */
-#line 1602 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(1) - (2)].state)[0];
- (yyval.state)[1] = (yyvsp[(1) - (2)].state)[1];
- (yyval.state)[2] = (yyvsp[(2) - (2)].state)[2];
- (yyval.state)[3] = (yyvsp[(2) - (2)].state)[3];
- (yyval.state)[4] = (yyvsp[(1) - (2)].state)[2];
- ;}
- break;
-
- case 192:
-
-/* Line 1455 of yacc.c */
-#line 1612 "program_parse.y"
- {
- (yyval.state)[2] = 0;
- (yyval.state)[3] = 3;
- ;}
- break;
-
- case 193:
-
-/* Line 1455 of yacc.c */
-#line 1617 "program_parse.y"
- {
- /* It seems logical that the matrix row range specifier would have
- * to specify a range or more than one row (i.e., $5 > $3).
- * However, the ARB_vertex_program spec says "a program will fail
- * to load if <a> is greater than <b>." This means that $3 == $5
- * is valid.
- */
- if ((yyvsp[(3) - (6)].integer) > (yyvsp[(5) - (6)].integer)) {
- yyerror(& (yylsp[(3) - (6)]), state, "invalid matrix row range");
- YYERROR;
- }
-
- (yyval.state)[2] = (yyvsp[(3) - (6)].integer);
- (yyval.state)[3] = (yyvsp[(5) - (6)].integer);
- ;}
- break;
-
- case 194:
-
-/* Line 1455 of yacc.c */
-#line 1635 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(2) - (3)].state)[0];
- (yyval.state)[1] = (yyvsp[(2) - (3)].state)[1];
- (yyval.state)[2] = (yyvsp[(3) - (3)].integer);
- ;}
- break;
-
- case 195:
-
-/* Line 1455 of yacc.c */
-#line 1643 "program_parse.y"
- {
- (yyval.integer) = 0;
- ;}
- break;
-
- case 196:
-
-/* Line 1455 of yacc.c */
-#line 1647 "program_parse.y"
- {
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 197:
-
-/* Line 1455 of yacc.c */
-#line 1653 "program_parse.y"
- {
- (yyval.integer) = STATE_MATRIX_INVERSE;
- ;}
- break;
-
- case 198:
-
-/* Line 1455 of yacc.c */
-#line 1657 "program_parse.y"
- {
- (yyval.integer) = STATE_MATRIX_TRANSPOSE;
- ;}
- break;
-
- case 199:
-
-/* Line 1455 of yacc.c */
-#line 1661 "program_parse.y"
- {
- (yyval.integer) = STATE_MATRIX_INVTRANS;
- ;}
- break;
-
- case 200:
-
-/* Line 1455 of yacc.c */
-#line 1667 "program_parse.y"
- {
- if ((yyvsp[(1) - (1)].integer) > 3) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid matrix row reference");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 201:
-
-/* Line 1455 of yacc.c */
-#line 1678 "program_parse.y"
- {
- (yyval.state)[0] = STATE_MODELVIEW_MATRIX;
- (yyval.state)[1] = (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 202:
-
-/* Line 1455 of yacc.c */
-#line 1683 "program_parse.y"
- {
- (yyval.state)[0] = STATE_PROJECTION_MATRIX;
- (yyval.state)[1] = 0;
- ;}
- break;
-
- case 203:
-
-/* Line 1455 of yacc.c */
-#line 1688 "program_parse.y"
- {
- (yyval.state)[0] = STATE_MVP_MATRIX;
- (yyval.state)[1] = 0;
- ;}
- break;
-
- case 204:
-
-/* Line 1455 of yacc.c */
-#line 1693 "program_parse.y"
- {
- (yyval.state)[0] = STATE_TEXTURE_MATRIX;
- (yyval.state)[1] = (yyvsp[(2) - (2)].integer);
- ;}
- break;
-
- case 205:
-
-/* Line 1455 of yacc.c */
-#line 1698 "program_parse.y"
- {
- yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported");
- YYERROR;
- ;}
- break;
-
- case 206:
-
-/* Line 1455 of yacc.c */
-#line 1703 "program_parse.y"
- {
- (yyval.state)[0] = STATE_PROGRAM_MATRIX;
- (yyval.state)[1] = (yyvsp[(3) - (4)].integer);
- ;}
- break;
-
- case 207:
-
-/* Line 1455 of yacc.c */
-#line 1710 "program_parse.y"
- {
- (yyval.integer) = 0;
- ;}
- break;
-
- case 208:
-
-/* Line 1455 of yacc.c */
-#line 1714 "program_parse.y"
- {
- (yyval.integer) = (yyvsp[(2) - (3)].integer);
- ;}
- break;
-
- case 209:
-
-/* Line 1455 of yacc.c */
-#line 1719 "program_parse.y"
- {
- /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix
- * zero is valid.
- */
- if ((yyvsp[(1) - (1)].integer) != 0) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid modelview matrix index");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 210:
-
-/* Line 1455 of yacc.c */
-#line 1732 "program_parse.y"
- {
- /* Since GL_ARB_matrix_palette isn't supported, just let any value
- * through here. The error will be generated later.
- */
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 211:
-
-/* Line 1455 of yacc.c */
-#line 1740 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxProgramMatrices) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid program matrix selector");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 212:
-
-/* Line 1455 of yacc.c */
-#line 1751 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = STATE_DEPTH_RANGE;
- ;}
- break;
-
- case 217:
-
-/* Line 1455 of yacc.c */
-#line 1763 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = state->state_param_enum;
- (yyval.state)[1] = STATE_ENV;
- (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0];
- (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1];
- ;}
- break;
-
- case 218:
-
-/* Line 1455 of yacc.c */
-#line 1773 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(1) - (1)].integer);
- (yyval.state)[1] = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 219:
-
-/* Line 1455 of yacc.c */
-#line 1778 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(1) - (3)].integer);
- (yyval.state)[1] = (yyvsp[(3) - (3)].integer);
- ;}
- break;
-
- case 220:
-
-/* Line 1455 of yacc.c */
-#line 1785 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = state->state_param_enum;
- (yyval.state)[1] = STATE_ENV;
- (yyval.state)[2] = (yyvsp[(4) - (5)].integer);
- (yyval.state)[3] = (yyvsp[(4) - (5)].integer);
- ;}
- break;
-
- case 221:
-
-/* Line 1455 of yacc.c */
-#line 1795 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = state->state_param_enum;
- (yyval.state)[1] = STATE_LOCAL;
- (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0];
- (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1];
- ;}
- break;
-
- case 222:
-
-/* Line 1455 of yacc.c */
-#line 1804 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(1) - (1)].integer);
- (yyval.state)[1] = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 223:
-
-/* Line 1455 of yacc.c */
-#line 1809 "program_parse.y"
- {
- (yyval.state)[0] = (yyvsp[(1) - (3)].integer);
- (yyval.state)[1] = (yyvsp[(3) - (3)].integer);
- ;}
- break;
-
- case 224:
-
-/* Line 1455 of yacc.c */
-#line 1816 "program_parse.y"
- {
- memset((yyval.state), 0, sizeof((yyval.state)));
- (yyval.state)[0] = state->state_param_enum;
- (yyval.state)[1] = STATE_LOCAL;
- (yyval.state)[2] = (yyvsp[(4) - (5)].integer);
- (yyval.state)[3] = (yyvsp[(4) - (5)].integer);
- ;}
- break;
-
- case 225:
-
-/* Line 1455 of yacc.c */
-#line 1826 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxEnvParams) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid environment parameter reference");
- YYERROR;
- }
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 226:
-
-/* Line 1455 of yacc.c */
-#line 1836 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxLocalParams) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid local parameter reference");
- YYERROR;
- }
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 231:
-
-/* Line 1455 of yacc.c */
-#line 1851 "program_parse.y"
- {
- (yyval.vector).count = 4;
- (yyval.vector).data[0] = (yyvsp[(1) - (1)].real);
- (yyval.vector).data[1] = (yyvsp[(1) - (1)].real);
- (yyval.vector).data[2] = (yyvsp[(1) - (1)].real);
- (yyval.vector).data[3] = (yyvsp[(1) - (1)].real);
- ;}
- break;
-
- case 232:
-
-/* Line 1455 of yacc.c */
-#line 1861 "program_parse.y"
- {
- (yyval.vector).count = 1;
- (yyval.vector).data[0] = (yyvsp[(1) - (1)].real);
- (yyval.vector).data[1] = (yyvsp[(1) - (1)].real);
- (yyval.vector).data[2] = (yyvsp[(1) - (1)].real);
- (yyval.vector).data[3] = (yyvsp[(1) - (1)].real);
- ;}
- break;
-
- case 233:
-
-/* Line 1455 of yacc.c */
-#line 1869 "program_parse.y"
- {
- (yyval.vector).count = 1;
- (yyval.vector).data[0] = (float) (yyvsp[(1) - (1)].integer);
- (yyval.vector).data[1] = (float) (yyvsp[(1) - (1)].integer);
- (yyval.vector).data[2] = (float) (yyvsp[(1) - (1)].integer);
- (yyval.vector).data[3] = (float) (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 234:
-
-/* Line 1455 of yacc.c */
-#line 1879 "program_parse.y"
- {
- (yyval.vector).count = 4;
- (yyval.vector).data[0] = (yyvsp[(2) - (3)].real);
- (yyval.vector).data[1] = 0.0f;
- (yyval.vector).data[2] = 0.0f;
- (yyval.vector).data[3] = 1.0f;
- ;}
- break;
-
- case 235:
-
-/* Line 1455 of yacc.c */
-#line 1887 "program_parse.y"
- {
- (yyval.vector).count = 4;
- (yyval.vector).data[0] = (yyvsp[(2) - (5)].real);
- (yyval.vector).data[1] = (yyvsp[(4) - (5)].real);
- (yyval.vector).data[2] = 0.0f;
- (yyval.vector).data[3] = 1.0f;
- ;}
- break;
-
- case 236:
-
-/* Line 1455 of yacc.c */
-#line 1896 "program_parse.y"
- {
- (yyval.vector).count = 4;
- (yyval.vector).data[0] = (yyvsp[(2) - (7)].real);
- (yyval.vector).data[1] = (yyvsp[(4) - (7)].real);
- (yyval.vector).data[2] = (yyvsp[(6) - (7)].real);
- (yyval.vector).data[3] = 1.0f;
- ;}
- break;
-
- case 237:
-
-/* Line 1455 of yacc.c */
-#line 1905 "program_parse.y"
- {
- (yyval.vector).count = 4;
- (yyval.vector).data[0] = (yyvsp[(2) - (9)].real);
- (yyval.vector).data[1] = (yyvsp[(4) - (9)].real);
- (yyval.vector).data[2] = (yyvsp[(6) - (9)].real);
- (yyval.vector).data[3] = (yyvsp[(8) - (9)].real);
- ;}
- break;
-
- case 238:
-
-/* Line 1455 of yacc.c */
-#line 1915 "program_parse.y"
- {
- (yyval.real) = ((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].real) : (yyvsp[(2) - (2)].real);
- ;}
- break;
-
- case 239:
-
-/* Line 1455 of yacc.c */
-#line 1919 "program_parse.y"
- {
- (yyval.real) = (float)(((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].integer) : (yyvsp[(2) - (2)].integer));
- ;}
- break;
-
- case 240:
-
-/* Line 1455 of yacc.c */
-#line 1924 "program_parse.y"
- { (yyval.negate) = FALSE; ;}
- break;
-
- case 241:
-
-/* Line 1455 of yacc.c */
-#line 1925 "program_parse.y"
- { (yyval.negate) = TRUE; ;}
- break;
-
- case 242:
-
-/* Line 1455 of yacc.c */
-#line 1926 "program_parse.y"
- { (yyval.negate) = FALSE; ;}
- break;
-
- case 243:
-
-/* Line 1455 of yacc.c */
-#line 1929 "program_parse.y"
- { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;}
- break;
-
- case 245:
-
-/* Line 1455 of yacc.c */
-#line 1933 "program_parse.y"
- {
- /* NV_fragment_program_option defines the size qualifiers in a
- * fairly broken way. "SHORT" or "LONG" can optionally be used
- * before TEMP or OUTPUT. However, neither is a reserved word!
- * This means that we have to parse it as an identifier, then check
- * to make sure it's one of the valid values. *sigh*
- *
- * In addition, the grammar in the extension spec does *not* allow
- * the size specifier to be optional, but all known implementations
- * do.
- */
- if (!state->option.NV_fragment) {
- yyerror(& (yylsp[(1) - (1)]), state, "unexpected IDENTIFIER");
- YYERROR;
- }
-
- if (strcmp("SHORT", (yyvsp[(1) - (1)].string)) == 0) {
- } else if (strcmp("LONG", (yyvsp[(1) - (1)].string)) == 0) {
- } else {
- char *const err_str =
- make_error_string("invalid storage size specifier \"%s\"",
- (yyvsp[(1) - (1)].string));
-
- yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL)
- ? err_str : "invalid storage size specifier");
-
- if (err_str != NULL) {
- free(err_str);
- }
-
- YYERROR;
- }
- ;}
- break;
-
- case 246:
-
-/* Line 1455 of yacc.c */
-#line 1967 "program_parse.y"
- {
- ;}
- break;
-
- case 247:
-
-/* Line 1455 of yacc.c */
-#line 1971 "program_parse.y"
- { (yyval.integer) = (yyvsp[(1) - (1)].integer); ;}
- break;
-
- case 249:
-
-/* Line 1455 of yacc.c */
-#line 1975 "program_parse.y"
- {
- if (!declare_variable(state, (yyvsp[(3) - (3)].string), (yyvsp[(0) - (3)].integer), & (yylsp[(3) - (3)]))) {
- free((yyvsp[(3) - (3)].string));
- YYERROR;
- }
- ;}
- break;
-
- case 250:
-
-/* Line 1455 of yacc.c */
-#line 1982 "program_parse.y"
- {
- if (!declare_variable(state, (yyvsp[(1) - (1)].string), (yyvsp[(0) - (1)].integer), & (yylsp[(1) - (1)]))) {
- free((yyvsp[(1) - (1)].string));
- YYERROR;
- }
- ;}
- break;
-
- case 251:
-
-/* Line 1455 of yacc.c */
-#line 1991 "program_parse.y"
- {
- struct asm_symbol *const s =
- declare_variable(state, (yyvsp[(3) - (5)].string), at_output, & (yylsp[(3) - (5)]));
-
- if (s == NULL) {
- free((yyvsp[(3) - (5)].string));
- YYERROR;
- } else {
- s->output_binding = (yyvsp[(5) - (5)].result);
- }
- ;}
- break;
-
- case 252:
-
-/* Line 1455 of yacc.c */
-#line 2005 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.result) = VERT_RESULT_HPOS;
- } else {
- yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 253:
-
-/* Line 1455 of yacc.c */
-#line 2014 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.result) = VERT_RESULT_FOGC;
- } else {
- yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 254:
-
-/* Line 1455 of yacc.c */
-#line 2023 "program_parse.y"
- {
- (yyval.result) = (yyvsp[(2) - (2)].result);
- ;}
- break;
-
- case 255:
-
-/* Line 1455 of yacc.c */
-#line 2027 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.result) = VERT_RESULT_PSIZ;
- } else {
- yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 256:
-
-/* Line 1455 of yacc.c */
-#line 2036 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.result) = VERT_RESULT_TEX0 + (yyvsp[(3) - (3)].integer);
- } else {
- yyerror(& (yylsp[(2) - (3)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 257:
-
-/* Line 1455 of yacc.c */
-#line 2045 "program_parse.y"
- {
- if (state->mode == ARB_fragment) {
- (yyval.result) = FRAG_RESULT_DEPTH;
- } else {
- yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 258:
-
-/* Line 1455 of yacc.c */
-#line 2056 "program_parse.y"
- {
- (yyval.result) = (yyvsp[(2) - (3)].integer) + (yyvsp[(3) - (3)].integer);
- ;}
- break;
-
- case 259:
-
-/* Line 1455 of yacc.c */
-#line 2062 "program_parse.y"
- {
- (yyval.integer) = (state->mode == ARB_vertex)
- ? VERT_RESULT_COL0
- : FRAG_RESULT_COLOR;
- ;}
- break;
-
- case 260:
-
-/* Line 1455 of yacc.c */
-#line 2068 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.integer) = VERT_RESULT_COL0;
- } else {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 261:
-
-/* Line 1455 of yacc.c */
-#line 2077 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.integer) = VERT_RESULT_BFC0;
- } else {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 262:
-
-/* Line 1455 of yacc.c */
-#line 2088 "program_parse.y"
- {
- (yyval.integer) = 0;
- ;}
- break;
-
- case 263:
-
-/* Line 1455 of yacc.c */
-#line 2092 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.integer) = 0;
- } else {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 264:
-
-/* Line 1455 of yacc.c */
-#line 2101 "program_parse.y"
- {
- if (state->mode == ARB_vertex) {
- (yyval.integer) = 1;
- } else {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
- YYERROR;
- }
- ;}
- break;
-
- case 265:
-
-/* Line 1455 of yacc.c */
-#line 2111 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 266:
-
-/* Line 1455 of yacc.c */
-#line 2112 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 267:
-
-/* Line 1455 of yacc.c */
-#line 2113 "program_parse.y"
- { (yyval.integer) = 1; ;}
- break;
-
- case 268:
-
-/* Line 1455 of yacc.c */
-#line 2116 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 269:
-
-/* Line 1455 of yacc.c */
-#line 2117 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 270:
-
-/* Line 1455 of yacc.c */
-#line 2118 "program_parse.y"
- { (yyval.integer) = 1; ;}
- break;
-
- case 271:
-
-/* Line 1455 of yacc.c */
-#line 2121 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 272:
-
-/* Line 1455 of yacc.c */
-#line 2122 "program_parse.y"
- { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;}
- break;
-
- case 273:
-
-/* Line 1455 of yacc.c */
-#line 2125 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 274:
-
-/* Line 1455 of yacc.c */
-#line 2126 "program_parse.y"
- { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;}
- break;
-
- case 275:
-
-/* Line 1455 of yacc.c */
-#line 2129 "program_parse.y"
- { (yyval.integer) = 0; ;}
- break;
-
- case 276:
-
-/* Line 1455 of yacc.c */
-#line 2130 "program_parse.y"
- { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;}
- break;
-
- case 277:
-
-/* Line 1455 of yacc.c */
-#line 2134 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureCoordUnits) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid texture coordinate unit selector");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 278:
-
-/* Line 1455 of yacc.c */
-#line 2145 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureImageUnits) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid texture image unit selector");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 279:
-
-/* Line 1455 of yacc.c */
-#line 2156 "program_parse.y"
- {
- if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureUnits) {
- yyerror(& (yylsp[(1) - (1)]), state, "invalid texture unit selector");
- YYERROR;
- }
-
- (yyval.integer) = (yyvsp[(1) - (1)].integer);
- ;}
- break;
-
- case 280:
-
-/* Line 1455 of yacc.c */
-#line 2167 "program_parse.y"
- {
- struct asm_symbol *exist = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(2) - (4)].string));
- struct asm_symbol *target = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(4) - (4)].string));
-
- free((yyvsp[(4) - (4)].string));
-
- if (exist != NULL) {
- char m[1000];
- _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", (yyvsp[(2) - (4)].string));
- free((yyvsp[(2) - (4)].string));
- yyerror(& (yylsp[(2) - (4)]), state, m);
- YYERROR;
- } else if (target == NULL) {
- free((yyvsp[(2) - (4)].string));
- yyerror(& (yylsp[(4) - (4)]), state,
- "undefined variable binding in ALIAS statement");
- YYERROR;
- } else {
- _mesa_symbol_table_add_symbol(state->st, 0, (yyvsp[(2) - (4)].string), target);
- }
- ;}
- break;
-
-
-
-/* Line 1455 of yacc.c */
-#line 4938 "program_parse.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
- *++yylsp = yyloc;
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (&yylloc, state, YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (&yylloc, state, yymsg);
- }
- else
- {
- yyerror (&yylloc, state, YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
- yyerror_range[0] = yylloc;
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse lookahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval, &yylloc, state);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse lookahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- yyerror_range[0] = yylsp[1-yylen];
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
- yyerror_range[0] = *yylsp;
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp, yylsp, state);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- *++yyvsp = yylval;
-
- yyerror_range[1] = yylloc;
- /* Using YYLLOC is tempting, but would change the location of
- the lookahead. YYLOC is available though. */
- YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
- *++yylsp = yyloc;
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#if !defined(yyoverflow) || YYERROR_VERBOSE
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (&yylloc, state, YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval, &yylloc, state);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp, yylsp, state);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
-/* Line 1675 of yacc.c */
-#line 2196 "program_parse.y"
-
-
-void
-asm_instruction_set_operands(struct asm_instruction *inst,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
-{
- /* In the core ARB extensions only the KIL instruction doesn't have a
- * destination register.
- */
- if (dst == NULL) {
- init_dst_reg(& inst->Base.DstReg);
- } else {
- inst->Base.DstReg = *dst;
- }
-
- /* The only instruction that doesn't have any source registers is the
- * condition-code based KIL instruction added by NV_fragment_program_option.
- */
- if (src0 != NULL) {
- inst->Base.SrcReg[0] = src0->Base;
- inst->SrcReg[0] = *src0;
- } else {
- init_src_reg(& inst->SrcReg[0]);
- }
-
- if (src1 != NULL) {
- inst->Base.SrcReg[1] = src1->Base;
- inst->SrcReg[1] = *src1;
- } else {
- init_src_reg(& inst->SrcReg[1]);
- }
-
- if (src2 != NULL) {
- inst->Base.SrcReg[2] = src2->Base;
- inst->SrcReg[2] = *src2;
- } else {
- init_src_reg(& inst->SrcReg[2]);
- }
-}
-
-
-struct asm_instruction *
-asm_instruction_ctor(gl_inst_opcode op,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
-{
- struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
-
- if (inst) {
- _mesa_init_instructions(& inst->Base, 1);
- inst->Base.Opcode = op;
-
- asm_instruction_set_operands(inst, dst, src0, src1, src2);
- }
-
- return inst;
-}
-
-
-struct asm_instruction *
-asm_instruction_copy_ctor(const struct prog_instruction *base,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
-{
- struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
-
- if (inst) {
- _mesa_init_instructions(& inst->Base, 1);
- inst->Base.Opcode = base->Opcode;
- inst->Base.CondUpdate = base->CondUpdate;
- inst->Base.CondDst = base->CondDst;
- inst->Base.SaturateMode = base->SaturateMode;
- inst->Base.Precision = base->Precision;
-
- asm_instruction_set_operands(inst, dst, src0, src1, src2);
- }
-
- return inst;
-}
-
-
-void
-init_dst_reg(struct prog_dst_register *r)
-{
- memset(r, 0, sizeof(*r));
- r->File = PROGRAM_UNDEFINED;
- r->WriteMask = WRITEMASK_XYZW;
- r->CondMask = COND_TR;
- r->CondSwizzle = SWIZZLE_NOOP;
-}
-
-
-/** Like init_dst_reg() but set the File and Index fields. */
-void
-set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index)
-{
- const GLint maxIndex = 1 << INST_INDEX_BITS;
- const GLint minIndex = 0;
- ASSERT(index >= minIndex);
- (void) minIndex;
- ASSERT(index <= maxIndex);
- (void) maxIndex;
- ASSERT(file == PROGRAM_TEMPORARY ||
- file == PROGRAM_ADDRESS ||
- file == PROGRAM_OUTPUT);
- memset(r, 0, sizeof(*r));
- r->File = file;
- r->Index = index;
- r->WriteMask = WRITEMASK_XYZW;
- r->CondMask = COND_TR;
- r->CondSwizzle = SWIZZLE_NOOP;
-}
-
-
-void
-init_src_reg(struct asm_src_register *r)
-{
- memset(r, 0, sizeof(*r));
- r->Base.File = PROGRAM_UNDEFINED;
- r->Base.Swizzle = SWIZZLE_NOOP;
- r->Symbol = NULL;
-}
-
-
-/** Like init_src_reg() but set the File and Index fields.
- * \return GL_TRUE if a valid src register, GL_FALSE otherwise
- */
-void
-set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index)
-{
- set_src_reg_swz(r, file, index, SWIZZLE_XYZW);
-}
-
-
-void
-set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index,
- GLuint swizzle)
-{
- const GLint maxIndex = (1 << INST_INDEX_BITS) - 1;
- const GLint minIndex = -(1 << INST_INDEX_BITS);
- ASSERT(file < PROGRAM_FILE_MAX);
- ASSERT(index >= minIndex);
- (void) minIndex;
- ASSERT(index <= maxIndex);
- (void) maxIndex;
- memset(r, 0, sizeof(*r));
- r->Base.File = file;
- r->Base.Index = index;
- r->Base.Swizzle = swizzle;
- r->Symbol = NULL;
-}
-
-
-/**
- * Validate the set of inputs used by a program
- *
- * Validates that legal sets of inputs are used by the program. In this case
- * "used" included both reading the input or binding the input to a name using
- * the \c ATTRIB command.
- *
- * \return
- * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise.
- */
-int
-validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state)
-{
- const int inputs = state->prog->InputsRead | state->InputsBound;
-
- if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) {
- yyerror(locp, state, "illegal use of generic attribute and name attribute");
- return 0;
- }
-
- return 1;
-}
-
-
-struct asm_symbol *
-declare_variable(struct asm_parser_state *state, char *name, enum asm_type t,
- struct YYLTYPE *locp)
-{
- struct asm_symbol *s = NULL;
- struct asm_symbol *exist = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, name);
-
-
- if (exist != NULL) {
- yyerror(locp, state, "redeclared identifier");
- } else {
- s = calloc(1, sizeof(struct asm_symbol));
- s->name = name;
- s->type = t;
-
- switch (t) {
- case at_temp:
- if (state->prog->NumTemporaries >= state->limits->MaxTemps) {
- yyerror(locp, state, "too many temporaries declared");
- free(s);
- return NULL;
- }
-
- s->temp_binding = state->prog->NumTemporaries;
- state->prog->NumTemporaries++;
- break;
-
- case at_address:
- if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) {
- yyerror(locp, state, "too many address registers declared");
- free(s);
- return NULL;
- }
-
- /* FINISHME: Add support for multiple address registers.
- */
- state->prog->NumAddressRegs++;
- break;
-
- default:
- break;
- }
-
- _mesa_symbol_table_add_symbol(state->st, 0, s->name, s);
- s->next = state->sym;
- state->sym = s;
- }
-
- return s;
-}
-
-
-int add_state_reference(struct gl_program_parameter_list *param_list,
- const gl_state_index tokens[STATE_LENGTH])
-{
- const GLuint size = 4; /* XXX fix */
- char *name;
- GLint index;
-
- name = _mesa_program_state_string(tokens);
- index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name,
- size, GL_NONE, NULL, tokens, 0x0);
- param_list->StateFlags |= _mesa_program_state_flags(tokens);
-
- /* free name string here since we duplicated it in add_parameter() */
- free(name);
-
- return index;
-}
-
-
-int
-initialize_symbol_from_state(struct gl_program *prog,
- struct asm_symbol *param_var,
- const gl_state_index tokens[STATE_LENGTH])
-{
- int idx = -1;
- gl_state_index state_tokens[STATE_LENGTH];
-
-
- memcpy(state_tokens, tokens, sizeof(state_tokens));
-
- param_var->type = at_param;
- param_var->param_binding_type = PROGRAM_STATE_VAR;
-
- /* If we are adding a STATE_MATRIX that has multiple rows, we need to
- * unroll it and call add_state_reference() for each row
- */
- if ((state_tokens[0] == STATE_MODELVIEW_MATRIX ||
- state_tokens[0] == STATE_PROJECTION_MATRIX ||
- state_tokens[0] == STATE_MVP_MATRIX ||
- state_tokens[0] == STATE_TEXTURE_MATRIX ||
- state_tokens[0] == STATE_PROGRAM_MATRIX)
- && (state_tokens[2] != state_tokens[3])) {
- int row;
- const int first_row = state_tokens[2];
- const int last_row = state_tokens[3];
-
- for (row = first_row; row <= last_row; row++) {
- state_tokens[2] = state_tokens[3] = row;
-
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
-
- param_var->param_binding_length++;
- }
- }
- else {
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
- }
-
- return idx;
-}
-
-
-int
-initialize_symbol_from_param(struct gl_program *prog,
- struct asm_symbol *param_var,
- const gl_state_index tokens[STATE_LENGTH])
-{
- int idx = -1;
- gl_state_index state_tokens[STATE_LENGTH];
-
-
- memcpy(state_tokens, tokens, sizeof(state_tokens));
-
- assert((state_tokens[0] == STATE_VERTEX_PROGRAM)
- || (state_tokens[0] == STATE_FRAGMENT_PROGRAM));
- assert((state_tokens[1] == STATE_ENV)
- || (state_tokens[1] == STATE_LOCAL));
-
- /*
- * The param type is STATE_VAR. The program parameter entry will
- * effectively be a pointer into the LOCAL or ENV parameter array.
- */
- param_var->type = at_param;
- param_var->param_binding_type = PROGRAM_STATE_VAR;
-
- /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements,
- * we need to unroll it and call add_state_reference() for each row
- */
- if (state_tokens[2] != state_tokens[3]) {
- int row;
- const int first_row = state_tokens[2];
- const int last_row = state_tokens[3];
-
- for (row = first_row; row <= last_row; row++) {
- state_tokens[2] = state_tokens[3] = row;
-
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
- }
- }
- else {
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
- }
-
- return idx;
-}
-
-
-/**
- * Put a float/vector constant/literal into the parameter list.
- * \param param_var returns info about the parameter/constant's location,
- * binding, type, etc.
- * \param vec the vector/constant to add
- * \param allowSwizzle if true, try to consolidate constants which only differ
- * by a swizzle. We don't want to do this when building
- * arrays of constants that may be indexed indirectly.
- * \return index of the constant in the parameter list.
- */
-int
-initialize_symbol_from_const(struct gl_program *prog,
- struct asm_symbol *param_var,
- const struct asm_vector *vec,
- GLboolean allowSwizzle)
-{
- unsigned swizzle;
- const int idx = _mesa_add_unnamed_constant(prog->Parameters,
- vec->data, vec->count,
- allowSwizzle ? &swizzle : NULL);
-
- param_var->type = at_param;
- param_var->param_binding_type = PROGRAM_CONSTANT;
-
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
-
- return idx;
-}
-
-
-char *
-make_error_string(const char *fmt, ...)
-{
- int length;
- char *str;
- va_list args;
-
-
- /* Call vsnprintf once to determine how large the final string is. Call it
- * again to do the actual formatting. from the vsnprintf manual page:
- *
- * Upon successful return, these functions return the number of
- * characters printed (not including the trailing '\0' used to end
- * output to strings).
- */
- va_start(args, fmt);
- length = 1 + vsnprintf(NULL, 0, fmt, args);
- va_end(args);
-
- str = malloc(length);
- if (str) {
- va_start(args, fmt);
- vsnprintf(str, length, fmt, args);
- va_end(args);
- }
-
- return str;
-}
-
-
-void
-yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s)
-{
- char *err_str;
-
-
- err_str = make_error_string("glProgramStringARB(%s)\n", s);
- if (err_str) {
- _mesa_error(state->ctx, GL_INVALID_OPERATION, "%s", err_str);
- free(err_str);
- }
-
- err_str = make_error_string("line %u, char %u: error: %s\n",
- locp->first_line, locp->first_column, s);
- _mesa_set_program_error(state->ctx, locp->position, err_str);
-
- if (err_str) {
- free(err_str);
- }
-}
-
-
-GLboolean
-_mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str,
- GLsizei len, struct asm_parser_state *state)
-{
- struct asm_instruction *inst;
- unsigned i;
- GLubyte *strz;
- GLboolean result = GL_FALSE;
- void *temp;
- struct asm_symbol *sym;
-
- state->ctx = ctx;
- state->prog->Target = target;
- state->prog->Parameters = _mesa_new_parameter_list();
-
- /* Make a copy of the program string and force it to be NUL-terminated.
- */
- strz = (GLubyte *) malloc(len + 1);
- if (strz == NULL) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB");
- return GL_FALSE;
- }
- memcpy (strz, str, len);
- strz[len] = '\0';
-
- state->prog->String = strz;
-
- state->st = _mesa_symbol_table_ctor();
-
- state->limits = (target == GL_VERTEX_PROGRAM_ARB)
- ? & ctx->Const.VertexProgram
- : & ctx->Const.FragmentProgram;
-
- state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
- state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits;
- state->MaxTextureUnits = ctx->Const.MaxTextureUnits;
- state->MaxClipPlanes = ctx->Const.MaxClipPlanes;
- state->MaxLights = ctx->Const.MaxLights;
- state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices;
-
- state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB)
- ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM;
-
- _mesa_set_program_error(ctx, -1, NULL);
-
- _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len);
- yyparse(state);
- _mesa_program_lexer_dtor(state->scanner);
-
-
- if (ctx->Program.ErrorPos != -1) {
- goto error;
- }
-
- if (! _mesa_layout_parameters(state)) {
- struct YYLTYPE loc;
-
- loc.first_line = 0;
- loc.first_column = 0;
- loc.position = len;
-
- yyerror(& loc, state, "invalid PARAM usage");
- goto error;
- }
-
-
-
- /* Add one instruction to store the "END" instruction.
- */
- state->prog->Instructions =
- _mesa_alloc_instructions(state->prog->NumInstructions + 1);
- inst = state->inst_head;
- for (i = 0; i < state->prog->NumInstructions; i++) {
- struct asm_instruction *const temp = inst->next;
-
- state->prog->Instructions[i] = inst->Base;
- inst = temp;
- }
-
- /* Finally, tag on an OPCODE_END instruction */
- {
- const GLuint numInst = state->prog->NumInstructions;
- _mesa_init_instructions(state->prog->Instructions + numInst, 1);
- state->prog->Instructions[numInst].Opcode = OPCODE_END;
- }
- state->prog->NumInstructions++;
-
- state->prog->NumParameters = state->prog->Parameters->NumParameters;
- state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead);
-
- /*
- * Initialize native counts to logical counts. The device driver may
- * change them if program is translated into a hardware program.
- */
- state->prog->NumNativeInstructions = state->prog->NumInstructions;
- state->prog->NumNativeTemporaries = state->prog->NumTemporaries;
- state->prog->NumNativeParameters = state->prog->NumParameters;
- state->prog->NumNativeAttributes = state->prog->NumAttributes;
- state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs;
-
- result = GL_TRUE;
-
-error:
- for (inst = state->inst_head; inst != NULL; inst = temp) {
- temp = inst->next;
- free(inst);
- }
-
- state->inst_head = NULL;
- state->inst_tail = NULL;
-
- for (sym = state->sym; sym != NULL; sym = temp) {
- temp = sym->next;
-
- free((void *) sym->name);
- free(sym);
- }
- state->sym = NULL;
-
- _mesa_symbol_table_dtor(state->st);
- state->st = NULL;
-
- return result;
-}
-
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 1
+
+
+
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 1 "program_parse.y"
+
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "main/mtypes.h"
+#include "main/imports.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
+#include "program/prog_parameter_layout.h"
+#include "program/prog_statevars.h"
+#include "program/prog_instruction.h"
+
+#include "program/symbol_table.h"
+#include "program/program_parser.h"
+
+extern void *yy_scan_string(char *);
+extern void yy_delete_buffer(void *);
+
+static struct asm_symbol *declare_variable(struct asm_parser_state *state,
+ char *name, enum asm_type t, struct YYLTYPE *locp);
+
+static int add_state_reference(struct gl_program_parameter_list *param_list,
+ const gl_state_index tokens[STATE_LENGTH]);
+
+static int initialize_symbol_from_state(struct gl_program *prog,
+ struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
+
+static int initialize_symbol_from_param(struct gl_program *prog,
+ struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
+
+static int initialize_symbol_from_const(struct gl_program *prog,
+ struct asm_symbol *param_var, const struct asm_vector *vec,
+ GLboolean allowSwizzle);
+
+static int yyparse(struct asm_parser_state *state);
+
+static char *make_error_string(const char *fmt, ...);
+
+static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state,
+ const char *s);
+
+static int validate_inputs(struct YYLTYPE *locp,
+ struct asm_parser_state *state);
+
+static void init_dst_reg(struct prog_dst_register *r);
+
+static void set_dst_reg(struct prog_dst_register *r,
+ gl_register_file file, GLint index);
+
+static void init_src_reg(struct asm_src_register *r);
+
+static void set_src_reg(struct asm_src_register *r,
+ gl_register_file file, GLint index);
+
+static void set_src_reg_swz(struct asm_src_register *r,
+ gl_register_file file, GLint index, GLuint swizzle);
+
+static void asm_instruction_set_operands(struct asm_instruction *inst,
+ const struct prog_dst_register *dst, const struct asm_src_register *src0,
+ const struct asm_src_register *src1, const struct asm_src_register *src2);
+
+static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
+ const struct prog_dst_register *dst, const struct asm_src_register *src0,
+ const struct asm_src_register *src1, const struct asm_src_register *src2);
+
+static struct asm_instruction *asm_instruction_copy_ctor(
+ const struct prog_instruction *base, const struct prog_dst_register *dst,
+ const struct asm_src_register *src0, const struct asm_src_register *src1,
+ const struct asm_src_register *src2);
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE (!FALSE)
+#endif
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (YYID(N)) { \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
+ (Current).position = YYRHSLOC(Rhs, 1).position; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC(Rhs, N).last_column; \
+ } else { \
+ (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
+ (Current).last_line = (Current).first_line; \
+ (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \
+ (Current).last_column = (Current).first_column; \
+ (Current).position = YYRHSLOC(Rhs, 0).position \
+ + (Current).first_column; \
+ } \
+ } while(YYID(0))
+
+#define YYLEX_PARAM state->scanner
+
+
+/* Line 189 of yacc.c */
+#line 193 "program_parse.tab.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ARBvp_10 = 258,
+ ARBfp_10 = 259,
+ ADDRESS = 260,
+ ALIAS = 261,
+ ATTRIB = 262,
+ OPTION = 263,
+ OUTPUT = 264,
+ PARAM = 265,
+ TEMP = 266,
+ END = 267,
+ BIN_OP = 268,
+ BINSC_OP = 269,
+ SAMPLE_OP = 270,
+ SCALAR_OP = 271,
+ TRI_OP = 272,
+ VECTOR_OP = 273,
+ ARL = 274,
+ KIL = 275,
+ SWZ = 276,
+ TXD_OP = 277,
+ INTEGER = 278,
+ REAL = 279,
+ AMBIENT = 280,
+ ATTENUATION = 281,
+ BACK = 282,
+ CLIP = 283,
+ COLOR = 284,
+ DEPTH = 285,
+ DIFFUSE = 286,
+ DIRECTION = 287,
+ EMISSION = 288,
+ ENV = 289,
+ EYE = 290,
+ FOG = 291,
+ FOGCOORD = 292,
+ FRAGMENT = 293,
+ FRONT = 294,
+ HALF = 295,
+ INVERSE = 296,
+ INVTRANS = 297,
+ LIGHT = 298,
+ LIGHTMODEL = 299,
+ LIGHTPROD = 300,
+ LOCAL = 301,
+ MATERIAL = 302,
+ MAT_PROGRAM = 303,
+ MATRIX = 304,
+ MATRIXINDEX = 305,
+ MODELVIEW = 306,
+ MVP = 307,
+ NORMAL = 308,
+ OBJECT = 309,
+ PALETTE = 310,
+ PARAMS = 311,
+ PLANE = 312,
+ POINT_TOK = 313,
+ POINTSIZE = 314,
+ POSITION = 315,
+ PRIMARY = 316,
+ PROGRAM = 317,
+ PROJECTION = 318,
+ RANGE = 319,
+ RESULT = 320,
+ ROW = 321,
+ SCENECOLOR = 322,
+ SECONDARY = 323,
+ SHININESS = 324,
+ SIZE_TOK = 325,
+ SPECULAR = 326,
+ SPOT = 327,
+ STATE = 328,
+ TEXCOORD = 329,
+ TEXENV = 330,
+ TEXGEN = 331,
+ TEXGEN_Q = 332,
+ TEXGEN_R = 333,
+ TEXGEN_S = 334,
+ TEXGEN_T = 335,
+ TEXTURE = 336,
+ TRANSPOSE = 337,
+ TEXTURE_UNIT = 338,
+ TEX_1D = 339,
+ TEX_2D = 340,
+ TEX_3D = 341,
+ TEX_CUBE = 342,
+ TEX_RECT = 343,
+ TEX_SHADOW1D = 344,
+ TEX_SHADOW2D = 345,
+ TEX_SHADOWRECT = 346,
+ TEX_ARRAY1D = 347,
+ TEX_ARRAY2D = 348,
+ TEX_ARRAYSHADOW1D = 349,
+ TEX_ARRAYSHADOW2D = 350,
+ VERTEX = 351,
+ VTXATTRIB = 352,
+ WEIGHT = 353,
+ IDENTIFIER = 354,
+ USED_IDENTIFIER = 355,
+ MASK4 = 356,
+ MASK3 = 357,
+ MASK2 = 358,
+ MASK1 = 359,
+ SWIZZLE = 360,
+ DOT_DOT = 361,
+ DOT = 362
+ };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c */
+#line 126 "program_parse.y"
+
+ struct asm_instruction *inst;
+ struct asm_symbol *sym;
+ struct asm_symbol temp_sym;
+ struct asm_swizzle_mask swiz_mask;
+ struct asm_src_register src_reg;
+ struct prog_dst_register dst_reg;
+ struct prog_instruction temp_inst;
+ char *string;
+ unsigned result;
+ unsigned attrib;
+ int integer;
+ float real;
+ gl_state_index state[STATE_LENGTH];
+ int negate;
+ struct asm_vector vector;
+ gl_inst_opcode opcode;
+
+ struct {
+ unsigned swz;
+ unsigned rgba_valid:1;
+ unsigned xyzw_valid:1;
+ unsigned negate:1;
+ } ext_swizzle;
+
+
+
+/* Line 214 of yacc.c */
+#line 364 "program_parse.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+/* Line 264 of yacc.c */
+#line 271 "program_parse.y"
+
+extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param,
+ void *yyscanner);
+
+
+/* Line 264 of yacc.c */
+#line 395 "program_parse.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+ YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 5
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 396
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 120
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 143
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 282
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 475
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 362
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 115, 116, 2, 113, 109, 114, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 108,
+ 2, 117, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 111, 2, 112, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 118, 110, 119, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 8, 10, 12, 15, 16, 20, 23,
+ 24, 27, 30, 32, 34, 36, 38, 40, 42, 44,
+ 46, 48, 50, 52, 54, 59, 64, 69, 76, 83,
+ 92, 101, 104, 107, 120, 123, 125, 127, 129, 131,
+ 133, 135, 137, 139, 141, 143, 145, 147, 154, 157,
+ 162, 165, 167, 171, 177, 181, 184, 192, 195, 197,
+ 199, 201, 203, 208, 210, 212, 214, 216, 218, 220,
+ 222, 226, 227, 230, 233, 235, 237, 239, 241, 243,
+ 245, 247, 249, 251, 252, 254, 256, 258, 260, 261,
+ 265, 269, 270, 273, 276, 278, 280, 282, 284, 286,
+ 288, 290, 292, 297, 300, 303, 305, 308, 310, 313,
+ 315, 318, 323, 328, 330, 331, 335, 337, 339, 342,
+ 344, 347, 349, 351, 355, 362, 363, 365, 368, 373,
+ 375, 379, 381, 383, 385, 387, 389, 391, 393, 395,
+ 397, 399, 402, 405, 408, 411, 414, 417, 420, 423,
+ 426, 429, 432, 435, 439, 441, 443, 445, 451, 453,
+ 455, 457, 460, 462, 464, 467, 469, 472, 479, 481,
+ 485, 487, 489, 491, 493, 495, 500, 502, 504, 506,
+ 508, 510, 512, 515, 517, 519, 525, 527, 530, 532,
+ 534, 540, 543, 544, 551, 555, 556, 558, 560, 562,
+ 564, 566, 569, 571, 573, 576, 581, 586, 587, 591,
+ 593, 595, 597, 600, 602, 604, 606, 608, 614, 616,
+ 620, 626, 632, 634, 638, 644, 646, 648, 650, 652,
+ 654, 656, 658, 660, 662, 666, 672, 680, 690, 693,
+ 696, 698, 700, 701, 702, 707, 709, 710, 711, 715,
+ 719, 721, 727, 730, 733, 736, 739, 743, 746, 750,
+ 751, 753, 755, 756, 758, 760, 761, 763, 765, 766,
+ 768, 770, 771, 775, 776, 780, 781, 785, 787, 789,
+ 791, 796, 798
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 121, 0, -1, 122, 123, 125, 12, -1, 3, -1,
+ 4, -1, 123, 124, -1, -1, 8, 262, 108, -1,
+ 125, 126, -1, -1, 127, 108, -1, 170, 108, -1,
+ 128, -1, 129, -1, 130, -1, 131, -1, 132, -1,
+ 133, -1, 134, -1, 135, -1, 141, -1, 136, -1,
+ 137, -1, 138, -1, 19, 146, 109, 142, -1, 18,
+ 145, 109, 144, -1, 16, 145, 109, 142, -1, 14,
+ 145, 109, 142, 109, 142, -1, 13, 145, 109, 144,
+ 109, 144, -1, 17, 145, 109, 144, 109, 144, 109,
+ 144, -1, 15, 145, 109, 144, 109, 139, 109, 140,
+ -1, 20, 144, -1, 20, 166, -1, 22, 145, 109,
+ 144, 109, 144, 109, 144, 109, 139, 109, 140, -1,
+ 83, 256, -1, 84, -1, 85, -1, 86, -1, 87,
+ -1, 88, -1, 89, -1, 90, -1, 91, -1, 92,
+ -1, 93, -1, 94, -1, 95, -1, 21, 145, 109,
+ 150, 109, 147, -1, 241, 143, -1, 241, 110, 143,
+ 110, -1, 150, 162, -1, 238, -1, 241, 150, 163,
+ -1, 241, 110, 150, 163, 110, -1, 151, 164, 165,
+ -1, 159, 161, -1, 148, 109, 148, 109, 148, 109,
+ 148, -1, 241, 149, -1, 23, -1, 262, -1, 100,
+ -1, 172, -1, 152, 111, 153, 112, -1, 186, -1,
+ 249, -1, 100, -1, 100, -1, 154, -1, 155, -1,
+ 23, -1, 159, 160, 156, -1, -1, 113, 157, -1,
+ 114, 158, -1, 23, -1, 23, -1, 100, -1, 104,
+ -1, 104, -1, 104, -1, 104, -1, 101, -1, 105,
+ -1, -1, 101, -1, 102, -1, 103, -1, 104, -1,
+ -1, 115, 166, 116, -1, 115, 167, 116, -1, -1,
+ 168, 163, -1, 169, 163, -1, 99, -1, 100, -1,
+ 171, -1, 178, -1, 242, -1, 245, -1, 248, -1,
+ 261, -1, 7, 99, 117, 172, -1, 96, 173, -1,
+ 38, 177, -1, 60, -1, 98, 175, -1, 53, -1,
+ 29, 254, -1, 37, -1, 74, 255, -1, 50, 111,
+ 176, 112, -1, 97, 111, 174, 112, -1, 23, -1,
+ -1, 111, 176, 112, -1, 23, -1, 60, -1, 29,
+ 254, -1, 37, -1, 74, 255, -1, 179, -1, 180,
+ -1, 10, 99, 182, -1, 10, 99, 111, 181, 112,
+ 183, -1, -1, 23, -1, 117, 185, -1, 117, 118,
+ 184, 119, -1, 187, -1, 184, 109, 187, -1, 189,
+ -1, 225, -1, 235, -1, 189, -1, 225, -1, 236,
+ -1, 188, -1, 226, -1, 235, -1, 189, -1, 73,
+ 213, -1, 73, 190, -1, 73, 192, -1, 73, 195,
+ -1, 73, 197, -1, 73, 203, -1, 73, 199, -1,
+ 73, 206, -1, 73, 208, -1, 73, 210, -1, 73,
+ 212, -1, 73, 224, -1, 47, 253, 191, -1, 201,
+ -1, 33, -1, 69, -1, 43, 111, 202, 112, 193,
+ -1, 201, -1, 60, -1, 26, -1, 72, 194, -1,
+ 40, -1, 32, -1, 44, 196, -1, 25, -1, 253,
+ 67, -1, 45, 111, 202, 112, 253, 198, -1, 201,
+ -1, 75, 257, 200, -1, 29, -1, 25, -1, 31,
+ -1, 71, -1, 23, -1, 76, 255, 204, 205, -1,
+ 35, -1, 54, -1, 79, -1, 80, -1, 78, -1,
+ 77, -1, 36, 207, -1, 29, -1, 56, -1, 28,
+ 111, 209, 112, 57, -1, 23, -1, 58, 211, -1,
+ 70, -1, 26, -1, 215, 66, 111, 218, 112, -1,
+ 215, 214, -1, -1, 66, 111, 218, 106, 218, 112,
+ -1, 49, 219, 216, -1, -1, 217, -1, 41, -1,
+ 82, -1, 42, -1, 23, -1, 51, 220, -1, 63,
+ -1, 52, -1, 81, 255, -1, 55, 111, 222, 112,
+ -1, 48, 111, 223, 112, -1, -1, 111, 221, 112,
+ -1, 23, -1, 23, -1, 23, -1, 30, 64, -1,
+ 229, -1, 232, -1, 227, -1, 230, -1, 62, 34,
+ 111, 228, 112, -1, 233, -1, 233, 106, 233, -1,
+ 62, 34, 111, 233, 112, -1, 62, 46, 111, 231,
+ 112, -1, 234, -1, 234, 106, 234, -1, 62, 46,
+ 111, 234, 112, -1, 23, -1, 23, -1, 237, -1,
+ 239, -1, 238, -1, 239, -1, 240, -1, 24, -1,
+ 23, -1, 118, 240, 119, -1, 118, 240, 109, 240,
+ 119, -1, 118, 240, 109, 240, 109, 240, 119, -1,
+ 118, 240, 109, 240, 109, 240, 109, 240, 119, -1,
+ 241, 24, -1, 241, 23, -1, 113, -1, 114, -1,
+ -1, -1, 244, 11, 243, 247, -1, 262, -1, -1,
+ -1, 5, 246, 247, -1, 247, 109, 99, -1, 99,
+ -1, 244, 9, 99, 117, 249, -1, 65, 60, -1,
+ 65, 37, -1, 65, 250, -1, 65, 59, -1, 65,
+ 74, 255, -1, 65, 30, -1, 29, 251, 252, -1,
+ -1, 39, -1, 27, -1, -1, 61, -1, 68, -1,
+ -1, 39, -1, 27, -1, -1, 61, -1, 68, -1,
+ -1, 111, 258, 112, -1, -1, 111, 259, 112, -1,
+ -1, 111, 260, 112, -1, 23, -1, 23, -1, 23,
+ -1, 6, 99, 117, 100, -1, 99, -1, 100, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 278, 278, 281, 289, 301, 302, 305, 329, 330,
+ 333, 348, 351, 356, 363, 364, 365, 366, 367, 368,
+ 369, 372, 373, 374, 377, 383, 389, 395, 402, 408,
+ 415, 459, 464, 474, 518, 524, 525, 526, 527, 528,
+ 529, 530, 531, 532, 533, 534, 535, 538, 550, 558,
+ 575, 582, 601, 612, 632, 657, 664, 697, 704, 719,
+ 774, 817, 826, 848, 858, 862, 891, 910, 910, 912,
+ 919, 931, 932, 933, 936, 950, 964, 984, 995, 1007,
+ 1009, 1010, 1011, 1012, 1015, 1015, 1015, 1015, 1016, 1019,
+ 1023, 1028, 1035, 1042, 1049, 1072, 1095, 1096, 1097, 1098,
+ 1099, 1100, 1103, 1122, 1126, 1132, 1136, 1140, 1144, 1153,
+ 1162, 1166, 1171, 1177, 1188, 1188, 1189, 1191, 1195, 1199,
+ 1203, 1209, 1209, 1211, 1229, 1255, 1258, 1269, 1275, 1281,
+ 1282, 1289, 1295, 1301, 1309, 1315, 1321, 1329, 1335, 1341,
+ 1349, 1350, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360,
+ 1361, 1362, 1363, 1366, 1375, 1379, 1383, 1389, 1398, 1402,
+ 1406, 1415, 1419, 1425, 1431, 1438, 1443, 1451, 1461, 1463,
+ 1471, 1477, 1481, 1485, 1491, 1502, 1511, 1515, 1520, 1524,
+ 1528, 1532, 1538, 1545, 1549, 1555, 1563, 1574, 1581, 1585,
+ 1591, 1601, 1612, 1616, 1634, 1643, 1646, 1652, 1656, 1660,
+ 1666, 1677, 1682, 1687, 1692, 1697, 1702, 1710, 1713, 1718,
+ 1731, 1739, 1750, 1758, 1758, 1760, 1760, 1762, 1772, 1777,
+ 1784, 1794, 1803, 1808, 1815, 1825, 1835, 1847, 1847, 1848,
+ 1848, 1850, 1860, 1868, 1878, 1886, 1894, 1903, 1914, 1918,
+ 1924, 1925, 1926, 1929, 1929, 1932, 1967, 1971, 1971, 1974,
+ 1981, 1990, 2004, 2013, 2022, 2026, 2035, 2044, 2055, 2062,
+ 2067, 2076, 2088, 2091, 2100, 2111, 2112, 2113, 2116, 2117,
+ 2118, 2121, 2122, 2125, 2126, 2129, 2130, 2133, 2144, 2155,
+ 2166, 2192, 2193
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "ARBvp_10", "ARBfp_10", "ADDRESS",
+ "ALIAS", "ATTRIB", "OPTION", "OUTPUT", "PARAM", "TEMP", "END", "BIN_OP",
+ "BINSC_OP", "SAMPLE_OP", "SCALAR_OP", "TRI_OP", "VECTOR_OP", "ARL",
+ "KIL", "SWZ", "TXD_OP", "INTEGER", "REAL", "AMBIENT", "ATTENUATION",
+ "BACK", "CLIP", "COLOR", "DEPTH", "DIFFUSE", "DIRECTION", "EMISSION",
+ "ENV", "EYE", "FOG", "FOGCOORD", "FRAGMENT", "FRONT", "HALF", "INVERSE",
+ "INVTRANS", "LIGHT", "LIGHTMODEL", "LIGHTPROD", "LOCAL", "MATERIAL",
+ "MAT_PROGRAM", "MATRIX", "MATRIXINDEX", "MODELVIEW", "MVP", "NORMAL",
+ "OBJECT", "PALETTE", "PARAMS", "PLANE", "POINT_TOK", "POINTSIZE",
+ "POSITION", "PRIMARY", "PROGRAM", "PROJECTION", "RANGE", "RESULT", "ROW",
+ "SCENECOLOR", "SECONDARY", "SHININESS", "SIZE_TOK", "SPECULAR", "SPOT",
+ "STATE", "TEXCOORD", "TEXENV", "TEXGEN", "TEXGEN_Q", "TEXGEN_R",
+ "TEXGEN_S", "TEXGEN_T", "TEXTURE", "TRANSPOSE", "TEXTURE_UNIT", "TEX_1D",
+ "TEX_2D", "TEX_3D", "TEX_CUBE", "TEX_RECT", "TEX_SHADOW1D",
+ "TEX_SHADOW2D", "TEX_SHADOWRECT", "TEX_ARRAY1D", "TEX_ARRAY2D",
+ "TEX_ARRAYSHADOW1D", "TEX_ARRAYSHADOW2D", "VERTEX", "VTXATTRIB",
+ "WEIGHT", "IDENTIFIER", "USED_IDENTIFIER", "MASK4", "MASK3", "MASK2",
+ "MASK1", "SWIZZLE", "DOT_DOT", "DOT", "';'", "','", "'|'", "'['", "']'",
+ "'+'", "'-'", "'('", "')'", "'='", "'{'", "'}'", "$accept", "program",
+ "language", "optionSequence", "option", "statementSequence", "statement",
+ "instruction", "ALU_instruction", "TexInstruction", "ARL_instruction",
+ "VECTORop_instruction", "SCALARop_instruction", "BINSCop_instruction",
+ "BINop_instruction", "TRIop_instruction", "SAMPLE_instruction",
+ "KIL_instruction", "TXD_instruction", "texImageUnit", "texTarget",
+ "SWZ_instruction", "scalarSrcReg", "scalarUse", "swizzleSrcReg",
+ "maskedDstReg", "maskedAddrReg", "extendedSwizzle", "extSwizComp",
+ "extSwizSel", "srcReg", "dstReg", "progParamArray", "progParamArrayMem",
+ "progParamArrayAbs", "progParamArrayRel", "addrRegRelOffset",
+ "addrRegPosOffset", "addrRegNegOffset", "addrReg", "addrComponent",
+ "addrWriteMask", "scalarSuffix", "swizzleSuffix", "optionalMask",
+ "optionalCcMask", "ccTest", "ccTest2", "ccMaskRule", "ccMaskRule2",
+ "namingStatement", "ATTRIB_statement", "attribBinding", "vtxAttribItem",
+ "vtxAttribNum", "vtxOptWeightNum", "vtxWeightNum", "fragAttribItem",
+ "PARAM_statement", "PARAM_singleStmt", "PARAM_multipleStmt",
+ "optArraySize", "paramSingleInit", "paramMultipleInit",
+ "paramMultInitList", "paramSingleItemDecl", "paramSingleItemUse",
+ "paramMultipleItem", "stateMultipleItem", "stateSingleItem",
+ "stateMaterialItem", "stateMatProperty", "stateLightItem",
+ "stateLightProperty", "stateSpotProperty", "stateLightModelItem",
+ "stateLModProperty", "stateLightProdItem", "stateLProdProperty",
+ "stateTexEnvItem", "stateTexEnvProperty", "ambDiffSpecProperty",
+ "stateLightNumber", "stateTexGenItem", "stateTexGenType",
+ "stateTexGenCoord", "stateFogItem", "stateFogProperty",
+ "stateClipPlaneItem", "stateClipPlaneNum", "statePointItem",
+ "statePointProperty", "stateMatrixRow", "stateMatrixRows",
+ "optMatrixRows", "stateMatrixItem", "stateOptMatModifier",
+ "stateMatModifier", "stateMatrixRowNum", "stateMatrixName",
+ "stateOptModMatNum", "stateModMatNum", "statePaletteMatNum",
+ "stateProgramMatNum", "stateDepthItem", "programSingleItem",
+ "programMultipleItem", "progEnvParams", "progEnvParamNums",
+ "progEnvParam", "progLocalParams", "progLocalParamNums",
+ "progLocalParam", "progEnvParamNum", "progLocalParamNum",
+ "paramConstDecl", "paramConstUse", "paramConstScalarDecl",
+ "paramConstScalarUse", "paramConstVector", "signedFloatConstant",
+ "optionalSign", "TEMP_statement", "@1", "optVarSize",
+ "ADDRESS_statement", "@2", "varNameList", "OUTPUT_statement",
+ "resultBinding", "resultColBinding", "optResultFaceType",
+ "optResultColorType", "optFaceType", "optColorType",
+ "optTexCoordUnitNum", "optTexImageUnitNum", "optLegacyTexUnitNum",
+ "texCoordUnitNum", "texImageUnitNum", "legacyTexUnitNum",
+ "ALIAS_statement", "string", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362, 59, 44,
+ 124, 91, 93, 43, 45, 40, 41, 61, 123, 125
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint16 yyr1[] =
+{
+ 0, 120, 121, 122, 122, 123, 123, 124, 125, 125,
+ 126, 126, 127, 127, 128, 128, 128, 128, 128, 128,
+ 128, 129, 129, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 137, 138, 139, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 141, 142, 142,
+ 143, 143, 144, 144, 145, 146, 147, 148, 149, 149,
+ 150, 150, 150, 150, 151, 151, 152, 153, 153, 154,
+ 155, 156, 156, 156, 157, 158, 159, 160, 161, 162,
+ 163, 163, 163, 163, 164, 164, 164, 164, 164, 165,
+ 165, 165, 166, 167, 168, 169, 170, 170, 170, 170,
+ 170, 170, 171, 172, 172, 173, 173, 173, 173, 173,
+ 173, 173, 173, 174, 175, 175, 176, 177, 177, 177,
+ 177, 178, 178, 179, 180, 181, 181, 182, 183, 184,
+ 184, 185, 185, 185, 186, 186, 186, 187, 187, 187,
+ 188, 188, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 190, 191, 191, 191, 192, 193, 193,
+ 193, 193, 193, 194, 195, 196, 196, 197, 198, 199,
+ 200, 201, 201, 201, 202, 203, 204, 204, 205, 205,
+ 205, 205, 206, 207, 207, 208, 209, 210, 211, 211,
+ 212, 213, 214, 214, 215, 216, 216, 217, 217, 217,
+ 218, 219, 219, 219, 219, 219, 219, 220, 220, 221,
+ 222, 223, 224, 225, 225, 226, 226, 227, 228, 228,
+ 229, 230, 231, 231, 232, 233, 234, 235, 235, 236,
+ 236, 237, 238, 238, 239, 239, 239, 239, 240, 240,
+ 241, 241, 241, 243, 242, 244, 244, 246, 245, 247,
+ 247, 248, 249, 249, 249, 249, 249, 249, 250, 251,
+ 251, 251, 252, 252, 252, 253, 253, 253, 254, 254,
+ 254, 255, 255, 256, 256, 257, 257, 258, 259, 260,
+ 261, 262, 262
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 4, 1, 1, 2, 0, 3, 2, 0,
+ 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 4, 4, 4, 6, 6, 8,
+ 8, 2, 2, 12, 2, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 6, 2, 4,
+ 2, 1, 3, 5, 3, 2, 7, 2, 1, 1,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 3, 0, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 1, 1, 1, 1, 0, 3,
+ 3, 0, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 4, 2, 2, 1, 2, 1, 2, 1,
+ 2, 4, 4, 1, 0, 3, 1, 1, 2, 1,
+ 2, 1, 1, 3, 6, 0, 1, 2, 4, 1,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 1, 1, 1, 5, 1, 1,
+ 1, 2, 1, 1, 2, 1, 2, 6, 1, 3,
+ 1, 1, 1, 1, 1, 4, 1, 1, 1, 1,
+ 1, 1, 2, 1, 1, 5, 1, 2, 1, 1,
+ 5, 2, 0, 6, 3, 0, 1, 1, 1, 1,
+ 1, 2, 1, 1, 2, 4, 4, 0, 3, 1,
+ 1, 1, 2, 1, 1, 1, 1, 5, 1, 3,
+ 5, 5, 1, 3, 5, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 5, 7, 9, 2, 2,
+ 1, 1, 0, 0, 4, 1, 0, 0, 3, 3,
+ 1, 5, 2, 2, 2, 2, 3, 2, 3, 0,
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
+ 1, 0, 3, 0, 3, 0, 3, 1, 1, 1,
+ 4, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint16 yydefact[] =
+{
+ 0, 3, 4, 0, 6, 1, 9, 0, 5, 246,
+ 281, 282, 0, 247, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 242, 0, 0, 8, 0,
+ 12, 13, 14, 15, 16, 17, 18, 19, 21, 22,
+ 23, 20, 0, 96, 97, 121, 122, 98, 0, 99,
+ 100, 101, 245, 7, 0, 0, 0, 0, 0, 65,
+ 0, 88, 64, 0, 0, 0, 0, 0, 76, 0,
+ 0, 94, 240, 241, 31, 32, 83, 0, 0, 0,
+ 10, 11, 0, 243, 250, 248, 0, 0, 125, 242,
+ 123, 259, 257, 253, 255, 252, 271, 254, 242, 84,
+ 85, 86, 87, 91, 242, 242, 242, 242, 242, 242,
+ 78, 55, 81, 80, 82, 92, 233, 232, 0, 0,
+ 0, 0, 60, 0, 242, 83, 0, 61, 63, 134,
+ 135, 213, 214, 136, 229, 230, 0, 242, 0, 0,
+ 0, 280, 102, 126, 0, 127, 131, 132, 133, 227,
+ 228, 231, 0, 261, 260, 262, 0, 256, 0, 0,
+ 54, 0, 0, 0, 26, 0, 25, 24, 268, 119,
+ 117, 271, 104, 0, 0, 0, 0, 0, 0, 265,
+ 0, 265, 0, 0, 275, 271, 142, 143, 144, 145,
+ 147, 146, 148, 149, 150, 151, 0, 152, 268, 109,
+ 0, 107, 105, 271, 0, 114, 103, 83, 0, 52,
+ 0, 0, 0, 0, 244, 249, 0, 239, 238, 263,
+ 264, 258, 277, 0, 242, 95, 0, 0, 83, 242,
+ 0, 48, 0, 51, 0, 242, 269, 270, 118, 120,
+ 0, 0, 0, 212, 183, 184, 182, 0, 165, 267,
+ 266, 164, 0, 0, 0, 0, 207, 203, 0, 202,
+ 271, 195, 189, 188, 187, 0, 0, 0, 0, 108,
+ 0, 110, 0, 0, 106, 0, 242, 234, 69, 0,
+ 67, 68, 0, 242, 242, 251, 0, 124, 272, 28,
+ 89, 90, 93, 27, 0, 79, 50, 273, 0, 0,
+ 225, 0, 226, 0, 186, 0, 174, 0, 166, 0,
+ 171, 172, 155, 156, 173, 153, 154, 0, 0, 201,
+ 0, 204, 197, 199, 198, 194, 196, 279, 0, 170,
+ 169, 176, 177, 0, 0, 116, 0, 113, 0, 0,
+ 53, 0, 62, 77, 71, 47, 0, 0, 0, 242,
+ 49, 0, 34, 0, 242, 220, 224, 0, 0, 265,
+ 211, 0, 209, 0, 210, 0, 276, 181, 180, 178,
+ 179, 175, 200, 0, 111, 112, 115, 242, 235, 0,
+ 0, 70, 242, 58, 57, 59, 242, 0, 0, 0,
+ 129, 137, 140, 138, 215, 216, 139, 278, 0, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 30, 29, 185, 160, 162, 159, 0, 157, 158,
+ 0, 206, 208, 205, 190, 0, 74, 72, 75, 73,
+ 0, 0, 0, 0, 141, 192, 242, 128, 274, 163,
+ 161, 167, 168, 242, 236, 242, 0, 0, 0, 0,
+ 191, 130, 0, 0, 0, 0, 218, 0, 222, 0,
+ 237, 242, 0, 217, 0, 221, 0, 0, 56, 33,
+ 219, 223, 0, 0, 193
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 3, 4, 6, 8, 9, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 298,
+ 411, 41, 161, 231, 74, 60, 69, 345, 346, 384,
+ 232, 61, 126, 279, 280, 281, 381, 427, 429, 70,
+ 344, 111, 296, 115, 103, 160, 75, 227, 76, 228,
+ 42, 43, 127, 206, 338, 274, 336, 172, 44, 45,
+ 46, 144, 90, 287, 389, 145, 128, 390, 391, 129,
+ 186, 315, 187, 418, 440, 188, 251, 189, 441, 190,
+ 330, 316, 307, 191, 333, 371, 192, 246, 193, 305,
+ 194, 264, 195, 434, 450, 196, 325, 326, 373, 261,
+ 319, 363, 365, 361, 197, 130, 393, 394, 455, 131,
+ 395, 457, 132, 301, 303, 396, 133, 149, 134, 135,
+ 151, 77, 47, 139, 48, 49, 54, 85, 50, 62,
+ 97, 155, 221, 252, 238, 157, 352, 266, 223, 398,
+ 328, 51, 12
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -401
+static const yytype_int16 yypact[] =
+{
+ 193, -401, -401, 27, -401, -401, 62, 143, -401, 24,
+ -401, -401, -30, -401, -18, 12, 83, -401, 15, 15,
+ 15, 15, 15, 15, 67, 61, 15, 15, -401, 127,
+ -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
+ -401, -401, 144, -401, -401, -401, -401, -401, 204, -401,
+ -401, -401, -401, -401, 155, 136, 138, 34, 140, -401,
+ 147, 108, -401, 150, 156, 157, 158, 160, -401, 162,
+ 159, -401, -401, -401, -401, -401, 102, -13, 163, 164,
+ -401, -401, 165, -401, -401, 166, 170, 10, 235, 0,
+ -401, 141, -401, -401, -401, -401, 167, -401, 131, -401,
+ -401, -401, -401, 168, 131, 131, 131, 131, 131, 131,
+ -401, -401, -401, -401, -401, -401, -401, -401, 104, 97,
+ 114, 38, 169, 30, 131, 102, 171, -401, -401, -401,
+ -401, -401, -401, -401, -401, -401, 30, 131, 172, 155,
+ 175, -401, -401, -401, 173, -401, -401, -401, -401, -401,
+ -401, -401, 223, -401, -401, 123, 253, -401, 177, 149,
+ -401, 178, -10, 181, -401, 182, -401, -401, 134, -401,
+ -401, 167, -401, 183, 184, 185, 213, 99, 186, 154,
+ 187, 146, 153, 7, 188, 167, -401, -401, -401, -401,
+ -401, -401, -401, -401, -401, -401, 215, -401, 134, -401,
+ 190, -401, -401, 167, 191, 192, -401, 102, -48, -401,
+ 1, 195, 196, 214, 166, -401, 189, -401, -401, -401,
+ -401, -401, -401, 180, 131, -401, 194, 197, 102, 131,
+ 30, -401, 203, 205, 201, 131, -401, -401, -401, -401,
+ 285, 288, 289, -401, -401, -401, -401, 291, -401, -401,
+ -401, -401, 248, 291, 33, 206, 207, -401, 208, -401,
+ 167, 14, -401, -401, -401, 293, 292, 92, 209, -401,
+ 299, -401, 301, 299, -401, 216, 131, -401, -401, 217,
+ -401, -401, 221, 131, 131, -401, 212, -401, -401, -401,
+ -401, -401, -401, -401, 218, -401, -401, 220, 224, 225,
+ -401, 226, -401, 227, -401, 228, -401, 230, -401, 231,
+ -401, -401, -401, -401, -401, -401, -401, 304, 309, -401,
+ 312, -401, -401, -401, -401, -401, -401, -401, 232, -401,
+ -401, -401, -401, 161, 313, -401, 233, -401, 234, 238,
+ -401, 13, -401, -401, 137, -401, 242, -15, 243, 3,
+ -401, 314, -401, 133, 131, -401, -401, 296, 94, 146,
+ -401, 245, -401, 246, -401, 247, -401, -401, -401, -401,
+ -401, -401, -401, 249, -401, -401, -401, 131, -401, 332,
+ 337, -401, 131, -401, -401, -401, 131, 142, 114, 28,
+ -401, -401, -401, -401, -401, -401, -401, -401, 250, -401,
+ -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
+ -401, -401, -401, -401, -401, -401, -401, 331, -401, -401,
+ 68, -401, -401, -401, -401, 43, -401, -401, -401, -401,
+ 255, 256, 257, 258, -401, 300, 3, -401, -401, -401,
+ -401, -401, -401, 131, -401, 131, 201, 285, 288, 259,
+ -401, -401, 252, 264, 265, 263, 261, 266, 270, 313,
+ -401, 131, 133, -401, 285, -401, 288, 80, -401, -401,
+ -401, -401, 313, 267, -401
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
+ -401, -401, -401, -401, -401, -401, -401, -401, -401, -69,
+ -82, -401, -100, 151, -86, 210, -401, -401, -366, -401,
+ -54, -401, -401, -401, -401, -401, -401, -401, -401, 174,
+ -401, -401, -401, -118, -401, -401, 229, -401, -401, -401,
+ -401, -401, 295, -401, -401, -401, 110, -401, -401, -401,
+ -401, -401, -401, -401, -401, -401, -401, -51, -401, -88,
+ -401, -401, -401, -401, -401, -401, -401, -401, -401, -401,
+ -401, -311, 139, -401, -401, -401, -401, -401, -401, -401,
+ -401, -401, -401, -401, -401, -2, -401, -401, -400, -401,
+ -401, -401, -401, -401, -401, 298, -401, -401, -401, -401,
+ -401, -401, -401, -390, -295, 302, -401, -401, -136, -87,
+ -120, -89, -401, -401, -401, -401, -401, 251, -401, 176,
+ -401, -401, -401, -176, 198, -153, -401, -401, -401, -401,
+ -401, -401, -6
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -230
+static const yytype_int16 yytable[] =
+{
+ 152, 146, 150, 52, 208, 254, 164, 209, 383, 167,
+ 116, 117, 158, 116, 117, 162, 430, 162, 239, 163,
+ 162, 165, 166, 125, 278, 118, 233, 5, 118, 13,
+ 14, 15, 267, 262, 16, 152, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 419, 118, 119,
+ 271, 212, 119, 116, 117, 322, 323, 456, 310, 467,
+ 120, 276, 119, 120, 311, 387, 312, 198, 118, 207,
+ 7, 277, 473, 120, 470, 199, 388, 263, 53, 453,
+ 58, 55, 211, 121, 10, 11, 121, 122, 200, 275,
+ 122, 201, 119, 310, 233, 468, 324, 123, 202, 311,
+ 230, 68, 313, 120, 314, 124, 121, 321, 124, 442,
+ 292, 56, 203, 72, 73, 59, 72, 73, 124, 310,
+ 414, 124, 377, 10, 11, 311, 121, 331, 244, 293,
+ 122, 173, 378, 168, 415, 204, 205, 436, 289, 314,
+ 162, 169, 175, 174, 176, 88, 332, 437, 124, 299,
+ 177, 89, 443, 458, 416, 245, 341, 178, 179, 180,
+ 71, 181, 444, 182, 170, 314, 417, 68, 153, 91,
+ 92, 471, 183, 249, 72, 73, 432, 93, 171, 248,
+ 154, 249, 57, 420, 219, 250, 472, 152, 433, 184,
+ 185, 220, 424, 250, 347, 236, 1, 2, 348, 94,
+ 95, 255, 237, 112, 256, 257, 113, 114, 258, 99,
+ 100, 101, 102, 82, 96, 83, 259, 399, 400, 401,
+ 402, 403, 404, 405, 406, 407, 408, 409, 410, 63,
+ 64, 65, 66, 67, 260, 80, 78, 79, 367, 368,
+ 369, 370, 10, 11, 72, 73, 217, 218, 71, 225,
+ 379, 380, 81, 86, 84, 87, 98, 425, 143, 104,
+ 152, 392, 150, 110, 138, 105, 106, 107, 412, 108,
+ 141, 109, 136, 137, 215, 140, 222, 243, 156, 58,
+ -66, 268, 210, 159, 297, 216, 224, 229, 152, 213,
+ 234, 235, 288, 347, 240, 241, 242, 247, 253, 265,
+ 431, 270, 272, 273, 283, 284, 286, 295, 300, -229,
+ 290, 302, 304, 291, 306, 308, 327, 317, 318, 320,
+ 334, 329, 335, 452, 337, 343, 340, 360, 350, 342,
+ 349, 351, 362, 353, 354, 364, 372, 397, 355, 356,
+ 357, 385, 358, 359, 366, 374, 375, 152, 392, 150,
+ 376, 382, 386, 413, 152, 426, 347, 421, 422, 423,
+ 428, 424, 438, 439, 445, 446, 449, 464, 447, 448,
+ 459, 460, 347, 461, 462, 463, 466, 454, 465, 474,
+ 469, 294, 142, 339, 282, 451, 435, 147, 226, 285,
+ 214, 148, 309, 0, 0, 0, 269
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 89, 89, 89, 9, 124, 181, 106, 125, 23, 109,
+ 23, 24, 98, 23, 24, 104, 382, 106, 171, 105,
+ 109, 107, 108, 77, 23, 38, 162, 0, 38, 5,
+ 6, 7, 185, 26, 10, 124, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 358, 38, 62,
+ 203, 137, 62, 23, 24, 41, 42, 447, 25, 459,
+ 73, 109, 62, 73, 31, 62, 33, 29, 38, 123,
+ 8, 119, 472, 73, 464, 37, 73, 70, 108, 445,
+ 65, 99, 136, 96, 99, 100, 96, 100, 50, 207,
+ 100, 53, 62, 25, 230, 461, 82, 110, 60, 31,
+ 110, 100, 69, 73, 71, 118, 96, 260, 118, 420,
+ 228, 99, 74, 113, 114, 100, 113, 114, 118, 25,
+ 26, 118, 109, 99, 100, 31, 96, 35, 29, 229,
+ 100, 34, 119, 29, 40, 97, 98, 109, 224, 71,
+ 229, 37, 28, 46, 30, 111, 54, 119, 118, 235,
+ 36, 117, 109, 448, 60, 56, 276, 43, 44, 45,
+ 99, 47, 119, 49, 60, 71, 72, 100, 27, 29,
+ 30, 466, 58, 27, 113, 114, 34, 37, 74, 25,
+ 39, 27, 99, 359, 61, 39, 106, 276, 46, 75,
+ 76, 68, 112, 39, 283, 61, 3, 4, 284, 59,
+ 60, 48, 68, 101, 51, 52, 104, 105, 55, 101,
+ 102, 103, 104, 9, 74, 11, 63, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 19,
+ 20, 21, 22, 23, 81, 108, 26, 27, 77, 78,
+ 79, 80, 99, 100, 113, 114, 23, 24, 99, 100,
+ 113, 114, 108, 117, 99, 117, 109, 377, 23, 109,
+ 349, 349, 349, 104, 99, 109, 109, 109, 354, 109,
+ 100, 109, 109, 109, 99, 109, 23, 64, 111, 65,
+ 111, 66, 111, 115, 83, 112, 109, 109, 377, 117,
+ 109, 109, 112, 382, 111, 111, 111, 111, 111, 111,
+ 386, 111, 111, 111, 109, 109, 117, 104, 23, 104,
+ 116, 23, 23, 116, 23, 67, 23, 111, 111, 111,
+ 111, 29, 23, 443, 23, 104, 110, 23, 110, 112,
+ 118, 111, 23, 109, 109, 23, 23, 23, 112, 112,
+ 112, 347, 112, 112, 112, 112, 112, 436, 436, 436,
+ 112, 109, 109, 57, 443, 23, 445, 112, 112, 112,
+ 23, 112, 112, 32, 109, 109, 66, 106, 111, 111,
+ 111, 119, 461, 109, 109, 112, 106, 446, 112, 112,
+ 462, 230, 87, 273, 210, 436, 388, 89, 159, 213,
+ 139, 89, 253, -1, -1, -1, 198
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint16 yystos[] =
+{
+ 0, 3, 4, 121, 122, 0, 123, 8, 124, 125,
+ 99, 100, 262, 5, 6, 7, 10, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
+ 138, 141, 170, 171, 178, 179, 180, 242, 244, 245,
+ 248, 261, 262, 108, 246, 99, 99, 99, 65, 100,
+ 145, 151, 249, 145, 145, 145, 145, 145, 100, 146,
+ 159, 99, 113, 114, 144, 166, 168, 241, 145, 145,
+ 108, 108, 9, 11, 99, 247, 117, 117, 111, 117,
+ 182, 29, 30, 37, 59, 60, 74, 250, 109, 101,
+ 102, 103, 104, 164, 109, 109, 109, 109, 109, 109,
+ 104, 161, 101, 104, 105, 163, 23, 24, 38, 62,
+ 73, 96, 100, 110, 118, 150, 152, 172, 186, 189,
+ 225, 229, 232, 236, 238, 239, 109, 109, 99, 243,
+ 109, 100, 172, 23, 181, 185, 189, 225, 235, 237,
+ 239, 240, 241, 27, 39, 251, 111, 255, 144, 115,
+ 165, 142, 241, 144, 142, 144, 144, 142, 29, 37,
+ 60, 74, 177, 34, 46, 28, 30, 36, 43, 44,
+ 45, 47, 49, 58, 75, 76, 190, 192, 195, 197,
+ 199, 203, 206, 208, 210, 212, 215, 224, 29, 37,
+ 50, 53, 60, 74, 97, 98, 173, 150, 240, 163,
+ 111, 150, 144, 117, 247, 99, 112, 23, 24, 61,
+ 68, 252, 23, 258, 109, 100, 166, 167, 169, 109,
+ 110, 143, 150, 238, 109, 109, 61, 68, 254, 255,
+ 111, 111, 111, 64, 29, 56, 207, 111, 25, 27,
+ 39, 196, 253, 111, 253, 48, 51, 52, 55, 63,
+ 81, 219, 26, 70, 211, 111, 257, 255, 66, 254,
+ 111, 255, 111, 111, 175, 163, 109, 119, 23, 153,
+ 154, 155, 159, 109, 109, 249, 117, 183, 112, 144,
+ 116, 116, 163, 142, 143, 104, 162, 83, 139, 144,
+ 23, 233, 23, 234, 23, 209, 23, 202, 67, 202,
+ 25, 31, 33, 69, 71, 191, 201, 111, 111, 220,
+ 111, 255, 41, 42, 82, 216, 217, 23, 260, 29,
+ 200, 35, 54, 204, 111, 23, 176, 23, 174, 176,
+ 110, 240, 112, 104, 160, 147, 148, 241, 144, 118,
+ 110, 111, 256, 109, 109, 112, 112, 112, 112, 112,
+ 23, 223, 23, 221, 23, 222, 112, 77, 78, 79,
+ 80, 205, 23, 218, 112, 112, 112, 109, 119, 113,
+ 114, 156, 109, 23, 149, 262, 109, 62, 73, 184,
+ 187, 188, 189, 226, 227, 230, 235, 23, 259, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 140, 144, 57, 26, 40, 60, 72, 193, 201,
+ 253, 112, 112, 112, 112, 240, 23, 157, 23, 158,
+ 148, 144, 34, 46, 213, 215, 109, 119, 112, 32,
+ 194, 198, 201, 109, 119, 109, 109, 111, 111, 66,
+ 214, 187, 240, 148, 139, 228, 233, 231, 234, 111,
+ 119, 109, 109, 112, 106, 112, 106, 218, 148, 140,
+ 233, 234, 106, 218, 112
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, state, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, scanner)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, Location, state); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ struct asm_parser_state *state;
+#endif
+{
+ if (!yyvaluep)
+ return;
+ YYUSE (yylocationp);
+ YYUSE (state);
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, state)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ struct asm_parser_state *state;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct asm_parser_state *state)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, state)
+ YYSTYPE *yyvsp;
+ YYLTYPE *yylsp;
+ int yyrule;
+ struct asm_parser_state *state;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , &(yylsp[(yyi + 1) - (yynrhs)]) , state);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, yylsp, Rule, state); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct asm_parser_state *state)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, state)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ YYLTYPE *yylocationp;
+ struct asm_parser_state *state;
+#endif
+{
+ YYUSE (yyvaluep);
+ YYUSE (yylocationp);
+ YYUSE (state);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (struct asm_parser_state *state);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (struct asm_parser_state *state)
+#else
+int
+yyparse (state)
+ struct asm_parser_state *state;
+#endif
+#endif
+{
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Location data for the lookahead symbol. */
+YYLTYPE yylloc;
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls;
+ YYLTYPE *yylsp;
+
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[2];
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yyls = yylsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+ yylsp = yyls;
+
+#if YYLTYPE_IS_TRIVIAL
+ /* Initialize the default location before parsing starts. */
+ yylloc.first_line = yylloc.last_line = 1;
+ yylloc.first_column = yylloc.last_column = 1;
+#endif
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yyls1, yysize * sizeof (*yylsp),
+ &yystacksize);
+
+ yyls = yyls1;
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyls_alloc, yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+ *++yylsp = yylloc;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 3:
+
+/* Line 1455 of yacc.c */
+#line 282 "program_parse.y"
+ {
+ if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid fragment program header");
+
+ }
+ state->mode = ARB_vertex;
+ ;}
+ break;
+
+ case 4:
+
+/* Line 1455 of yacc.c */
+#line 290 "program_parse.y"
+ {
+ if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex program header");
+ }
+ state->mode = ARB_fragment;
+
+ state->option.TexRect =
+ (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE);
+ ;}
+ break;
+
+ case 7:
+
+/* Line 1455 of yacc.c */
+#line 306 "program_parse.y"
+ {
+ int valid = 0;
+
+ if (state->mode == ARB_vertex) {
+ valid = _mesa_ARBvp_parse_option(state, (yyvsp[(2) - (3)].string));
+ } else if (state->mode == ARB_fragment) {
+ valid = _mesa_ARBfp_parse_option(state, (yyvsp[(2) - (3)].string));
+ }
+
+
+ free((yyvsp[(2) - (3)].string));
+
+ if (!valid) {
+ const char *const err_str = (state->mode == ARB_vertex)
+ ? "invalid ARB vertex program option"
+ : "invalid ARB fragment program option";
+
+ yyerror(& (yylsp[(2) - (3)]), state, err_str);
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 10:
+
+/* Line 1455 of yacc.c */
+#line 334 "program_parse.y"
+ {
+ if ((yyvsp[(1) - (2)].inst) != NULL) {
+ if (state->inst_tail == NULL) {
+ state->inst_head = (yyvsp[(1) - (2)].inst);
+ } else {
+ state->inst_tail->next = (yyvsp[(1) - (2)].inst);
+ }
+
+ state->inst_tail = (yyvsp[(1) - (2)].inst);
+ (yyvsp[(1) - (2)].inst)->next = NULL;
+
+ state->prog->NumInstructions++;
+ }
+ ;}
+ break;
+
+ case 12:
+
+/* Line 1455 of yacc.c */
+#line 352 "program_parse.y"
+ {
+ (yyval.inst) = (yyvsp[(1) - (1)].inst);
+ state->prog->NumAluInstructions++;
+ ;}
+ break;
+
+ case 13:
+
+/* Line 1455 of yacc.c */
+#line 357 "program_parse.y"
+ {
+ (yyval.inst) = (yyvsp[(1) - (1)].inst);
+ state->prog->NumTexInstructions++;
+ ;}
+ break;
+
+ case 24:
+
+/* Line 1455 of yacc.c */
+#line 378 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_ctor(OPCODE_ARL, & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL);
+ ;}
+ break;
+
+ case 25:
+
+/* Line 1455 of yacc.c */
+#line 384 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL);
+ ;}
+ break;
+
+ case 26:
+
+/* Line 1455 of yacc.c */
+#line 390 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL);
+ ;}
+ break;
+
+ case 27:
+
+/* Line 1455 of yacc.c */
+#line 396 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL);
+ ;}
+ break;
+
+ case 28:
+
+/* Line 1455 of yacc.c */
+#line 403 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL);
+ ;}
+ break;
+
+ case 29:
+
+/* Line 1455 of yacc.c */
+#line 410 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), & (yyvsp[(6) - (8)].src_reg), & (yyvsp[(8) - (8)].src_reg));
+ ;}
+ break;
+
+ case 30:
+
+/* Line 1455 of yacc.c */
+#line 416 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), NULL, NULL);
+ if ((yyval.inst) != NULL) {
+ const GLbitfield tex_mask = (1U << (yyvsp[(6) - (8)].integer));
+ GLbitfield shadow_tex = 0;
+ GLbitfield target_mask = 0;
+
+
+ (yyval.inst)->Base.TexSrcUnit = (yyvsp[(6) - (8)].integer);
+
+ if ((yyvsp[(8) - (8)].integer) < 0) {
+ shadow_tex = tex_mask;
+
+ (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(8) - (8)].integer);
+ (yyval.inst)->Base.TexShadow = 1;
+ } else {
+ (yyval.inst)->Base.TexSrcTarget = (yyvsp[(8) - (8)].integer);
+ }
+
+ target_mask = (1U << (yyval.inst)->Base.TexSrcTarget);
+
+ /* If this texture unit was previously accessed and that access
+ * had a different texture target, generate an error.
+ *
+ * If this texture unit was previously accessed and that access
+ * had a different shadow mode, generate an error.
+ */
+ if ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != 0)
+ && ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != target_mask)
+ || ((state->prog->ShadowSamplers & tex_mask)
+ != shadow_tex))) {
+ yyerror(& (yylsp[(8) - (8)]), state,
+ "multiple targets used on one texture image unit");
+ YYERROR;
+ }
+
+
+ state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] |= target_mask;
+ state->prog->ShadowSamplers |= shadow_tex;
+ }
+ ;}
+ break;
+
+ case 31:
+
+/* Line 1455 of yacc.c */
+#line 460 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_ctor(OPCODE_KIL, NULL, & (yyvsp[(2) - (2)].src_reg), NULL, NULL);
+ state->fragment.UsesKill = 1;
+ ;}
+ break;
+
+ case 32:
+
+/* Line 1455 of yacc.c */
+#line 465 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL);
+ (yyval.inst)->Base.DstReg.CondMask = (yyvsp[(2) - (2)].dst_reg).CondMask;
+ (yyval.inst)->Base.DstReg.CondSwizzle = (yyvsp[(2) - (2)].dst_reg).CondSwizzle;
+ (yyval.inst)->Base.DstReg.CondSrc = (yyvsp[(2) - (2)].dst_reg).CondSrc;
+ state->fragment.UsesKill = 1;
+ ;}
+ break;
+
+ case 33:
+
+/* Line 1455 of yacc.c */
+#line 475 "program_parse.y"
+ {
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (12)].temp_inst), & (yyvsp[(2) - (12)].dst_reg), & (yyvsp[(4) - (12)].src_reg), & (yyvsp[(6) - (12)].src_reg), & (yyvsp[(8) - (12)].src_reg));
+ if ((yyval.inst) != NULL) {
+ const GLbitfield tex_mask = (1U << (yyvsp[(10) - (12)].integer));
+ GLbitfield shadow_tex = 0;
+ GLbitfield target_mask = 0;
+
+
+ (yyval.inst)->Base.TexSrcUnit = (yyvsp[(10) - (12)].integer);
+
+ if ((yyvsp[(12) - (12)].integer) < 0) {
+ shadow_tex = tex_mask;
+
+ (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(12) - (12)].integer);
+ (yyval.inst)->Base.TexShadow = 1;
+ } else {
+ (yyval.inst)->Base.TexSrcTarget = (yyvsp[(12) - (12)].integer);
+ }
+
+ target_mask = (1U << (yyval.inst)->Base.TexSrcTarget);
+
+ /* If this texture unit was previously accessed and that access
+ * had a different texture target, generate an error.
+ *
+ * If this texture unit was previously accessed and that access
+ * had a different shadow mode, generate an error.
+ */
+ if ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != 0)
+ && ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != target_mask)
+ || ((state->prog->ShadowSamplers & tex_mask)
+ != shadow_tex))) {
+ yyerror(& (yylsp[(12) - (12)]), state,
+ "multiple targets used on one texture image unit");
+ YYERROR;
+ }
+
+
+ state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] |= target_mask;
+ state->prog->ShadowSamplers |= shadow_tex;
+ }
+ ;}
+ break;
+
+ case 34:
+
+/* Line 1455 of yacc.c */
+#line 519 "program_parse.y"
+ {
+ (yyval.integer) = (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 35:
+
+/* Line 1455 of yacc.c */
+#line 524 "program_parse.y"
+ { (yyval.integer) = TEXTURE_1D_INDEX; ;}
+ break;
+
+ case 36:
+
+/* Line 1455 of yacc.c */
+#line 525 "program_parse.y"
+ { (yyval.integer) = TEXTURE_2D_INDEX; ;}
+ break;
+
+ case 37:
+
+/* Line 1455 of yacc.c */
+#line 526 "program_parse.y"
+ { (yyval.integer) = TEXTURE_3D_INDEX; ;}
+ break;
+
+ case 38:
+
+/* Line 1455 of yacc.c */
+#line 527 "program_parse.y"
+ { (yyval.integer) = TEXTURE_CUBE_INDEX; ;}
+ break;
+
+ case 39:
+
+/* Line 1455 of yacc.c */
+#line 528 "program_parse.y"
+ { (yyval.integer) = TEXTURE_RECT_INDEX; ;}
+ break;
+
+ case 40:
+
+/* Line 1455 of yacc.c */
+#line 529 "program_parse.y"
+ { (yyval.integer) = -TEXTURE_1D_INDEX; ;}
+ break;
+
+ case 41:
+
+/* Line 1455 of yacc.c */
+#line 530 "program_parse.y"
+ { (yyval.integer) = -TEXTURE_2D_INDEX; ;}
+ break;
+
+ case 42:
+
+/* Line 1455 of yacc.c */
+#line 531 "program_parse.y"
+ { (yyval.integer) = -TEXTURE_RECT_INDEX; ;}
+ break;
+
+ case 43:
+
+/* Line 1455 of yacc.c */
+#line 532 "program_parse.y"
+ { (yyval.integer) = TEXTURE_1D_ARRAY_INDEX; ;}
+ break;
+
+ case 44:
+
+/* Line 1455 of yacc.c */
+#line 533 "program_parse.y"
+ { (yyval.integer) = TEXTURE_2D_ARRAY_INDEX; ;}
+ break;
+
+ case 45:
+
+/* Line 1455 of yacc.c */
+#line 534 "program_parse.y"
+ { (yyval.integer) = -TEXTURE_1D_ARRAY_INDEX; ;}
+ break;
+
+ case 46:
+
+/* Line 1455 of yacc.c */
+#line 535 "program_parse.y"
+ { (yyval.integer) = -TEXTURE_2D_ARRAY_INDEX; ;}
+ break;
+
+ case 47:
+
+/* Line 1455 of yacc.c */
+#line 539 "program_parse.y"
+ {
+ /* FIXME: Is this correct? Should the extenedSwizzle be applied
+ * FIXME: to the existing swizzle?
+ */
+ (yyvsp[(4) - (6)].src_reg).Base.Swizzle = (yyvsp[(6) - (6)].swiz_mask).swizzle;
+ (yyvsp[(4) - (6)].src_reg).Base.Negate = (yyvsp[(6) - (6)].swiz_mask).mask;
+
+ (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), NULL, NULL);
+ ;}
+ break;
+
+ case 48:
+
+/* Line 1455 of yacc.c */
+#line 551 "program_parse.y"
+ {
+ (yyval.src_reg) = (yyvsp[(2) - (2)].src_reg);
+
+ if ((yyvsp[(1) - (2)].negate)) {
+ (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
+ }
+ ;}
+ break;
+
+ case 49:
+
+/* Line 1455 of yacc.c */
+#line 559 "program_parse.y"
+ {
+ (yyval.src_reg) = (yyvsp[(3) - (4)].src_reg);
+
+ if (!state->option.NV_fragment) {
+ yyerror(& (yylsp[(2) - (4)]), state, "unexpected character '|'");
+ YYERROR;
+ }
+
+ if ((yyvsp[(1) - (4)].negate)) {
+ (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
+ }
+
+ (yyval.src_reg).Base.Abs = 1;
+ ;}
+ break;
+
+ case 50:
+
+/* Line 1455 of yacc.c */
+#line 576 "program_parse.y"
+ {
+ (yyval.src_reg) = (yyvsp[(1) - (2)].src_reg);
+
+ (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle,
+ (yyvsp[(2) - (2)].swiz_mask).swizzle);
+ ;}
+ break;
+
+ case 51:
+
+/* Line 1455 of yacc.c */
+#line 583 "program_parse.y"
+ {
+ struct asm_symbol temp_sym;
+
+ if (!state->option.NV_fragment) {
+ yyerror(& (yylsp[(1) - (1)]), state, "expected scalar suffix");
+ YYERROR;
+ }
+
+ memset(& temp_sym, 0, sizeof(temp_sym));
+ temp_sym.param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & temp_sym, & (yyvsp[(1) - (1)].vector), GL_TRUE);
+
+ set_src_reg_swz(& (yyval.src_reg), PROGRAM_CONSTANT,
+ temp_sym.param_binding_begin,
+ temp_sym.param_binding_swizzle);
+ ;}
+ break;
+
+ case 52:
+
+/* Line 1455 of yacc.c */
+#line 602 "program_parse.y"
+ {
+ (yyval.src_reg) = (yyvsp[(2) - (3)].src_reg);
+
+ if ((yyvsp[(1) - (3)].negate)) {
+ (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
+ }
+
+ (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle,
+ (yyvsp[(3) - (3)].swiz_mask).swizzle);
+ ;}
+ break;
+
+ case 53:
+
+/* Line 1455 of yacc.c */
+#line 613 "program_parse.y"
+ {
+ (yyval.src_reg) = (yyvsp[(3) - (5)].src_reg);
+
+ if (!state->option.NV_fragment) {
+ yyerror(& (yylsp[(2) - (5)]), state, "unexpected character '|'");
+ YYERROR;
+ }
+
+ if ((yyvsp[(1) - (5)].negate)) {
+ (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate;
+ }
+
+ (yyval.src_reg).Base.Abs = 1;
+ (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle,
+ (yyvsp[(4) - (5)].swiz_mask).swizzle);
+ ;}
+ break;
+
+ case 54:
+
+/* Line 1455 of yacc.c */
+#line 633 "program_parse.y"
+ {
+ (yyval.dst_reg) = (yyvsp[(1) - (3)].dst_reg);
+ (yyval.dst_reg).WriteMask = (yyvsp[(2) - (3)].swiz_mask).mask;
+ (yyval.dst_reg).CondMask = (yyvsp[(3) - (3)].dst_reg).CondMask;
+ (yyval.dst_reg).CondSwizzle = (yyvsp[(3) - (3)].dst_reg).CondSwizzle;
+ (yyval.dst_reg).CondSrc = (yyvsp[(3) - (3)].dst_reg).CondSrc;
+
+ if ((yyval.dst_reg).File == PROGRAM_OUTPUT) {
+ /* Technically speaking, this should check that it is in
+ * vertex program mode. However, PositionInvariant can never be
+ * set in fragment program mode, so it is somewhat irrelevant.
+ */
+ if (state->option.PositionInvariant
+ && ((yyval.dst_reg).Index == VERT_RESULT_HPOS)) {
+ yyerror(& (yylsp[(1) - (3)]), state, "position-invariant programs cannot "
+ "write position");
+ YYERROR;
+ }
+
+ state->prog->OutputsWritten |= BITFIELD64_BIT((yyval.dst_reg).Index);
+ }
+ ;}
+ break;
+
+ case 55:
+
+/* Line 1455 of yacc.c */
+#line 658 "program_parse.y"
+ {
+ set_dst_reg(& (yyval.dst_reg), PROGRAM_ADDRESS, 0);
+ (yyval.dst_reg).WriteMask = (yyvsp[(2) - (2)].swiz_mask).mask;
+ ;}
+ break;
+
+ case 56:
+
+/* Line 1455 of yacc.c */
+#line 665 "program_parse.y"
+ {
+ const unsigned xyzw_valid =
+ ((yyvsp[(1) - (7)].ext_swizzle).xyzw_valid << 0)
+ | ((yyvsp[(3) - (7)].ext_swizzle).xyzw_valid << 1)
+ | ((yyvsp[(5) - (7)].ext_swizzle).xyzw_valid << 2)
+ | ((yyvsp[(7) - (7)].ext_swizzle).xyzw_valid << 3);
+ const unsigned rgba_valid =
+ ((yyvsp[(1) - (7)].ext_swizzle).rgba_valid << 0)
+ | ((yyvsp[(3) - (7)].ext_swizzle).rgba_valid << 1)
+ | ((yyvsp[(5) - (7)].ext_swizzle).rgba_valid << 2)
+ | ((yyvsp[(7) - (7)].ext_swizzle).rgba_valid << 3);
+
+ /* All of the swizzle components have to be valid in either RGBA
+ * or XYZW. Note that 0 and 1 are valid in both, so both masks
+ * can have some bits set.
+ *
+ * We somewhat deviate from the spec here. It would be really hard
+ * to figure out which component is the error, and there probably
+ * isn't a lot of benefit.
+ */
+ if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) {
+ yyerror(& (yylsp[(1) - (7)]), state, "cannot combine RGBA and XYZW swizzle "
+ "components");
+ YYERROR;
+ }
+
+ (yyval.swiz_mask).swizzle = MAKE_SWIZZLE4((yyvsp[(1) - (7)].ext_swizzle).swz, (yyvsp[(3) - (7)].ext_swizzle).swz, (yyvsp[(5) - (7)].ext_swizzle).swz, (yyvsp[(7) - (7)].ext_swizzle).swz);
+ (yyval.swiz_mask).mask = ((yyvsp[(1) - (7)].ext_swizzle).negate) | ((yyvsp[(3) - (7)].ext_swizzle).negate << 1) | ((yyvsp[(5) - (7)].ext_swizzle).negate << 2)
+ | ((yyvsp[(7) - (7)].ext_swizzle).negate << 3);
+ ;}
+ break;
+
+ case 57:
+
+/* Line 1455 of yacc.c */
+#line 698 "program_parse.y"
+ {
+ (yyval.ext_swizzle) = (yyvsp[(2) - (2)].ext_swizzle);
+ (yyval.ext_swizzle).negate = ((yyvsp[(1) - (2)].negate)) ? 1 : 0;
+ ;}
+ break;
+
+ case 58:
+
+/* Line 1455 of yacc.c */
+#line 705 "program_parse.y"
+ {
+ if (((yyvsp[(1) - (1)].integer) != 0) && ((yyvsp[(1) - (1)].integer) != 1)) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector");
+ YYERROR;
+ }
+
+ (yyval.ext_swizzle).swz = ((yyvsp[(1) - (1)].integer) == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
+
+ /* 0 and 1 are valid for both RGBA swizzle names and XYZW
+ * swizzle names.
+ */
+ (yyval.ext_swizzle).xyzw_valid = 1;
+ (yyval.ext_swizzle).rgba_valid = 1;
+ ;}
+ break;
+
+ case 59:
+
+/* Line 1455 of yacc.c */
+#line 720 "program_parse.y"
+ {
+ char s;
+
+ if (strlen((yyvsp[(1) - (1)].string)) > 1) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector");
+ YYERROR;
+ }
+
+ s = (yyvsp[(1) - (1)].string)[0];
+ free((yyvsp[(1) - (1)].string));
+
+ switch (s) {
+ case 'x':
+ (yyval.ext_swizzle).swz = SWIZZLE_X;
+ (yyval.ext_swizzle).xyzw_valid = 1;
+ break;
+ case 'y':
+ (yyval.ext_swizzle).swz = SWIZZLE_Y;
+ (yyval.ext_swizzle).xyzw_valid = 1;
+ break;
+ case 'z':
+ (yyval.ext_swizzle).swz = SWIZZLE_Z;
+ (yyval.ext_swizzle).xyzw_valid = 1;
+ break;
+ case 'w':
+ (yyval.ext_swizzle).swz = SWIZZLE_W;
+ (yyval.ext_swizzle).xyzw_valid = 1;
+ break;
+
+ case 'r':
+ (yyval.ext_swizzle).swz = SWIZZLE_X;
+ (yyval.ext_swizzle).rgba_valid = 1;
+ break;
+ case 'g':
+ (yyval.ext_swizzle).swz = SWIZZLE_Y;
+ (yyval.ext_swizzle).rgba_valid = 1;
+ break;
+ case 'b':
+ (yyval.ext_swizzle).swz = SWIZZLE_Z;
+ (yyval.ext_swizzle).rgba_valid = 1;
+ break;
+ case 'a':
+ (yyval.ext_swizzle).swz = SWIZZLE_W;
+ (yyval.ext_swizzle).rgba_valid = 1;
+ break;
+
+ default:
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector");
+ YYERROR;
+ break;
+ }
+ ;}
+ break;
+
+ case 60:
+
+/* Line 1455 of yacc.c */
+#line 775 "program_parse.y"
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
+
+ free((yyvsp[(1) - (1)].string));
+
+ if (s == NULL) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type != at_param) && (s->type != at_temp)
+ && (s->type != at_attrib)) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type == at_param) && s->param_is_array) {
+ yyerror(& (yylsp[(1) - (1)]), state, "non-array access to array PARAM");
+ YYERROR;
+ }
+
+ init_src_reg(& (yyval.src_reg));
+ switch (s->type) {
+ case at_temp:
+ set_src_reg(& (yyval.src_reg), PROGRAM_TEMPORARY, s->temp_binding);
+ break;
+ case at_param:
+ set_src_reg_swz(& (yyval.src_reg), s->param_binding_type,
+ s->param_binding_begin,
+ s->param_binding_swizzle);
+ break;
+ case at_attrib:
+ set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, s->attrib_binding);
+ state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index);
+
+ if (!validate_inputs(& (yylsp[(1) - (1)]), state)) {
+ YYERROR;
+ }
+ break;
+
+ default:
+ YYERROR;
+ break;
+ }
+ ;}
+ break;
+
+ case 61:
+
+/* Line 1455 of yacc.c */
+#line 818 "program_parse.y"
+ {
+ set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, (yyvsp[(1) - (1)].attrib));
+ state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index);
+
+ if (!validate_inputs(& (yylsp[(1) - (1)]), state)) {
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 62:
+
+/* Line 1455 of yacc.c */
+#line 827 "program_parse.y"
+ {
+ if (! (yyvsp[(3) - (4)].src_reg).Base.RelAddr
+ && ((unsigned) (yyvsp[(3) - (4)].src_reg).Base.Index >= (yyvsp[(1) - (4)].sym)->param_binding_length)) {
+ yyerror(& (yylsp[(3) - (4)]), state, "out of bounds array access");
+ YYERROR;
+ }
+
+ init_src_reg(& (yyval.src_reg));
+ (yyval.src_reg).Base.File = (yyvsp[(1) - (4)].sym)->param_binding_type;
+
+ if ((yyvsp[(3) - (4)].src_reg).Base.RelAddr) {
+ state->prog->IndirectRegisterFiles |= (1 << (yyval.src_reg).Base.File);
+ (yyvsp[(1) - (4)].sym)->param_accessed_indirectly = 1;
+
+ (yyval.src_reg).Base.RelAddr = 1;
+ (yyval.src_reg).Base.Index = (yyvsp[(3) - (4)].src_reg).Base.Index;
+ (yyval.src_reg).Symbol = (yyvsp[(1) - (4)].sym);
+ } else {
+ (yyval.src_reg).Base.Index = (yyvsp[(1) - (4)].sym)->param_binding_begin + (yyvsp[(3) - (4)].src_reg).Base.Index;
+ }
+ ;}
+ break;
+
+ case 63:
+
+/* Line 1455 of yacc.c */
+#line 849 "program_parse.y"
+ {
+ gl_register_file file = ((yyvsp[(1) - (1)].temp_sym).name != NULL)
+ ? (yyvsp[(1) - (1)].temp_sym).param_binding_type
+ : PROGRAM_CONSTANT;
+ set_src_reg_swz(& (yyval.src_reg), file, (yyvsp[(1) - (1)].temp_sym).param_binding_begin,
+ (yyvsp[(1) - (1)].temp_sym).param_binding_swizzle);
+ ;}
+ break;
+
+ case 64:
+
+/* Line 1455 of yacc.c */
+#line 859 "program_parse.y"
+ {
+ set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, (yyvsp[(1) - (1)].result));
+ ;}
+ break;
+
+ case 65:
+
+/* Line 1455 of yacc.c */
+#line 863 "program_parse.y"
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
+
+ free((yyvsp[(1) - (1)].string));
+
+ if (s == NULL) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type != at_output) && (s->type != at_temp)) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
+ YYERROR;
+ }
+
+ switch (s->type) {
+ case at_temp:
+ set_dst_reg(& (yyval.dst_reg), PROGRAM_TEMPORARY, s->temp_binding);
+ break;
+ case at_output:
+ set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, s->output_binding);
+ break;
+ default:
+ set_dst_reg(& (yyval.dst_reg), s->param_binding_type, s->param_binding_begin);
+ break;
+ }
+ ;}
+ break;
+
+ case 66:
+
+/* Line 1455 of yacc.c */
+#line 892 "program_parse.y"
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
+
+ free((yyvsp[(1) - (1)].string));
+
+ if (s == NULL) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type != at_param) || !s->param_is_array) {
+ yyerror(& (yylsp[(1) - (1)]), state, "array access to non-PARAM variable");
+ YYERROR;
+ } else {
+ (yyval.sym) = s;
+ }
+ ;}
+ break;
+
+ case 69:
+
+/* Line 1455 of yacc.c */
+#line 913 "program_parse.y"
+ {
+ init_src_reg(& (yyval.src_reg));
+ (yyval.src_reg).Base.Index = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 70:
+
+/* Line 1455 of yacc.c */
+#line 920 "program_parse.y"
+ {
+ /* FINISHME: Add support for multiple address registers.
+ */
+ /* FINISHME: Add support for 4-component address registers.
+ */
+ init_src_reg(& (yyval.src_reg));
+ (yyval.src_reg).Base.RelAddr = 1;
+ (yyval.src_reg).Base.Index = (yyvsp[(3) - (3)].integer);
+ ;}
+ break;
+
+ case 71:
+
+/* Line 1455 of yacc.c */
+#line 931 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 72:
+
+/* Line 1455 of yacc.c */
+#line 932 "program_parse.y"
+ { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;}
+ break;
+
+ case 73:
+
+/* Line 1455 of yacc.c */
+#line 933 "program_parse.y"
+ { (yyval.integer) = -(yyvsp[(2) - (2)].integer); ;}
+ break;
+
+ case 74:
+
+/* Line 1455 of yacc.c */
+#line 937 "program_parse.y"
+ {
+ if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 4095)) {
+ char s[100];
+ _mesa_snprintf(s, sizeof(s),
+ "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer));
+ yyerror(& (yylsp[(1) - (1)]), state, s);
+ YYERROR;
+ } else {
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ }
+ ;}
+ break;
+
+ case 75:
+
+/* Line 1455 of yacc.c */
+#line 951 "program_parse.y"
+ {
+ if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 4096)) {
+ char s[100];
+ _mesa_snprintf(s, sizeof(s),
+ "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer));
+ yyerror(& (yylsp[(1) - (1)]), state, s);
+ YYERROR;
+ } else {
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ }
+ ;}
+ break;
+
+ case 76:
+
+/* Line 1455 of yacc.c */
+#line 965 "program_parse.y"
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string));
+
+ free((yyvsp[(1) - (1)].string));
+
+ if (s == NULL) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid array member");
+ YYERROR;
+ } else if (s->type != at_address) {
+ yyerror(& (yylsp[(1) - (1)]), state,
+ "invalid variable for indexed array access");
+ YYERROR;
+ } else {
+ (yyval.sym) = s;
+ }
+ ;}
+ break;
+
+ case 77:
+
+/* Line 1455 of yacc.c */
+#line 985 "program_parse.y"
+ {
+ if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid address component selector");
+ YYERROR;
+ } else {
+ (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask);
+ }
+ ;}
+ break;
+
+ case 78:
+
+/* Line 1455 of yacc.c */
+#line 996 "program_parse.y"
+ {
+ if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) {
+ yyerror(& (yylsp[(1) - (1)]), state,
+ "address register write mask must be \".x\"");
+ YYERROR;
+ } else {
+ (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask);
+ }
+ ;}
+ break;
+
+ case 83:
+
+/* Line 1455 of yacc.c */
+#line 1012 "program_parse.y"
+ { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;}
+ break;
+
+ case 88:
+
+/* Line 1455 of yacc.c */
+#line 1016 "program_parse.y"
+ { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;}
+ break;
+
+ case 89:
+
+/* Line 1455 of yacc.c */
+#line 1020 "program_parse.y"
+ {
+ (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg);
+ ;}
+ break;
+
+ case 90:
+
+/* Line 1455 of yacc.c */
+#line 1024 "program_parse.y"
+ {
+ (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg);
+ ;}
+ break;
+
+ case 91:
+
+/* Line 1455 of yacc.c */
+#line 1028 "program_parse.y"
+ {
+ (yyval.dst_reg).CondMask = COND_TR;
+ (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP;
+ (yyval.dst_reg).CondSrc = 0;
+ ;}
+ break;
+
+ case 92:
+
+/* Line 1455 of yacc.c */
+#line 1036 "program_parse.y"
+ {
+ (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg);
+ (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle;
+ ;}
+ break;
+
+ case 93:
+
+/* Line 1455 of yacc.c */
+#line 1043 "program_parse.y"
+ {
+ (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg);
+ (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle;
+ ;}
+ break;
+
+ case 94:
+
+/* Line 1455 of yacc.c */
+#line 1050 "program_parse.y"
+ {
+ const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string));
+ if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) {
+ char *const err_str =
+ make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string));
+
+ yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL)
+ ? err_str : "invalid condition code");
+
+ if (err_str != NULL) {
+ free(err_str);
+ }
+
+ YYERROR;
+ }
+
+ (yyval.dst_reg).CondMask = cond;
+ (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP;
+ (yyval.dst_reg).CondSrc = 0;
+ ;}
+ break;
+
+ case 95:
+
+/* Line 1455 of yacc.c */
+#line 1073 "program_parse.y"
+ {
+ const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string));
+ if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) {
+ char *const err_str =
+ make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string));
+
+ yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL)
+ ? err_str : "invalid condition code");
+
+ if (err_str != NULL) {
+ free(err_str);
+ }
+
+ YYERROR;
+ }
+
+ (yyval.dst_reg).CondMask = cond;
+ (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP;
+ (yyval.dst_reg).CondSrc = 0;
+ ;}
+ break;
+
+ case 102:
+
+/* Line 1455 of yacc.c */
+#line 1104 "program_parse.y"
+ {
+ struct asm_symbol *const s =
+ declare_variable(state, (yyvsp[(2) - (4)].string), at_attrib, & (yylsp[(2) - (4)]));
+
+ if (s == NULL) {
+ free((yyvsp[(2) - (4)].string));
+ YYERROR;
+ } else {
+ s->attrib_binding = (yyvsp[(4) - (4)].attrib);
+ state->InputsBound |= (1U << s->attrib_binding);
+
+ if (!validate_inputs(& (yylsp[(4) - (4)]), state)) {
+ YYERROR;
+ }
+ }
+ ;}
+ break;
+
+ case 103:
+
+/* Line 1455 of yacc.c */
+#line 1123 "program_parse.y"
+ {
+ (yyval.attrib) = (yyvsp[(2) - (2)].attrib);
+ ;}
+ break;
+
+ case 104:
+
+/* Line 1455 of yacc.c */
+#line 1127 "program_parse.y"
+ {
+ (yyval.attrib) = (yyvsp[(2) - (2)].attrib);
+ ;}
+ break;
+
+ case 105:
+
+/* Line 1455 of yacc.c */
+#line 1133 "program_parse.y"
+ {
+ (yyval.attrib) = VERT_ATTRIB_POS;
+ ;}
+ break;
+
+ case 106:
+
+/* Line 1455 of yacc.c */
+#line 1137 "program_parse.y"
+ {
+ (yyval.attrib) = VERT_ATTRIB_WEIGHT;
+ ;}
+ break;
+
+ case 107:
+
+/* Line 1455 of yacc.c */
+#line 1141 "program_parse.y"
+ {
+ (yyval.attrib) = VERT_ATTRIB_NORMAL;
+ ;}
+ break;
+
+ case 108:
+
+/* Line 1455 of yacc.c */
+#line 1145 "program_parse.y"
+ {
+ if (!state->ctx->Extensions.EXT_secondary_color) {
+ yyerror(& (yylsp[(2) - (2)]), state, "GL_EXT_secondary_color not supported");
+ YYERROR;
+ }
+
+ (yyval.attrib) = VERT_ATTRIB_COLOR0 + (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 109:
+
+/* Line 1455 of yacc.c */
+#line 1154 "program_parse.y"
+ {
+ if (!state->ctx->Extensions.EXT_fog_coord) {
+ yyerror(& (yylsp[(1) - (1)]), state, "GL_EXT_fog_coord not supported");
+ YYERROR;
+ }
+
+ (yyval.attrib) = VERT_ATTRIB_FOG;
+ ;}
+ break;
+
+ case 110:
+
+/* Line 1455 of yacc.c */
+#line 1163 "program_parse.y"
+ {
+ (yyval.attrib) = VERT_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 111:
+
+/* Line 1455 of yacc.c */
+#line 1167 "program_parse.y"
+ {
+ yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported");
+ YYERROR;
+ ;}
+ break;
+
+ case 112:
+
+/* Line 1455 of yacc.c */
+#line 1172 "program_parse.y"
+ {
+ (yyval.attrib) = VERT_ATTRIB_GENERIC0 + (yyvsp[(3) - (4)].integer);
+ ;}
+ break;
+
+ case 113:
+
+/* Line 1455 of yacc.c */
+#line 1178 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxAttribs) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex attribute reference");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 117:
+
+/* Line 1455 of yacc.c */
+#line 1192 "program_parse.y"
+ {
+ (yyval.attrib) = FRAG_ATTRIB_WPOS;
+ ;}
+ break;
+
+ case 118:
+
+/* Line 1455 of yacc.c */
+#line 1196 "program_parse.y"
+ {
+ (yyval.attrib) = FRAG_ATTRIB_COL0 + (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 119:
+
+/* Line 1455 of yacc.c */
+#line 1200 "program_parse.y"
+ {
+ (yyval.attrib) = FRAG_ATTRIB_FOGC;
+ ;}
+ break;
+
+ case 120:
+
+/* Line 1455 of yacc.c */
+#line 1204 "program_parse.y"
+ {
+ (yyval.attrib) = FRAG_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 123:
+
+/* Line 1455 of yacc.c */
+#line 1212 "program_parse.y"
+ {
+ struct asm_symbol *const s =
+ declare_variable(state, (yyvsp[(2) - (3)].string), at_param, & (yylsp[(2) - (3)]));
+
+ if (s == NULL) {
+ free((yyvsp[(2) - (3)].string));
+ YYERROR;
+ } else {
+ s->param_binding_type = (yyvsp[(3) - (3)].temp_sym).param_binding_type;
+ s->param_binding_begin = (yyvsp[(3) - (3)].temp_sym).param_binding_begin;
+ s->param_binding_length = (yyvsp[(3) - (3)].temp_sym).param_binding_length;
+ s->param_binding_swizzle = (yyvsp[(3) - (3)].temp_sym).param_binding_swizzle;
+ s->param_is_array = 0;
+ }
+ ;}
+ break;
+
+ case 124:
+
+/* Line 1455 of yacc.c */
+#line 1230 "program_parse.y"
+ {
+ if (((yyvsp[(4) - (6)].integer) != 0) && ((unsigned) (yyvsp[(4) - (6)].integer) != (yyvsp[(6) - (6)].temp_sym).param_binding_length)) {
+ free((yyvsp[(2) - (6)].string));
+ yyerror(& (yylsp[(4) - (6)]), state,
+ "parameter array size and number of bindings must match");
+ YYERROR;
+ } else {
+ struct asm_symbol *const s =
+ declare_variable(state, (yyvsp[(2) - (6)].string), (yyvsp[(6) - (6)].temp_sym).type, & (yylsp[(2) - (6)]));
+
+ if (s == NULL) {
+ free((yyvsp[(2) - (6)].string));
+ YYERROR;
+ } else {
+ s->param_binding_type = (yyvsp[(6) - (6)].temp_sym).param_binding_type;
+ s->param_binding_begin = (yyvsp[(6) - (6)].temp_sym).param_binding_begin;
+ s->param_binding_length = (yyvsp[(6) - (6)].temp_sym).param_binding_length;
+ s->param_binding_swizzle = SWIZZLE_XYZW;
+ s->param_is_array = 1;
+ }
+ }
+ ;}
+ break;
+
+ case 125:
+
+/* Line 1455 of yacc.c */
+#line 1255 "program_parse.y"
+ {
+ (yyval.integer) = 0;
+ ;}
+ break;
+
+ case 126:
+
+/* Line 1455 of yacc.c */
+#line 1259 "program_parse.y"
+ {
+ if (((yyvsp[(1) - (1)].integer) < 1) || ((unsigned) (yyvsp[(1) - (1)].integer) > state->limits->MaxParameters)) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid parameter array size");
+ YYERROR;
+ } else {
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ }
+ ;}
+ break;
+
+ case 127:
+
+/* Line 1455 of yacc.c */
+#line 1270 "program_parse.y"
+ {
+ (yyval.temp_sym) = (yyvsp[(2) - (2)].temp_sym);
+ ;}
+ break;
+
+ case 128:
+
+/* Line 1455 of yacc.c */
+#line 1276 "program_parse.y"
+ {
+ (yyval.temp_sym) = (yyvsp[(3) - (4)].temp_sym);
+ ;}
+ break;
+
+ case 130:
+
+/* Line 1455 of yacc.c */
+#line 1283 "program_parse.y"
+ {
+ (yyvsp[(1) - (3)].temp_sym).param_binding_length += (yyvsp[(3) - (3)].temp_sym).param_binding_length;
+ (yyval.temp_sym) = (yyvsp[(1) - (3)].temp_sym);
+ ;}
+ break;
+
+ case 131:
+
+/* Line 1455 of yacc.c */
+#line 1290 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
+ ;}
+ break;
+
+ case 132:
+
+/* Line 1455 of yacc.c */
+#line 1296 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
+ ;}
+ break;
+
+ case 133:
+
+/* Line 1455 of yacc.c */
+#line 1302 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE);
+ ;}
+ break;
+
+ case 134:
+
+/* Line 1455 of yacc.c */
+#line 1310 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
+ ;}
+ break;
+
+ case 135:
+
+/* Line 1455 of yacc.c */
+#line 1316 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
+ ;}
+ break;
+
+ case 136:
+
+/* Line 1455 of yacc.c */
+#line 1322 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE);
+ ;}
+ break;
+
+ case 137:
+
+/* Line 1455 of yacc.c */
+#line 1330 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
+ ;}
+ break;
+
+ case 138:
+
+/* Line 1455 of yacc.c */
+#line 1336 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state));
+ ;}
+ break;
+
+ case 139:
+
+/* Line 1455 of yacc.c */
+#line 1342 "program_parse.y"
+ {
+ memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym)));
+ (yyval.temp_sym).param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_FALSE);
+ ;}
+ break;
+
+ case 140:
+
+/* Line 1455 of yacc.c */
+#line 1349 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(1) - (1)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 141:
+
+/* Line 1455 of yacc.c */
+#line 1350 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 142:
+
+/* Line 1455 of yacc.c */
+#line 1353 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 143:
+
+/* Line 1455 of yacc.c */
+#line 1354 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 144:
+
+/* Line 1455 of yacc.c */
+#line 1355 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 145:
+
+/* Line 1455 of yacc.c */
+#line 1356 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 146:
+
+/* Line 1455 of yacc.c */
+#line 1357 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 147:
+
+/* Line 1455 of yacc.c */
+#line 1358 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 148:
+
+/* Line 1455 of yacc.c */
+#line 1359 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 149:
+
+/* Line 1455 of yacc.c */
+#line 1360 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 150:
+
+/* Line 1455 of yacc.c */
+#line 1361 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 151:
+
+/* Line 1455 of yacc.c */
+#line 1362 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 152:
+
+/* Line 1455 of yacc.c */
+#line 1363 "program_parse.y"
+ { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;}
+ break;
+
+ case 153:
+
+/* Line 1455 of yacc.c */
+#line 1367 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_MATERIAL;
+ (yyval.state)[1] = (yyvsp[(2) - (3)].integer);
+ (yyval.state)[2] = (yyvsp[(3) - (3)].integer);
+ ;}
+ break;
+
+ case 154:
+
+/* Line 1455 of yacc.c */
+#line 1376 "program_parse.y"
+ {
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 155:
+
+/* Line 1455 of yacc.c */
+#line 1380 "program_parse.y"
+ {
+ (yyval.integer) = STATE_EMISSION;
+ ;}
+ break;
+
+ case 156:
+
+/* Line 1455 of yacc.c */
+#line 1384 "program_parse.y"
+ {
+ (yyval.integer) = STATE_SHININESS;
+ ;}
+ break;
+
+ case 157:
+
+/* Line 1455 of yacc.c */
+#line 1390 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_LIGHT;
+ (yyval.state)[1] = (yyvsp[(3) - (5)].integer);
+ (yyval.state)[2] = (yyvsp[(5) - (5)].integer);
+ ;}
+ break;
+
+ case 158:
+
+/* Line 1455 of yacc.c */
+#line 1399 "program_parse.y"
+ {
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 159:
+
+/* Line 1455 of yacc.c */
+#line 1403 "program_parse.y"
+ {
+ (yyval.integer) = STATE_POSITION;
+ ;}
+ break;
+
+ case 160:
+
+/* Line 1455 of yacc.c */
+#line 1407 "program_parse.y"
+ {
+ if (!state->ctx->Extensions.EXT_point_parameters) {
+ yyerror(& (yylsp[(1) - (1)]), state, "GL_ARB_point_parameters not supported");
+ YYERROR;
+ }
+
+ (yyval.integer) = STATE_ATTENUATION;
+ ;}
+ break;
+
+ case 161:
+
+/* Line 1455 of yacc.c */
+#line 1416 "program_parse.y"
+ {
+ (yyval.integer) = (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 162:
+
+/* Line 1455 of yacc.c */
+#line 1420 "program_parse.y"
+ {
+ (yyval.integer) = STATE_HALF_VECTOR;
+ ;}
+ break;
+
+ case 163:
+
+/* Line 1455 of yacc.c */
+#line 1426 "program_parse.y"
+ {
+ (yyval.integer) = STATE_SPOT_DIRECTION;
+ ;}
+ break;
+
+ case 164:
+
+/* Line 1455 of yacc.c */
+#line 1432 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(2) - (2)].state)[0];
+ (yyval.state)[1] = (yyvsp[(2) - (2)].state)[1];
+ ;}
+ break;
+
+ case 165:
+
+/* Line 1455 of yacc.c */
+#line 1439 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_LIGHTMODEL_AMBIENT;
+ ;}
+ break;
+
+ case 166:
+
+/* Line 1455 of yacc.c */
+#line 1444 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_LIGHTMODEL_SCENECOLOR;
+ (yyval.state)[1] = (yyvsp[(1) - (2)].integer);
+ ;}
+ break;
+
+ case 167:
+
+/* Line 1455 of yacc.c */
+#line 1452 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_LIGHTPROD;
+ (yyval.state)[1] = (yyvsp[(3) - (6)].integer);
+ (yyval.state)[2] = (yyvsp[(5) - (6)].integer);
+ (yyval.state)[3] = (yyvsp[(6) - (6)].integer);
+ ;}
+ break;
+
+ case 169:
+
+/* Line 1455 of yacc.c */
+#line 1464 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = (yyvsp[(3) - (3)].integer);
+ (yyval.state)[1] = (yyvsp[(2) - (3)].integer);
+ ;}
+ break;
+
+ case 170:
+
+/* Line 1455 of yacc.c */
+#line 1472 "program_parse.y"
+ {
+ (yyval.integer) = STATE_TEXENV_COLOR;
+ ;}
+ break;
+
+ case 171:
+
+/* Line 1455 of yacc.c */
+#line 1478 "program_parse.y"
+ {
+ (yyval.integer) = STATE_AMBIENT;
+ ;}
+ break;
+
+ case 172:
+
+/* Line 1455 of yacc.c */
+#line 1482 "program_parse.y"
+ {
+ (yyval.integer) = STATE_DIFFUSE;
+ ;}
+ break;
+
+ case 173:
+
+/* Line 1455 of yacc.c */
+#line 1486 "program_parse.y"
+ {
+ (yyval.integer) = STATE_SPECULAR;
+ ;}
+ break;
+
+ case 174:
+
+/* Line 1455 of yacc.c */
+#line 1492 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxLights) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid light selector");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 175:
+
+/* Line 1455 of yacc.c */
+#line 1503 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_TEXGEN;
+ (yyval.state)[1] = (yyvsp[(2) - (4)].integer);
+ (yyval.state)[2] = (yyvsp[(3) - (4)].integer) + (yyvsp[(4) - (4)].integer);
+ ;}
+ break;
+
+ case 176:
+
+/* Line 1455 of yacc.c */
+#line 1512 "program_parse.y"
+ {
+ (yyval.integer) = STATE_TEXGEN_EYE_S;
+ ;}
+ break;
+
+ case 177:
+
+/* Line 1455 of yacc.c */
+#line 1516 "program_parse.y"
+ {
+ (yyval.integer) = STATE_TEXGEN_OBJECT_S;
+ ;}
+ break;
+
+ case 178:
+
+/* Line 1455 of yacc.c */
+#line 1521 "program_parse.y"
+ {
+ (yyval.integer) = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S;
+ ;}
+ break;
+
+ case 179:
+
+/* Line 1455 of yacc.c */
+#line 1525 "program_parse.y"
+ {
+ (yyval.integer) = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S;
+ ;}
+ break;
+
+ case 180:
+
+/* Line 1455 of yacc.c */
+#line 1529 "program_parse.y"
+ {
+ (yyval.integer) = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S;
+ ;}
+ break;
+
+ case 181:
+
+/* Line 1455 of yacc.c */
+#line 1533 "program_parse.y"
+ {
+ (yyval.integer) = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S;
+ ;}
+ break;
+
+ case 182:
+
+/* Line 1455 of yacc.c */
+#line 1539 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 183:
+
+/* Line 1455 of yacc.c */
+#line 1546 "program_parse.y"
+ {
+ (yyval.integer) = STATE_FOG_COLOR;
+ ;}
+ break;
+
+ case 184:
+
+/* Line 1455 of yacc.c */
+#line 1550 "program_parse.y"
+ {
+ (yyval.integer) = STATE_FOG_PARAMS;
+ ;}
+ break;
+
+ case 185:
+
+/* Line 1455 of yacc.c */
+#line 1556 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_CLIPPLANE;
+ (yyval.state)[1] = (yyvsp[(3) - (5)].integer);
+ ;}
+ break;
+
+ case 186:
+
+/* Line 1455 of yacc.c */
+#line 1564 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxClipPlanes) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid clip plane selector");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 187:
+
+/* Line 1455 of yacc.c */
+#line 1575 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 188:
+
+/* Line 1455 of yacc.c */
+#line 1582 "program_parse.y"
+ {
+ (yyval.integer) = STATE_POINT_SIZE;
+ ;}
+ break;
+
+ case 189:
+
+/* Line 1455 of yacc.c */
+#line 1586 "program_parse.y"
+ {
+ (yyval.integer) = STATE_POINT_ATTENUATION;
+ ;}
+ break;
+
+ case 190:
+
+/* Line 1455 of yacc.c */
+#line 1592 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(1) - (5)].state)[0];
+ (yyval.state)[1] = (yyvsp[(1) - (5)].state)[1];
+ (yyval.state)[2] = (yyvsp[(4) - (5)].integer);
+ (yyval.state)[3] = (yyvsp[(4) - (5)].integer);
+ (yyval.state)[4] = (yyvsp[(1) - (5)].state)[2];
+ ;}
+ break;
+
+ case 191:
+
+/* Line 1455 of yacc.c */
+#line 1602 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(1) - (2)].state)[0];
+ (yyval.state)[1] = (yyvsp[(1) - (2)].state)[1];
+ (yyval.state)[2] = (yyvsp[(2) - (2)].state)[2];
+ (yyval.state)[3] = (yyvsp[(2) - (2)].state)[3];
+ (yyval.state)[4] = (yyvsp[(1) - (2)].state)[2];
+ ;}
+ break;
+
+ case 192:
+
+/* Line 1455 of yacc.c */
+#line 1612 "program_parse.y"
+ {
+ (yyval.state)[2] = 0;
+ (yyval.state)[3] = 3;
+ ;}
+ break;
+
+ case 193:
+
+/* Line 1455 of yacc.c */
+#line 1617 "program_parse.y"
+ {
+ /* It seems logical that the matrix row range specifier would have
+ * to specify a range or more than one row (i.e., $5 > $3).
+ * However, the ARB_vertex_program spec says "a program will fail
+ * to load if <a> is greater than <b>." This means that $3 == $5
+ * is valid.
+ */
+ if ((yyvsp[(3) - (6)].integer) > (yyvsp[(5) - (6)].integer)) {
+ yyerror(& (yylsp[(3) - (6)]), state, "invalid matrix row range");
+ YYERROR;
+ }
+
+ (yyval.state)[2] = (yyvsp[(3) - (6)].integer);
+ (yyval.state)[3] = (yyvsp[(5) - (6)].integer);
+ ;}
+ break;
+
+ case 194:
+
+/* Line 1455 of yacc.c */
+#line 1635 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(2) - (3)].state)[0];
+ (yyval.state)[1] = (yyvsp[(2) - (3)].state)[1];
+ (yyval.state)[2] = (yyvsp[(3) - (3)].integer);
+ ;}
+ break;
+
+ case 195:
+
+/* Line 1455 of yacc.c */
+#line 1643 "program_parse.y"
+ {
+ (yyval.integer) = 0;
+ ;}
+ break;
+
+ case 196:
+
+/* Line 1455 of yacc.c */
+#line 1647 "program_parse.y"
+ {
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 197:
+
+/* Line 1455 of yacc.c */
+#line 1653 "program_parse.y"
+ {
+ (yyval.integer) = STATE_MATRIX_INVERSE;
+ ;}
+ break;
+
+ case 198:
+
+/* Line 1455 of yacc.c */
+#line 1657 "program_parse.y"
+ {
+ (yyval.integer) = STATE_MATRIX_TRANSPOSE;
+ ;}
+ break;
+
+ case 199:
+
+/* Line 1455 of yacc.c */
+#line 1661 "program_parse.y"
+ {
+ (yyval.integer) = STATE_MATRIX_INVTRANS;
+ ;}
+ break;
+
+ case 200:
+
+/* Line 1455 of yacc.c */
+#line 1667 "program_parse.y"
+ {
+ if ((yyvsp[(1) - (1)].integer) > 3) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid matrix row reference");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 201:
+
+/* Line 1455 of yacc.c */
+#line 1678 "program_parse.y"
+ {
+ (yyval.state)[0] = STATE_MODELVIEW_MATRIX;
+ (yyval.state)[1] = (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 202:
+
+/* Line 1455 of yacc.c */
+#line 1683 "program_parse.y"
+ {
+ (yyval.state)[0] = STATE_PROJECTION_MATRIX;
+ (yyval.state)[1] = 0;
+ ;}
+ break;
+
+ case 203:
+
+/* Line 1455 of yacc.c */
+#line 1688 "program_parse.y"
+ {
+ (yyval.state)[0] = STATE_MVP_MATRIX;
+ (yyval.state)[1] = 0;
+ ;}
+ break;
+
+ case 204:
+
+/* Line 1455 of yacc.c */
+#line 1693 "program_parse.y"
+ {
+ (yyval.state)[0] = STATE_TEXTURE_MATRIX;
+ (yyval.state)[1] = (yyvsp[(2) - (2)].integer);
+ ;}
+ break;
+
+ case 205:
+
+/* Line 1455 of yacc.c */
+#line 1698 "program_parse.y"
+ {
+ yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported");
+ YYERROR;
+ ;}
+ break;
+
+ case 206:
+
+/* Line 1455 of yacc.c */
+#line 1703 "program_parse.y"
+ {
+ (yyval.state)[0] = STATE_PROGRAM_MATRIX;
+ (yyval.state)[1] = (yyvsp[(3) - (4)].integer);
+ ;}
+ break;
+
+ case 207:
+
+/* Line 1455 of yacc.c */
+#line 1710 "program_parse.y"
+ {
+ (yyval.integer) = 0;
+ ;}
+ break;
+
+ case 208:
+
+/* Line 1455 of yacc.c */
+#line 1714 "program_parse.y"
+ {
+ (yyval.integer) = (yyvsp[(2) - (3)].integer);
+ ;}
+ break;
+
+ case 209:
+
+/* Line 1455 of yacc.c */
+#line 1719 "program_parse.y"
+ {
+ /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix
+ * zero is valid.
+ */
+ if ((yyvsp[(1) - (1)].integer) != 0) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid modelview matrix index");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 210:
+
+/* Line 1455 of yacc.c */
+#line 1732 "program_parse.y"
+ {
+ /* Since GL_ARB_matrix_palette isn't supported, just let any value
+ * through here. The error will be generated later.
+ */
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 211:
+
+/* Line 1455 of yacc.c */
+#line 1740 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxProgramMatrices) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid program matrix selector");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 212:
+
+/* Line 1455 of yacc.c */
+#line 1751 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = STATE_DEPTH_RANGE;
+ ;}
+ break;
+
+ case 217:
+
+/* Line 1455 of yacc.c */
+#line 1763 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = state->state_param_enum;
+ (yyval.state)[1] = STATE_ENV;
+ (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0];
+ (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1];
+ ;}
+ break;
+
+ case 218:
+
+/* Line 1455 of yacc.c */
+#line 1773 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(1) - (1)].integer);
+ (yyval.state)[1] = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 219:
+
+/* Line 1455 of yacc.c */
+#line 1778 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(1) - (3)].integer);
+ (yyval.state)[1] = (yyvsp[(3) - (3)].integer);
+ ;}
+ break;
+
+ case 220:
+
+/* Line 1455 of yacc.c */
+#line 1785 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = state->state_param_enum;
+ (yyval.state)[1] = STATE_ENV;
+ (yyval.state)[2] = (yyvsp[(4) - (5)].integer);
+ (yyval.state)[3] = (yyvsp[(4) - (5)].integer);
+ ;}
+ break;
+
+ case 221:
+
+/* Line 1455 of yacc.c */
+#line 1795 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = state->state_param_enum;
+ (yyval.state)[1] = STATE_LOCAL;
+ (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0];
+ (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1];
+ ;}
+ break;
+
+ case 222:
+
+/* Line 1455 of yacc.c */
+#line 1804 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(1) - (1)].integer);
+ (yyval.state)[1] = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 223:
+
+/* Line 1455 of yacc.c */
+#line 1809 "program_parse.y"
+ {
+ (yyval.state)[0] = (yyvsp[(1) - (3)].integer);
+ (yyval.state)[1] = (yyvsp[(3) - (3)].integer);
+ ;}
+ break;
+
+ case 224:
+
+/* Line 1455 of yacc.c */
+#line 1816 "program_parse.y"
+ {
+ memset((yyval.state), 0, sizeof((yyval.state)));
+ (yyval.state)[0] = state->state_param_enum;
+ (yyval.state)[1] = STATE_LOCAL;
+ (yyval.state)[2] = (yyvsp[(4) - (5)].integer);
+ (yyval.state)[3] = (yyvsp[(4) - (5)].integer);
+ ;}
+ break;
+
+ case 225:
+
+/* Line 1455 of yacc.c */
+#line 1826 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxEnvParams) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid environment parameter reference");
+ YYERROR;
+ }
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 226:
+
+/* Line 1455 of yacc.c */
+#line 1836 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxLocalParams) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid local parameter reference");
+ YYERROR;
+ }
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 231:
+
+/* Line 1455 of yacc.c */
+#line 1851 "program_parse.y"
+ {
+ (yyval.vector).count = 4;
+ (yyval.vector).data[0] = (yyvsp[(1) - (1)].real);
+ (yyval.vector).data[1] = (yyvsp[(1) - (1)].real);
+ (yyval.vector).data[2] = (yyvsp[(1) - (1)].real);
+ (yyval.vector).data[3] = (yyvsp[(1) - (1)].real);
+ ;}
+ break;
+
+ case 232:
+
+/* Line 1455 of yacc.c */
+#line 1861 "program_parse.y"
+ {
+ (yyval.vector).count = 1;
+ (yyval.vector).data[0] = (yyvsp[(1) - (1)].real);
+ (yyval.vector).data[1] = (yyvsp[(1) - (1)].real);
+ (yyval.vector).data[2] = (yyvsp[(1) - (1)].real);
+ (yyval.vector).data[3] = (yyvsp[(1) - (1)].real);
+ ;}
+ break;
+
+ case 233:
+
+/* Line 1455 of yacc.c */
+#line 1869 "program_parse.y"
+ {
+ (yyval.vector).count = 1;
+ (yyval.vector).data[0] = (float) (yyvsp[(1) - (1)].integer);
+ (yyval.vector).data[1] = (float) (yyvsp[(1) - (1)].integer);
+ (yyval.vector).data[2] = (float) (yyvsp[(1) - (1)].integer);
+ (yyval.vector).data[3] = (float) (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 234:
+
+/* Line 1455 of yacc.c */
+#line 1879 "program_parse.y"
+ {
+ (yyval.vector).count = 4;
+ (yyval.vector).data[0] = (yyvsp[(2) - (3)].real);
+ (yyval.vector).data[1] = 0.0f;
+ (yyval.vector).data[2] = 0.0f;
+ (yyval.vector).data[3] = 1.0f;
+ ;}
+ break;
+
+ case 235:
+
+/* Line 1455 of yacc.c */
+#line 1887 "program_parse.y"
+ {
+ (yyval.vector).count = 4;
+ (yyval.vector).data[0] = (yyvsp[(2) - (5)].real);
+ (yyval.vector).data[1] = (yyvsp[(4) - (5)].real);
+ (yyval.vector).data[2] = 0.0f;
+ (yyval.vector).data[3] = 1.0f;
+ ;}
+ break;
+
+ case 236:
+
+/* Line 1455 of yacc.c */
+#line 1896 "program_parse.y"
+ {
+ (yyval.vector).count = 4;
+ (yyval.vector).data[0] = (yyvsp[(2) - (7)].real);
+ (yyval.vector).data[1] = (yyvsp[(4) - (7)].real);
+ (yyval.vector).data[2] = (yyvsp[(6) - (7)].real);
+ (yyval.vector).data[3] = 1.0f;
+ ;}
+ break;
+
+ case 237:
+
+/* Line 1455 of yacc.c */
+#line 1905 "program_parse.y"
+ {
+ (yyval.vector).count = 4;
+ (yyval.vector).data[0] = (yyvsp[(2) - (9)].real);
+ (yyval.vector).data[1] = (yyvsp[(4) - (9)].real);
+ (yyval.vector).data[2] = (yyvsp[(6) - (9)].real);
+ (yyval.vector).data[3] = (yyvsp[(8) - (9)].real);
+ ;}
+ break;
+
+ case 238:
+
+/* Line 1455 of yacc.c */
+#line 1915 "program_parse.y"
+ {
+ (yyval.real) = ((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].real) : (yyvsp[(2) - (2)].real);
+ ;}
+ break;
+
+ case 239:
+
+/* Line 1455 of yacc.c */
+#line 1919 "program_parse.y"
+ {
+ (yyval.real) = (float)(((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].integer) : (yyvsp[(2) - (2)].integer));
+ ;}
+ break;
+
+ case 240:
+
+/* Line 1455 of yacc.c */
+#line 1924 "program_parse.y"
+ { (yyval.negate) = FALSE; ;}
+ break;
+
+ case 241:
+
+/* Line 1455 of yacc.c */
+#line 1925 "program_parse.y"
+ { (yyval.negate) = TRUE; ;}
+ break;
+
+ case 242:
+
+/* Line 1455 of yacc.c */
+#line 1926 "program_parse.y"
+ { (yyval.negate) = FALSE; ;}
+ break;
+
+ case 243:
+
+/* Line 1455 of yacc.c */
+#line 1929 "program_parse.y"
+ { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;}
+ break;
+
+ case 245:
+
+/* Line 1455 of yacc.c */
+#line 1933 "program_parse.y"
+ {
+ /* NV_fragment_program_option defines the size qualifiers in a
+ * fairly broken way. "SHORT" or "LONG" can optionally be used
+ * before TEMP or OUTPUT. However, neither is a reserved word!
+ * This means that we have to parse it as an identifier, then check
+ * to make sure it's one of the valid values. *sigh*
+ *
+ * In addition, the grammar in the extension spec does *not* allow
+ * the size specifier to be optional, but all known implementations
+ * do.
+ */
+ if (!state->option.NV_fragment) {
+ yyerror(& (yylsp[(1) - (1)]), state, "unexpected IDENTIFIER");
+ YYERROR;
+ }
+
+ if (strcmp("SHORT", (yyvsp[(1) - (1)].string)) == 0) {
+ } else if (strcmp("LONG", (yyvsp[(1) - (1)].string)) == 0) {
+ } else {
+ char *const err_str =
+ make_error_string("invalid storage size specifier \"%s\"",
+ (yyvsp[(1) - (1)].string));
+
+ yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL)
+ ? err_str : "invalid storage size specifier");
+
+ if (err_str != NULL) {
+ free(err_str);
+ }
+
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 246:
+
+/* Line 1455 of yacc.c */
+#line 1967 "program_parse.y"
+ {
+ ;}
+ break;
+
+ case 247:
+
+/* Line 1455 of yacc.c */
+#line 1971 "program_parse.y"
+ { (yyval.integer) = (yyvsp[(1) - (1)].integer); ;}
+ break;
+
+ case 249:
+
+/* Line 1455 of yacc.c */
+#line 1975 "program_parse.y"
+ {
+ if (!declare_variable(state, (yyvsp[(3) - (3)].string), (yyvsp[(0) - (3)].integer), & (yylsp[(3) - (3)]))) {
+ free((yyvsp[(3) - (3)].string));
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 250:
+
+/* Line 1455 of yacc.c */
+#line 1982 "program_parse.y"
+ {
+ if (!declare_variable(state, (yyvsp[(1) - (1)].string), (yyvsp[(0) - (1)].integer), & (yylsp[(1) - (1)]))) {
+ free((yyvsp[(1) - (1)].string));
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 251:
+
+/* Line 1455 of yacc.c */
+#line 1991 "program_parse.y"
+ {
+ struct asm_symbol *const s =
+ declare_variable(state, (yyvsp[(3) - (5)].string), at_output, & (yylsp[(3) - (5)]));
+
+ if (s == NULL) {
+ free((yyvsp[(3) - (5)].string));
+ YYERROR;
+ } else {
+ s->output_binding = (yyvsp[(5) - (5)].result);
+ }
+ ;}
+ break;
+
+ case 252:
+
+/* Line 1455 of yacc.c */
+#line 2005 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.result) = VERT_RESULT_HPOS;
+ } else {
+ yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 253:
+
+/* Line 1455 of yacc.c */
+#line 2014 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.result) = VERT_RESULT_FOGC;
+ } else {
+ yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 254:
+
+/* Line 1455 of yacc.c */
+#line 2023 "program_parse.y"
+ {
+ (yyval.result) = (yyvsp[(2) - (2)].result);
+ ;}
+ break;
+
+ case 255:
+
+/* Line 1455 of yacc.c */
+#line 2027 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.result) = VERT_RESULT_PSIZ;
+ } else {
+ yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 256:
+
+/* Line 1455 of yacc.c */
+#line 2036 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.result) = VERT_RESULT_TEX0 + (yyvsp[(3) - (3)].integer);
+ } else {
+ yyerror(& (yylsp[(2) - (3)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 257:
+
+/* Line 1455 of yacc.c */
+#line 2045 "program_parse.y"
+ {
+ if (state->mode == ARB_fragment) {
+ (yyval.result) = FRAG_RESULT_DEPTH;
+ } else {
+ yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 258:
+
+/* Line 1455 of yacc.c */
+#line 2056 "program_parse.y"
+ {
+ (yyval.result) = (yyvsp[(2) - (3)].integer) + (yyvsp[(3) - (3)].integer);
+ ;}
+ break;
+
+ case 259:
+
+/* Line 1455 of yacc.c */
+#line 2062 "program_parse.y"
+ {
+ (yyval.integer) = (state->mode == ARB_vertex)
+ ? VERT_RESULT_COL0
+ : FRAG_RESULT_COLOR;
+ ;}
+ break;
+
+ case 260:
+
+/* Line 1455 of yacc.c */
+#line 2068 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.integer) = VERT_RESULT_COL0;
+ } else {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 261:
+
+/* Line 1455 of yacc.c */
+#line 2077 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.integer) = VERT_RESULT_BFC0;
+ } else {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 262:
+
+/* Line 1455 of yacc.c */
+#line 2088 "program_parse.y"
+ {
+ (yyval.integer) = 0;
+ ;}
+ break;
+
+ case 263:
+
+/* Line 1455 of yacc.c */
+#line 2092 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.integer) = 0;
+ } else {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 264:
+
+/* Line 1455 of yacc.c */
+#line 2101 "program_parse.y"
+ {
+ if (state->mode == ARB_vertex) {
+ (yyval.integer) = 1;
+ } else {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name");
+ YYERROR;
+ }
+ ;}
+ break;
+
+ case 265:
+
+/* Line 1455 of yacc.c */
+#line 2111 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 266:
+
+/* Line 1455 of yacc.c */
+#line 2112 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 267:
+
+/* Line 1455 of yacc.c */
+#line 2113 "program_parse.y"
+ { (yyval.integer) = 1; ;}
+ break;
+
+ case 268:
+
+/* Line 1455 of yacc.c */
+#line 2116 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 269:
+
+/* Line 1455 of yacc.c */
+#line 2117 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 270:
+
+/* Line 1455 of yacc.c */
+#line 2118 "program_parse.y"
+ { (yyval.integer) = 1; ;}
+ break;
+
+ case 271:
+
+/* Line 1455 of yacc.c */
+#line 2121 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 272:
+
+/* Line 1455 of yacc.c */
+#line 2122 "program_parse.y"
+ { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;}
+ break;
+
+ case 273:
+
+/* Line 1455 of yacc.c */
+#line 2125 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 274:
+
+/* Line 1455 of yacc.c */
+#line 2126 "program_parse.y"
+ { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;}
+ break;
+
+ case 275:
+
+/* Line 1455 of yacc.c */
+#line 2129 "program_parse.y"
+ { (yyval.integer) = 0; ;}
+ break;
+
+ case 276:
+
+/* Line 1455 of yacc.c */
+#line 2130 "program_parse.y"
+ { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;}
+ break;
+
+ case 277:
+
+/* Line 1455 of yacc.c */
+#line 2134 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureCoordUnits) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid texture coordinate unit selector");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 278:
+
+/* Line 1455 of yacc.c */
+#line 2145 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureImageUnits) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid texture image unit selector");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 279:
+
+/* Line 1455 of yacc.c */
+#line 2156 "program_parse.y"
+ {
+ if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureUnits) {
+ yyerror(& (yylsp[(1) - (1)]), state, "invalid texture unit selector");
+ YYERROR;
+ }
+
+ (yyval.integer) = (yyvsp[(1) - (1)].integer);
+ ;}
+ break;
+
+ case 280:
+
+/* Line 1455 of yacc.c */
+#line 2167 "program_parse.y"
+ {
+ struct asm_symbol *exist = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(2) - (4)].string));
+ struct asm_symbol *target = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(4) - (4)].string));
+
+ free((yyvsp[(4) - (4)].string));
+
+ if (exist != NULL) {
+ char m[1000];
+ _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", (yyvsp[(2) - (4)].string));
+ free((yyvsp[(2) - (4)].string));
+ yyerror(& (yylsp[(2) - (4)]), state, m);
+ YYERROR;
+ } else if (target == NULL) {
+ free((yyvsp[(2) - (4)].string));
+ yyerror(& (yylsp[(4) - (4)]), state,
+ "undefined variable binding in ALIAS statement");
+ YYERROR;
+ } else {
+ _mesa_symbol_table_add_symbol(state->st, 0, (yyvsp[(2) - (4)].string), target);
+ }
+ ;}
+ break;
+
+
+
+/* Line 1455 of yacc.c */
+#line 4938 "program_parse.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (&yylloc, state, YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (&yylloc, state, yymsg);
+ }
+ else
+ {
+ yyerror (&yylloc, state, YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+ yyerror_range[0] = yylloc;
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, &yylloc, state);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ yyerror_range[0] = yylsp[1-yylen];
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[0] = *yylsp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, yylsp, state);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+ yyerror_range[1] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+ the lookahead. YYLOC is available though. */
+ YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
+ *++yylsp = yyloc;
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, state, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc, state);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, yylsp, state);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+/* Line 1675 of yacc.c */
+#line 2196 "program_parse.y"
+
+
+void
+asm_instruction_set_operands(struct asm_instruction *inst,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ /* In the core ARB extensions only the KIL instruction doesn't have a
+ * destination register.
+ */
+ if (dst == NULL) {
+ init_dst_reg(& inst->Base.DstReg);
+ } else {
+ inst->Base.DstReg = *dst;
+ }
+
+ /* The only instruction that doesn't have any source registers is the
+ * condition-code based KIL instruction added by NV_fragment_program_option.
+ */
+ if (src0 != NULL) {
+ inst->Base.SrcReg[0] = src0->Base;
+ inst->SrcReg[0] = *src0;
+ } else {
+ init_src_reg(& inst->SrcReg[0]);
+ }
+
+ if (src1 != NULL) {
+ inst->Base.SrcReg[1] = src1->Base;
+ inst->SrcReg[1] = *src1;
+ } else {
+ init_src_reg(& inst->SrcReg[1]);
+ }
+
+ if (src2 != NULL) {
+ inst->Base.SrcReg[2] = src2->Base;
+ inst->SrcReg[2] = *src2;
+ } else {
+ init_src_reg(& inst->SrcReg[2]);
+ }
+}
+
+
+struct asm_instruction *
+asm_instruction_ctor(gl_inst_opcode op,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
+
+ if (inst) {
+ _mesa_init_instructions(& inst->Base, 1);
+ inst->Base.Opcode = op;
+
+ asm_instruction_set_operands(inst, dst, src0, src1, src2);
+ }
+
+ return inst;
+}
+
+
+struct asm_instruction *
+asm_instruction_copy_ctor(const struct prog_instruction *base,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
+
+ if (inst) {
+ _mesa_init_instructions(& inst->Base, 1);
+ inst->Base.Opcode = base->Opcode;
+ inst->Base.CondUpdate = base->CondUpdate;
+ inst->Base.CondDst = base->CondDst;
+ inst->Base.SaturateMode = base->SaturateMode;
+ inst->Base.Precision = base->Precision;
+
+ asm_instruction_set_operands(inst, dst, src0, src1, src2);
+ }
+
+ return inst;
+}
+
+
+void
+init_dst_reg(struct prog_dst_register *r)
+{
+ memset(r, 0, sizeof(*r));
+ r->File = PROGRAM_UNDEFINED;
+ r->WriteMask = WRITEMASK_XYZW;
+ r->CondMask = COND_TR;
+ r->CondSwizzle = SWIZZLE_NOOP;
+}
+
+
+/** Like init_dst_reg() but set the File and Index fields. */
+void
+set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index)
+{
+ const GLint maxIndex = 1 << INST_INDEX_BITS;
+ const GLint minIndex = 0;
+ ASSERT(index >= minIndex);
+ (void) minIndex;
+ ASSERT(index <= maxIndex);
+ (void) maxIndex;
+ ASSERT(file == PROGRAM_TEMPORARY ||
+ file == PROGRAM_ADDRESS ||
+ file == PROGRAM_OUTPUT);
+ memset(r, 0, sizeof(*r));
+ r->File = file;
+ r->Index = index;
+ r->WriteMask = WRITEMASK_XYZW;
+ r->CondMask = COND_TR;
+ r->CondSwizzle = SWIZZLE_NOOP;
+}
+
+
+void
+init_src_reg(struct asm_src_register *r)
+{
+ memset(r, 0, sizeof(*r));
+ r->Base.File = PROGRAM_UNDEFINED;
+ r->Base.Swizzle = SWIZZLE_NOOP;
+ r->Symbol = NULL;
+}
+
+
+/** Like init_src_reg() but set the File and Index fields.
+ * \return GL_TRUE if a valid src register, GL_FALSE otherwise
+ */
+void
+set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index)
+{
+ set_src_reg_swz(r, file, index, SWIZZLE_XYZW);
+}
+
+
+void
+set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index,
+ GLuint swizzle)
+{
+ const GLint maxIndex = (1 << INST_INDEX_BITS) - 1;
+ const GLint minIndex = -(1 << INST_INDEX_BITS);
+ ASSERT(file < PROGRAM_FILE_MAX);
+ ASSERT(index >= minIndex);
+ (void) minIndex;
+ ASSERT(index <= maxIndex);
+ (void) maxIndex;
+ memset(r, 0, sizeof(*r));
+ r->Base.File = file;
+ r->Base.Index = index;
+ r->Base.Swizzle = swizzle;
+ r->Symbol = NULL;
+}
+
+
+/**
+ * Validate the set of inputs used by a program
+ *
+ * Validates that legal sets of inputs are used by the program. In this case
+ * "used" included both reading the input or binding the input to a name using
+ * the \c ATTRIB command.
+ *
+ * \return
+ * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise.
+ */
+int
+validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state)
+{
+ const int inputs = state->prog->InputsRead | state->InputsBound;
+
+ if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) {
+ yyerror(locp, state, "illegal use of generic attribute and name attribute");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct asm_symbol *
+declare_variable(struct asm_parser_state *state, char *name, enum asm_type t,
+ struct YYLTYPE *locp)
+{
+ struct asm_symbol *s = NULL;
+ struct asm_symbol *exist = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, name);
+
+
+ if (exist != NULL) {
+ yyerror(locp, state, "redeclared identifier");
+ } else {
+ s = calloc(1, sizeof(struct asm_symbol));
+ s->name = name;
+ s->type = t;
+
+ switch (t) {
+ case at_temp:
+ if (state->prog->NumTemporaries >= state->limits->MaxTemps) {
+ yyerror(locp, state, "too many temporaries declared");
+ free(s);
+ return NULL;
+ }
+
+ s->temp_binding = state->prog->NumTemporaries;
+ state->prog->NumTemporaries++;
+ break;
+
+ case at_address:
+ if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) {
+ yyerror(locp, state, "too many address registers declared");
+ free(s);
+ return NULL;
+ }
+
+ /* FINISHME: Add support for multiple address registers.
+ */
+ state->prog->NumAddressRegs++;
+ break;
+
+ default:
+ break;
+ }
+
+ _mesa_symbol_table_add_symbol(state->st, 0, s->name, s);
+ s->next = state->sym;
+ state->sym = s;
+ }
+
+ return s;
+}
+
+
+int add_state_reference(struct gl_program_parameter_list *param_list,
+ const gl_state_index tokens[STATE_LENGTH])
+{
+ const GLuint size = 4; /* XXX fix */
+ char *name;
+ GLint index;
+
+ name = _mesa_program_state_string(tokens);
+ index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name,
+ size, GL_NONE, NULL, tokens, 0x0);
+ param_list->StateFlags |= _mesa_program_state_flags(tokens);
+
+ /* free name string here since we duplicated it in add_parameter() */
+ free(name);
+
+ return index;
+}
+
+
+int
+initialize_symbol_from_state(struct gl_program *prog,
+ struct asm_symbol *param_var,
+ const gl_state_index tokens[STATE_LENGTH])
+{
+ int idx = -1;
+ gl_state_index state_tokens[STATE_LENGTH];
+
+
+ memcpy(state_tokens, tokens, sizeof(state_tokens));
+
+ param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+ /* If we are adding a STATE_MATRIX that has multiple rows, we need to
+ * unroll it and call add_state_reference() for each row
+ */
+ if ((state_tokens[0] == STATE_MODELVIEW_MATRIX ||
+ state_tokens[0] == STATE_PROJECTION_MATRIX ||
+ state_tokens[0] == STATE_MVP_MATRIX ||
+ state_tokens[0] == STATE_TEXTURE_MATRIX ||
+ state_tokens[0] == STATE_PROGRAM_MATRIX)
+ && (state_tokens[2] != state_tokens[3])) {
+ int row;
+ const int first_row = state_tokens[2];
+ const int last_row = state_tokens[3];
+
+ for (row = first_row; row <= last_row; row++) {
+ state_tokens[2] = state_tokens[3] = row;
+
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+
+ param_var->param_binding_length++;
+ }
+ }
+ else {
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+ }
+
+ return idx;
+}
+
+
+int
+initialize_symbol_from_param(struct gl_program *prog,
+ struct asm_symbol *param_var,
+ const gl_state_index tokens[STATE_LENGTH])
+{
+ int idx = -1;
+ gl_state_index state_tokens[STATE_LENGTH];
+
+
+ memcpy(state_tokens, tokens, sizeof(state_tokens));
+
+ assert((state_tokens[0] == STATE_VERTEX_PROGRAM)
+ || (state_tokens[0] == STATE_FRAGMENT_PROGRAM));
+ assert((state_tokens[1] == STATE_ENV)
+ || (state_tokens[1] == STATE_LOCAL));
+
+ /*
+ * The param type is STATE_VAR. The program parameter entry will
+ * effectively be a pointer into the LOCAL or ENV parameter array.
+ */
+ param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+ /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements,
+ * we need to unroll it and call add_state_reference() for each row
+ */
+ if (state_tokens[2] != state_tokens[3]) {
+ int row;
+ const int first_row = state_tokens[2];
+ const int last_row = state_tokens[3];
+
+ for (row = first_row; row <= last_row; row++) {
+ state_tokens[2] = state_tokens[3] = row;
+
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+ }
+ }
+ else {
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+ }
+
+ return idx;
+}
+
+
+/**
+ * Put a float/vector constant/literal into the parameter list.
+ * \param param_var returns info about the parameter/constant's location,
+ * binding, type, etc.
+ * \param vec the vector/constant to add
+ * \param allowSwizzle if true, try to consolidate constants which only differ
+ * by a swizzle. We don't want to do this when building
+ * arrays of constants that may be indexed indirectly.
+ * \return index of the constant in the parameter list.
+ */
+int
+initialize_symbol_from_const(struct gl_program *prog,
+ struct asm_symbol *param_var,
+ const struct asm_vector *vec,
+ GLboolean allowSwizzle)
+{
+ unsigned swizzle;
+ const int idx = _mesa_add_unnamed_constant(prog->Parameters,
+ vec->data, vec->count,
+ allowSwizzle ? &swizzle : NULL);
+
+ param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_CONSTANT;
+
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+
+ return idx;
+}
+
+
+char *
+make_error_string(const char *fmt, ...)
+{
+ int length;
+ char *str;
+ va_list args;
+
+
+ /* Call vsnprintf once to determine how large the final string is. Call it
+ * again to do the actual formatting. from the vsnprintf manual page:
+ *
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings).
+ */
+ va_start(args, fmt);
+ length = 1 + vsnprintf(NULL, 0, fmt, args);
+ va_end(args);
+
+ str = malloc(length);
+ if (str) {
+ va_start(args, fmt);
+ vsnprintf(str, length, fmt, args);
+ va_end(args);
+ }
+
+ return str;
+}
+
+
+void
+yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s)
+{
+ char *err_str;
+
+
+ err_str = make_error_string("glProgramStringARB(%s)\n", s);
+ if (err_str) {
+ _mesa_error(state->ctx, GL_INVALID_OPERATION, "%s", err_str);
+ free(err_str);
+ }
+
+ err_str = make_error_string("line %u, char %u: error: %s\n",
+ locp->first_line, locp->first_column, s);
+ _mesa_set_program_error(state->ctx, locp->position, err_str);
+
+ if (err_str) {
+ free(err_str);
+ }
+}
+
+
+GLboolean
+_mesa_parse_arb_program(struct gl_context *ctx, GLenum target, const GLubyte *str,
+ GLsizei len, struct asm_parser_state *state)
+{
+ struct asm_instruction *inst;
+ unsigned i;
+ GLubyte *strz;
+ GLboolean result = GL_FALSE;
+ void *temp;
+ struct asm_symbol *sym;
+
+ state->ctx = ctx;
+ state->prog->Target = target;
+ state->prog->Parameters = _mesa_new_parameter_list();
+
+ /* Make a copy of the program string and force it to be NUL-terminated.
+ */
+ strz = (GLubyte *) malloc(len + 1);
+ if (strz == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB");
+ return GL_FALSE;
+ }
+ memcpy (strz, str, len);
+ strz[len] = '\0';
+
+ state->prog->String = strz;
+
+ state->st = _mesa_symbol_table_ctor();
+
+ state->limits = (target == GL_VERTEX_PROGRAM_ARB)
+ ? & ctx->Const.VertexProgram
+ : & ctx->Const.FragmentProgram;
+
+ state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
+ state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits;
+ state->MaxTextureUnits = ctx->Const.MaxTextureUnits;
+ state->MaxClipPlanes = ctx->Const.MaxClipPlanes;
+ state->MaxLights = ctx->Const.MaxLights;
+ state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices;
+
+ state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB)
+ ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM;
+
+ _mesa_set_program_error(ctx, -1, NULL);
+
+ _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len);
+ yyparse(state);
+ _mesa_program_lexer_dtor(state->scanner);
+
+
+ if (ctx->Program.ErrorPos != -1) {
+ goto error;
+ }
+
+ if (! _mesa_layout_parameters(state)) {
+ struct YYLTYPE loc;
+
+ loc.first_line = 0;
+ loc.first_column = 0;
+ loc.position = len;
+
+ yyerror(& loc, state, "invalid PARAM usage");
+ goto error;
+ }
+
+
+
+ /* Add one instruction to store the "END" instruction.
+ */
+ state->prog->Instructions =
+ _mesa_alloc_instructions(state->prog->NumInstructions + 1);
+ inst = state->inst_head;
+ for (i = 0; i < state->prog->NumInstructions; i++) {
+ struct asm_instruction *const temp = inst->next;
+
+ state->prog->Instructions[i] = inst->Base;
+ inst = temp;
+ }
+
+ /* Finally, tag on an OPCODE_END instruction */
+ {
+ const GLuint numInst = state->prog->NumInstructions;
+ _mesa_init_instructions(state->prog->Instructions + numInst, 1);
+ state->prog->Instructions[numInst].Opcode = OPCODE_END;
+ }
+ state->prog->NumInstructions++;
+
+ state->prog->NumParameters = state->prog->Parameters->NumParameters;
+ state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead);
+
+ /*
+ * Initialize native counts to logical counts. The device driver may
+ * change them if program is translated into a hardware program.
+ */
+ state->prog->NumNativeInstructions = state->prog->NumInstructions;
+ state->prog->NumNativeTemporaries = state->prog->NumTemporaries;
+ state->prog->NumNativeParameters = state->prog->NumParameters;
+ state->prog->NumNativeAttributes = state->prog->NumAttributes;
+ state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs;
+
+ result = GL_TRUE;
+
+error:
+ for (inst = state->inst_head; inst != NULL; inst = temp) {
+ temp = inst->next;
+ free(inst);
+ }
+
+ state->inst_head = NULL;
+ state->inst_tail = NULL;
+
+ for (sym = state->sym; sym != NULL; sym = temp) {
+ temp = sym->next;
+
+ free((void *) sym->name);
+ free(sym);
+ }
+ state->sym = NULL;
+
+ _mesa_symbol_table_dtor(state->st);
+ state->st = NULL;
+
+ return result;
+}
+
diff --git a/mesalib/src/mesa/program/program_parse.y b/mesalib/src/mesa/program/program_parse.y
index cf621ae42..a85977e2e 100644
--- a/mesalib/src/mesa/program/program_parse.y
+++ b/mesalib/src/mesa/program/program_parse.y
@@ -1,2768 +1,2768 @@
-%{
-/*
- * Copyright © 2009 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "main/mtypes.h"
-#include "main/imports.h"
-#include "program/program.h"
-#include "program/prog_parameter.h"
-#include "program/prog_parameter_layout.h"
-#include "program/prog_statevars.h"
-#include "program/prog_instruction.h"
-
-#include "program/symbol_table.h"
-#include "program/program_parser.h"
-
-extern void *yy_scan_string(char *);
-extern void yy_delete_buffer(void *);
-
-static struct asm_symbol *declare_variable(struct asm_parser_state *state,
- char *name, enum asm_type t, struct YYLTYPE *locp);
-
-static int add_state_reference(struct gl_program_parameter_list *param_list,
- const gl_state_index tokens[STATE_LENGTH]);
-
-static int initialize_symbol_from_state(struct gl_program *prog,
- struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
-
-static int initialize_symbol_from_param(struct gl_program *prog,
- struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
-
-static int initialize_symbol_from_const(struct gl_program *prog,
- struct asm_symbol *param_var, const struct asm_vector *vec,
- GLboolean allowSwizzle);
-
-static int yyparse(struct asm_parser_state *state);
-
-static char *make_error_string(const char *fmt, ...);
-
-static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state,
- const char *s);
-
-static int validate_inputs(struct YYLTYPE *locp,
- struct asm_parser_state *state);
-
-static void init_dst_reg(struct prog_dst_register *r);
-
-static void set_dst_reg(struct prog_dst_register *r,
- gl_register_file file, GLint index);
-
-static void init_src_reg(struct asm_src_register *r);
-
-static void set_src_reg(struct asm_src_register *r,
- gl_register_file file, GLint index);
-
-static void set_src_reg_swz(struct asm_src_register *r,
- gl_register_file file, GLint index, GLuint swizzle);
-
-static void asm_instruction_set_operands(struct asm_instruction *inst,
- const struct prog_dst_register *dst, const struct asm_src_register *src0,
- const struct asm_src_register *src1, const struct asm_src_register *src2);
-
-static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
- const struct prog_dst_register *dst, const struct asm_src_register *src0,
- const struct asm_src_register *src1, const struct asm_src_register *src2);
-
-static struct asm_instruction *asm_instruction_copy_ctor(
- const struct prog_instruction *base, const struct prog_dst_register *dst,
- const struct asm_src_register *src0, const struct asm_src_register *src1,
- const struct asm_src_register *src2);
-
-#ifndef FALSE
-#define FALSE 0
-#define TRUE (!FALSE)
-#endif
-
-#define YYLLOC_DEFAULT(Current, Rhs, N) \
- do { \
- if (YYID(N)) { \
- (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
- (Current).position = YYRHSLOC(Rhs, 1).position; \
- (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC(Rhs, N).last_column; \
- } else { \
- (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
- (Current).last_line = (Current).first_line; \
- (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \
- (Current).last_column = (Current).first_column; \
- (Current).position = YYRHSLOC(Rhs, 0).position \
- + (Current).first_column; \
- } \
- } while(YYID(0))
-
-#define YYLEX_PARAM state->scanner
-%}
-
-%pure-parser
-%locations
-%parse-param { struct asm_parser_state *state }
-%error-verbose
-%lex-param { void *scanner }
-
-%union {
- struct asm_instruction *inst;
- struct asm_symbol *sym;
- struct asm_symbol temp_sym;
- struct asm_swizzle_mask swiz_mask;
- struct asm_src_register src_reg;
- struct prog_dst_register dst_reg;
- struct prog_instruction temp_inst;
- char *string;
- unsigned result;
- unsigned attrib;
- int integer;
- float real;
- gl_state_index state[STATE_LENGTH];
- int negate;
- struct asm_vector vector;
- gl_inst_opcode opcode;
-
- struct {
- unsigned swz;
- unsigned rgba_valid:1;
- unsigned xyzw_valid:1;
- unsigned negate:1;
- } ext_swizzle;
-}
-
-%token ARBvp_10 ARBfp_10
-
-/* Tokens for assembler pseudo-ops */
-%token <integer> ADDRESS
-%token ALIAS ATTRIB
-%token OPTION OUTPUT
-%token PARAM
-%token <integer> TEMP
-%token END
-
- /* Tokens for instructions */
-%token <temp_inst> BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP TRI_OP VECTOR_OP
-%token <temp_inst> ARL KIL SWZ TXD_OP
-
-%token <integer> INTEGER
-%token <real> REAL
-
-%token AMBIENT ATTENUATION
-%token BACK
-%token CLIP COLOR
-%token DEPTH DIFFUSE DIRECTION
-%token EMISSION ENV EYE
-%token FOG FOGCOORD FRAGMENT FRONT
-%token HALF
-%token INVERSE INVTRANS
-%token LIGHT LIGHTMODEL LIGHTPROD LOCAL
-%token MATERIAL MAT_PROGRAM MATRIX MATRIXINDEX MODELVIEW MVP
-%token NORMAL
-%token OBJECT
-%token PALETTE PARAMS PLANE POINT_TOK POINTSIZE POSITION PRIMARY PROGRAM PROJECTION
-%token RANGE RESULT ROW
-%token SCENECOLOR SECONDARY SHININESS SIZE_TOK SPECULAR SPOT STATE
-%token TEXCOORD TEXENV TEXGEN TEXGEN_Q TEXGEN_R TEXGEN_S TEXGEN_T TEXTURE TRANSPOSE
-%token TEXTURE_UNIT TEX_1D TEX_2D TEX_3D TEX_CUBE TEX_RECT
-%token TEX_SHADOW1D TEX_SHADOW2D TEX_SHADOWRECT
-%token TEX_ARRAY1D TEX_ARRAY2D TEX_ARRAYSHADOW1D TEX_ARRAYSHADOW2D
-%token VERTEX VTXATTRIB
-%token WEIGHT
-
-%token <string> IDENTIFIER USED_IDENTIFIER
-%type <string> string
-%token <swiz_mask> MASK4 MASK3 MASK2 MASK1 SWIZZLE
-%token DOT_DOT
-%token DOT
-
-%type <inst> instruction ALU_instruction TexInstruction
-%type <inst> ARL_instruction VECTORop_instruction
-%type <inst> SCALARop_instruction BINSCop_instruction BINop_instruction
-%type <inst> TRIop_instruction TXD_instruction SWZ_instruction SAMPLE_instruction
-%type <inst> KIL_instruction
-
-%type <dst_reg> dstReg maskedDstReg maskedAddrReg
-%type <src_reg> srcReg scalarUse scalarSrcReg swizzleSrcReg
-%type <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle
-%type <ext_swizzle> extSwizComp extSwizSel
-%type <swiz_mask> optionalMask
-
-%type <sym> progParamArray
-%type <integer> addrRegRelOffset addrRegPosOffset addrRegNegOffset
-%type <src_reg> progParamArrayMem progParamArrayAbs progParamArrayRel
-%type <sym> addrReg
-%type <swiz_mask> addrComponent addrWriteMask
-
-%type <dst_reg> ccMaskRule ccTest ccMaskRule2 ccTest2 optionalCcMask
-
-%type <result> resultBinding resultColBinding
-%type <integer> optFaceType optColorType
-%type <integer> optResultFaceType optResultColorType
-
-%type <integer> optTexImageUnitNum texImageUnitNum
-%type <integer> optTexCoordUnitNum texCoordUnitNum
-%type <integer> optLegacyTexUnitNum legacyTexUnitNum
-%type <integer> texImageUnit texTarget
-%type <integer> vtxAttribNum
-
-%type <attrib> attribBinding vtxAttribItem fragAttribItem
-
-%type <temp_sym> paramSingleInit paramSingleItemDecl
-%type <integer> optArraySize
-
-%type <state> stateSingleItem stateMultipleItem
-%type <state> stateMaterialItem
-%type <state> stateLightItem stateLightModelItem stateLightProdItem
-%type <state> stateTexGenItem stateFogItem stateClipPlaneItem statePointItem
-%type <state> stateMatrixItem stateMatrixRow stateMatrixRows
-%type <state> stateTexEnvItem stateDepthItem
-
-%type <state> stateLModProperty
-%type <state> stateMatrixName optMatrixRows
-
-%type <integer> stateMatProperty
-%type <integer> stateLightProperty stateSpotProperty
-%type <integer> stateLightNumber stateLProdProperty
-%type <integer> stateTexGenType stateTexGenCoord
-%type <integer> stateTexEnvProperty
-%type <integer> stateFogProperty
-%type <integer> stateClipPlaneNum
-%type <integer> statePointProperty
-
-%type <integer> stateOptMatModifier stateMatModifier stateMatrixRowNum
-%type <integer> stateOptModMatNum stateModMatNum statePaletteMatNum
-%type <integer> stateProgramMatNum
-
-%type <integer> ambDiffSpecProperty
-
-%type <state> programSingleItem progEnvParam progLocalParam
-%type <state> programMultipleItem progEnvParams progLocalParams
-
-%type <temp_sym> paramMultipleInit paramMultInitList paramMultipleItem
-%type <temp_sym> paramSingleItemUse
-
-%type <integer> progEnvParamNum progLocalParamNum
-%type <state> progEnvParamNums progLocalParamNums
-
-%type <vector> paramConstDecl paramConstUse
-%type <vector> paramConstScalarDecl paramConstScalarUse paramConstVector
-%type <real> signedFloatConstant
-%type <negate> optionalSign
-
-%{
-extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param,
- void *yyscanner);
-%}
-
-%%
-
-program: language optionSequence statementSequence END
- ;
-
-language: ARBvp_10
- {
- if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) {
- yyerror(& @1, state, "invalid fragment program header");
-
- }
- state->mode = ARB_vertex;
- }
- | ARBfp_10
- {
- if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) {
- yyerror(& @1, state, "invalid vertex program header");
- }
- state->mode = ARB_fragment;
-
- state->option.TexRect =
- (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE);
- }
- ;
-
-optionSequence: optionSequence option
- |
- ;
-
-option: OPTION string ';'
- {
- int valid = 0;
-
- if (state->mode == ARB_vertex) {
- valid = _mesa_ARBvp_parse_option(state, $2);
- } else if (state->mode == ARB_fragment) {
- valid = _mesa_ARBfp_parse_option(state, $2);
- }
-
-
- free($2);
-
- if (!valid) {
- const char *const err_str = (state->mode == ARB_vertex)
- ? "invalid ARB vertex program option"
- : "invalid ARB fragment program option";
-
- yyerror(& @2, state, err_str);
- YYERROR;
- }
- }
- ;
-
-statementSequence: statementSequence statement
- |
- ;
-
-statement: instruction ';'
- {
- if ($1 != NULL) {
- if (state->inst_tail == NULL) {
- state->inst_head = $1;
- } else {
- state->inst_tail->next = $1;
- }
-
- state->inst_tail = $1;
- $1->next = NULL;
-
- state->prog->NumInstructions++;
- }
- }
- | namingStatement ';'
- ;
-
-instruction: ALU_instruction
- {
- $$ = $1;
- state->prog->NumAluInstructions++;
- }
- | TexInstruction
- {
- $$ = $1;
- state->prog->NumTexInstructions++;
- }
- ;
-
-ALU_instruction: ARL_instruction
- | VECTORop_instruction
- | SCALARop_instruction
- | BINSCop_instruction
- | BINop_instruction
- | TRIop_instruction
- | SWZ_instruction
- ;
-
-TexInstruction: SAMPLE_instruction
- | KIL_instruction
- | TXD_instruction
- ;
-
-ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg
- {
- $$ = asm_instruction_ctor(OPCODE_ARL, & $2, & $4, NULL, NULL);
- }
- ;
-
-VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg
- {
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
- }
- ;
-
-SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg
- {
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
- }
- ;
-
-BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg
- {
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
- }
- ;
-
-
-BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
- {
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
- }
- ;
-
-TRIop_instruction: TRI_OP maskedDstReg ','
- swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
- {
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
- }
- ;
-
-SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
- {
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
- if ($$ != NULL) {
- const GLbitfield tex_mask = (1U << $6);
- GLbitfield shadow_tex = 0;
- GLbitfield target_mask = 0;
-
-
- $$->Base.TexSrcUnit = $6;
-
- if ($8 < 0) {
- shadow_tex = tex_mask;
-
- $$->Base.TexSrcTarget = -$8;
- $$->Base.TexShadow = 1;
- } else {
- $$->Base.TexSrcTarget = $8;
- }
-
- target_mask = (1U << $$->Base.TexSrcTarget);
-
- /* If this texture unit was previously accessed and that access
- * had a different texture target, generate an error.
- *
- * If this texture unit was previously accessed and that access
- * had a different shadow mode, generate an error.
- */
- if ((state->prog->TexturesUsed[$6] != 0)
- && ((state->prog->TexturesUsed[$6] != target_mask)
- || ((state->prog->ShadowSamplers & tex_mask)
- != shadow_tex))) {
- yyerror(& @8, state,
- "multiple targets used on one texture image unit");
- YYERROR;
- }
-
-
- state->prog->TexturesUsed[$6] |= target_mask;
- state->prog->ShadowSamplers |= shadow_tex;
- }
- }
- ;
-
-KIL_instruction: KIL swizzleSrcReg
- {
- $$ = asm_instruction_ctor(OPCODE_KIL, NULL, & $2, NULL, NULL);
- state->fragment.UsesKill = 1;
- }
- | KIL ccTest
- {
- $$ = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL);
- $$->Base.DstReg.CondMask = $2.CondMask;
- $$->Base.DstReg.CondSwizzle = $2.CondSwizzle;
- $$->Base.DstReg.CondSrc = $2.CondSrc;
- state->fragment.UsesKill = 1;
- }
- ;
-
-TXD_instruction: TXD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
- {
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
- if ($$ != NULL) {
- const GLbitfield tex_mask = (1U << $10);
- GLbitfield shadow_tex = 0;
- GLbitfield target_mask = 0;
-
-
- $$->Base.TexSrcUnit = $10;
-
- if ($12 < 0) {
- shadow_tex = tex_mask;
-
- $$->Base.TexSrcTarget = -$12;
- $$->Base.TexShadow = 1;
- } else {
- $$->Base.TexSrcTarget = $12;
- }
-
- target_mask = (1U << $$->Base.TexSrcTarget);
-
- /* If this texture unit was previously accessed and that access
- * had a different texture target, generate an error.
- *
- * If this texture unit was previously accessed and that access
- * had a different shadow mode, generate an error.
- */
- if ((state->prog->TexturesUsed[$10] != 0)
- && ((state->prog->TexturesUsed[$10] != target_mask)
- || ((state->prog->ShadowSamplers & tex_mask)
- != shadow_tex))) {
- yyerror(& @12, state,
- "multiple targets used on one texture image unit");
- YYERROR;
- }
-
-
- state->prog->TexturesUsed[$10] |= target_mask;
- state->prog->ShadowSamplers |= shadow_tex;
- }
- }
- ;
-
-texImageUnit: TEXTURE_UNIT optTexImageUnitNum
- {
- $$ = $2;
- }
- ;
-
-texTarget: TEX_1D { $$ = TEXTURE_1D_INDEX; }
- | TEX_2D { $$ = TEXTURE_2D_INDEX; }
- | TEX_3D { $$ = TEXTURE_3D_INDEX; }
- | TEX_CUBE { $$ = TEXTURE_CUBE_INDEX; }
- | TEX_RECT { $$ = TEXTURE_RECT_INDEX; }
- | TEX_SHADOW1D { $$ = -TEXTURE_1D_INDEX; }
- | TEX_SHADOW2D { $$ = -TEXTURE_2D_INDEX; }
- | TEX_SHADOWRECT { $$ = -TEXTURE_RECT_INDEX; }
- | TEX_ARRAY1D { $$ = TEXTURE_1D_ARRAY_INDEX; }
- | TEX_ARRAY2D { $$ = TEXTURE_2D_ARRAY_INDEX; }
- | TEX_ARRAYSHADOW1D { $$ = -TEXTURE_1D_ARRAY_INDEX; }
- | TEX_ARRAYSHADOW2D { $$ = -TEXTURE_2D_ARRAY_INDEX; }
- ;
-
-SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle
- {
- /* FIXME: Is this correct? Should the extenedSwizzle be applied
- * FIXME: to the existing swizzle?
- */
- $4.Base.Swizzle = $6.swizzle;
- $4.Base.Negate = $6.mask;
-
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
- }
- ;
-
-scalarSrcReg: optionalSign scalarUse
- {
- $$ = $2;
-
- if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
- }
- }
- | optionalSign '|' scalarUse '|'
- {
- $$ = $3;
-
- if (!state->option.NV_fragment) {
- yyerror(& @2, state, "unexpected character '|'");
- YYERROR;
- }
-
- if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
- }
-
- $$.Base.Abs = 1;
- }
- ;
-
-scalarUse: srcReg scalarSuffix
- {
- $$ = $1;
-
- $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
- $2.swizzle);
- }
- | paramConstScalarUse
- {
- struct asm_symbol temp_sym;
-
- if (!state->option.NV_fragment) {
- yyerror(& @1, state, "expected scalar suffix");
- YYERROR;
- }
-
- memset(& temp_sym, 0, sizeof(temp_sym));
- temp_sym.param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & temp_sym, & $1, GL_TRUE);
-
- set_src_reg_swz(& $$, PROGRAM_CONSTANT,
- temp_sym.param_binding_begin,
- temp_sym.param_binding_swizzle);
- }
- ;
-
-swizzleSrcReg: optionalSign srcReg swizzleSuffix
- {
- $$ = $2;
-
- if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
- }
-
- $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
- $3.swizzle);
- }
- | optionalSign '|' srcReg swizzleSuffix '|'
- {
- $$ = $3;
-
- if (!state->option.NV_fragment) {
- yyerror(& @2, state, "unexpected character '|'");
- YYERROR;
- }
-
- if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
- }
-
- $$.Base.Abs = 1;
- $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
- $4.swizzle);
- }
-
- ;
-
-maskedDstReg: dstReg optionalMask optionalCcMask
- {
- $$ = $1;
- $$.WriteMask = $2.mask;
- $$.CondMask = $3.CondMask;
- $$.CondSwizzle = $3.CondSwizzle;
- $$.CondSrc = $3.CondSrc;
-
- if ($$.File == PROGRAM_OUTPUT) {
- /* Technically speaking, this should check that it is in
- * vertex program mode. However, PositionInvariant can never be
- * set in fragment program mode, so it is somewhat irrelevant.
- */
- if (state->option.PositionInvariant
- && ($$.Index == VERT_RESULT_HPOS)) {
- yyerror(& @1, state, "position-invariant programs cannot "
- "write position");
- YYERROR;
- }
-
- state->prog->OutputsWritten |= BITFIELD64_BIT($$.Index);
- }
- }
- ;
-
-maskedAddrReg: addrReg addrWriteMask
- {
- set_dst_reg(& $$, PROGRAM_ADDRESS, 0);
- $$.WriteMask = $2.mask;
- }
- ;
-
-extendedSwizzle: extSwizComp ',' extSwizComp ',' extSwizComp ',' extSwizComp
- {
- const unsigned xyzw_valid =
- ($1.xyzw_valid << 0)
- | ($3.xyzw_valid << 1)
- | ($5.xyzw_valid << 2)
- | ($7.xyzw_valid << 3);
- const unsigned rgba_valid =
- ($1.rgba_valid << 0)
- | ($3.rgba_valid << 1)
- | ($5.rgba_valid << 2)
- | ($7.rgba_valid << 3);
-
- /* All of the swizzle components have to be valid in either RGBA
- * or XYZW. Note that 0 and 1 are valid in both, so both masks
- * can have some bits set.
- *
- * We somewhat deviate from the spec here. It would be really hard
- * to figure out which component is the error, and there probably
- * isn't a lot of benefit.
- */
- if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) {
- yyerror(& @1, state, "cannot combine RGBA and XYZW swizzle "
- "components");
- YYERROR;
- }
-
- $$.swizzle = MAKE_SWIZZLE4($1.swz, $3.swz, $5.swz, $7.swz);
- $$.mask = ($1.negate) | ($3.negate << 1) | ($5.negate << 2)
- | ($7.negate << 3);
- }
- ;
-
-extSwizComp: optionalSign extSwizSel
- {
- $$ = $2;
- $$.negate = ($1) ? 1 : 0;
- }
- ;
-
-extSwizSel: INTEGER
- {
- if (($1 != 0) && ($1 != 1)) {
- yyerror(& @1, state, "invalid extended swizzle selector");
- YYERROR;
- }
-
- $$.swz = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
-
- /* 0 and 1 are valid for both RGBA swizzle names and XYZW
- * swizzle names.
- */
- $$.xyzw_valid = 1;
- $$.rgba_valid = 1;
- }
- | string
- {
- char s;
-
- if (strlen($1) > 1) {
- yyerror(& @1, state, "invalid extended swizzle selector");
- YYERROR;
- }
-
- s = $1[0];
- free($1);
-
- switch (s) {
- case 'x':
- $$.swz = SWIZZLE_X;
- $$.xyzw_valid = 1;
- break;
- case 'y':
- $$.swz = SWIZZLE_Y;
- $$.xyzw_valid = 1;
- break;
- case 'z':
- $$.swz = SWIZZLE_Z;
- $$.xyzw_valid = 1;
- break;
- case 'w':
- $$.swz = SWIZZLE_W;
- $$.xyzw_valid = 1;
- break;
-
- case 'r':
- $$.swz = SWIZZLE_X;
- $$.rgba_valid = 1;
- break;
- case 'g':
- $$.swz = SWIZZLE_Y;
- $$.rgba_valid = 1;
- break;
- case 'b':
- $$.swz = SWIZZLE_Z;
- $$.rgba_valid = 1;
- break;
- case 'a':
- $$.swz = SWIZZLE_W;
- $$.rgba_valid = 1;
- break;
-
- default:
- yyerror(& @1, state, "invalid extended swizzle selector");
- YYERROR;
- break;
- }
- }
- ;
-
-srcReg: USED_IDENTIFIER /* temporaryReg | progParamSingle */
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, $1);
-
- free($1);
-
- if (s == NULL) {
- yyerror(& @1, state, "invalid operand variable");
- YYERROR;
- } else if ((s->type != at_param) && (s->type != at_temp)
- && (s->type != at_attrib)) {
- yyerror(& @1, state, "invalid operand variable");
- YYERROR;
- } else if ((s->type == at_param) && s->param_is_array) {
- yyerror(& @1, state, "non-array access to array PARAM");
- YYERROR;
- }
-
- init_src_reg(& $$);
- switch (s->type) {
- case at_temp:
- set_src_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding);
- break;
- case at_param:
- set_src_reg_swz(& $$, s->param_binding_type,
- s->param_binding_begin,
- s->param_binding_swizzle);
- break;
- case at_attrib:
- set_src_reg(& $$, PROGRAM_INPUT, s->attrib_binding);
- state->prog->InputsRead |= (1U << $$.Base.Index);
-
- if (!validate_inputs(& @1, state)) {
- YYERROR;
- }
- break;
-
- default:
- YYERROR;
- break;
- }
- }
- | attribBinding
- {
- set_src_reg(& $$, PROGRAM_INPUT, $1);
- state->prog->InputsRead |= (1U << $$.Base.Index);
-
- if (!validate_inputs(& @1, state)) {
- YYERROR;
- }
- }
- | progParamArray '[' progParamArrayMem ']'
- {
- if (! $3.Base.RelAddr
- && ((unsigned) $3.Base.Index >= $1->param_binding_length)) {
- yyerror(& @3, state, "out of bounds array access");
- YYERROR;
- }
-
- init_src_reg(& $$);
- $$.Base.File = $1->param_binding_type;
-
- if ($3.Base.RelAddr) {
- state->prog->IndirectRegisterFiles |= (1 << $$.Base.File);
- $1->param_accessed_indirectly = 1;
-
- $$.Base.RelAddr = 1;
- $$.Base.Index = $3.Base.Index;
- $$.Symbol = $1;
- } else {
- $$.Base.Index = $1->param_binding_begin + $3.Base.Index;
- }
- }
- | paramSingleItemUse
- {
- gl_register_file file = ($1.name != NULL)
- ? $1.param_binding_type
- : PROGRAM_CONSTANT;
- set_src_reg_swz(& $$, file, $1.param_binding_begin,
- $1.param_binding_swizzle);
- }
- ;
-
-dstReg: resultBinding
- {
- set_dst_reg(& $$, PROGRAM_OUTPUT, $1);
- }
- | USED_IDENTIFIER /* temporaryReg | vertexResultReg */
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, $1);
-
- free($1);
-
- if (s == NULL) {
- yyerror(& @1, state, "invalid operand variable");
- YYERROR;
- } else if ((s->type != at_output) && (s->type != at_temp)) {
- yyerror(& @1, state, "invalid operand variable");
- YYERROR;
- }
-
- switch (s->type) {
- case at_temp:
- set_dst_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding);
- break;
- case at_output:
- set_dst_reg(& $$, PROGRAM_OUTPUT, s->output_binding);
- break;
- default:
- set_dst_reg(& $$, s->param_binding_type, s->param_binding_begin);
- break;
- }
- }
- ;
-
-progParamArray: USED_IDENTIFIER
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, $1);
-
- free($1);
-
- if (s == NULL) {
- yyerror(& @1, state, "invalid operand variable");
- YYERROR;
- } else if ((s->type != at_param) || !s->param_is_array) {
- yyerror(& @1, state, "array access to non-PARAM variable");
- YYERROR;
- } else {
- $$ = s;
- }
- }
- ;
-
-progParamArrayMem: progParamArrayAbs | progParamArrayRel;
-
-progParamArrayAbs: INTEGER
- {
- init_src_reg(& $$);
- $$.Base.Index = $1;
- }
- ;
-
-progParamArrayRel: addrReg addrComponent addrRegRelOffset
- {
- /* FINISHME: Add support for multiple address registers.
- */
- /* FINISHME: Add support for 4-component address registers.
- */
- init_src_reg(& $$);
- $$.Base.RelAddr = 1;
- $$.Base.Index = $3;
- }
- ;
-
-addrRegRelOffset: { $$ = 0; }
- | '+' addrRegPosOffset { $$ = $2; }
- | '-' addrRegNegOffset { $$ = -$2; }
- ;
-
-addrRegPosOffset: INTEGER
- {
- if (($1 < 0) || ($1 > 4095)) {
- char s[100];
- _mesa_snprintf(s, sizeof(s),
- "relative address offset too large (%d)", $1);
- yyerror(& @1, state, s);
- YYERROR;
- } else {
- $$ = $1;
- }
- }
- ;
-
-addrRegNegOffset: INTEGER
- {
- if (($1 < 0) || ($1 > 4096)) {
- char s[100];
- _mesa_snprintf(s, sizeof(s),
- "relative address offset too large (%d)", $1);
- yyerror(& @1, state, s);
- YYERROR;
- } else {
- $$ = $1;
- }
- }
- ;
-
-addrReg: USED_IDENTIFIER
- {
- struct asm_symbol *const s = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, $1);
-
- free($1);
-
- if (s == NULL) {
- yyerror(& @1, state, "invalid array member");
- YYERROR;
- } else if (s->type != at_address) {
- yyerror(& @1, state,
- "invalid variable for indexed array access");
- YYERROR;
- } else {
- $$ = s;
- }
- }
- ;
-
-addrComponent: MASK1
- {
- if ($1.mask != WRITEMASK_X) {
- yyerror(& @1, state, "invalid address component selector");
- YYERROR;
- } else {
- $$ = $1;
- }
- }
- ;
-
-addrWriteMask: MASK1
- {
- if ($1.mask != WRITEMASK_X) {
- yyerror(& @1, state,
- "address register write mask must be \".x\"");
- YYERROR;
- } else {
- $$ = $1;
- }
- }
- ;
-
-scalarSuffix: MASK1;
-
-swizzleSuffix: MASK1
- | MASK4
- | SWIZZLE
- | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; }
- ;
-
-optionalMask: MASK4 | MASK3 | MASK2 | MASK1
- | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; }
- ;
-
-optionalCcMask: '(' ccTest ')'
- {
- $$ = $2;
- }
- | '(' ccTest2 ')'
- {
- $$ = $2;
- }
- |
- {
- $$.CondMask = COND_TR;
- $$.CondSwizzle = SWIZZLE_NOOP;
- $$.CondSrc = 0;
- }
- ;
-
-ccTest: ccMaskRule swizzleSuffix
- {
- $$ = $1;
- $$.CondSwizzle = $2.swizzle;
- }
- ;
-
-ccTest2: ccMaskRule2 swizzleSuffix
- {
- $$ = $1;
- $$.CondSwizzle = $2.swizzle;
- }
- ;
-
-ccMaskRule: IDENTIFIER
- {
- const int cond = _mesa_parse_cc($1);
- if ((cond == 0) || ($1[2] != '\0')) {
- char *const err_str =
- make_error_string("invalid condition code \"%s\"", $1);
-
- yyerror(& @1, state, (err_str != NULL)
- ? err_str : "invalid condition code");
-
- if (err_str != NULL) {
- free(err_str);
- }
-
- YYERROR;
- }
-
- $$.CondMask = cond;
- $$.CondSwizzle = SWIZZLE_NOOP;
- $$.CondSrc = 0;
- }
- ;
-
-ccMaskRule2: USED_IDENTIFIER
- {
- const int cond = _mesa_parse_cc($1);
- if ((cond == 0) || ($1[2] != '\0')) {
- char *const err_str =
- make_error_string("invalid condition code \"%s\"", $1);
-
- yyerror(& @1, state, (err_str != NULL)
- ? err_str : "invalid condition code");
-
- if (err_str != NULL) {
- free(err_str);
- }
-
- YYERROR;
- }
-
- $$.CondMask = cond;
- $$.CondSwizzle = SWIZZLE_NOOP;
- $$.CondSrc = 0;
- }
- ;
-
-namingStatement: ATTRIB_statement
- | PARAM_statement
- | TEMP_statement
- | ADDRESS_statement
- | OUTPUT_statement
- | ALIAS_statement
- ;
-
-ATTRIB_statement: ATTRIB IDENTIFIER '=' attribBinding
- {
- struct asm_symbol *const s =
- declare_variable(state, $2, at_attrib, & @2);
-
- if (s == NULL) {
- free($2);
- YYERROR;
- } else {
- s->attrib_binding = $4;
- state->InputsBound |= (1U << s->attrib_binding);
-
- if (!validate_inputs(& @4, state)) {
- YYERROR;
- }
- }
- }
- ;
-
-attribBinding: VERTEX vtxAttribItem
- {
- $$ = $2;
- }
- | FRAGMENT fragAttribItem
- {
- $$ = $2;
- }
- ;
-
-vtxAttribItem: POSITION
- {
- $$ = VERT_ATTRIB_POS;
- }
- | WEIGHT vtxOptWeightNum
- {
- $$ = VERT_ATTRIB_WEIGHT;
- }
- | NORMAL
- {
- $$ = VERT_ATTRIB_NORMAL;
- }
- | COLOR optColorType
- {
- if (!state->ctx->Extensions.EXT_secondary_color) {
- yyerror(& @2, state, "GL_EXT_secondary_color not supported");
- YYERROR;
- }
-
- $$ = VERT_ATTRIB_COLOR0 + $2;
- }
- | FOGCOORD
- {
- if (!state->ctx->Extensions.EXT_fog_coord) {
- yyerror(& @1, state, "GL_EXT_fog_coord not supported");
- YYERROR;
- }
-
- $$ = VERT_ATTRIB_FOG;
- }
- | TEXCOORD optTexCoordUnitNum
- {
- $$ = VERT_ATTRIB_TEX0 + $2;
- }
- | MATRIXINDEX '[' vtxWeightNum ']'
- {
- yyerror(& @1, state, "GL_ARB_matrix_palette not supported");
- YYERROR;
- }
- | VTXATTRIB '[' vtxAttribNum ']'
- {
- $$ = VERT_ATTRIB_GENERIC0 + $3;
- }
- ;
-
-vtxAttribNum: INTEGER
- {
- if ((unsigned) $1 >= state->limits->MaxAttribs) {
- yyerror(& @1, state, "invalid vertex attribute reference");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-vtxOptWeightNum: | '[' vtxWeightNum ']';
-vtxWeightNum: INTEGER;
-
-fragAttribItem: POSITION
- {
- $$ = FRAG_ATTRIB_WPOS;
- }
- | COLOR optColorType
- {
- $$ = FRAG_ATTRIB_COL0 + $2;
- }
- | FOGCOORD
- {
- $$ = FRAG_ATTRIB_FOGC;
- }
- | TEXCOORD optTexCoordUnitNum
- {
- $$ = FRAG_ATTRIB_TEX0 + $2;
- }
- ;
-
-PARAM_statement: PARAM_singleStmt | PARAM_multipleStmt;
-
-PARAM_singleStmt: PARAM IDENTIFIER paramSingleInit
- {
- struct asm_symbol *const s =
- declare_variable(state, $2, at_param, & @2);
-
- if (s == NULL) {
- free($2);
- YYERROR;
- } else {
- s->param_binding_type = $3.param_binding_type;
- s->param_binding_begin = $3.param_binding_begin;
- s->param_binding_length = $3.param_binding_length;
- s->param_binding_swizzle = $3.param_binding_swizzle;
- s->param_is_array = 0;
- }
- }
- ;
-
-PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit
- {
- if (($4 != 0) && ((unsigned) $4 != $6.param_binding_length)) {
- free($2);
- yyerror(& @4, state,
- "parameter array size and number of bindings must match");
- YYERROR;
- } else {
- struct asm_symbol *const s =
- declare_variable(state, $2, $6.type, & @2);
-
- if (s == NULL) {
- free($2);
- YYERROR;
- } else {
- s->param_binding_type = $6.param_binding_type;
- s->param_binding_begin = $6.param_binding_begin;
- s->param_binding_length = $6.param_binding_length;
- s->param_binding_swizzle = SWIZZLE_XYZW;
- s->param_is_array = 1;
- }
- }
- }
- ;
-
-optArraySize:
- {
- $$ = 0;
- }
- | INTEGER
- {
- if (($1 < 1) || ((unsigned) $1 > state->limits->MaxParameters)) {
- yyerror(& @1, state, "invalid parameter array size");
- YYERROR;
- } else {
- $$ = $1;
- }
- }
- ;
-
-paramSingleInit: '=' paramSingleItemDecl
- {
- $$ = $2;
- }
- ;
-
-paramMultipleInit: '=' '{' paramMultInitList '}'
- {
- $$ = $3;
- }
- ;
-
-paramMultInitList: paramMultipleItem
- | paramMultInitList ',' paramMultipleItem
- {
- $1.param_binding_length += $3.param_binding_length;
- $$ = $1;
- }
- ;
-
-paramSingleItemDecl: stateSingleItem
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_state(state->prog, & $$, $1);
- }
- | programSingleItem
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_param(state->prog, & $$, $1);
- }
- | paramConstDecl
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE);
- }
- ;
-
-paramSingleItemUse: stateSingleItem
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_state(state->prog, & $$, $1);
- }
- | programSingleItem
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_param(state->prog, & $$, $1);
- }
- | paramConstUse
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE);
- }
- ;
-
-paramMultipleItem: stateMultipleItem
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_state(state->prog, & $$, $1);
- }
- | programMultipleItem
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_param(state->prog, & $$, $1);
- }
- | paramConstDecl
- {
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & $$, & $1, GL_FALSE);
- }
- ;
-
-stateMultipleItem: stateSingleItem { memcpy($$, $1, sizeof($$)); }
- | STATE stateMatrixRows { memcpy($$, $2, sizeof($$)); }
- ;
-
-stateSingleItem: STATE stateMaterialItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateLightItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateLightModelItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateLightProdItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateTexGenItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateTexEnvItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateFogItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateClipPlaneItem { memcpy($$, $2, sizeof($$)); }
- | STATE statePointItem { memcpy($$, $2, sizeof($$)); }
- | STATE stateMatrixRow { memcpy($$, $2, sizeof($$)); }
- | STATE stateDepthItem { memcpy($$, $2, sizeof($$)); }
- ;
-
-stateMaterialItem: MATERIAL optFaceType stateMatProperty
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_MATERIAL;
- $$[1] = $2;
- $$[2] = $3;
- }
- ;
-
-stateMatProperty: ambDiffSpecProperty
- {
- $$ = $1;
- }
- | EMISSION
- {
- $$ = STATE_EMISSION;
- }
- | SHININESS
- {
- $$ = STATE_SHININESS;
- }
- ;
-
-stateLightItem: LIGHT '[' stateLightNumber ']' stateLightProperty
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_LIGHT;
- $$[1] = $3;
- $$[2] = $5;
- }
- ;
-
-stateLightProperty: ambDiffSpecProperty
- {
- $$ = $1;
- }
- | POSITION
- {
- $$ = STATE_POSITION;
- }
- | ATTENUATION
- {
- if (!state->ctx->Extensions.EXT_point_parameters) {
- yyerror(& @1, state, "GL_ARB_point_parameters not supported");
- YYERROR;
- }
-
- $$ = STATE_ATTENUATION;
- }
- | SPOT stateSpotProperty
- {
- $$ = $2;
- }
- | HALF
- {
- $$ = STATE_HALF_VECTOR;
- }
- ;
-
-stateSpotProperty: DIRECTION
- {
- $$ = STATE_SPOT_DIRECTION;
- }
- ;
-
-stateLightModelItem: LIGHTMODEL stateLModProperty
- {
- $$[0] = $2[0];
- $$[1] = $2[1];
- }
- ;
-
-stateLModProperty: AMBIENT
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_LIGHTMODEL_AMBIENT;
- }
- | optFaceType SCENECOLOR
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_LIGHTMODEL_SCENECOLOR;
- $$[1] = $1;
- }
- ;
-
-stateLightProdItem: LIGHTPROD '[' stateLightNumber ']' optFaceType stateLProdProperty
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_LIGHTPROD;
- $$[1] = $3;
- $$[2] = $5;
- $$[3] = $6;
- }
- ;
-
-stateLProdProperty: ambDiffSpecProperty;
-
-stateTexEnvItem: TEXENV optLegacyTexUnitNum stateTexEnvProperty
- {
- memset($$, 0, sizeof($$));
- $$[0] = $3;
- $$[1] = $2;
- }
- ;
-
-stateTexEnvProperty: COLOR
- {
- $$ = STATE_TEXENV_COLOR;
- }
- ;
-
-ambDiffSpecProperty: AMBIENT
- {
- $$ = STATE_AMBIENT;
- }
- | DIFFUSE
- {
- $$ = STATE_DIFFUSE;
- }
- | SPECULAR
- {
- $$ = STATE_SPECULAR;
- }
- ;
-
-stateLightNumber: INTEGER
- {
- if ((unsigned) $1 >= state->MaxLights) {
- yyerror(& @1, state, "invalid light selector");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-stateTexGenItem: TEXGEN optTexCoordUnitNum stateTexGenType stateTexGenCoord
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_TEXGEN;
- $$[1] = $2;
- $$[2] = $3 + $4;
- }
- ;
-
-stateTexGenType: EYE
- {
- $$ = STATE_TEXGEN_EYE_S;
- }
- | OBJECT
- {
- $$ = STATE_TEXGEN_OBJECT_S;
- }
- ;
-stateTexGenCoord: TEXGEN_S
- {
- $$ = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S;
- }
- | TEXGEN_T
- {
- $$ = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S;
- }
- | TEXGEN_R
- {
- $$ = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S;
- }
- | TEXGEN_Q
- {
- $$ = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S;
- }
- ;
-
-stateFogItem: FOG stateFogProperty
- {
- memset($$, 0, sizeof($$));
- $$[0] = $2;
- }
- ;
-
-stateFogProperty: COLOR
- {
- $$ = STATE_FOG_COLOR;
- }
- | PARAMS
- {
- $$ = STATE_FOG_PARAMS;
- }
- ;
-
-stateClipPlaneItem: CLIP '[' stateClipPlaneNum ']' PLANE
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_CLIPPLANE;
- $$[1] = $3;
- }
- ;
-
-stateClipPlaneNum: INTEGER
- {
- if ((unsigned) $1 >= state->MaxClipPlanes) {
- yyerror(& @1, state, "invalid clip plane selector");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-statePointItem: POINT_TOK statePointProperty
- {
- memset($$, 0, sizeof($$));
- $$[0] = $2;
- }
- ;
-
-statePointProperty: SIZE_TOK
- {
- $$ = STATE_POINT_SIZE;
- }
- | ATTENUATION
- {
- $$ = STATE_POINT_ATTENUATION;
- }
- ;
-
-stateMatrixRow: stateMatrixItem ROW '[' stateMatrixRowNum ']'
- {
- $$[0] = $1[0];
- $$[1] = $1[1];
- $$[2] = $4;
- $$[3] = $4;
- $$[4] = $1[2];
- }
- ;
-
-stateMatrixRows: stateMatrixItem optMatrixRows
- {
- $$[0] = $1[0];
- $$[1] = $1[1];
- $$[2] = $2[2];
- $$[3] = $2[3];
- $$[4] = $1[2];
- }
- ;
-
-optMatrixRows:
- {
- $$[2] = 0;
- $$[3] = 3;
- }
- | ROW '[' stateMatrixRowNum DOT_DOT stateMatrixRowNum ']'
- {
- /* It seems logical that the matrix row range specifier would have
- * to specify a range or more than one row (i.e., $5 > $3).
- * However, the ARB_vertex_program spec says "a program will fail
- * to load if <a> is greater than <b>." This means that $3 == $5
- * is valid.
- */
- if ($3 > $5) {
- yyerror(& @3, state, "invalid matrix row range");
- YYERROR;
- }
-
- $$[2] = $3;
- $$[3] = $5;
- }
- ;
-
-stateMatrixItem: MATRIX stateMatrixName stateOptMatModifier
- {
- $$[0] = $2[0];
- $$[1] = $2[1];
- $$[2] = $3;
- }
- ;
-
-stateOptMatModifier:
- {
- $$ = 0;
- }
- | stateMatModifier
- {
- $$ = $1;
- }
- ;
-
-stateMatModifier: INVERSE
- {
- $$ = STATE_MATRIX_INVERSE;
- }
- | TRANSPOSE
- {
- $$ = STATE_MATRIX_TRANSPOSE;
- }
- | INVTRANS
- {
- $$ = STATE_MATRIX_INVTRANS;
- }
- ;
-
-stateMatrixRowNum: INTEGER
- {
- if ($1 > 3) {
- yyerror(& @1, state, "invalid matrix row reference");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-stateMatrixName: MODELVIEW stateOptModMatNum
- {
- $$[0] = STATE_MODELVIEW_MATRIX;
- $$[1] = $2;
- }
- | PROJECTION
- {
- $$[0] = STATE_PROJECTION_MATRIX;
- $$[1] = 0;
- }
- | MVP
- {
- $$[0] = STATE_MVP_MATRIX;
- $$[1] = 0;
- }
- | TEXTURE optTexCoordUnitNum
- {
- $$[0] = STATE_TEXTURE_MATRIX;
- $$[1] = $2;
- }
- | PALETTE '[' statePaletteMatNum ']'
- {
- yyerror(& @1, state, "GL_ARB_matrix_palette not supported");
- YYERROR;
- }
- | MAT_PROGRAM '[' stateProgramMatNum ']'
- {
- $$[0] = STATE_PROGRAM_MATRIX;
- $$[1] = $3;
- }
- ;
-
-stateOptModMatNum:
- {
- $$ = 0;
- }
- | '[' stateModMatNum ']'
- {
- $$ = $2;
- }
- ;
-stateModMatNum: INTEGER
- {
- /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix
- * zero is valid.
- */
- if ($1 != 0) {
- yyerror(& @1, state, "invalid modelview matrix index");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-statePaletteMatNum: INTEGER
- {
- /* Since GL_ARB_matrix_palette isn't supported, just let any value
- * through here. The error will be generated later.
- */
- $$ = $1;
- }
- ;
-stateProgramMatNum: INTEGER
- {
- if ((unsigned) $1 >= state->MaxProgramMatrices) {
- yyerror(& @1, state, "invalid program matrix selector");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-stateDepthItem: DEPTH RANGE
- {
- memset($$, 0, sizeof($$));
- $$[0] = STATE_DEPTH_RANGE;
- }
- ;
-
-
-programSingleItem: progEnvParam | progLocalParam;
-
-programMultipleItem: progEnvParams | progLocalParams;
-
-progEnvParams: PROGRAM ENV '[' progEnvParamNums ']'
- {
- memset($$, 0, sizeof($$));
- $$[0] = state->state_param_enum;
- $$[1] = STATE_ENV;
- $$[2] = $4[0];
- $$[3] = $4[1];
- }
- ;
-
-progEnvParamNums: progEnvParamNum
- {
- $$[0] = $1;
- $$[1] = $1;
- }
- | progEnvParamNum DOT_DOT progEnvParamNum
- {
- $$[0] = $1;
- $$[1] = $3;
- }
- ;
-
-progEnvParam: PROGRAM ENV '[' progEnvParamNum ']'
- {
- memset($$, 0, sizeof($$));
- $$[0] = state->state_param_enum;
- $$[1] = STATE_ENV;
- $$[2] = $4;
- $$[3] = $4;
- }
- ;
-
-progLocalParams: PROGRAM LOCAL '[' progLocalParamNums ']'
- {
- memset($$, 0, sizeof($$));
- $$[0] = state->state_param_enum;
- $$[1] = STATE_LOCAL;
- $$[2] = $4[0];
- $$[3] = $4[1];
- }
-
-progLocalParamNums: progLocalParamNum
- {
- $$[0] = $1;
- $$[1] = $1;
- }
- | progLocalParamNum DOT_DOT progLocalParamNum
- {
- $$[0] = $1;
- $$[1] = $3;
- }
- ;
-
-progLocalParam: PROGRAM LOCAL '[' progLocalParamNum ']'
- {
- memset($$, 0, sizeof($$));
- $$[0] = state->state_param_enum;
- $$[1] = STATE_LOCAL;
- $$[2] = $4;
- $$[3] = $4;
- }
- ;
-
-progEnvParamNum: INTEGER
- {
- if ((unsigned) $1 >= state->limits->MaxEnvParams) {
- yyerror(& @1, state, "invalid environment parameter reference");
- YYERROR;
- }
- $$ = $1;
- }
- ;
-
-progLocalParamNum: INTEGER
- {
- if ((unsigned) $1 >= state->limits->MaxLocalParams) {
- yyerror(& @1, state, "invalid local parameter reference");
- YYERROR;
- }
- $$ = $1;
- }
- ;
-
-
-
-paramConstDecl: paramConstScalarDecl | paramConstVector;
-paramConstUse: paramConstScalarUse | paramConstVector;
-
-paramConstScalarDecl: signedFloatConstant
- {
- $$.count = 4;
- $$.data[0] = $1;
- $$.data[1] = $1;
- $$.data[2] = $1;
- $$.data[3] = $1;
- }
- ;
-
-paramConstScalarUse: REAL
- {
- $$.count = 1;
- $$.data[0] = $1;
- $$.data[1] = $1;
- $$.data[2] = $1;
- $$.data[3] = $1;
- }
- | INTEGER
- {
- $$.count = 1;
- $$.data[0] = (float) $1;
- $$.data[1] = (float) $1;
- $$.data[2] = (float) $1;
- $$.data[3] = (float) $1;
- }
- ;
-
-paramConstVector: '{' signedFloatConstant '}'
- {
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = 0.0f;
- $$.data[2] = 0.0f;
- $$.data[3] = 1.0f;
- }
- | '{' signedFloatConstant ',' signedFloatConstant '}'
- {
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = 0.0f;
- $$.data[3] = 1.0f;
- }
- | '{' signedFloatConstant ',' signedFloatConstant ','
- signedFloatConstant '}'
- {
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = $6;
- $$.data[3] = 1.0f;
- }
- | '{' signedFloatConstant ',' signedFloatConstant ','
- signedFloatConstant ',' signedFloatConstant '}'
- {
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = $6;
- $$.data[3] = $8;
- }
- ;
-
-signedFloatConstant: optionalSign REAL
- {
- $$ = ($1) ? -$2 : $2;
- }
- | optionalSign INTEGER
- {
- $$ = (float)(($1) ? -$2 : $2);
- }
- ;
-
-optionalSign: '+' { $$ = FALSE; }
- | '-' { $$ = TRUE; }
- | { $$ = FALSE; }
- ;
-
-TEMP_statement: optVarSize TEMP { $<integer>$ = $2; } varNameList
- ;
-
-optVarSize: string
- {
- /* NV_fragment_program_option defines the size qualifiers in a
- * fairly broken way. "SHORT" or "LONG" can optionally be used
- * before TEMP or OUTPUT. However, neither is a reserved word!
- * This means that we have to parse it as an identifier, then check
- * to make sure it's one of the valid values. *sigh*
- *
- * In addition, the grammar in the extension spec does *not* allow
- * the size specifier to be optional, but all known implementations
- * do.
- */
- if (!state->option.NV_fragment) {
- yyerror(& @1, state, "unexpected IDENTIFIER");
- YYERROR;
- }
-
- if (strcmp("SHORT", $1) == 0) {
- } else if (strcmp("LONG", $1) == 0) {
- } else {
- char *const err_str =
- make_error_string("invalid storage size specifier \"%s\"",
- $1);
-
- yyerror(& @1, state, (err_str != NULL)
- ? err_str : "invalid storage size specifier");
-
- if (err_str != NULL) {
- free(err_str);
- }
-
- YYERROR;
- }
- }
- |
- {
- }
- ;
-
-ADDRESS_statement: ADDRESS { $<integer>$ = $1; } varNameList
- ;
-
-varNameList: varNameList ',' IDENTIFIER
- {
- if (!declare_variable(state, $3, $<integer>0, & @3)) {
- free($3);
- YYERROR;
- }
- }
- | IDENTIFIER
- {
- if (!declare_variable(state, $1, $<integer>0, & @1)) {
- free($1);
- YYERROR;
- }
- }
- ;
-
-OUTPUT_statement: optVarSize OUTPUT IDENTIFIER '=' resultBinding
- {
- struct asm_symbol *const s =
- declare_variable(state, $3, at_output, & @3);
-
- if (s == NULL) {
- free($3);
- YYERROR;
- } else {
- s->output_binding = $5;
- }
- }
- ;
-
-resultBinding: RESULT POSITION
- {
- if (state->mode == ARB_vertex) {
- $$ = VERT_RESULT_HPOS;
- } else {
- yyerror(& @2, state, "invalid program result name");
- YYERROR;
- }
- }
- | RESULT FOGCOORD
- {
- if (state->mode == ARB_vertex) {
- $$ = VERT_RESULT_FOGC;
- } else {
- yyerror(& @2, state, "invalid program result name");
- YYERROR;
- }
- }
- | RESULT resultColBinding
- {
- $$ = $2;
- }
- | RESULT POINTSIZE
- {
- if (state->mode == ARB_vertex) {
- $$ = VERT_RESULT_PSIZ;
- } else {
- yyerror(& @2, state, "invalid program result name");
- YYERROR;
- }
- }
- | RESULT TEXCOORD optTexCoordUnitNum
- {
- if (state->mode == ARB_vertex) {
- $$ = VERT_RESULT_TEX0 + $3;
- } else {
- yyerror(& @2, state, "invalid program result name");
- YYERROR;
- }
- }
- | RESULT DEPTH
- {
- if (state->mode == ARB_fragment) {
- $$ = FRAG_RESULT_DEPTH;
- } else {
- yyerror(& @2, state, "invalid program result name");
- YYERROR;
- }
- }
- ;
-
-resultColBinding: COLOR optResultFaceType optResultColorType
- {
- $$ = $2 + $3;
- }
- ;
-
-optResultFaceType:
- {
- $$ = (state->mode == ARB_vertex)
- ? VERT_RESULT_COL0
- : FRAG_RESULT_COLOR;
- }
- | FRONT
- {
- if (state->mode == ARB_vertex) {
- $$ = VERT_RESULT_COL0;
- } else {
- yyerror(& @1, state, "invalid program result name");
- YYERROR;
- }
- }
- | BACK
- {
- if (state->mode == ARB_vertex) {
- $$ = VERT_RESULT_BFC0;
- } else {
- yyerror(& @1, state, "invalid program result name");
- YYERROR;
- }
- }
- ;
-
-optResultColorType:
- {
- $$ = 0;
- }
- | PRIMARY
- {
- if (state->mode == ARB_vertex) {
- $$ = 0;
- } else {
- yyerror(& @1, state, "invalid program result name");
- YYERROR;
- }
- }
- | SECONDARY
- {
- if (state->mode == ARB_vertex) {
- $$ = 1;
- } else {
- yyerror(& @1, state, "invalid program result name");
- YYERROR;
- }
- }
- ;
-
-optFaceType: { $$ = 0; }
- | FRONT { $$ = 0; }
- | BACK { $$ = 1; }
- ;
-
-optColorType: { $$ = 0; }
- | PRIMARY { $$ = 0; }
- | SECONDARY { $$ = 1; }
- ;
-
-optTexCoordUnitNum: { $$ = 0; }
- | '[' texCoordUnitNum ']' { $$ = $2; }
- ;
-
-optTexImageUnitNum: { $$ = 0; }
- | '[' texImageUnitNum ']' { $$ = $2; }
- ;
-
-optLegacyTexUnitNum: { $$ = 0; }
- | '[' legacyTexUnitNum ']' { $$ = $2; }
- ;
-
-texCoordUnitNum: INTEGER
- {
- if ((unsigned) $1 >= state->MaxTextureCoordUnits) {
- yyerror(& @1, state, "invalid texture coordinate unit selector");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-texImageUnitNum: INTEGER
- {
- if ((unsigned) $1 >= state->MaxTextureImageUnits) {
- yyerror(& @1, state, "invalid texture image unit selector");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-legacyTexUnitNum: INTEGER
- {
- if ((unsigned) $1 >= state->MaxTextureUnits) {
- yyerror(& @1, state, "invalid texture unit selector");
- YYERROR;
- }
-
- $$ = $1;
- }
- ;
-
-ALIAS_statement: ALIAS IDENTIFIER '=' USED_IDENTIFIER
- {
- struct asm_symbol *exist = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, $2);
- struct asm_symbol *target = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, $4);
-
- free($4);
-
- if (exist != NULL) {
- char m[1000];
- _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", $2);
- free($2);
- yyerror(& @2, state, m);
- YYERROR;
- } else if (target == NULL) {
- free($2);
- yyerror(& @4, state,
- "undefined variable binding in ALIAS statement");
- YYERROR;
- } else {
- _mesa_symbol_table_add_symbol(state->st, 0, $2, target);
- }
- }
- ;
-
-string: IDENTIFIER
- | USED_IDENTIFIER
- ;
-
-%%
-
-void
-asm_instruction_set_operands(struct asm_instruction *inst,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
-{
- /* In the core ARB extensions only the KIL instruction doesn't have a
- * destination register.
- */
- if (dst == NULL) {
- init_dst_reg(& inst->Base.DstReg);
- } else {
- inst->Base.DstReg = *dst;
- }
-
- /* The only instruction that doesn't have any source registers is the
- * condition-code based KIL instruction added by NV_fragment_program_option.
- */
- if (src0 != NULL) {
- inst->Base.SrcReg[0] = src0->Base;
- inst->SrcReg[0] = *src0;
- } else {
- init_src_reg(& inst->SrcReg[0]);
- }
-
- if (src1 != NULL) {
- inst->Base.SrcReg[1] = src1->Base;
- inst->SrcReg[1] = *src1;
- } else {
- init_src_reg(& inst->SrcReg[1]);
- }
-
- if (src2 != NULL) {
- inst->Base.SrcReg[2] = src2->Base;
- inst->SrcReg[2] = *src2;
- } else {
- init_src_reg(& inst->SrcReg[2]);
- }
-}
-
-
-struct asm_instruction *
-asm_instruction_ctor(gl_inst_opcode op,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
-{
- struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
-
- if (inst) {
- _mesa_init_instructions(& inst->Base, 1);
- inst->Base.Opcode = op;
-
- asm_instruction_set_operands(inst, dst, src0, src1, src2);
- }
-
- return inst;
-}
-
-
-struct asm_instruction *
-asm_instruction_copy_ctor(const struct prog_instruction *base,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
-{
- struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
-
- if (inst) {
- _mesa_init_instructions(& inst->Base, 1);
- inst->Base.Opcode = base->Opcode;
- inst->Base.CondUpdate = base->CondUpdate;
- inst->Base.CondDst = base->CondDst;
- inst->Base.SaturateMode = base->SaturateMode;
- inst->Base.Precision = base->Precision;
-
- asm_instruction_set_operands(inst, dst, src0, src1, src2);
- }
-
- return inst;
-}
-
-
-void
-init_dst_reg(struct prog_dst_register *r)
-{
- memset(r, 0, sizeof(*r));
- r->File = PROGRAM_UNDEFINED;
- r->WriteMask = WRITEMASK_XYZW;
- r->CondMask = COND_TR;
- r->CondSwizzle = SWIZZLE_NOOP;
-}
-
-
-/** Like init_dst_reg() but set the File and Index fields. */
-void
-set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index)
-{
- const GLint maxIndex = 1 << INST_INDEX_BITS;
- const GLint minIndex = 0;
- ASSERT(index >= minIndex);
- (void) minIndex;
- ASSERT(index <= maxIndex);
- (void) maxIndex;
- ASSERT(file == PROGRAM_TEMPORARY ||
- file == PROGRAM_ADDRESS ||
- file == PROGRAM_OUTPUT);
- memset(r, 0, sizeof(*r));
- r->File = file;
- r->Index = index;
- r->WriteMask = WRITEMASK_XYZW;
- r->CondMask = COND_TR;
- r->CondSwizzle = SWIZZLE_NOOP;
-}
-
-
-void
-init_src_reg(struct asm_src_register *r)
-{
- memset(r, 0, sizeof(*r));
- r->Base.File = PROGRAM_UNDEFINED;
- r->Base.Swizzle = SWIZZLE_NOOP;
- r->Symbol = NULL;
-}
-
-
-/** Like init_src_reg() but set the File and Index fields.
- * \return GL_TRUE if a valid src register, GL_FALSE otherwise
- */
-void
-set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index)
-{
- set_src_reg_swz(r, file, index, SWIZZLE_XYZW);
-}
-
-
-void
-set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index,
- GLuint swizzle)
-{
- const GLint maxIndex = (1 << INST_INDEX_BITS) - 1;
- const GLint minIndex = -(1 << INST_INDEX_BITS);
- ASSERT(file < PROGRAM_FILE_MAX);
- ASSERT(index >= minIndex);
- (void) minIndex;
- ASSERT(index <= maxIndex);
- (void) maxIndex;
- memset(r, 0, sizeof(*r));
- r->Base.File = file;
- r->Base.Index = index;
- r->Base.Swizzle = swizzle;
- r->Symbol = NULL;
-}
-
-
-/**
- * Validate the set of inputs used by a program
- *
- * Validates that legal sets of inputs are used by the program. In this case
- * "used" included both reading the input or binding the input to a name using
- * the \c ATTRIB command.
- *
- * \return
- * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise.
- */
-int
-validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state)
-{
- const int inputs = state->prog->InputsRead | state->InputsBound;
-
- if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) {
- yyerror(locp, state, "illegal use of generic attribute and name attribute");
- return 0;
- }
-
- return 1;
-}
-
-
-struct asm_symbol *
-declare_variable(struct asm_parser_state *state, char *name, enum asm_type t,
- struct YYLTYPE *locp)
-{
- struct asm_symbol *s = NULL;
- struct asm_symbol *exist = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, name);
-
-
- if (exist != NULL) {
- yyerror(locp, state, "redeclared identifier");
- } else {
- s = calloc(1, sizeof(struct asm_symbol));
- s->name = name;
- s->type = t;
-
- switch (t) {
- case at_temp:
- if (state->prog->NumTemporaries >= state->limits->MaxTemps) {
- yyerror(locp, state, "too many temporaries declared");
- free(s);
- return NULL;
- }
-
- s->temp_binding = state->prog->NumTemporaries;
- state->prog->NumTemporaries++;
- break;
-
- case at_address:
- if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) {
- yyerror(locp, state, "too many address registers declared");
- free(s);
- return NULL;
- }
-
- /* FINISHME: Add support for multiple address registers.
- */
- state->prog->NumAddressRegs++;
- break;
-
- default:
- break;
- }
-
- _mesa_symbol_table_add_symbol(state->st, 0, s->name, s);
- s->next = state->sym;
- state->sym = s;
- }
-
- return s;
-}
-
-
-int add_state_reference(struct gl_program_parameter_list *param_list,
- const gl_state_index tokens[STATE_LENGTH])
-{
- const GLuint size = 4; /* XXX fix */
- char *name;
- GLint index;
-
- name = _mesa_program_state_string(tokens);
- index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name,
- size, GL_NONE, NULL, tokens, 0x0);
- param_list->StateFlags |= _mesa_program_state_flags(tokens);
-
- /* free name string here since we duplicated it in add_parameter() */
- free(name);
-
- return index;
-}
-
-
-int
-initialize_symbol_from_state(struct gl_program *prog,
- struct asm_symbol *param_var,
- const gl_state_index tokens[STATE_LENGTH])
-{
- int idx = -1;
- gl_state_index state_tokens[STATE_LENGTH];
-
-
- memcpy(state_tokens, tokens, sizeof(state_tokens));
-
- param_var->type = at_param;
- param_var->param_binding_type = PROGRAM_STATE_VAR;
-
- /* If we are adding a STATE_MATRIX that has multiple rows, we need to
- * unroll it and call add_state_reference() for each row
- */
- if ((state_tokens[0] == STATE_MODELVIEW_MATRIX ||
- state_tokens[0] == STATE_PROJECTION_MATRIX ||
- state_tokens[0] == STATE_MVP_MATRIX ||
- state_tokens[0] == STATE_TEXTURE_MATRIX ||
- state_tokens[0] == STATE_PROGRAM_MATRIX)
- && (state_tokens[2] != state_tokens[3])) {
- int row;
- const int first_row = state_tokens[2];
- const int last_row = state_tokens[3];
-
- for (row = first_row; row <= last_row; row++) {
- state_tokens[2] = state_tokens[3] = row;
-
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
-
- param_var->param_binding_length++;
- }
- }
- else {
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
- }
-
- return idx;
-}
-
-
-int
-initialize_symbol_from_param(struct gl_program *prog,
- struct asm_symbol *param_var,
- const gl_state_index tokens[STATE_LENGTH])
-{
- int idx = -1;
- gl_state_index state_tokens[STATE_LENGTH];
-
-
- memcpy(state_tokens, tokens, sizeof(state_tokens));
-
- assert((state_tokens[0] == STATE_VERTEX_PROGRAM)
- || (state_tokens[0] == STATE_FRAGMENT_PROGRAM));
- assert((state_tokens[1] == STATE_ENV)
- || (state_tokens[1] == STATE_LOCAL));
-
- /*
- * The param type is STATE_VAR. The program parameter entry will
- * effectively be a pointer into the LOCAL or ENV parameter array.
- */
- param_var->type = at_param;
- param_var->param_binding_type = PROGRAM_STATE_VAR;
-
- /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements,
- * we need to unroll it and call add_state_reference() for each row
- */
- if (state_tokens[2] != state_tokens[3]) {
- int row;
- const int first_row = state_tokens[2];
- const int last_row = state_tokens[3];
-
- for (row = first_row; row <= last_row; row++) {
- state_tokens[2] = state_tokens[3] = row;
-
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
- }
- }
- else {
- idx = add_state_reference(prog->Parameters, state_tokens);
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
- }
-
- return idx;
-}
-
-
-/**
- * Put a float/vector constant/literal into the parameter list.
- * \param param_var returns info about the parameter/constant's location,
- * binding, type, etc.
- * \param vec the vector/constant to add
- * \param allowSwizzle if true, try to consolidate constants which only differ
- * by a swizzle. We don't want to do this when building
- * arrays of constants that may be indexed indirectly.
- * \return index of the constant in the parameter list.
- */
-int
-initialize_symbol_from_const(struct gl_program *prog,
- struct asm_symbol *param_var,
- const struct asm_vector *vec,
- GLboolean allowSwizzle)
-{
- unsigned swizzle;
- const int idx = _mesa_add_unnamed_constant(prog->Parameters,
- vec->data, vec->count,
- allowSwizzle ? &swizzle : NULL);
-
- param_var->type = at_param;
- param_var->param_binding_type = PROGRAM_CONSTANT;
-
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
-
- return idx;
-}
-
-
-char *
-make_error_string(const char *fmt, ...)
-{
- int length;
- char *str;
- va_list args;
-
-
- /* Call vsnprintf once to determine how large the final string is. Call it
- * again to do the actual formatting. from the vsnprintf manual page:
- *
- * Upon successful return, these functions return the number of
- * characters printed (not including the trailing '\0' used to end
- * output to strings).
- */
- va_start(args, fmt);
- length = 1 + vsnprintf(NULL, 0, fmt, args);
- va_end(args);
-
- str = malloc(length);
- if (str) {
- va_start(args, fmt);
- vsnprintf(str, length, fmt, args);
- va_end(args);
- }
-
- return str;
-}
-
-
-void
-yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s)
-{
- char *err_str;
-
-
- err_str = make_error_string("glProgramStringARB(%s)\n", s);
- if (err_str) {
- _mesa_error(state->ctx, GL_INVALID_OPERATION, "%s", err_str);
- free(err_str);
- }
-
- err_str = make_error_string("line %u, char %u: error: %s\n",
- locp->first_line, locp->first_column, s);
- _mesa_set_program_error(state->ctx, locp->position, err_str);
-
- if (err_str) {
- free(err_str);
- }
-}
-
-
-GLboolean
-_mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str,
- GLsizei len, struct asm_parser_state *state)
-{
- struct asm_instruction *inst;
- unsigned i;
- GLubyte *strz;
- GLboolean result = GL_FALSE;
- void *temp;
- struct asm_symbol *sym;
-
- state->ctx = ctx;
- state->prog->Target = target;
- state->prog->Parameters = _mesa_new_parameter_list();
-
- /* Make a copy of the program string and force it to be NUL-terminated.
- */
- strz = (GLubyte *) malloc(len + 1);
- if (strz == NULL) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB");
- return GL_FALSE;
- }
- memcpy (strz, str, len);
- strz[len] = '\0';
-
- state->prog->String = strz;
-
- state->st = _mesa_symbol_table_ctor();
-
- state->limits = (target == GL_VERTEX_PROGRAM_ARB)
- ? & ctx->Const.VertexProgram
- : & ctx->Const.FragmentProgram;
-
- state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
- state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits;
- state->MaxTextureUnits = ctx->Const.MaxTextureUnits;
- state->MaxClipPlanes = ctx->Const.MaxClipPlanes;
- state->MaxLights = ctx->Const.MaxLights;
- state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices;
-
- state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB)
- ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM;
-
- _mesa_set_program_error(ctx, -1, NULL);
-
- _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len);
- yyparse(state);
- _mesa_program_lexer_dtor(state->scanner);
-
-
- if (ctx->Program.ErrorPos != -1) {
- goto error;
- }
-
- if (! _mesa_layout_parameters(state)) {
- struct YYLTYPE loc;
-
- loc.first_line = 0;
- loc.first_column = 0;
- loc.position = len;
-
- yyerror(& loc, state, "invalid PARAM usage");
- goto error;
- }
-
-
-
- /* Add one instruction to store the "END" instruction.
- */
- state->prog->Instructions =
- _mesa_alloc_instructions(state->prog->NumInstructions + 1);
- inst = state->inst_head;
- for (i = 0; i < state->prog->NumInstructions; i++) {
- struct asm_instruction *const temp = inst->next;
-
- state->prog->Instructions[i] = inst->Base;
- inst = temp;
- }
-
- /* Finally, tag on an OPCODE_END instruction */
- {
- const GLuint numInst = state->prog->NumInstructions;
- _mesa_init_instructions(state->prog->Instructions + numInst, 1);
- state->prog->Instructions[numInst].Opcode = OPCODE_END;
- }
- state->prog->NumInstructions++;
-
- state->prog->NumParameters = state->prog->Parameters->NumParameters;
- state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead);
-
- /*
- * Initialize native counts to logical counts. The device driver may
- * change them if program is translated into a hardware program.
- */
- state->prog->NumNativeInstructions = state->prog->NumInstructions;
- state->prog->NumNativeTemporaries = state->prog->NumTemporaries;
- state->prog->NumNativeParameters = state->prog->NumParameters;
- state->prog->NumNativeAttributes = state->prog->NumAttributes;
- state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs;
-
- result = GL_TRUE;
-
-error:
- for (inst = state->inst_head; inst != NULL; inst = temp) {
- temp = inst->next;
- free(inst);
- }
-
- state->inst_head = NULL;
- state->inst_tail = NULL;
-
- for (sym = state->sym; sym != NULL; sym = temp) {
- temp = sym->next;
-
- free((void *) sym->name);
- free(sym);
- }
- state->sym = NULL;
-
- _mesa_symbol_table_dtor(state->st);
- state->st = NULL;
-
- return result;
-}
+%{
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "main/mtypes.h"
+#include "main/imports.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
+#include "program/prog_parameter_layout.h"
+#include "program/prog_statevars.h"
+#include "program/prog_instruction.h"
+
+#include "program/symbol_table.h"
+#include "program/program_parser.h"
+
+extern void *yy_scan_string(char *);
+extern void yy_delete_buffer(void *);
+
+static struct asm_symbol *declare_variable(struct asm_parser_state *state,
+ char *name, enum asm_type t, struct YYLTYPE *locp);
+
+static int add_state_reference(struct gl_program_parameter_list *param_list,
+ const gl_state_index tokens[STATE_LENGTH]);
+
+static int initialize_symbol_from_state(struct gl_program *prog,
+ struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
+
+static int initialize_symbol_from_param(struct gl_program *prog,
+ struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
+
+static int initialize_symbol_from_const(struct gl_program *prog,
+ struct asm_symbol *param_var, const struct asm_vector *vec,
+ GLboolean allowSwizzle);
+
+static int yyparse(struct asm_parser_state *state);
+
+static char *make_error_string(const char *fmt, ...);
+
+static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state,
+ const char *s);
+
+static int validate_inputs(struct YYLTYPE *locp,
+ struct asm_parser_state *state);
+
+static void init_dst_reg(struct prog_dst_register *r);
+
+static void set_dst_reg(struct prog_dst_register *r,
+ gl_register_file file, GLint index);
+
+static void init_src_reg(struct asm_src_register *r);
+
+static void set_src_reg(struct asm_src_register *r,
+ gl_register_file file, GLint index);
+
+static void set_src_reg_swz(struct asm_src_register *r,
+ gl_register_file file, GLint index, GLuint swizzle);
+
+static void asm_instruction_set_operands(struct asm_instruction *inst,
+ const struct prog_dst_register *dst, const struct asm_src_register *src0,
+ const struct asm_src_register *src1, const struct asm_src_register *src2);
+
+static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
+ const struct prog_dst_register *dst, const struct asm_src_register *src0,
+ const struct asm_src_register *src1, const struct asm_src_register *src2);
+
+static struct asm_instruction *asm_instruction_copy_ctor(
+ const struct prog_instruction *base, const struct prog_dst_register *dst,
+ const struct asm_src_register *src0, const struct asm_src_register *src1,
+ const struct asm_src_register *src2);
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE (!FALSE)
+#endif
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (YYID(N)) { \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
+ (Current).position = YYRHSLOC(Rhs, 1).position; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC(Rhs, N).last_column; \
+ } else { \
+ (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
+ (Current).last_line = (Current).first_line; \
+ (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \
+ (Current).last_column = (Current).first_column; \
+ (Current).position = YYRHSLOC(Rhs, 0).position \
+ + (Current).first_column; \
+ } \
+ } while(YYID(0))
+
+#define YYLEX_PARAM state->scanner
+%}
+
+%pure-parser
+%locations
+%parse-param { struct asm_parser_state *state }
+%error-verbose
+%lex-param { void *scanner }
+
+%union {
+ struct asm_instruction *inst;
+ struct asm_symbol *sym;
+ struct asm_symbol temp_sym;
+ struct asm_swizzle_mask swiz_mask;
+ struct asm_src_register src_reg;
+ struct prog_dst_register dst_reg;
+ struct prog_instruction temp_inst;
+ char *string;
+ unsigned result;
+ unsigned attrib;
+ int integer;
+ float real;
+ gl_state_index state[STATE_LENGTH];
+ int negate;
+ struct asm_vector vector;
+ gl_inst_opcode opcode;
+
+ struct {
+ unsigned swz;
+ unsigned rgba_valid:1;
+ unsigned xyzw_valid:1;
+ unsigned negate:1;
+ } ext_swizzle;
+}
+
+%token ARBvp_10 ARBfp_10
+
+/* Tokens for assembler pseudo-ops */
+%token <integer> ADDRESS
+%token ALIAS ATTRIB
+%token OPTION OUTPUT
+%token PARAM
+%token <integer> TEMP
+%token END
+
+ /* Tokens for instructions */
+%token <temp_inst> BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP TRI_OP VECTOR_OP
+%token <temp_inst> ARL KIL SWZ TXD_OP
+
+%token <integer> INTEGER
+%token <real> REAL
+
+%token AMBIENT ATTENUATION
+%token BACK
+%token CLIP COLOR
+%token DEPTH DIFFUSE DIRECTION
+%token EMISSION ENV EYE
+%token FOG FOGCOORD FRAGMENT FRONT
+%token HALF
+%token INVERSE INVTRANS
+%token LIGHT LIGHTMODEL LIGHTPROD LOCAL
+%token MATERIAL MAT_PROGRAM MATRIX MATRIXINDEX MODELVIEW MVP
+%token NORMAL
+%token OBJECT
+%token PALETTE PARAMS PLANE POINT_TOK POINTSIZE POSITION PRIMARY PROGRAM PROJECTION
+%token RANGE RESULT ROW
+%token SCENECOLOR SECONDARY SHININESS SIZE_TOK SPECULAR SPOT STATE
+%token TEXCOORD TEXENV TEXGEN TEXGEN_Q TEXGEN_R TEXGEN_S TEXGEN_T TEXTURE TRANSPOSE
+%token TEXTURE_UNIT TEX_1D TEX_2D TEX_3D TEX_CUBE TEX_RECT
+%token TEX_SHADOW1D TEX_SHADOW2D TEX_SHADOWRECT
+%token TEX_ARRAY1D TEX_ARRAY2D TEX_ARRAYSHADOW1D TEX_ARRAYSHADOW2D
+%token VERTEX VTXATTRIB
+%token WEIGHT
+
+%token <string> IDENTIFIER USED_IDENTIFIER
+%type <string> string
+%token <swiz_mask> MASK4 MASK3 MASK2 MASK1 SWIZZLE
+%token DOT_DOT
+%token DOT
+
+%type <inst> instruction ALU_instruction TexInstruction
+%type <inst> ARL_instruction VECTORop_instruction
+%type <inst> SCALARop_instruction BINSCop_instruction BINop_instruction
+%type <inst> TRIop_instruction TXD_instruction SWZ_instruction SAMPLE_instruction
+%type <inst> KIL_instruction
+
+%type <dst_reg> dstReg maskedDstReg maskedAddrReg
+%type <src_reg> srcReg scalarUse scalarSrcReg swizzleSrcReg
+%type <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle
+%type <ext_swizzle> extSwizComp extSwizSel
+%type <swiz_mask> optionalMask
+
+%type <sym> progParamArray
+%type <integer> addrRegRelOffset addrRegPosOffset addrRegNegOffset
+%type <src_reg> progParamArrayMem progParamArrayAbs progParamArrayRel
+%type <sym> addrReg
+%type <swiz_mask> addrComponent addrWriteMask
+
+%type <dst_reg> ccMaskRule ccTest ccMaskRule2 ccTest2 optionalCcMask
+
+%type <result> resultBinding resultColBinding
+%type <integer> optFaceType optColorType
+%type <integer> optResultFaceType optResultColorType
+
+%type <integer> optTexImageUnitNum texImageUnitNum
+%type <integer> optTexCoordUnitNum texCoordUnitNum
+%type <integer> optLegacyTexUnitNum legacyTexUnitNum
+%type <integer> texImageUnit texTarget
+%type <integer> vtxAttribNum
+
+%type <attrib> attribBinding vtxAttribItem fragAttribItem
+
+%type <temp_sym> paramSingleInit paramSingleItemDecl
+%type <integer> optArraySize
+
+%type <state> stateSingleItem stateMultipleItem
+%type <state> stateMaterialItem
+%type <state> stateLightItem stateLightModelItem stateLightProdItem
+%type <state> stateTexGenItem stateFogItem stateClipPlaneItem statePointItem
+%type <state> stateMatrixItem stateMatrixRow stateMatrixRows
+%type <state> stateTexEnvItem stateDepthItem
+
+%type <state> stateLModProperty
+%type <state> stateMatrixName optMatrixRows
+
+%type <integer> stateMatProperty
+%type <integer> stateLightProperty stateSpotProperty
+%type <integer> stateLightNumber stateLProdProperty
+%type <integer> stateTexGenType stateTexGenCoord
+%type <integer> stateTexEnvProperty
+%type <integer> stateFogProperty
+%type <integer> stateClipPlaneNum
+%type <integer> statePointProperty
+
+%type <integer> stateOptMatModifier stateMatModifier stateMatrixRowNum
+%type <integer> stateOptModMatNum stateModMatNum statePaletteMatNum
+%type <integer> stateProgramMatNum
+
+%type <integer> ambDiffSpecProperty
+
+%type <state> programSingleItem progEnvParam progLocalParam
+%type <state> programMultipleItem progEnvParams progLocalParams
+
+%type <temp_sym> paramMultipleInit paramMultInitList paramMultipleItem
+%type <temp_sym> paramSingleItemUse
+
+%type <integer> progEnvParamNum progLocalParamNum
+%type <state> progEnvParamNums progLocalParamNums
+
+%type <vector> paramConstDecl paramConstUse
+%type <vector> paramConstScalarDecl paramConstScalarUse paramConstVector
+%type <real> signedFloatConstant
+%type <negate> optionalSign
+
+%{
+extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param,
+ void *yyscanner);
+%}
+
+%%
+
+program: language optionSequence statementSequence END
+ ;
+
+language: ARBvp_10
+ {
+ if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) {
+ yyerror(& @1, state, "invalid fragment program header");
+
+ }
+ state->mode = ARB_vertex;
+ }
+ | ARBfp_10
+ {
+ if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) {
+ yyerror(& @1, state, "invalid vertex program header");
+ }
+ state->mode = ARB_fragment;
+
+ state->option.TexRect =
+ (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE);
+ }
+ ;
+
+optionSequence: optionSequence option
+ |
+ ;
+
+option: OPTION string ';'
+ {
+ int valid = 0;
+
+ if (state->mode == ARB_vertex) {
+ valid = _mesa_ARBvp_parse_option(state, $2);
+ } else if (state->mode == ARB_fragment) {
+ valid = _mesa_ARBfp_parse_option(state, $2);
+ }
+
+
+ free($2);
+
+ if (!valid) {
+ const char *const err_str = (state->mode == ARB_vertex)
+ ? "invalid ARB vertex program option"
+ : "invalid ARB fragment program option";
+
+ yyerror(& @2, state, err_str);
+ YYERROR;
+ }
+ }
+ ;
+
+statementSequence: statementSequence statement
+ |
+ ;
+
+statement: instruction ';'
+ {
+ if ($1 != NULL) {
+ if (state->inst_tail == NULL) {
+ state->inst_head = $1;
+ } else {
+ state->inst_tail->next = $1;
+ }
+
+ state->inst_tail = $1;
+ $1->next = NULL;
+
+ state->prog->NumInstructions++;
+ }
+ }
+ | namingStatement ';'
+ ;
+
+instruction: ALU_instruction
+ {
+ $$ = $1;
+ state->prog->NumAluInstructions++;
+ }
+ | TexInstruction
+ {
+ $$ = $1;
+ state->prog->NumTexInstructions++;
+ }
+ ;
+
+ALU_instruction: ARL_instruction
+ | VECTORop_instruction
+ | SCALARop_instruction
+ | BINSCop_instruction
+ | BINop_instruction
+ | TRIop_instruction
+ | SWZ_instruction
+ ;
+
+TexInstruction: SAMPLE_instruction
+ | KIL_instruction
+ | TXD_instruction
+ ;
+
+ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg
+ {
+ $$ = asm_instruction_ctor(OPCODE_ARL, & $2, & $4, NULL, NULL);
+ }
+ ;
+
+VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
+ }
+ ;
+
+SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
+ }
+ ;
+
+BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
+ }
+ ;
+
+
+BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
+ }
+ ;
+
+TRIop_instruction: TRI_OP maskedDstReg ','
+ swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
+ }
+ ;
+
+SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
+ if ($$ != NULL) {
+ const GLbitfield tex_mask = (1U << $6);
+ GLbitfield shadow_tex = 0;
+ GLbitfield target_mask = 0;
+
+
+ $$->Base.TexSrcUnit = $6;
+
+ if ($8 < 0) {
+ shadow_tex = tex_mask;
+
+ $$->Base.TexSrcTarget = -$8;
+ $$->Base.TexShadow = 1;
+ } else {
+ $$->Base.TexSrcTarget = $8;
+ }
+
+ target_mask = (1U << $$->Base.TexSrcTarget);
+
+ /* If this texture unit was previously accessed and that access
+ * had a different texture target, generate an error.
+ *
+ * If this texture unit was previously accessed and that access
+ * had a different shadow mode, generate an error.
+ */
+ if ((state->prog->TexturesUsed[$6] != 0)
+ && ((state->prog->TexturesUsed[$6] != target_mask)
+ || ((state->prog->ShadowSamplers & tex_mask)
+ != shadow_tex))) {
+ yyerror(& @8, state,
+ "multiple targets used on one texture image unit");
+ YYERROR;
+ }
+
+
+ state->prog->TexturesUsed[$6] |= target_mask;
+ state->prog->ShadowSamplers |= shadow_tex;
+ }
+ }
+ ;
+
+KIL_instruction: KIL swizzleSrcReg
+ {
+ $$ = asm_instruction_ctor(OPCODE_KIL, NULL, & $2, NULL, NULL);
+ state->fragment.UsesKill = 1;
+ }
+ | KIL ccTest
+ {
+ $$ = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL);
+ $$->Base.DstReg.CondMask = $2.CondMask;
+ $$->Base.DstReg.CondSwizzle = $2.CondSwizzle;
+ $$->Base.DstReg.CondSrc = $2.CondSrc;
+ state->fragment.UsesKill = 1;
+ }
+ ;
+
+TXD_instruction: TXD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
+ if ($$ != NULL) {
+ const GLbitfield tex_mask = (1U << $10);
+ GLbitfield shadow_tex = 0;
+ GLbitfield target_mask = 0;
+
+
+ $$->Base.TexSrcUnit = $10;
+
+ if ($12 < 0) {
+ shadow_tex = tex_mask;
+
+ $$->Base.TexSrcTarget = -$12;
+ $$->Base.TexShadow = 1;
+ } else {
+ $$->Base.TexSrcTarget = $12;
+ }
+
+ target_mask = (1U << $$->Base.TexSrcTarget);
+
+ /* If this texture unit was previously accessed and that access
+ * had a different texture target, generate an error.
+ *
+ * If this texture unit was previously accessed and that access
+ * had a different shadow mode, generate an error.
+ */
+ if ((state->prog->TexturesUsed[$10] != 0)
+ && ((state->prog->TexturesUsed[$10] != target_mask)
+ || ((state->prog->ShadowSamplers & tex_mask)
+ != shadow_tex))) {
+ yyerror(& @12, state,
+ "multiple targets used on one texture image unit");
+ YYERROR;
+ }
+
+
+ state->prog->TexturesUsed[$10] |= target_mask;
+ state->prog->ShadowSamplers |= shadow_tex;
+ }
+ }
+ ;
+
+texImageUnit: TEXTURE_UNIT optTexImageUnitNum
+ {
+ $$ = $2;
+ }
+ ;
+
+texTarget: TEX_1D { $$ = TEXTURE_1D_INDEX; }
+ | TEX_2D { $$ = TEXTURE_2D_INDEX; }
+ | TEX_3D { $$ = TEXTURE_3D_INDEX; }
+ | TEX_CUBE { $$ = TEXTURE_CUBE_INDEX; }
+ | TEX_RECT { $$ = TEXTURE_RECT_INDEX; }
+ | TEX_SHADOW1D { $$ = -TEXTURE_1D_INDEX; }
+ | TEX_SHADOW2D { $$ = -TEXTURE_2D_INDEX; }
+ | TEX_SHADOWRECT { $$ = -TEXTURE_RECT_INDEX; }
+ | TEX_ARRAY1D { $$ = TEXTURE_1D_ARRAY_INDEX; }
+ | TEX_ARRAY2D { $$ = TEXTURE_2D_ARRAY_INDEX; }
+ | TEX_ARRAYSHADOW1D { $$ = -TEXTURE_1D_ARRAY_INDEX; }
+ | TEX_ARRAYSHADOW2D { $$ = -TEXTURE_2D_ARRAY_INDEX; }
+ ;
+
+SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle
+ {
+ /* FIXME: Is this correct? Should the extenedSwizzle be applied
+ * FIXME: to the existing swizzle?
+ */
+ $4.Base.Swizzle = $6.swizzle;
+ $4.Base.Negate = $6.mask;
+
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
+ }
+ ;
+
+scalarSrcReg: optionalSign scalarUse
+ {
+ $$ = $2;
+
+ if ($1) {
+ $$.Base.Negate = ~$$.Base.Negate;
+ }
+ }
+ | optionalSign '|' scalarUse '|'
+ {
+ $$ = $3;
+
+ if (!state->option.NV_fragment) {
+ yyerror(& @2, state, "unexpected character '|'");
+ YYERROR;
+ }
+
+ if ($1) {
+ $$.Base.Negate = ~$$.Base.Negate;
+ }
+
+ $$.Base.Abs = 1;
+ }
+ ;
+
+scalarUse: srcReg scalarSuffix
+ {
+ $$ = $1;
+
+ $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
+ $2.swizzle);
+ }
+ | paramConstScalarUse
+ {
+ struct asm_symbol temp_sym;
+
+ if (!state->option.NV_fragment) {
+ yyerror(& @1, state, "expected scalar suffix");
+ YYERROR;
+ }
+
+ memset(& temp_sym, 0, sizeof(temp_sym));
+ temp_sym.param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & temp_sym, & $1, GL_TRUE);
+
+ set_src_reg_swz(& $$, PROGRAM_CONSTANT,
+ temp_sym.param_binding_begin,
+ temp_sym.param_binding_swizzle);
+ }
+ ;
+
+swizzleSrcReg: optionalSign srcReg swizzleSuffix
+ {
+ $$ = $2;
+
+ if ($1) {
+ $$.Base.Negate = ~$$.Base.Negate;
+ }
+
+ $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
+ $3.swizzle);
+ }
+ | optionalSign '|' srcReg swizzleSuffix '|'
+ {
+ $$ = $3;
+
+ if (!state->option.NV_fragment) {
+ yyerror(& @2, state, "unexpected character '|'");
+ YYERROR;
+ }
+
+ if ($1) {
+ $$.Base.Negate = ~$$.Base.Negate;
+ }
+
+ $$.Base.Abs = 1;
+ $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
+ $4.swizzle);
+ }
+
+ ;
+
+maskedDstReg: dstReg optionalMask optionalCcMask
+ {
+ $$ = $1;
+ $$.WriteMask = $2.mask;
+ $$.CondMask = $3.CondMask;
+ $$.CondSwizzle = $3.CondSwizzle;
+ $$.CondSrc = $3.CondSrc;
+
+ if ($$.File == PROGRAM_OUTPUT) {
+ /* Technically speaking, this should check that it is in
+ * vertex program mode. However, PositionInvariant can never be
+ * set in fragment program mode, so it is somewhat irrelevant.
+ */
+ if (state->option.PositionInvariant
+ && ($$.Index == VERT_RESULT_HPOS)) {
+ yyerror(& @1, state, "position-invariant programs cannot "
+ "write position");
+ YYERROR;
+ }
+
+ state->prog->OutputsWritten |= BITFIELD64_BIT($$.Index);
+ }
+ }
+ ;
+
+maskedAddrReg: addrReg addrWriteMask
+ {
+ set_dst_reg(& $$, PROGRAM_ADDRESS, 0);
+ $$.WriteMask = $2.mask;
+ }
+ ;
+
+extendedSwizzle: extSwizComp ',' extSwizComp ',' extSwizComp ',' extSwizComp
+ {
+ const unsigned xyzw_valid =
+ ($1.xyzw_valid << 0)
+ | ($3.xyzw_valid << 1)
+ | ($5.xyzw_valid << 2)
+ | ($7.xyzw_valid << 3);
+ const unsigned rgba_valid =
+ ($1.rgba_valid << 0)
+ | ($3.rgba_valid << 1)
+ | ($5.rgba_valid << 2)
+ | ($7.rgba_valid << 3);
+
+ /* All of the swizzle components have to be valid in either RGBA
+ * or XYZW. Note that 0 and 1 are valid in both, so both masks
+ * can have some bits set.
+ *
+ * We somewhat deviate from the spec here. It would be really hard
+ * to figure out which component is the error, and there probably
+ * isn't a lot of benefit.
+ */
+ if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) {
+ yyerror(& @1, state, "cannot combine RGBA and XYZW swizzle "
+ "components");
+ YYERROR;
+ }
+
+ $$.swizzle = MAKE_SWIZZLE4($1.swz, $3.swz, $5.swz, $7.swz);
+ $$.mask = ($1.negate) | ($3.negate << 1) | ($5.negate << 2)
+ | ($7.negate << 3);
+ }
+ ;
+
+extSwizComp: optionalSign extSwizSel
+ {
+ $$ = $2;
+ $$.negate = ($1) ? 1 : 0;
+ }
+ ;
+
+extSwizSel: INTEGER
+ {
+ if (($1 != 0) && ($1 != 1)) {
+ yyerror(& @1, state, "invalid extended swizzle selector");
+ YYERROR;
+ }
+
+ $$.swz = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
+
+ /* 0 and 1 are valid for both RGBA swizzle names and XYZW
+ * swizzle names.
+ */
+ $$.xyzw_valid = 1;
+ $$.rgba_valid = 1;
+ }
+ | string
+ {
+ char s;
+
+ if (strlen($1) > 1) {
+ yyerror(& @1, state, "invalid extended swizzle selector");
+ YYERROR;
+ }
+
+ s = $1[0];
+ free($1);
+
+ switch (s) {
+ case 'x':
+ $$.swz = SWIZZLE_X;
+ $$.xyzw_valid = 1;
+ break;
+ case 'y':
+ $$.swz = SWIZZLE_Y;
+ $$.xyzw_valid = 1;
+ break;
+ case 'z':
+ $$.swz = SWIZZLE_Z;
+ $$.xyzw_valid = 1;
+ break;
+ case 'w':
+ $$.swz = SWIZZLE_W;
+ $$.xyzw_valid = 1;
+ break;
+
+ case 'r':
+ $$.swz = SWIZZLE_X;
+ $$.rgba_valid = 1;
+ break;
+ case 'g':
+ $$.swz = SWIZZLE_Y;
+ $$.rgba_valid = 1;
+ break;
+ case 'b':
+ $$.swz = SWIZZLE_Z;
+ $$.rgba_valid = 1;
+ break;
+ case 'a':
+ $$.swz = SWIZZLE_W;
+ $$.rgba_valid = 1;
+ break;
+
+ default:
+ yyerror(& @1, state, "invalid extended swizzle selector");
+ YYERROR;
+ break;
+ }
+ }
+ ;
+
+srcReg: USED_IDENTIFIER /* temporaryReg | progParamSingle */
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, $1);
+
+ free($1);
+
+ if (s == NULL) {
+ yyerror(& @1, state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type != at_param) && (s->type != at_temp)
+ && (s->type != at_attrib)) {
+ yyerror(& @1, state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type == at_param) && s->param_is_array) {
+ yyerror(& @1, state, "non-array access to array PARAM");
+ YYERROR;
+ }
+
+ init_src_reg(& $$);
+ switch (s->type) {
+ case at_temp:
+ set_src_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding);
+ break;
+ case at_param:
+ set_src_reg_swz(& $$, s->param_binding_type,
+ s->param_binding_begin,
+ s->param_binding_swizzle);
+ break;
+ case at_attrib:
+ set_src_reg(& $$, PROGRAM_INPUT, s->attrib_binding);
+ state->prog->InputsRead |= (1U << $$.Base.Index);
+
+ if (!validate_inputs(& @1, state)) {
+ YYERROR;
+ }
+ break;
+
+ default:
+ YYERROR;
+ break;
+ }
+ }
+ | attribBinding
+ {
+ set_src_reg(& $$, PROGRAM_INPUT, $1);
+ state->prog->InputsRead |= (1U << $$.Base.Index);
+
+ if (!validate_inputs(& @1, state)) {
+ YYERROR;
+ }
+ }
+ | progParamArray '[' progParamArrayMem ']'
+ {
+ if (! $3.Base.RelAddr
+ && ((unsigned) $3.Base.Index >= $1->param_binding_length)) {
+ yyerror(& @3, state, "out of bounds array access");
+ YYERROR;
+ }
+
+ init_src_reg(& $$);
+ $$.Base.File = $1->param_binding_type;
+
+ if ($3.Base.RelAddr) {
+ state->prog->IndirectRegisterFiles |= (1 << $$.Base.File);
+ $1->param_accessed_indirectly = 1;
+
+ $$.Base.RelAddr = 1;
+ $$.Base.Index = $3.Base.Index;
+ $$.Symbol = $1;
+ } else {
+ $$.Base.Index = $1->param_binding_begin + $3.Base.Index;
+ }
+ }
+ | paramSingleItemUse
+ {
+ gl_register_file file = ($1.name != NULL)
+ ? $1.param_binding_type
+ : PROGRAM_CONSTANT;
+ set_src_reg_swz(& $$, file, $1.param_binding_begin,
+ $1.param_binding_swizzle);
+ }
+ ;
+
+dstReg: resultBinding
+ {
+ set_dst_reg(& $$, PROGRAM_OUTPUT, $1);
+ }
+ | USED_IDENTIFIER /* temporaryReg | vertexResultReg */
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, $1);
+
+ free($1);
+
+ if (s == NULL) {
+ yyerror(& @1, state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type != at_output) && (s->type != at_temp)) {
+ yyerror(& @1, state, "invalid operand variable");
+ YYERROR;
+ }
+
+ switch (s->type) {
+ case at_temp:
+ set_dst_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding);
+ break;
+ case at_output:
+ set_dst_reg(& $$, PROGRAM_OUTPUT, s->output_binding);
+ break;
+ default:
+ set_dst_reg(& $$, s->param_binding_type, s->param_binding_begin);
+ break;
+ }
+ }
+ ;
+
+progParamArray: USED_IDENTIFIER
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, $1);
+
+ free($1);
+
+ if (s == NULL) {
+ yyerror(& @1, state, "invalid operand variable");
+ YYERROR;
+ } else if ((s->type != at_param) || !s->param_is_array) {
+ yyerror(& @1, state, "array access to non-PARAM variable");
+ YYERROR;
+ } else {
+ $$ = s;
+ }
+ }
+ ;
+
+progParamArrayMem: progParamArrayAbs | progParamArrayRel;
+
+progParamArrayAbs: INTEGER
+ {
+ init_src_reg(& $$);
+ $$.Base.Index = $1;
+ }
+ ;
+
+progParamArrayRel: addrReg addrComponent addrRegRelOffset
+ {
+ /* FINISHME: Add support for multiple address registers.
+ */
+ /* FINISHME: Add support for 4-component address registers.
+ */
+ init_src_reg(& $$);
+ $$.Base.RelAddr = 1;
+ $$.Base.Index = $3;
+ }
+ ;
+
+addrRegRelOffset: { $$ = 0; }
+ | '+' addrRegPosOffset { $$ = $2; }
+ | '-' addrRegNegOffset { $$ = -$2; }
+ ;
+
+addrRegPosOffset: INTEGER
+ {
+ if (($1 < 0) || ($1 > 4095)) {
+ char s[100];
+ _mesa_snprintf(s, sizeof(s),
+ "relative address offset too large (%d)", $1);
+ yyerror(& @1, state, s);
+ YYERROR;
+ } else {
+ $$ = $1;
+ }
+ }
+ ;
+
+addrRegNegOffset: INTEGER
+ {
+ if (($1 < 0) || ($1 > 4096)) {
+ char s[100];
+ _mesa_snprintf(s, sizeof(s),
+ "relative address offset too large (%d)", $1);
+ yyerror(& @1, state, s);
+ YYERROR;
+ } else {
+ $$ = $1;
+ }
+ }
+ ;
+
+addrReg: USED_IDENTIFIER
+ {
+ struct asm_symbol *const s = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, $1);
+
+ free($1);
+
+ if (s == NULL) {
+ yyerror(& @1, state, "invalid array member");
+ YYERROR;
+ } else if (s->type != at_address) {
+ yyerror(& @1, state,
+ "invalid variable for indexed array access");
+ YYERROR;
+ } else {
+ $$ = s;
+ }
+ }
+ ;
+
+addrComponent: MASK1
+ {
+ if ($1.mask != WRITEMASK_X) {
+ yyerror(& @1, state, "invalid address component selector");
+ YYERROR;
+ } else {
+ $$ = $1;
+ }
+ }
+ ;
+
+addrWriteMask: MASK1
+ {
+ if ($1.mask != WRITEMASK_X) {
+ yyerror(& @1, state,
+ "address register write mask must be \".x\"");
+ YYERROR;
+ } else {
+ $$ = $1;
+ }
+ }
+ ;
+
+scalarSuffix: MASK1;
+
+swizzleSuffix: MASK1
+ | MASK4
+ | SWIZZLE
+ | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; }
+ ;
+
+optionalMask: MASK4 | MASK3 | MASK2 | MASK1
+ | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; }
+ ;
+
+optionalCcMask: '(' ccTest ')'
+ {
+ $$ = $2;
+ }
+ | '(' ccTest2 ')'
+ {
+ $$ = $2;
+ }
+ |
+ {
+ $$.CondMask = COND_TR;
+ $$.CondSwizzle = SWIZZLE_NOOP;
+ $$.CondSrc = 0;
+ }
+ ;
+
+ccTest: ccMaskRule swizzleSuffix
+ {
+ $$ = $1;
+ $$.CondSwizzle = $2.swizzle;
+ }
+ ;
+
+ccTest2: ccMaskRule2 swizzleSuffix
+ {
+ $$ = $1;
+ $$.CondSwizzle = $2.swizzle;
+ }
+ ;
+
+ccMaskRule: IDENTIFIER
+ {
+ const int cond = _mesa_parse_cc($1);
+ if ((cond == 0) || ($1[2] != '\0')) {
+ char *const err_str =
+ make_error_string("invalid condition code \"%s\"", $1);
+
+ yyerror(& @1, state, (err_str != NULL)
+ ? err_str : "invalid condition code");
+
+ if (err_str != NULL) {
+ free(err_str);
+ }
+
+ YYERROR;
+ }
+
+ $$.CondMask = cond;
+ $$.CondSwizzle = SWIZZLE_NOOP;
+ $$.CondSrc = 0;
+ }
+ ;
+
+ccMaskRule2: USED_IDENTIFIER
+ {
+ const int cond = _mesa_parse_cc($1);
+ if ((cond == 0) || ($1[2] != '\0')) {
+ char *const err_str =
+ make_error_string("invalid condition code \"%s\"", $1);
+
+ yyerror(& @1, state, (err_str != NULL)
+ ? err_str : "invalid condition code");
+
+ if (err_str != NULL) {
+ free(err_str);
+ }
+
+ YYERROR;
+ }
+
+ $$.CondMask = cond;
+ $$.CondSwizzle = SWIZZLE_NOOP;
+ $$.CondSrc = 0;
+ }
+ ;
+
+namingStatement: ATTRIB_statement
+ | PARAM_statement
+ | TEMP_statement
+ | ADDRESS_statement
+ | OUTPUT_statement
+ | ALIAS_statement
+ ;
+
+ATTRIB_statement: ATTRIB IDENTIFIER '=' attribBinding
+ {
+ struct asm_symbol *const s =
+ declare_variable(state, $2, at_attrib, & @2);
+
+ if (s == NULL) {
+ free($2);
+ YYERROR;
+ } else {
+ s->attrib_binding = $4;
+ state->InputsBound |= (1U << s->attrib_binding);
+
+ if (!validate_inputs(& @4, state)) {
+ YYERROR;
+ }
+ }
+ }
+ ;
+
+attribBinding: VERTEX vtxAttribItem
+ {
+ $$ = $2;
+ }
+ | FRAGMENT fragAttribItem
+ {
+ $$ = $2;
+ }
+ ;
+
+vtxAttribItem: POSITION
+ {
+ $$ = VERT_ATTRIB_POS;
+ }
+ | WEIGHT vtxOptWeightNum
+ {
+ $$ = VERT_ATTRIB_WEIGHT;
+ }
+ | NORMAL
+ {
+ $$ = VERT_ATTRIB_NORMAL;
+ }
+ | COLOR optColorType
+ {
+ if (!state->ctx->Extensions.EXT_secondary_color) {
+ yyerror(& @2, state, "GL_EXT_secondary_color not supported");
+ YYERROR;
+ }
+
+ $$ = VERT_ATTRIB_COLOR0 + $2;
+ }
+ | FOGCOORD
+ {
+ if (!state->ctx->Extensions.EXT_fog_coord) {
+ yyerror(& @1, state, "GL_EXT_fog_coord not supported");
+ YYERROR;
+ }
+
+ $$ = VERT_ATTRIB_FOG;
+ }
+ | TEXCOORD optTexCoordUnitNum
+ {
+ $$ = VERT_ATTRIB_TEX0 + $2;
+ }
+ | MATRIXINDEX '[' vtxWeightNum ']'
+ {
+ yyerror(& @1, state, "GL_ARB_matrix_palette not supported");
+ YYERROR;
+ }
+ | VTXATTRIB '[' vtxAttribNum ']'
+ {
+ $$ = VERT_ATTRIB_GENERIC0 + $3;
+ }
+ ;
+
+vtxAttribNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->limits->MaxAttribs) {
+ yyerror(& @1, state, "invalid vertex attribute reference");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+vtxOptWeightNum: | '[' vtxWeightNum ']';
+vtxWeightNum: INTEGER;
+
+fragAttribItem: POSITION
+ {
+ $$ = FRAG_ATTRIB_WPOS;
+ }
+ | COLOR optColorType
+ {
+ $$ = FRAG_ATTRIB_COL0 + $2;
+ }
+ | FOGCOORD
+ {
+ $$ = FRAG_ATTRIB_FOGC;
+ }
+ | TEXCOORD optTexCoordUnitNum
+ {
+ $$ = FRAG_ATTRIB_TEX0 + $2;
+ }
+ ;
+
+PARAM_statement: PARAM_singleStmt | PARAM_multipleStmt;
+
+PARAM_singleStmt: PARAM IDENTIFIER paramSingleInit
+ {
+ struct asm_symbol *const s =
+ declare_variable(state, $2, at_param, & @2);
+
+ if (s == NULL) {
+ free($2);
+ YYERROR;
+ } else {
+ s->param_binding_type = $3.param_binding_type;
+ s->param_binding_begin = $3.param_binding_begin;
+ s->param_binding_length = $3.param_binding_length;
+ s->param_binding_swizzle = $3.param_binding_swizzle;
+ s->param_is_array = 0;
+ }
+ }
+ ;
+
+PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit
+ {
+ if (($4 != 0) && ((unsigned) $4 != $6.param_binding_length)) {
+ free($2);
+ yyerror(& @4, state,
+ "parameter array size and number of bindings must match");
+ YYERROR;
+ } else {
+ struct asm_symbol *const s =
+ declare_variable(state, $2, $6.type, & @2);
+
+ if (s == NULL) {
+ free($2);
+ YYERROR;
+ } else {
+ s->param_binding_type = $6.param_binding_type;
+ s->param_binding_begin = $6.param_binding_begin;
+ s->param_binding_length = $6.param_binding_length;
+ s->param_binding_swizzle = SWIZZLE_XYZW;
+ s->param_is_array = 1;
+ }
+ }
+ }
+ ;
+
+optArraySize:
+ {
+ $$ = 0;
+ }
+ | INTEGER
+ {
+ if (($1 < 1) || ((unsigned) $1 > state->limits->MaxParameters)) {
+ yyerror(& @1, state, "invalid parameter array size");
+ YYERROR;
+ } else {
+ $$ = $1;
+ }
+ }
+ ;
+
+paramSingleInit: '=' paramSingleItemDecl
+ {
+ $$ = $2;
+ }
+ ;
+
+paramMultipleInit: '=' '{' paramMultInitList '}'
+ {
+ $$ = $3;
+ }
+ ;
+
+paramMultInitList: paramMultipleItem
+ | paramMultInitList ',' paramMultipleItem
+ {
+ $1.param_binding_length += $3.param_binding_length;
+ $$ = $1;
+ }
+ ;
+
+paramSingleItemDecl: stateSingleItem
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_state(state->prog, & $$, $1);
+ }
+ | programSingleItem
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_param(state->prog, & $$, $1);
+ }
+ | paramConstDecl
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE);
+ }
+ ;
+
+paramSingleItemUse: stateSingleItem
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_state(state->prog, & $$, $1);
+ }
+ | programSingleItem
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_param(state->prog, & $$, $1);
+ }
+ | paramConstUse
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE);
+ }
+ ;
+
+paramMultipleItem: stateMultipleItem
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_state(state->prog, & $$, $1);
+ }
+ | programMultipleItem
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_param(state->prog, & $$, $1);
+ }
+ | paramConstDecl
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & $$, & $1, GL_FALSE);
+ }
+ ;
+
+stateMultipleItem: stateSingleItem { memcpy($$, $1, sizeof($$)); }
+ | STATE stateMatrixRows { memcpy($$, $2, sizeof($$)); }
+ ;
+
+stateSingleItem: STATE stateMaterialItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateLightItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateLightModelItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateLightProdItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateTexGenItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateTexEnvItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateFogItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateClipPlaneItem { memcpy($$, $2, sizeof($$)); }
+ | STATE statePointItem { memcpy($$, $2, sizeof($$)); }
+ | STATE stateMatrixRow { memcpy($$, $2, sizeof($$)); }
+ | STATE stateDepthItem { memcpy($$, $2, sizeof($$)); }
+ ;
+
+stateMaterialItem: MATERIAL optFaceType stateMatProperty
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_MATERIAL;
+ $$[1] = $2;
+ $$[2] = $3;
+ }
+ ;
+
+stateMatProperty: ambDiffSpecProperty
+ {
+ $$ = $1;
+ }
+ | EMISSION
+ {
+ $$ = STATE_EMISSION;
+ }
+ | SHININESS
+ {
+ $$ = STATE_SHININESS;
+ }
+ ;
+
+stateLightItem: LIGHT '[' stateLightNumber ']' stateLightProperty
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_LIGHT;
+ $$[1] = $3;
+ $$[2] = $5;
+ }
+ ;
+
+stateLightProperty: ambDiffSpecProperty
+ {
+ $$ = $1;
+ }
+ | POSITION
+ {
+ $$ = STATE_POSITION;
+ }
+ | ATTENUATION
+ {
+ if (!state->ctx->Extensions.EXT_point_parameters) {
+ yyerror(& @1, state, "GL_ARB_point_parameters not supported");
+ YYERROR;
+ }
+
+ $$ = STATE_ATTENUATION;
+ }
+ | SPOT stateSpotProperty
+ {
+ $$ = $2;
+ }
+ | HALF
+ {
+ $$ = STATE_HALF_VECTOR;
+ }
+ ;
+
+stateSpotProperty: DIRECTION
+ {
+ $$ = STATE_SPOT_DIRECTION;
+ }
+ ;
+
+stateLightModelItem: LIGHTMODEL stateLModProperty
+ {
+ $$[0] = $2[0];
+ $$[1] = $2[1];
+ }
+ ;
+
+stateLModProperty: AMBIENT
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_LIGHTMODEL_AMBIENT;
+ }
+ | optFaceType SCENECOLOR
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_LIGHTMODEL_SCENECOLOR;
+ $$[1] = $1;
+ }
+ ;
+
+stateLightProdItem: LIGHTPROD '[' stateLightNumber ']' optFaceType stateLProdProperty
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_LIGHTPROD;
+ $$[1] = $3;
+ $$[2] = $5;
+ $$[3] = $6;
+ }
+ ;
+
+stateLProdProperty: ambDiffSpecProperty;
+
+stateTexEnvItem: TEXENV optLegacyTexUnitNum stateTexEnvProperty
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = $3;
+ $$[1] = $2;
+ }
+ ;
+
+stateTexEnvProperty: COLOR
+ {
+ $$ = STATE_TEXENV_COLOR;
+ }
+ ;
+
+ambDiffSpecProperty: AMBIENT
+ {
+ $$ = STATE_AMBIENT;
+ }
+ | DIFFUSE
+ {
+ $$ = STATE_DIFFUSE;
+ }
+ | SPECULAR
+ {
+ $$ = STATE_SPECULAR;
+ }
+ ;
+
+stateLightNumber: INTEGER
+ {
+ if ((unsigned) $1 >= state->MaxLights) {
+ yyerror(& @1, state, "invalid light selector");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+stateTexGenItem: TEXGEN optTexCoordUnitNum stateTexGenType stateTexGenCoord
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_TEXGEN;
+ $$[1] = $2;
+ $$[2] = $3 + $4;
+ }
+ ;
+
+stateTexGenType: EYE
+ {
+ $$ = STATE_TEXGEN_EYE_S;
+ }
+ | OBJECT
+ {
+ $$ = STATE_TEXGEN_OBJECT_S;
+ }
+ ;
+stateTexGenCoord: TEXGEN_S
+ {
+ $$ = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S;
+ }
+ | TEXGEN_T
+ {
+ $$ = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S;
+ }
+ | TEXGEN_R
+ {
+ $$ = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S;
+ }
+ | TEXGEN_Q
+ {
+ $$ = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S;
+ }
+ ;
+
+stateFogItem: FOG stateFogProperty
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = $2;
+ }
+ ;
+
+stateFogProperty: COLOR
+ {
+ $$ = STATE_FOG_COLOR;
+ }
+ | PARAMS
+ {
+ $$ = STATE_FOG_PARAMS;
+ }
+ ;
+
+stateClipPlaneItem: CLIP '[' stateClipPlaneNum ']' PLANE
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_CLIPPLANE;
+ $$[1] = $3;
+ }
+ ;
+
+stateClipPlaneNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->MaxClipPlanes) {
+ yyerror(& @1, state, "invalid clip plane selector");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+statePointItem: POINT_TOK statePointProperty
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = $2;
+ }
+ ;
+
+statePointProperty: SIZE_TOK
+ {
+ $$ = STATE_POINT_SIZE;
+ }
+ | ATTENUATION
+ {
+ $$ = STATE_POINT_ATTENUATION;
+ }
+ ;
+
+stateMatrixRow: stateMatrixItem ROW '[' stateMatrixRowNum ']'
+ {
+ $$[0] = $1[0];
+ $$[1] = $1[1];
+ $$[2] = $4;
+ $$[3] = $4;
+ $$[4] = $1[2];
+ }
+ ;
+
+stateMatrixRows: stateMatrixItem optMatrixRows
+ {
+ $$[0] = $1[0];
+ $$[1] = $1[1];
+ $$[2] = $2[2];
+ $$[3] = $2[3];
+ $$[4] = $1[2];
+ }
+ ;
+
+optMatrixRows:
+ {
+ $$[2] = 0;
+ $$[3] = 3;
+ }
+ | ROW '[' stateMatrixRowNum DOT_DOT stateMatrixRowNum ']'
+ {
+ /* It seems logical that the matrix row range specifier would have
+ * to specify a range or more than one row (i.e., $5 > $3).
+ * However, the ARB_vertex_program spec says "a program will fail
+ * to load if <a> is greater than <b>." This means that $3 == $5
+ * is valid.
+ */
+ if ($3 > $5) {
+ yyerror(& @3, state, "invalid matrix row range");
+ YYERROR;
+ }
+
+ $$[2] = $3;
+ $$[3] = $5;
+ }
+ ;
+
+stateMatrixItem: MATRIX stateMatrixName stateOptMatModifier
+ {
+ $$[0] = $2[0];
+ $$[1] = $2[1];
+ $$[2] = $3;
+ }
+ ;
+
+stateOptMatModifier:
+ {
+ $$ = 0;
+ }
+ | stateMatModifier
+ {
+ $$ = $1;
+ }
+ ;
+
+stateMatModifier: INVERSE
+ {
+ $$ = STATE_MATRIX_INVERSE;
+ }
+ | TRANSPOSE
+ {
+ $$ = STATE_MATRIX_TRANSPOSE;
+ }
+ | INVTRANS
+ {
+ $$ = STATE_MATRIX_INVTRANS;
+ }
+ ;
+
+stateMatrixRowNum: INTEGER
+ {
+ if ($1 > 3) {
+ yyerror(& @1, state, "invalid matrix row reference");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+stateMatrixName: MODELVIEW stateOptModMatNum
+ {
+ $$[0] = STATE_MODELVIEW_MATRIX;
+ $$[1] = $2;
+ }
+ | PROJECTION
+ {
+ $$[0] = STATE_PROJECTION_MATRIX;
+ $$[1] = 0;
+ }
+ | MVP
+ {
+ $$[0] = STATE_MVP_MATRIX;
+ $$[1] = 0;
+ }
+ | TEXTURE optTexCoordUnitNum
+ {
+ $$[0] = STATE_TEXTURE_MATRIX;
+ $$[1] = $2;
+ }
+ | PALETTE '[' statePaletteMatNum ']'
+ {
+ yyerror(& @1, state, "GL_ARB_matrix_palette not supported");
+ YYERROR;
+ }
+ | MAT_PROGRAM '[' stateProgramMatNum ']'
+ {
+ $$[0] = STATE_PROGRAM_MATRIX;
+ $$[1] = $3;
+ }
+ ;
+
+stateOptModMatNum:
+ {
+ $$ = 0;
+ }
+ | '[' stateModMatNum ']'
+ {
+ $$ = $2;
+ }
+ ;
+stateModMatNum: INTEGER
+ {
+ /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix
+ * zero is valid.
+ */
+ if ($1 != 0) {
+ yyerror(& @1, state, "invalid modelview matrix index");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+statePaletteMatNum: INTEGER
+ {
+ /* Since GL_ARB_matrix_palette isn't supported, just let any value
+ * through here. The error will be generated later.
+ */
+ $$ = $1;
+ }
+ ;
+stateProgramMatNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->MaxProgramMatrices) {
+ yyerror(& @1, state, "invalid program matrix selector");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+stateDepthItem: DEPTH RANGE
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_DEPTH_RANGE;
+ }
+ ;
+
+
+programSingleItem: progEnvParam | progLocalParam;
+
+programMultipleItem: progEnvParams | progLocalParams;
+
+progEnvParams: PROGRAM ENV '[' progEnvParamNums ']'
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = state->state_param_enum;
+ $$[1] = STATE_ENV;
+ $$[2] = $4[0];
+ $$[3] = $4[1];
+ }
+ ;
+
+progEnvParamNums: progEnvParamNum
+ {
+ $$[0] = $1;
+ $$[1] = $1;
+ }
+ | progEnvParamNum DOT_DOT progEnvParamNum
+ {
+ $$[0] = $1;
+ $$[1] = $3;
+ }
+ ;
+
+progEnvParam: PROGRAM ENV '[' progEnvParamNum ']'
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = state->state_param_enum;
+ $$[1] = STATE_ENV;
+ $$[2] = $4;
+ $$[3] = $4;
+ }
+ ;
+
+progLocalParams: PROGRAM LOCAL '[' progLocalParamNums ']'
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = state->state_param_enum;
+ $$[1] = STATE_LOCAL;
+ $$[2] = $4[0];
+ $$[3] = $4[1];
+ }
+
+progLocalParamNums: progLocalParamNum
+ {
+ $$[0] = $1;
+ $$[1] = $1;
+ }
+ | progLocalParamNum DOT_DOT progLocalParamNum
+ {
+ $$[0] = $1;
+ $$[1] = $3;
+ }
+ ;
+
+progLocalParam: PROGRAM LOCAL '[' progLocalParamNum ']'
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = state->state_param_enum;
+ $$[1] = STATE_LOCAL;
+ $$[2] = $4;
+ $$[3] = $4;
+ }
+ ;
+
+progEnvParamNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->limits->MaxEnvParams) {
+ yyerror(& @1, state, "invalid environment parameter reference");
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+progLocalParamNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->limits->MaxLocalParams) {
+ yyerror(& @1, state, "invalid local parameter reference");
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+
+
+paramConstDecl: paramConstScalarDecl | paramConstVector;
+paramConstUse: paramConstScalarUse | paramConstVector;
+
+paramConstScalarDecl: signedFloatConstant
+ {
+ $$.count = 4;
+ $$.data[0] = $1;
+ $$.data[1] = $1;
+ $$.data[2] = $1;
+ $$.data[3] = $1;
+ }
+ ;
+
+paramConstScalarUse: REAL
+ {
+ $$.count = 1;
+ $$.data[0] = $1;
+ $$.data[1] = $1;
+ $$.data[2] = $1;
+ $$.data[3] = $1;
+ }
+ | INTEGER
+ {
+ $$.count = 1;
+ $$.data[0] = (float) $1;
+ $$.data[1] = (float) $1;
+ $$.data[2] = (float) $1;
+ $$.data[3] = (float) $1;
+ }
+ ;
+
+paramConstVector: '{' signedFloatConstant '}'
+ {
+ $$.count = 4;
+ $$.data[0] = $2;
+ $$.data[1] = 0.0f;
+ $$.data[2] = 0.0f;
+ $$.data[3] = 1.0f;
+ }
+ | '{' signedFloatConstant ',' signedFloatConstant '}'
+ {
+ $$.count = 4;
+ $$.data[0] = $2;
+ $$.data[1] = $4;
+ $$.data[2] = 0.0f;
+ $$.data[3] = 1.0f;
+ }
+ | '{' signedFloatConstant ',' signedFloatConstant ','
+ signedFloatConstant '}'
+ {
+ $$.count = 4;
+ $$.data[0] = $2;
+ $$.data[1] = $4;
+ $$.data[2] = $6;
+ $$.data[3] = 1.0f;
+ }
+ | '{' signedFloatConstant ',' signedFloatConstant ','
+ signedFloatConstant ',' signedFloatConstant '}'
+ {
+ $$.count = 4;
+ $$.data[0] = $2;
+ $$.data[1] = $4;
+ $$.data[2] = $6;
+ $$.data[3] = $8;
+ }
+ ;
+
+signedFloatConstant: optionalSign REAL
+ {
+ $$ = ($1) ? -$2 : $2;
+ }
+ | optionalSign INTEGER
+ {
+ $$ = (float)(($1) ? -$2 : $2);
+ }
+ ;
+
+optionalSign: '+' { $$ = FALSE; }
+ | '-' { $$ = TRUE; }
+ | { $$ = FALSE; }
+ ;
+
+TEMP_statement: optVarSize TEMP { $<integer>$ = $2; } varNameList
+ ;
+
+optVarSize: string
+ {
+ /* NV_fragment_program_option defines the size qualifiers in a
+ * fairly broken way. "SHORT" or "LONG" can optionally be used
+ * before TEMP or OUTPUT. However, neither is a reserved word!
+ * This means that we have to parse it as an identifier, then check
+ * to make sure it's one of the valid values. *sigh*
+ *
+ * In addition, the grammar in the extension spec does *not* allow
+ * the size specifier to be optional, but all known implementations
+ * do.
+ */
+ if (!state->option.NV_fragment) {
+ yyerror(& @1, state, "unexpected IDENTIFIER");
+ YYERROR;
+ }
+
+ if (strcmp("SHORT", $1) == 0) {
+ } else if (strcmp("LONG", $1) == 0) {
+ } else {
+ char *const err_str =
+ make_error_string("invalid storage size specifier \"%s\"",
+ $1);
+
+ yyerror(& @1, state, (err_str != NULL)
+ ? err_str : "invalid storage size specifier");
+
+ if (err_str != NULL) {
+ free(err_str);
+ }
+
+ YYERROR;
+ }
+ }
+ |
+ {
+ }
+ ;
+
+ADDRESS_statement: ADDRESS { $<integer>$ = $1; } varNameList
+ ;
+
+varNameList: varNameList ',' IDENTIFIER
+ {
+ if (!declare_variable(state, $3, $<integer>0, & @3)) {
+ free($3);
+ YYERROR;
+ }
+ }
+ | IDENTIFIER
+ {
+ if (!declare_variable(state, $1, $<integer>0, & @1)) {
+ free($1);
+ YYERROR;
+ }
+ }
+ ;
+
+OUTPUT_statement: optVarSize OUTPUT IDENTIFIER '=' resultBinding
+ {
+ struct asm_symbol *const s =
+ declare_variable(state, $3, at_output, & @3);
+
+ if (s == NULL) {
+ free($3);
+ YYERROR;
+ } else {
+ s->output_binding = $5;
+ }
+ }
+ ;
+
+resultBinding: RESULT POSITION
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = VERT_RESULT_HPOS;
+ } else {
+ yyerror(& @2, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ | RESULT FOGCOORD
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = VERT_RESULT_FOGC;
+ } else {
+ yyerror(& @2, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ | RESULT resultColBinding
+ {
+ $$ = $2;
+ }
+ | RESULT POINTSIZE
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = VERT_RESULT_PSIZ;
+ } else {
+ yyerror(& @2, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ | RESULT TEXCOORD optTexCoordUnitNum
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = VERT_RESULT_TEX0 + $3;
+ } else {
+ yyerror(& @2, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ | RESULT DEPTH
+ {
+ if (state->mode == ARB_fragment) {
+ $$ = FRAG_RESULT_DEPTH;
+ } else {
+ yyerror(& @2, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ ;
+
+resultColBinding: COLOR optResultFaceType optResultColorType
+ {
+ $$ = $2 + $3;
+ }
+ ;
+
+optResultFaceType:
+ {
+ $$ = (state->mode == ARB_vertex)
+ ? VERT_RESULT_COL0
+ : FRAG_RESULT_COLOR;
+ }
+ | FRONT
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = VERT_RESULT_COL0;
+ } else {
+ yyerror(& @1, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ | BACK
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = VERT_RESULT_BFC0;
+ } else {
+ yyerror(& @1, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ ;
+
+optResultColorType:
+ {
+ $$ = 0;
+ }
+ | PRIMARY
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = 0;
+ } else {
+ yyerror(& @1, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ | SECONDARY
+ {
+ if (state->mode == ARB_vertex) {
+ $$ = 1;
+ } else {
+ yyerror(& @1, state, "invalid program result name");
+ YYERROR;
+ }
+ }
+ ;
+
+optFaceType: { $$ = 0; }
+ | FRONT { $$ = 0; }
+ | BACK { $$ = 1; }
+ ;
+
+optColorType: { $$ = 0; }
+ | PRIMARY { $$ = 0; }
+ | SECONDARY { $$ = 1; }
+ ;
+
+optTexCoordUnitNum: { $$ = 0; }
+ | '[' texCoordUnitNum ']' { $$ = $2; }
+ ;
+
+optTexImageUnitNum: { $$ = 0; }
+ | '[' texImageUnitNum ']' { $$ = $2; }
+ ;
+
+optLegacyTexUnitNum: { $$ = 0; }
+ | '[' legacyTexUnitNum ']' { $$ = $2; }
+ ;
+
+texCoordUnitNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->MaxTextureCoordUnits) {
+ yyerror(& @1, state, "invalid texture coordinate unit selector");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+texImageUnitNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->MaxTextureImageUnits) {
+ yyerror(& @1, state, "invalid texture image unit selector");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+legacyTexUnitNum: INTEGER
+ {
+ if ((unsigned) $1 >= state->MaxTextureUnits) {
+ yyerror(& @1, state, "invalid texture unit selector");
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+ALIAS_statement: ALIAS IDENTIFIER '=' USED_IDENTIFIER
+ {
+ struct asm_symbol *exist = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, $2);
+ struct asm_symbol *target = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, $4);
+
+ free($4);
+
+ if (exist != NULL) {
+ char m[1000];
+ _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", $2);
+ free($2);
+ yyerror(& @2, state, m);
+ YYERROR;
+ } else if (target == NULL) {
+ free($2);
+ yyerror(& @4, state,
+ "undefined variable binding in ALIAS statement");
+ YYERROR;
+ } else {
+ _mesa_symbol_table_add_symbol(state->st, 0, $2, target);
+ }
+ }
+ ;
+
+string: IDENTIFIER
+ | USED_IDENTIFIER
+ ;
+
+%%
+
+void
+asm_instruction_set_operands(struct asm_instruction *inst,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ /* In the core ARB extensions only the KIL instruction doesn't have a
+ * destination register.
+ */
+ if (dst == NULL) {
+ init_dst_reg(& inst->Base.DstReg);
+ } else {
+ inst->Base.DstReg = *dst;
+ }
+
+ /* The only instruction that doesn't have any source registers is the
+ * condition-code based KIL instruction added by NV_fragment_program_option.
+ */
+ if (src0 != NULL) {
+ inst->Base.SrcReg[0] = src0->Base;
+ inst->SrcReg[0] = *src0;
+ } else {
+ init_src_reg(& inst->SrcReg[0]);
+ }
+
+ if (src1 != NULL) {
+ inst->Base.SrcReg[1] = src1->Base;
+ inst->SrcReg[1] = *src1;
+ } else {
+ init_src_reg(& inst->SrcReg[1]);
+ }
+
+ if (src2 != NULL) {
+ inst->Base.SrcReg[2] = src2->Base;
+ inst->SrcReg[2] = *src2;
+ } else {
+ init_src_reg(& inst->SrcReg[2]);
+ }
+}
+
+
+struct asm_instruction *
+asm_instruction_ctor(gl_inst_opcode op,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
+
+ if (inst) {
+ _mesa_init_instructions(& inst->Base, 1);
+ inst->Base.Opcode = op;
+
+ asm_instruction_set_operands(inst, dst, src0, src1, src2);
+ }
+
+ return inst;
+}
+
+
+struct asm_instruction *
+asm_instruction_copy_ctor(const struct prog_instruction *base,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
+
+ if (inst) {
+ _mesa_init_instructions(& inst->Base, 1);
+ inst->Base.Opcode = base->Opcode;
+ inst->Base.CondUpdate = base->CondUpdate;
+ inst->Base.CondDst = base->CondDst;
+ inst->Base.SaturateMode = base->SaturateMode;
+ inst->Base.Precision = base->Precision;
+
+ asm_instruction_set_operands(inst, dst, src0, src1, src2);
+ }
+
+ return inst;
+}
+
+
+void
+init_dst_reg(struct prog_dst_register *r)
+{
+ memset(r, 0, sizeof(*r));
+ r->File = PROGRAM_UNDEFINED;
+ r->WriteMask = WRITEMASK_XYZW;
+ r->CondMask = COND_TR;
+ r->CondSwizzle = SWIZZLE_NOOP;
+}
+
+
+/** Like init_dst_reg() but set the File and Index fields. */
+void
+set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index)
+{
+ const GLint maxIndex = 1 << INST_INDEX_BITS;
+ const GLint minIndex = 0;
+ ASSERT(index >= minIndex);
+ (void) minIndex;
+ ASSERT(index <= maxIndex);
+ (void) maxIndex;
+ ASSERT(file == PROGRAM_TEMPORARY ||
+ file == PROGRAM_ADDRESS ||
+ file == PROGRAM_OUTPUT);
+ memset(r, 0, sizeof(*r));
+ r->File = file;
+ r->Index = index;
+ r->WriteMask = WRITEMASK_XYZW;
+ r->CondMask = COND_TR;
+ r->CondSwizzle = SWIZZLE_NOOP;
+}
+
+
+void
+init_src_reg(struct asm_src_register *r)
+{
+ memset(r, 0, sizeof(*r));
+ r->Base.File = PROGRAM_UNDEFINED;
+ r->Base.Swizzle = SWIZZLE_NOOP;
+ r->Symbol = NULL;
+}
+
+
+/** Like init_src_reg() but set the File and Index fields.
+ * \return GL_TRUE if a valid src register, GL_FALSE otherwise
+ */
+void
+set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index)
+{
+ set_src_reg_swz(r, file, index, SWIZZLE_XYZW);
+}
+
+
+void
+set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index,
+ GLuint swizzle)
+{
+ const GLint maxIndex = (1 << INST_INDEX_BITS) - 1;
+ const GLint minIndex = -(1 << INST_INDEX_BITS);
+ ASSERT(file < PROGRAM_FILE_MAX);
+ ASSERT(index >= minIndex);
+ (void) minIndex;
+ ASSERT(index <= maxIndex);
+ (void) maxIndex;
+ memset(r, 0, sizeof(*r));
+ r->Base.File = file;
+ r->Base.Index = index;
+ r->Base.Swizzle = swizzle;
+ r->Symbol = NULL;
+}
+
+
+/**
+ * Validate the set of inputs used by a program
+ *
+ * Validates that legal sets of inputs are used by the program. In this case
+ * "used" included both reading the input or binding the input to a name using
+ * the \c ATTRIB command.
+ *
+ * \return
+ * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise.
+ */
+int
+validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state)
+{
+ const int inputs = state->prog->InputsRead | state->InputsBound;
+
+ if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) {
+ yyerror(locp, state, "illegal use of generic attribute and name attribute");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct asm_symbol *
+declare_variable(struct asm_parser_state *state, char *name, enum asm_type t,
+ struct YYLTYPE *locp)
+{
+ struct asm_symbol *s = NULL;
+ struct asm_symbol *exist = (struct asm_symbol *)
+ _mesa_symbol_table_find_symbol(state->st, 0, name);
+
+
+ if (exist != NULL) {
+ yyerror(locp, state, "redeclared identifier");
+ } else {
+ s = calloc(1, sizeof(struct asm_symbol));
+ s->name = name;
+ s->type = t;
+
+ switch (t) {
+ case at_temp:
+ if (state->prog->NumTemporaries >= state->limits->MaxTemps) {
+ yyerror(locp, state, "too many temporaries declared");
+ free(s);
+ return NULL;
+ }
+
+ s->temp_binding = state->prog->NumTemporaries;
+ state->prog->NumTemporaries++;
+ break;
+
+ case at_address:
+ if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) {
+ yyerror(locp, state, "too many address registers declared");
+ free(s);
+ return NULL;
+ }
+
+ /* FINISHME: Add support for multiple address registers.
+ */
+ state->prog->NumAddressRegs++;
+ break;
+
+ default:
+ break;
+ }
+
+ _mesa_symbol_table_add_symbol(state->st, 0, s->name, s);
+ s->next = state->sym;
+ state->sym = s;
+ }
+
+ return s;
+}
+
+
+int add_state_reference(struct gl_program_parameter_list *param_list,
+ const gl_state_index tokens[STATE_LENGTH])
+{
+ const GLuint size = 4; /* XXX fix */
+ char *name;
+ GLint index;
+
+ name = _mesa_program_state_string(tokens);
+ index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name,
+ size, GL_NONE, NULL, tokens, 0x0);
+ param_list->StateFlags |= _mesa_program_state_flags(tokens);
+
+ /* free name string here since we duplicated it in add_parameter() */
+ free(name);
+
+ return index;
+}
+
+
+int
+initialize_symbol_from_state(struct gl_program *prog,
+ struct asm_symbol *param_var,
+ const gl_state_index tokens[STATE_LENGTH])
+{
+ int idx = -1;
+ gl_state_index state_tokens[STATE_LENGTH];
+
+
+ memcpy(state_tokens, tokens, sizeof(state_tokens));
+
+ param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+ /* If we are adding a STATE_MATRIX that has multiple rows, we need to
+ * unroll it and call add_state_reference() for each row
+ */
+ if ((state_tokens[0] == STATE_MODELVIEW_MATRIX ||
+ state_tokens[0] == STATE_PROJECTION_MATRIX ||
+ state_tokens[0] == STATE_MVP_MATRIX ||
+ state_tokens[0] == STATE_TEXTURE_MATRIX ||
+ state_tokens[0] == STATE_PROGRAM_MATRIX)
+ && (state_tokens[2] != state_tokens[3])) {
+ int row;
+ const int first_row = state_tokens[2];
+ const int last_row = state_tokens[3];
+
+ for (row = first_row; row <= last_row; row++) {
+ state_tokens[2] = state_tokens[3] = row;
+
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+
+ param_var->param_binding_length++;
+ }
+ }
+ else {
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+ }
+
+ return idx;
+}
+
+
+int
+initialize_symbol_from_param(struct gl_program *prog,
+ struct asm_symbol *param_var,
+ const gl_state_index tokens[STATE_LENGTH])
+{
+ int idx = -1;
+ gl_state_index state_tokens[STATE_LENGTH];
+
+
+ memcpy(state_tokens, tokens, sizeof(state_tokens));
+
+ assert((state_tokens[0] == STATE_VERTEX_PROGRAM)
+ || (state_tokens[0] == STATE_FRAGMENT_PROGRAM));
+ assert((state_tokens[1] == STATE_ENV)
+ || (state_tokens[1] == STATE_LOCAL));
+
+ /*
+ * The param type is STATE_VAR. The program parameter entry will
+ * effectively be a pointer into the LOCAL or ENV parameter array.
+ */
+ param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+ /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements,
+ * we need to unroll it and call add_state_reference() for each row
+ */
+ if (state_tokens[2] != state_tokens[3]) {
+ int row;
+ const int first_row = state_tokens[2];
+ const int last_row = state_tokens[3];
+
+ for (row = first_row; row <= last_row; row++) {
+ state_tokens[2] = state_tokens[3] = row;
+
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+ }
+ }
+ else {
+ idx = add_state_reference(prog->Parameters, state_tokens);
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+ }
+
+ return idx;
+}
+
+
+/**
+ * Put a float/vector constant/literal into the parameter list.
+ * \param param_var returns info about the parameter/constant's location,
+ * binding, type, etc.
+ * \param vec the vector/constant to add
+ * \param allowSwizzle if true, try to consolidate constants which only differ
+ * by a swizzle. We don't want to do this when building
+ * arrays of constants that may be indexed indirectly.
+ * \return index of the constant in the parameter list.
+ */
+int
+initialize_symbol_from_const(struct gl_program *prog,
+ struct asm_symbol *param_var,
+ const struct asm_vector *vec,
+ GLboolean allowSwizzle)
+{
+ unsigned swizzle;
+ const int idx = _mesa_add_unnamed_constant(prog->Parameters,
+ vec->data, vec->count,
+ allowSwizzle ? &swizzle : NULL);
+
+ param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_CONSTANT;
+
+ if (param_var->param_binding_begin == ~0U) {
+ param_var->param_binding_begin = idx;
+ param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW;
+ }
+ param_var->param_binding_length++;
+
+ return idx;
+}
+
+
+char *
+make_error_string(const char *fmt, ...)
+{
+ int length;
+ char *str;
+ va_list args;
+
+
+ /* Call vsnprintf once to determine how large the final string is. Call it
+ * again to do the actual formatting. from the vsnprintf manual page:
+ *
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings).
+ */
+ va_start(args, fmt);
+ length = 1 + vsnprintf(NULL, 0, fmt, args);
+ va_end(args);
+
+ str = malloc(length);
+ if (str) {
+ va_start(args, fmt);
+ vsnprintf(str, length, fmt, args);
+ va_end(args);
+ }
+
+ return str;
+}
+
+
+void
+yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s)
+{
+ char *err_str;
+
+
+ err_str = make_error_string("glProgramStringARB(%s)\n", s);
+ if (err_str) {
+ _mesa_error(state->ctx, GL_INVALID_OPERATION, "%s", err_str);
+ free(err_str);
+ }
+
+ err_str = make_error_string("line %u, char %u: error: %s\n",
+ locp->first_line, locp->first_column, s);
+ _mesa_set_program_error(state->ctx, locp->position, err_str);
+
+ if (err_str) {
+ free(err_str);
+ }
+}
+
+
+GLboolean
+_mesa_parse_arb_program(struct gl_context *ctx, GLenum target, const GLubyte *str,
+ GLsizei len, struct asm_parser_state *state)
+{
+ struct asm_instruction *inst;
+ unsigned i;
+ GLubyte *strz;
+ GLboolean result = GL_FALSE;
+ void *temp;
+ struct asm_symbol *sym;
+
+ state->ctx = ctx;
+ state->prog->Target = target;
+ state->prog->Parameters = _mesa_new_parameter_list();
+
+ /* Make a copy of the program string and force it to be NUL-terminated.
+ */
+ strz = (GLubyte *) malloc(len + 1);
+ if (strz == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB");
+ return GL_FALSE;
+ }
+ memcpy (strz, str, len);
+ strz[len] = '\0';
+
+ state->prog->String = strz;
+
+ state->st = _mesa_symbol_table_ctor();
+
+ state->limits = (target == GL_VERTEX_PROGRAM_ARB)
+ ? & ctx->Const.VertexProgram
+ : & ctx->Const.FragmentProgram;
+
+ state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
+ state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits;
+ state->MaxTextureUnits = ctx->Const.MaxTextureUnits;
+ state->MaxClipPlanes = ctx->Const.MaxClipPlanes;
+ state->MaxLights = ctx->Const.MaxLights;
+ state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices;
+
+ state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB)
+ ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM;
+
+ _mesa_set_program_error(ctx, -1, NULL);
+
+ _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len);
+ yyparse(state);
+ _mesa_program_lexer_dtor(state->scanner);
+
+
+ if (ctx->Program.ErrorPos != -1) {
+ goto error;
+ }
+
+ if (! _mesa_layout_parameters(state)) {
+ struct YYLTYPE loc;
+
+ loc.first_line = 0;
+ loc.first_column = 0;
+ loc.position = len;
+
+ yyerror(& loc, state, "invalid PARAM usage");
+ goto error;
+ }
+
+
+
+ /* Add one instruction to store the "END" instruction.
+ */
+ state->prog->Instructions =
+ _mesa_alloc_instructions(state->prog->NumInstructions + 1);
+ inst = state->inst_head;
+ for (i = 0; i < state->prog->NumInstructions; i++) {
+ struct asm_instruction *const temp = inst->next;
+
+ state->prog->Instructions[i] = inst->Base;
+ inst = temp;
+ }
+
+ /* Finally, tag on an OPCODE_END instruction */
+ {
+ const GLuint numInst = state->prog->NumInstructions;
+ _mesa_init_instructions(state->prog->Instructions + numInst, 1);
+ state->prog->Instructions[numInst].Opcode = OPCODE_END;
+ }
+ state->prog->NumInstructions++;
+
+ state->prog->NumParameters = state->prog->Parameters->NumParameters;
+ state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead);
+
+ /*
+ * Initialize native counts to logical counts. The device driver may
+ * change them if program is translated into a hardware program.
+ */
+ state->prog->NumNativeInstructions = state->prog->NumInstructions;
+ state->prog->NumNativeTemporaries = state->prog->NumTemporaries;
+ state->prog->NumNativeParameters = state->prog->NumParameters;
+ state->prog->NumNativeAttributes = state->prog->NumAttributes;
+ state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs;
+
+ result = GL_TRUE;
+
+error:
+ for (inst = state->inst_head; inst != NULL; inst = temp) {
+ temp = inst->next;
+ free(inst);
+ }
+
+ state->inst_head = NULL;
+ state->inst_tail = NULL;
+
+ for (sym = state->sym; sym != NULL; sym = temp) {
+ temp = sym->next;
+
+ free((void *) sym->name);
+ free(sym);
+ }
+ state->sym = NULL;
+
+ _mesa_symbol_table_dtor(state->st);
+ state->st = NULL;
+
+ return result;
+}
diff --git a/mesalib/src/mesa/program/program_parser.h b/mesalib/src/mesa/program/program_parser.h
index be952d4b9..ff2f4f25f 100644
--- a/mesalib/src/mesa/program/program_parser.h
+++ b/mesalib/src/mesa/program/program_parser.h
@@ -1,302 +1,299 @@
-/*
- * Copyright © 2009 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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.
- */
-#pragma once
-
-#include "main/config.h"
-
-#ifndef MTYPES_H
-struct __GLcontextRec;
-typedef struct __GLcontextRec GLcontext;
-#endif
-
-enum asm_type {
- at_none,
- at_address,
- at_attrib,
- at_param,
- at_temp,
- at_output
-};
-
-struct asm_symbol {
- struct asm_symbol *next; /**< List linkage for freeing. */
- const char *name;
- enum asm_type type;
- unsigned attrib_binding;
- unsigned output_binding; /**< Output / result register number. */
-
- /**
- * One of PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM, or PROGRAM_ENV_PARAM.
- */
- unsigned param_binding_type;
-
- /**
- * Offset into the program_parameter_list where the tokens representing our
- * bound state (or constants) start.
- */
- unsigned param_binding_begin;
-
- /**
- * Constants put into the parameter list may be swizzled. This
- * field contain's the symbol's swizzle. (SWIZZLE_X/Y/Z/W)
- */
- unsigned param_binding_swizzle;
-
- /* This is how many entries in 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.
- */
- unsigned param_binding_length;
-
- /**
- * Index of the temp register assigned to this variable.
- */
- unsigned temp_binding;
-
- /**
- * Flag whether or not a PARAM is an array
- */
- unsigned param_is_array:1;
-
-
- /**
- * Flag whether or not a PARAM array is accessed indirectly
- */
- unsigned param_accessed_indirectly:1;
-
-
- /**
- * \brief Is first pass of parameter layout done with this variable?
- *
- * The parameter layout routine operates in two passes. This flag tracks
- * whether or not the first pass has handled this variable.
- *
- * \sa _mesa_layout_parameters
- */
- unsigned pass1_done:1;
-};
-
-
-struct asm_vector {
- unsigned count;
- float data[4];
-};
-
-
-struct asm_swizzle_mask {
- unsigned swizzle:12;
- unsigned mask:4;
-};
-
-
-struct asm_src_register {
- struct prog_src_register Base;
-
- /**
- * Symbol associated with indirect access to parameter arrays.
- *
- * If \c Base::RelAddr is 1, this will point to the symbol for the parameter
- * that is being dereferenced. Further, \c Base::Index will be the offset
- * from the address register being used.
- */
- struct asm_symbol *Symbol;
-};
-
-
-struct asm_instruction {
- struct prog_instruction Base;
- struct asm_instruction *next;
- struct asm_src_register SrcReg[3];
-};
-
-
-struct asm_parser_state {
- GLcontext *ctx;
- struct gl_program *prog;
-
- /**
- * Per-program target limits
- */
- struct gl_program_constants *limits;
-
- struct _mesa_symbol_table *st;
-
- /**
- * Linked list of symbols
- *
- * This list is \b only used when cleaning up compiler state and freeing
- * memory.
- */
- struct asm_symbol *sym;
-
- /**
- * State for the lexer.
- */
- void *scanner;
-
- /**
- * Linked list of instructions generated during parsing.
- */
- /*@{*/
- struct asm_instruction *inst_head;
- struct asm_instruction *inst_tail;
- /*@}*/
-
-
- /**
- * Selected limits copied from gl_constants
- *
- * These are limits from the GL context, but various bits in the program
- * must be validated against these values.
- */
- /*@{*/
- unsigned MaxTextureCoordUnits;
- unsigned MaxTextureImageUnits;
- unsigned MaxTextureUnits;
- unsigned MaxClipPlanes;
- unsigned MaxLights;
- unsigned MaxProgramMatrices;
- /*@}*/
-
- /**
- * Value to use in state vector accessors for environment and local
- * parameters
- */
- unsigned state_param_enum;
-
-
- /**
- * Input attributes bound to specific names
- *
- * This is only needed so that errors can be properly produced when
- * multiple ATTRIB statements bind illegal combinations of vertex
- * attributes.
- */
- unsigned InputsBound;
-
- enum {
- invalid_mode = 0,
- ARB_vertex,
- ARB_fragment
- } mode;
-
- struct {
- unsigned PositionInvariant:1;
- unsigned Fog:2;
- unsigned PrecisionHint:2;
- unsigned DrawBuffers:1;
- unsigned Shadow:1;
- unsigned TexRect:1;
- unsigned TexArray:1;
- unsigned NV_fragment:1;
- unsigned OriginUpperLeft:1;
- unsigned PixelCenterInteger:1;
- } option;
-
- struct {
- unsigned UsesKill:1;
- } fragment;
-};
-
-#define OPTION_NONE 0
-#define OPTION_FOG_EXP 1
-#define OPTION_FOG_EXP2 2
-#define OPTION_FOG_LINEAR 3
-#define OPTION_NICEST 1
-#define OPTION_FASTEST 2
-
-typedef struct YYLTYPE {
- int first_line;
- int first_column;
- int last_line;
- int last_column;
- int position;
-} YYLTYPE;
-
-#define YYLTYPE_IS_DECLARED 1
-#define YYLTYPE_IS_TRIVIAL 1
-
-
-extern GLboolean _mesa_parse_arb_program(GLcontext *ctx, GLenum target,
- const GLubyte *str, GLsizei len, struct asm_parser_state *state);
-
-
-
-/* From program_lexer.l. */
-extern void _mesa_program_lexer_dtor(void *scanner);
-
-extern void _mesa_program_lexer_ctor(void **scanner,
- struct asm_parser_state *state, const char *string, size_t len);
-
-
-/**
- *\name From program_parse_extra.c
- */
-/*@{*/
-
-/**
- * Parses and processes an option string to an ARB vertex program
- *
- * \return
- * Non-zero on success, zero on failure.
- */
-extern int _mesa_ARBvp_parse_option(struct asm_parser_state *state,
- const char *option);
-
-/**
- * Parses and processes an option string to an ARB fragment program
- *
- * \return
- * Non-zero on success, zero on failure.
- */
-extern int _mesa_ARBfp_parse_option(struct asm_parser_state *state,
- const char *option);
-
-/**
- * Parses and processes instruction suffixes
- *
- * Instruction suffixes, such as \c _SAT, are processed. The relevant bits
- * are set in \c inst. If suffixes are encountered that are either not known
- * or not supported by the modes and options set in \c state, zero will be
- * returned.
- *
- * \return
- * Non-zero on success, zero on failure.
- */
-extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
- const char *suffix, struct prog_instruction *inst);
-
-/**
- * Parses a condition code name
- *
- * The condition code names (e.g., \c LT, \c GT, \c NE) were added to assembly
- * shaders with the \c GL_NV_fragment_program_option extension. This function
- * converts a string representation into one of the \c COND_ macros.
- *
- * \return
- * One of the \c COND_ macros defined in prog_instruction.h on success or zero
- * on failure.
- */
-extern int _mesa_parse_cc(const char *s);
-
-/*@}*/
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+#pragma once
+
+#include "main/config.h"
+
+struct gl_context;
+
+enum asm_type {
+ at_none,
+ at_address,
+ at_attrib,
+ at_param,
+ at_temp,
+ at_output
+};
+
+struct asm_symbol {
+ struct asm_symbol *next; /**< List linkage for freeing. */
+ const char *name;
+ enum asm_type type;
+ unsigned attrib_binding;
+ unsigned output_binding; /**< Output / result register number. */
+
+ /**
+ * One of PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM, or PROGRAM_ENV_PARAM.
+ */
+ unsigned param_binding_type;
+
+ /**
+ * Offset into the program_parameter_list where the tokens representing our
+ * bound state (or constants) start.
+ */
+ unsigned param_binding_begin;
+
+ /**
+ * Constants put into the parameter list may be swizzled. This
+ * field contain's the symbol's swizzle. (SWIZZLE_X/Y/Z/W)
+ */
+ unsigned param_binding_swizzle;
+
+ /* This is how many entries in 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.
+ */
+ unsigned param_binding_length;
+
+ /**
+ * Index of the temp register assigned to this variable.
+ */
+ unsigned temp_binding;
+
+ /**
+ * Flag whether or not a PARAM is an array
+ */
+ unsigned param_is_array:1;
+
+
+ /**
+ * Flag whether or not a PARAM array is accessed indirectly
+ */
+ unsigned param_accessed_indirectly:1;
+
+
+ /**
+ * \brief Is first pass of parameter layout done with this variable?
+ *
+ * The parameter layout routine operates in two passes. This flag tracks
+ * whether or not the first pass has handled this variable.
+ *
+ * \sa _mesa_layout_parameters
+ */
+ unsigned pass1_done:1;
+};
+
+
+struct asm_vector {
+ unsigned count;
+ float data[4];
+};
+
+
+struct asm_swizzle_mask {
+ unsigned swizzle:12;
+ unsigned mask:4;
+};
+
+
+struct asm_src_register {
+ struct prog_src_register Base;
+
+ /**
+ * Symbol associated with indirect access to parameter arrays.
+ *
+ * If \c Base::RelAddr is 1, this will point to the symbol for the parameter
+ * that is being dereferenced. Further, \c Base::Index will be the offset
+ * from the address register being used.
+ */
+ struct asm_symbol *Symbol;
+};
+
+
+struct asm_instruction {
+ struct prog_instruction Base;
+ struct asm_instruction *next;
+ struct asm_src_register SrcReg[3];
+};
+
+
+struct asm_parser_state {
+ struct gl_context *ctx;
+ struct gl_program *prog;
+
+ /**
+ * Per-program target limits
+ */
+ struct gl_program_constants *limits;
+
+ struct _mesa_symbol_table *st;
+
+ /**
+ * Linked list of symbols
+ *
+ * This list is \b only used when cleaning up compiler state and freeing
+ * memory.
+ */
+ struct asm_symbol *sym;
+
+ /**
+ * State for the lexer.
+ */
+ void *scanner;
+
+ /**
+ * Linked list of instructions generated during parsing.
+ */
+ /*@{*/
+ struct asm_instruction *inst_head;
+ struct asm_instruction *inst_tail;
+ /*@}*/
+
+
+ /**
+ * Selected limits copied from gl_constants
+ *
+ * These are limits from the GL context, but various bits in the program
+ * must be validated against these values.
+ */
+ /*@{*/
+ unsigned MaxTextureCoordUnits;
+ unsigned MaxTextureImageUnits;
+ unsigned MaxTextureUnits;
+ unsigned MaxClipPlanes;
+ unsigned MaxLights;
+ unsigned MaxProgramMatrices;
+ /*@}*/
+
+ /**
+ * Value to use in state vector accessors for environment and local
+ * parameters
+ */
+ unsigned state_param_enum;
+
+
+ /**
+ * Input attributes bound to specific names
+ *
+ * This is only needed so that errors can be properly produced when
+ * multiple ATTRIB statements bind illegal combinations of vertex
+ * attributes.
+ */
+ unsigned InputsBound;
+
+ enum {
+ invalid_mode = 0,
+ ARB_vertex,
+ ARB_fragment
+ } mode;
+
+ struct {
+ unsigned PositionInvariant:1;
+ unsigned Fog:2;
+ unsigned PrecisionHint:2;
+ unsigned DrawBuffers:1;
+ unsigned Shadow:1;
+ unsigned TexRect:1;
+ unsigned TexArray:1;
+ unsigned NV_fragment:1;
+ unsigned OriginUpperLeft:1;
+ unsigned PixelCenterInteger:1;
+ } option;
+
+ struct {
+ unsigned UsesKill:1;
+ } fragment;
+};
+
+#define OPTION_NONE 0
+#define OPTION_FOG_EXP 1
+#define OPTION_FOG_EXP2 2
+#define OPTION_FOG_LINEAR 3
+#define OPTION_NICEST 1
+#define OPTION_FASTEST 2
+
+typedef struct YYLTYPE {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+ int position;
+} YYLTYPE;
+
+#define YYLTYPE_IS_DECLARED 1
+#define YYLTYPE_IS_TRIVIAL 1
+
+
+extern GLboolean _mesa_parse_arb_program(struct gl_context *ctx, GLenum target,
+ const GLubyte *str, GLsizei len, struct asm_parser_state *state);
+
+
+
+/* From program_lexer.l. */
+extern void _mesa_program_lexer_dtor(void *scanner);
+
+extern void _mesa_program_lexer_ctor(void **scanner,
+ struct asm_parser_state *state, const char *string, size_t len);
+
+
+/**
+ *\name From program_parse_extra.c
+ */
+/*@{*/
+
+/**
+ * Parses and processes an option string to an ARB vertex program
+ *
+ * \return
+ * Non-zero on success, zero on failure.
+ */
+extern int _mesa_ARBvp_parse_option(struct asm_parser_state *state,
+ const char *option);
+
+/**
+ * Parses and processes an option string to an ARB fragment program
+ *
+ * \return
+ * Non-zero on success, zero on failure.
+ */
+extern int _mesa_ARBfp_parse_option(struct asm_parser_state *state,
+ const char *option);
+
+/**
+ * Parses and processes instruction suffixes
+ *
+ * Instruction suffixes, such as \c _SAT, are processed. The relevant bits
+ * are set in \c inst. If suffixes are encountered that are either not known
+ * or not supported by the modes and options set in \c state, zero will be
+ * returned.
+ *
+ * \return
+ * Non-zero on success, zero on failure.
+ */
+extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
+ const char *suffix, struct prog_instruction *inst);
+
+/**
+ * Parses a condition code name
+ *
+ * The condition code names (e.g., \c LT, \c GT, \c NE) were added to assembly
+ * shaders with the \c GL_NV_fragment_program_option extension. This function
+ * converts a string representation into one of the \c COND_ macros.
+ *
+ * \return
+ * One of the \c COND_ macros defined in prog_instruction.h on success or zero
+ * on failure.
+ */
+extern int _mesa_parse_cc(const char *s);
+
+/*@}*/
diff --git a/mesalib/src/mesa/program/programopt.c b/mesalib/src/mesa/program/programopt.c
index fb2ebe633..6601f7416 100644
--- a/mesalib/src/mesa/program/programopt.c
+++ b/mesalib/src/mesa/program/programopt.c
@@ -1,669 +1,669 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.3
- *
- * Copyright (C) 1999-2007 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 "main/glheader.h"
-#include "main/context.h"
-#include "prog_parameter.h"
-#include "prog_statevars.h"
-#include "program.h"
-#include "programopt.h"
-#include "prog_instruction.h"
-
-
-/**
- * This function inserts instructions for coordinate modelview * projection
- * into a vertex program.
- * May be used to implement the position_invariant option.
- */
-static void
-_mesa_insert_mvp_dp4_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 gl_state_index mvpState[4][STATE_LENGTH] = {
- { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */
- { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */
- { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */
- { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* 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;
- */
- _mesa_init_instructions(newInst, 4);
- for (i = 0; i < 4; 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_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
-
- /* free old instructions */
- _mesa_free_instructions(vprog->Base.Instructions, origLen);
-
- /* install new instructions */
- vprog->Base.Instructions = newInst;
- vprog->Base.NumInstructions = newLen;
- vprog->Base.InputsRead |= VERT_BIT_POS;
- vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS);
-}
-
-
-static void
-_mesa_insert_mvp_mad_code(GLcontext *ctx, struct gl_vertex_program *vprog)
-{
- struct prog_instruction *newInst;
- const GLuint origLen = vprog->Base.NumInstructions;
- const GLuint newLen = origLen + 4;
- GLuint hposTemp;
- GLuint i;
-
- /*
- * Setup state references for the modelview/projection matrix.
- * XXX we should check if these state vars are already declared.
- */
- static const gl_state_index mvpState[4][STATE_LENGTH] = {
- { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE },
- { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE },
- { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE },
- { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE },
- };
- 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;
- }
-
- /* TEMP hposTemp; */
- hposTemp = vprog->Base.NumTemporaries++;
-
- /*
- * Generated instructions:
- * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
- * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
- * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
- * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
- */
- _mesa_init_instructions(newInst, 4);
-
- newInst[0].Opcode = OPCODE_MUL;
- newInst[0].DstReg.File = PROGRAM_TEMPORARY;
- newInst[0].DstReg.Index = hposTemp;
- newInst[0].DstReg.WriteMask = WRITEMASK_XYZW;
- newInst[0].SrcReg[0].File = PROGRAM_INPUT;
- newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS;
- newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX;
- newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR;
- newInst[0].SrcReg[1].Index = mvpRef[0];
- newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP;
-
- for (i = 1; i <= 2; i++) {
- newInst[i].Opcode = OPCODE_MAD;
- newInst[i].DstReg.File = PROGRAM_TEMPORARY;
- newInst[i].DstReg.Index = hposTemp;
- newInst[i].DstReg.WriteMask = WRITEMASK_XYZW;
- newInst[i].SrcReg[0].File = PROGRAM_INPUT;
- newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS;
- newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i);
- newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR;
- newInst[i].SrcReg[1].Index = mvpRef[i];
- newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
- newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY;
- newInst[i].SrcReg[2].Index = hposTemp;
- newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP;
- }
-
- newInst[3].Opcode = OPCODE_MAD;
- newInst[3].DstReg.File = PROGRAM_OUTPUT;
- newInst[3].DstReg.Index = VERT_RESULT_HPOS;
- newInst[3].DstReg.WriteMask = WRITEMASK_XYZW;
- newInst[3].SrcReg[0].File = PROGRAM_INPUT;
- newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS;
- newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW;
- newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR;
- newInst[3].SrcReg[1].Index = mvpRef[3];
- newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP;
- newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY;
- newInst[3].SrcReg[2].Index = hposTemp;
- newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP;
-
-
- /* Append original instructions after new instructions */
- _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
-
- /* free old instructions */
- _mesa_free_instructions(vprog->Base.Instructions, origLen);
-
- /* install new instructions */
- vprog->Base.Instructions = newInst;
- vprog->Base.NumInstructions = newLen;
- vprog->Base.InputsRead |= VERT_BIT_POS;
- vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS);
-}
-
-
-void
-_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog)
-{
- if (ctx->mvp_with_dp4)
- _mesa_insert_mvp_dp4_code( ctx, vprog );
- else
- _mesa_insert_mvp_mad_code( ctx, vprog );
-}
-
-
-
-
-
-
-/**
- * Append extra instructions onto the given fragment program to implement
- * the fog mode specified by fprog->FogOption.
- * The fragment.fogcoord input is used to compute the fog blend factor.
- *
- * XXX with a little work, this function could be adapted to add fog code
- * to vertex programs too.
- */
-void
-_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog)
-{
- static const gl_state_index fogPStateOpt[STATE_LENGTH]
- = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 };
- static const gl_state_index fogColorState[STATE_LENGTH]
- = { STATE_FOG_COLOR, 0, 0, 0, 0};
- struct prog_instruction *newInst, *inst;
- const GLuint origLen = fprog->Base.NumInstructions;
- const GLuint newLen = origLen + 5;
- GLuint i;
- GLint fogPRefOpt, fogColorRef; /* state references */
- GLuint colorTemp, fogFactorTemp; /* temporary registerss */
-
- if (fprog->FogOption == GL_NONE) {
- _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
- " with FogOption == GL_NONE");
- return;
- }
-
- /* Alloc storage for new instructions */
- newInst = _mesa_alloc_instructions(newLen);
- if (!newInst) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "glProgramString(inserting fog_option code)");
- return;
- }
-
- /* Copy orig instructions into new instruction buffer */
- _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen);
-
- /* PARAM fogParamsRefOpt = internal optimized fog params; */
- fogPRefOpt
- = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt);
- /* PARAM fogColorRef = state.fog.color; */
- fogColorRef
- = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
-
- /* TEMP colorTemp; */
- colorTemp = fprog->Base.NumTemporaries++;
- /* TEMP fogFactorTemp; */
- fogFactorTemp = fprog->Base.NumTemporaries++;
-
- /* Scan program to find where result.color is written */
- inst = newInst;
- for (i = 0; i < fprog->Base.NumInstructions; i++) {
- if (inst->Opcode == OPCODE_END)
- break;
- if (inst->DstReg.File == PROGRAM_OUTPUT &&
- inst->DstReg.Index == FRAG_RESULT_COLOR) {
- /* change the instruction to write to colorTemp w/ clamping */
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = colorTemp;
- inst->SaturateMode = SATURATE_ZERO_ONE;
- /* don't break (may be several writes to result.color) */
- }
- inst++;
- }
- assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
-
- _mesa_init_instructions(inst, 5);
-
- /* emit instructions to compute fog blending factor */
- if (fprog->FogOption == GL_LINEAR) {
- /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */
- inst->Opcode = OPCODE_MAD;
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = fogFactorTemp;
- inst->DstReg.WriteMask = WRITEMASK_X;
- inst->SrcReg[0].File = PROGRAM_INPUT;
- inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC;
- inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
- inst->SrcReg[1].File = PROGRAM_STATE_VAR;
- inst->SrcReg[1].Index = fogPRefOpt;
- inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
- inst->SrcReg[2].File = PROGRAM_STATE_VAR;
- inst->SrcReg[2].Index = fogPRefOpt;
- inst->SrcReg[2].Swizzle = SWIZZLE_YYYY;
- inst->SaturateMode = SATURATE_ZERO_ONE;
- inst++;
- }
- else {
- ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2);
- /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */
- /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */
- /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */
- inst->Opcode = OPCODE_MUL;
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = fogFactorTemp;
- inst->DstReg.WriteMask = WRITEMASK_X;
- inst->SrcReg[0].File = PROGRAM_STATE_VAR;
- inst->SrcReg[0].Index = fogPRefOpt;
- inst->SrcReg[0].Swizzle
- = (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW;
- inst->SrcReg[1].File = PROGRAM_INPUT;
- inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC;
- inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
- inst++;
- if (fprog->FogOption == GL_EXP2) {
- /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
- inst->Opcode = OPCODE_MUL;
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = fogFactorTemp;
- inst->DstReg.WriteMask = WRITEMASK_X;
- inst->SrcReg[0].File = PROGRAM_TEMPORARY;
- inst->SrcReg[0].Index = fogFactorTemp;
- inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
- inst->SrcReg[1].File = PROGRAM_TEMPORARY;
- inst->SrcReg[1].Index = fogFactorTemp;
- inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
- inst++;
- }
- /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
- inst->Opcode = OPCODE_EX2;
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = fogFactorTemp;
- inst->DstReg.WriteMask = WRITEMASK_X;
- inst->SrcReg[0].File = PROGRAM_TEMPORARY;
- inst->SrcReg[0].Index = fogFactorTemp;
- inst->SrcReg[0].Negate = NEGATE_XYZW;
- inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
- inst->SaturateMode = SATURATE_ZERO_ONE;
- inst++;
- }
- /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
- inst->Opcode = OPCODE_LRP;
- inst->DstReg.File = PROGRAM_OUTPUT;
- inst->DstReg.Index = FRAG_RESULT_COLOR;
- inst->DstReg.WriteMask = WRITEMASK_XYZ;
- inst->SrcReg[0].File = PROGRAM_TEMPORARY;
- inst->SrcReg[0].Index = fogFactorTemp;
- inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
- inst->SrcReg[1].File = PROGRAM_TEMPORARY;
- inst->SrcReg[1].Index = colorTemp;
- inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
- inst->SrcReg[2].File = PROGRAM_STATE_VAR;
- inst->SrcReg[2].Index = fogColorRef;
- inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
- inst++;
- /* MOV result.color.w, colorTemp.x; # copy alpha */
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.File = PROGRAM_OUTPUT;
- inst->DstReg.Index = FRAG_RESULT_COLOR;
- inst->DstReg.WriteMask = WRITEMASK_W;
- inst->SrcReg[0].File = PROGRAM_TEMPORARY;
- inst->SrcReg[0].Index = colorTemp;
- inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
- inst++;
- /* END; */
- inst->Opcode = OPCODE_END;
- inst++;
-
- /* free old instructions */
- _mesa_free_instructions(fprog->Base.Instructions, origLen);
-
- /* install new instructions */
- fprog->Base.Instructions = newInst;
- fprog->Base.NumInstructions = inst - newInst;
- fprog->Base.InputsRead |= FRAG_BIT_FOGC;
- /* XXX do this? fprog->FogOption = GL_NONE; */
-}
-
-
-
-static GLboolean
-is_texture_instruction(const struct prog_instruction *inst)
-{
- switch (inst->Opcode) {
- case OPCODE_TEX:
- case OPCODE_TXB:
- case OPCODE_TXD:
- case OPCODE_TXL:
- case OPCODE_TXP:
- case OPCODE_TXP_NV:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * Count the number of texure indirections in the given program.
- * The program's NumTexIndirections field will be updated.
- * See the GL_ARB_fragment_program spec (issue 24) for details.
- * XXX we count texture indirections in texenvprogram.c (maybe use this code
- * instead and elsewhere).
- */
-void
-_mesa_count_texture_indirections(struct gl_program *prog)
-{
- GLuint indirections = 1;
- GLbitfield tempsOutput = 0x0;
- GLbitfield aluTemps = 0x0;
- GLuint i;
-
- for (i = 0; i < prog->NumInstructions; i++) {
- const struct prog_instruction *inst = prog->Instructions + i;
-
- if (is_texture_instruction(inst)) {
- if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) &&
- (tempsOutput & (1 << inst->SrcReg[0].Index))) ||
- ((inst->Opcode != OPCODE_KIL) &&
- (inst->DstReg.File == PROGRAM_TEMPORARY) &&
- (aluTemps & (1 << inst->DstReg.Index))))
- {
- indirections++;
- tempsOutput = 0x0;
- aluTemps = 0x0;
- }
- }
- else {
- GLuint j;
- for (j = 0; j < 3; j++) {
- if (inst->SrcReg[j].File == PROGRAM_TEMPORARY)
- aluTemps |= (1 << inst->SrcReg[j].Index);
- }
- if (inst->DstReg.File == PROGRAM_TEMPORARY)
- aluTemps |= (1 << inst->DstReg.Index);
- }
-
- if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY))
- tempsOutput |= (1 << inst->DstReg.Index);
- }
-
- prog->NumTexIndirections = indirections;
-}
-
-
-/**
- * Count number of texture instructions in given program and update the
- * program's NumTexInstructions field.
- */
-void
-_mesa_count_texture_instructions(struct gl_program *prog)
-{
- GLuint i;
- prog->NumTexInstructions = 0;
- for (i = 0; i < prog->NumInstructions; i++) {
- prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i);
- }
-}
-
-
-/**
- * Scan/rewrite program to remove reads of custom (output) registers.
- * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING
- * (for vertex shaders).
- * In GLSL shaders, varying vars can be read and written.
- * On some hardware, trying to read an output register causes trouble.
- * So, rewrite the program to use a temporary register in this case.
- */
-void
-_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type)
-{
- GLuint i;
- GLint outputMap[VERT_RESULT_MAX];
- GLuint numVaryingReads = 0;
- GLboolean usedTemps[MAX_PROGRAM_TEMPS];
- GLuint firstTemp = 0;
-
- _mesa_find_used_registers(prog, PROGRAM_TEMPORARY,
- usedTemps, MAX_PROGRAM_TEMPS);
-
- assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT);
- assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING);
-
- for (i = 0; i < VERT_RESULT_MAX; i++)
- outputMap[i] = -1;
-
- /* look for instructions which read from varying vars */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
- GLuint j;
- for (j = 0; j < numSrc; j++) {
- if (inst->SrcReg[j].File == type) {
- /* replace the read with a temp reg */
- const GLuint var = inst->SrcReg[j].Index;
- if (outputMap[var] == -1) {
- numVaryingReads++;
- outputMap[var] = _mesa_find_free_register(usedTemps,
- MAX_PROGRAM_TEMPS,
- firstTemp);
- firstTemp = outputMap[var] + 1;
- }
- inst->SrcReg[j].File = PROGRAM_TEMPORARY;
- inst->SrcReg[j].Index = outputMap[var];
- }
- }
- }
-
- if (numVaryingReads == 0)
- return; /* nothing to be done */
-
- /* look for instructions which write to the varying vars identified above */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- if (inst->DstReg.File == type &&
- outputMap[inst->DstReg.Index] >= 0) {
- /* change inst to write to the temp reg, instead of the varying */
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = outputMap[inst->DstReg.Index];
- }
- }
-
- /* insert new instructions to copy the temp vars to the varying vars */
- {
- struct prog_instruction *inst;
- GLint endPos, var;
-
- /* Look for END instruction and insert the new varying writes */
- endPos = -1;
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- if (inst->Opcode == OPCODE_END) {
- endPos = i;
- _mesa_insert_instructions(prog, i, numVaryingReads);
- break;
- }
- }
-
- assert(endPos >= 0);
-
- /* insert new MOV instructions here */
- inst = prog->Instructions + endPos;
- for (var = 0; var < VERT_RESULT_MAX; var++) {
- if (outputMap[var] >= 0) {
- /* MOV VAR[var], TEMP[tmp]; */
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.File = type;
- inst->DstReg.Index = var;
- inst->SrcReg[0].File = PROGRAM_TEMPORARY;
- inst->SrcReg[0].Index = outputMap[var];
- inst++;
- }
- }
- }
-}
-
-
-/**
- * Make the given fragment program into a "no-op" shader.
- * Actually, just copy the incoming fragment color (or texcoord)
- * to the output color.
- * This is for debug/test purposes.
- */
-void
-_mesa_nop_fragment_program(GLcontext *ctx, struct gl_fragment_program *prog)
-{
- struct prog_instruction *inst;
- GLuint inputAttr;
-
- inst = _mesa_alloc_instructions(2);
- if (!inst) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program");
- return;
- }
-
- _mesa_init_instructions(inst, 2);
-
- inst[0].Opcode = OPCODE_MOV;
- inst[0].DstReg.File = PROGRAM_OUTPUT;
- inst[0].DstReg.Index = FRAG_RESULT_COLOR;
- inst[0].SrcReg[0].File = PROGRAM_INPUT;
- if (prog->Base.InputsRead & FRAG_BIT_COL0)
- inputAttr = FRAG_ATTRIB_COL0;
- else
- inputAttr = FRAG_ATTRIB_TEX0;
- inst[0].SrcReg[0].Index = inputAttr;
-
- inst[1].Opcode = OPCODE_END;
-
- _mesa_free_instructions(prog->Base.Instructions,
- prog->Base.NumInstructions);
-
- prog->Base.Instructions = inst;
- prog->Base.NumInstructions = 2;
- prog->Base.InputsRead = 1 << inputAttr;
- prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
-}
-
-
-/**
- * \sa _mesa_nop_fragment_program
- * Replace the given vertex program with a "no-op" program that just
- * transforms vertex position and emits color.
- */
-void
-_mesa_nop_vertex_program(GLcontext *ctx, struct gl_vertex_program *prog)
-{
- struct prog_instruction *inst;
- GLuint inputAttr;
-
- /*
- * Start with a simple vertex program that emits color.
- */
- inst = _mesa_alloc_instructions(2);
- if (!inst) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program");
- return;
- }
-
- _mesa_init_instructions(inst, 2);
-
- inst[0].Opcode = OPCODE_MOV;
- inst[0].DstReg.File = PROGRAM_OUTPUT;
- inst[0].DstReg.Index = VERT_RESULT_COL0;
- inst[0].SrcReg[0].File = PROGRAM_INPUT;
- if (prog->Base.InputsRead & VERT_BIT_COLOR0)
- inputAttr = VERT_ATTRIB_COLOR0;
- else
- inputAttr = VERT_ATTRIB_TEX0;
- inst[0].SrcReg[0].Index = inputAttr;
-
- inst[1].Opcode = OPCODE_END;
-
- _mesa_free_instructions(prog->Base.Instructions,
- prog->Base.NumInstructions);
-
- prog->Base.Instructions = inst;
- prog->Base.NumInstructions = 2;
- prog->Base.InputsRead = 1 << inputAttr;
- prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0);
-
- /*
- * Now insert code to do standard modelview/projection transformation.
- */
- _mesa_insert_mvp_code(ctx, prog);
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.3
+ *
+ * Copyright (C) 1999-2007 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 "main/glheader.h"
+#include "main/context.h"
+#include "prog_parameter.h"
+#include "prog_statevars.h"
+#include "program.h"
+#include "programopt.h"
+#include "prog_instruction.h"
+
+
+/**
+ * This function inserts instructions for coordinate modelview * projection
+ * into a vertex program.
+ * May be used to implement the position_invariant option.
+ */
+static void
+_mesa_insert_mvp_dp4_code(struct gl_context *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 gl_state_index mvpState[4][STATE_LENGTH] = {
+ { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */
+ { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */
+ { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */
+ { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* 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;
+ */
+ _mesa_init_instructions(newInst, 4);
+ for (i = 0; i < 4; 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_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
+
+ /* free old instructions */
+ _mesa_free_instructions(vprog->Base.Instructions, origLen);
+
+ /* install new instructions */
+ vprog->Base.Instructions = newInst;
+ vprog->Base.NumInstructions = newLen;
+ vprog->Base.InputsRead |= VERT_BIT_POS;
+ vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS);
+}
+
+
+static void
+_mesa_insert_mvp_mad_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
+{
+ struct prog_instruction *newInst;
+ const GLuint origLen = vprog->Base.NumInstructions;
+ const GLuint newLen = origLen + 4;
+ GLuint hposTemp;
+ GLuint i;
+
+ /*
+ * Setup state references for the modelview/projection matrix.
+ * XXX we should check if these state vars are already declared.
+ */
+ static const gl_state_index mvpState[4][STATE_LENGTH] = {
+ { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE },
+ { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE },
+ { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE },
+ { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE },
+ };
+ 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;
+ }
+
+ /* TEMP hposTemp; */
+ hposTemp = vprog->Base.NumTemporaries++;
+
+ /*
+ * Generated instructions:
+ * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
+ * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
+ * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
+ * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
+ */
+ _mesa_init_instructions(newInst, 4);
+
+ newInst[0].Opcode = OPCODE_MUL;
+ newInst[0].DstReg.File = PROGRAM_TEMPORARY;
+ newInst[0].DstReg.Index = hposTemp;
+ newInst[0].DstReg.WriteMask = WRITEMASK_XYZW;
+ newInst[0].SrcReg[0].File = PROGRAM_INPUT;
+ newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS;
+ newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX;
+ newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR;
+ newInst[0].SrcReg[1].Index = mvpRef[0];
+ newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP;
+
+ for (i = 1; i <= 2; i++) {
+ newInst[i].Opcode = OPCODE_MAD;
+ newInst[i].DstReg.File = PROGRAM_TEMPORARY;
+ newInst[i].DstReg.Index = hposTemp;
+ newInst[i].DstReg.WriteMask = WRITEMASK_XYZW;
+ newInst[i].SrcReg[0].File = PROGRAM_INPUT;
+ newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS;
+ newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i);
+ newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR;
+ newInst[i].SrcReg[1].Index = mvpRef[i];
+ newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
+ newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY;
+ newInst[i].SrcReg[2].Index = hposTemp;
+ newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP;
+ }
+
+ newInst[3].Opcode = OPCODE_MAD;
+ newInst[3].DstReg.File = PROGRAM_OUTPUT;
+ newInst[3].DstReg.Index = VERT_RESULT_HPOS;
+ newInst[3].DstReg.WriteMask = WRITEMASK_XYZW;
+ newInst[3].SrcReg[0].File = PROGRAM_INPUT;
+ newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS;
+ newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW;
+ newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR;
+ newInst[3].SrcReg[1].Index = mvpRef[3];
+ newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP;
+ newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY;
+ newInst[3].SrcReg[2].Index = hposTemp;
+ newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP;
+
+
+ /* Append original instructions after new instructions */
+ _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
+
+ /* free old instructions */
+ _mesa_free_instructions(vprog->Base.Instructions, origLen);
+
+ /* install new instructions */
+ vprog->Base.Instructions = newInst;
+ vprog->Base.NumInstructions = newLen;
+ vprog->Base.InputsRead |= VERT_BIT_POS;
+ vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS);
+}
+
+
+void
+_mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
+{
+ if (ctx->mvp_with_dp4)
+ _mesa_insert_mvp_dp4_code( ctx, vprog );
+ else
+ _mesa_insert_mvp_mad_code( ctx, vprog );
+}
+
+
+
+
+
+
+/**
+ * Append extra instructions onto the given fragment program to implement
+ * the fog mode specified by fprog->FogOption.
+ * The fragment.fogcoord input is used to compute the fog blend factor.
+ *
+ * XXX with a little work, this function could be adapted to add fog code
+ * to vertex programs too.
+ */
+void
+_mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog)
+{
+ static const gl_state_index fogPStateOpt[STATE_LENGTH]
+ = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 };
+ static const gl_state_index fogColorState[STATE_LENGTH]
+ = { STATE_FOG_COLOR, 0, 0, 0, 0};
+ struct prog_instruction *newInst, *inst;
+ const GLuint origLen = fprog->Base.NumInstructions;
+ const GLuint newLen = origLen + 5;
+ GLuint i;
+ GLint fogPRefOpt, fogColorRef; /* state references */
+ GLuint colorTemp, fogFactorTemp; /* temporary registerss */
+
+ if (fprog->FogOption == GL_NONE) {
+ _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
+ " with FogOption == GL_NONE");
+ return;
+ }
+
+ /* Alloc storage for new instructions */
+ newInst = _mesa_alloc_instructions(newLen);
+ if (!newInst) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "glProgramString(inserting fog_option code)");
+ return;
+ }
+
+ /* Copy orig instructions into new instruction buffer */
+ _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen);
+
+ /* PARAM fogParamsRefOpt = internal optimized fog params; */
+ fogPRefOpt
+ = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt);
+ /* PARAM fogColorRef = state.fog.color; */
+ fogColorRef
+ = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
+
+ /* TEMP colorTemp; */
+ colorTemp = fprog->Base.NumTemporaries++;
+ /* TEMP fogFactorTemp; */
+ fogFactorTemp = fprog->Base.NumTemporaries++;
+
+ /* Scan program to find where result.color is written */
+ inst = newInst;
+ for (i = 0; i < fprog->Base.NumInstructions; i++) {
+ if (inst->Opcode == OPCODE_END)
+ break;
+ if (inst->DstReg.File == PROGRAM_OUTPUT &&
+ inst->DstReg.Index == FRAG_RESULT_COLOR) {
+ /* change the instruction to write to colorTemp w/ clamping */
+ inst->DstReg.File = PROGRAM_TEMPORARY;
+ inst->DstReg.Index = colorTemp;
+ inst->SaturateMode = SATURATE_ZERO_ONE;
+ /* don't break (may be several writes to result.color) */
+ }
+ inst++;
+ }
+ assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
+
+ _mesa_init_instructions(inst, 5);
+
+ /* emit instructions to compute fog blending factor */
+ if (fprog->FogOption == GL_LINEAR) {
+ /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */
+ inst->Opcode = OPCODE_MAD;
+ inst->DstReg.File = PROGRAM_TEMPORARY;
+ inst->DstReg.Index = fogFactorTemp;
+ inst->DstReg.WriteMask = WRITEMASK_X;
+ inst->SrcReg[0].File = PROGRAM_INPUT;
+ inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
+ inst->SrcReg[1].File = PROGRAM_STATE_VAR;
+ inst->SrcReg[1].Index = fogPRefOpt;
+ inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
+ inst->SrcReg[2].File = PROGRAM_STATE_VAR;
+ inst->SrcReg[2].Index = fogPRefOpt;
+ inst->SrcReg[2].Swizzle = SWIZZLE_YYYY;
+ inst->SaturateMode = SATURATE_ZERO_ONE;
+ inst++;
+ }
+ else {
+ ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2);
+ /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */
+ /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */
+ /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */
+ inst->Opcode = OPCODE_MUL;
+ inst->DstReg.File = PROGRAM_TEMPORARY;
+ inst->DstReg.Index = fogFactorTemp;
+ inst->DstReg.WriteMask = WRITEMASK_X;
+ inst->SrcReg[0].File = PROGRAM_STATE_VAR;
+ inst->SrcReg[0].Index = fogPRefOpt;
+ inst->SrcReg[0].Swizzle
+ = (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW;
+ inst->SrcReg[1].File = PROGRAM_INPUT;
+ inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC;
+ inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
+ inst++;
+ if (fprog->FogOption == GL_EXP2) {
+ /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
+ inst->Opcode = OPCODE_MUL;
+ inst->DstReg.File = PROGRAM_TEMPORARY;
+ inst->DstReg.Index = fogFactorTemp;
+ inst->DstReg.WriteMask = WRITEMASK_X;
+ inst->SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[0].Index = fogFactorTemp;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
+ inst->SrcReg[1].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[1].Index = fogFactorTemp;
+ inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
+ inst++;
+ }
+ /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
+ inst->Opcode = OPCODE_EX2;
+ inst->DstReg.File = PROGRAM_TEMPORARY;
+ inst->DstReg.Index = fogFactorTemp;
+ inst->DstReg.WriteMask = WRITEMASK_X;
+ inst->SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[0].Index = fogFactorTemp;
+ inst->SrcReg[0].Negate = NEGATE_XYZW;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
+ inst->SaturateMode = SATURATE_ZERO_ONE;
+ inst++;
+ }
+ /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
+ inst->Opcode = OPCODE_LRP;
+ inst->DstReg.File = PROGRAM_OUTPUT;
+ inst->DstReg.Index = FRAG_RESULT_COLOR;
+ inst->DstReg.WriteMask = WRITEMASK_XYZ;
+ inst->SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[0].Index = fogFactorTemp;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
+ inst->SrcReg[1].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[1].Index = colorTemp;
+ inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
+ inst->SrcReg[2].File = PROGRAM_STATE_VAR;
+ inst->SrcReg[2].Index = fogColorRef;
+ inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
+ inst++;
+ /* MOV result.color.w, colorTemp.x; # copy alpha */
+ inst->Opcode = OPCODE_MOV;
+ inst->DstReg.File = PROGRAM_OUTPUT;
+ inst->DstReg.Index = FRAG_RESULT_COLOR;
+ inst->DstReg.WriteMask = WRITEMASK_W;
+ inst->SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[0].Index = colorTemp;
+ inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
+ inst++;
+ /* END; */
+ inst->Opcode = OPCODE_END;
+ inst++;
+
+ /* free old instructions */
+ _mesa_free_instructions(fprog->Base.Instructions, origLen);
+
+ /* install new instructions */
+ fprog->Base.Instructions = newInst;
+ fprog->Base.NumInstructions = inst - newInst;
+ fprog->Base.InputsRead |= FRAG_BIT_FOGC;
+ /* XXX do this? fprog->FogOption = GL_NONE; */
+}
+
+
+
+static GLboolean
+is_texture_instruction(const struct prog_instruction *inst)
+{
+ switch (inst->Opcode) {
+ case OPCODE_TEX:
+ case OPCODE_TXB:
+ case OPCODE_TXD:
+ case OPCODE_TXL:
+ case OPCODE_TXP:
+ case OPCODE_TXP_NV:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Count the number of texure indirections in the given program.
+ * The program's NumTexIndirections field will be updated.
+ * See the GL_ARB_fragment_program spec (issue 24) for details.
+ * XXX we count texture indirections in texenvprogram.c (maybe use this code
+ * instead and elsewhere).
+ */
+void
+_mesa_count_texture_indirections(struct gl_program *prog)
+{
+ GLuint indirections = 1;
+ GLbitfield tempsOutput = 0x0;
+ GLbitfield aluTemps = 0x0;
+ GLuint i;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+
+ if (is_texture_instruction(inst)) {
+ if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) &&
+ (tempsOutput & (1 << inst->SrcReg[0].Index))) ||
+ ((inst->Opcode != OPCODE_KIL) &&
+ (inst->DstReg.File == PROGRAM_TEMPORARY) &&
+ (aluTemps & (1 << inst->DstReg.Index))))
+ {
+ indirections++;
+ tempsOutput = 0x0;
+ aluTemps = 0x0;
+ }
+ }
+ else {
+ GLuint j;
+ for (j = 0; j < 3; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_TEMPORARY)
+ aluTemps |= (1 << inst->SrcReg[j].Index);
+ }
+ if (inst->DstReg.File == PROGRAM_TEMPORARY)
+ aluTemps |= (1 << inst->DstReg.Index);
+ }
+
+ if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY))
+ tempsOutput |= (1 << inst->DstReg.Index);
+ }
+
+ prog->NumTexIndirections = indirections;
+}
+
+
+/**
+ * Count number of texture instructions in given program and update the
+ * program's NumTexInstructions field.
+ */
+void
+_mesa_count_texture_instructions(struct gl_program *prog)
+{
+ GLuint i;
+ prog->NumTexInstructions = 0;
+ for (i = 0; i < prog->NumInstructions; i++) {
+ prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i);
+ }
+}
+
+
+/**
+ * Scan/rewrite program to remove reads of custom (output) registers.
+ * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING
+ * (for vertex shaders).
+ * In GLSL shaders, varying vars can be read and written.
+ * On some hardware, trying to read an output register causes trouble.
+ * So, rewrite the program to use a temporary register in this case.
+ */
+void
+_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type)
+{
+ GLuint i;
+ GLint outputMap[VERT_RESULT_MAX];
+ GLuint numVaryingReads = 0;
+ GLboolean usedTemps[MAX_PROGRAM_TEMPS];
+ GLuint firstTemp = 0;
+
+ _mesa_find_used_registers(prog, PROGRAM_TEMPORARY,
+ usedTemps, MAX_PROGRAM_TEMPS);
+
+ assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT);
+ assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING);
+
+ for (i = 0; i < VERT_RESULT_MAX; i++)
+ outputMap[i] = -1;
+
+ /* look for instructions which read from varying vars */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ GLuint j;
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == type) {
+ /* replace the read with a temp reg */
+ const GLuint var = inst->SrcReg[j].Index;
+ if (outputMap[var] == -1) {
+ numVaryingReads++;
+ outputMap[var] = _mesa_find_free_register(usedTemps,
+ MAX_PROGRAM_TEMPS,
+ firstTemp);
+ firstTemp = outputMap[var] + 1;
+ }
+ inst->SrcReg[j].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[j].Index = outputMap[var];
+ }
+ }
+ }
+
+ if (numVaryingReads == 0)
+ return; /* nothing to be done */
+
+ /* look for instructions which write to the varying vars identified above */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->DstReg.File == type &&
+ outputMap[inst->DstReg.Index] >= 0) {
+ /* change inst to write to the temp reg, instead of the varying */
+ inst->DstReg.File = PROGRAM_TEMPORARY;
+ inst->DstReg.Index = outputMap[inst->DstReg.Index];
+ }
+ }
+
+ /* insert new instructions to copy the temp vars to the varying vars */
+ {
+ struct prog_instruction *inst;
+ GLint endPos, var;
+
+ /* Look for END instruction and insert the new varying writes */
+ endPos = -1;
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->Opcode == OPCODE_END) {
+ endPos = i;
+ _mesa_insert_instructions(prog, i, numVaryingReads);
+ break;
+ }
+ }
+
+ assert(endPos >= 0);
+
+ /* insert new MOV instructions here */
+ inst = prog->Instructions + endPos;
+ for (var = 0; var < VERT_RESULT_MAX; var++) {
+ if (outputMap[var] >= 0) {
+ /* MOV VAR[var], TEMP[tmp]; */
+ inst->Opcode = OPCODE_MOV;
+ inst->DstReg.File = type;
+ inst->DstReg.Index = var;
+ inst->SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[0].Index = outputMap[var];
+ inst++;
+ }
+ }
+ }
+}
+
+
+/**
+ * Make the given fragment program into a "no-op" shader.
+ * Actually, just copy the incoming fragment color (or texcoord)
+ * to the output color.
+ * This is for debug/test purposes.
+ */
+void
+_mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog)
+{
+ struct prog_instruction *inst;
+ GLuint inputAttr;
+
+ inst = _mesa_alloc_instructions(2);
+ if (!inst) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program");
+ return;
+ }
+
+ _mesa_init_instructions(inst, 2);
+
+ inst[0].Opcode = OPCODE_MOV;
+ inst[0].DstReg.File = PROGRAM_OUTPUT;
+ inst[0].DstReg.Index = FRAG_RESULT_COLOR;
+ inst[0].SrcReg[0].File = PROGRAM_INPUT;
+ if (prog->Base.InputsRead & FRAG_BIT_COL0)
+ inputAttr = FRAG_ATTRIB_COL0;
+ else
+ inputAttr = FRAG_ATTRIB_TEX0;
+ inst[0].SrcReg[0].Index = inputAttr;
+
+ inst[1].Opcode = OPCODE_END;
+
+ _mesa_free_instructions(prog->Base.Instructions,
+ prog->Base.NumInstructions);
+
+ prog->Base.Instructions = inst;
+ prog->Base.NumInstructions = 2;
+ prog->Base.InputsRead = 1 << inputAttr;
+ prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
+}
+
+
+/**
+ * \sa _mesa_nop_fragment_program
+ * Replace the given vertex program with a "no-op" program that just
+ * transforms vertex position and emits color.
+ */
+void
+_mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog)
+{
+ struct prog_instruction *inst;
+ GLuint inputAttr;
+
+ /*
+ * Start with a simple vertex program that emits color.
+ */
+ inst = _mesa_alloc_instructions(2);
+ if (!inst) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program");
+ return;
+ }
+
+ _mesa_init_instructions(inst, 2);
+
+ inst[0].Opcode = OPCODE_MOV;
+ inst[0].DstReg.File = PROGRAM_OUTPUT;
+ inst[0].DstReg.Index = VERT_RESULT_COL0;
+ inst[0].SrcReg[0].File = PROGRAM_INPUT;
+ if (prog->Base.InputsRead & VERT_BIT_COLOR0)
+ inputAttr = VERT_ATTRIB_COLOR0;
+ else
+ inputAttr = VERT_ATTRIB_TEX0;
+ inst[0].SrcReg[0].Index = inputAttr;
+
+ inst[1].Opcode = OPCODE_END;
+
+ _mesa_free_instructions(prog->Base.Instructions,
+ prog->Base.NumInstructions);
+
+ prog->Base.Instructions = inst;
+ prog->Base.NumInstructions = 2;
+ prog->Base.InputsRead = 1 << inputAttr;
+ prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0);
+
+ /*
+ * Now insert code to do standard modelview/projection transformation.
+ */
+ _mesa_insert_mvp_code(ctx, prog);
+}
diff --git a/mesalib/src/mesa/program/programopt.h b/mesalib/src/mesa/program/programopt.h
index 4af6357f9..2e07d8989 100644
--- a/mesalib/src/mesa/program/programopt.h
+++ b/mesalib/src/mesa/program/programopt.h
@@ -1,53 +1,53 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.3
- *
- * Copyright (C) 1999-2007 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
-
-#include "main/mtypes.h"
-
-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);
-
-extern void
-_mesa_count_texture_indirections(struct gl_program *prog);
-
-extern void
-_mesa_count_texture_instructions(struct gl_program *prog);
-
-extern void
-_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type);
-
-extern void
-_mesa_nop_fragment_program(GLcontext *ctx, struct gl_fragment_program *prog);
-
-extern void
-_mesa_nop_vertex_program(GLcontext *ctx, struct gl_vertex_program *prog);
-
-
-#endif /* PROGRAMOPT_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.3
+ *
+ * Copyright (C) 1999-2007 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
+
+#include "main/mtypes.h"
+
+extern void
+_mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog);
+
+extern void
+_mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog);
+
+extern void
+_mesa_count_texture_indirections(struct gl_program *prog);
+
+extern void
+_mesa_count_texture_instructions(struct gl_program *prog);
+
+extern void
+_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type);
+
+extern void
+_mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog);
+
+extern void
+_mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog);
+
+
+#endif /* PROGRAMOPT_H */
diff --git a/mesalib/src/mesa/program/register_allocate.c b/mesalib/src/mesa/program/register_allocate.c
new file mode 100644
index 000000000..93e0cbe78
--- /dev/null
+++ b/mesalib/src/mesa/program/register_allocate.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/** @file register_allocate.c
+ *
+ * Graph-coloring register allocator.
+ */
+
+#include <talloc.h>
+
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "register_allocate.h"
+
+struct ra_reg {
+ char *name;
+ GLboolean *conflicts;
+};
+
+struct ra_regs {
+ struct ra_reg *regs;
+ unsigned int count;
+
+ struct ra_class **classes;
+ unsigned int class_count;
+};
+
+struct ra_class {
+ GLboolean *regs;
+
+ /**
+ * p_B in Runeson/Nyström paper.
+ *
+ * This is "how many regs are in the set."
+ */
+ unsigned int p;
+
+ /**
+ * q_B,C in Runeson/Nyström paper.
+ */
+ unsigned int *q;
+};
+
+struct ra_node {
+ GLboolean *adjacency;
+ unsigned int class;
+ unsigned int adjacency_count;
+ unsigned int reg;
+ GLboolean in_stack;
+ float spill_cost;
+};
+
+struct ra_graph {
+ struct ra_regs *regs;
+ /**
+ * the variables that need register allocation.
+ */
+ struct ra_node *nodes;
+ unsigned int count; /**< count of nodes. */
+
+ unsigned int *stack;
+ unsigned int stack_count;
+};
+
+struct ra_regs *
+ra_alloc_reg_set(unsigned int count)
+{
+ unsigned int i;
+ struct ra_regs *regs;
+
+ regs = talloc_zero(NULL, struct ra_regs);
+ regs->count = count;
+ regs->regs = talloc_zero_array(regs, struct ra_reg, count);
+
+ for (i = 0; i < count; i++) {
+ regs->regs[i].conflicts = talloc_zero_array(regs->regs, GLboolean, count);
+ regs->regs[i].conflicts[i] = GL_TRUE;
+ }
+
+ return regs;
+}
+
+void
+ra_add_reg_conflict(struct ra_regs *regs, unsigned int r1, unsigned int r2)
+{
+ regs->regs[r1].conflicts[r2] = GL_TRUE;
+ regs->regs[r2].conflicts[r1] = GL_TRUE;
+}
+
+unsigned int
+ra_alloc_reg_class(struct ra_regs *regs)
+{
+ struct ra_class *class;
+
+ regs->classes = talloc_realloc(regs, regs->classes,
+ struct ra_class *,
+ regs->class_count + 1);
+
+ class = talloc_zero(regs, struct ra_class);
+ regs->classes[regs->class_count] = class;
+
+ class->regs = talloc_zero_array(class, GLboolean, regs->count);
+
+ return regs->class_count++;
+}
+
+void
+ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int r)
+{
+ struct ra_class *class = regs->classes[c];
+
+ class->regs[r] = GL_TRUE;
+ class->p++;
+}
+
+/**
+ * Must be called after all conflicts and register classes have been
+ * set up and before the register set is used for allocation.
+ */
+void
+ra_set_finalize(struct ra_regs *regs)
+{
+ unsigned int b, c;
+
+ for (b = 0; b < regs->class_count; b++) {
+ regs->classes[b]->q = talloc_array(regs, unsigned int, regs->class_count);
+ }
+
+ /* Compute, for each class B and C, how many regs of B an
+ * allocation to C could conflict with.
+ */
+ for (b = 0; b < regs->class_count; b++) {
+ for (c = 0; c < regs->class_count; c++) {
+ unsigned int rc;
+ int max_conflicts = 0;
+
+ for (rc = 0; rc < regs->count; rc++) {
+ unsigned int rb;
+ int conflicts = 0;
+
+ if (!regs->classes[c]->regs[rc])
+ continue;
+
+ for (rb = 0; rb < regs->count; rb++) {
+ if (regs->classes[b]->regs[rb] &&
+ regs->regs[rb].conflicts[rc])
+ conflicts++;
+ }
+ max_conflicts = MAX2(max_conflicts, conflicts);
+ }
+ regs->classes[b]->q[c] = max_conflicts;
+ }
+ }
+}
+
+struct ra_graph *
+ra_alloc_interference_graph(struct ra_regs *regs, unsigned int count)
+{
+ struct ra_graph *g;
+ unsigned int i;
+
+ g = talloc_zero(regs, struct ra_graph);
+ g->regs = regs;
+ g->nodes = talloc_zero_array(g, struct ra_node, count);
+ g->count = count;
+
+ g->stack = talloc_zero_array(g, unsigned int, count);
+
+ for (i = 0; i < count; i++) {
+ g->nodes[i].adjacency = talloc_zero_array(g, GLboolean, count);
+ g->nodes[i].adjacency[i] = GL_TRUE;
+ g->nodes[i].reg = ~0;
+ }
+
+ return g;
+}
+
+void
+ra_set_node_class(struct ra_graph *g,
+ unsigned int n, unsigned int class)
+{
+ g->nodes[n].class = class;
+}
+
+void
+ra_add_node_interference(struct ra_graph *g,
+ unsigned int n1, unsigned int n2)
+{
+ if (g->nodes[n1].adjacency[n2])
+ return;
+
+ g->nodes[n1].adjacency[n2] = GL_TRUE;
+ g->nodes[n2].adjacency_count++;
+ g->nodes[n2].adjacency[n1] = GL_TRUE;
+ g->nodes[n2].adjacency_count++;
+}
+
+static GLboolean pq_test(struct ra_graph *g, unsigned int n)
+{
+ unsigned int j;
+ unsigned int q = 0;
+ int n_class = g->nodes[n].class;
+
+ for (j = 0; j < g->count; j++) {
+ if (j == n || g->nodes[j].in_stack)
+ continue;
+
+ if (g->nodes[n].adjacency[j]) {
+ unsigned int j_class = g->nodes[j].class;
+ q += g->regs->classes[n_class]->q[j_class];
+ }
+ }
+
+ return q < g->regs->classes[n_class]->p;
+}
+
+/**
+ * Simplifies the interference graph by pushing all
+ * trivially-colorable nodes into a stack of nodes to be colored,
+ * removing them from the graph, and rinsing and repeating.
+ *
+ * Returns GL_TRUE if all nodes were removed from the graph. GL_FALSE
+ * means that either spilling will be required, or optimistic coloring
+ * should be applied.
+ */
+GLboolean
+ra_simplify(struct ra_graph *g)
+{
+ GLboolean progress = GL_TRUE;
+ int i;
+
+ while (progress) {
+ progress = GL_FALSE;
+
+ for (i = g->count - 1; i >= 0; i--) {
+ if (g->nodes[i].in_stack)
+ continue;
+
+ if (pq_test(g, i)) {
+ g->stack[g->stack_count] = i;
+ g->stack_count++;
+ g->nodes[i].in_stack = GL_TRUE;
+ progress = GL_TRUE;
+ }
+ }
+ }
+
+ for (i = 0; i < g->count; i++) {
+ if (!g->nodes[i].in_stack)
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+/**
+ * Pops nodes from the stack back into the graph, coloring them with
+ * registers as they go.
+ *
+ * If all nodes were trivially colorable, then this must succeed. If
+ * not (optimistic coloring), then it may return GL_FALSE;
+ */
+GLboolean
+ra_select(struct ra_graph *g)
+{
+ int i;
+
+ while (g->stack_count != 0) {
+ unsigned int r;
+ int n = g->stack[g->stack_count - 1];
+ struct ra_class *c = g->regs->classes[g->nodes[n].class];
+
+ /* Find the lowest-numbered reg which is not used by a member
+ * of the graph adjacent to us.
+ */
+ for (r = 0; r < g->regs->count; r++) {
+ if (!c->regs[r])
+ continue;
+
+ /* Check if any of our neighbors conflict with this register choice. */
+ for (i = 0; i < g->count; i++) {
+ if (g->nodes[n].adjacency[i] &&
+ !g->nodes[i].in_stack &&
+ g->regs->regs[r].conflicts[g->nodes[i].reg]) {
+ break;
+ }
+ }
+ if (i == g->count)
+ break;
+ }
+ if (r == g->regs->count)
+ return GL_FALSE;
+
+ g->nodes[n].reg = r;
+ g->nodes[n].in_stack = GL_FALSE;
+ g->stack_count--;
+ }
+
+ return GL_TRUE;
+}
+
+/**
+ * Optimistic register coloring: Just push the remaining nodes
+ * on the stack. They'll be colored first in ra_select(), and
+ * if they succeed then the locally-colorable nodes are still
+ * locally-colorable and the rest of the register allocation
+ * will succeed.
+ */
+void
+ra_optimistic_color(struct ra_graph *g)
+{
+ unsigned int i;
+
+ for (i = 0; i < g->count; i++) {
+ if (g->nodes[i].in_stack)
+ continue;
+
+ g->stack[g->stack_count] = i;
+ g->stack_count++;
+ g->nodes[i].in_stack = GL_TRUE;
+ }
+}
+
+GLboolean
+ra_allocate_no_spills(struct ra_graph *g)
+{
+ if (!ra_simplify(g)) {
+ ra_optimistic_color(g);
+ }
+ return ra_select(g);
+}
+
+unsigned int
+ra_get_node_reg(struct ra_graph *g, unsigned int n)
+{
+ return g->nodes[n].reg;
+}
+
+static float
+ra_get_spill_benefit(struct ra_graph *g, unsigned int n)
+{
+ int j;
+ float benefit = 0;
+ int n_class = g->nodes[n].class;
+
+ /* Define the benefit of eliminating an interference between n, j
+ * through spilling as q(C, B) / p(C). This is similar to the
+ * "count number of edges" approach of traditional graph coloring,
+ * but takes classes into account.
+ */
+ for (j = 0; j < g->count; j++) {
+ if (j != n && g->nodes[n].adjacency[j]) {
+ unsigned int j_class = g->nodes[j].class;
+ benefit += ((float)g->regs->classes[n_class]->q[j_class] /
+ g->regs->classes[n_class]->p);
+ break;
+ }
+ }
+
+ return benefit;
+}
+
+/**
+ * Returns a node number to be spilled according to the cost/benefit using
+ * the pq test, or -1 if there are no spillable nodes.
+ */
+int
+ra_get_best_spill_node(struct ra_graph *g)
+{
+ unsigned int best_node = -1;
+ unsigned int best_benefit = 0.0;
+ unsigned int n;
+
+ for (n = 0; n < g->count; n++) {
+ float cost = g->nodes[n].spill_cost;
+ float benefit;
+
+ if (cost <= 0.0)
+ continue;
+
+ benefit = ra_get_spill_benefit(g, n);
+
+ if (benefit / cost > best_benefit) {
+ best_benefit = benefit / cost;
+ best_node = n;
+ }
+ }
+
+ return best_node;
+}
+
+/**
+ * Only nodes with a spill cost set (cost != 0.0) will be considered
+ * for register spilling.
+ */
+void
+ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost)
+{
+ g->nodes[n].spill_cost = cost;
+}
diff --git a/mesalib/src/mesa/program/register_allocate.h b/mesalib/src/mesa/program/register_allocate.h
new file mode 100644
index 000000000..bb9e2740a
--- /dev/null
+++ b/mesalib/src/mesa/program/register_allocate.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+struct ra_class;
+struct ra_regs;
+
+/* @{
+ * Register set setup.
+ *
+ * This should be done once at backend initializaion, as
+ * ra_set_finalize is O(r^2*c^2). The registers may be virtual
+ * registers, such as aligned register pairs that conflict with the
+ * two real registers from which they are composed.
+ */
+struct ra_regs *ra_alloc_reg_set(unsigned int count);
+unsigned int ra_alloc_reg_class(struct ra_regs *regs);
+void ra_add_reg_conflict(struct ra_regs *regs,
+ unsigned int r1, unsigned int r2);
+void ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int reg);
+void ra_set_finalize(struct ra_regs *regs);
+/** @} */
+
+/** @{ Interference graph setup.
+ *
+ * Each interference graph node is a virtual variable in the IL. It
+ * is up to the user to ra_set_node_class() for the virtual variable,
+ * and compute live ranges and ra_node_interfere() between conflicting
+ * live ranges.
+ */
+struct ra_graph *ra_alloc_interference_graph(struct ra_regs *regs,
+ unsigned int count);
+void ra_set_node_class(struct ra_graph *g, unsigned int n, unsigned int c);
+void ra_add_node_interference(struct ra_graph *g,
+ unsigned int n1, unsigned int n2);
+/** @} */
+
+/** @{ Graph-coloring register allocation */
+GLboolean ra_simplify(struct ra_graph *g);
+void ra_optimistic_color(struct ra_graph *g);
+GLboolean ra_select(struct ra_graph *g);
+GLboolean ra_allocate_no_spills(struct ra_graph *g);
+
+unsigned int ra_get_node_reg(struct ra_graph *g, unsigned int n);
+void ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost);
+int ra_get_best_spill_node(struct ra_graph *g);
+/** @} */
+
diff --git a/mesalib/src/mesa/program/sampler.cpp b/mesalib/src/mesa/program/sampler.cpp
new file mode 100644
index 000000000..cd44467a3
--- /dev/null
+++ b/mesalib/src/mesa/program/sampler.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 <cstdio>
+#include "ir.h"
+#include "glsl_types.h"
+#include "ir_visitor.h"
+
+extern "C" {
+#include "main/compiler.h"
+#include "main/mtypes.h"
+#include "program/prog_parameter.h"
+}
+
+static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
+
+static void fail_link(struct gl_shader_program *prog, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, args);
+ va_end(args);
+
+ prog->LinkStatus = GL_FALSE;
+}
+
+class get_sampler_name : public ir_hierarchical_visitor
+{
+public:
+ get_sampler_name(ir_dereference *last,
+ struct gl_shader_program *shader_program)
+ {
+ this->mem_ctx = talloc_new(NULL);
+ this->shader_program = shader_program;
+ this->name = NULL;
+ this->offset = 0;
+ this->last = last;
+ }
+
+ ~get_sampler_name()
+ {
+ talloc_free(this->mem_ctx);
+ }
+
+ virtual ir_visitor_status visit(ir_dereference_variable *ir)
+ {
+ this->name = ir->var->name;
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
+ {
+ this->name = talloc_asprintf(mem_ctx, "%s.%s", name, ir->field);
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
+ {
+ ir_constant *index = ir->array_index->as_constant();
+ int i;
+
+ if (index) {
+ i = index->value.i[0];
+ } else {
+ /* GLSL 1.10 and 1.20 allowed variable sampler array indices,
+ * while GLSL 1.30 requires that the array indices be
+ * constant integer expressions. We don't expect any driver
+ * to actually work with a really variable array index, so
+ * all that would work would be an unrolled loop counter that ends
+ * up being constant above.
+ */
+ shader_program->InfoLog =
+ talloc_asprintf_append(shader_program->InfoLog,
+ "warning: Variable sampler array index "
+ "unsupported.\nThis feature of the language "
+ "was removed in GLSL 1.20 and is unlikely "
+ "to be supported for 1.10 in Mesa.\n");
+ i = 0;
+ }
+ if (ir != last) {
+ this->name = talloc_asprintf(mem_ctx, "%s[%d]", name, i);
+ } else {
+ offset = i;
+ }
+ return visit_continue;
+ }
+
+ struct gl_shader_program *shader_program;
+ const char *name;
+ void *mem_ctx;
+ int offset;
+ ir_dereference *last;
+};
+
+extern "C" {
+int
+_mesa_get_sampler_uniform_value(class ir_dereference *sampler,
+ struct gl_shader_program *shader_program,
+ const struct gl_program *prog)
+{
+ get_sampler_name getname(sampler, shader_program);
+
+ sampler->accept(&getname);
+
+ GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
+ getname.name);
+
+ if (index < 0) {
+ fail_link(shader_program,
+ "failed to find sampler named %s.\n", getname.name);
+ return 0;
+ }
+
+ index += getname.offset;
+
+ return prog->Parameters->ParameterValues[index][0];
+}
+}
diff --git a/mesalib/src/mesa/program/sampler.h b/mesalib/src/mesa/program/sampler.h
new file mode 100644
index 000000000..c76d7077b
--- /dev/null
+++ b/mesalib/src/mesa/program/sampler.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+int
+_mesa_get_sampler_uniform_value(class ir_dereference *sampler,
+ struct gl_shader_program *shader_program,
+ const struct gl_program *prog);
diff --git a/mesalib/src/mesa/program/symbol_table.c b/mesalib/src/mesa/program/symbol_table.c
index 09e7cb44e..45aeb97b1 100644
--- a/mesalib/src/mesa/program/symbol_table.c
+++ b/mesalib/src/mesa/program/symbol_table.c
@@ -1,413 +1,488 @@
-/*
- * Copyright © 2008 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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 "main/imports.h"
-#include "symbol_table.h"
-#include "hash_table.h"
-
-struct symbol {
- /**
- * Link to the next symbol in the table with the same name
- *
- * The linked list of symbols with the same name is ordered by scope
- * from inner-most to outer-most.
- */
- struct symbol *next_with_same_name;
-
-
- /**
- * Link to the next symbol in the table with the same scope
- *
- * The linked list of symbols with the same scope is unordered. Symbols
- * in this list my have unique names.
- */
- struct symbol *next_with_same_scope;
-
-
- /**
- * Header information for the list of symbols with the same name.
- */
- struct symbol_header *hdr;
-
-
- /**
- * Name space of the symbol
- *
- * Name space are arbitrary user assigned integers. No two symbols can
- * exist in the same name space at the same scope level.
- */
- int name_space;
-
- /** Scope depth where this symbol was defined. */
- unsigned depth;
-
- /**
- * Arbitrary user supplied data.
- */
- void *data;
-};
-
-
-/**
- */
-struct symbol_header {
- /** Linkage in list of all headers in a given symbol table. */
- struct symbol_header *next;
-
- /** Symbol name. */
- char *name;
-
- /** Linked list of symbols with the same name. */
- struct symbol *symbols;
-};
-
-
-/**
- * Element of the scope stack.
- */
-struct scope_level {
- /** Link to next (inner) scope level. */
- struct scope_level *next;
-
- /** Linked list of symbols with the same scope. */
- struct symbol *symbols;
-};
-
-
-/**
- *
- */
-struct _mesa_symbol_table {
- /** Hash table containing all symbols in the symbol table. */
- struct hash_table *ht;
-
- /** Top of scope stack. */
- struct scope_level *current_scope;
-
- /** List of all symbol headers in the table. */
- struct symbol_header *hdr;
-
- /** Current scope depth. */
- unsigned depth;
-};
-
-
-struct _mesa_symbol_table_iterator {
- /**
- * Name space of symbols returned by this iterator.
- */
- int name_space;
-
-
- /**
- * Currently iterated symbol
- *
- * The next call to \c _mesa_symbol_table_iterator_get will return this
- * value. It will also update this value to the value that should be
- * returned by the next call.
- */
- struct symbol *curr;
-};
-
-
-static void
-check_symbol_table(struct _mesa_symbol_table *table)
-{
-#if 1
- struct scope_level *scope;
-
- for (scope = table->current_scope; scope != NULL; scope = scope->next) {
- struct symbol *sym;
-
- for (sym = scope->symbols
- ; sym != NULL
- ; sym = sym->next_with_same_name) {
- const struct symbol_header *const hdr = sym->hdr;
- struct symbol *sym2;
-
- for (sym2 = hdr->symbols
- ; sym2 != NULL
- ; sym2 = sym2->next_with_same_name) {
- assert(sym2->hdr == hdr);
- }
- }
- }
-#endif
-}
-
-void
-_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table)
-{
- struct scope_level *const scope = table->current_scope;
- struct symbol *sym = scope->symbols;
-
- table->current_scope = scope->next;
- table->depth--;
-
- free(scope);
-
- while (sym != NULL) {
- struct symbol *const next = sym->next_with_same_scope;
- struct symbol_header *const hdr = sym->hdr;
-
- assert(hdr->symbols == sym);
-
- hdr->symbols = sym->next_with_same_name;
-
- free(sym);
-
- sym = next;
- }
-
- check_symbol_table(table);
-}
-
-
-void
-_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table)
-{
- struct scope_level *const scope = calloc(1, sizeof(*scope));
-
- scope->next = table->current_scope;
- table->current_scope = scope;
- table->depth++;
-}
-
-
-static struct symbol_header *
-find_symbol(struct _mesa_symbol_table *table, const char *name)
-{
- return (struct symbol_header *) hash_table_find(table->ht, name);
-}
-
-
-struct _mesa_symbol_table_iterator *
-_mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table *table,
- int name_space, const char *name)
-{
- struct _mesa_symbol_table_iterator *iter = calloc(1, sizeof(*iter));
- struct symbol_header *const hdr = find_symbol(table, name);
-
- iter->name_space = name_space;
-
- if (hdr != NULL) {
- struct symbol *sym;
-
- for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
- assert(sym->hdr == hdr);
-
- if ((name_space == -1) || (sym->name_space == name_space)) {
- iter->curr = sym;
- break;
- }
- }
- }
-
- return iter;
-}
-
-
-void
-_mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator *iter)
-{
- free(iter);
-}
-
-
-void *
-_mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator *iter)
-{
- return (iter->curr == NULL) ? NULL : iter->curr->data;
-}
-
-
-int
-_mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter)
-{
- struct symbol_header *hdr;
-
- if (iter->curr == NULL) {
- return 0;
- }
-
- hdr = iter->curr->hdr;
- iter->curr = iter->curr->next_with_same_name;
-
- while (iter->curr != NULL) {
- assert(iter->curr->hdr == hdr);
-
- if ((iter->name_space == -1)
- || (iter->curr->name_space == iter->name_space)) {
- return 1;
- }
-
- iter->curr = iter->curr->next_with_same_name;
- }
-
- return 0;
-}
-
-
-/**
- * Determine the scope "distance" of a symbol from the current scope
- *
- * \return
- * A non-negative number for the number of scopes between the current scope
- * and the scope where a symbol was defined. A value of zero means the current
- * scope. A negative number if the symbol does not exist.
- */
-int
-_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table,
- int name_space, const char *name)
-{
- struct symbol_header *const hdr = find_symbol(table, name);
- struct symbol *sym;
-
- if (hdr != NULL) {
- for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
- assert(sym->hdr == hdr);
-
- if ((name_space == -1) || (sym->name_space == name_space)) {
- assert(sym->depth <= table->depth);
- return sym->depth - table->depth;
- }
- }
- }
-
- return -1;
-}
-
-
-void *
-_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table,
- int name_space, const char *name)
-{
- struct symbol_header *const hdr = find_symbol(table, name);
-
- if (hdr != NULL) {
- struct symbol *sym;
-
-
- for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
- assert(sym->hdr == hdr);
-
- if ((name_space == -1) || (sym->name_space == name_space)) {
- return sym->data;
- }
- }
- }
-
- return NULL;
-}
-
-
-int
-_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table,
- int name_space, const char *name,
- void *declaration)
-{
- struct symbol_header *hdr;
- struct symbol *sym;
-
- check_symbol_table(table);
-
- hdr = find_symbol(table, name);
-
- check_symbol_table(table);
-
- if (hdr == NULL) {
- hdr = calloc(1, sizeof(*hdr));
- hdr->name = strdup(name);
-
- hash_table_insert(table->ht, hdr, hdr->name);
- hdr->next = table->hdr;
- table->hdr = hdr;
- }
-
- check_symbol_table(table);
-
- /* If the symbol already exists in this namespace at this scope, it cannot
- * be added to the table.
- */
- for (sym = hdr->symbols
- ; (sym != NULL) && (sym->name_space != name_space)
- ; sym = sym->next_with_same_name) {
- /* empty */
- }
-
- if (sym && (sym->depth == table->depth))
- return -1;
-
- sym = calloc(1, sizeof(*sym));
- sym->next_with_same_name = hdr->symbols;
- sym->next_with_same_scope = table->current_scope->symbols;
- sym->hdr = hdr;
- sym->name_space = name_space;
- sym->data = declaration;
- sym->depth = table->depth;
-
- assert(sym->hdr == hdr);
-
- hdr->symbols = sym;
- table->current_scope->symbols = sym;
-
- check_symbol_table(table);
- return 0;
-}
-
-
-struct _mesa_symbol_table *
-_mesa_symbol_table_ctor(void)
-{
- struct _mesa_symbol_table *table = calloc(1, sizeof(*table));
-
- if (table != NULL) {
- table->ht = hash_table_ctor(32, hash_table_string_hash,
- hash_table_string_compare);
-
- _mesa_symbol_table_push_scope(table);
- }
-
- return table;
-}
-
-
-void
-_mesa_symbol_table_dtor(struct _mesa_symbol_table *table)
-{
- struct symbol_header *hdr;
- struct symbol_header *next;
-
- while (table->current_scope != NULL) {
- _mesa_symbol_table_pop_scope(table);
- }
-
- for (hdr = table->hdr; hdr != NULL; hdr = next) {
- next = hdr->next;
- free(hdr->name);
- free(hdr);
- }
-
- hash_table_dtor(table->ht);
- free(table);
-}
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "main/imports.h"
+#include "symbol_table.h"
+#include "hash_table.h"
+
+struct symbol {
+ /**
+ * Link to the next symbol in the table with the same name
+ *
+ * The linked list of symbols with the same name is ordered by scope
+ * from inner-most to outer-most.
+ */
+ struct symbol *next_with_same_name;
+
+
+ /**
+ * Link to the next symbol in the table with the same scope
+ *
+ * The linked list of symbols with the same scope is unordered. Symbols
+ * in this list my have unique names.
+ */
+ struct symbol *next_with_same_scope;
+
+
+ /**
+ * Header information for the list of symbols with the same name.
+ */
+ struct symbol_header *hdr;
+
+
+ /**
+ * Name space of the symbol
+ *
+ * Name space are arbitrary user assigned integers. No two symbols can
+ * exist in the same name space at the same scope level.
+ */
+ int name_space;
+
+ /** Scope depth where this symbol was defined. */
+ unsigned depth;
+
+ /**
+ * Arbitrary user supplied data.
+ */
+ void *data;
+};
+
+
+/**
+ */
+struct symbol_header {
+ /** Linkage in list of all headers in a given symbol table. */
+ struct symbol_header *next;
+
+ /** Symbol name. */
+ char *name;
+
+ /** Linked list of symbols with the same name. */
+ struct symbol *symbols;
+};
+
+
+/**
+ * Element of the scope stack.
+ */
+struct scope_level {
+ /** Link to next (inner) scope level. */
+ struct scope_level *next;
+
+ /** Linked list of symbols with the same scope. */
+ struct symbol *symbols;
+};
+
+
+/**
+ *
+ */
+struct _mesa_symbol_table {
+ /** Hash table containing all symbols in the symbol table. */
+ struct hash_table *ht;
+
+ /** Top of scope stack. */
+ struct scope_level *current_scope;
+
+ /** List of all symbol headers in the table. */
+ struct symbol_header *hdr;
+
+ /** Current scope depth. */
+ unsigned depth;
+};
+
+
+struct _mesa_symbol_table_iterator {
+ /**
+ * Name space of symbols returned by this iterator.
+ */
+ int name_space;
+
+
+ /**
+ * Currently iterated symbol
+ *
+ * The next call to \c _mesa_symbol_table_iterator_get will return this
+ * value. It will also update this value to the value that should be
+ * returned by the next call.
+ */
+ struct symbol *curr;
+};
+
+
+static void
+check_symbol_table(struct _mesa_symbol_table *table)
+{
+#if 1
+ struct scope_level *scope;
+
+ for (scope = table->current_scope; scope != NULL; scope = scope->next) {
+ struct symbol *sym;
+
+ for (sym = scope->symbols
+ ; sym != NULL
+ ; sym = sym->next_with_same_name) {
+ const struct symbol_header *const hdr = sym->hdr;
+ struct symbol *sym2;
+
+ for (sym2 = hdr->symbols
+ ; sym2 != NULL
+ ; sym2 = sym2->next_with_same_name) {
+ assert(sym2->hdr == hdr);
+ }
+ }
+ }
+#endif
+}
+
+void
+_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table)
+{
+ struct scope_level *const scope = table->current_scope;
+ struct symbol *sym = scope->symbols;
+
+ table->current_scope = scope->next;
+ table->depth--;
+
+ free(scope);
+
+ while (sym != NULL) {
+ struct symbol *const next = sym->next_with_same_scope;
+ struct symbol_header *const hdr = sym->hdr;
+
+ assert(hdr->symbols == sym);
+
+ hdr->symbols = sym->next_with_same_name;
+
+ free(sym);
+
+ sym = next;
+ }
+
+ check_symbol_table(table);
+}
+
+
+void
+_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table)
+{
+ struct scope_level *const scope = calloc(1, sizeof(*scope));
+
+ scope->next = table->current_scope;
+ table->current_scope = scope;
+ table->depth++;
+}
+
+
+static struct symbol_header *
+find_symbol(struct _mesa_symbol_table *table, const char *name)
+{
+ return (struct symbol_header *) hash_table_find(table->ht, name);
+}
+
+
+struct _mesa_symbol_table_iterator *
+_mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table *table,
+ int name_space, const char *name)
+{
+ struct _mesa_symbol_table_iterator *iter = calloc(1, sizeof(*iter));
+ struct symbol_header *const hdr = find_symbol(table, name);
+
+ iter->name_space = name_space;
+
+ if (hdr != NULL) {
+ struct symbol *sym;
+
+ for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
+ assert(sym->hdr == hdr);
+
+ if ((name_space == -1) || (sym->name_space == name_space)) {
+ iter->curr = sym;
+ break;
+ }
+ }
+ }
+
+ return iter;
+}
+
+
+void
+_mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator *iter)
+{
+ free(iter);
+}
+
+
+void *
+_mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator *iter)
+{
+ return (iter->curr == NULL) ? NULL : iter->curr->data;
+}
+
+
+int
+_mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter)
+{
+ struct symbol_header *hdr;
+
+ if (iter->curr == NULL) {
+ return 0;
+ }
+
+ hdr = iter->curr->hdr;
+ iter->curr = iter->curr->next_with_same_name;
+
+ while (iter->curr != NULL) {
+ assert(iter->curr->hdr == hdr);
+
+ if ((iter->name_space == -1)
+ || (iter->curr->name_space == iter->name_space)) {
+ return 1;
+ }
+
+ iter->curr = iter->curr->next_with_same_name;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Determine the scope "distance" of a symbol from the current scope
+ *
+ * \return
+ * A non-negative number for the number of scopes between the current scope
+ * and the scope where a symbol was defined. A value of zero means the current
+ * scope. A negative number if the symbol does not exist.
+ */
+int
+_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table,
+ int name_space, const char *name)
+{
+ struct symbol_header *const hdr = find_symbol(table, name);
+ struct symbol *sym;
+
+ if (hdr != NULL) {
+ for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
+ assert(sym->hdr == hdr);
+
+ if ((name_space == -1) || (sym->name_space == name_space)) {
+ assert(sym->depth <= table->depth);
+ return sym->depth - table->depth;
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+void *
+_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table,
+ int name_space, const char *name)
+{
+ struct symbol_header *const hdr = find_symbol(table, name);
+
+ if (hdr != NULL) {
+ struct symbol *sym;
+
+
+ for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
+ assert(sym->hdr == hdr);
+
+ if ((name_space == -1) || (sym->name_space == name_space)) {
+ return sym->data;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+int
+_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table,
+ int name_space, const char *name,
+ void *declaration)
+{
+ struct symbol_header *hdr;
+ struct symbol *sym;
+
+ check_symbol_table(table);
+
+ hdr = find_symbol(table, name);
+
+ check_symbol_table(table);
+
+ if (hdr == NULL) {
+ hdr = calloc(1, sizeof(*hdr));
+ hdr->name = strdup(name);
+
+ hash_table_insert(table->ht, hdr, hdr->name);
+ hdr->next = table->hdr;
+ table->hdr = hdr;
+ }
+
+ check_symbol_table(table);
+
+ /* If the symbol already exists in this namespace at this scope, it cannot
+ * be added to the table.
+ */
+ for (sym = hdr->symbols
+ ; (sym != NULL) && (sym->name_space != name_space)
+ ; sym = sym->next_with_same_name) {
+ /* empty */
+ }
+
+ if (sym && (sym->depth == table->depth))
+ return -1;
+
+ sym = calloc(1, sizeof(*sym));
+ sym->next_with_same_name = hdr->symbols;
+ sym->next_with_same_scope = table->current_scope->symbols;
+ sym->hdr = hdr;
+ sym->name_space = name_space;
+ sym->data = declaration;
+ sym->depth = table->depth;
+
+ assert(sym->hdr == hdr);
+
+ hdr->symbols = sym;
+ table->current_scope->symbols = sym;
+
+ check_symbol_table(table);
+ return 0;
+}
+
+
+int
+_mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table,
+ int name_space, const char *name,
+ void *declaration)
+{
+ struct symbol_header *hdr;
+ struct symbol *sym;
+ struct symbol *curr;
+ struct scope_level *top_scope;
+
+ check_symbol_table(table);
+
+ hdr = find_symbol(table, name);
+
+ check_symbol_table(table);
+
+ if (hdr == NULL) {
+ hdr = calloc(1, sizeof(*hdr));
+ hdr->name = strdup(name);
+
+ hash_table_insert(table->ht, hdr, hdr->name);
+ hdr->next = table->hdr;
+ table->hdr = hdr;
+ }
+
+ check_symbol_table(table);
+
+ /* If the symbol already exists in this namespace at this scope, it cannot
+ * be added to the table.
+ */
+ for (sym = hdr->symbols
+ ; (sym != NULL) && (sym->name_space != name_space)
+ ; sym = sym->next_with_same_name) {
+ /* empty */
+ }
+
+ if (sym && sym->depth == 0)
+ return -1;
+
+ /* Find the top-level scope */
+ for (top_scope = table->current_scope
+ ; top_scope->next != NULL
+ ; top_scope = top_scope->next) {
+ /* empty */
+ }
+
+ sym = calloc(1, sizeof(*sym));
+ sym->next_with_same_scope = top_scope->symbols;
+ sym->hdr = hdr;
+ sym->name_space = name_space;
+ sym->data = declaration;
+
+ assert(sym->hdr == hdr);
+
+ /* Since next_with_same_name is ordered by scope, we need to append the
+ * new symbol to the _end_ of the list.
+ */
+ if (hdr->symbols == NULL) {
+ hdr->symbols = sym;
+ } else {
+ for (curr = hdr->symbols
+ ; curr->next_with_same_name != NULL
+ ; curr = curr->next_with_same_name) {
+ /* empty */
+ }
+ curr->next_with_same_name = sym;
+ }
+ top_scope->symbols = sym;
+
+ check_symbol_table(table);
+ return 0;
+}
+
+
+
+struct _mesa_symbol_table *
+_mesa_symbol_table_ctor(void)
+{
+ struct _mesa_symbol_table *table = calloc(1, sizeof(*table));
+
+ if (table != NULL) {
+ table->ht = hash_table_ctor(32, hash_table_string_hash,
+ hash_table_string_compare);
+
+ _mesa_symbol_table_push_scope(table);
+ }
+
+ return table;
+}
+
+
+void
+_mesa_symbol_table_dtor(struct _mesa_symbol_table *table)
+{
+ struct symbol_header *hdr;
+ struct symbol_header *next;
+
+ while (table->current_scope != NULL) {
+ _mesa_symbol_table_pop_scope(table);
+ }
+
+ for (hdr = table->hdr; hdr != NULL; hdr = next) {
+ next = hdr->next;
+ free(hdr->name);
+ free(hdr);
+ }
+
+ hash_table_dtor(table->ht);
+ free(table);
+}
diff --git a/mesalib/src/mesa/program/symbol_table.h b/mesalib/src/mesa/program/symbol_table.h
index 1d570fc1a..1de29a8f0 100644
--- a/mesalib/src/mesa/program/symbol_table.h
+++ b/mesalib/src/mesa/program/symbol_table.h
@@ -1,58 +1,62 @@
-/*
- * Copyright © 2008 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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 MESA_SYMBOL_TABLE_H
-#define MESA_SYMBOL_TABLE_H
-
-struct _mesa_symbol_table;
-struct _mesa_symbol_table_iterator;
-
-extern void _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table);
-
-extern void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table);
-
-extern int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *symtab,
- int name_space, const char *name, void *declaration);
-
-extern int _mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table,
- int name_space, const char *name);
-
-extern void *_mesa_symbol_table_find_symbol(
- struct _mesa_symbol_table *symtab, int name_space, const char *name);
-
-extern struct _mesa_symbol_table *_mesa_symbol_table_ctor(void);
-
-extern void _mesa_symbol_table_dtor(struct _mesa_symbol_table *);
-
-extern struct _mesa_symbol_table_iterator *_mesa_symbol_table_iterator_ctor(
- struct _mesa_symbol_table *table, int name_space, const char *name);
-
-extern void _mesa_symbol_table_iterator_dtor(
- struct _mesa_symbol_table_iterator *);
-
-extern void *_mesa_symbol_table_iterator_get(
- struct _mesa_symbol_table_iterator *iter);
-
-extern int _mesa_symbol_table_iterator_next(
- struct _mesa_symbol_table_iterator *iter);
-
-#endif /* MESA_SYMBOL_TABLE_H */
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 MESA_SYMBOL_TABLE_H
+#define MESA_SYMBOL_TABLE_H
+
+struct _mesa_symbol_table;
+struct _mesa_symbol_table_iterator;
+
+extern void _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table);
+
+extern void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table);
+
+extern int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *symtab,
+ int name_space, const char *name, void *declaration);
+
+extern int _mesa_symbol_table_add_global_symbol(
+ struct _mesa_symbol_table *symtab, int name_space, const char *name,
+ void *declaration);
+
+extern int _mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table,
+ int name_space, const char *name);
+
+extern void *_mesa_symbol_table_find_symbol(
+ struct _mesa_symbol_table *symtab, int name_space, const char *name);
+
+extern struct _mesa_symbol_table *_mesa_symbol_table_ctor(void);
+
+extern void _mesa_symbol_table_dtor(struct _mesa_symbol_table *);
+
+extern struct _mesa_symbol_table_iterator *_mesa_symbol_table_iterator_ctor(
+ struct _mesa_symbol_table *table, int name_space, const char *name);
+
+extern void _mesa_symbol_table_iterator_dtor(
+ struct _mesa_symbol_table_iterator *);
+
+extern void *_mesa_symbol_table_iterator_get(
+ struct _mesa_symbol_table_iterator *iter);
+
+extern int _mesa_symbol_table_iterator_next(
+ struct _mesa_symbol_table_iterator *iter);
+
+#endif /* MESA_SYMBOL_TABLE_H */