diff options
author | marha <marha@users.sourceforge.net> | 2010-12-29 12:20:21 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2010-12-29 12:20:21 +0000 |
commit | 053f5dfd42ade05252e586a282e34906db10828d (patch) | |
tree | de215580ce205409a6d810a005c6c5909f3145d1 /mesalib/src/mesa/program | |
parent | 04ceb8c4a0cca3d8682f094d1d6faed8f693afb5 (diff) | |
parent | 807c6931fe683fd844ceec1b023232181e6aae03 (diff) | |
download | vcxsrv-053f5dfd42ade05252e586a282e34906db10828d.tar.gz vcxsrv-053f5dfd42ade05252e586a282e34906db10828d.tar.bz2 vcxsrv-053f5dfd42ade05252e586a282e34906db10828d.zip |
svn merge ^/branches/released .
Diffstat (limited to 'mesalib/src/mesa/program')
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(¶mList->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(¶mList->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 */
|